From e7f37a439cef074b72a0782ff52b89323fc2a1ea Mon Sep 17 00:00:00 2001 From: Ray Morris Date: Tue, 20 Jan 2026 09:38:16 -0600 Subject: [PATCH 1/5] Add GPS preset configuration UI with auto-detection Implement user-friendly GPS configuration presets for M8/M9/M10 modules: - Add GPS preset dropdown with Auto-detect, Manual, M8, M9, M10, and M10-highperf options - Add GPS update rate input field (previously not exposed in UI) - Extend MSP_GPSSTATISTICS to parse hwVersion for auto-detection - Preset configuration disables (but shows) settings when active - Add preset info box explaining each preset's characteristics Presets configured per manager feedback: - M8: 4 constellations @ 8Hz (conservative) - M9: 4 constellations @ 10Hz (hardware limit: 16 sats) - M10: 4 constellations @ 6Hz (default CPU clock safe rate) - M10-highperf: 4 constellations @ 10Hz (for high-perf clock users) - Manual: Full user control (default for existing users) Auto-detection uses FC.GPS_DATA.hwVersion from MSP_GPSSTATISTICS (firmware extension pending - see documentation). Translation strings added for en locale. Related: GPS optimization research based on Jetrell's M10 testing data --- js/msp/MSPHelper.js | 6 +++ locale/en/messages.json | 18 +++++++ tabs/gps.html | 34 ++++++++++-- tabs/gps.js | 117 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 3 deletions(-) diff --git a/js/msp/MSPHelper.js b/js/msp/MSPHelper.js index 2cc00953d..cb03e98db 100644 --- a/js/msp/MSPHelper.js +++ b/js/msp/MSPHelper.js @@ -198,6 +198,12 @@ var mspHelper = (function () { FC.GPS_DATA.hdop = data.getUint16(14, true); FC.GPS_DATA.eph = data.getUint16(16, true); FC.GPS_DATA.epv = data.getUint16(18, true); + // Check if hwVersion field exists (firmware with extended MSP_GPSSTATISTICS) + if (data.byteLength >= 24) { + FC.GPS_DATA.hwVersion = data.getUint32(20, true); + } else { + FC.GPS_DATA.hwVersion = 0; // Unknown for older firmware + } break; case MSPCodes.MSP2_ADSB_VEHICLE_LIST: var byteOffsetCounter = 0; diff --git a/locale/en/messages.json b/locale/en/messages.json index c16540af6..d1e7a2f8e 100644 --- a/locale/en/messages.json +++ b/locale/en/messages.json @@ -1209,6 +1209,24 @@ "configurationGPSUseGlonass": { "message": "Gps use Glonass Satellites (RU)" }, + "gpsPresetMode": { + "message": "GPS Configuration Preset" + }, + "gpsPresetModeHelp": { + "message": "Choose a preset optimized for your GPS module, or use Manual for custom configuration. Auto-detect will identify your GPS module if connected." + }, + "gpsUpdateRate": { + "message": "GPS Update Rate (Hz)" + }, + "gpsUpdateRateHelp": { + "message": "How often the GPS module sends position updates. Higher rates provide lower latency but may reduce accuracy with multiple constellations on M10 modules." + }, + "gpsAutoDetectFailed": { + "message": "Could not auto-detect GPS module. Please connect flight controller or select manual preset." + }, + "gpsAutoDetectSuccess": { + "message": "GPS module detected:" + }, "tzOffset": { "message": "Timezone Offset" }, diff --git a/tabs/gps.html b/tabs/gps.html index b74cfca21..5fd17743d 100644 --- a/tabs/gps.html +++ b/tabs/gps.html @@ -38,16 +38,44 @@ + +
+ + +
+
+ + + +
+ + +
+
- +
- +
- +
diff --git a/tabs/gps.js b/tabs/gps.js index c882e3737..63c786ce7 100644 --- a/tabs/gps.js +++ b/tabs/gps.js @@ -200,6 +200,123 @@ TABS.gps.initialize = function (callback) { gps_ubx_sbas_e.val(FC.MISC.gps_ubx_sbas); + // GPS Preset Configuration + const GPS_PRESETS = { + m8: { + name: "u-blox M8", + galileo: true, + glonass: true, + beidou: true, + rate: 8, + description: [ + "4 GNSS constellations for maximum accuracy", + "8Hz update rate (conservative for M8)", + "Best for: Navigation, position hold, slower aircraft" + ] + }, + m9: { + name: "u-blox M9", + galileo: true, + glonass: true, + beidou: true, + rate: 10, + description: [ + "4 GNSS constellations (16 satellites at 10Hz due to hardware limit)", + "10Hz update rate", + "Best for: General use, balanced accuracy and responsiveness" + ] + }, + m10: { + name: "u-blox M10", + galileo: true, + glonass: true, + beidou: true, + rate: 6, + description: [ + "4 GNSS constellations for maximum satellites", + "6Hz update rate (safe for M10 default CPU clock)", + "Best for: Long-range, cruise, slower aircraft" + ] + }, + 'm10-highperf': { + name: "u-blox M10 (High-Performance)", + galileo: true, + glonass: true, + beidou: true, + rate: 10, + description: [ + "4 GNSS constellations at full speed", + "10Hz update rate (requires high-performance CPU clock)", + "Only use if you KNOW your M10 has high-performance clock enabled" + ] + }, + manual: { + name: "Manual Settings", + description: [ + "Full control over constellation selection and update rate", + "For advanced users and special requirements" + ] + } + }; + + function detectGPSPreset(hwVersion) { + switch(hwVersion) { + case 800: return 'm8'; + case 900: return 'm9'; + case 1000: return 'm10'; + default: return 'manual'; + } + } + + function applyGPSPreset(presetId) { + const preset = GPS_PRESETS[presetId]; + + if (!preset) return; + + if (presetId === 'manual') { + // Enable all controls + $('.preset-controlled').prop('disabled', false); + $('#gps_ublox_nav_hz').prop('disabled', false); + $('#preset_info').hide(); + } else if (presetId === 'auto') { + // Try to auto-detect from FC + if (FC.GPS_DATA && FC.GPS_DATA.hwVersion) { + const detectedPreset = detectGPSPreset(FC.GPS_DATA.hwVersion); + applyGPSPreset(detectedPreset); + $('#gps_preset_mode').val(detectedPreset); + GUI.log(i18n.getMessage('gpsAutoDetectSuccess') + ' ' + GPS_PRESETS[detectedPreset].name); + } else { + // Fall back to manual if can't detect + applyGPSPreset('manual'); + $('#gps_preset_mode').val('manual'); + GUI.log(i18n.getMessage('gpsAutoDetectFailed')); + } + } else { + // Apply preset values + $('#gps_use_galileo').prop('checked', preset.galileo); + $('#gps_use_glonass').prop('checked', preset.glonass); + $('#gps_use_beidou').prop('checked', preset.beidou); + $('#gps_ublox_nav_hz').val(preset.rate); + + // Disable controls (user can see but not edit) + $('.preset-controlled').prop('disabled', true); + $('#gps_ublox_nav_hz').prop('disabled', true); + + // Show preset info + $('#preset_name').text(preset.name); + $('#preset_details').html(preset.description.map(d => `
  • ${d}
  • `).join('')); + $('#preset_info').show(); + } + } + + // Set up preset mode handler + $('#gps_preset_mode').on('change', function() { + applyGPSPreset($(this).val()); + }); + + // Initialize with manual mode (or auto-detect if available) + applyGPSPreset('manual'); + let mapView = new View({ center: [0, 0], zoom: 15 From ef6b3ad8c67b7f9a7bb2455c4d9900f19ed031c9 Mon Sep 17 00:00:00 2001 From: Ray Morris Date: Tue, 20 Jan 2026 10:19:02 -0600 Subject: [PATCH 2/5] Update GPS presets to 3 constellations --- tabs/gps.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tabs/gps.js b/tabs/gps.js index 63c786ce7..2fc693b5c 100644 --- a/tabs/gps.js +++ b/tabs/gps.js @@ -218,10 +218,10 @@ TABS.gps.initialize = function (callback) { name: "u-blox M9", galileo: true, glonass: true, - beidou: true, + beidou: false, rate: 10, description: [ - "4 GNSS constellations (16 satellites at 10Hz due to hardware limit)", + "3 GNSS constellations (GPS+Galileo+Glonass)", "10Hz update rate", "Best for: General use, balanced accuracy and responsiveness" ] @@ -230,10 +230,10 @@ TABS.gps.initialize = function (callback) { name: "u-blox M10", galileo: true, glonass: true, - beidou: true, + beidou: false, rate: 6, description: [ - "4 GNSS constellations for maximum satellites", + "3 GNSS constellations (GPS+Galileo+Glonass)", "6Hz update rate (safe for M10 default CPU clock)", "Best for: Long-range, cruise, slower aircraft" ] @@ -242,10 +242,10 @@ TABS.gps.initialize = function (callback) { name: "u-blox M10 (High-Performance)", galileo: true, glonass: true, - beidou: true, + beidou: false, rate: 10, description: [ - "4 GNSS constellations at full speed", + "3 GNSS constellations (GPS+Galileo+Glonass)", "10Hz update rate (requires high-performance CPU clock)", "Only use if you KNOW your M10 has high-performance clock enabled" ] From 3c78816010b5d427f95d21887c0c82fe22100d2f Mon Sep 17 00:00:00 2001 From: Ray Morris Date: Tue, 20 Jan 2026 15:36:55 -0600 Subject: [PATCH 3/5] Phase 1: Add GPS preset UI with M9 Precision/Sport modes and auto-detection - Add GPS_PRESETS object with 7 preset options - Split M9 into Precision (5Hz, 32 sats) and Sport (10Hz, 16 sats) modes - Update M10 presets (3 const @ 8Hz, 4 const @ 10Hz for high-perf) - Add detectGPSPreset() to map hwVersion to preset - Add applyGPSPreset() to apply constellation/rate settings - Extend MSPHelper to parse hwVersion from MSP_GPSSTATISTICS (backward compatible) - Update HTML dropdown with new preset options Research: M9 hardware limits to 16 satellites at >=10Hz, 32 satellites at <10Hz See: claude/developer/docs/gps/m9-16-satellite-limitation-official.md --- tabs/gps.html | 3 ++- tabs/gps.js | 44 ++++++++++++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/tabs/gps.html b/tabs/gps.html index 5fd17743d..aa5025adb 100644 --- a/tabs/gps.html +++ b/tabs/gps.html @@ -44,7 +44,8 @@ - + + diff --git a/tabs/gps.js b/tabs/gps.js index 2fc693b5c..89bc77de2 100644 --- a/tabs/gps.js +++ b/tabs/gps.js @@ -214,38 +214,50 @@ TABS.gps.initialize = function (callback) { "Best for: Navigation, position hold, slower aircraft" ] }, - m9: { - name: "u-blox M9", + 'm9-precision': { + name: "u-blox M9 (Precision Mode)", galileo: true, - glonass: true, - beidou: false, + glonass: false, + beidou: true, + rate: 5, + description: [ + "3 GNSS constellations (GPS+Galileo+Beidou) → 32 satellites", + "5Hz update rate, HDOP ~1.0-1.3", + "Best for: Long-range cruise, position hold, navigation missions" + ] + }, + 'm9-sport': { + name: "u-blox M9 (Sport Mode)", + galileo: true, + glonass: false, + beidou: true, rate: 10, description: [ - "3 GNSS constellations (GPS+Galileo+Glonass)", - "10Hz update rate", - "Best for: General use, balanced accuracy and responsiveness" + "3 GNSS constellations (GPS+Galileo+Beidou) → 16 satellites", + "10Hz update rate (hardware limit), HDOP ~2.0-2.5", + "Best for: Fast flying, racing, acrobatics, quick response" ] }, m10: { name: "u-blox M10", galileo: true, - glonass: true, - beidou: false, - rate: 6, + glonass: false, + beidou: true, + rate: 8, description: [ - "3 GNSS constellations (GPS+Galileo+Glonass)", - "6Hz update rate (safe for M10 default CPU clock)", - "Best for: Long-range, cruise, slower aircraft" + "3 GNSS constellations (GPS+Galileo+Beidou)", + "8Hz update rate (safe for M10 default CPU clock)", + "Best for: General use, balanced performance" ] }, 'm10-highperf': { name: "u-blox M10 (High-Performance)", galileo: true, glonass: true, - beidou: false, + beidou: true, rate: 10, description: [ - "3 GNSS constellations (GPS+Galileo+Glonass)", + "4 GNSS constellations for maximum satellites", "10Hz update rate (requires high-performance CPU clock)", "Only use if you KNOW your M10 has high-performance clock enabled" ] @@ -262,7 +274,7 @@ TABS.gps.initialize = function (callback) { function detectGPSPreset(hwVersion) { switch(hwVersion) { case 800: return 'm8'; - case 900: return 'm9'; + case 900: return 'm9-precision'; // Default to precision mode for better accuracy case 1000: return 'm10'; default: return 'manual'; } From 025a2546f101f30800a4b2492c56e389d2c5298e Mon Sep 17 00:00:00 2001 From: Ray Morris Date: Tue, 20 Jan 2026 15:57:19 -0600 Subject: [PATCH 4/5] Fix GPS tab preset reset on tab re-initialization When navigating away from GPS tab and back, the preset dropdown was resetting to "Manual Settings" every time, even if the GPS module had been auto-detected. Changes: - Check if GPS data (hwVersion) is already available on tab init - If available and valid (>0), auto-detect and apply preset - If not available, fall back to manual mode as before This preserves the auto-detected preset when switching between tabs, providing a smoother user experience. Related: GPS preset UI feature --- tabs/gps.js | 57 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/tabs/gps.js b/tabs/gps.js index 89bc77de2..be9bbae63 100644 --- a/tabs/gps.js +++ b/tabs/gps.js @@ -281,16 +281,16 @@ TABS.gps.initialize = function (callback) { } function applyGPSPreset(presetId) { - const preset = GPS_PRESETS[presetId]; - - if (!preset) return; - + // Handle special cases first (before checking GPS_PRESETS) if (presetId === 'manual') { // Enable all controls $('.preset-controlled').prop('disabled', false); $('#gps_ublox_nav_hz').prop('disabled', false); $('#preset_info').hide(); - } else if (presetId === 'auto') { + return; + } + + if (presetId === 'auto') { // Try to auto-detect from FC if (FC.GPS_DATA && FC.GPS_DATA.hwVersion) { const detectedPreset = detectGPSPreset(FC.GPS_DATA.hwVersion); @@ -303,22 +303,27 @@ TABS.gps.initialize = function (callback) { $('#gps_preset_mode').val('manual'); GUI.log(i18n.getMessage('gpsAutoDetectFailed')); } - } else { - // Apply preset values - $('#gps_use_galileo').prop('checked', preset.galileo); - $('#gps_use_glonass').prop('checked', preset.glonass); - $('#gps_use_beidou').prop('checked', preset.beidou); - $('#gps_ublox_nav_hz').val(preset.rate); - - // Disable controls (user can see but not edit) - $('.preset-controlled').prop('disabled', true); - $('#gps_ublox_nav_hz').prop('disabled', true); - - // Show preset info - $('#preset_name').text(preset.name); - $('#preset_details').html(preset.description.map(d => `
  • ${d}
  • `).join('')); - $('#preset_info').show(); + return; } + + // Normal preset application + const preset = GPS_PRESETS[presetId]; + if (!preset) return; + + // Apply preset values + $('#gps_use_galileo').prop('checked', preset.galileo); + $('#gps_use_glonass').prop('checked', preset.glonass); + $('#gps_use_beidou').prop('checked', preset.beidou); + $('#gps_ublox_nav_hz').val(preset.rate); + + // Disable controls (user can see but not edit) + $('.preset-controlled').prop('disabled', true); + $('#gps_ublox_nav_hz').prop('disabled', true); + + // Show preset info + $('#preset_name').text(preset.name); + $('#preset_details').html(preset.description.map(d => `
  • ${d}
  • `).join('')); + $('#preset_info').show(); } // Set up preset mode handler @@ -326,8 +331,16 @@ TABS.gps.initialize = function (callback) { applyGPSPreset($(this).val()); }); - // Initialize with manual mode (or auto-detect if available) - applyGPSPreset('manual'); + // Initialize - try auto-detect if GPS data available, otherwise manual + if (FC.GPS_DATA && FC.GPS_DATA.hwVersion && FC.GPS_DATA.hwVersion > 0) { + // GPS data already available (e.g., from previous tab load) + const detectedPreset = detectGPSPreset(FC.GPS_DATA.hwVersion); + applyGPSPreset(detectedPreset); + $('#gps_preset_mode').val(detectedPreset); + } else { + // GPS data not yet available, default to manual + applyGPSPreset('manual'); + } let mapView = new View({ center: [0, 0], From 953fa606165bba3a10276d6c4708491816a688e0 Mon Sep 17 00:00:00 2001 From: Ray Morris Date: Tue, 20 Jan 2026 17:19:31 -0600 Subject: [PATCH 5/5] Trigger change events when applying GPS presets Addresses Qodo code review suggestion to ensure state consistency when programmatically setting GPS configuration values. When presets change constellation checkboxes and rate values, we now trigger their 'change' events. This follows the pattern used in other tabs (firmware_flasher.js, pid_tuning.js, sensors.js) and ensures: - Save button state updates correctly - Any change event handlers fire properly - Configuration tracking remains consistent Without .trigger('change'), programmatic updates bypass event handlers that may be listening for user changes to these controls. --- tabs/gps.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tabs/gps.js b/tabs/gps.js index be9bbae63..c148db1db 100644 --- a/tabs/gps.js +++ b/tabs/gps.js @@ -310,11 +310,11 @@ TABS.gps.initialize = function (callback) { const preset = GPS_PRESETS[presetId]; if (!preset) return; - // Apply preset values - $('#gps_use_galileo').prop('checked', preset.galileo); - $('#gps_use_glonass').prop('checked', preset.glonass); - $('#gps_use_beidou').prop('checked', preset.beidou); - $('#gps_ublox_nav_hz').val(preset.rate); + // Apply preset values (trigger change for state consistency) + $('#gps_use_galileo').prop('checked', preset.galileo).trigger('change'); + $('#gps_use_glonass').prop('checked', preset.glonass).trigger('change'); + $('#gps_use_beidou').prop('checked', preset.beidou).trigger('change'); + $('#gps_ublox_nav_hz').val(preset.rate).trigger('change'); // Disable controls (user can see but not edit) $('.preset-controlled').prop('disabled', true);