Load AGPS data on app start and automatically in background

pull/2028/head
Marco H 2022-07-06 14:03:35 +02:00 committed by Marco Heiming
parent 9d65537dc2
commit dabaec97d6
7 changed files with 181 additions and 112 deletions

View File

@ -1 +1,2 @@
0.01: First, proof of concept 0.01: First, proof of concept
0.02: Load AGPS data on app start and automatically in background

View File

@ -1,125 +1,29 @@
var _GB = global.GB; function display(text1, text2) {
var counter = 0;
function GB(msg) {
console.log(msg);
if (msg.t == "http") {
display("Received", "(" + msg.resp.length + ") Touch to apply", () => {
display("Apply data..", "");
setTimeout(() => {
if (setAGPS(msg.resp)) {
display("Success", "Touch for restart", httpTest);
}
else {
display("Error", "Touch for restart", httpTest);
}
}, 1);
});
}
if (_GB) {
_GB(msg);
}
}
function setAGPS(data) {
var js = jsFromBase64(data);
console.log(js);
try {
eval(js);
return true;
}
catch(e) {
console.log("Error:", e);
}
return false;
}
function jsFromBase64(b64) {
var bin = atob(b64);
var chunkSize = 128;
var js = "Bangle.setGPSPower(1);\n"; // turn GPS on
var gnss_select="1";
js += `Serial1.println("${CASIC_CHECKSUM("$PCAS04,"+gnss_select)}")\n`; // set GNSS mode
// What about:
// NAV-TIMEUTC (0x01 0x10)
// NAV-PV (0x01 0x03)
// or AGPS.zip uses AID-INI (0x0B 0x01)
for (var i=0;i<bin.length;i+=chunkSize) {
var chunk = bin.substr(i,chunkSize);
js += `Serial1.write(atob("${btoa(chunk)}"))\n`;
}
return js;
}
function CASIC_CHECKSUM(cmd) {
var cs = 0;
for (var i=1;i<cmd.length;i++)
cs = cs ^ cmd.charCodeAt(i);
return cmd+"*"+cs.toString(16).toUpperCase().padStart(2, '0');
}
function display(text1, text2, next) {
g.reset(); g.reset();
g.clear(); g.clear();
var img = require("Storage").read("agpsdata.img"); var img = require("Storage").read("agpsdata.img");
if (img) { if (img) {
g.drawImage(img, g.getWidth() - 48, g.getHeight()-48-24); g.drawImage(img, g.getWidth() - 48, g.getHeight()-48-24);
} }
g.setFont("Vector", 30); g.setFont("Vector", 20);
g.setFontAlign(0, 1); g.setFontAlign(0, 1);
g.drawString(text1, g.getWidth() / 2, g.getHeight() / 3 + 24); g.drawString(text1, g.getWidth() / 2, g.getHeight() / 3 + 24);
g.setFont("Vector", 15); if (text2 != undefined) {
g.setFontAlign(-1, -1); g.setFont("Vector", 15);
g.drawString(text2, 0, g.getHeight() / 3 + 29); g.setFontAlign(-1, -1);
g.drawString(text2, 5, g.getHeight() / 3 + 29);
}
Bangle.drawWidgets(); Bangle.drawWidgets();
nextStep = null;
if (next) {
nextStep = next;
}
} }
function httpTest() {
counter++;
display("AGPS Data", "Touch for start", () => {
display("Request...", "Touch for restart", httpTest);
if (Bluetooth.println) {
console.log("On device");
Bluetooth.println(JSON.stringify({t:"info", msg:"HTTP Request"}));
Bluetooth.println(JSON.stringify({t:"http", url:"https://www.espruino.com/agps/casic.base64"}));
}
else {
console.log("Testing on Emulator");
setTimeout(() => {
GB({t:"http", resp:testData});
}, 1);
}
});
}
var nextStep = null;
Bangle.on("touch", () => {
if (nextStep) {
nextStep();
}
});
httpTest();
// Show launcher when middle button pressed // Show launcher when middle button pressed
// Load widgets // Load widgets
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
display("Updating data...");
/* require("agpsdata").pull(function() {
require("Storage").write("httptest.info",{ display("Success", "AGPS data updated.");
"id":"httptest", },function(error) {
"name":"Http Test", display("Error:", error);
"src":"httptest.js",
"icon":"wristlight.img"
}); });
*/
var testData = "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";

33
apps/agpsdata/boot.js Normal file
View File

@ -0,0 +1,33 @@
(function() {
let waiting = false;
let settings = require("Storage").readJSON("agpsdata.json", 1) || {
enabled: true,
refresh: 1440
};
if (settings.refresh == undefined) settings.refresh = 1440;
function successCallback(){
waiting = false;
}
function errorCallback(){
waiting = false;
}
if (settings.enabled) {
let lastUpdate = settings.lastUpdate;
if (!lastUpdate || lastUpdate + settings.refresh * 1000 * 60 < Date.now()){
if (!waiting){
waiting = true;
require("agpsdata").pull(successCallback, errorCallback);
}
}
setInterval(() => {
if (!waiting && NRF.getSecurityStatus().connected){
waiting = true;
require("agpsdata").pull(successCallback, errorCallback);
}
}, settings.refresh * 1000 * 60);
}
})();

View File

@ -0,0 +1 @@
{"enabled":true,"refresh":1440}

64
apps/agpsdata/lib.js Normal file
View File

@ -0,0 +1,64 @@
function setAGPS(data) {
var js = jsFromBase64(data);
try {
eval(js);
return true;
}
catch(e) {
console.log("error:", e);
}
return false;
}
function jsFromBase64(b64) {
var bin = atob(b64);
var chunkSize = 128;
var js = "Bangle.setGPSPower(1);\n"; // turn GPS on
var gnss_select="1";
js += `Serial1.println("${CASIC_CHECKSUM("$PCAS04,"+gnss_select)}")\n`; // set GNSS mode
// What about:
// NAV-TIMEUTC (0x01 0x10)
// NAV-PV (0x01 0x03)
// or AGPS.zip uses AID-INI (0x0B 0x01)
for (var i=0;i<bin.length;i+=chunkSize) {
var chunk = bin.substr(i,chunkSize);
js += `Serial1.write(atob("${btoa(chunk)}"))\n`;
}
return js;
}
function CASIC_CHECKSUM(cmd) {
var cs = 0;
for (var i=1;i<cmd.length;i++)
cs = cs ^ cmd.charCodeAt(i);
return cmd+"*"+cs.toString(16).toUpperCase().padStart(2, '0');
}
function updateLastUpdate() {
let settings = require("Storage").readJSON("agpsdata.json", 1) || {};
settings.lastUpdate = Math.round(Date.now());
require("Storage").writeJSON("agpsdata.json", settings)
}
exports.pull = function(successCallback, failureCallback) {
let uri = "https://www.espruino.com/agps/casic.base64";
if (Bangle.http){
Bangle.http(uri, {timeout:10000}).then(event => {
let result = setAGPS(event.resp);
if (result) {
updateLastUpdate();
if (successCallback) successCallback();
} else {
console.log("error applying AGPS data");
if (failureCallback) failureCallback("Error applying AGPS data");
}
}).catch((e)=>{
console.log("error", e);
if (failureCallback) failureCallback(e);
});
} else {
console.log("error: No http method found");
if (failureCallback) failureCallback(/*LANG*/"No http method found");
}
};

View File

@ -2,15 +2,22 @@
"name": "A-GPS Data", "name": "A-GPS Data",
"shortName":"AGPS Data", "shortName":"AGPS Data",
"icon": "agpsdata.png", "icon": "agpsdata.png",
"version":"0.01", "version":"0.02",
"description": "Download assisted GPS data directly to watch", "description": "Download assisted GPS (AGPS) data directly to watch",
"tags": "assisted,gps,agps,http", "tags": "boot,tool,assisted,gps,agps,http",
"allow_emulator":true, "allow_emulator":true,
"supports": ["BANGLEJS2"], "supports": ["BANGLEJS2"],
"readme":"README.md", "readme":"README.md",
"screenshots" : [ { "url":"screenshot.png" }, { "url":"screenshot2.png" }, { "url":"screenshot3.png" }, { "url":"screenshot4.png" }, { "url":"screenshot5.png" } ], "screenshots" : [ { "url":"screenshot.png" }, { "url":"screenshot2.png" }, { "url":"screenshot3.png" }, { "url":"screenshot4.png" }, { "url":"screenshot5.png" } ],
"storage": [ "storage": [
{"name":"agpsdata.app.js","url":"app.js"}, {"name":"agpsdata.app.js","url":"app.js"},
{"name":"agpsdata.img","url":"agpsdata-icon.js","evaluate":true} {"name":"agpsdata.img","url":"agpsdata-icon.js","evaluate":true},
{"name":"agpsdata.default.json","url":"default.json"},
{"name":"agpsdata.boot.js","url":"boot.js"},
{"name":"agpsdata","url":"lib.js"},
{"name":"agpsdata.settings.js","url":"settings.js"}
],
"data": [
{"name": "agpsdata.json"}
] ]
} }

59
apps/agpsdata/settings.js Normal file
View File

@ -0,0 +1,59 @@
(function(back) {
function writeSettings(key, value) {
var s = require('Storage').readJSON(FILE, true) || {};
s[key] = value;
require('Storage').writeJSON(FILE, s);
readSettings();
}
function readSettings(){
settings = Object.assign(
require('Storage').readJSON("agpsdata.default.json", true) || {},
require('Storage').readJSON(FILE, true) || {}
);
}
var FILE="agpsdata.json";
var settings;
readSettings();
function buildMainMenu(){
var mainmenu = {
'': { 'title': 'AGPS download' },
'< Back': back,
"Enabled": {
value: !!settings.enabled,
onchange: v => {
writeSettings("enabled", v);
}
},
"Refresh every": {
value: settings.refresh / 60,
min: 1,
max: 48,
step: 1,
format: v=>v+"h",
onchange: v => {
writeSettings("refresh",Math.round(v * 60));
}
},
"Force refresh": ()=>{
E.showMessage("Loading AGPS data");
require("agpsdata").pull(function() {
E.showAlert("Success").then(()=>{
E.showMenu(buildMainMenu());
});
},function(error) {
E.showAlert(error,"Error").then(()=>{
E.showMenu(buildMainMenu());
});
});
}
};
return mainmenu;
}
E.showMenu(buildMainMenu());
});