(() => { const SAMPLES=5; function initState(){ //cleanup volatile state here state = {}; state.compassSamples = new Array(SAMPLES).fill(0); state.lastSample = 0; state.sampleIndex = 0; state.currentPos={}; state.steps = 0; state.calibAltDiff = 0; state.numberOfSlices = 3; state.steps = 0; state.up = 0; state.down = 0; state.saved = 0; state.avgComp = 0; } const STORAGE=require('Storage'); let state = STORAGE.readJSON("gpstrek.state.json"); if (!state) { state = {}; initState(); } let bgChanged = false; function saveState(){ state.saved = Date.now(); STORAGE.writeJSON("gpstrek.state.json", state); } function onKill(){ if (bgChanged || state.route || state.waypoint){ saveState(); } } E.on("kill", onKill); function onPulse(e){ state.bpm = e.bpm; } function onGPS(fix) { if(fix.fix) state.currentPos = fix; } let radians = function(a) { return a*Math.PI/180; }; let degrees = function(a) { let d = a*180/Math.PI; return (d+360)%360; }; function average(samples){ let s = 0; let c = 0; for (let h of samples){ s += Math.sin(radians(h)); c += Math.cos(radians(h)); } s /= samples.length; c /= samples.length; let result = degrees(Math.atan(s/c)); if (c < 0) result += 180; if (s < 0 && c > 0) result += 360; result%=360; return result; } function onMag(e) { if (!isNaN(e.heading)){ if (Bangle.isLocked() || (Bangle.getGPSFix() && Bangle.getGPSFix().lon)) state.avgComp = e.heading; else { state.compassSamples[state.sampleIndex++] = e.heading; state.lastSample = Date.now(); if (state.sampleIndex > SAMPLES - 1){ state.sampleIndex = 0; let avg = average(state.compassSamples); state.avgComp = average([state.avgComp,avg]); } } } } function onStep(e) { state.steps++; } function onPressure(e) { state.pressure = e.pressure; if (!state.altitude){ state.altitude = e.altitude; state.up = 0; state.down = 0; } let diff = state.altitude - e.altitude; if (Math.abs(diff) > 3){ if (diff > 0){ state.up += diff; } else { state.down -= diff; } state.altitude = e.altitude; } } function onAcc (e){ state.acc = e; } function update(){ if (state.active){ start(false); } if (state.active == !(WIDGETS.gpstrek.width)) { if(WIDGETS.gpstrek) WIDGETS.gpstrek.width = state.active?24:0; Bangle.drawWidgets(); } } function start(bg){ Bangle.removeListener('GPS', onGPS); Bangle.removeListener("HRM", onPulse); Bangle.removeListener("mag", onMag); Bangle.removeListener("step", onStep); Bangle.removeListener("pressure", onPressure); Bangle.removeListener('accel', onAcc); Bangle.on('GPS', onGPS); Bangle.on("HRM", onPulse); Bangle.on("mag", onMag); Bangle.on("step", onStep); Bangle.on("pressure", onPressure); Bangle.on('accel', onAcc); Bangle.setGPSPower(1, "gpstrek"); Bangle.setHRMPower(1, "gpstrek"); Bangle.setCompassPower(1, "gpstrek"); Bangle.setBarometerPower(1, "gpstrek"); if (bg){ if (!state.active) bgChanged = true; state.active = true; update(); saveState(); } } function stop(bg){ if (bg){ if (state.active) bgChanged = true; state.active = false; } else if (!state.active) { Bangle.setGPSPower(0, "gpstrek"); Bangle.setHRMPower(0, "gpstrek"); Bangle.setCompassPower(0, "gpstrek"); Bangle.setBarometerPower(0, "gpstrek"); Bangle.removeListener('GPS', onGPS); Bangle.removeListener("HRM", onPulse); Bangle.removeListener("mag", onMag); Bangle.removeListener("step", onStep); Bangle.removeListener("pressure", onPressure); Bangle.removeListener('accel', onAcc); E.removeListener("kill", onKill); } update(); saveState(); } if (state.active){ start(false); } WIDGETS["gpstrek"]={ area:"tl", width:state.active?24:0, resetState: initState, getState: function() { if (state.saved && Date.now() - state.saved > 60000 || !state){ initState(); } return state; }, start:start, stop:stop, draw:function() { update(); if (state.active){ g.reset(); g.drawImage(atob("GBiBAAAAAAAAAAAYAAAYAAAYAAA8AAA8AAB+AAB+AADbAADbAAGZgAGZgAMYwAMYwAcY4AYYYA5+cA3/sB/D+B4AeBAACAAAAAAAAA=="), this.x, this.y); } } }; })();