zephyrproject-rtos / zephyr

Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
https://docs.zephyrproject.org
Apache License 2.0
10.82k stars 6.59k forks source link

RFC: GNSS API #30564

Closed sslupsky closed 8 months ago

sslupsky commented 3 years ago

Introduction

Has there been any work on developing a GNSS API for Zephyr?

Problem description

GNSS is a widely used technology for global positioning. Zephyr should consider support of an API to interface with various GNSS chips.

Proposed change

This proposed API was developed to work the u-blox GNSS solutions. It does not implement advanced GNSS capabilities at the current time. I am not familiar with the recent GPS solution offered by Nordic so it would be helpful to know what Nordic's thinking is regarding an API and how to make this better.

/**
 * @file gnss.h
 * @author Steven Slupsky (sslupsky@scanimetrics.com)
 * @brief 
 * @version 0.1
 * @date 2020-05-20
 * 
 * @copyright Copyright (c) 2020
 * SPDX-License-Identifier: Apache-2.0
 * 
 *    _____                 _                _        _          
 *   / ____|               (_)              | |      (_)         
 *  | (___   ___ __ _ _ __  _ _ __ ___   ___| |_ _ __ _  ___ ___ 
 *   \___ \ / __/ _` | '_ \| | '_ ` _ \ / _ \ __| '__| |/ __/ __|
 *   ____) | (_| (_| | | | | | | | | | |  __/ |_| |  | | (__\__ \
 *  |_____/ \___\__,_|_| |_|_|_| |_| |_|\___|\__|_|  |_|\___|___/
 *                                                               
 */

#ifndef ZEPHYR_INCLUDE_DRIVERS_GNSS_H_
#define ZEPHYR_INCLUDE_DRIVERS_GNSS_H_

#include <sys/__assert.h>
#include <sys/slist.h>

#include <zephyr/types.h>
#include <stddef.h>
#include <device.h>
// #include <dt-bindings/gpio/gpio.h>

#ifdef __cplusplus
extern "C" {
#endif

struct gnss_time {
    u32_t timeOfWeek;        // ms
    u16_t gpsYear;
    u8_t gpsMonth;
    u8_t gpsDay;
    u8_t gpsHour;
    u8_t gpsMinute;
    u8_t gpsSecond;
    struct {
        u8_t validDate : 1;
        u8_t validTime : 1;
        u8_t fullyResolved : 1;
        u8_t validMag : 1;
    } valid;
    u32_t accuracy;
    s32_t gpsNanosecond;
} __packed;

struct gnss_position {
    u8_t fixType;        //Tells us when we have a solution aka lock
    struct {
        u8_t gnssFixOK : 1; // valid fix (ie: within DOP nad accuracy masks)
        u8_t diffSoln : 1;  // differential corrections were applied
        u8_t psmState : 4;  
        u8_t headVehValid : 1;  // heading of vehicle is valid (only set if the receivers is in sensor fusion mode)
        u8_t carrSoln : 1;  // carrier phase range solution status
    } fix_status;           // Tells us when we have a solution aka lock
    u8_t flags2;
    u8_t SIV;            //Number of satellites used in position solution
    s32_t longitude;         //Degrees * 10^-7 (more accurate than floats)
    s32_t latitude;      //Degrees * 10^-7 (more accurate than floats)
    s32_t altitude;      //Number of mm above ellipsoid
    s32_t altitudeMSL;   //Number of mm above Mean Sea Level
    u32_t horizontalAccuracy; // mm * 10^-1 (i.e. 0.1mm)
    u32_t verticalAccuracy;  // mm * 10^-1 (i.e. 0.1mm)
} __packed;

struct gnss_velocity {
    s32_t north;     //mm/s
    s32_t east;  //mm/s
    s32_t down;  //mm/s
    s32_t ground_speed;  //mm/s
    s32_t heading_of_motion; //degrees * 10^-5
    u32_t speed_accuracy;
    u32_t heading_accuracy;
    u16_t pDOP;          //Positional dilution of precision
    u8_t flags3;
    u8_t reserved1[5];
    s32_t headVeh;
    s16_t magDec;
    u16_t magAcc;
} __packed;

struct gnss_pvt {
    //The major datums we want to globally store
    struct gnss_time time;
    struct gnss_position position;
    struct gnss_velocity velocity;
};

struct gnss_fix_status {
    u8_t gpsFixOk : 1;
    u8_t diffSoln : 1;
    u8_t wknSet : 1;
    u8_t towSet : 1;
};

struct gnss_status {
    u32_t tow;          // GPS time of week of the navigation epoch
    u32_t ttff;         // (ms) time to first fix
    u32_t uptime;           // (ms) device uptime
    u8_t fix;           // fix type
    struct gnss_fix_status fix_status;  // fix status
};

struct gnss_firmware_version {
    u8_t versionLow;         //Loaded from getProtocolVersion().
    u8_t versionHigh;
};

// Struct to hold the results returned by getGeofenceState (returned by UBX-NAV-GEOFENCE)
struct geo_fence_state {
    u8_t status;       // Geofencing status: 0 - Geofencing not available or not reliable; 1 - Geofencing active
    u8_t numFences; // Number of geofences
    u8_t combState; // Combined (logical OR) state of all geofences: 0 - Unknown; 1 - Inside; 2 - Outside
    u8_t states[4]; // Geofence states: 0 - Unknown; 1 - Inside; 2 - Outside
};

// Struct to hold the current geofence parameters
struct geo_fence_params {
    u8_t numFences; // Number of active geofences
    s32_t lats[4];   // Latitudes of geofences (in degrees * 10^-7)
    s32_t longs[4];  // Longitudes of geofences (in degrees * 10^-7)
    u32_t rads[4];  // Radii of geofences (in m * 10^-2)
};

/* driver sensor channels */
enum gnss_channel {
    GNSS_CHAN_NONE,
    GNSS_CHAN_TIME,
    GNSS_CHAN_POSITION,
    GNSS_CHAN_VELOCITY,

    /** All channels. */
    GNSS_CHAN_ALL,

    /**
     * Number of all common sensor channels.
     */
    GNSS_CHAN_COMMON_COUNT,

    /**
     * This and higher values are sensor specific.
     * Refer to the sensor header file.
     */
    GNSS_CHAN_PRIV_START = GNSS_CHAN_COMMON_COUNT,

    /**
     * Maximum value describing a sensor channel type.
     */
    GNSS_CHAN_MAX = INT16_MAX,
};

/* driver sensor attributes */
enum gnss_attribute {
    GNSS_ATTR_UPDATE_PERIOD,
    GNSS_ATTR_SEARCH_PERIOD,
    GNSS_ATTR_SLEEP_DURATION,

    GNSS_ATTR_NAV_MEASUREMENT_RATE,
    GNSS_ATTR_NAV_SOLUTION_RATE,
    GNSS_ATTR_NAV_TIMEREF,
    GNSS_ATTR_NAV_SETTINGS,
    GNSS_ATTR_NAV_MSG_PVT_RATE,
    GNSS_ATTR_NAV_MSG_SOL_RATE,
    GNSS_ATTR_NAV_MSG_STATUS_RATE,

    GNSS_ATTR_INFO_ID,
    GNSS_ATTR_INFO_HW_STATUS,
    GNSS_ATTR_INFO_HW2_STATUS,
    GNSS_ATTR_INFO_IO_STATUS,
    GNSS_ATTR_INFO_GNSS_STATUS,

    GNSS_ATTR_INFO_VERSION_HW,
    GNSS_ATTR_INFO_VERSION_SW,
    GNSS_ATTR_INFO_VERSION_PROTO,

    GNSS_ATTR_PORT_UART,
    GNSS_ATTR_PORT_I2C,
    GNSS_ATTR_PORT_USB,

    GNSS_ATTR_NAV_STATUS,

    GNSS_ATTR_PM_STATUS,
    GNSS_ATTR_PM_MODE,
    GNSS_ATTR_PM_SLEEP,

    GNSS_ATTR_TIMEPULSE_STATUS,

    GNSS_ATTR_SAVE,

    /**
     * Number of all common sensor attributes.
     */
    GNSS_ATTR_COMMON_COUNT,

    /**
     * This and higher values are sensor specific.
     * Refer to the sensor header file.
     */
    GNSS_ATTR_PRIV_START = GNSS_ATTR_COMMON_COUNT,

    /**
     * Maximum value describing a sensor attribute type.
     */
    GNSS_ATTR_MAX = INT16_MAX,
};

/**
 * @brief Sensor trigger types.
 */
enum gnss_trigger_type {
    /**
     * Timer-based trigger, useful when the sensor does not have an
     * interrupt line.
     */
    GNSS_TRIG_TIMER,
    /** Trigger fires whenever new data is ready. */
    GNSS_TRIG_DATA_READY,
    GNSS_TRIG_PVT,
    GNSS_TRIG_TIMEPULSE,
    GNSS_TRIG_POLL,
    /** Trigger fires when a geofence event is detected. */
    GNSS_TRIG_GEOFENCE,
    /**
     * Trigger fires when channel reading transitions configured
     * thresholds.  The thresholds are configured via the @ref
     * GNSS_ATTR_LOWER_THRESH and @ref GNSS_ATTR_UPPER_THRESH
     * attributes.
     */
    GNSS_TRIG_THRESHOLD,

    /**
     * Number of all common sensor triggers.
     */
    GNSS_TRIG_COMMON_COUNT,

    /**
     * This and higher values are sensor specific.
     * Refer to the sensor header file.
     */
    GNSS_TRIG_PRIV_START = GNSS_TRIG_COMMON_COUNT,

    /**
     * Maximum value describing a sensor trigger type.
     */
    GNSS_TRIG_MAX = INT16_MAX,
};

/**
 * @brief Sensor trigger spec.
 */
struct gnss_trigger {
    /** Trigger type. */
    enum gnss_trigger_type type;
    /** Channel the trigger is set on. */
    enum gnss_channel chan;
};

enum gnss_device_state {
    GNSS_DEVICE_STATE_UNINITIALIZED = 0,
    GNSS_DEVICE_STATE_INITIALIZED,
    GNSS_DEVICE_STATE_RESET,
    GNSS_DEVICE_STATE_CONFIGURED,
    GNSS_DEVICE_STATE_ACTIVE,
    GNSS_DEVICE_STATE_INACTIVE,
    GNSS_DEVICE_STATE_LOWPOWER,
    GNSS_DEVICE_STATE_DISCONNECTED,
};

enum gnss_tracking_state {
    GNSS_TRACKING_STATE_DISABLED,
    GNSS_TRACKING_STATE_ENABLED,
    GNSS_TRACKING_STATE_ACQUISITION,
    GNSS_TRACKING_STATE_TRACKING,
    GNSS_TRACKING_STATE_INACTIVE,
};

enum gnss_sentence_state {
    GNSS_SENTENCE_STATE_IDLE = 0,
    GNSS_SENTENCE_STATE_UBX,
    GNSS_SENTENCE_STATE_NMEA,
    GNSS_SENTENCE_STATE_RTCM,
    GNSS_SENTENCE_STATE_RTCM3,
    GNSS_SENTENCE_STATE_ERROR,
};

//Depending on the sentence type the processor will load characters into different arrays
enum gnss_sentence_type {
    NONE = 0,
    NMEA,
    UBX,
    RTCM
};

//Controls which port we look to for incoming bytes
enum gnss_module_comm_type {
    COMM_TYPE_I2C = 0,
    COMM_TYPE_SERIAL,
    COMM_TYPE_SPI,
};

enum gnss_model // Possible values for the dynamic platform model, which provide more accuract position output for the situation. Description extracted from ZED-F9P Integration Manual
{
    GNSS_MODEL_PORTABLE = 0, //Applications with low acceleration, e.g. portable devices. Suitable for most situations.
    // 1 is not defined
    GNSS_MODEL_STATIONARY = 2, //Used in timing applications (antenna must be stationary) or other stationary applications. Velocity restricted to 0 m/s. Zero dynamics assumed.
    GNSS_MODEL_PEDESTRIAN,    //Applications with low acceleration and speed, e.g. how a pedestrian would move. Low acceleration assumed.
    GNSS_MODEL_AUTOMOTIVE,    //Used for applications with equivalent dynamics to those of a passenger car. Low vertical acceleration assumed
    GNSS_MODEL_SEA,           //Recommended for applications at sea, with zero vertical velocity. Zero vertical velocity assumed. Sea level assumed.
    GNSS_MODEL_AIRBORNE1g,    //Airborne <1g acceleration. Used for applications with a higher dynamic range and greater vertical acceleration than a passenger car. No 2D position fixes supported.
    GNSS_MODEL_AIRBORNE2g,    //Airborne <2g acceleration. Recommended for typical airborne environments. No 2D position fixes supported.
    GNSS_MODEL_AIRBORNE4g,    //Airborne <4g acceleration. Only recommended for extremely dynamic environments. No 2D position fixes supported.
    GNSS_MODEL_WRIST,         // Not supported in protocol versions less than 18. Only recommended for wrist worn applications. Receiver will filter out arm motion.
    GNSS_MODEL_BIKE,              // Supported in protocol versions 19.2
};

/**
 * @typedef gnss_trigger_handler_t
 * @brief Callback API upon firing of a trigger
 *
 * @param "struct device *dev" Pointer to the sensor device
 * @param "struct gnss_trigger *trigger" The trigger
 */
typedef void (*gnss_trigger_handler_t)(struct device *dev,
                    struct gnss_trigger *trigger);

/**
 * @typedef gnss_trigger_set_t
 * @brief Callback API for setting a sensor's trigger and handler
 *
 * See gnss_trigger_set() for argument description
 */
typedef int (*gnss_trigger_set_t)(struct device *dev,
                    const struct gnss_trigger *trig,
                    gnss_trigger_handler_t handler);

/**
 * @typedef gnss_attr_get_t
 * @brief Callback API upon getting a sensor's attributes
 *
 * See gnss_attr_get() for argument description
 */
typedef int (*gnss_attr_get_t)(struct device *dev,
                 enum gnss_channel chan,
                 enum gnss_attribute attr,
                 void *val);

/**
 * @typedef gnss_attr_set_t
 * @brief Callback API upon setting a sensor's attributes
 *
 * See gnss_attr_set() for argument description
 */
typedef int (*gnss_attr_set_t)(struct device *dev,
                 enum gnss_channel chan,
                 enum gnss_attribute attr,
                 void *val);
/**
 * @typedef gnss_sample_fetch_t
 * @brief Callback API for fetching data from a sensor
 *
 * See gnss_sample_fetch() for argument description
 */
typedef int (*gnss_sample_fetch_t)(struct device *dev,
                     enum gnss_channel chan);
/**
 * @typedef gnss_channel_get_t
 * @brief Callback API for getting a reading from a sensor
 *
 * See gnss_channel_get() for argument description
 */
typedef int (*gnss_channel_get_t)(struct device *dev,
                    enum gnss_channel chan,
                    void *val);

/**
 * @typedef gnss_status_callback_t
 * @brief Callback API upon enabling the gnss module
 *
 * @param "struct device *dev" Pointer to the sensor device
 */
typedef void (*gnss_status_callback_t)(struct device *dev);

/**
 * @typedef gnss_enable_t
 * @brief Callback API upon enabling the gps module
 *
 * See gnss_attr_get() for argument description
 */
typedef int (*gnss_enable_t)(struct device *dev,
                 gnss_status_callback_t handler);

__subsystem struct gnss_driver_api {
    gnss_sample_fetch_t sample_fetch;
    gnss_channel_get_t channel_get;
    gnss_attr_get_t attr_get;
    gnss_attr_set_t attr_set;
    gnss_trigger_set_t trigger_set;
    gnss_enable_t enable;
};

/**
 * @brief Get an attribute for a sensor
 *
 * @param dev Pointer to the sensor device
 * @param chan The channel the attribute belongs to, if any.  Some
 * attributes may only be set for all channels of a device, depending on
 * device capabilities.
 * @param attr The attribute to set
 * @param val The value to set the attribute to
 *
 * @return 0 if successful, negative errno code if failure.
 */
__syscall int gnss_attr_get(struct device *dev,
                  enum gnss_channel chan,
                  enum gnss_attribute attr,
                  void *val);

static inline int z_impl_gnss_attr_get(struct device *dev,
                    enum gnss_channel chan,
                    enum gnss_attribute attr,
                    void *val)
{
    const struct gnss_driver_api *api =
        (const struct gnss_driver_api *)dev->driver_api;

    if (api->attr_get == NULL) {
        return -ENOTSUP;
    }

    return api->attr_get(dev, chan, attr, val);
}

/**
 * @brief Set an attribute for a sensor
 *
 * @param dev Pointer to the sensor device
 * @param chan The channel the attribute belongs to, if any.  Some
 * attributes may only be set for all channels of a device, depending on
 * device capabilities.
 * @param attr The attribute to set
 * @param val The value to set the attribute to
 *
 * @return 0 if successful, negative errno code if failure.
 */
__syscall int gnss_attr_set(struct device *dev,
                  enum gnss_channel chan,
                  enum gnss_attribute attr,
                  void *val);

static inline int z_impl_gnss_attr_set(struct device *dev,
                    enum gnss_channel chan,
                    enum gnss_attribute attr,
                    void *val)
{
    const struct gnss_driver_api *api =
        (const struct gnss_driver_api *)dev->driver_api;

    if (api->attr_set == NULL) {
        return -ENOTSUP;
    }

    return api->attr_set(dev, chan, attr, val);
}

/**
 * @brief Activate a sensor's trigger and set the trigger handler
 *
 * The handler will be called from a thread, so I2C or SPI operations are
 * safe.  However, the thread's stack is limited and defined by the
 * driver.  It is currently up to the caller to ensure that the handler
 * does not overflow the stack.
 *
 * This API is not permitted for user threads.
 *
 * @param dev Pointer to the sensor device
 * @param trig The trigger to activate
 * @param handler The function that should be called when the trigger
 * fires
 *
 * @return 0 if successful, negative errno code if failure.
 */
static inline int gnss_trigger_set(struct device *dev,
                     struct gnss_trigger *trig,
                     gnss_trigger_handler_t handler)
{
    const struct gnss_driver_api *api =
        (const struct gnss_driver_api *)dev->driver_api;

    if (api->trigger_set == NULL) {
        return -ENOTSUP;
    }

    return api->trigger_set(dev, trig, handler);
}

/**
 * @brief Fetch a sample from the sensor and store it in an internal
 * driver buffer
 *
 * Read all of a sensor's active channels and, if necessary, perform any
 * additional operations necessary to make the values useful.  The user
 * may then get individual channel values by calling @ref
 * gnss_channel_get.
 *
 * Since the function communicates with the sensor device, it is unsafe
 * to call it in an ISR if the device is connected via I2C or SPI.
 *
 * @param dev Pointer to the sensor device
 *
 * @return 0 if successful, negative errno code if failure.
 */
__syscall int gnss_sample_fetch(struct device *dev);

static inline int z_impl_gnss_sample_fetch(struct device *dev)
{
    const struct gnss_driver_api *api =
        (const struct gnss_driver_api *)dev->driver_api;

    return api->sample_fetch(dev, GNSS_CHAN_ALL);
}

/**
 * @brief Fetch a sample from the sensor and store it in an internal
 * driver buffer
 *
 * Read and compute compensation for one type of sensor data (magnetometer,
 * accelerometer, etc). The user may then get individual channel values by
 * calling @ref gnss_channel_get.
 *
 * This is mostly implemented by multi function devices enabling reading at
 * different sampling rates.
 *
 * Since the function communicates with the sensor device, it is unsafe
 * to call it in an ISR if the device is connected via I2C or SPI.
 *
 * @param dev Pointer to the sensor device
 * @param type The channel that needs updated
 *
 * @return 0 if successful, negative errno code if failure.
 */
__syscall int gnss_sample_fetch_chan(struct device *dev,
                       enum gnss_channel type);

static inline int z_impl_gnss_sample_fetch_chan(struct device *dev,
                         enum gnss_channel type)
{
    const struct gnss_driver_api *api =
        (const struct gnss_driver_api *)dev->driver_api;

    return api->sample_fetch(dev, type);
}

/**
 * @brief Get a reading from a sensor device
 *
 * Return a useful value for a particular channel, from the driver's
 * internal data.  Before calling this function, a sample must be
 * obtained by calling @ref gnss_sample_fetch or
 * @ref gnss_sample_fetch_chan. It is guaranteed that two subsequent
 * calls of this function for the same channels will yield the same
 * value, if @ref gnss_sample_fetch or @ref gnss_sample_fetch_chan
 * has not been called in the meantime.
 *
 * For vectorial data samples you can request all axes in just one call
 * by passing the specific channel with _XYZ suffix. The sample will be
 * returned at val[0], val[1] and val[2] (X, Y and Z in that order).
 *
 * @param dev Pointer to the sensor device
 * @param chan The channel to read
 * @param val Where to store the value
 *
 * @return 0 if successful, negative errno code if failure.
 */
__syscall int gnss_channel_get(struct device *dev,
                 enum gnss_channel chan,
                 void *val);

static inline int z_impl_gnss_channel_get(struct device *dev,
                       enum gnss_channel chan,
                       void *val)
{
    const struct gnss_driver_api *api =
        (const struct gnss_driver_api *)dev->driver_api;

    return api->channel_get(dev, chan, val);
}

/**
 * @brief Enable the gnss module and set the enable handler
 *
 * This function initializes the GNSS core subsystem and enables the
 * corresponding hardware so that it can begin receiving
 * as well as generating interrupts.
 *
 * @param dev Pointer to the sensor device
 * @param status_cb Callback registered by user to notify
 *                      about USB device controller state.
 *
 * @return 0 if successful, negative errno code if failure.
 */
static inline int gnss_enable(struct device *dev,
                  gnss_status_callback_t status_cb)
{
    const struct gnss_driver_api *api =
        (const struct gnss_driver_api *)dev->driver_api;

    if (api->enable == NULL) {
        return -ENOTSUP;
    }

    return api->enable(dev, status_cb);
}

#ifdef __cplusplus
}
#endif

#include <syscalls/gnss.h>

#endif /* ZEPHYR_INCLUDE_DRIVERS_GNSS_H_ */
jukkar commented 3 years ago

I just wonder would it make sense to look how gpsd (https://gitlab.com/gpsd/gpsd) is interfacing to different GNSS providers. It has this gps_type_t API https://gitlab.com/gpsd/gpsd/-/blob/master/include/gpsd.h#L423 for that. See https://gitlab.com/gpsd/gpsd/-/tree/master/drivers for different drivers. I do not mean we would need to do things the same way as gpsd, but we need to make sure that our APIs are able to support all different GNSS providers.

sslupsky commented 3 years ago

I will have a look at that. I had done some prior work with the Sparkfun library which was my starting point.

sslupsky commented 3 years ago

@jukkar Have you used gpsd? I had a look and it looks quite good.

A couple observations:

  1. I am unsure about the weight of this. Does it require the network stack to be running? I think I saw that it uses sockets so I think networking is a requirement which increases the memory requirements significantly.
  2. The intro It says you can connect via serial or usb. Do you know if there are there other input sources? U-blox devices have an i2c interface as well as serial and usb. I am not sure which interfaces are available for the gps functions of the nRF9160. I think I recall that it is an AT style interface so presumably serial?
jukkar commented 3 years ago

I have used gpsd (but over 10 year ago). I would not want to use it in zephyr as is, but perhaps we can look how it interfaces to different chips as it has lot of supported GNSS providers. Your API looks reasonable but you mentioned it was developed according to u-blox GNSS. So would that API work with other GNSS providers?

sslupsky commented 3 years ago

@jukkar I agree, I think there are some good things to learn from the studying the gpsd library. I think the API above would be fine across other GNSS providers. We need to add additional protocols as the API only contemplates four at the moment:

    GNSS_SENTENCE_STATE_UBX,
    GNSS_SENTENCE_STATE_NMEA,
    GNSS_SENTENCE_STATE_RTCM,
    GNSS_SENTENCE_STATE_RTCM3,

We also need to understand how the existing and future solutions interface to the mcu. I think the majority use a serial uart. Some have USB. u-blox supports i2c but I do not know if anyone else does.

jukkar commented 3 years ago

Also cellular modems usually provide support for GNSS. For example GSM modems have GSM muxing implemented where one UART will provide multiple virtual channels to the caller, and the GNSS data is transferred in one of these channels. The muxed UART will look same as normal UART to the application so it should work ok.

beriberikix commented 3 years ago

@sslupsky I have only limited experience with GPS but the vast majority I've seen either use NMEA or UBX. I've never used RTCM but it seems to also be common and modern. Are there indeed other commonly used protocols than those 4 or is that good enough starting point?

@jukkar I believe this is also implied with your point but there are some modems that have an integrated GNSS and some that a dedicated interface as you described. To further add to the complexity, some have user-programmable application processors (though most need NDA'd permission) and some can only be interfaced via a host processor.

It might be worthwhile to pick a small subset of common standalone GNSS modules as well as GSM+GNSS modems as a starting point and plan to expand the design over time.

mfiumara commented 3 years ago

I have a quectel BG95 I could experiment with, would love to see this functionality added to Zephyr.

beriberikix commented 3 years ago

The BG95 would be a good one to target! Actually, many of the NB/Cat-M1 modules are based on the qcomm 9205, so picking one would provide good representation.

My personal reqs would be to start with:

RobMeades commented 3 years ago

Hi guys. For disclosure purposes, I'm from u-blox, though not the GNSS side (cellular). I am interested in this discussion because we have a C support library (I'd call it a "hopefully useful lump of well-tested code") for our cellular, Wifi, BLE and soon GNSS modules and I'd like it to be compatible with this API.

A very quick scan suggests that the proposal above is fine, though since it comes originally from support for a u-blox GNSS chip I guess that will be no surprise :-). Some comments:

  1. Might we want the user to have control over the size/location of this internal sample buffer? Could be better to let them pass this in, then it can be static/malloc()'ed/stuck-in-some-bit-of-RAM-they-found-spare-from-an-unused-DMA-buffer, etc. Or does the generic Zephyr dev thingy allow this?
  2. As is mentioned above, GNSS devices can often be hidden behind other devices: for instance, many of our customers connect the GNSS chip to one of our cellular modules and then talk to it through that, allowing synergy with cellular-based positioning that is not otherwise possible. Effectively the [in our case] UBX messages from the host get passed transparently through an AT interface and are muxed in the cellular module with messages from the cellular device itself. So it would be sensible if the message-level interface within the above was clearly available for such arrangements, though I suppose that could be done on a device-specific basis.
  3. Assistance information: time to first fix may be significantly reduced through provision of assistance information (current time or approximate position or satellite metadata from a previous session, allowing the GNSS chip to find satellites more quickly). While this might not be included right now, it would be worth thinking about how it would be added to the API.
  4. Looking to the future, this is obviously a GNSS API but parts of it are common with a more abstract "Location" API. For instance, location can be achieved via cellular (alone or with GNSS), most recently BLE, etc. Does such a "Location" API exist within Zephyr and, if not, do we want to sketch out what it might look like in order to at least put the abstracted types in the right place?
jukkar commented 3 years ago

Hi @RobMeades

couple of random comments to your questions:

Anyway, it would be nice to see a PR in review, so just propose something if you have the code and we can then start to comment it.

avigreen1978 commented 3 years ago

The GNSS API in zephyr is really desired. What's the current status of that?

carlescufi commented 3 years ago

@avigreen1978 as usual with open source work, someone needs to send an RFC Pull Request so we can start considering it for addition to the tree.

allen-k-liu commented 3 years ago

@sslupsky I'm trying to adopt gnss api for our zephyr porting on silab pg board. do you have any suggestion or any reference that we can work on? Thanks!

sslupsky commented 3 years ago

@allen-k-liu I built an API using the header I posted above and implemented a driver for a u-blox gnss device (SAM-M8Q). The driver and API work for my use case but it is not a complete solution. I am a couple zephyr versions behind so the code needs to be rebased to work with the most recent release of Zephyr. If someone was interested to collaborate on the code development it might make sense for me to generate an RFC PR and use my code as a starting point.

allen-k-liu commented 3 years ago

thanks a lot @sslupsky ! I'm interested to do so. We original planed to use u-blox m8q but probably will switch to sony's cxd5605. I'm not familiar with RFC PR, is it something you will summit to zephyr to merge to main line?

sslupsky commented 3 years ago

@allen-k-liu I had a look at the PG board: https://www.silabs.com/documents/public/user-guides/ug474-pg22-dk2503a-user-guide.pdf

does this board have gnss capability?

allen-k-liu commented 3 years ago

@sslupsky i just did quick scan, i don't see it. I used efm32pg12 (stk3402a) that zephyr has supported. But I haven't figure out where to insert gps module. probably under zephyr/module/gps/

allen-k-liu commented 3 years ago

@sslupsky Would you mind if you can share your gnss project branch so I can base on that to not go too far off? Thanks a lot!

sslupsky commented 2 years ago

@allen-k-liu I posted all my out-of-tree zephyr stuff here: https://github.com/sslupsky/zephyr-out-of-tree

bperseghetti commented 1 year ago

Is there a good way we can "revive" the evaluation of this RFC?

bjarki-andreasen commented 8 months ago

We now have a vendor agnostic GNSS API supporting both Quectel and Ublox, and should support Nordic as well, included from release 3.6 If there is some request in this RFC that is still relevant, please reopen this issue and we can take it from there

beriberikix commented 8 months ago

Linking the documentation here so others can find it in the future :)

bperseghetti commented 8 months ago

@bjarki-trackunit @beriberikix are there any thoughts on extending this to include RTCM3 corrections?

bperseghetti commented 8 months ago

If not yet should this be re-opened or a new one opened?

bjarki-andreasen commented 8 months ago

@bperseghetti That would require a new RFC :)