From 2644f2226dd835cec2094d2b36b30c3384217b9f Mon Sep 17 00:00:00 2001 From: hughbarney Date: Sun, 18 Apr 2021 12:28:13 +0100 Subject: [PATCH 1/2] improved display in kitchen/stopwatch, updated README files --- apps.json | 4 ++-- apps/kitchen/ChangeLog | 1 + apps/kitchen/README.md | 6 +++++- apps/kitchen/kitchen.app.js | 40 ++++++++++++++++++++++--------------- apps/kitchen/swatch.kit.js | 20 +------------------ apps/stepo/README.md | 3 +++ 6 files changed, 36 insertions(+), 38 deletions(-) diff --git a/apps.json b/apps.json index db8e2d92f..595812a08 100644 --- a/apps.json +++ b/apps.json @@ -3029,7 +3029,7 @@ "name": "Stepometer Clock", "icon": "stepo.png", "version":"0.03", - "description": "A large font watch, displays step count in a doughnut guage and warns of low battery", + "description": "A large font watch, displays step count in a doughnut guage and warns of low battery, requires one of the steps widgets to be installed", "tags": "clock", "type":"clock", "readme": "README.md", @@ -3083,7 +3083,7 @@ { "id": "kitchen", "name": "Kitchen Combo", "icon": "kitchen.png", - "version":"0.04", + "version":"0.05", "description": "Combination of the stepo, walkersclock, arrow and waypointer apps into a multiclock format. 'Everything but the kitchen sink'. Requires firmware v2.08.167 or later", "tags": "tool,outdoors,gps", "type":"clock", diff --git a/apps/kitchen/ChangeLog b/apps/kitchen/ChangeLog index 2bb3989da..6c282018e 100644 --- a/apps/kitchen/ChangeLog +++ b/apps/kitchen/ChangeLog @@ -2,3 +2,4 @@ 0.02: compass disable BTN1,BTN2 while waiting for GPS to reach RUNNING status 0.03: Don't buzz for GPS fix in Quiet Mode 0.04: Added stopwatch face +0.05: Stopwatch, hide hours if 0, fixed flicker when stopped, updated README issues diff --git a/apps/kitchen/README.md b/apps/kitchen/README.md index 06e4a40ba..3ba2dc3b1 100644 --- a/apps/kitchen/README.md +++ b/apps/kitchen/README.md @@ -207,4 +207,8 @@ is recorded in a storage file named `magnav.json`. * GPS time display shows GMT and not BST, needs localising * Occassional buzzing after 2-3 days of use, seems to disappear after a reset to the launcher menu. Needs investigation -* Stopwatch display to hide hours count if elapsed time is less than 1 hour. +* Need to gracefully handle incorrect firmware +* Need to gracefully handle missing compass calibration data +* Need to gracefully handle missing steps widget +* Need to improve memory management for compass widget + diff --git a/apps/kitchen/kitchen.app.js b/apps/kitchen/kitchen.app.js index 5f2c4c046..3b14817df 100644 --- a/apps/kitchen/kitchen.app.js +++ b/apps/kitchen/kitchen.app.js @@ -488,6 +488,7 @@ function STOPWATCH() { this.displayInterval; this.redrawButtons = true; this.redrawLaps = true; + this.redrawTime = true; } STOPWATCH.prototype.log_debug = function(o) { @@ -498,8 +499,13 @@ 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); - let text = ("00"+hrs).substr(-3) + ":" + ("0"+mins).substr(-2) + ":" + ("0"+secs).substr(-2); this.log_debug(text); return text; } @@ -520,7 +526,7 @@ STOPWATCH.prototype.stopStart = function() { this.tCurrent = Date.now(); this.redrawButtons = true; this.redrawLaps = true; - + this.redrawTime = true; this.draw(); } @@ -529,7 +535,7 @@ STOPWATCH.prototype.lap = function() { if (this.running) { this.tCurrent = Date.now(); this.lapTimes.unshift(this.tCurrent - this.tStart); - console.log(this.tCurrent - this.tStart); + log_debug(this.tCurrent - this.tStart); } this.tStart = this.tCurrent; @@ -552,6 +558,7 @@ STOPWATCH.prototype.reset = function() { STOPWATCH.prototype.lapOrReset = function() { this.redrawButtons = true; this.redrawLaptimes = true; + this.redrawTime = true; this.log_debug("lapReset()"); if (this.running) @@ -566,7 +573,7 @@ STOPWATCH.prototype.draw = function() { g.setColor(1,1,1); if (this.redrawButtons) this.drawButtons(); - this.drawTime(); + if (this.running || this.redrawTime) this.drawTime(); if (this.redrawLaps) this.drawLaptimes(); } @@ -597,33 +604,34 @@ STOPWATCH.prototype.drawLaptimes = function() { STOPWATCH.prototype.drawTime = function() { this.log_debug("drawTime()"); - let t = this.tCurrent - this.tStart; - let Tt = this.tCurrent - this.tTotal; - - let txt = this.timeToText(t); - let Ttxt = this.timeToText(Tt); - - let x = 100; - let Tx = 125; + 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.clearRect(0, this.timeY-21, 200, this.timeY+21); g.setColor(0xFFC0); - g.drawString(Ttxt,x,this.timeY); + g.drawString(txtTotal, xTotal, this.timeY); // current lap time g.setFont("Vector", 20); - g.clearRect(0, this.TtimeY-7,200, this.TtimeY+7); + g.clearRect(0, this.TtimeY-7, 200, this.TtimeY+7); g.setColor(1,1,1); - g.drawString(txt,Tx, this.TtimeY); + 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); } diff --git a/apps/kitchen/swatch.kit.js b/apps/kitchen/swatch.kit.js index 9f12b0af7..efec39d97 100644 --- a/apps/kitchen/swatch.kit.js +++ b/apps/kitchen/swatch.kit.js @@ -2,36 +2,18 @@ function getFace(){ let swObject = undefined; - function log_debug(o) { - //console.log(o); - } - function init(gps, sw) { - showMem("swatch init 1"); swObject = sw; g.clear(); - showMem("swatch init 2"); } - function freeResources() { - showMem("swatch free 1"); - swObject = undefined; - showMem("swatch free 2"); - } - - function showMem(msg) { - var val = process.memory(); - var str = msg + " " + Math.round(val.usage*100/val.total) + "%"; - log_debug(str); - } + function freeResources() {} function startTimer() { - log_debug("swObject.startTimer()"); swObject.startTimer(); } function stopTimer() { - log_debug("swObject.stopTimer()"); swObject.stopTimer(); } diff --git a/apps/stepo/README.md b/apps/stepo/README.md index 26531c121..d26f656b7 100644 --- a/apps/stepo/README.md +++ b/apps/stepo/README.md @@ -10,6 +10,9 @@ A large font watch, displays step count in a doughnut guage and warns of low bat - The guage show percentage of steps out of a goal of 10000 steps +## Dependancies +- Requires one of the steps widgets to be installed + ![](screenshot1.jpg) From 9bce2540db8e14d254a3684a4d4c2220ec8340db Mon Sep 17 00:00:00 2001 From: hughbarney Date: Mon, 19 Apr 2021 21:48:12 +0100 Subject: [PATCH 2/2] modified kitchen/compass to write directly to screen to avoid LOW_MEMORY exceptions --- apps.json | 2 +- apps/kitchen/ChangeLog | 1 + apps/kitchen/README.md | 18 ++++- apps/kitchen/compass.kit.js | 139 ++++++++++++++++-------------------- 4 files changed, 78 insertions(+), 82 deletions(-) diff --git a/apps.json b/apps.json index 74fcfde73..1a2931ff8 100644 --- a/apps.json +++ b/apps.json @@ -3083,7 +3083,7 @@ { "id": "kitchen", "name": "Kitchen Combo", "icon": "kitchen.png", - "version":"0.05", + "version":"0.06", "description": "Combination of the stepo, walkersclock, arrow and waypointer apps into a multiclock format. 'Everything but the kitchen sink'. Requires firmware v2.08.167 or later", "tags": "tool,outdoors,gps", "type":"clock", diff --git a/apps/kitchen/ChangeLog b/apps/kitchen/ChangeLog index 6c282018e..42e790bc2 100644 --- a/apps/kitchen/ChangeLog +++ b/apps/kitchen/ChangeLog @@ -3,3 +3,4 @@ 0.03: Don't buzz for GPS fix in Quiet Mode 0.04: Added stopwatch face 0.05: Stopwatch, hide hours if 0, fixed flicker when stopped, updated README issues +0.06: Reduced memory footprint of compass, used direct screen access rather than arrayBuffer diff --git a/apps/kitchen/README.md b/apps/kitchen/README.md index 3ba2dc3b1..76c2494e8 100644 --- a/apps/kitchen/README.md +++ b/apps/kitchen/README.md @@ -202,6 +202,22 @@ the correct direction heading or is not stable with respect to tilt and roll - redo the calibration by pressing *BTN3*. Calibration data is recorded in a storage file named `magnav.json`. + +### Technical Notes on Memory Management + +v0.06: The stepo watch face uses an ArrayBuffer to setup the doughnut +gauge before it is displayed. This is necessary as the drawing of +the doughnut shape is quite slow. However I found that when an +ArrayBuffer was also used for the compass arrow part of the App it +could result in LOW_MEMORY errors due to the memory fragmentation +caused when switching multiple times between the watch faces. It is +possible to call Bangle.defrag() when switching to a new watch face +but this causes an annoying delay in the time it takes to switch. So +I have settled on directly writing to the screen using the Graphics +object (g.) for the compass App. This creates a bit of flicker when +the arrow moves but is more reliable than using the ArrayBuffer. + + ### Issues * GPS time display shows GMT and not BST, needs localising @@ -210,5 +226,3 @@ is recorded in a storage file named `magnav.json`. * Need to gracefully handle incorrect firmware * Need to gracefully handle missing compass calibration data * Need to gracefully handle missing steps widget -* Need to improve memory management for compass widget - diff --git a/apps/kitchen/compass.kit.js b/apps/kitchen/compass.kit.js index 25bf5433f..1649730e6 100644 --- a/apps/kitchen/compass.kit.js +++ b/apps/kitchen/compass.kit.js @@ -1,11 +1,6 @@ (() => { function getFace(){ var intervalRefSec; - var pal_by; - var pal_bw; - var pal_bb; - var buf1; - var buf2; var bearing; var heading; var oldHeading; @@ -24,17 +19,11 @@ function init(gps,sw) { showMem("compass init() START"); gpsObject = gps; - pal_by = new Uint16Array([0x0000,0xFFC0],0,1); // black, yellow - pal_bw = new Uint16Array([0x0000,0xffff],0,1); // black, white - pal_bb = new Uint16Array([0x0000,0x07ff],0,1); // black, blue - buf1 = Graphics.createArrayBuffer(128,128,1,{msb:true}); - buf2 = Graphics.createArrayBuffer(80,40,1,{msb:true}); - intervalRefSec = undefined; bearing = 0; // always point north if GPS is off heading = 0; oldHeading = 0; - previous = {bs:"-", dst:"-", wp_name:"-", course:999}; + previous = {hding:"-", bs:"-", dst:"-", wp_name:"-", course:999}; loc = require("locale"); CALIBDATA = require("Storage").readJSON("magnav.json",1)||null; getWaypoint(); @@ -52,14 +41,8 @@ function freeResources() { showMem("compass freeResources() START"); gpsObject = undefined; - pal_by = undefined; - pal_bw = undefined; - pal_bb = undefined; - buf1 = undefined; - buf2 = undefined; intervalRefSec = undefined; previous = undefined; - bearing = 0; heading = 0; oldHeading = 0; @@ -70,21 +53,6 @@ showMem("compass freeResources() END"); } - function flip1(x,y) { - g.drawImage({width:128,height:128,bpp:1,buffer:buf1.buffer, palette:pal_by},x ,y); - buf1.clear(); - } - - function flip2_bw(x,y) { - g.drawImage({width:80,height:40,bpp:1,buffer:buf2.buffer, palette:pal_bw},x ,y); - buf2.clear(); - } - - function flip2_bb(x,y) { - g.drawImage({width:80,height:40,bpp:1,buffer:buf2.buffer, palette:pal_bb},x ,y); - buf2.clear(); - } - function startTimer() { log_debug("startTimer()"); if (!Bangle.isCompassOn()) Bangle.setCompassPower(1); @@ -143,29 +111,34 @@ wp = gpsObject.getCurrentWaypoint(); wp_distance = gpsObject.getWPdistance(); wp_bearing = gpsObject.getWPbearing(); + + if (gpsObject.getState() === gpsObject.GPS_RUNNING) + bearing = wp_bearing; + else + bearing = 0; + log_debug(wp); log_debug("wp_distance:" + wp_distance); log_debug("wp_bearing:" + wp_bearing); } - // takes 32ms - function drawCompass(hd) { - if (Math.abs(hd - oldHeading) < 2) return 0; - hd=hd*Math.PI/180; + // takes 16-20ms, will be called twice + function drawCompass(angle, col) { + angle = angle * Math.PI/180; var p = [0, 1.1071, Math.PI/4, 2.8198, 3.4633, 7*Math.PI/4 , 5.1760]; var poly = [ - 64+60*Math.sin(hd+p[0]), 64-60*Math.cos(hd+p[0]), - 64+44.7214*Math.sin(hd+p[1]), 64-44.7214*Math.cos(hd+p[1]), - 64+28.2843*Math.sin(hd+p[2]), 64-28.2843*Math.cos(hd+p[2]), - 64+63.2455*Math.sin(hd+p[3]), 64-63.2455*Math.cos(hd+p[3]), - 64+63.2455*Math.sin(hd+p[4]), 64-63.2455*Math.cos(hd+p[4]), - 64+28.2843*Math.sin(hd+p[5]), 64-28.2843*Math.cos(hd+p[5]), - 64+44.7214*Math.sin(hd+p[6]), 64-44.7214*Math.cos(hd+p[6]) + 120+60*Math.sin(angle+p[0]), 120-60*Math.cos(angle+p[0]), + 120+44.7214*Math.sin(angle+p[1]), 120-44.7214*Math.cos(angle+p[1]), + 120+28.2843*Math.sin(angle+p[2]), 120-28.2843*Math.cos(angle+p[2]), + 120+63.2455*Math.sin(angle+p[3]), 120-63.2455*Math.cos(angle+p[3]), + 120+63.2455*Math.sin(angle+p[4]), 120-63.2455*Math.cos(angle+p[4]), + 120+28.2843*Math.sin(angle+p[5]), 120-28.2843*Math.cos(angle+p[5]), + 120+44.7214*Math.sin(angle+p[6]), 120-44.7214*Math.cos(angle+p[6]) ]; - buf1.fillPoly(poly); - flip1(56, 56); + g.setColor(col); + g.fillPoly(poly); } // stops violent compass swings and wobbles, takes 3ms @@ -205,15 +178,20 @@ //log_debug("draw()"); var d = tiltfixread(CALIBDATA.offset,CALIBDATA.scale); heading = newHeading(d,heading); + // sets bearing to waypoint bearing if GPS on else sets to 0 (north) + getWaypoint(); - getWaypoint(); - + // make the compass point in the direction we need to go var dir = bearing - heading; if (dir < 0) dir += 360; if (dir > 360) dir -= 360; - var t = drawCompass(dir); // we want compass to show us where to go - oldHeading = dir; + if (dir !== oldHeading) { + drawCompass(oldHeading, 0); + drawCompass(dir, 0xFFC0); // yellow + oldHeading = dir; + } + if (gpsObject.getState() === gpsObject.GPS_RUNNING) { drawGPSData(); } else { @@ -221,22 +199,25 @@ } } + // only used when acting as compass with GPS off function drawCompassHeading() { //log_debug("drawCompassHeading()"); - // draw the heading - buf2.setColor(1); - buf2.setFontAlign(-1,-1); - buf2.setFont("Vector",38); var hding = Math.round(heading); var hd = hding.toString(); hd = hding < 10 ? "00"+hd : hding < 100 ? "0"+hd : hd; - buf2.drawString(hd,0,0); - flip2_bw(90, 200); + + if (previous.hding !== hd) { + previous.hding = hd; + g.setColor(1,1,1); + g.setFontAlign(-1,-1); + g.setFont("Vector",38); + g.clearRect(80, 200, 159, 239); + g.drawString(hd, 80, 200); + } } function drawGPSData() { log_debug("drawGPSData()"); - buf2.setFont("Vector",24); var bs = wp_bearing.toString(); bs = wp_bearing<10?"00"+bs : wp_bearing<100 ?"0"+bs : bs; var dst = loc.distance(wp_distance); @@ -249,45 +230,45 @@ // show distance on the left if (previous.dst !== dst) { previous.dst = dst - buf2.setColor(1); - buf2.setFontAlign(-1,-1); - buf2.setFont("Vector", 20); - if (gpsObject.waypointHasLocation()) { - buf2.drawString(dst,0,0); - flip2_bb(0, 200); - } else { - buf2.drawString(" ",0,0); - flip2_bw(0, 200); - } + g.setFontAlign(-1,-1); // left, bottom + g.setFont("Vector", 20); + g.clearRect(0, 200, 79, 239); + + if (gpsObject.waypointHasLocation()) + g.setColor(0x07ff); + else + g.setColor(1,1,1); + g.drawString(dst, 0, 200); } // bearing, place in middle at bottom of compass if (previous.bs !== bs) { previous.bs = bs; - buf2.setColor(1); - buf2.setFontAlign(0, -1); - buf2.setFont("Vector",38); - buf2.drawString(bs,40,0); - flip2_bw(80, 200); + g.setColor(1,1,1); + g.setFontAlign(0,-1); // middle, bottom + g.setFont("Vector",38); + g.clearRect(80, 200, 159, 239); + g.drawString(bs, 119, 200); } // waypoint name on right if (previous.wp_name !== wp.name) { - buf2.setColor(1); - buf2.setFontAlign(1,-1); // right, bottom - buf2.setFont("Vector", 20); - buf2.drawString(wp.name, 80, 0); + g.setFontAlign(1,-1); // right, bottom + g.setFont("Vector", 20); + g.clearRect(160, 200, 239, 239); + if (gpsObject.waypointHasLocation()) - flip2_bb(160, 200); + g.setColor(0x07ff); else - flip2_bw(160, 200); + g.setColor(1,1,1); + g.drawString(wp.name, 239, 200); } } // clear the attributes that control the display refresh function resetPrevious() { log_debug("resetPrevious()"); - previous = {bs:"-", dst:"-", wp_name:"-", course:999}; + previous = {hding:"-", bs:"-", dst:"-", wp_name:"-", course:999}; } return {init:init, freeResources:freeResources, startTimer:startTimer, stopTimer:stopTimer,