forked from espruino/BangleApps
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from espruino/master
update from upstream
- Loading branch information
Showing
40 changed files
with
1,324 additions
and
94 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# Arrow Compass | ||
|
||
A variation of jeffmer's Navigation Compass. The compass points | ||
North and shows the current heading. | ||
|
||
This is a tilt and roll compensated compass with a linear | ||
display. The compass will display the same direction that it shows | ||
when flat as when it is tilted (rotation around the W-S axis) or | ||
rolled (rotation around the N-S) axis. *Even with compensation, it | ||
would be beyond foolish to rely solely on this app for any serious | ||
navigational purpose.* | ||
|
||
![](arrow_screenshot.jpg) | ||
|
||
## 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`. | ||
|
||
It is also worth noting that the presence of the magnetic charging | ||
clamps will require the compass to be recalibrated after every | ||
charge. | ||
|
||
## Controls | ||
|
||
*BTN1* - switches to your selected clock app. | ||
|
||
*BTN2* - switches to the app launcher. | ||
|
||
*BTN3* - invokes calibration ( can be cancelled if pressed accidentally) | ||
|
||
|
||
## Acknowledgement | ||
|
||
This app is based in the work done by [jeffmer](https://github.com/jeffmer/JeffsBangleAppsDev) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
var pal1color = new Uint16Array([0x0000,0xFFC0],0,1); | ||
var pal2color = new Uint16Array([0x0000,0xffff],0,1); | ||
var buf1 = Graphics.createArrayBuffer(160,160,1,{msb:true}); | ||
var buf2 = Graphics.createArrayBuffer(80,40,1,{msb:true}); | ||
var img = require("heatshrink").decompress(atob("lEowIPMjAEDngEDvwED/4DCgP/wAEBgf/4AEBg//8AEBh//+AEBj///AEBn///gEBv///wmCAAImCAAIoBFggE/AkaaEABo=")); | ||
|
||
var bearing=0; // always point north | ||
var heading = 0; | ||
var candraw = false; | ||
var CALIBDATA = require("Storage").readJSON("magnav.json",1)||null; | ||
|
||
Bangle.setLCDTimeout(30); | ||
|
||
function flip1(x,y) { | ||
g.drawImage({width:160,height:160,bpp:1,buffer:buf1.buffer, palette:pal1color},x,y); | ||
buf1.clear(); | ||
} | ||
|
||
function flip2(x,y) { | ||
g.drawImage({width:80,height:40,bpp:1,buffer:buf2.buffer, palette:pal2color},x,y); | ||
buf2.clear(); | ||
} | ||
|
||
function radians(d) { | ||
return (d*Math.PI) / 180; | ||
} | ||
|
||
function drawCompass(course) { | ||
if(!candraw) return; | ||
|
||
buf1.setColor(1); | ||
buf1.fillCircle(80,80,79,79); | ||
buf1.setColor(0); | ||
buf1.fillCircle(80,80,69,69); | ||
buf1.setColor(1); | ||
buf1.drawImage(img, 80, 80, {scale:3, rotate:radians(course)} ); | ||
flip1(40, 30); | ||
} | ||
|
||
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; | ||
} | ||
|
||
function tiltfixread(O,S){ | ||
var start = Date.now(); | ||
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() { | ||
var d = tiltfixread(CALIBDATA.offset,CALIBDATA.scale); | ||
heading = newHeading(d,heading); | ||
var dir = bearing - heading; | ||
if (dir < 0) dir += 360; | ||
if (dir > 360) dir -= 360; | ||
drawCompass(dir); // we want compass to show us where to go | ||
buf2.setColor(1); | ||
buf2.setFontAlign(-1,-1); | ||
buf2.setFont("Vector",38); | ||
var course = Math.round(heading); | ||
var cs = course.toString(); | ||
cs = course<10?"00"+cs : course<100 ?"0"+cs : cs; | ||
buf2.drawString(cs,0,0); | ||
flip2(90, 200); | ||
} | ||
|
||
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<min.x?m.x:min.x; | ||
min.y = m.y<min.y?m.y:min.y; | ||
min.z = m.z<min.z?m.z:min.z; | ||
}, 100); | ||
return new Promise((resolve) => { | ||
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}); | ||
},30000); | ||
}); | ||
} | ||
|
||
function docalibrate(e,first){ | ||
const title = "Calibrate"; | ||
const msg = "takes 30 seconds"; | ||
function action(b){ | ||
if (b) { | ||
buf1.setColor(1); | ||
buf1.setFont("Vector", 30); | ||
buf1.setFontAlign(0,-1); | ||
buf1.drawString("Figure 8s",80, 40); | ||
buf1.drawString("to",80, 80); | ||
buf1.drawString("Calibrate",80, 120); | ||
flip1(40,40); | ||
|
||
calibrate().then((r)=>{ | ||
require("Storage").write("magnav.json",r); | ||
Bangle.buzz(); | ||
CALIBDATA = r; | ||
startdraw(); | ||
setButtons(); | ||
}); | ||
} else { | ||
startdraw(); | ||
setTimeout(setButtons,1000); | ||
} | ||
} | ||
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); | ||
} | ||
|
||
var intervalRef; | ||
|
||
function startdraw(){ | ||
g.clear(); | ||
g.setColor(1,1,1); | ||
Bangle.drawWidgets(); | ||
candraw = true; | ||
intervalRef = setInterval(reading,200); | ||
} | ||
|
||
function stopdraw() { | ||
candraw=false; | ||
if(intervalRef) {clearInterval(intervalRef);} | ||
} | ||
|
||
function setButtons(){ | ||
setWatch(()=>{load();}, BTN1, {repeat:false,edge:"falling"}); | ||
setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); | ||
setWatch(docalibrate, BTN3, {repeat:false,edge:"falling"}); | ||
} | ||
|
||
Bangle.on('lcdPower',function(on) { | ||
if (on) { | ||
startdraw(); | ||
} else { | ||
stopdraw(); | ||
} | ||
}); | ||
|
||
Bangle.on('kill',()=>{Bangle.setCompassPower(0);}); | ||
|
||
Bangle.loadWidgets(); | ||
Bangle.setCompassPower(1); | ||
startdraw(); | ||
setButtons(); |
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.