diff --git a/apps.json b/apps.json index 7fe259899..12ba766f3 100644 --- a/apps.json +++ b/apps.json @@ -2639,14 +2639,15 @@ { "id": "magnav", "name": "Navigation Compass", - "version": "0.04", + "version": "0.05", "description": "Compass with linear display as for GPSNAV. Has Tilt compensation and remembers calibration.", "icon": "magnav.png", "tags": "tool,outdoors", - "supports": ["BANGLEJS"], + "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ - {"name":"magnav.app.js","url":"magnav.min.js"}, + {"name":"magnav.app.js","url":"magnav-b1.js","supports":"BANGLEJS"}, + {"name":"magnav.app.js","url":"magnav-b2.js","supports":"BANGLEJS2"}, {"name":"magnav.img","url":"magnav-icon.js","evaluate":true} ], "data": [{"name":"magnav.json"}] @@ -2730,7 +2731,7 @@ { "id": "multiclock", "name": "Multi Clock", - "version": "0.08", + "version": "0.09", "description": "Clock with multiple faces. Switch between faces with BTN1 & BTN3 or swipe left-right. For best display set theme Background 2 to cyan or some other bright colour in settings.", "icon": "multiclock.png", "type": "clock", diff --git a/apps/magnav/ChangeLog b/apps/magnav/ChangeLog index 35e8798c6..2b2782c7b 100644 --- a/apps/magnav/ChangeLog +++ b/apps/magnav/ChangeLog @@ -2,5 +2,6 @@ 0.02: Course marker 0.03: Tilt compensation and calibration 0.04: Fix Font size +0.05: Inital portable version diff --git a/apps/magnav/README.md b/apps/magnav/README.md index a036644fb..bd9190d2f 100644 --- a/apps/magnav/README.md +++ b/apps/magnav/README.md @@ -6,19 +6,17 @@ This is a tilt and roll compensated compass with a linear display. The compass w ## Calibration -Correct operation of this app depends critically on calibration. When first run on a Bangle, the app will request calibration. This lasts for 30 seconds during which you should move the watch slowly through figures of 8. It is important that during calibration the watch is fully rotated around each of it axes. If the app does give 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`. +Correct operation of this app depends critically on calibration. When first run on a Bangle, the app will request calibration. This lasts for 20 seconds during which you should move the watch slowly through figures of 8. It is important that during calibration the watch is fully rotated around each of it axes. If the app does give the correct direction heading or is not stable with respect to tilt and roll - redo the calibration by pressing *BTN2*. Calibration data is recorded in a storage file named `magnav.json`. + +Note: Charging your Bangle due to the magnetic connector clamp seems to require recalibration afterwards for accurate readings. ## Controls -*BTN1* - switches to your selected clock app. +*BTN1* - marks the current heading with a blue circle - see screen shot. This can be used to take a bearing and then follow it.. -*BTN2* - switches to the app launcher. +*BTN2* - invokes calibration ( can be cancelled if pressed accidentally). -*BTN3* - invokes calibration ( can be cancelled if pressed accidentally) - -*Touch Left* - marks the current heading with a blue circle - see screen shot. This can be used to take a bearing and then follow it. - -*Touch Right* - cancels the marker (blue circle not displayed). +*BTN3* - cancels the marker (blue circle not displayed) ## Support diff --git a/apps/magnav/magnav.min.js b/apps/magnav/magnav.min.js deleted file mode 100644 index 1d5439164..000000000 --- a/apps/magnav/magnav.min.js +++ /dev/null @@ -1,10 +0,0 @@ -var Yoff=80,pal2color=new Uint16Array([0,65535,2047,50712],0,2),buf=Graphics.createArrayBuffer(240,60,2,{msb:!0});Bangle.setLCDTimeout(30);function flip(b,c){g.drawImage({width:240,height:60,bpp:2,buffer:b.buffer,palette:pal2color},0,c);b.clear()}var labels="N NE E SE S SW W NW".split(" "),brg=null; -function drawCompass(b){buf.setColor(1);buf.setFont("Vector",24);var c=b-90;0>c&&(c+=360);buf.fillRect(28,45,212,49);var a=30,d=15-c%15;15>d?a+=d:d=0;for(var e=d;e<=180-d;e+=15){var f=c+e;0==f%90?(buf.drawString(labels[Math.floor(f/45)%8],a-8,0),buf.fillRect(a-2,25,a+2,45)):0==f%45?(buf.drawString(labels[Math.floor(f/45)%8],a-12,0),buf.fillRect(a-2,30,a+2,45)):0==f%15&&buf.fillRect(a,35,a+1,45);a+=15}brg&&(b=brg-b,180b&&(b+=360),b+=120,30>b&&(b=14),210c?1:-1;180<=a&&(a=360-a,d=-d);if(2>a)return c;a=c+d*(1+Math.round(a/5));0>a&&(a+=360);360a&&(a+=360);return a} -function reading(){var b=tiltfixread(CALIBDATA.offset,CALIBDATA.scale);heading=newHeading(b,heading);drawCompass(heading);buf.setColor(1);buf.setFont("6x8",2);buf.setFontAlign(-1,-1);buf.drawString("o",170,0);buf.setFont("Vector",54);b=Math.round(heading);var c=b.toString();buf.drawString(10>b?"00"+c:100>b?"0"+c:c,70,10);flip(buf,Yoff+80)} -function calibrate(){var b=-32E3,c=-32E3,a=-32E3,d=32E3,e=32E3,f=32E3,k=setInterval(function(){var h=Bangle.getCompass();b=h.x>b?h.x:b;c=h.y>c?h.y:c;a=h.z>a?h.z:a;d=h.x{ require("Storage").write("magnav.json",r); - CALIBDATA = r; - startdraw(); - setButtons(); + restart() }); } else { - startdraw(); - setTimeout(setButtons,1000); - } + restart() + } } if (first===undefined) first=false; stopdraw(); - clearWatch(); if (first) E.showAlert(msg,title).then(action.bind(null,true)); else E.showPrompt(msg,{title:title,buttons:{"Start":true,"Cancel":false}}).then(action); } -Bangle.on('touch', function(b) { - if(!candraw) return; - if(b==1) brg=heading; - if(b==2) brg=null; - }); - var intervalRef; function startdraw(){ @@ -176,29 +173,17 @@ function stopdraw() { } function setButtons(){ - setWatch(()=>{load();}, BTN1, {repeat:false,edge:"falling"}); - setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); - setWatch(docalibrate, BTN3, {repeat:false,edge:"falling"}); + function actions(v){ + if (!v) docalibrate(false); + else if (v==1) brg=null; + else brg=heading; + } + Bangle.setUI("updown",actions); } -var SCREENACCESS = { - withApp:true, - request:function(){ - this.withApp=false; - stopdraw(); - clearWatch(); - }, - release:function(){ - this.withApp=true; - startdraw(); - setButtons(); - } -}; - Bangle.on('lcdPower',function(on) { - if (!SCREENACCESS.withApp) return; if (on) { - startdraw(); + if (!calibrating) startdraw(); } else { stopdraw(); } @@ -209,7 +194,7 @@ Bangle.on('kill',()=>{Bangle.setCompassPower(0);}); Bangle.loadWidgets(); Bangle.setCompassPower(1); if (!CALIBDATA) - docalibrate({},true); + docalibrate(true); else { startdraw(); setButtons(); @@ -217,4 +202,3 @@ else { - diff --git a/apps/magnav/magnav_b1.min.js b/apps/magnav/magnav_b1.min.js new file mode 100644 index 000000000..805dc3fd4 --- /dev/null +++ b/apps/magnav/magnav_b1.min.js @@ -0,0 +1,9 @@ +var Yoff=80,pal2color=new Uint16Array([0,65535,2047,50712],0,2),buf=Graphics.createArrayBuffer(240,60,2,{msb:!0});Bangle.setLCDTimeout(30);function flip(b,c){g.drawImage({width:240,height:60,bpp:2,buffer:b.buffer,palette:pal2color},0,c);b.clear()}var labels="N NE E SE S SW W NW".split(" "),brg=null; +function drawCompass(b){"ram";buf.setColor(1);buf.setFont("Vector",24);var c=b-90;0>c&&(c+=360);buf.fillRect(28,45,212,49);var a=30,d=15-c%15;15>d?a+=d:d=0;for(var e=d;e<=180-d;e+=15){var f=c+e;0==f%90?(buf.drawString(labels[Math.floor(f/45)%8],a-8,0),buf.fillRect(a-2,25,a+2,45)):0==f%45?(buf.drawString(labels[Math.floor(f/45)%8],a-12,0),buf.fillRect(a-2,30,a+2,45)):0==f%15&&buf.fillRect(a,35,a+1,45);a+=15}brg&&(b=brg-b,180b&&(b+=360),b+=120,30>b&&(b=14),210c?1:-1;180<=a&&(a=360-a,d=-d);if(2>a)return c;a=c+d*(1+Math.round(a/5));0>a&&(a+=360);360a&&(a+=360);return a} +function reading(){var b=tiltfixread(CALIBDATA.offset,CALIBDATA.scale);heading=newHeading(b,heading);drawCompass(heading);buf.setColor(1);buf.setFont("6x8",2);buf.setFontAlign(-1,-1);buf.drawString("o",170,0);buf.setFont("Vector",54);b=Math.round(heading);var c=b.toString();buf.drawString(10>b?"00"+c:100>b?"0"+c:c,70,10);flip(buf,Yoff+80)} +function calibrate(){var b=-32E3,c=-32E3,a=-32E3,d=32E3,e=32E3,f=32E3,k=setInterval(function(){var h=Bangle.getCompass();b=h.x>b?h.x:b;c=h.y>c?h.y:c;a=h.z>a?h.z:a;d=h.x180) bpos -=360; + if (bpos<-180) bpos +=360; + bpos= Math.floor((bpos*4)/5)+88; + if (bpos<16) bpos = 8; + if (bpos>160) bpos = 170; + g.setColor(g.theme.fg2); + g.fillCircle(bpos,Ypos+45,6); + } +} + +var heading = 0; +function newHeading(m,h){ + var s = Math.abs(m - h); + var delta = (m>h)?1:-1; + if (s>=180){s=360-s; delta = -delta;} + if (s<2) return h; + var hd = h + delta*(1 + Math.round(s/5)); + if (hd<0) hd+=360; + if (hd>360)hd-= 360; + return hd; +} + +var candraw = false; +var CALIBDATA = require("Storage").readJSON("magnav.json",1)||null; + +function tiltfixread(O,S){ + "ram" + var m = Bangle.getCompass(); + var g = Bangle.getAccel(); + m.dx =(m.x-O.x)*S.x; m.dy=(m.y-O.y)*S.y; m.dz=(m.z-O.z)*S.z; + var d = Math.atan2(-m.dx,m.dy)*180/Math.PI; + if (d<0) d+=360; + var phi = Math.atan(-g.x/-g.z); + var cosphi = Math.cos(phi), sinphi = Math.sin(phi); + var theta = Math.atan(-g.y/(-g.x*sinphi-g.z*cosphi)); + var costheta = Math.cos(theta), sintheta = Math.sin(theta); + var xh = m.dy*costheta + m.dx*sinphi*sintheta + m.dz*cosphi*sintheta; + var yh = m.dz*sinphi - m.dx*cosphi; + var psi = Math.atan2(yh,xh)*180/Math.PI; + if (psi<0) psi+=360; + return psi; +} + +// Note actual mag is 360-m, error in firmware +function reading() { + "ram" + g.clearRect(0,24,175,175); + var d = tiltfixread(CALIBDATA.offset,CALIBDATA.scale); + heading = newHeading(d,heading); + drawCompass(heading); + g.setColor(g.theme.fg); + g.setFont("6x8",2); + g.setFontAlign(-1,-1); + g.drawString("o",120,Ypos+80); + g.setFont("Vector",40); + var course = Math.round(heading); + var cs = course.toString(); + cs = course<10?"00"+cs : course<100 ?"0"+cs : cs; + g.drawString(cs,50,Ypos+90); + g.setColor(g.theme.fg2); + g.fillPoly([88,Ypos+60,78,Ypos+80,98,Ypos+80]); + g.setColor(g.theme.fg); + g.flip(); +} + +function calibrate(){ + var max={x:-32000, y:-32000, z:-32000}, + min={x:32000, y:32000, z:32000}; + var ref = setInterval(()=>{ + var m = Bangle.getCompass(); + max.x = m.x>max.x?m.x:max.x; + max.y = m.y>max.y?m.y:max.y; + max.z = m.z>max.z?m.z:max.z; + min.x = m.x { + setTimeout(()=>{ + if(ref) clearInterval(ref); + var offset = {x:(max.x+min.x)/2,y:(max.y+min.y)/2,z:(max.z+min.z)/2}; + var delta = {x:(max.x-min.x)/2,y:(max.y-min.y)/2,z:(max.z-min.z)/2}; + var avg = (delta.x+delta.y+delta.z)/3; + var scale = {x:avg/delta.x, y:avg/delta.y, z:avg/delta.z}; + resolve({offset:offset,scale:scale}); + },20000); + }); +} + +var calibrating=false; +function docalibrate(first){ + calibrating=true; + const title = "Calibrate"; + const msg = "takes 20 seconds"; + function restart() { + calibrating=false; + setButtons(); + startdraw(); + } + function action(b){ + if (b) { + g.clearRect(0,24,175,175); + g.setColor(g.theme.fg); + g.setFont("Vector",18); + g.setFontAlign(0,-1); + g.drawString("Fig 8s to",88,Ypos); + g.drawString("Calibrate",88,Ypos+18); + g.flip(); + calibrate().then((r)=>{ + require("Storage").write("magnav.json",r); + restart(); + }); + } else { + restart(); + } + } + if (first===undefined) first=false; + stopdraw(); + if (first) + E.showAlert(msg,title).then(action.bind(null,true)); + else + E.showPrompt(msg,{title:title,buttons:{"Start":true,"Cancel":false}}).then(action); +} + +var intervalRef; + +function startdraw(){ + g.clear(1); + Bangle.drawWidgets(); + candraw = true; + intervalRef = setInterval(reading,200); +} + +function stopdraw() { + candraw=false; + if(intervalRef) {clearInterval(intervalRef);} +} + +function setButtons(){ + function actions(v){ + if (!v) docalibrate(false); + else if (v==1) brg=null; + else brg=heading; + } + Bangle.setUI("updown",actions); +} + +Bangle.on('kill',()=>{Bangle.setCompassPower(0);}); + +Bangle.loadWidgets(); +Bangle.setCompassPower(1); +if (!CALIBDATA) + docalibrate(true); +else { + startdraw(); + setButtons(); +} + + + diff --git a/apps/multiclock/ChangeLog b/apps/multiclock/ChangeLog index 9d02ae85e..442a5277a 100644 --- a/apps/multiclock/ChangeLog +++ b/apps/multiclock/ChangeLog @@ -6,6 +6,7 @@ 0.06: add minute tick for efficiency and nifty A clock 0.07: compatible with Bang;e.js 2 0.08: fix minute tick bug +0.09: use setUI clockupdown for controls + fix small display bug in nifty face diff --git a/apps/multiclock/README.md b/apps/multiclock/README.md index e8b8335ea..25c997329 100644 --- a/apps/multiclock/README.md +++ b/apps/multiclock/README.md @@ -5,7 +5,9 @@ This is a clock app that supports multiple clock faces. The user can switch betw ## Controls -Swipe left and right on both the Bangle and Bangle 2 switch between faces. BTN1 & BTH3 also switch faces on the Bangle. +Uses `setUI("clockupdown")` +BTN1 & BTH3 switch faces on the Bangle. +Touch upper right and lower right quadrant switch faces on the Bangle 2. ## Adding a new face Clock faces are described in javascript storage files named `name.face.js`. For example, the Analog Clock Face is described in `ana.face.js`. These files have the following structure: diff --git a/apps/multiclock/multiclock.app.js b/apps/multiclock/multiclock.app.js index c24e5c94b..0565a7040 100644 --- a/apps/multiclock/multiclock.app.js +++ b/apps/multiclock/multiclock.app.js @@ -67,7 +67,7 @@ function setButtons(){ startdraw(); } } - Bangle.setUI("leftright", newFace); + Bangle.setUI("clockupdown", newFace); } E.on('kill',()=>{ diff --git a/apps/multiclock/nifty.face.js b/apps/multiclock/nifty.face.js index 2c2af6063..54962da34 100644 --- a/apps/multiclock/nifty.face.js +++ b/apps/multiclock/nifty.face.js @@ -28,7 +28,7 @@ var now = new Date(); const hour = d02(now.getHours() - (is12Hour && now.getHours() > 12 ? 12 : 0)); const minutes = d02(now.getMinutes()); - const day = d02(now.getDay()); + const day = d02(now.getDate()); const month = d02(now.getMonth() + 1); const year = now.getFullYear(); const month2 = locale.month(now, 3);