BangleApps/apps/speedalt2/app.js

779 lines
18 KiB
JavaScript
Raw Normal View History

2021-10-19 01:02:29 +00:00
/*
Speed and Altitude [speedalt2]
Mike Bennett mike[at]kereru.com
2021-10-29 09:19:35 +00:00
1.10 : add inverted colours
2022-02-03 08:45:34 +00:00
1.14 : Add VMG screen
2022-02-04 02:17:25 +00:00
1.34 : Add bluetooth data stream for Droidscript
2022-02-05 00:33:58 +00:00
1.43 : Keep GPS in SuperE mode while using Droiscript screen mirroring
2022-05-23 04:13:52 +00:00
1.50 : Add cfg.wptSfx one char suffix to append to waypoints.json filename. Protects speedalt2 waypoints from other apps that use the same file name for waypoints.
2021-10-19 01:02:29 +00:00
*/
2022-05-23 04:13:52 +00:00
var v = '1.50';
2022-02-07 19:27:32 +00:00
var vDroid = '1.50'; // Required DroidScript program version
2021-10-19 01:02:29 +00:00
/*kalmanjs, Wouter Bulten, MIT, https://github.com/wouterbulten/kalmanjs */
var KalmanFilter = (function () {
'use strict';
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
/**
* KalmanFilter
* @class
* @author Wouter Bulten
* @see {@link http://github.com/wouterbulten/kalmanjs}
* @version Version: 1.0.0-beta
* @copyright Copyright 2015-2018 Wouter Bulten
* @license MIT License
* @preserve
*/
var KalmanFilter =
/*#__PURE__*/
function () {
/**
* Create 1-dimensional kalman filter
* @param {Number} options.R Process noise
* @param {Number} options.Q Measurement noise
* @param {Number} options.A State vector
* @param {Number} options.B Control vector
* @param {Number} options.C Measurement vector
* @return {KalmanFilter}
*/
function KalmanFilter() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref$R = _ref.R,
R = _ref$R === void 0 ? 1 : _ref$R,
_ref$Q = _ref.Q,
Q = _ref$Q === void 0 ? 1 : _ref$Q,
_ref$A = _ref.A,
A = _ref$A === void 0 ? 1 : _ref$A,
_ref$B = _ref.B,
B = _ref$B === void 0 ? 0 : _ref$B,
_ref$C = _ref.C,
C = _ref$C === void 0 ? 1 : _ref$C;
_classCallCheck(this, KalmanFilter);
this.R = R; // noise power desirable
this.Q = Q; // noise power estimated
this.A = A;
this.C = C;
this.B = B;
this.cov = NaN;
this.x = NaN; // estimated signal without noise
}
/**
* Filter a new value
* @param {Number} z Measurement
* @param {Number} u Control
* @return {Number}
*/
_createClass(KalmanFilter, [{
key: "filter",
value: function filter(z) {
var u = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
if (isNaN(this.x)) {
this.x = 1 / this.C * z;
this.cov = 1 / this.C * this.Q * (1 / this.C);
} else {
// Compute prediction
var predX = this.predict(u);
var predCov = this.uncertainty(); // Kalman gain
var K = predCov * this.C * (1 / (this.C * predCov * this.C + this.Q)); // Correction
this.x = predX + K * (z - this.C * predX);
this.cov = predCov - K * this.C * predCov;
}
return this.x;
}
/**
* Predict next value
* @param {Number} [u] Control
* @return {Number}
*/
}, {
key: "predict",
value: function predict() {
var u = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
return this.A * this.x + this.B * u;
}
/**
* Return uncertainty of filter
* @return {Number}
*/
}, {
key: "uncertainty",
value: function uncertainty() {
return this.A * this.cov * this.A + this.R;
}
/**
* Return the last filtered measurement
* @return {Number}
*/
}, {
key: "lastMeasurement",
value: function lastMeasurement() {
return this.x;
}
/**
* Set measurement noise Q
* @param {Number} noise
*/
}, {
key: "setMeasurementNoise",
value: function setMeasurementNoise(noise) {
this.Q = noise;
}
/**
* Set the process noise R
* @param {Number} noise
*/
}, {
key: "setProcessNoise",
value: function setProcessNoise(noise) {
this.R = noise;
}
}]);
return KalmanFilter;
}();
return KalmanFilter;
}());
var buf = Graphics.createArrayBuffer(240,160,2,{msb:true});
2022-02-09 03:03:18 +00:00
2021-10-29 03:14:40 +00:00
let LED = // LED as minimal and only definition (as instance / singleton)
{ isOn: false // status on / off, not needed if you don't need to ask for it
, set: function(v) { // turn on w/ no arg or truey, else off
2022-03-01 08:12:53 +00:00
this.isOn = v===undefined||!!v;
g.setColor(this.isOn?1:0,0,0).fillCircle(120,10,10); }
2021-10-29 03:14:40 +00:00
, reset: function() { this.set(false); } // turn off
, write: function(v) { this.set(v); } // turn on w/ no arg or truey, else off
, toggle: function() { this.set( ! this.isOn); } // toggle the LED
}, LED1 = LED; // LED1 as 'synonym' for LED
2022-02-09 03:03:18 +00:00
2021-10-29 03:14:40 +00:00
2021-10-19 01:02:29 +00:00
var lf = {fix:0,satellites:0};
var showMax = 0; // 1 = display the max values. 0 = display the cur fix
var pwrSav = 1; // 1 = default power saving with watch screen off and GPS to PMOO mode. 0 = screen kept on.
var canDraw = 1;
var tmrLP; // Timer for delay in switching to low power after screen turns off
2021-10-29 03:14:40 +00:00
var maxSpd = 0;
var maxAlt = 0;
var maxN = 0; // counter. Only start comparing for max after a certain number of fixes to allow kalman filter to have smoohed the data.
2021-10-19 01:02:29 +00:00
var emulator = (process.env.BOARD=="EMSCRIPTEN")?1:0; // 1 = running in emulator. Supplies test values;
2022-02-04 01:36:40 +00:00
var bt = 0; // 0 = bluetooth data feed off. 1 = on
2022-02-04 08:52:29 +00:00
var btLast = 0; // time of last bt transmit
2021-10-19 01:02:29 +00:00
var wp = {}; // Waypoint to use for distance from cur position.
2021-10-29 03:14:40 +00:00
function nxtWp(){
cfg.wp++;
2021-10-19 01:02:29 +00:00
loadWp();
}
function loadWp() {
var w = require("waypoints").load(cfg.wptSfx);
2021-10-19 01:02:29 +00:00
if (cfg.wp>=w.length) cfg.wp=0;
if (cfg.wp<0) cfg.wp = w.length-1;
savSettings();
wp = w[cfg.wp];
}
function radians(a) {
return a*Math.PI/180;
}
2022-02-03 08:45:34 +00:00
function degrees(a) {
var d = a*180/Math.PI;
return (d+360)%360;
}
function bearing(a,b){
var delta = radians(b.lon-a.lon);
var alat = radians(a.lat);
var blat = radians(b.lat);
var y = Math.sin(delta) * Math.cos(blat);
var x = Math.cos(alat)*Math.sin(blat) -
Math.sin(alat)*Math.cos(blat)*Math.cos(delta);
return Math.round(degrees(Math.atan2(y, x)));
}
2021-10-19 01:02:29 +00:00
function distance(a,b){
var x = radians(a.lon-b.lon) * Math.cos(radians((a.lat+b.lat)/2));
var y = radians(b.lat-a.lat);
2022-02-03 08:45:34 +00:00
// Distance in metres
2021-10-19 01:02:29 +00:00
var d = Math.sqrt(x*x + y*y) * 6371000;
return d;
}
function drawScrn(dat) {
if (!canDraw) return;
buf.clear();
2021-10-29 09:19:35 +00:00
buf.setBgColor(0);
2021-10-19 01:02:29 +00:00
var n;
n = dat.val.toString();
2021-10-19 03:09:29 +00:00
var s=50; // Font size
2021-10-19 01:02:29 +00:00
var l=n.length;
2021-10-19 03:09:29 +00:00
if ( l <= 7 ) s=55;
if ( l <= 6 ) s=60;
if ( l <= 5 ) s=80;
if ( l <= 4 ) s=100;
if ( l <= 3 ) s=120;
buf.setFontAlign(0,0); //Centre
buf.setColor(1);
2021-10-19 01:02:29 +00:00
buf.setFontVector(s);
2021-10-19 03:09:29 +00:00
buf.drawString(n,126,52);
2021-10-19 01:02:29 +00:00
// Primary Units
buf.setFontAlign(-1,1); //left, bottom
buf.setColor(2);
2021-10-19 01:02:29 +00:00
buf.setFontVector(35);
buf.drawString(dat.unit,5,164);
2021-10-29 03:14:40 +00:00
drawMax(dat.max); // MAX display indicator
drawWP(dat.wp); // Waypoint name
drawSats(dat.sats);
2021-10-19 01:02:29 +00:00
g.reset();
g.drawImage(img,0,40);
2021-10-29 03:14:40 +00:00
LED1.write(!pwrSav);
2021-10-19 03:09:29 +00:00
2021-10-19 01:02:29 +00:00
}
2021-10-20 01:39:46 +00:00
function drawPosn(dat) {
if (!canDraw) return;
buf.clear();
2021-10-29 09:19:35 +00:00
buf.setBgColor(0);
2021-10-20 01:39:46 +00:00
var x, y;
x=210;
y=0;
buf.setFontAlign(1,-1);
2021-10-20 01:39:46 +00:00
buf.setFontVector(60);
buf.setColor(1);
2021-10-20 06:47:15 +00:00
buf.drawString(dat.lat,x,y);
buf.drawString(dat.lon,x,y+70);
2021-10-20 01:39:46 +00:00
x = 240;
buf.setColor(2);
buf.setFontVector(40);
2021-10-20 06:47:15 +00:00
buf.drawString(dat.ns,x,y);
buf.drawString(dat.ew,x,y+70);
2021-10-20 01:39:46 +00:00
2021-10-29 03:14:40 +00:00
drawSats(dat.sats);
2021-10-20 06:47:15 +00:00
2021-10-20 01:39:46 +00:00
g.reset();
g.drawImage(img,0,40);
2021-10-20 06:47:15 +00:00
2021-10-29 03:14:40 +00:00
LED1.write(!pwrSav);
2021-10-20 01:39:46 +00:00
}
2021-10-19 01:02:29 +00:00
function drawClock() {
if (!canDraw) return;
2021-10-19 01:02:29 +00:00
buf.clear();
2021-10-29 09:19:35 +00:00
buf.setBgColor(0);
2021-10-19 01:02:29 +00:00
var x, y;
2021-10-20 01:39:46 +00:00
x=185;
2021-10-19 01:02:29 +00:00
y=0;
buf.setFontAlign(1,-1);
2021-10-20 01:39:46 +00:00
buf.setFontVector(94);
2024-03-13 10:51:40 +00:00
const time = require("locale").time(new Date(),1);
2021-10-20 05:12:03 +00:00
buf.setColor(1);
2021-10-20 01:39:46 +00:00
buf.drawString(time.substring(0,2),x,y);
buf.drawString(time.substring(3,5),x,y+80);
2021-10-19 01:02:29 +00:00
g.reset();
g.drawImage(img,0,40);
2021-10-29 03:14:40 +00:00
LED1.write(!pwrSav);
2021-10-19 01:02:29 +00:00
}
2021-10-29 03:14:40 +00:00
function drawWP(wp) {
buf.setColor(3);
2021-10-19 01:02:29 +00:00
buf.setFontAlign(0,1); //left, bottom
2022-02-03 08:45:34 +00:00
buf.setFontVector(40);
buf.drawString(wp,120,132);
2021-10-19 01:02:29 +00:00
}
function drawSats(sats) {
buf.setColor(3);
2021-10-19 01:02:29 +00:00
buf.setFont("6x8", 2);
buf.setFontAlign(1,1); //right, bottom
buf.drawString(sats,240,160);
2021-10-19 01:02:29 +00:00
}
2021-10-29 03:14:40 +00:00
function drawMax(max) {
2021-10-19 01:02:29 +00:00
buf.setFontVector(30);
buf.setColor(2);
2021-10-19 01:02:29 +00:00
buf.setFontAlign(0,1); //centre, bottom
2021-10-29 03:14:40 +00:00
buf.drawString(max,120,164);
2021-10-19 01:02:29 +00:00
}
function onGPS(fix) {
2021-10-29 03:14:40 +00:00
if ( emulator ) {
2021-10-19 01:02:29 +00:00
fix.fix = 1;
fix.speed = 10 + (Math.random()*5);
fix.alt = 354 + (Math.random()*50);
fix.lat = -38.92;
fix.lon = 175.7613350;
2021-10-19 01:02:29 +00:00
fix.course = 245;
fix.satellites = 12;
fix.time = new Date();
fix.smoothed = 0;
}
2024-03-04 20:34:50 +00:00
//var m;
2021-10-19 01:02:29 +00:00
var sp = '---';
2022-02-03 08:45:34 +00:00
var al = sp;
var di = sp;
var brg = ''; // bearing
var crs = ''; // course
var age = sp;
2021-10-20 06:47:15 +00:00
var lat = '---.--';
var ns = '';
var ew = '';
var lon = '---.--';
2022-02-03 08:45:34 +00:00
var sats = sp;
var vmg = sp;
2021-10-29 05:51:39 +00:00
// Waypoint name
var wpName = wp.name;
if ( wpName == undefined || wpName == 'NONE' ) wpName = '';
wpName = wpName.substring(0,8);
2021-10-19 01:02:29 +00:00
if (fix.fix) lf = fix;
2021-10-19 01:02:29 +00:00
if (lf.fix) {
// Smooth data
if ( lf.smoothed !== 1 ) {
if ( cfg.spdFilt ) lf.speed = spdFilter.filter(lf.speed);
if ( cfg.altFilt ) lf.alt = altFilter.filter(lf.alt);
lf.smoothed = 1;
2021-10-29 03:14:40 +00:00
if ( maxN <= 15 ) maxN++;
2021-10-19 01:02:29 +00:00
}
2022-02-03 08:45:34 +00:00
// Bearing to waypoint
brg = bearing(lf,wp);
2022-02-03 08:45:34 +00:00
// Current course
crs = lf.course;
// Relative angle to wp
var a = Math.max(crs,brg) - Math.min(crs,brg);
if ( a >= 180 ) a = 360 -a;
2021-10-20 06:47:15 +00:00
2021-10-19 01:02:29 +00:00
// Speed
2022-02-03 08:45:34 +00:00
sp = parseFloat(lf.speed)/parseFloat(cfg.spd); // Calculate for selected units
// vmg
if ( a >= 90 ) vmg = sp * Math.cos(radians(180-a)) * -1; // moving away from WP
else vmg = sp * Math.cos(radians(a)); // towards wp
2021-10-31 22:58:16 +00:00
2021-10-19 01:02:29 +00:00
if ( sp < 10 ) sp = sp.toFixed(1);
else sp = Math.round(sp);
2021-10-29 03:31:23 +00:00
if (isNaN(sp)) sp = '---';
2021-10-29 03:14:40 +00:00
if (parseFloat(sp) > parseFloat(maxSpd) && maxN > 15 ) maxSpd = sp;
2021-10-19 01:02:29 +00:00
2022-02-03 08:45:34 +00:00
if ( Math.abs(vmg) >= 0.05 && Math.abs(vmg) < 10 ) vmg = vmg.toFixed(1);
else vmg = Math.round(vmg);
if (isNaN(vmg)) vmg = '---';
2021-10-19 01:02:29 +00:00
// Altitude
al = lf.alt;
al = Math.round(parseFloat(al)/parseFloat(cfg.alt));
2021-10-29 03:14:40 +00:00
if (parseFloat(al) > parseFloat(maxAlt) && maxN > 15 ) maxAlt = al;
2021-10-29 03:31:23 +00:00
if (isNaN(al)) al = '---';
2021-10-19 01:02:29 +00:00
2021-10-31 22:39:30 +00:00
// Distance to waypoint
2021-10-19 01:02:29 +00:00
di = distance(lf,wp);
2022-02-03 08:45:34 +00:00
di = (di/parseFloat(cfg.dist)).toFixed(2);
if ( di >= 100 ) di = parseFloat(di).toFixed(1);
if ( di >= 1000 ) di = parseFloat(di).toFixed(0);
if (isNaN(di)) di = '------';
2021-10-19 01:02:29 +00:00
// Age of last fix (secs)
age = Math.max(0,Math.round(getTime())-(lf.time.getTime()/1000));
2021-10-20 06:47:15 +00:00
// Lat / Lon
ns = 'N';
if ( lf.lat < 0 ) ns = 'S';
lat = Math.abs(lf.lat.toFixed(2));
2021-10-20 06:47:15 +00:00
ew = 'E';
if ( lf.lon < 0 ) ew = 'W';
lon = Math.abs(lf.lon.toFixed(2));
2021-10-29 03:14:40 +00:00
// Sats
if ( age > 10 ) {
2021-10-29 03:31:23 +00:00
sats = 'Age:'+Math.round(age);
2021-10-29 03:14:40 +00:00
if ( age > 90 ) sats = 'Age:>90';
}
else sats = 'Sats:'+lf.satellites;
2021-10-20 06:47:15 +00:00
2021-10-19 01:02:29 +00:00
}
2022-02-04 02:33:45 +00:00
2022-02-04 02:17:25 +00:00
// Bluetooth send data
btSend({
2022-02-05 10:28:47 +00:00
id:'speedalt2',
2022-02-04 20:52:30 +00:00
v:v,
2022-02-05 12:04:27 +00:00
vd:vDroid,
2022-02-04 20:52:30 +00:00
m:cfg.modeA,
2022-02-04 02:17:25 +00:00
spd_unit:cfg.spd_unit,
alt_unit:cfg.alt_unit,
dist_unit:cfg.dist_unit,
wp:wpName,
sp:sp,
al:al,
2022-02-04 04:39:26 +00:00
di:di,
2022-02-04 02:17:25 +00:00
sats:sats,
2022-02-04 22:10:56 +00:00
vmg:vmg,
lat:lat,
lon:lon,
ns:ns,
ew:ew
2022-02-04 02:17:25 +00:00
});
2022-02-04 02:33:45 +00:00
2021-10-19 01:02:29 +00:00
if ( cfg.modeA == 0 ) {
// Speed
2022-02-04 02:17:25 +00:00
if ( showMax ) {
2021-10-19 01:02:29 +00:00
drawScrn({
2021-10-29 03:14:40 +00:00
val:maxSpd,
2021-10-19 01:02:29 +00:00
unit:cfg.spd_unit,
2021-10-29 03:14:40 +00:00
sats:sats,
2021-10-19 01:02:29 +00:00
age:age,
2021-10-29 03:14:40 +00:00
max:'MAX',
wp:''
2021-10-19 01:02:29 +00:00
}); // Speed maximums
2022-02-04 02:17:25 +00:00
}
else {
2021-10-19 01:02:29 +00:00
drawScrn({
val:sp,
unit:cfg.spd_unit,
2021-10-29 03:14:40 +00:00
sats:sats,
2021-10-19 01:02:29 +00:00
age:age,
2021-10-31 20:24:24 +00:00
max:'SPD',
2021-10-29 03:14:40 +00:00
wp:''
2021-10-19 01:02:29 +00:00
});
2022-02-04 02:17:25 +00:00
}
2021-10-19 01:02:29 +00:00
}
if ( cfg.modeA == 1 ) {
// Alt
2022-02-04 02:17:25 +00:00
if ( showMax ) {
2021-10-19 01:02:29 +00:00
drawScrn({
2021-10-29 03:14:40 +00:00
val:maxAlt,
2021-10-19 01:02:29 +00:00
unit:cfg.alt_unit,
2021-10-29 03:14:40 +00:00
sats:sats,
2021-10-19 01:02:29 +00:00
age:age,
2021-10-29 03:14:40 +00:00
max:'MAX',
wp:''
2021-10-19 01:02:29 +00:00
}); // Alt maximums
2022-02-04 02:17:25 +00:00
}
else {
2021-10-19 01:02:29 +00:00
drawScrn({
val:al,
unit:cfg.alt_unit,
2021-10-29 03:14:40 +00:00
sats:sats,
2021-10-19 01:02:29 +00:00
age:age,
2021-10-31 20:24:24 +00:00
max:'ALT',
2021-10-29 03:14:40 +00:00
wp:''
2021-10-19 01:02:29 +00:00
});
2022-02-04 02:17:25 +00:00
}
2021-10-19 01:02:29 +00:00
}
if ( cfg.modeA == 2 ) {
// Dist
drawScrn({
val:di,
unit:cfg.dist_unit,
2021-10-29 03:14:40 +00:00
sats:sats,
2021-10-19 01:02:29 +00:00
age:age,
2021-10-31 20:24:24 +00:00
max:'DST',
2021-10-29 03:14:40 +00:00
wp:wpName
2021-10-19 01:02:29 +00:00
});
}
2021-10-20 01:39:46 +00:00
if ( cfg.modeA == 3 ) {
2022-02-03 08:45:34 +00:00
// VMG
drawScrn({
val:vmg,
unit:cfg.spd_unit,
sats:sats,
age:age,
max:'VMG',
wp:wpName
});
}
if ( cfg.modeA == 4 ) {
2021-10-20 01:39:46 +00:00
// Position
2021-10-29 03:14:40 +00:00
drawPosn({
sats:sats,
2021-10-20 01:39:46 +00:00
age:age,
2021-10-20 06:47:15 +00:00
lat:lat,
lon:lon,
ns:ns,
2021-10-29 03:14:40 +00:00
ew:ew
2021-10-20 01:39:46 +00:00
});
}
2022-02-03 08:45:34 +00:00
if ( cfg.modeA == 5 ) {
2021-10-19 01:02:29 +00:00
// Large clock
drawClock();
}
}
2021-10-20 02:11:01 +00:00
function prevScrn() {
cfg.modeA = cfg.modeA-1;
2022-02-03 08:45:34 +00:00
if ( cfg.modeA < 0 ) cfg.modeA = 5;
2021-10-20 02:11:01 +00:00
savSettings();
onGPS(lf);
2021-10-20 02:11:01 +00:00
}
function nextScrn() {
cfg.modeA = cfg.modeA+1;
2022-02-03 08:45:34 +00:00
if ( cfg.modeA > 5 ) cfg.modeA = 0;
2021-10-20 02:11:01 +00:00
savSettings();
onGPS(lf);
2021-10-20 02:11:01 +00:00
}
2021-10-20 03:50:20 +00:00
// Next function on a screen
2021-10-20 04:01:09 +00:00
function nextFunc(dur) {
2021-10-19 01:02:29 +00:00
if ( cfg.modeA == 0 || cfg.modeA == 1 ) {
// Spd+Alt mode - Switch between fix and MAX
if ( dur < 2 ) showMax = !showMax; // Short press toggle fix/max display
2021-10-29 03:14:40 +00:00
else { maxSpd = 0; maxAlt = 0; } // Long press resets max values.
2021-10-19 01:02:29 +00:00
}
2022-02-03 08:45:34 +00:00
else if ( cfg.modeA == 2 || cfg.modeA == 3) nxtWp(); // Dist or VMG mode - Select next waypoint
2021-10-19 01:02:29 +00:00
onGPS(lf);
2021-10-20 03:50:20 +00:00
}
2021-10-21 21:59:37 +00:00
function updateClock() {
if (!canDraw) return;
2022-02-03 08:45:34 +00:00
if ( cfg.modeA != 5 ) return;
drawClock();
2021-10-29 03:14:40 +00:00
if ( emulator ) {maxSpd++;maxAlt++;}
2021-10-21 21:59:37 +00:00
}
function startDraw(){
canDraw=true;
g.clear();
Bangle.drawWidgets();
setLpMode('SuperE'); // off
onGPS(lf); // draw app screen
}
function stopDraw() {
canDraw=false;
2022-02-05 00:33:58 +00:00
if ( bt ) return; // If bt screen mirror to Droidscript in use then keep GPS in SuperE mode to keep screen updates going.
2021-10-21 21:59:37 +00:00
if (!tmrLP) tmrLP=setInterval(function () {if (lf.fix) setLpMode('PSMOO');}, 10000); //Drop to low power in 10 secs. Keep lp mode off until we have a first fix.
}
function savSettings() {
require("Storage").write('speedalt2.json',cfg);
}
function setLpMode(m) {
if (tmrLP) {clearInterval(tmrLP);tmrLP = false;} // Stop any scheduled drop to low power
if ( !gpssetup ) return;
gpssetup.setPowerMode({power_mode:m});
}
2022-02-04 20:50:53 +00:00
// == Droidscript bluetooth data
2022-02-03 19:16:29 +00:00
2022-02-04 01:23:40 +00:00
function btOn(b) {
2022-02-04 20:50:53 +00:00
bt = b; // Turn data transmit on/off
}
2022-02-04 01:23:40 +00:00
function btSend(dat) {
2022-02-04 08:52:29 +00:00
if ( ! bt ) return; // bt transmit off
var dur = getTime() - btLast;
2022-02-05 07:48:36 +00:00
if ( dur < 1.0 ) return; // Don't need to transmit more than every 1.0 secs.
2022-02-04 08:52:29 +00:00
btLast = getTime();
2022-02-07 19:17:31 +00:00
Bluetooth.println(JSON.stringify(dat)); // transmit the data
2022-02-03 08:45:34 +00:00
}
2022-02-03 19:16:29 +00:00
2021-10-21 21:59:37 +00:00
// == Events
2021-10-20 03:50:20 +00:00
function setButtons(){
// BTN1 - Max speed/alt or next waypoint
setWatch(function(e) {
var dur = e.time - e.lastTime;
nextFunc(dur);
2021-10-19 01:02:29 +00:00
}, BTN1, { edge:"falling",repeat:true});
// Power saving on/off
2021-10-19 01:02:29 +00:00
setWatch(function(e){
pwrSav=!pwrSav;
2021-10-19 01:02:29 +00:00
if ( pwrSav ) {
var s = require('Storage').readJSON('setting.json',1)||{};
var t = s.timeout||10;
Bangle.setLCDTimeout(t);
}
else {
Bangle.setLCDTimeout(0);
2021-10-21 19:16:59 +00:00
// Bangle.setLCDPower(1);
2021-10-19 01:02:29 +00:00
}
2021-10-29 03:14:40 +00:00
LED1.write(!pwrSav);
2021-10-19 01:02:29 +00:00
}, BTN2, {repeat:true,edge:"falling"});
2021-10-19 01:02:29 +00:00
// BTN3 - next screen
setWatch(function(e){
2021-10-20 02:11:01 +00:00
nextScrn();
2021-10-19 01:02:29 +00:00
}, BTN3, {repeat:true,edge:"falling"});
}
2021-10-21 21:59:37 +00:00
Bangle.on('lcdPower',function(on) {
if (!SCREENACCESS.withApp) return;
if (on) startDraw();
2021-10-21 21:59:37 +00:00
else stopDraw();
});
2021-10-19 01:02:29 +00:00
2021-10-21 21:59:37 +00:00
Bangle.on('swipe',function(dir) {
2021-10-24 20:25:06 +00:00
if ( ! cfg.touch ) return;
2021-10-21 22:16:13 +00:00
if(dir == 1) prevScrn();
else nextScrn();
2021-10-21 21:59:37 +00:00
});
2021-10-19 01:02:29 +00:00
2021-10-21 21:59:37 +00:00
Bangle.on('touch', function(button){
2021-10-24 20:25:06 +00:00
if ( ! cfg.touch ) return;
2021-10-21 22:16:13 +00:00
nextFunc(0); // Same function as short BTN1
2022-02-03 08:45:34 +00:00
});
2021-10-21 22:16:13 +00:00
2021-10-21 21:59:37 +00:00
// == Main Prog
2021-10-19 01:02:29 +00:00
// Read settings.
2021-10-19 02:14:44 +00:00
let cfg = require('Storage').readJSON('speedalt2.json',1)||{};
2021-10-19 01:02:29 +00:00
2022-02-03 08:45:34 +00:00
cfg.spd = cfg.spd||1; // Multiplier for speed unit conversions. 0 = use the locale values for speed
cfg.spd_unit = cfg.spd_unit||'kph'; // Displayed speed unit
2021-10-19 01:02:29 +00:00
cfg.alt = cfg.alt||0.3048;// Multiplier for altitude unit conversions.
cfg.alt_unit = cfg.alt_unit||'feet'; // Displayed altitude units
cfg.dist = cfg.dist||1000;// Multiplier for distnce unit conversions.
cfg.dist_unit = cfg.dist_unit||'km'; // Displayed altitude units
cfg.colour = cfg.colour||0; // Colour scheme.
cfg.wp = cfg.wp||0; // Last selected waypoint for dist
cfg.modeA = cfg.modeA||0; // 0=Speed 1=Alt 2=Dist 3 = vmg 4=Position 5=Clock
2021-10-19 01:02:29 +00:00
cfg.primSpd = cfg.primSpd||0; // 1 = Spd in primary, 0 = Spd in secondary
cfg.spdFilt = cfg.spdFilt==undefined?true:cfg.spdFilt;
2021-10-19 01:02:29 +00:00
cfg.altFilt = cfg.altFilt==undefined?true:cfg.altFilt;
2021-10-24 20:25:06 +00:00
cfg.touch = cfg.touch==undefined?true:cfg.touch;
cfg.wptSfx = cfg.wptSfx==undefined?'':cfg.wptSfx;
2021-10-19 01:02:29 +00:00
if ( cfg.spdFilt ) var spdFilter = new KalmanFilter({R: 0.1 , Q: 1 });
if ( cfg.altFilt ) var altFilter = new KalmanFilter({R: 0.01, Q: 2 });
loadWp();
/*
Colour Pallet Idx
0 : Background (black)
1 : Speed/Alt
2 : Units
3 : Sats
*/
var img = {
width:buf.getWidth(),
height:buf.getHeight(),
bpp:2,
buffer:buf.buffer,
palette:new Uint16Array([0,0x4FE0,0xEFE0,0x07DB])
};
if ( cfg.colour == 1 ) img.palette = new Uint16Array([0,0xFFFF,0xFFF6,0xDFFF]);
2021-10-29 08:55:45 +00:00
if ( cfg.colour == 2 ) img.palette = new Uint16Array([0,0xF800,0xFAE0,0xF813]);
2021-10-29 09:19:35 +00:00
if ( cfg.colour == 3 ) img.palette = new Uint16Array([0xFFFF,0x007F,0x0054,0x0054]);
2021-10-19 01:02:29 +00:00
var SCREENACCESS = {
withApp:true,
request:function(){this.withApp=false;stopDraw();},
release:function(){this.withApp=true;startDraw();}
};
2021-10-19 01:02:29 +00:00
var gpssetup;
try {
gpssetup = require("gpssetup");
} catch(e) {
gpssetup = false;
}
// All set up. Lets go.
g.clear();
Bangle.loadWidgets();
Bangle.drawWidgets();
onGPS(lf);
Bangle.setGPSPower(1);
if ( gpssetup ) {
gpssetup.setPowerMode({power_mode:"SuperE"}).then(function() { Bangle.setGPSPower(1); });
}
else {
Bangle.setGPSPower(1);
}
Bangle.on('GPS', onGPS);
setButtons();
setInterval(updateClock, 10000);