modified kitchen/compass to write directly to screen to avoid LOW_MEMORY exceptions

pull/726/head
hughbarney 2021-04-19 21:48:12 +01:00
parent e49ced572a
commit 9bce2540db
4 changed files with 78 additions and 82 deletions

View File

@ -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",

View File

@ -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

View File

@ -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

View File

@ -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,14 +178,19 @@
//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();
// 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();
@ -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,