Skip to content

Commit 8b741d9

Browse files
Merge pull request #2526 from sensei-hacker/feature-gps-preset-ui
Add GPS preset UI with auto-detection and M9 Precision/Sport modes
2 parents a303be2 + 8239d70 commit 8b741d9

File tree

4 files changed

+238
-8
lines changed

4 files changed

+238
-8
lines changed

js/msp/MSPHelper.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,12 @@ var mspHelper = (function () {
198198
FC.GPS_DATA.hdop = data.getUint16(14, true);
199199
FC.GPS_DATA.eph = data.getUint16(16, true);
200200
FC.GPS_DATA.epv = data.getUint16(18, true);
201+
// Check if hwVersion field exists (firmware with extended MSP_GPSSTATISTICS)
202+
if (data.byteLength >= 24) {
203+
FC.GPS_DATA.hwVersion = data.getUint32(20, true);
204+
} else {
205+
FC.GPS_DATA.hwVersion = 0; // Unknown for older firmware
206+
}
201207
break;
202208
case MSPCodes.MSP2_ADSB_VEHICLE_LIST:
203209
var byteOffsetCounter = 0;

locale/en/messages.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,24 @@
12091209
"configurationGPSUseGlonass": {
12101210
"message": "Gps use Glonass Satellites (RU)"
12111211
},
1212+
"gpsPresetMode": {
1213+
"message": "GPS Configuration Preset"
1214+
},
1215+
"gpsPresetModeHelp": {
1216+
"message": "Choose a preset optimized for your GPS module, or use Manual for custom configuration. Auto-detect will identify your GPS module if connected."
1217+
},
1218+
"gpsUpdateRate": {
1219+
"message": "GPS Update Rate (Hz)"
1220+
},
1221+
"gpsUpdateRateHelp": {
1222+
"message": "How often the GPS module sends position updates. Higher rates provide lower latency but may reduce accuracy with multiple constellations on M10 modules."
1223+
},
1224+
"gpsAutoDetectFailed": {
1225+
"message": "Could not auto-detect GPS module. Please connect flight controller or select manual preset."
1226+
},
1227+
"gpsAutoDetectSuccess": {
1228+
"message": "GPS module detected:"
1229+
},
12121230
"tzOffset": {
12131231
"message": "Timezone Offset"
12141232
},

tabs/gps.html

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,51 @@
3838
<input type="number" id="mag_declination" name="mag_declination" step="0.1" min="-180" max="180" />
3939
<label for="mag_declination"><span data-i18n="configurationMagDeclination"></span></label>
4040
</div>
41+
<!-- GPS Optimization Preset -->
42+
<div class="select">
43+
<select id="gps_preset_mode">
44+
<option value="auto">Auto-detect GPS Type</option>
45+
<option value="manual" selected>Manual Settings</option>
46+
<option value="m8">u-blox M8</option>
47+
<option value="m9-precision">u-blox M9 (Precision Mode)</option>
48+
<option value="m9-sport">u-blox M9 (Sport Mode)</option>
49+
<option value="m10">u-blox M10</option>
50+
<option value="m10-highperf">u-blox M10 (High-Performance)</option>
51+
</select>
52+
<label for="gps_preset_mode">
53+
<span data-i18n="gpsPresetMode">GPS Configuration Preset</span>
54+
</label>
55+
<div for="gps_preset_mode" class="helpicon cf_tip" data-i18n_title="gpsPresetModeHelp"></div>
56+
</div>
57+
<!-- Hardware detection status -->
58+
<div id="gps_hardware_status" style="display: none; padding: 5px; margin: 5px 0; font-size: 12px; color: #28a745;">
59+
<span style="margin-right: 5px;"></span>
60+
<span id="gps_hardware_name"></span>
61+
<a href="#" id="gps_apply_optimal" style="margin-left: 10px; color: #007bff; text-decoration: none;">[Use optimal settings]</a>
62+
</div>
63+
<!-- GPS Preset Info (shown when preset selected) -->
64+
<div class="preset-info" id="preset_info" style="display: none; padding: 5px; margin: 5px 0; background: #f0f0f0; border-radius: 3px;">
65+
<strong><span id="preset_name"></span></strong>
66+
<ul id="preset_details" style="margin: 5px 0; padding-left: 20px;"></ul>
67+
</div>
68+
<!-- GPS Update Rate -->
69+
<div class="number">
70+
<input type="number" id="gps_ublox_nav_hz" data-setting="gps_ublox_nav_hz" step="1" min="5" max="20" />
71+
<label for="gps_ublox_nav_hz">
72+
<span data-i18n="gpsUpdateRate">GPS Update Rate (Hz)</span>
73+
</label>
74+
<div for="gps_ublox_nav_hz" class="helpicon cf_tip" data-i18n_title="gpsUpdateRateHelp"></div>
75+
</div>
4176
<div class="checkbox">
42-
<input type="checkbox" class="toggle update_preview" data-setting="gps_ublox_use_galileo" data-live="true">
77+
<input type="checkbox" id="gps_use_galileo" class="toggle update_preview preset-controlled" data-setting="gps_ublox_use_galileo">
4378
<label for="gps_use_galileo"><span data-i18n="configurationGPSUseGalileo"></span></label>
4479
</div>
4580
<div class="checkbox">
46-
<input type="checkbox" class="toggle update_preview" data-setting="gps_ublox_use_beidou" data-live="true">
81+
<input type="checkbox" id="gps_use_beidou" class="toggle update_preview preset-controlled" data-setting="gps_ublox_use_beidou">
4782
<label for="gps_use_beidou"><span data-i18n="configurationGPSUseBeidou"></span></label>
4883
</div>
4984
<div class="checkbox">
50-
<input type="checkbox" class="toggle update_preview" data-setting="gps_ublox_use_glonass" data-live="true">
85+
<input type="checkbox" id="gps_use_glonass" class="toggle update_preview preset-controlled" data-setting="gps_ublox_use_glonass">
5186
<label for="gps_use_glonass"><span data-i18n="configurationGPSUseGlonass"></span></label>
5287
</div>
5388
<div class="number">

tabs/gps.js

Lines changed: 176 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,13 @@ TABS.gps.initialize = function (callback) {
130130
let vehiclesCursorInitialized = false;
131131
let arrowIcon;
132132

133-
function process_html() {
133+
async function process_html(settingsPromise) {
134+
// Wait for settings to finish loading to avoid race conditions
135+
// where user changes are overwritten by background setting loads
136+
if (settingsPromise) {
137+
await settingsPromise;
138+
}
139+
134140
i18n.localize();
135141

136142
var fcFeatures = FC.getFeatures();
@@ -200,6 +206,163 @@ TABS.gps.initialize = function (callback) {
200206

201207
gps_ubx_sbas_e.val(FC.MISC.gps_ubx_sbas);
202208

209+
// GPS Preset Configuration
210+
const GPS_PRESETS = {
211+
m8: {
212+
name: "u-blox M8",
213+
galileo: true,
214+
glonass: true,
215+
beidou: true,
216+
rate: 8,
217+
description: [
218+
"4 GNSS constellations for maximum accuracy",
219+
"8Hz update rate (conservative for M8)",
220+
"Best for: Navigation, position hold, slower aircraft"
221+
]
222+
},
223+
'm9-precision': {
224+
name: "u-blox M9 (Precision Mode)",
225+
galileo: true,
226+
glonass: false,
227+
beidou: true,
228+
rate: 5,
229+
description: [
230+
"3 GNSS constellations (GPS+Galileo+Beidou) → 32 satellites",
231+
"5Hz update rate, HDOP ~1.0-1.3",
232+
"Best for: Long-range cruise, position hold, navigation missions"
233+
]
234+
},
235+
'm9-sport': {
236+
name: "u-blox M9 (Sport Mode)",
237+
galileo: true,
238+
glonass: false,
239+
beidou: true,
240+
rate: 10,
241+
description: [
242+
"3 GNSS constellations (GPS+Galileo+Beidou) → 16 satellites",
243+
"10Hz update rate (hardware limit), HDOP ~2.0-2.5",
244+
"Best for: Fast flying, racing, acrobatics, quick response"
245+
]
246+
},
247+
m10: {
248+
name: "u-blox M10",
249+
galileo: true,
250+
glonass: false,
251+
beidou: true,
252+
rate: 8,
253+
description: [
254+
"3 GNSS constellations (GPS+Galileo+Beidou)",
255+
"8Hz update rate (safe for M10 default CPU clock)",
256+
"Best for: General use, balanced performance"
257+
]
258+
},
259+
'm10-highperf': {
260+
name: "u-blox M10 (High-Performance)",
261+
galileo: true,
262+
glonass: true,
263+
beidou: true,
264+
rate: 10,
265+
description: [
266+
"4 GNSS constellations for maximum satellites",
267+
"10Hz update rate (requires high-performance CPU clock)",
268+
"Only use if you KNOW your M10 has high-performance clock enabled"
269+
]
270+
},
271+
manual: {
272+
name: "Manual Settings",
273+
description: [
274+
"Full control over constellation selection and update rate",
275+
"For advanced users and special requirements"
276+
]
277+
}
278+
};
279+
280+
function detectGPSPreset(hwVersion) {
281+
switch(hwVersion) {
282+
case 800: return 'm8';
283+
case 900: return 'm9-precision'; // Default to precision mode for better accuracy
284+
case 1000: return 'm10';
285+
default: return 'manual';
286+
}
287+
}
288+
289+
function applyGPSPreset(presetId) {
290+
// Handle special cases first (before checking GPS_PRESETS)
291+
if (presetId === 'manual') {
292+
// Enable all controls
293+
$('.preset-controlled').prop('disabled', false);
294+
$('#gps_ublox_nav_hz').prop('disabled', false);
295+
$('#preset_info').hide();
296+
return;
297+
}
298+
299+
if (presetId === 'auto') {
300+
// Try to auto-detect from FC
301+
if (FC.GPS_DATA && FC.GPS_DATA.hwVersion) {
302+
const detectedPreset = detectGPSPreset(FC.GPS_DATA.hwVersion);
303+
applyGPSPreset(detectedPreset);
304+
$('#gps_preset_mode').val(detectedPreset);
305+
GUI.log(i18n.getMessage('gpsAutoDetectSuccess') + ' ' + GPS_PRESETS[detectedPreset].name);
306+
} else {
307+
// Fall back to manual if can't detect
308+
applyGPSPreset('manual');
309+
$('#gps_preset_mode').val('manual');
310+
GUI.log(i18n.getMessage('gpsAutoDetectFailed'));
311+
}
312+
return;
313+
}
314+
315+
// Normal preset application
316+
const preset = GPS_PRESETS[presetId];
317+
if (!preset) return;
318+
319+
// Apply preset values (user can still adjust after applying)
320+
$('#gps_use_galileo').prop('checked', preset.galileo);
321+
$('#gps_use_glonass').prop('checked', preset.glonass);
322+
$('#gps_use_beidou').prop('checked', preset.beidou);
323+
$('#gps_ublox_nav_hz').val(preset.rate);
324+
325+
// Show preset info
326+
$('#preset_name').text(preset.name);
327+
$('#preset_details').html(preset.description.map(d => `<li>${d}</li>`).join(''));
328+
$('#preset_info').show();
329+
}
330+
331+
// Set up preset mode handler (namespaced to prevent memory leaks)
332+
$('#gps_preset_mode').on('change.gpsTab', function() {
333+
applyGPSPreset($(this).val());
334+
});
335+
336+
// Hardware detection status indicator
337+
function updateHardwareStatus() {
338+
if (FC.GPS_DATA && FC.GPS_DATA.hwVersion && FC.GPS_DATA.hwVersion > 0) {
339+
const detectedPreset = detectGPSPreset(FC.GPS_DATA.hwVersion);
340+
if (detectedPreset && detectedPreset !== 'manual' && GPS_PRESETS[detectedPreset]) {
341+
$('#gps_hardware_name').text(GPS_PRESETS[detectedPreset].name + ' detected');
342+
$('#gps_hardware_status').show();
343+
}
344+
}
345+
}
346+
347+
// Handler for "Use optimal settings" link (namespaced)
348+
$('#gps_apply_optimal').on('click.gpsTab', function(e) {
349+
e.preventDefault();
350+
if (FC.GPS_DATA && FC.GPS_DATA.hwVersion) {
351+
const detectedPreset = detectGPSPreset(FC.GPS_DATA.hwVersion);
352+
if (detectedPreset && detectedPreset !== 'manual') {
353+
$('#gps_preset_mode').val(detectedPreset).trigger('change');
354+
GUI.log('Applied recommended settings for ' + GPS_PRESETS[detectedPreset].name);
355+
}
356+
}
357+
});
358+
359+
// Initialize - default to manual mode to preserve user's existing settings
360+
// User can explicitly select a preset or use "Auto-detect" if desired
361+
applyGPSPreset('manual');
362+
363+
// Check for hardware detection after a short delay to allow GPS data to arrive
364+
setTimeout(updateHardwareStatus, 500);
365+
203366
let mapView = new View({
204367
center: [0, 0],
205368
zoom: 15
@@ -240,7 +403,7 @@ TABS.gps.initialize = function (callback) {
240403
}));
241404
}
242405

243-
$("#center_button").on('click', function () {
406+
$("#center_button").on('click.gpsTab', function () {
244407
let lat = FC.GPS_DATA.lat / 10000000;
245408
let lon = FC.GPS_DATA.lon / 10000000;
246409
let center = fromLonLat([lon, lat]);
@@ -466,7 +629,7 @@ TABS.gps.initialize = function (callback) {
466629
});
467630
}
468631

469-
$('a.save').on('click', function () {
632+
$('a.save').on('click.gpsTab', function () {
470633
serialPortHelper.set($port.val(), 'GPS', $baud.val());
471634
features.reset();
472635
features.fromUI($('.tab-gps'));
@@ -517,15 +680,15 @@ TABS.gps.initialize = function (callback) {
517680
}
518681
}
519682

520-
$('a.loadAssistnowOnline').on('click', function () {
683+
$('a.loadAssistnowOnline').on('click.gpsTab', function () {
521684
if(globalSettings.assistnowApiKey != null && globalSettings.assistnowApiKey != '') {
522685
ublox.loadAssistnowOnline(processUbloxData);
523686
} else {
524687
dialog.alert("Assistnow Token not set!");
525688
}
526689
});
527690

528-
$('a.loadAssistnowOffline').on('click', function () {
691+
$('a.loadAssistnowOffline').on('click.gpsTab', function () {
529692
if(globalSettings.assistnowApiKey != null && globalSettings.assistnowApiKey != '') {
530693
ublox.loadAssistnowOffline(processUbloxData);
531694
} else {
@@ -539,6 +702,14 @@ TABS.gps.initialize = function (callback) {
539702
};
540703

541704
TABS.gps.cleanup = function (callback) {
705+
// Remove all namespaced event handlers to prevent memory leaks
706+
$('#gps_preset_mode').off('.gpsTab');
707+
$('#gps_apply_optimal').off('.gpsTab');
708+
$('#center_button').off('.gpsTab');
709+
$('a.save').off('.gpsTab');
710+
$('a.loadAssistnowOnline').off('.gpsTab');
711+
$('a.loadAssistnowOffline').off('.gpsTab');
712+
542713
if (callback) callback();
543714
if (TABS.gps.toolboxAdsbVehicle){
544715
TABS.gps.toolboxAdsbVehicle.close();

0 commit comments

Comments
 (0)