From 9bce2540db8e14d254a3684a4d4c2220ec8340db Mon Sep 17 00:00:00 2001 From: hughbarney Date: Mon, 19 Apr 2021 21:48:12 +0100 Subject: [PATCH] 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,