mirror of https://github.com/espruino/BangleApps
809 lines
21 KiB
JavaScript
809 lines
21 KiB
JavaScript
// read in the faces
|
|
var FACES = [];
|
|
var STOR = require("Storage");
|
|
STOR.list(/\.kit\.js$/).forEach(face=>FACES.push(eval(require("Storage").read(face))));
|
|
var iface = STOR.list(/\.kit\.js$/).indexOf("stepo2.kit.js");
|
|
var face = FACES[iface]();
|
|
var firstPress
|
|
var pressTimer;
|
|
|
|
function stopdraw() {
|
|
face.stopTimer();
|
|
}
|
|
|
|
function startdraw() {
|
|
Bangle.drawWidgets();
|
|
face.startTimer();
|
|
}
|
|
|
|
function nextFace(){
|
|
stopdraw();
|
|
face.freeResources();
|
|
|
|
iface += 1
|
|
iface = iface % FACES.length;
|
|
face = FACES[iface]();
|
|
|
|
g.clear();
|
|
g.reset();
|
|
face.init(gpsObj, swObj, hrmObj, tripObject);
|
|
startdraw();
|
|
}
|
|
|
|
// when you feel the buzzer you know you have done a long press
|
|
function longPressCheck() {
|
|
Bangle.buzz();
|
|
debug_log("BUZZ, long press");
|
|
if (pressTimer) {
|
|
clearInterval(pressTimer);
|
|
debug_log("CLEAR pressTimer 2");
|
|
pressTimer = undefined;
|
|
}
|
|
}
|
|
|
|
// start a timer and buzz when held long enough
|
|
function buttonPressed(btn) {
|
|
if (btn === 3) {
|
|
nextFace();
|
|
} else {
|
|
firstPress = getTime();
|
|
if (pressTimer) {
|
|
debug_log("CLEAR pressTimer 1");
|
|
clearInterval(pressTimer);
|
|
}
|
|
debug_log("SET pressTimer 1");
|
|
pressTimer = setInterval(longPressCheck, 1500);
|
|
}
|
|
}
|
|
|
|
// if you release too soon there is no buzz as timer is cleared
|
|
function buttonReleased(btn) {
|
|
var dur = getTime() - firstPress;
|
|
if (pressTimer) {
|
|
debug_log("CLEAR pressTimer 3");
|
|
clearInterval(pressTimer);
|
|
pressTimer = undefined;
|
|
}
|
|
|
|
if ( dur >= 1.5 ) {
|
|
switch(btn) {
|
|
case 1:
|
|
face.onButtonLong(btn);
|
|
break;
|
|
case 2:
|
|
face.onButtonLong(btn);
|
|
//Bangle.showLauncher();
|
|
break;
|
|
case 3:
|
|
// do nothing
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (btn !== 3) face.onButtonShort(btn);
|
|
}
|
|
|
|
function setButtons(){
|
|
setWatch(buttonPressed.bind(null,1), BTN1, {repeat:true,edge:"rising"});
|
|
setWatch(buttonPressed.bind(null,2), BTN2, {repeat:true,edge:"rising"});
|
|
setWatch(nextFace, BTN3, {repeat:true,edge:"rising"});
|
|
|
|
setWatch(buttonReleased.bind(null,1), BTN1, {repeat:true,edge:"falling"});
|
|
setWatch(buttonReleased.bind(null,2), BTN2, {repeat:true,edge:"falling"});
|
|
// BTN 3 long press should always reset the bangle
|
|
}
|
|
|
|
Bangle.on('kill',()=>{
|
|
Bangle.setCompassPower(0,'kitchen');
|
|
Bangle.setGPSPower(0,'kitchen');
|
|
});
|
|
|
|
Bangle.on('lcdPower',function(on) {
|
|
if (on) {
|
|
startdraw();
|
|
} else {
|
|
stopdraw();
|
|
}
|
|
});
|
|
|
|
/*****************************************************************************
|
|
|
|
Start of GPS object code so we can share it between faces
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
function log_debug(o) {
|
|
//console.log(o);
|
|
}
|
|
|
|
function radians(a) {
|
|
return a*Math.PI/180;
|
|
}
|
|
|
|
function degrees(a) {
|
|
var d = a*180/Math.PI;
|
|
return (d+360)%360;
|
|
}
|
|
|
|
function GPS() {
|
|
this.wp;
|
|
this.wp_index = 0;
|
|
this.wp_current = undefined;
|
|
this.GPS_OFF = 0;
|
|
this.GPS_TIME = 1;
|
|
this.GPS_SATS = 2;
|
|
this.GPS_RUNNING = 3;
|
|
this.gpsState = this.GPS_OFF;
|
|
this.gpsPowerState = false;
|
|
this.last_fix = {
|
|
fix: 0,
|
|
alt: 0,
|
|
lat: 0,
|
|
lon: 0,
|
|
speed: 0,
|
|
time: 0,
|
|
satellites: 0
|
|
};
|
|
this.listenerCount = 0;
|
|
this.loadFirstWaypoint();
|
|
}
|
|
|
|
GPS.prototype.log_debug = function(o) {
|
|
//console.log(o);
|
|
};
|
|
|
|
GPS.prototype.getState = function() {
|
|
return this.gpsState;
|
|
}
|
|
|
|
GPS.prototype.getLastFix = function() {
|
|
return this.last_fix;
|
|
}
|
|
|
|
GPS.prototype.determineGPSState = function() {
|
|
this.log_debug("determineGPSState");
|
|
gpsPowerState = Bangle.isGPSOn();
|
|
|
|
//this.log_debug("last_fix.fix " + this.last_fix.fix);
|
|
//this.log_debug("gpsPowerState " + this.gpsPowerState);
|
|
//this.log_debug("last_fix.satellites " + this.last_fix.satellites);
|
|
|
|
if (!gpsPowerState) {
|
|
this.gpsState = this.GPS_OFF;
|
|
this.resetLastFix();
|
|
} else if (this.last_fix.fix && this.gpsPowerState && this.last_fix.satellites > 0) {
|
|
this.gpsState = this.GPS_RUNNING;
|
|
} else {
|
|
this.gpsState = this.GPS_SATS;
|
|
}
|
|
|
|
this.log_debug("gpsState=" + this.gpsState);
|
|
|
|
if (this.gpsState !== this.GPS_OFF) {
|
|
if (this.listenerCount === 0) {
|
|
Bangle.on('GPS', processFix);
|
|
this.listenerCount++;
|
|
this.log_debug("listener added " + this.listenerCount);
|
|
}
|
|
} else {
|
|
if (this.listenerCount > 0) {
|
|
Bangle.removeListener("GPS", processFix);
|
|
this.listenerCount--;
|
|
this.log_debug("listener removed " + this.listenerCount);
|
|
}
|
|
}
|
|
};
|
|
|
|
GPS.prototype.getGPSTime = function() {
|
|
var time;
|
|
|
|
if (this.last_fix !== undefined && this.last_fix.time !== undefined && this.last_fix.time.toUTCString !== undefined &&
|
|
(this.gpsState == this.GPS_SATS || this.gpsState == this.GPS_RUNNING)) {
|
|
time = this.last_fix.time.toUTCString().split(" ");
|
|
return time[4];
|
|
} else {
|
|
var d = new Date();
|
|
var da = d.toString().split(" ");
|
|
time = da[4].substr(0,5);
|
|
return time;
|
|
}
|
|
};
|
|
|
|
GPS.prototype.toggleGPSPower = function() {
|
|
this.log_debug("toggleGPSPower()");
|
|
this.gpsPowerState = Bangle.isGPSOn();
|
|
this.gpsPowerState = !this.gpsPowerState;
|
|
Bangle.setGPSPower((this.gpsPowerState ? 1 : 0), 'kitchen');
|
|
|
|
this.resetLastFix();
|
|
this.determineGPSState();
|
|
|
|
// poke the gps widget indicator to change
|
|
if (WIDGETS.gps !== undefined) {
|
|
WIDGETS.gps.draw();
|
|
}
|
|
};
|
|
|
|
GPS.prototype.resetLastFix = function() {
|
|
this.last_fix = {
|
|
fix: 0,
|
|
alt: 0,
|
|
lat: 0,
|
|
lon: 0,
|
|
speed: 0,
|
|
time: 0,
|
|
satellites: 0
|
|
};
|
|
};
|
|
|
|
function processFix(fix) {
|
|
//log_debug("processFix()");
|
|
gpsObj.processFix(fix);
|
|
}
|
|
|
|
GPS.prototype.processFix = function(fix) {
|
|
//this.log_debug("GPS:processFix()");
|
|
//this.log_debug(fix);
|
|
this.last_fix.time = fix.time;
|
|
|
|
if (this.gpsState == this.GPS_TIME) {
|
|
this.gpsState = this.GPS_SATS;
|
|
}
|
|
|
|
if (fix.fix) {
|
|
//this.log_debug("Got fix - setting state to GPS_RUNNING");
|
|
this.gpsState = this.GPS_RUNNING;
|
|
if (!this.last_fix.fix && !(require("Storage").readJSON("setting.json", 1) || {}).quiet) {
|
|
Bangle.buzz(); // buzz on first position
|
|
debug_log("BUZZ - gps fix");
|
|
}
|
|
this.last_fix = fix;
|
|
}
|
|
};
|
|
|
|
GPS.prototype.formatTime = function(now) {
|
|
var fd = now.toUTCString().split(" ");
|
|
return fd[4];
|
|
};
|
|
|
|
GPS.prototype.timeSince = function(t) {
|
|
var hms = t.split(":");
|
|
var now = new Date();
|
|
|
|
var sn = 3600*(now.getHours()) + 60*(now.getMinutes()) + 1*(now.getSeconds());
|
|
var st = 3600*(hms[0]) + 60*(hms[1]) + 1*(hms[2]);
|
|
|
|
return (sn - st);
|
|
};
|
|
|
|
GPS.prototype.getOsRef = function() {
|
|
let os = OsGridRef.latLongToOsGrid(this.last_fix);
|
|
let ref = to_map_ref(6, os.easting, os.northing);
|
|
return ref;
|
|
};
|
|
|
|
GPS.prototype.calcBearing = function(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)));
|
|
}
|
|
|
|
GPS.prototype.calcDistance = function(a,b) {
|
|
var x = radians(a.lon-b.lon) * Math.cos(radians((a.lat+b.lat)/2));
|
|
var y = radians(b.lat-a.lat);
|
|
return Math.round(Math.sqrt(x*x + y*y) * 6371000);
|
|
}
|
|
|
|
GPS.prototype.getWPdistance = function() {
|
|
//log_debug(this.last_fix);
|
|
//log_debug(this.wp_current);
|
|
|
|
if (this.wp_current.name === "E-WPT" || this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0)
|
|
return 0;
|
|
else
|
|
return this.calcDistance(this.last_fix, this.wp_current);
|
|
}
|
|
|
|
GPS.prototype.getWPbearing = function() {
|
|
//log_debug(this.last_fix);
|
|
//log_debug(this.wp_current);
|
|
|
|
if (this.wp_current.name === "E-WPT" || this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0)
|
|
return 0;
|
|
else
|
|
return this.calcBearing(this.last_fix, this.wp_current);
|
|
}
|
|
|
|
GPS.prototype.loadFirstWaypoint = function() {
|
|
var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"E-WPT"}];
|
|
this.wp_index = 0;
|
|
this.wp_current = waypoints[this.wp_index];
|
|
log_debug(this.wp_current);
|
|
return this.wp_current;
|
|
}
|
|
|
|
GPS.prototype.getCurrentWaypoint = function() {
|
|
return this.wp_current;
|
|
}
|
|
|
|
GPS.prototype.waypointHasLocation = function() {
|
|
if (this.wp_current.name === "E-WPT" || this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
GPS.prototype.markWaypoint = function() {
|
|
|
|
if(this.wp_current.name === "E-WPT" || this.wp_current.name === "NONE")
|
|
return;
|
|
|
|
log_debug("GPS::markWaypoint()");
|
|
|
|
var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"E-WPT"}];
|
|
this.wp_current = waypoints[this.wp_index];
|
|
|
|
if (this.waypointHasLocation()) {
|
|
waypoints[this.wp_index] = {name:this.wp_current.name, lat:0, lon:0};
|
|
} else {
|
|
waypoints[this.wp_index] = {name:this.wp_current.name, lat:this.last_fix.lat, lon:this.last_fix.lon};
|
|
}
|
|
|
|
this.wp_current = waypoints[this.wp_index];
|
|
require("Storage").writeJSON("waypoints.json", waypoints);
|
|
log_debug("GPS::markWaypoint() written");
|
|
}
|
|
|
|
GPS.prototype.nextWaypoint = function(inc) {
|
|
var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"E-WPT"}];
|
|
this.wp_index+=inc;
|
|
if (this.wp_index>=waypoints.length) this.wp_index=0;
|
|
if (this.wp_index<0) this.wp_index = waypoints.length-1;
|
|
this.wp_current = waypoints[this.wp_index];
|
|
log_debug(this.wp_current);
|
|
return this.wp_current;
|
|
}
|
|
|
|
GPS.prototype.toggleGpsLogging = function() {
|
|
var settings = require("Storage").readJSON("gpsrec.json",1)||{};
|
|
if (settings == {}) return false;
|
|
|
|
settings.recording = !settings.recording;
|
|
require("Storage").write("gpsrec.json", settings);
|
|
|
|
if (WIDGETS["gpsrec"])
|
|
WIDGETS["gpsrec"].reload();
|
|
|
|
return true;
|
|
}
|
|
|
|
GPS.prototype.loggingStatus = function() {
|
|
var settings = require("Storage").readJSON("gpsrec.json",1)||{};
|
|
if (settings == {}) return "E-LOG";
|
|
if (settings.recording) return "ON";
|
|
return "OFF";
|
|
}
|
|
|
|
var gpsObj = new GPS();
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
Start of OS lat lon to grid ref code
|
|
|
|
******************************************************************************/
|
|
|
|
Number.prototype.toRad = function() { return this*Math.PI/180; };
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
/* Ordnance Survey Grid Reference functions (c) Chris Veness 2005-2014 */
|
|
/* - www.movable-type.co.uk/scripts/gridref.js */
|
|
/* - www.movable-type.co.uk/scripts/latlon-gridref.html */
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
function OsGridRef(easting, northing) {
|
|
this.easting = 0|easting;
|
|
this.northing = 0|northing;
|
|
}
|
|
|
|
OsGridRef.latLongToOsGrid = function(point) {
|
|
var lat = point.lat.toRad();
|
|
var lon = point.lon.toRad();
|
|
|
|
var a = 6377563.396, b = 6356256.909; // Airy 1830 major & minor semi-axes
|
|
var F0 = 0.9996012717; // NatGrid scale factor on central meridian
|
|
var lat0 = (49).toRad(), lon0 = (-2).toRad(); // NatGrid true origin is 49�N,2�W
|
|
var N0 = -100000, E0 = 400000; // northing & easting of true origin, metres
|
|
var e2 = 1 - (b*b)/(a*a); // eccentricity squared
|
|
var n = (a-b)/(a+b), n2 = n*n, n3 = n*n*n;
|
|
|
|
var cosLat = Math.cos(lat), sinLat = Math.sin(lat);
|
|
var nu = a*F0/Math.sqrt(1-e2*sinLat*sinLat); // transverse radius of curvature
|
|
var rho = a*F0*(1-e2)/Math.pow(1-e2*sinLat*sinLat, 1.5); // meridional radius of curvature
|
|
var eta2 = nu/rho-1;
|
|
|
|
var Ma = (1 + n + (5/4)*n2 + (5/4)*n3) * (lat-lat0);
|
|
var Mb = (3*n + 3*n*n + (21/8)*n3) * Math.sin(lat-lat0) * Math.cos(lat+lat0);
|
|
var Mc = ((15/8)*n2 + (15/8)*n3) * Math.sin(2*(lat-lat0)) * Math.cos(2*(lat+lat0));
|
|
var Md = (35/24)*n3 * Math.sin(3*(lat-lat0)) * Math.cos(3*(lat+lat0));
|
|
var M = b * F0 * (Ma - Mb + Mc - Md); // meridional arc
|
|
|
|
var cos3lat = cosLat*cosLat*cosLat;
|
|
var cos5lat = cos3lat*cosLat*cosLat;
|
|
var tan2lat = Math.tan(lat)*Math.tan(lat);
|
|
var tan4lat = tan2lat*tan2lat;
|
|
|
|
var I = M + N0;
|
|
var II = (nu/2)*sinLat*cosLat;
|
|
var III = (nu/24)*sinLat*cos3lat*(5-tan2lat+9*eta2);
|
|
var IIIA = (nu/720)*sinLat*cos5lat*(61-58*tan2lat+tan4lat);
|
|
var IV = nu*cosLat;
|
|
var V = (nu/6)*cos3lat*(nu/rho-tan2lat);
|
|
var VI = (nu/120) * cos5lat * (5 - 18*tan2lat + tan4lat + 14*eta2 - 58*tan2lat*eta2);
|
|
|
|
var dLon = lon-lon0;
|
|
var dLon2 = dLon*dLon, dLon3 = dLon2*dLon, dLon4 = dLon3*dLon, dLon5 = dLon4*dLon, dLon6 = dLon5*dLon;
|
|
|
|
var N = I + II*dLon2 + III*dLon4 + IIIA*dLon6;
|
|
var E = E0 + IV*dLon + V*dLon3 + VI*dLon5;
|
|
|
|
return new OsGridRef(E, N);
|
|
};
|
|
|
|
/*
|
|
* converts northing, easting to standard OS grid reference.
|
|
*
|
|
* [digits=10] - precision (10 digits = metres)
|
|
* to_map_ref(8, 651409, 313177); => 'TG 5140 1317'
|
|
* to_map_ref(0, 651409, 313177); => '651409,313177'
|
|
*
|
|
*/
|
|
function to_map_ref(digits, easting, northing) {
|
|
if (![ 0,2,4,6,8,10,12,14,16 ].includes(Number(digits))) throw new RangeError(`invalid precision '${digits}'`); // eslint-disable-line comma-spacing
|
|
|
|
let e = easting;
|
|
let n = northing;
|
|
|
|
// use digits = 0 to return numeric format (in metres) - note northing may be >= 1e7
|
|
if (digits == 0) {
|
|
const format = { useGrouping: false, minimumIntegerDigits: 6, maximumFractionDigits: 3 };
|
|
const ePad = e.toLocaleString('en', format);
|
|
const nPad = n.toLocaleString('en', format);
|
|
return `${ePad},${nPad}`;
|
|
}
|
|
|
|
// get the 100km-grid indices
|
|
const e100km = Math.floor(e / 100000), n100km = Math.floor(n / 100000);
|
|
|
|
// translate those into numeric equivalents of the grid letters
|
|
let l1 = (19 - n100km) - (19 - n100km) % 5 + Math.floor((e100km + 10) / 5);
|
|
let l2 = (19 - n100km) * 5 % 25 + e100km % 5;
|
|
|
|
// compensate for skipped 'I' and build grid letter-pairs
|
|
if (l1 > 7) l1++;
|
|
if (l2 > 7) l2++;
|
|
const letterPair = String.fromCharCode(l1 + 'A'.charCodeAt(0), l2 + 'A'.charCodeAt(0));
|
|
|
|
// strip 100km-grid indices from easting & northing, and reduce precision
|
|
e = Math.floor((e % 100000) / Math.pow(10, 5 - digits / 2));
|
|
n = Math.floor((n % 100000) / Math.pow(10, 5 - digits / 2));
|
|
|
|
// pad eastings & northings with leading zeros
|
|
e = e.toString().padStart(digits/2, '0');
|
|
n = n.toString().padStart(digits/2, '0');
|
|
|
|
return `${letterPair} ${e} ${n}`;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
Stopwatch Class Code
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
function STOPWATCH() {
|
|
this.tTotal = Date.now();
|
|
this.tStart = Date.now();
|
|
this.tCurrent = Date.now();
|
|
this.running = false;
|
|
this.timeY = 45;
|
|
this.TtimeY = 75;
|
|
this.lapTimes = [];
|
|
this.displayInterval;
|
|
this.redrawButtons = true;
|
|
this.redrawLaps = true;
|
|
this.redrawTime = true;
|
|
}
|
|
|
|
STOPWATCH.prototype.log_debug = function(o) {
|
|
//console.log(o);
|
|
}
|
|
|
|
STOPWATCH.prototype.timeToText = function(t) {
|
|
let hrs = Math.floor(t/3600000);
|
|
let mins = Math.floor(t/60000)%60;
|
|
let secs = Math.floor(t/1000)%60;
|
|
let text;
|
|
|
|
if (hrs === 0)
|
|
text = ("0"+mins).substr(-2) + ":" + ("0"+secs).substr(-2);
|
|
else
|
|
text = (""+hrs) + ":" + ("0"+mins).substr(-2) + ":" + ("0"+secs).substr(-2);
|
|
|
|
this.log_debug(text);
|
|
return text;
|
|
}
|
|
|
|
STOPWATCH.prototype.getLapTimesArray = function() {
|
|
this.lapTimes.push(tCurrent-tTotal);
|
|
return this.lapTimes.map(timeToText).reverse();
|
|
}
|
|
|
|
STOPWATCH.prototype.stopStart = function() {
|
|
this.log_debug("stopStart()");
|
|
this.running = !this.running;
|
|
|
|
if (this.running)
|
|
this.tStart = Date.now() + this.tStart - this.tCurrent;
|
|
|
|
this.tTotal = Date.now() + this.tTotal - this.tCurrent;
|
|
this.tCurrent = Date.now();
|
|
this.redrawButtons = true;
|
|
this.redrawLaps = true;
|
|
this.redrawTime = true;
|
|
this.draw();
|
|
}
|
|
|
|
STOPWATCH.prototype.lap = function() {
|
|
this.log_debug("lap()");
|
|
if (this.running) {
|
|
this.tCurrent = Date.now();
|
|
this.lapTimes.unshift(this.tCurrent - this.tStart);
|
|
log_debug(this.tCurrent - this.tStart);
|
|
}
|
|
|
|
this.tStart = this.tCurrent;
|
|
this.redrawButtons = true;
|
|
this.redrawLaps = true;
|
|
this.draw();
|
|
}
|
|
|
|
STOPWATCH.prototype.reset = function() {
|
|
this.log_debug("reset()");
|
|
if (this.running === false) {
|
|
this.tStart = this.tCurrent = this.tTotal = Date.now();
|
|
this.lapTimes = [];
|
|
}
|
|
g.clear();
|
|
this.draw();
|
|
}
|
|
|
|
// lap or reset
|
|
STOPWATCH.prototype.lapOrReset = function() {
|
|
this.redrawButtons = true;
|
|
this.redrawLaptimes = true;
|
|
this.redrawTime = true;
|
|
|
|
this.log_debug("lapReset()");
|
|
if (this.running)
|
|
this.lap()
|
|
else
|
|
this.reset();
|
|
}
|
|
|
|
STOPWATCH.prototype.draw = function() {
|
|
if (this.running) this.tCurrent = Date.now();
|
|
this.log_debug("draw()" + getTime());
|
|
|
|
g.setColor(1,1,1);
|
|
if (this.redrawButtons) this.drawButtons();
|
|
if (this.running || this.redrawTime) this.drawTime();
|
|
if (this.redrawLaps) this.drawLaptimes();
|
|
}
|
|
|
|
STOPWATCH.prototype.drawButtons = function() {
|
|
this.log_debug("drawButtons()");
|
|
|
|
g.clearRect(0,23,g.getWidth()-1,g.getHeight()-24);
|
|
g.setColor(1,1,1);
|
|
g.setFont("Vector", 20);
|
|
g.setFontAlign(0,0,3);
|
|
g.drawString(this.running? "STOP" : "GO", 230, 50); // BTN1
|
|
g.drawString(this.running? "LAP" : "RESET", 230, 120); // BTN2
|
|
this.redrawButtons = false;
|
|
}
|
|
|
|
STOPWATCH.prototype.drawLaptimes = function() {
|
|
g.setFont("Vector",24);
|
|
g.setFontAlign(-1,-1);
|
|
g.clearRect(4, 205, 239, 229); // clear the last line of the lap times
|
|
|
|
let laps = 0;
|
|
for (let i in this.lapTimes) {
|
|
g.drawString(this.lapTimes.length-i + ": " + this.timeToText(this.lapTimes[i]), 4, this.timeY + 40 + i*24);
|
|
if (++laps > 5) break;
|
|
}
|
|
this.redrawLaps = false;
|
|
}
|
|
|
|
STOPWATCH.prototype.drawTime = function() {
|
|
this.log_debug("drawTime()");
|
|
let tLap = this.tCurrent - this.tStart;
|
|
let tTotal = this.tCurrent - this.tTotal;
|
|
let txtLap = this.timeToText(tLap);
|
|
let txtTotal = this.timeToText(tTotal);
|
|
let xTotal = 100;
|
|
let xLap = 125;
|
|
|
|
// total time
|
|
g.setFont("Vector",38);
|
|
g.setFontAlign(0,0);
|
|
g.clearRect(0, this.timeY-21, 200, this.timeY+21);
|
|
g.setColor(0xFFC0);
|
|
g.drawString(txtTotal, xTotal, this.timeY);
|
|
|
|
// current lap time
|
|
g.setFont("Vector", 20);
|
|
g.clearRect(0, this.TtimeY-7, 200, this.TtimeY+7);
|
|
g.setColor(1,1,1);
|
|
g.drawString(txtLap, xLap, this.TtimeY);
|
|
|
|
this.redrawTime = false;
|
|
}
|
|
|
|
STOPWATCH.prototype.startTimer = function() {
|
|
this.log_debug("startTimer()");
|
|
this.redrawButtons = true;
|
|
this.redrawLaps = true;
|
|
this.redrawTime = true;
|
|
this.draw();
|
|
this.displayInterval = setInterval(stopwatchDraw, 1000);
|
|
}
|
|
|
|
STOPWATCH.prototype.stopTimer = function() {
|
|
this.log_debug("stopTimer()");
|
|
if (this.displayInterval) {
|
|
clearInterval(this.displayInterval);
|
|
this.displayInterval = undefined;
|
|
}
|
|
}
|
|
|
|
let swObj = new STOPWATCH();
|
|
|
|
function stopwatchDraw() {
|
|
swObj.draw();
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
Heart Rate Monitor
|
|
|
|
******************************************************************************/
|
|
|
|
function HRM() {
|
|
this.bpm = 0;
|
|
this.confidence = 0;
|
|
}
|
|
|
|
HRM.prototype.log_debug = function(o) {
|
|
//console.log(o);
|
|
}
|
|
|
|
HRM.prototype.toggleHRMPower = function() {
|
|
this.log_debug("HRM.toggleHRMPower()");
|
|
if (!Bangle.isHRMOn) return; // old firmware
|
|
|
|
if (!Bangle.isHRMOn()) {
|
|
this.log_debug("HRM.toggleHRMPower(powerOn)");
|
|
Bangle.removeListener('HRM', onHRM);
|
|
Bangle.setHRMPower(1);
|
|
Bangle.on('HRM', onHRM);
|
|
} else {
|
|
this.log_debug("HRM.toggleHRMPower(powerOff)");
|
|
Bangle.removeListener('HRM', onHRM);
|
|
Bangle.setHRMPower(0);
|
|
}
|
|
|
|
// poke the hrt widget indicator to change
|
|
if (WIDGETS.widhrt !== undefined) {
|
|
WIDGETS.widhrt.draw();
|
|
}
|
|
}
|
|
|
|
HRM.prototype.getBpm = function() {
|
|
return this.bpm;
|
|
}
|
|
|
|
HRM.prototype.getConfidence = function() {
|
|
return this.confidence;
|
|
}
|
|
|
|
HRM.prototype.onHRM = function(hrm) {
|
|
this.bpm = hrm.bpm;
|
|
this.confidence = hrm.confidence;
|
|
this.log_debug("onHRM:(bpm)" + this.bpm);
|
|
this.log_debug("onHRM:(conf) " + this.confidence);
|
|
}
|
|
|
|
let hrmObj = new HRM();
|
|
|
|
function onHRM(hrm) {
|
|
hrmObj.onHRM(hrm);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
Trip Counter
|
|
|
|
******************************************************************************/
|
|
|
|
function TRIP() {
|
|
this.showTrip = false;
|
|
this.tripStart = 0;
|
|
}
|
|
|
|
TRIP.prototype.resetTrip = function(steps) {
|
|
this.tripStart = (0 + steps);
|
|
log_debug("resetTrip starting=" + this.tripStart);
|
|
}
|
|
|
|
TRIP.prototype.getTrip = function(steps) {
|
|
let tripSteps = (0 + steps) - this.tripStart;
|
|
log_debug("getTrip steps=" + steps);
|
|
log_debug("getTrip tripStart=" + this.tripStart);
|
|
log_debug("getTrip=" + tripSteps);
|
|
return tripSteps;
|
|
}
|
|
|
|
TRIP.prototype.getTripState = function() {
|
|
return this.showTrip;
|
|
}
|
|
|
|
TRIP.prototype.setTripState = function(t) {
|
|
this.showTrip = t;
|
|
}
|
|
|
|
let tripObject = new TRIP();
|
|
|
|
/*****************************************************************************
|
|
|
|
Debug Object
|
|
|
|
******************************************************************************/
|
|
|
|
function DEBUG() {
|
|
this.logfile = require("Storage").open("debug.log","a");
|
|
}
|
|
|
|
DEBUG.prototype.log = function(msg) {
|
|
let timestamp = new Date().toString().split(" ")[4];
|
|
let line = timestamp + ", " + msg + "\n";
|
|
this.logfile.write(line);
|
|
}
|
|
|
|
debugObj = new DEBUG();
|
|
|
|
function debug_log(m) {
|
|
//debugObj.log(m);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
|
|
Start App
|
|
|
|
******************************************************************************/
|
|
|
|
g.clear();
|
|
Bangle.loadWidgets();
|
|
face.init(gpsObj,swObj, hrmObj, tripObject);
|
|
startdraw();
|
|
setButtons();
|