From 1dbcbd47f82652348f7df3cbd94cf86a7b72676d Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 28 Apr 2022 17:57:39 -0400 Subject: [PATCH 1/7] Fix true wind computation bug, add swipe gesture to pause GPS --- apps/openwind/ChangeLog | 1 + apps/openwind/README.md | 4 ++- apps/openwind/app.js | 72 ++++++++++++++++++++++++------------- apps/openwind/metadata.json | 2 +- 4 files changed, 53 insertions(+), 26 deletions(-) diff --git a/apps/openwind/ChangeLog b/apps/openwind/ChangeLog index 5560f00bc..1e5f791b2 100644 --- a/apps/openwind/ChangeLog +++ b/apps/openwind/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Fix true wind computation, add swipe gesture to pause GPS diff --git a/apps/openwind/README.md b/apps/openwind/README.md index 1df7ea158..c03ec1401 100644 --- a/apps/openwind/README.md +++ b/apps/openwind/README.md @@ -14,7 +14,9 @@ additionally displayed in red. In this mode, the speed over ground in knots is ## Controls -There are no controls in the main app, but there are two settings in the settings app that can be changed: +In the main app, when true wind mode is enabled (see below), swiping left on the screen will temporarily disable GPS (to preserve battery); a small +red satellite symbol will appear on the bottom right. Swiping right will turn GPS back on. +The settings app provides the following two settings: * True wind: enables or disables true wind calculations; enabling this will turn on GPS inside the app * Mounting angle: mounting relative to the boat of the wind instrument (in degrees) diff --git a/apps/openwind/app.js b/apps/openwind/app.js index b1c8fea4b..ca837defa 100644 --- a/apps/openwind/app.js +++ b/apps/openwind/app.js @@ -1,16 +1,20 @@ OW_CHAR_UUID = '0000cc91-0000-1000-8000-00805f9b34fb'; require("Font7x11Numeric7Seg").add(Graphics); -gatt = {}; -cx = g.getWidth()/2; -cy = 24+(g.getHeight()-24)/2; -w = (g.getWidth()-24)/2; - -gps_course = { spd: 0 }; +var gatt = {}; +var cx = g.getWidth()/2; +var cy = 24+(g.getHeight()-24)/2; +var w = (g.getWidth()-24)/2; +var y1 = 24; +var y2 = g.getHeight()-1; +var gps_course = { spd: 0 }; +var course_marker_len = g.getWidth()/4; var settings = require("Storage").readJSON('openwindsettings.json', 1) || {}; -i = 0; -hullpoly = []; +var pause_gps = false; + +var i = 0; +var hullpoly = []; for (y=-1; y<=1; y+=0.1) { hullpoly[i++] = cx - (y<0 ? 1+y*0.15 : (Math.sqrt(1-0.7*y*y)-Math.sqrt(0.3))/(1-Math.sqrt(0.3)))*w*0.3; hullpoly[i++] = cy - y*w*0.7; @@ -22,21 +26,22 @@ for (y=1; y>=-1; y-=0.1) { function wind_updated(ev) { if (ev.target.uuid == "0xcc91") { - awa = settings.mount_angle-ev.target.value.getInt16(1, true)*0.1; + awa = settings.mount_angle+ev.target.value.getInt16(1, true)*0.1; + if (awa<0) awa += 360; aws = ev.target.value.getInt16(3, true)*0.01; -// console.log(awa, aws); + //console.log(awa, aws); if (gps_course.spd > 0) { - wv = { // wind vector (in fixed reference frame) - lon: Math.sin(Math.PI*(gps_course.course+awa)/180)*aws, - lat: Math.cos(Math.PI*(gps_course.course+awa)/180)*aws + wv = { // wind vector (in "earth" reference frame) + vlon: Math.sin(Math.PI*(gps_course.course+(awa+180))/180)*aws, + vlat: Math.cos(Math.PI*(gps_course.course+(awa+180))/180)*aws }; - twv = { lon: wv.lon+gps_course.lon, lat: wv.lat+gps_course.lat }; - tws = Math.sqrt(Math.pow(twv.lon,2)+Math.pow(twv.lat, 2)); - twa = Math.atan2(twv.lat, twv.lon)*180/Math.PI-gps_course.course; + twv = { vlon: wv.vlon+gps_course.vlon, vlat: wv.vlat+gps_course.vlat }; + tws = Math.sqrt(Math.pow(twv.vlon,2)+Math.pow(twv.vlat, 2)); + twa = 180+Math.atan2(twv.vlon, twv.vlat)*180/Math.PI-gps_course.course; if (twa<0) twa += 360; if (twa>360) twa -=360; } - else { + else { tws = -1; twa = 0; } @@ -57,15 +62,18 @@ function draw_compass(awa, aws, twa, tws) { a = i*Math.PI/2+Math.PI/4; g.drawLineAA(cx+Math.cos(a)*w*0.85, cy+Math.sin(a)*w*0.85, cx+Math.cos(a)*w*0.99, cy+Math.sin(a)*w*0.99); } - g.setColor(0, 1, 0).fillCircle(cx+Math.sin(Math.PI*awa/180)*w*0.9, cy+Math.cos(Math.PI*awa/180)*w*0.9, w*0.1); + g.setColor(0, 1, 0).fillCircle(cx+Math.sin(Math.PI*awa/180)*w*0.9, cy-Math.cos(Math.PI*awa/180)*w*0.9, w*0.1); if (tws>0) g.setColor(1, 0, 0).fillCircle(cx+Math.sin(Math.PI*twa/180)*w*0.9, cy+Math.cos(Math.PI*twa/180)*w*0.9, w*0.1); g.setColor(0, 1, 0).setFont("7x11Numeric7Seg",w*0.06); g.setFontAlign(0, 0, 0).drawString(aws.toFixed(1), cx, cy-0.32*w); - if (tws>0) g.setColor(1, 0, 0).drawString(tws.toFixed(1), cx, cy+0.32*w); - if (settings.truewind && typeof gps_course.spd!=='undefined') { - spd = gps_course.spd/1.852; - g.setColor(g.theme.fg).setFont("7x11Numeric7Seg", w*0.03).setFontAlign(-1, 1, 0).drawString(spd.toFixed(1), 1, g.getHeight()-1); + if (!pause_gps) { + if (tws>0) g.setColor(1, 0, 0).drawString(tws.toFixed(1), cx, cy+0.32*w); + if (settings.truewind && gps_course.spd!=-1) { + spd = gps_course.spd/1.852; + g.setColor(g.theme.fg).setFont("7x11Numeric7Seg", w*0.03).setFontAlign(-1, 1, 0).drawString(spd.toFixed(1), 1, g.getHeight()-1); + } } + if (pause_gps) g.setColor("#f00").drawImage(atob("DAwBEAKARAKQE4DwHkPqPRGKAEAA"),g.getWidth()-15, g.getHeight()-15); } function parseDevice(d) { @@ -96,8 +104,10 @@ if (settings.truewind) { Bangle.on('GPS',function(fix) { if (fix.fix && fix.satellites>3 && fix.speed>2) { // only uses fixes w/ more than 3 sats and speed > 2kph gps_course = - { lon: Math.sin(Math.PI*fix.course/180)*fix.speed/1.852, - lat: Math.cos(Math.PI*fix.course/180)*fix.speed/1.852, + { vlon: Math.sin(Math.PI*fix.course/180)*fix.speed/1.852, + vlat: Math.cos(Math.PI*fix.course/180)*fix.speed/1.852, + lat: fix.lat, + lon: fix.lon, spd: fix.speed, course: fix.course }; @@ -107,6 +117,20 @@ if (settings.truewind) { Bangle.setGPSPower(1, "app"); } +if (settings.truewind) { + Bangle.on("swipe", (d)=>{ + if (d==-1 && !pause_gps) { + pause_gps = true; + Bangle.setGPSPower(0); + draw_compass(0, 0, 0, 0); + } + else if (d==1 && pause_gps) { + pause_gps = false; + Bangle.setGPSPower(1, "app"); + draw_compass(0, 0, 0, 0); + } + }); +} Bangle.loadWidgets(); Bangle.drawWidgets(); draw_compass(0, 0, 0, 0); diff --git a/apps/openwind/metadata.json b/apps/openwind/metadata.json index 9229f7f25..43961cc44 100644 --- a/apps/openwind/metadata.json +++ b/apps/openwind/metadata.json @@ -1,7 +1,7 @@ { "id": "openwind", "name": "OpenWind", "shortName":"OpenWind", - "version":"0.01", + "version":"0.02", "description": "OpenWind", "icon": "openwind.png", "readme": "README.md", From 3032376af713854801a621c4bb333a685f1ae014 Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 28 Apr 2022 19:38:34 -0400 Subject: [PATCH 2/7] Fix spaces/tabs issue --- apps/scicalc/app.js | 113 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 apps/scicalc/app.js diff --git a/apps/scicalc/app.js b/apps/scicalc/app.js new file mode 100644 index 000000000..5d914d0c5 --- /dev/null +++ b/apps/scicalc/app.js @@ -0,0 +1,113 @@ +const W = g.getWidth(); +const H = g.getHeight(); + +const dispH = H/5; +const butH = H-dispH; + +const buttons = [[['7', '8', '9'], + ['4', '5', '6'], + ['1', '2', '3'], + ['E', '0', '.']], + [['<', 'M', 'C'], + ['+', '-', '*'], + ['/', '(', ')'], + ['^', ',', '=']], + [['Sin', 'Cos', 'Tan'], + ['Asi', 'Aco', 'Ata'], + ['Pi', '1/x', '+/-'], + ['Log', 'Exp', 'Pow'] + ]]; + +var curPage = 0; +var inputStr = ''; +var memory = ''; +var qResult = false; + +function drawPage (p) { + g.clearRect(0, dispH, W-1, H-1); + g.setFont('Vector', butH/5).setFontAlign(0, 0, 0).setColor(g.theme.fg); + for (x=0; x<3; ++x) + for (y=0; y<4; ++y) + g.drawString(buttons[p][y][x], (x+0.5)*W/3, dispH+(y+0.7)*butH/4); + g.setColor(0.5, 0.5, 0.5); + for (x=1; x<3; ++x) g.drawLine(x*W/3, dispH+0.2*butH/4-2, x*W/3, H-1); + for (y=1; y<4; ++y) g.drawLine(0, dispH+(y+0.2)*butH/4, W-1, dispH+(y+0.2)*butH/4); + g.setColor(g.theme.fg).drawLine(0, dispH+0.2*butH/4-2, W-1, dispH+0.2*butH/4-2); +} + +function updateDisp(s, len) { + var fh = butH/5; + if (s.toString().length>len) s = s.toString().substr(0,len); + g.setFont("Vector", butH/5).setColor(g.theme.fg).setFontAlign(1, 0, 0); + while (g.stringWidth(s) > W-1) { + fh /= 1.05; + g.setFont("Vector", fh); + } + g.clearRect(0, 0, W-1, dispH-1).drawString(s, W-2, dispH/2); + g.setColor(g.theme.fg).drawLine(0, dispH+0.2*butH/4-2, W-1, dispH+0.2*butH/4-2); +} + +function processInp (s) { + var idx = s.indexOf("^"); + if (idx > 0) s = "Math.pow(" + s.slice(0,idx) + "," + s.slice(idx+1, s.length) + ")"; + ['Sin', 'Cos', 'Tan', 'Asin', 'Acos', 'Atan', 'Log', 'Exp', 'Pow'].forEach((x) => { + var i = s.indexOf(x); + while (i>-1) { + s = s.slice(0,i)+"Math."+s.slice(i,i+1).toLowerCase()+s.slice(i+1, s.length); + i = s.indexOf(x, i+6); + } + }); + idx = s.indexOf('Pi'); + if (idx>-1) s = s.slice(0,idx) + "Math.PI" + s.slice(idx+2, s.length); + idx = 0; + s.split('').forEach((x)=>{ if (x=='(') idx++; if (x==')') idx-- }); + s += ')'.repeat(idx); + return s; +} + +function compute() { + var res; + console.log(processInp(inputStr)); + try { res = eval(processInp(inputStr)); } + catch(e) { res = "error"; } + inputStr = res; + qResult = true; + updateDisp(inputStr, 19); +} + +function touchHandler(e, d) { + var x = Math.floor(d.x/(W/3)); + var y = Math.floor((d.y-dispH-0.2*butH/4)/(butH/4)); + var c = buttons[curPage][y][x]; + if (c=="=") { // do the computation + compute(); + return; + } + else if (c=="<" && inputStr.length>0) inputStr = inputStr.slice(0, -1); // delete last character + else if (c=='M' && qResult) memory = inputStr; + else if (c=='M') inputStr += memory; + else if (c=="C") inputStr = ''; // clear + else { + if ("Sin Cos Tan Log Exp Pow".indexOf(c)>-1 && c!='E') c += "("; + if ("Asi Aco Ata".indexOf(c)>-1) c += "n("; + if (c=='1/x') { inputStr = "1/("+inputStr+")"; compute(); return; } + if (c=='+/-') { inputStr = "-("+inputStr+")"; compute(); return; } + if (qResult && "+-*/^".indexOf(c)==-1) inputStr = c + inputStr + ")"; + else inputStr += c; + } + qResult = false; + updateDisp(inputStr, 32); +} + +function swipeHandler(e,d) { + curPage -= e; + if (curPage>buttons.length-1) curPage = 0; + if (curPage<0) curPage = buttons.length-1; + drawPage(curPage); + if (d==1) compute(); +} + +Bangle.on("touch", touchHandler); +Bangle.on("swipe", swipeHandler); +g.clear(); +drawPage(curPage); From 2675dd6c2dd777a1d8bdc416a35a5051579be29e Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 28 Apr 2022 19:40:33 -0400 Subject: [PATCH 3/7] New app scicalc --- apps/scicalc/ChangeLog | 1 + apps/scicalc/README.md | 18 ++++++++++++++++++ apps/scicalc/app-icon.js | 1 + apps/scicalc/metadata.json | 14 ++++++++++++++ apps/scicalc/scicalc.png | Bin 0 -> 562 bytes 5 files changed, 34 insertions(+) create mode 100644 apps/scicalc/ChangeLog create mode 100644 apps/scicalc/README.md create mode 100644 apps/scicalc/app-icon.js create mode 100644 apps/scicalc/metadata.json create mode 100644 apps/scicalc/scicalc.png diff --git a/apps/scicalc/ChangeLog b/apps/scicalc/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/scicalc/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/scicalc/README.md b/apps/scicalc/README.md new file mode 100644 index 000000000..bbe4b93c4 --- /dev/null +++ b/apps/scicalc/README.md @@ -0,0 +1,18 @@ +# SciCalc + +Simple scientific calculator. I needed one, so I wrote a basic one, no design frills. Input expressions are slightly post processed and then evaluated +by the JS interpreter. + +## Usage + +Buttons are arranged on 3 separate screens, swiping left or right switches between them. Swiping down has the same effect as hitting the "=" button. + +## Features + +The calculator supports the following operations: + + * basic arithmetic: +, -, *, /, ^ (raise to a power), +/- (invert sign), 1/x (inverse), use of parentheses + * trigonometric fucntions: sin, cos, tan, asin, acos, atan + * exponential exp, natural logarithm log, pow function (this one takes 2 comma separated arguments) + * Pi is provided as a constant + * a memory button "M" stores or recalls the last result (after hitting the "=" button or swiping down) diff --git a/apps/scicalc/app-icon.js b/apps/scicalc/app-icon.js new file mode 100644 index 000000000..b8363e6ee --- /dev/null +++ b/apps/scicalc/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AJioAaF1wwSFzowRCQUZo4AWjIvVFy4ABF/4vXyGQAYov/R+sZFy8ZF6oAcF/4vvi4AeF/4SCjseAAMdAx8MAAYvVEAQABAx4v/R/TvvF96PUg8cAAMHd9QuCAAIv/R+rvvF96Pvd94vvR97vvF96Pvd94vvR97vsGDwuQGDouSAH4A/AGwA==")) diff --git a/apps/scicalc/metadata.json b/apps/scicalc/metadata.json new file mode 100644 index 000000000..54fdc5a26 --- /dev/null +++ b/apps/scicalc/metadata.json @@ -0,0 +1,14 @@ +{ "id": "scicalc", + "name": "Scientific Calculator", + "shortName":"SciCalc", + "version":"0.01", + "description": "Scientific calculator", + "icon": "scicalc.png", + "readme": "README.md", + "tags": "app,tool", + "supports" : ["BANGLEJS2"], + "storage": [ + {"name":"scicalc.app.js","url":"app.js"}, + {"name":"scicalc.img","url":"app-icon.js","evaluate":true}, + ] +} diff --git a/apps/scicalc/scicalc.png b/apps/scicalc/scicalc.png new file mode 100644 index 0000000000000000000000000000000000000000..b5aa6ff7e90ddf52c08c77ea9f943ff62c19574c GIT binary patch literal 562 zcmV-20?qx2P)f z2@6dVMx#5}gm-ZDZ`78BmPBO0q0t4JLbUhZmbO;!Z|ceUa_@I~PES%mAo$-bu!xGq zVxACk3ZMjFIb2J42cSukbf{_C9ZgIvU~K*dKxQ89IOqe|=yW=Umx$0#8Nd0c&0~D$ z2~Ct@IH)vv*gnW3lV1#Cii-I%!u7fH(o0@ifT06$&3xGA0YF||a)&E4Jxc+`25#lPK+wD%px~>P#J*B3n_(76*EYbhSDwWD7*NJmRRaH-qi65cZw@|rUMmC#u za;9mb)oL+&ihT>Y%>#fe%RH8nKSHr@AIkXnmLv&bOm6CrVEKnRaJMr1k?`Lwp{~Y(R3luCxp~!B5DE6 zX7kpz?M(m|aE()l3;Lhx AZ2$lO literal 0 HcmV?d00001 From 06581584a63d241f6f69007f9aaa7323ecdc2ffe Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 28 Apr 2022 19:42:43 -0400 Subject: [PATCH 4/7] Typo in metadata.json --- apps/scicalc/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/scicalc/metadata.json b/apps/scicalc/metadata.json index 54fdc5a26..6732e097d 100644 --- a/apps/scicalc/metadata.json +++ b/apps/scicalc/metadata.json @@ -9,6 +9,6 @@ "supports" : ["BANGLEJS2"], "storage": [ {"name":"scicalc.app.js","url":"app.js"}, - {"name":"scicalc.img","url":"app-icon.js","evaluate":true}, + {"name":"scicalc.img","url":"app-icon.js","evaluate":true} ] } From 7ec3b149b18ea4806bb1502938e59639bc6e3491 Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 28 Apr 2022 19:45:37 -0400 Subject: [PATCH 5/7] Fix more spaces/tabs --- apps/openwind/app.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/openwind/app.js b/apps/openwind/app.js index ca837defa..4abe84fca 100644 --- a/apps/openwind/app.js +++ b/apps/openwind/app.js @@ -79,20 +79,20 @@ function draw_compass(awa, aws, twa, tws) { function parseDevice(d) { device = d; console.log("Found device"); - device.gatt.connect().then(function(ga) { - console.log("Connected"); - gatt = ga; - return ga.getPrimaryService("cc90"); -}).then(function(s) { - return s.getCharacteristic("cc91"); -}).then(function(c) { - c.on('characteristicvaluechanged', (event)=>wind_updated(event)); - return c.startNotifications(); -}).then(function() { - console.log("Done!"); -}).catch(function(e) { - console.log("ERROR"+e); -});} + device.gatt.connect().then(function(ga) { + console.log("Connected"); + gatt = ga; + return ga.getPrimaryService("cc90"); + }).then(function(s) { + return s.getCharacteristic("cc91"); + }).then(function(c) { + c.on('characteristicvaluechanged', (event)=>wind_updated(event)); + return c.startNotifications(); + }).then(function() { + console.log("Done!"); + }).catch(function(e) { + console.log("ERROR"+e); + });} function connection_setup() { NRF.setScan(); @@ -106,8 +106,8 @@ if (settings.truewind) { gps_course = { vlon: Math.sin(Math.PI*fix.course/180)*fix.speed/1.852, vlat: Math.cos(Math.PI*fix.course/180)*fix.speed/1.852, - lat: fix.lat, - lon: fix.lon, + lat: fix.lat, + lon: fix.lon, spd: fix.speed, course: fix.course }; From 31ef7c3d97367abf71dcf81a3604b457bffb1616 Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 28 Apr 2022 19:48:24 -0400 Subject: [PATCH 6/7] Fix tabs, again, sigh... --- apps/openwind/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openwind/app.js b/apps/openwind/app.js index 4abe84fca..db67804f3 100644 --- a/apps/openwind/app.js +++ b/apps/openwind/app.js @@ -106,8 +106,8 @@ if (settings.truewind) { gps_course = { vlon: Math.sin(Math.PI*fix.course/180)*fix.speed/1.852, vlat: Math.cos(Math.PI*fix.course/180)*fix.speed/1.852, - lat: fix.lat, - lon: fix.lon, + lat: fix.lat, + lon: fix.lon, spd: fix.speed, course: fix.course }; From 51aa4ac12ab2eb74829b85e331870932a165fccc Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 28 Apr 2022 19:56:09 -0400 Subject: [PATCH 7/7] Enable emulator --- apps/scicalc/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/scicalc/metadata.json b/apps/scicalc/metadata.json index 6732e097d..d2d855dc2 100644 --- a/apps/scicalc/metadata.json +++ b/apps/scicalc/metadata.json @@ -6,6 +6,7 @@ "icon": "scicalc.png", "readme": "README.md", "tags": "app,tool", + "allow_emulator": true, "supports" : ["BANGLEJS2"], "storage": [ {"name":"scicalc.app.js","url":"app.js"},