Merge branch 'espruino:master' into master

master
xxDUxx 2023-01-24 09:54:57 +01:00 committed by GitHub
commit 152af164e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 264 additions and 121 deletions

1
apps/backswipe/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: New App!

BIN
apps/backswipe/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 B

50
apps/backswipe/boot.js Normal file
View File

@ -0,0 +1,50 @@
(function () {
var DEFAULTS = {
mode: 0,
apps: [],
};
var settings = require("Storage").readJSON("backswipe.json", 1) || DEFAULTS;
// Overrride the default setUI method, so we can save the back button callback
var setUI = Bangle.setUI;
Bangle.setUI = function (mode, cb) {
var options = {};
if ("object"==typeof mode) {
options = mode;
}
var currentFile = global.__FILE__ || "";
if(global.BACK) delete global.BACK;
if (options && options.back && enabledForApp(currentFile)) {
global.BACK = options.back;
}
setUI(mode, cb);
};
function goBack(lr, ud) {
// if it is a left to right swipe
if (lr === 1) {
// if we're in an app that has a back button, run the callback for it
if (global.BACK) {
global.BACK();
}
}
}
// Check if the back button should be enabled for the current app
// app is the src file of the app
function enabledForApp(app) {
if (!settings) return true;
if (settings.mode === 0) {
return !(settings.apps.filter((a) => a.src === app).length > 0);
} else if (settings.mode === 1) {
return settings.apps.filter((a) => a.src === app).length > 0;
} else {
return settings.mode === 2 ? true : false;
}
}
// Listen to left to right swipe
Bangle.on("swipe", goBack);
})();

View File

@ -0,0 +1,17 @@
{ "id": "backswipe",
"name": "Back Swipe",
"shortName":"BackSwipe",
"version":"0.01",
"description": "Service that allows you to use an app's back button using left to right swipe gesture",
"icon": "app.png",
"tags": "back,gesture,swipe",
"supports" : ["BANGLEJS2"],
"type": "bootloader",
"storage": [
{"name":"backswipe.boot.js","url":"boot.js"},
{"name":"backswipe.settings.js","url":"settings.js"}
],
"data": [
{"name":"backswipe.json"}
]
}

104
apps/backswipe/settings.js Normal file
View File

@ -0,0 +1,104 @@
(function(back) {
var FILE = 'backswipe.json';
// Mode can be 'blacklist', 'whitelist', 'on' or 'disabled'
// Apps is an array of app info objects, where all the apps that are there are either blocked or allowed, depending on the mode
var DEFAULTS = {
'mode': 0,
'apps': []
};
var settings = {};
var loadSettings = function() {
settings = require('Storage').readJSON(FILE, 1) || DEFAULTS;
}
var saveSettings = function(settings) {
require('Storage').write(FILE, settings);
}
// Get all app info files
var getApps = function() {
var apps = require('Storage').list(/\.info$/).map(appInfoFileName => {
var appInfo = require('Storage').readJSON(appInfoFileName, 1);
return appInfo && {
'name': appInfo.name,
'sortorder': appInfo.sortorder,
'src': appInfo.src
};
}).filter(app => app && !!app.src);
apps.sort((a, b) => {
var n = (0 | a.sortorder) - (0 | b.sortorder);
if (n) return n; // do sortorder first
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
});
return apps;
}
var showMenu = function() {
var menu = {
'': { 'title': 'Backswipe' },
'< Back': () => {
back();
},
'Mode': {
value: settings.mode,
min: 0,
max: 3,
format: v => ["Blacklist", "Whitelist", "Always On", "Disabled"][v],
onchange: v => {
settings.mode = v;
saveSettings(settings);
},
},
'App List': () => {
showAppSubMenu();
}
};
E.showMenu(menu);
}
var showAppSubMenu = function() {
var menu = {
'': { 'title': 'Backswipe' },
'< Back': () => {
showMenu();
},
'Add App': () => {
showAppList();
}
};
settings.apps.forEach(app => {
menu[app.name] = () => {
settings.apps.splice(settings.apps.indexOf(app), 1);
saveSettings(settings);
showAppSubMenu();
}
});
E.showMenu(menu);
}
var showAppList = function() {
var apps = getApps();
var menu = {
'': { 'title': 'Backswipe' },
'< Back': () => {
showMenu();
}
};
apps.forEach(app => {
menu[app.name] = () => {
settings.apps.push(app);
saveSettings(settings);
showAppSubMenu();
}
});
E.showMenu(menu);
}
loadSettings();
showMenu();
})

View File

@ -2,6 +2,5 @@
0.02: Course marker
0.03: Tilt compensation and calibration
0.04: Fix Font size
0.05: Inital portable version
0.05: Initial portable version
0.06: Outsource tilt compensation to library

41
apps/magnav/lib.js Normal file
View File

@ -0,0 +1,41 @@
exports.calibrate = () => {
var max={x:-32000, y:-32000, z:-32000},
min={x:32000, y:32000, z:32000};
var ref = setInterval(()=>{
var m = Bangle.getCompass();
max.x = m.x>max.x?m.x:max.x;
max.y = m.y>max.y?m.y:max.y;
max.z = m.z>max.z?m.z:max.z;
min.x = m.x<min.x?m.x:min.x;
min.y = m.y<min.y?m.y:min.y;
min.z = m.z<min.z?m.z:min.z;
}, 100);
return new Promise((resolve) => {
setTimeout(()=>{
if(ref) clearInterval(ref);
var offset = {x:(max.x+min.x)/2,y:(max.y+min.y)/2,z:(max.z+min.z)/2};
var delta = {x:(max.x-min.x)/2,y:(max.y-min.y)/2,z:(max.z-min.z)/2};
var avg = (delta.x+delta.y+delta.z)/3;
var scale = {x:avg/delta.x, y:avg/delta.y, z:avg/delta.z};
resolve({offset:offset,scale:scale});
},20000);
});
}
exports.tiltfixread = (O,S) => {
"ram"
var m = Bangle.getCompass();
var g = Bangle.getAccel();
m.dx =(m.x-O.x)*S.x; m.dy=(m.y-O.y)*S.y; m.dz=(m.z-O.z)*S.z;
var d = Math.atan2(-m.dx,m.dy)*180/Math.PI;
if (d<0) d+=360;
var phi = Math.atan(-g.x/-g.z);
var cosphi = Math.cos(phi), sinphi = Math.sin(phi);
var theta = Math.atan(-g.y/(-g.x*sinphi-g.z*cosphi));
var costheta = Math.cos(theta), sintheta = Math.sin(theta);
var xh = m.dy*costheta + m.dx*sinphi*sintheta + m.dz*cosphi*sintheta;
var yh = m.dz*sinphi - m.dx*cosphi;
var psi = Math.atan2(yh,xh)*180/Math.PI;
if (psi<0) psi+=360;
return psi;
}

View File

@ -61,24 +61,7 @@ function newHeading(m,h){
var candraw = false;
var CALIBDATA = require("Storage").readJSON("magnav.json",1)||null;
function tiltfixread(O,S){
"ram"
var m = Bangle.getCompass();
var g = Bangle.getAccel();
m.dx =(m.x-O.x)*S.x; m.dy=(m.y-O.y)*S.y; m.dz=(m.z-O.z)*S.z;
var d = Math.atan2(-m.dx,m.dy)*180/Math.PI;
if (d<0) d+=360;
var phi = Math.atan(-g.x/-g.z);
var cosphi = Math.cos(phi), sinphi = Math.sin(phi);
var theta = Math.atan(-g.y/(-g.x*sinphi-g.z*cosphi));
var costheta = Math.cos(theta), sintheta = Math.sin(theta);
var xh = m.dy*costheta + m.dx*sinphi*sintheta + m.dz*cosphi*sintheta;
var yh = m.dz*sinphi - m.dx*cosphi;
var psi = Math.atan2(yh,xh)*180/Math.PI;
if (psi<0) psi+=360;
return psi;
}
const tiltfixread = require("magnav").tiltfixread;
// Note actual mag is 360-m, error in firmware
function reading() {
@ -97,30 +80,6 @@ function reading() {
flip(buf,Yoff+80);
}
function calibrate(){
var max={x:-32000, y:-32000, z:-32000},
min={x:32000, y:32000, z:32000};
var ref = setInterval(()=>{
var m = Bangle.getCompass();
max.x = m.x>max.x?m.x:max.x;
max.y = m.y>max.y?m.y:max.y;
max.z = m.z>max.z?m.z:max.z;
min.x = m.x<min.x?m.x:min.x;
min.y = m.y<min.y?m.y:min.y;
min.z = m.z<min.z?m.z:min.z;
}, 100);
return new Promise((resolve) => {
setTimeout(()=>{
if(ref) clearInterval(ref);
var offset = {x:(max.x+min.x)/2,y:(max.y+min.y)/2,z:(max.z+min.z)/2};
var delta = {x:(max.x-min.x)/2,y:(max.y-min.y)/2,z:(max.z-min.z)/2};
var avg = (delta.x+delta.y+delta.z)/3;
var scale = {x:avg/delta.x, y:avg/delta.y, z:avg/delta.z};
resolve({offset:offset,scale:scale});
},20000);
});
}
var calibrating=false;
function docalibrate(first){
calibrating=true;
@ -139,7 +98,7 @@ function docalibrate(first){
buf.drawString("Fig 8s to",120,0);
buf.drawString("Calibrate",120,26);
flip(buf,Yoff);
calibrate().then((r)=>{
require("magnav").calibrate().then((r)=>{
CALIBDATA=r;
require("Storage").write("magnav.json",r);
restart()

View File

@ -53,24 +53,7 @@ function newHeading(m,h){
var candraw = false;
var CALIBDATA = require("Storage").readJSON("magnav.json",1)||null;
function tiltfixread(O,S){
"ram"
var m = Bangle.getCompass();
var g = Bangle.getAccel();
m.dx =(m.x-O.x)*S.x; m.dy=(m.y-O.y)*S.y; m.dz=(m.z-O.z)*S.z;
var d = Math.atan2(-m.dx,m.dy)*180/Math.PI;
if (d<0) d+=360;
var phi = Math.atan(-g.x/-g.z);
var cosphi = Math.cos(phi), sinphi = Math.sin(phi);
var theta = Math.atan(-g.y/(-g.x*sinphi-g.z*cosphi));
var costheta = Math.cos(theta), sintheta = Math.sin(theta);
var xh = m.dy*costheta + m.dx*sinphi*sintheta + m.dz*cosphi*sintheta;
var yh = m.dz*sinphi - m.dx*cosphi;
var psi = Math.atan2(yh,xh)*180/Math.PI;
if (psi<0) psi+=360;
return psi;
}
const tiltfixread = require("magnav").tiltfixread;
// Note actual mag is 360-m, error in firmware
function reading() {
@ -94,30 +77,6 @@ function reading() {
g.flip();
}
function calibrate(){
var max={x:-32000, y:-32000, z:-32000},
min={x:32000, y:32000, z:32000};
var ref = setInterval(()=>{
var m = Bangle.getCompass();
max.x = m.x>max.x?m.x:max.x;
max.y = m.y>max.y?m.y:max.y;
max.z = m.z>max.z?m.z:max.z;
min.x = m.x<min.x?m.x:min.x;
min.y = m.y<min.y?m.y:min.y;
min.z = m.z<min.z?m.z:min.z;
}, 100);
return new Promise((resolve) => {
setTimeout(()=>{
if(ref) clearInterval(ref);
var offset = {x:(max.x+min.x)/2,y:(max.y+min.y)/2,z:(max.z+min.z)/2};
var delta = {x:(max.x-min.x)/2,y:(max.y-min.y)/2,z:(max.z-min.z)/2};
var avg = (delta.x+delta.y+delta.z)/3;
var scale = {x:avg/delta.x, y:avg/delta.y, z:avg/delta.z};
resolve({offset:offset,scale:scale});
},20000);
});
}
var calibrating=false;
function docalibrate(first){
calibrating=true;
@ -137,7 +96,7 @@ function docalibrate(first){
g.drawString("Fig 8s to",88,Ypos);
g.drawString("Calibrate",88,Ypos+18);
g.flip();
calibrate().then((r)=>{
require("magnav").calibrate().then((r)=>{
CALIBDATA=r;
require("Storage").write("magnav.json",r);
restart();

View File

@ -1,7 +1,7 @@
{
"id": "magnav",
"name": "Navigation Compass",
"version": "0.05",
"version": "0.06",
"description": "Compass with linear display as for GPSNAV. Has Tilt compensation and remembers calibration.",
"screenshots": [{"url":"screenshot-b2.png"},{"url":"screenshot-light-b2.png"}],
"icon": "magnav.png",
@ -11,6 +11,7 @@
"storage": [
{"name":"magnav.app.js","url":"magnav_b1.js","supports":["BANGLEJS"]},
{"name":"magnav.app.js","url":"magnav_b2.js","supports":["BANGLEJS2"]},
{"name":"magnav","url":"lib.js"},
{"name":"magnav.img","url":"magnav-icon.js","evaluate":true}
],
"data": [{"name":"magnav.json"}]

View File

@ -5,3 +5,4 @@
0.05: Fix not displaying of wpindex = 0
0.06: Added adjustment for Bangle.js magnetometer heading fix
0.07: Add settings file with the option to disable the slow direction updates
0.08: Use tilt compensation from new magnav library

View File

@ -85,31 +85,22 @@ function newHeading(m,h){
}
var CALIBDATA = require("Storage").readJSON("magnav.json",1) || {};
function tiltfixread(O,S){
var m = Bangle.getCompass();
if (O === undefined || S === undefined) {
// no valid calibration from magnav, use built in
return m.heading;
}
var g = Bangle.getAccel();
m.dx =(m.x-O.x)*S.x; m.dy=(m.y-O.y)*S.y; m.dz=(m.z-O.z)*S.z;
var d = Math.atan2(-m.dx,m.dy)*180/Math.PI;
if (d<0) d+=360;
var phi = Math.atan(-g.x/-g.z);
var cosphi = Math.cos(phi), sinphi = Math.sin(phi);
var theta = Math.atan(-g.y/(-g.x*sinphi-g.z*cosphi));
var costheta = Math.cos(theta), sintheta = Math.sin(theta);
var xh = m.dy*costheta + m.dx*sinphi*sintheta + m.dz*cosphi*sintheta;
var yh = m.dz*sinphi - m.dx*cosphi;
var psi = Math.atan2(yh,xh)*180/Math.PI;
if (psi<0) psi+=360;
return psi;
let tiltfixread;
try {
tiltfixread = require("magnav").tiltfixread;
} catch(e) {
// magnav not installed
}
// Note actual mag is 360-m, error in firmware
function read_compass() {
var d = tiltfixread(CALIBDATA.offset,CALIBDATA.scale);
let d;
if (tiltfixread === undefined || CALIBDATA.offset === undefined || CALIBDATA.scale === undefined) {
// magnav not installed or no valid calibration, use built in
d = Bangle.getCompass().heading;
} else {
d = tiltfixread(CALIBDATA.offset,CALIBDATA.scale);
}
if (isNaN(d)) return; // built in compass heading can return NaN when uncalibrated
heading = newHeading(d,heading);
direction = wp_bearing - heading;
@ -278,6 +269,9 @@ function doselect(){
wp = waypoints[wpindex];
require("waypoints").save(waypoints);
}
if (selected) {
Bangle.resetCompass(); // reset built in compass when a waypoint is selected
}
selected=!selected;
drawN();
}
@ -294,6 +288,7 @@ Bangle.drawWidgets();
// load widgets can turn off GPS
Bangle.setGPSPower(1);
Bangle.setCompassPower(1);
Bangle.resetCompass() // reset built in compass on start in case we are not using tilt compensation
drawAll();
startTimers();
Bangle.on('GPS', onGPS);

View File

@ -1,12 +1,12 @@
{
"id": "waypointer",
"name": "Way Pointer",
"version": "0.07",
"version": "0.08",
"description": "Navigate to a waypoint using the GPS for bearing and compass to point way, uses the same waypoint interface as GPS Navigation",
"icon": "waypointer.png",
"tags": "tool,outdoors,gps",
"supports": ["BANGLEJS", "BANGLEJS2"],
"dependencies" : { "waypoints":"type" },
"dependencies" : { "waypoints":"type", "magnav" : "app" },
"readme": "README.md",
"storage": [
{"name":"waypointer.app.js","url":"app.js"},

View File

@ -186,8 +186,12 @@ Layout.prototype.render = function (l) {
x+4,y+h-1,
x,y+h-5,
x,y+4
], bg = l.selected?gfx.theme.bgH:gfx.theme.bg2;
gfx.setColor(bg).fillPoly(poly).setColor(l.selected ? gfx.theme.fgH : gfx.theme.fg2).drawPoly(poly);
], bg = l.bgCol!==undefined?l.bgCol:gfx.theme.bg2,
btnborder = l.btnBorder!==undefined?l.btnBorder:gfx.theme.fg2;
if(l.selected){
bg = gfx.theme.bgH, btnborder = gfx.theme.fgH;
}
gfx.setColor(bg).fillPoly(poly).setColor(btnborder).drawPoly(poly);
if (l.col!==undefined) gfx.setColor(l.col);
if (l.src) gfx.setBgColor(bg).drawImage(
"function"==typeof l.src?l.src():l.src,

View File

@ -46,7 +46,8 @@ layout.render();
- A `r` field to set rotation of text or images (0: 0°, 1: 90°, 2: 180°, 3: 270°).
- A `wrap` field to enable line wrapping. Requires some combination of `width`/`height` and `fillx`/`filly` to be set. Not compatible with text rotation.
- A `col` field, eg `#f00` for red
- A `bgCol` field for background color (will automatically fill on render)
- A `bgCol` field for background color (will automatically fill on render). When `type:"btn"`, this sets the background color of the button, and will not change color on press
- A `btnBorder` field for button border color (will default to theme if not set)
- A `halign` field to set horizontal alignment WITHIN a `v` container. `-1`=left, `1`=right, `0`=center
- A `valign` field to set vertical alignment WITHIN a `h` container. `-1`=top, `1`=bottom, `0`=center
- A `pad` integer field to set pixels padding

View File

@ -54,7 +54,7 @@ let storage = require("Storage");
let stepGoal = undefined;
// Load step goal from health app and pedometer widget
let d = storage.readJSON("health.json", true) || {};
stepGoal = d != undefined && d.settings != undefined ? d.settings.stepGoal : undefined;
stepGoal = d.stepGoal;
if (stepGoal == undefined) {
d = storage.readJSON("wpedom.json", true) || {};
stepGoal = d != undefined && d.settings != undefined ? d.settings.goal : 10000;
@ -120,8 +120,10 @@ exports.load = function() {
if (Bangle.getPressure){ // Altimeter may not exist
bangleItems.push({ name : "Altitude",
hasRange : true,
get : () => ({
text : alt, v : alt,
text : alt, v : parseInt(alt),
min : 0, max : 3000,
img : atob("GBiBAAAAAAAAAAAAAAAAAAAAAAACAAAGAAAPAAEZgAOwwAPwQAZgYAwAMBgAGBAACDAADGAABv///////wAAAAAAAAAAAAAAAAAAAA==")
}),
show : function() { this.interval = setInterval(altUpdateHandler, 60000); alt = "--"; altUpdateHandler(); },
@ -266,7 +268,14 @@ exports.addInteractive = function(menu, options) {
}
Bangle.on("swipe",swipeHandler);
var touchHandler;
var lockHandler;
if (options.x!==undefined && options.y!==undefined && options.w && options.h) {
lockHandler = function() {
if(options.focus) {
options.focus=false;
options.redraw();
}
};
touchHandler = function(_,e) {
if (e.x<options.x || e.y<options.y ||
e.x>(options.x+options.w) || e.y>(options.y+options.h)) {
@ -278,7 +287,7 @@ exports.addInteractive = function(menu, options) {
}
if (!options.focus) {
options.focus=true; // if not focussed, set focus
options.redraw();
options.redraw();
} else if (menu[options.menuA].items[options.menuB].run) {
Bangle.buzz(100, 0.7);
menu[options.menuA].items[options.menuB].run(); // allow tap on an item to run it (eg home assistant)
@ -287,6 +296,7 @@ exports.addInteractive = function(menu, options) {
}
};
Bangle.on("touch",touchHandler);
Bangle.on("lock", lockHandler);
}
// draw the first item
menuShowItem(menu[options.menuA].items[options.menuB]);
@ -294,6 +304,7 @@ exports.addInteractive = function(menu, options) {
options.remove = function() {
Bangle.removeListener("swipe",swipeHandler);
if (touchHandler) Bangle.removeListener("touch",touchHandler);
if (lockHandler) Bangle.removeListener("lock", lockHandler);
menuHideItem(menu[options.menuA].items[options.menuB]);
exports.loadCount--;
};

View File

@ -1,6 +1,6 @@
// draw an arc between radii minR and maxR, and between angles minAngle and maxAngle centered at X,Y. All angles are radians.
exports.fillArc = function(graphics, X, Y, minR, maxR, minAngle, maxAngle, stepAngle) {
var step = stepAngle || 0.2;
var step = stepAngle || 0.21;
var angle = minAngle;
var inside = [];
var outside = [];
@ -31,5 +31,5 @@ exports.degreesToRadians = function(degrees){
}
exports.radiansToDegrees = function(radians){
return 180/Math.PI * degrees;
return 180/Math.PI * radians;
}