diff --git a/docs/Settings.md b/docs/Settings.md index 6d7169b7c5b..ec0f68785e2 100644 --- a/docs/Settings.md +++ b/docs/Settings.md @@ -2048,6 +2048,16 @@ Enable use of Glonass satellites. This is at the expense of other regional const --- +### gps_ublox_use_navic + +Enable use of NavIC satellites, the Indian regional system, on receivers that have it, such as the u-blox F10. They are only visible over India and the region around it. Receivers without NavIC ignore this setting [OFF/ON]. + +| Default | Min | Max | +| --- | --- | --- | +| OFF | OFF | ON | + +--- + ### ground_test_mode For developer ground test use. Disables motors, sets heading status = Trusted on FW. diff --git a/docs/development/msp/README.md b/docs/development/msp/README.md index 42634e951db..53e53b58bdb 100644 --- a/docs/development/msp/README.md +++ b/docs/development/msp/README.md @@ -2333,6 +2333,12 @@ When the MSP JSON specification changes, bump `msp_messages.json` version: | `eph` | `uint16_t` | 2 | cm | Estimated Horizontal Position Accuracy (`gpsSol.eph`) | | `epv` | `uint16_t` | 2 | cm | Estimated Vertical Position Accuracy (`gpsSol.epv`) | | `hwVersion` | `uint8_t` | 1 | - | GPS hardware version bit-field: bits[7:6]=series (0b01=u-blox Neo/M), bits[5:0]=generation. E.g. 0x48=M8, 0x49=M9, 0x4A=M10, 0=unknown. | +| `supportedGnss` | `uint8_t` | 1 | Bitmask | Bitmask: major constellations the receiver reports in UBX-MON-GNSS: Bit 0=GPS, Bit 1=GLONASS, Bit 2=BeiDou, Bit 3=Galileo. 0 if the receiver has not reported them, or the provider is not u-blox | +| `enabledGnss` | `uint8_t` | 1 | Bitmask | Bitmask: which of those constellations the receiver says are running. Same bit order as `supportedGnss` | +| `extendedGnss` | `uint8_t` | 1 | Bitmask | Bitmask: augmentation and regional systems listed in the UBX-MON-VER extensions, which UBX-MON-GNSS does not carry: Bit 0=SBAS, Bit 1=QZSS, Bit 2=NavIC | +| `maxGnss` | `uint8_t` | 1 | Count | How many major constellations the receiver can track at the same time, as reported by UBX-MON-GNSS. 0 if unknown | +| `moduleNameLength` | `uint8_t` | 1 | - | Length of the module name string that follows. 0 if the receiver does not report one | +| `moduleName` | `char[]` | array | - | Module name as the receiver reports it in the UBX-MON-VER extensions (e.g., "NEO-M10N"). Length given by previous field | **Notes:** Requires `USE_GPS`. diff --git a/docs/development/msp/msp_messages.json b/docs/development/msp/msp_messages.json index 97a8ab9f185..4d1ad0688fb 100644 --- a/docs/development/msp/msp_messages.json +++ b/docs/development/msp/msp_messages.json @@ -1,8 +1,8 @@ { "version": { "major": 2, - "minor": 1, - "patch": 1 + "minor": 2, + "patch": 0 }, "messages": { "MSP_API_VERSION": { @@ -4923,6 +4923,47 @@ "ctype": "uint8_t", "desc": "GPS hardware version bit-field: bits[7:6]=series (0b01=u-blox Neo/M), bits[5:0]=generation. E.g. 0x48=M8, 0x49=M9, 0x4A=M10, 0=unknown.", "units": "" + }, + { + "name": "supportedGnss", + "ctype": "uint8_t", + "desc": "Bitmask: major constellations the receiver reports in UBX-MON-GNSS: Bit 0=GPS, Bit 1=GLONASS, Bit 2=BeiDou, Bit 3=Galileo. 0 if the receiver has not reported them, or the provider is not u-blox", + "units": "Bitmask", + "bitmask": true + }, + { + "name": "enabledGnss", + "ctype": "uint8_t", + "desc": "Bitmask: which of those constellations the receiver says are running. Same bit order as `supportedGnss`", + "units": "Bitmask", + "bitmask": true + }, + { + "name": "extendedGnss", + "ctype": "uint8_t", + "desc": "Bitmask: augmentation and regional systems listed in the UBX-MON-VER extensions, which UBX-MON-GNSS does not carry: Bit 0=SBAS, Bit 1=QZSS, Bit 2=NavIC", + "units": "Bitmask", + "bitmask": true + }, + { + "name": "maxGnss", + "ctype": "uint8_t", + "desc": "How many major constellations the receiver can track at the same time, as reported by UBX-MON-GNSS. 0 if unknown", + "units": "Count" + }, + { + "name": "moduleNameLength", + "ctype": "uint8_t", + "desc": "Length of the module name string that follows. 0 if the receiver does not report one", + "units": "" + }, + { + "name": "moduleName", + "desc": "Module name as the receiver reports it in the UBX-MON-VER extensions (e.g., \"NEO-M10N\"). Length given by previous field", + "ctype": "char", + "array": true, + "array_size": 0, + "units": "" } ] }, diff --git a/src/main/fc/fc_msp.c b/src/main/fc/fc_msp.c index d00984f2d85..ebb34700237 100644 --- a/src/main/fc/fc_msp.c +++ b/src/main/fc/fc_msp.c @@ -1070,6 +1070,22 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF sbufWriteU16(dst, gpsSol.eph); sbufWriteU16(dst, gpsSol.epv); sbufWriteU8(dst, gpsState.hwVersion); + // Which constellations the receiver has, and which of them are running, so the + // configurator can stop offering the ones that are not there. Zero means unknown + sbufWriteU8(dst, isGpsUblox() ? gpsUbloxSupportedGnss() : 0); + sbufWriteU8(dst, isGpsUblox() ? gpsUbloxEnabledGnss() : 0); + // SBAS, QZSS and NavIC, which MON-GNSS does not report, and how many major + // constellations the receiver can run at once + sbufWriteU8(dst, isGpsUblox() ? gpsUbloxExtendedGnss() : 0); + sbufWriteU8(dst, isGpsUblox() ? gpsUbloxMaxGnss() : 0); + // The module's own name, as it reports it, so the configurator can say which + // receiver this is instead of guessing from the hardware version + { + const char * module = isGpsUblox() ? gpsUbloxModuleName() : ""; + const uint8_t len = strlen(module); + sbufWriteU8(dst, len); + sbufWriteData(dst, module, len); + } break; #endif case MSP2_ADSB_VEHICLE_LIST: diff --git a/src/main/fc/settings.yaml b/src/main/fc/settings.yaml index f805e60d658..84c0299fd3a 100644 --- a/src/main/fc/settings.yaml +++ b/src/main/fc/settings.yaml @@ -1874,6 +1874,11 @@ groups: default_value: OFF field: ubloxUseGlonass type: bool + - name: gps_ublox_use_navic + description: "Enable use of NavIC satellites, the Indian regional system, on receivers that have it, such as the u-blox F10. They are only visible over India and the region around it. Receivers without NavIC ignore this setting [OFF/ON]." + default_value: OFF + field: ubloxUseNavic + type: bool - name: gps_min_sats description: "Minimum number of GPS satellites in view to acquire GPS_FIX and consider GPS position valid. Some GPS receivers appeared to be very inaccurate with low satellite count." default_value: 6 diff --git a/src/main/io/gps.c b/src/main/io/gps.c index 3d2afe754b4..1e06eb5c6ef 100755 --- a/src/main/io/gps.c +++ b/src/main/io/gps.c @@ -146,7 +146,8 @@ PG_RESET_TEMPLATE(gpsConfig_t, gpsConfig, .ubloxUseBeidou = SETTING_GPS_UBLOX_USE_BEIDOU_DEFAULT, .ubloxUseGlonass = SETTING_GPS_UBLOX_USE_GLONASS_DEFAULT, .ubloxNavHz = SETTING_GPS_UBLOX_NAV_HZ_DEFAULT, - .autoBaudMax = SETTING_GPS_AUTO_BAUD_MAX_SUPPORTED_DEFAULT + .autoBaudMax = SETTING_GPS_AUTO_BAUD_MAX_SUPPORTED_DEFAULT, + .ubloxUseNavic = SETTING_GPS_UBLOX_USE_NAVIC_DEFAULT ); int gpsBaudRateToInt(gpsBaudRate_e baudrate) diff --git a/src/main/io/gps.h b/src/main/io/gps.h index ec531a5c6ba..b5c79008c7d 100755 --- a/src/main/io/gps.h +++ b/src/main/io/gps.h @@ -106,6 +106,7 @@ typedef struct gpsConfig_s { uint8_t gpsMinSats; uint8_t ubloxNavHz; gpsBaudRate_e autoBaudMax; + bool ubloxUseNavic; } gpsConfig_t; PG_DECLARE(gpsConfig_t, gpsConfig); diff --git a/src/main/io/gps_ublox.c b/src/main/io/gps_ublox.c index 703242d10dd..9851404b50e 100755 --- a/src/main/io/gps_ublox.c +++ b/src/main/io/gps_ublox.c @@ -87,6 +87,12 @@ static const char * baudInitDataNMEA[GPS_BAUDRATE_COUNT] = { static ubx_nav_sig_info satelites[UBLOX_MAX_SIGNALS] = {}; +// The module name from the MON-VER extensions, as in MOD=NEO-F10N. Empty when not reported +static char ubxModuleName[UBLOX_MODULE_NAME_LEN] = ""; + +// SBAS, QZSS and NavIC, which the receiver lists in MON-VER but not in MON-GNSS +static uint8_t ubxExtendedGnss = 0; + // MON-RF noise value (noisePerMS) reported by UBX-MON-RF as U2 at payload offset 0x10 static uint16_t monRfNoisePerMs = 0; static uint16_t monAgcCount = 0; @@ -215,6 +221,27 @@ uint8_t gpsUbloxMaxGnss(void) return ubx_capabilities.capMaxGnss; } +// The MON-GNSS masks as the receiver reports them: bit 0 GPS, 1 Glonass, 2 Beidou, 3 Galileo +uint8_t gpsUbloxSupportedGnss(void) +{ + return ubx_capabilities.supported; +} + +uint8_t gpsUbloxEnabledGnss(void) +{ + return ubx_capabilities.enabledGnss; +} + +const char * gpsUbloxModuleName(void) +{ + return ubxModuleName; +} + +uint8_t gpsUbloxExtendedGnss(void) +{ + return ubxExtendedGnss; +} + timeMs_t gpsUbloxCapLastUpdate(void) { return gpsState.lastCapaUpdMs; @@ -445,6 +472,18 @@ static int configureGNSS_GLONASS(ubx_gnss_element_t * gnss_block) return 1; } +// NavIC goes out on its own. Its keys exist only on receivers that have it, and +// one key a receiver does not know makes it refuse the whole message +static void configureNAVIC(void) +{ + ubx_config_data8_payload_t navicValues[] = { + {UBLOX_CFG_NAVIC_ENA, gpsState.gpsConfig->ubloxUseNavic}, + {UBLOX_CFG_NAVIC_L5_ENA, gpsState.gpsConfig->ubloxUseNavic} + }; + + ubloxSendSetCfgBytes(navicValues, 2); +} + static void configureGNSS10(void) { ubx_config_data8_payload_t gnssConfigValues[] = { @@ -765,6 +804,31 @@ static bool gpsParseFrameUBLOX(void) break; } } + + // Whole extensions only: a frame whose length is not a round number + // of them would have its last line read past the payload + for (int j = 40; j + 30 <= _payload_length; j += 30) { + const char * line = (const char *)(_buffer.bytes + j); + + const char * mod = strnstr(line, "MOD=", 30); + if (mod) { + const char * name = mod + 4; + const size_t room = (size_t)(line + 30 - name); + strncpy(ubxModuleName, name, MIN(room, (size_t)(UBLOX_MODULE_NAME_LEN - 1))); + ubxModuleName[UBLOX_MODULE_NAME_LEN - 1] = '\0'; + } + + // The augmentation and regional systems, which MON-GNSS does not carry + if (strnstr(line, "SBAS", 30)) { + ubxExtendedGnss |= UBLOX_EXT_GNSS_SBAS; + } + if (strnstr(line, "QZSS", 30)) { + ubxExtendedGnss |= UBLOX_EXT_GNSS_QZSS; + } + if (strnstr(line, "NAVIC", 30)) { + ubxExtendedGnss |= UBLOX_EXT_GNSS_NAVIC; + } + } } } break; @@ -1171,6 +1235,14 @@ STATIC_PROTOTHREAD(gpsConfigure) gpsConfigMutable()->ubloxUseBeidou = SETTING_GPS_UBLOX_USE_BEIDOU_DEFAULT; gpsConfigMutable()->ubloxUseGlonass = SETTING_GPS_UBLOX_USE_GLONASS_DEFAULT; } + + // Only a receiver that lists NavIC gets its keys, and only through the + // configuration interface, which is where those keys live + if (ubloxVersionGT(23, 1) && (ubxExtendedGnss & UBLOX_EXT_GNSS_NAVIC)) { + gpsSetProtocolTimeout(GPS_SHORT_TIMEOUT); + configureNAVIC(); + ptWaitTimeout((_ack_state == UBX_ACK_GOT_ACK || _ack_state == UBX_ACK_GOT_NAK), GPS_CFG_CMD_TIMEOUT_MS); + } } for(int i = 0; i < UBLOX_MAX_SIGNALS; ++i) @@ -1250,6 +1322,8 @@ STATIC_PROTOTHREAD(gpsProtocolStateThread) // Attempt to detect GPS hw version gpsState.hwVersion = UBX_HW_VERSION_UNKNOWN; + ubxModuleName[0] = '\0'; + ubxExtendedGnss = 0; gpsState.autoConfigStep = 0; // Configure GPS module if enabled @@ -1261,7 +1335,10 @@ STATIC_PROTOTHREAD(gpsProtocolStateThread) } while(gpsState.autoConfigStep < GPS_VERSION_RETRY_TIMES && gpsState.hwVersion == UBX_HW_VERSION_UNKNOWN); gpsState.autoConfigStep = 0; + // The limit goes with them: left over from a receiver that has been swapped out + // it would end the poll below before the new one has answered ubx_capabilities.supported = ubx_capabilities.enabledGnss = ubx_capabilities.defaultGnss = 0; + ubx_capabilities.capMaxGnss = 0; // M7 and earlier will never get pass this step, so skip it (#9440). // UBLOX documents that this is M8N and later if (gpsState.hwVersion > UBX_HW_VERSION_UBLOX7) { diff --git a/src/main/io/gps_ublox.h b/src/main/io/gps_ublox.h index 75f10901035..bd6b4669db8 100644 --- a/src/main/io/gps_ublox.h +++ b/src/main/io/gps_ublox.h @@ -119,6 +119,10 @@ STATIC_ASSERT(MAX_UBLOX_PAYLOAD_SIZE >= 256, ubx_size_too_small); #define UBLOX_CFG_GLO_ENA 0x10310025 // U1 default off - may conflict with other constelations #define UBLOX_CFG_GLO_L1_ENA 0x10310018 // U1 default off +// Only on receivers that list NAVIC in their MON-VER extensions, such as the F10 +#define UBLOX_CFG_NAVIC_ENA 0x10310026 // U1 default off +#define UBLOX_CFG_NAVIC_L5_ENA 0x1031001d // U1 default off + #define UBLOX_CFG_SBAS_PRNSCANMASK 0x50360006 // 0 = auto // X8 #define UBLOX_SBAS_ALL 0x0000000000000000 //Enable search for all SBAS PRNs #define UBLOX_SBAS_PRN120 0x0000000000000001 //Enable search for SBAS PRN120 @@ -535,7 +539,21 @@ typedef enum { NAV_STATUS_FIX_VALID = 1 } ubx_nav_status_bits_t; +// Long enough for the names u-blox ships, such as NEO-F10N and ZED-F9P +#define UBLOX_MODULE_NAME_LEN 16 + +/* The augmentation and regional systems a receiver lists in its MON-VER extensions. + * UBX-MON-GNSS only reports the four major constellations, so these come from the + * version strings instead, where the list reads SBAS;QZSS and NAVIC. */ +#define UBLOX_EXT_GNSS_SBAS (1 << 0) +#define UBLOX_EXT_GNSS_QZSS (1 << 1) +#define UBLOX_EXT_GNSS_NAVIC (1 << 2) + uint8_t gpsUbloxMaxGnss(void); +uint8_t gpsUbloxSupportedGnss(void); +uint8_t gpsUbloxEnabledGnss(void); +const char * gpsUbloxModuleName(void); +uint8_t gpsUbloxExtendedGnss(void); timeMs_t gpsUbloxCapLastUpdate(void); bool gpsUbloxHasGalileo(void);