Merge pull request #2123 from iNavFlight/mmosca-gps-assitnow

Add UBLOX AssistNow support to configurator
pull/2126/head
Marcelo Bezerra 3 months ago committed by GitHub
commit 4f6325ae2d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -89,6 +89,7 @@ sources.js = [
'./js/msp/MSPCodes.js', './js/msp/MSPCodes.js',
'./js/msp/MSPHelper.js', './js/msp/MSPHelper.js',
'./js/msp/MSPchainer.js', './js/msp/MSPchainer.js',
'./js/ublox/UBLOX.js',
'./js/port_handler.js', './js/port_handler.js',
'./js/connection/connection.js', './js/connection/connection.js',
'./js/connection/connectionBle.js', './js/connection/connectionBle.js',

@ -78,12 +78,16 @@ $(function() {
$('a', activeTab).trigger('click'); $('a', activeTab).trigger('click');
} }
globalSettings.store = store;
globalSettings.unitType = store.get('unit_type', UnitType.none); globalSettings.unitType = store.get('unit_type', UnitType.none);
globalSettings.mapProviderType = store.get('map_provider_type', 'osm'); globalSettings.mapProviderType = store.get('map_provider_type', 'osm');
globalSettings.mapApiKey = store.get('map_api_key', ''); globalSettings.mapApiKey = store.get('map_api_key', '');
globalSettings.assistnowApiKey = store.get('assistnow_api_key', '');
globalSettings.proxyURL = store.get('proxyurl', 'http://192.168.1.222/mapproxy/service?'); globalSettings.proxyURL = store.get('proxyurl', 'http://192.168.1.222/mapproxy/service?');
globalSettings.proxyLayer = store.get('proxylayer', 'your_proxy_layer_name'); globalSettings.proxyLayer = store.get('proxylayer', 'your_proxy_layer_name');
globalSettings.showProfileParameters = store.get('show_profile_parameters', 1); globalSettings.showProfileParameters = store.get('show_profile_parameters', 1);
globalSettings.assistnowOfflineData = store.get('assistnow_offline_data', []);
globalSettings.assistnowOfflineDate = store.get('assistnow_offline_date', 0);
updateProfilesHighlightColours(); updateProfilesHighlightColours();
var cliAutocomplete = store.get('cli_autocomplete', true); var cliAutocomplete = store.get('cli_autocomplete', true);
@ -340,6 +344,7 @@ $(function() {
$('#proxylayer').val(globalSettings.proxyLayer); $('#proxylayer').val(globalSettings.proxyLayer);
$('#showProfileParameters').prop('checked', globalSettings.showProfileParameters); $('#showProfileParameters').prop('checked', globalSettings.showProfileParameters);
$('#cliAutocomplete').prop('checked', globalSettings.cliAutocomplete); $('#cliAutocomplete').prop('checked', globalSettings.cliAutocomplete);
$('#assistnow-api-key').val(globalSettings.assistnowApiKey);
i18n.getLanguages().forEach(lng => { i18n.getLanguages().forEach(lng => {
$('#languageOption').append("<option value='{0}'>{1}</option>".format(lng, i18n.getMessage("language_" + lng))); $('#languageOption').append("<option value='{0}'>{1}</option>".format(lng, i18n.getMessage("language_" + lng)));
@ -383,6 +388,11 @@ $(function() {
store.set('proxylayer', $(this).val()); store.set('proxylayer', $(this).val());
globalSettings.proxyLayer = $(this).val(); globalSettings.proxyLayer = $(this).val();
}); });
$('#assistnow-api-key').on('change', function () {
store.set('assistnow_api_key', $(this).val());
globalSettings.assistnowApiKey = $(this).val();
});
$('#demoModeReset').on('click', function () { $('#demoModeReset').on('click', function () {
SITLProcess.deleteEepromFile('demo.bin'); SITLProcess.deleteEepromFile('demo.bin');
}); });

@ -21,6 +21,14 @@ var globalSettings = {
// tree target for documents // tree target for documents
docsTreeLocation: 'master', docsTreeLocation: 'master',
cliAutocomplete: true, cliAutocomplete: true,
assistnowApiKey: null,
assistnowOfflineData: [],
assistnowOfflineDate: 0,
store: null,
saveAssistnowData: function() {
this.store.set('assistnow_offline_data', this.assistnowOfflineData);
this.store.set('assistnow_offline_date', this.assistnowOfflineDate);
}
}; };
module.exports = { globalSettings, UnitType }; module.exports = { globalSettings, UnitType };

@ -225,6 +225,8 @@ var MSPCodes = {
MSP2_INAV_FW_APPROACH: 0x204A, MSP2_INAV_FW_APPROACH: 0x204A,
MSP2_INAV_SET_FW_APPROACH: 0x204B, MSP2_INAV_SET_FW_APPROACH: 0x204B,
MSP2_INAV_GPS_UBLOX_COMMAND: 0x2050,
MSP2_INAV_RATE_DYNAMICS: 0x2060, MSP2_INAV_RATE_DYNAMICS: 0x2060,
MSP2_INAV_SET_RATE_DYNAMICS: 0x2061, MSP2_INAV_SET_RATE_DYNAMICS: 0x2061,

@ -1588,11 +1588,14 @@ var mspHelper = (function () {
FC.OSD_CUSTOM_ELEMENTS .items.push(customElement) FC.OSD_CUSTOM_ELEMENTS .items.push(customElement)
} }
break; break;
case MSPCodes.MSP2_INAV_GPS_UBLOX_COMMAND:
// Just and ACK from the fc.
break;
default: default:
console.log('Unknown code detected: ' + dataHandler.code); console.log('Unknown code detected: 0x' + dataHandler.code.toString(16));
} else { } else {
console.log('FC reports unsupported message error: ' + dataHandler.code); console.log('FC reports unsupported message error: 0x' + dataHandler.code.toString(16));
} }
// trigger callbacks, cleanup/remove callback after trigger // trigger callbacks, cleanup/remove callback after trigger
@ -3383,6 +3386,10 @@ var mspHelper = (function () {
MSP.send_message(MSPCodes.MSP2_SET_CF_SERIAL_CONFIG, mspHelper.crunch(MSPCodes.MSP2_SET_CF_SERIAL_CONFIG), false, callback); MSP.send_message(MSPCodes.MSP2_SET_CF_SERIAL_CONFIG, mspHelper.crunch(MSPCodes.MSP2_SET_CF_SERIAL_CONFIG), false, callback);
}; };
self.sendUbloxCommand = function (ubloxData, callback) {
MSP.send_message(MSPCodes.MSP2_INAV_GPS_UBLOX_COMMAND, ubloxData, false, callback);
};
return self; return self;
})(); })();

@ -0,0 +1,239 @@
'use strict';
const semver = require('semver');
require('./../injected_methods');
const jBox = require('./../libraries/jBox/jBox.min');
const i18n = require('./../localization');
const { GUI } = require('./../gui');
const { globalSettings } = require('../globalSettings');
const Store = require('electron-store');
var ublox = (function () {
var self = {};
var assistnowOnline = null;
var assistnowOffline = null;
// m7 = aid, not supported
// m8+ = mga
const fmt="mga";;
const gnss="gps,gal,bds,glo,qzss";
const onlineServers = [
'online-live1.services.u-blox.com',
'online-live2.services.u-blox.com',
];
const period=5
const offline_gnss="gps,gal,bds,glo";
const offline_alm="gps,gal,bds,glo";
const offlineServers = [
'offline-live1.services.u-blox.com',
'offline-live2.services.u-blox.com'
];
self.init = function() {
};
var hasFirstHeader;
var hasSecondHeader;
var ubxClass;
var ubxId;
var lenLow;
var lenHigh;
var payloadLen;
var skipped;
var currentCommand;
function resetUbloxState() {
//console.log("Reset ublox state");
hasFirstHeader = false;
hasSecondHeader = false;
ubxClass = false;
ubxId = false;
lenLow = false;
lenHigh = false;
payloadLen = 0;
skipped = 0;
currentCommand = [];
}
function splitUbloxData(ubxBytesBuffer) {
//console.log("type of data: " +typeof(ubxBytesBuffer));
//console.log("splitUbloxData: " + ubxBytesBuffer.byteLength);
let ubxBytes = new DataView(ubxBytesBuffer);
var ubxCommands = []
resetUbloxState()
for(var i = 0; i < ubxBytes.byteLength;++i) {
let c = ubxBytes.getUint8(i);
//console.log("byte: 0x" + c.toString(16));
if (!hasFirstHeader) {
if (c == 0xb5) {
//console.log("First header");
hasFirstHeader = true;
currentCommand.push(c);
continue;
}
else
{
resetUbloxState();
continue;
}
}
if (!hasSecondHeader) {
if (c == 0x62) {
//console.log("Second header");
hasSecondHeader = true;
currentCommand.push(c);
continue;
}
else
{
resetUbloxState();
continue;
}
}
if (!ubxClass) {
ubxClass = true;
//console.log("ubxClass: 0x"+ (c).toString(16));
currentCommand.push(c)
continue;
}
if (!ubxId) {
ubxId = true;
//console.log("ubxId: 0x"+ (c).toString(16));
currentCommand.push(c);
continue;
}
if (!lenLow) {
//console.log("Len low");
lenLow = true;
//(int) c
payloadLen = c;
currentCommand.push(c);
continue;
}
if (!lenHigh) {
//console.log("Len high");
lenHigh = true;
// (int)c
payloadLen = (c << 8) | payloadLen;
//console.log("Payload len " + payloadLen);
payloadLen += 2; // add crc bytes;
currentCommand.push(c);
continue
}
if (skipped < payloadLen - 1) {
//console.log("payload + crc");
skipped = skipped + 1;
currentCommand.push(c);
continue;
}
if (skipped == payloadLen - 1) {
skipped = skipped + 1;
currentCommand.push(c);
ubxCommands.push(currentCommand);
//console.log("Adding command");
resetUbloxState();
continue;
}
}
return ubxCommands
}
function getBinaryData(url, successCallback, failCallback) {
const req = new XMLHttpRequest();
req.open("GET", url, true);
req.responseType = "arraybuffer";
if (successCallback != null) {
req.onload = (event) => {
successCallback(req.response);
};
}
if (failCallback != null) {
req.onerror = (event) => {
failCallback(event);
}
}
req.send(null);
}
function loadError(event) {
GUI.alert(i18n.getMessage("gpsAssistnowLoadDataError"));
console.log(i18n.getMessage("gpsAssistnowLoadDataError") + ':' + event.toString());
}
// For more info on assistnow, check:
// https://developer.thingstream.io/guides/location-services/assistnow-user-guide
// Currently only supported for M8+ units
self.loadAssistnowOffline = function(callback) {
let url = `https://${ offlineServers[0] }/GetOfflineData.ashx?token=${globalSettings.assistnowApiKey};gnss=${offline_gnss};format=${fmt};period=${period};resolution=1;alm=${offline_alm};`
//console.log(url);
function processOfflineData(data) {
if(globalSettings.assistnowOfflineData == null || ((Date.now() / 1000)-globalSettings.assistnowOfflineDate) > (60*60*24*3)) {
console.log("AssistnowOfflineData older than 3 days, refreshing.");
globalSettings.assistnowOfflineData = splitUbloxData(data);
globalSettings.assistnowOfflineDate = Math.floor(Date.now() / 1000);
globalSettings.saveAssistnowData();
} else {
console.log("AssitnowOfflineData newer than 3 days. Re-using.");
}
//console.log("Assitnow offline commands:" + globalSettings.assistnowOfflineData.length);
callback(globalSettings.assistnowOfflineData);
}
getBinaryData(url, processOfflineData, loadError);
//$.get(url, processOfflineData).fail(function() {GUI.alert("Error loading Offline data")});
};
self.loadAssistnowOnline = function(callback) {
//url = "https://online-live1.services.u-blox.com/GetOnlineData.ashx?token=" + online_token + ";gnss=" + gnss + ";datatype=eph,alm,aux,pos;format=" + fmt + ";"
let url = `https://${ onlineServers[0] }/GetOnlineData.ashx?token=${globalSettings.assistnowApiKey};gnss=${ gnss };datatype=eph,alm,aux,pos;format=${ fmt }`;
function processOnlineData(data) {
assistnowOnline = splitUbloxData(data);
//console.log("Assitnow online commands:" + assistnowOnline.length);
callback(assistnowOnline);
}
//$.get(url, processOnlineData).fail(function() {GUI.alert("Error loading Offline data")});
getBinaryData(url, processOnlineData, loadError);
}
self.isAssistnowDataRelevant = function(ubxMessage, cy, cm, cd) {
if ((ubxMessage[2] == 0x13 /*UBX_CLASS_MGA*/) && (ubxMessage[3] == 0x20 /*UBX_MGA_ANO*/))
{
// UBX-MGA-ANO
const payloadOffset = 6;
if (((ubxMessage[payloadOffset + 4] + 2000) == cy) && (ubxMessage[payloadOffset + 5] == cm) && (ubxMessage[payloadOffset + 6] == cd))
{
//console.log("UBX-MGA_ANO date matches");
return true;
}
} else {
//console.log("UBX-CMD: class: 0x" + ubxMessage[2].toString(16) + " id: 0x" + ubxMessage[3].toString(16));
return true;
}
return false;
}
return self;
})();
module.exports = ublox;

@ -5911,5 +5911,29 @@
}, },
"maintenanceFlushSettingsCache": { "maintenanceFlushSettingsCache": {
"message": "Flush settings cache" "message": "Flush settings cache"
},
"gpsOptions": {
"message": "GPS Options"
},
"gpsOptionsAssistnowToken": {
"message": "AssitNow Token"
},
"gpsLoadAssistnowOfflineButton": {
"message": "Load AssistNow Offline"
},
"gpsLoadAssistnowOnlineButton": {
"message": "Load AssistNow Online"
},
"gpsAssistnowStart": {
"message": "AssistNow data transfer starting..."
},
"gpsAssistnowDone": {
"message": "AssistNow data transfer complete."
},
"gpsAssistnowUpdate": {
"message": "AssistNow messages sent."
},
"gpsAssistnowLoadDataError": {
"message": "Error loading AssistNow data."
} }
} }

@ -159,5 +159,11 @@
<div class="btn save_btn"> <div class="btn save_btn">
<a class="save" href="#" data-i18n="configurationButtonSave"></a> <a class="save" href="#" data-i18n="configurationButtonSave"></a>
</div> </div>
<div class="btn save_btn">
<a class="loadAssistnowOnline" href="#" data-i18n="gpsLoadAssistnowOnlineButton"></a>
</div>
<div class="btn save_btn">
<a class="loadAssistnowOffline" href="#" data-i18n="gpsLoadAssistnowOfflineButton"></a>
</div>
</div> </div>
</div> </div>

@ -18,6 +18,7 @@ const features = require('./../js/feature_framework');
const { globalSettings } = require('./../js/globalSettings'); const { globalSettings } = require('./../js/globalSettings');
const jBox = require('./../js/libraries/jBox/jBox.min'); const jBox = require('./../js/libraries/jBox/jBox.min');
const SerialBackend = require('../js/serial_backend'); const SerialBackend = require('../js/serial_backend');
const ublox = require('../js/ublox/UBLOX');
TABS.gps = {}; TABS.gps = {};
@ -418,6 +419,64 @@ TABS.gps.initialize = function (callback) {
}); });
}); });
function processUbloxData(data) {
if(data != null) {
//console.log("processing data type: " + typeof(data));
let totalSent = 0;
let total = data.length;
var ubloxChainer = MSPChainerClass();
var chain = [];
let d = new Date();
GUI.log(i18n.getMessage('gpsAssistnowStart'));
data.forEach((item) => {
chain.push(function (callback) {
//console.log("UBX command: " + item.length);
let callCallback = false;
if (ublox.isAssistnowDataRelevant(item, d.getUTCFullYear(), d.getUTCMonth()+1, d.getUTCDate()+1)) {
mspHelper.sendUbloxCommand(item, callback);
} else {
// Ignore msp command, but keep counter going.
callCallback = true;
}
totalSent++;
if((totalSent % 100) == 0) {
GUI.log(totalSent + '/' + total + ' ' + i18n.getMessage('gpsAssistnowUpdate'));
}
if(callCallback) {
callback();
}
});
});
ubloxChainer.setChain(chain);
ubloxChainer.setExitPoint(function () {
if ((totalSent % 100) != 0) {
GUI.log(totalSent + '/' + total + ' ' + i18n.getMessage('gpsAssistnowUpdate'));
}
GUI.log(i18n.getMessage('gpsAssistnowDone'));
});
ubloxChainer.execute();
}
}
$('a.loadAssistnowOnline').on('click', function () {
if(globalSettings.assistnowApiKey != null && globalSettings.assistnowApiKey != '') {
ublox.loadAssistnowOnline(processUbloxData);
} else {
GUI.alert("Assistnow Token not set!");
}
});
$('a.loadAssistnowOffline').on('click', function () {
if(globalSettings.assistnowApiKey != null && globalSettings.assistnowApiKey != '') {
ublox.loadAssistnowOffline(processUbloxData);
} else {
GUI.alert("Assistnow Token not set!");
}
});
GUI.content_ready(callback); GUI.content_ready(callback);
} }

@ -97,5 +97,17 @@
</div> </div>
</div> </div>
</div> </div>
<div class="options-section gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" data-i18n="gpsOptions"></div>
</div>
<div class="spacer_box settings">
<div class="number">
<input type="password" id="assistnow-api-key" style="border: solid 1px black" />
<label for="assistnow-api-key" data-i18n="gpsOptionsAssistnowToken"></label>
</div>
</div>
</div>
</div> </div>
</div> </div>
Loading…
Cancel
Save