Merge remote-tracking branch 'upstream/master'

pull/671/head
hughbarney 2021-02-17 18:03:33 +00:00
commit c1bda46364
20 changed files with 730 additions and 266 deletions

View File

@ -65,7 +65,7 @@
{ "id": "locale",
"name": "Languages",
"icon": "locale.png",
"version":"0.08",
"version":"0.09",
"description": "Translations for different countries",
"tags": "tool,system,locale,translate",
"type": "locale",
@ -269,6 +269,30 @@
{"name":"clock2x3.img","url":"clock2x3-icon.js","evaluate":true}
]
},
{ "id": "geissclk",
"name": "Geiss Clock",
"icon": "clock.png",
"version":"0.01",
"description": "7 segment clock with animated background in the style of Ryan Geiss' music visualisation. NOTE: The first run will take ~1 minute to do some precalculation",
"tags": "clock",
"type":"clock",
"storage": [
{"name":"geissclk.app.js","url":"clock.js"},
{"name":"geissclk.precompute.js","url":"precompute.js"},
{"name":"geissclk.img","url":"clock-icon.js","evaluate":true}
],
"data": [
{"name":"geissclk.0.map"},
{"name":"geissclk.1.map"},
{"name":"geissclk.2.map"},
{"name":"geissclk.3.map"},
{"name":"geissclk.4.map"},
{"name":"geissclk.5.map"},
{"name":"geissclk.0.pal"},
{"name":"geissclk.1.pal"},
{"name":"geissclk.2.pal"}
]
},
{ "id": "trex",
"name": "T-Rex",
"icon": "trex.png",
@ -1492,7 +1516,7 @@
"name": "Digital Assistant, not EDITH",
"shortName": "DANE",
"icon": "app.png",
"version": "0.15",
"version": "0.16",
"description": "A Watchface inspired by Tony Stark's EDITH and based on https://arwes.dev/",
"tags": "clock",
"type": "clock",
@ -2637,11 +2661,11 @@
]
},
{ "id": "speedalt",
"name": "GPS Speedo and Altimeter",
"shortName":"GPS Speed Alt",
"name": "GPS Adventure Sports",
"shortName":"GPS Adv Sport",
"icon": "app.png",
"version":"0.07",
"description": "GPS speed and altitude display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.",
"version":"1.00",
"description": "GPS speed, altitude and distance to waypoint display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.",
"tags": "tool,outdoors",
"type":"app",
"allow_emulator":true,

View File

@ -11,3 +11,4 @@
0.13: Improve icon
0.14: Switch Icon back to 8bit web palette to fix it
0.15: Hotfix: Remove var declaration from app image
0.16: Revert: Change Counter back to button control

View File

@ -67,7 +67,7 @@ function levelColor(l) {
function drawBattery() {
const l = E.getBattery(), c = levelColor(l);
count = l;
// count = l;
const xl = 45 + l * (194 - 46) / 100;
g.clearRect(46, 58 + 80 + yOffset + 37, 193, height - 5);
g.setColor(c).fillRect(46, 58 + 80 + yOffset + 37, xl, height - 5);
@ -124,14 +124,14 @@ drawClock();
setWatch(Bangle.showLauncher, BTN2, {repeat: false, edge: "falling"});
// setWatch(function () {
// count++;
// drawCounterText();
// }, BTN1, {repeat: true, edge: "falling"});
// setWatch(function () {
// count--;
// drawCounterText();
// }, BTN3, {repeat: true, edge: "falling"});
setWatch(function () {
count++;
drawCounterText();
}, BTN1, {repeat: true, edge: "falling"});
setWatch(function () {
count--;
drawCounterText();
}, BTN3, {repeat: true, edge: "falling"});
// refesh every 100 milliseconds
setInterval(updateClock, 500);

1
apps/geissclk/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: New App!

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEw4X/AoMF/3G/2m/wOCmoaKmtAAgVQBYsFoECwALMAA0JBZQABBYIbBBaVUBYMVBYkBIIILDgEKGYUBqkA6oLB6sAlQLDqsAioLBCAOq4AkCqtAivCBYMC1YwDitQgtCwNUhWsOwlUBYVQlWwJAlVgtSxNQFwnwGANBqWFqQuE1QwBqNewtKFwgLBGANWytq2EFWoU6gWBqoLBFwNVYIZZBqtXyurioLF1W1q/W1tVPIIxE1NV72VqpTDDAleEIgADnWq3qgBTIYADvQuBAAVUBYla1XVBYYbDyt632qd40Fqulquq0ALFOwO16t6BYpxBvWX6tW0aoDXwNU1XXNQMD1T7CAwPC1abBegPqFodQdQILCO4hxBlWxq2FoqaFBYOBcYNxQggLCToOBqAwBTgwLCiqoGgtCJ4L0BBYsVBYRmBBY0CwEUJ4IwFBYkVBYsMBYI0CJAwLDAA4L2A="))

145
apps/geissclk/clock.js Normal file
View File

@ -0,0 +1,145 @@
var W = 79, H = 64;
/*var compiled = E.compiledC(`
// void transl(int, int, int )
int transl(unsigned char *map, unsigned char *imgfrom, unsigned char *imgto) {
int n = 0;
const int W = 79;
const int H = 64;
for (int y=0;y<H;y++)
for (int x=0;x<W;x++) {
int d = map[n];
int nx = (x<<3) + ((d )&0x0F) - 8;
int ny = (y<<3) + ((d>>4)&0x0F) - 8;
int ax = nx&7;
int ay = ny&7;
int a = (nx>>3) + ((ny>>3)*W);
int c = 0;
if (a>=0 && a<(W*H-(W+1))) {
c = imgfrom[a]*(8-ax)*(8-ay) +
imgfrom[a+1]*(ax)*(8-ay) +
imgfrom[a+W]*(8-ax)*(ay) +
imgfrom[a+W+1]*(ax)*(ay);
c = (c>>6) - 4;
if (c<0) c=0;
}
imgto[n] = c;
n++;
}
}
`);*/
var compiled = (function(){
var bin=atob("Len3TwAnT/BPCPsAAJMI+wfzAOsDCdMYAZMAJhn4BkAAnQTwDwMD68YDBesUFAg7CDzdEE/q5AoI+wpaQfJvNapFItgB6woOA/AHAxH4CsCe+AGww/EIBQX7DPwD+wvMnvhPsATwBwQF+wv1ZUPE8QgKCvsMXJ74UFBrQwT7A8SkEQQ8JOrkdADgACQBm5xVATZPLsLRATdAL7bRA7C96PCPAAA=");
return {
transl:E.nativeCall(1, "void(int, int, int )", bin),
};
})();
require("Font7x11Numeric7Seg").add(Graphics);
// Allocate the data
var dataa = new Uint8Array(W*H);
var datab = new Uint8Array(W*H);
var map = new Uint8Array(W*H);
var pal = new Uint16Array(256);
var PALETTES = 3;
var MAPS = 6;
// If we're missing any maps, compute them!
(function() {
var files = require("Storage").list(/^geissclk/);
var allOk = true;
for (var n=0;n<PALETTES;n++)
if (!files.includes("geissclk."+n+".pal"))
allOk = false;
for (var n=0;n<MAPS;n++)
if (!files.includes("geissclk."+n+".map"))
allOk = false;
if (!allOk)
eval(require("Storage").read("geissclk.precompute.js"));
})();
function randomPalette() {
var n = (0|Math.random()*200000) % PALETTES;
var p = new Uint8Array(pal.buffer);
p.set(require("Storage").readArrayBuffer("geissclk."+n+".pal"));
}
function randomMap() {
var n = (0|Math.random()*200000) % MAPS;
map.set(require("Storage").readArrayBuffer("geissclk."+n+".map"));
}
randomPalette();
randomMap();
// Get the address
var addra = E.getAddressOf(dataa,true);
if (!addra) throw new Error("Not a Flat String");
var addrb = E.getAddressOf(datab,true);
if (!addrb) throw new Error("Not a Flat String");
var addrmap = E.getAddressOf(map,true);
if (!addrmap) throw new Error("Not a Flat String");
var gfx = Graphics.createArrayBuffer(W,H,8);
gfx.buffer = dataa.buffer;
var im = {
width:W, height:H, bpp:8,
palette: pal,
buffer : dataa.buffer
};
var lastSeconds = -1;
function iterate() { "ram"
var d = new Date();
var time = d.getHours().toString().padStart(2," ")+":"+d.getMinutes().toString().padStart(2,0);
var seconds = d.getSeconds().toString().padStart(2,0);
t = addra; addra = addrb; addrb = t;
t = dataa; dataa = datab; datab = t;
if (seconds!=lastSeconds) {
lastSeconds = seconds;
im.buffer = datab.buffer;
gfx.buffer = datab.buffer;
} else {
im.buffer = dataa.buffer;
gfx.buffer = dataa.buffer;
}
var x,y,n,t = getTime()/10;
var amt = 100*Bangle.getAccel().diff;
for (var i=0;i<amt;i++) {
//x = Math.round((W/2) + 20*Math.sin(t));
//y = Math.round((H/2) + 20*Math.cos(t));
//t += 0.628;
x = 1+(Math.random()*(W-2))|0;
y = 1+(Math.random()*(H-2))|0;
dataa[x + y*W] = 240;
}
compiled.transl(addrmap, addra, addrb);
gfx.setFont("7x11Numeric7Seg",2);
gfx.drawString(time, -5, 20);
gfx.setFont("7x11Numeric7Seg");
gfx.drawString(seconds, 62, 30);
// firmwares pre-2v09 wouldn't accelerate a 3x blit if it went right to the RHS - hence we're 79px not 80
g.drawImage(im,1,24,{scale:3});
}
Bangle.on('lcdPower',function(on) {
if (animInterval) {
clearInterval(animInterval);
animInterval = undefined;
}
if (on) {
randomMap();
randomPalette();
iterate();
animInterval = setInterval(iterate, 50);
}
});
g.clear();
Bangle.loadWidgets();
Bangle.drawWidgets();
iterate();
animInterval = setInterval(iterate, 50);

BIN
apps/geissclk/clock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

108
apps/geissclk/precompute.js Normal file
View File

@ -0,0 +1,108 @@
// PALETTES ---------------------------
E.showMessage("Precomputing\npalettes\n\nPlease wait...\n0 / 3");
(function() { // fire
for (var i=0;i<256;i++) {
var r = Math.min(i*6,240);
var g = Math.min(i*3,240);
var b = E.clip((i-192)*8,0,240);
pal[i] = (b>>3) | ((g&0xFC)<<3) | ((r&0xF8)<<8);
}pal[255] = 65535;
})()
require("Storage").write("geissclk.0.pal",pal.buffer);
E.showMessage("Precomputing\npalettes\n\nPlease wait...\n1 / 3");
(function() { // gunge
for (var i=0;i<256;i++) {
var r = 0;
var g = Math.min(i*3,255);
var b = Math.min(i,255);
pal[i] = (b>>3) | ((g&0xFC)<<3) | ((r&0xF8)<<8);
}pal[255] = 65535;
})()
require("Storage").write("geissclk.1.pal",pal.buffer);
E.showMessage("Precomputing\npalettes\n\nPlease wait...\n2 / 3");
(function() { // rainbow
for (var i=0;i<256;i++) {
var cl = E.HSBtoRGB((48+i)/128,1,Math.min(i/16,0.9),true);
var r = cl[0];
var g = cl[1];
var b = cl[2];
pal[i] = (b>>3) | ((g&0xFC)<<3) | ((r&0xF8)<<8);
}pal[255] = 65535;pal[255] = 65535;
})()
require("Storage").write("geissclk.2.pal",pal.buffer);
// MAPS ----------------------------------------------
E.showMessage("Precomputing\nmaps\n\nPlease wait...\n0 / 5");
// straight out
(function() { "ram"; var n = 0; for (var y=0;y<H;y++) {
for (var x=0;x<W;x++) {
var dx = x-(W/2);
var dy = y-(H/2);
var d = Math.sqrt(dx*dx + dy*dy);
var s = -2 + Math.sin(d*0.5);
dx = dx*s/d;
dy = dy*s/d;
map[n++] = ((dx*2 + 8) & 0x0F) | (((dy*2 + 8) & 0x0F)<<4);
}
}})();
require("Storage").write("geissclk.0.map",map);
E.showMessage("Precomputing\nmaps\n\nPlease wait...\n1 / 5");
// ripple out
(function() { "ram"; var n = 0; for (var y=0;y<H;y++) {
for (var x=0;x<W;x++) {
var dx = x-(W/2);
var dy = y-(H/2);
var d = Math.sqrt(dx*dx + dy*dy);
var s = -2 + Math.sin(d*0.5)/2;
dx = dx*s/d;
dy = dy*s/d;
map[n++] = ((dx*3 + 8) & 0x0F) | (((dy*3 + 8) & 0x0F)<<4);
}
}})();
require("Storage").write("geissclk.1.map",map);
E.showMessage("Precomputing\nmaps\n\nPlease wait...\n2 / 5");
// twisty outwards
(function() { "ram"; var n = 0; for (var y=0;y<H;y++) {
for (var x=0;x<W;x++) {
var dx = x-(W/2);
var dy = y-(H/2);
var d = Math.sqrt(dx*dx + dy*dy);
dx = (-dx/d) + (((y&7)>3)?0.5:-0.5);
dy = (-dy/d) + (((x&7)>3)?0.5:-0.5);
map[n++] = ((dx*3 + 8) & 0x0F) | (((dy*3 + 8) & 0x0F)<<4);
}
}})()
require("Storage").write("geissclk.2.map",map);
E.showMessage("Precomputing\nmaps\n\nPlease wait...\n3 / 5");
// spiral
(function() { "ram"; var n = 0; for (var y=0;y<H;y++) {
for (var x=0;x<W;x++) {
var dx = x-(W/2);
var dy = y-(H/2);
var d = Math.sqrt(dx*dx + dy*dy);
var cx = (2*dy-dx)/(2*d);
var cy = (-2*dx-dy)/(2*d);
map[n++] = ((cx*3 + 8) & 0x0F) | (((cy*3 + 8) & 0x0F)<<4);
}
}})();
require("Storage").write("geissclk.3.map",map);
E.showMessage("Precomputing\nmaps\n\nPlease wait...\n4 / 5");
// blur down
(function() { "ram"; var n=0; for (var y=0;y<H;y++) {
for (var x=0;x<W;x++) {
map[n++] = 136 - 6*16 + (y&1)*8-4;
}
}})()
require("Storage").write("geissclk.4.map",map);
E.showMessage("Precomputing\nmaps\n\nPlease wait...\n5 / 5");
// twisty
(function() { "ram"; var n=0; for (var y=0;y<H;y++) {
for (var x=0;x<W;x++) {
dx = Math.sin(y*0.2);
dy = Math.cos(x*0.2);
map[n++] = ((dx*6 + 8) & 0x0F) | (((dy*6 + 8) & 0x0F)<<4);
}
}})()
require("Storage").write("geissclk.5.map",map)
E.showMessage("Finished!");

View File

@ -8,3 +8,4 @@
Ensure 'on' is always supplied for translations
0.07: Improve handling of non-ASCII characters (fix #469)
0.08: Added Mavigation units and en_NAV
0.09: Added New Zealand en_NZ

View File

@ -245,6 +245,24 @@ var locales = {
day: "söndag,måndag,tisdag,onsdag,torsdag,fredag,lördag",
trans: { yes: "ja", Yes: "Ja", no: "nej", No: "Nej", ok: "ok", on: "on", off: "off" }
},
"en_NZ": {
lang: "en_NZ",
decimal_point: ".",
thousands_sep: ",",
currency_symbol: "$",
int_curr_symbol: "NZD",
speed: "kph",
distance: { 0: "m", 1: "km" },
temperature: "°C",
ampm: { 0: "am", 1: "pm" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%A, %B %d, %Y", "1": "%d/%m/%y" }, // Sunday, 1 March 2020 // 1/3/20
abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
month: "January,February,March,April,May,June,July,August,September,October,November,December",
abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
// No translation for english...
},
"en_AU": {
lang: "en_AU",
decimal_point: ".",

View File

@ -5,3 +5,4 @@
0.05: Add setting to turn vibrate on/off.
0.06: Tweaks to vibration settings.
0.07: Switch to BTN1 for Max toggle and reset function.
1.00: New features. Added waypoints file and distance to selected waypoint display. Added integration with GPS Setup module to switch GPS to low power mode when screen off. Save display settings and restore when app restarted.

View File

@ -1,18 +1,143 @@
Displays the GPS speed and altitude. One is displayed on the watch face using the largest possible characters depending on the number of digits. The other is in a smaller characters below that. Both are always visible. You can display the current or maximum observed speed/altitude values. Current time is always displayed.
# GPS Speed, Altimeter and Distance to Waypoint
Display Tap : Swaps the displays. You can have either speed or altitude on the large primary display.
You can switch between two display modes. One showing speed and altitude (A) and one showing speed and distance to waypoint (D).
BTN1 : Short press < 2 secs toggles the displays between showing the current speed/alt values or the maximum values recorded.
Within each display mode one figure is displayed on the watch face using the largest possible characters depending on the number of digits. The other is in a smaller characters below that. Both are always visible. You can display the current or maximum observed speed/altitude values. Current time is always displayed.
The waypoints list is the same as that used with the [GPS Navigation](https://banglejs.com/apps/#gps%20navigation) app so the same set of waypoints can be used across both apps. Refer to that app for waypoint file information.
## Buttons and Controls
BTN3 : Swaps the modes between Speed+[A]ltitude or Speed+[D]istance.
### [A]ltitude mode
BTN1 : Short press < 2 secs toggles the displays between showing the current speed/alt values or the maximum speed/alt values recorded.
BTN1 : Long press > 2 secs resets the recorded maximum values.
App Settings : Select the desired display units. Speed can be as per the default locale, kph, knots, mph or m/s. Altitude can be feet or metres. Select one of three colour schemes. Colours, high contrast (all white on black) or night ( all red on black ). Vibration can be used to indicate when a fix is lost or gained. One buzz for a lost fix and a double buzz when a fix is found.
### [D]istance mode
![](screen1.png)
![](screen2.png)
![](screen3.png)
![](screen4.png)
BTN1 : Select next waypoint. Last fix distance from selected waypoint is displayed.
### Both modes
BTN2 : Disables/Restores power saving timeout. Locks the screen on to enable reading for longer periods but uses maximum battery drain. Red LED (dot) at top of screen when screen is locked on. Press again to restore power saving timeouts.
BTN3 : Long press exit and return to watch.
BTN4 : Left Display Tap : Swaps which figure is in the large display. You can have either speed or [A]ltitude/[D]istance on the large primary display.
## App Settings
Select the desired display units. Speed can be as per the default locale, kph, knots, mph or m/s. Distance can be km, miles or nautical miles. Altitude can be feet or metres. Select one of three colour schemes. Default (three colours), high contrast (all white on black) or night ( all red on black ).
## Loss of fix
When the GPS obtains a fix the number of satellites is displayed as 'Sats:nn'. When unable to obtain a fix then the last known fix is used and the age of that fix in seconds is displayed as 'Age:nn'. Seeing 'Sats' or 'Age' indicates whether the GPS has a current fix or not.
## Screens
Speed and Altitude:<br>
![](screen1.png)<p>
Left tap swaps displays:<br>
![](screen2.png)<p>
Distance to waypoint DeltaW:<br>
![](screen5.png)<p>
MAX Values instead:<br>
![](screen3.png)<p>
Settings:<br>
![](screen4.png)<p>
## Power Saving
The The GPS Adv Sport app obeys the watch screen off timeouts as a power saving measure. Restore the screen as per any of the colck/watch apps. Use BTN2 to lock the screen on but doing this will use more battery.
This app will work quite happily on its own but will use the [GPS Setup App](https://banglejs.com/apps/#gps%20setup) if it is installed. You may choose to use the GPS Setup App to gain significantly longer battery life while the GPS is on. Please read the Low Power GPS Setup App Readme to understand what this does.
When using the GPS Setup App this app switches the GPS to SuperE (default) mode while the display is lit and showing fix information. This ensures that that fixes are updated every second or so. 10 seconds after the display is blanked by the watch this app will switch the GPS to PSMOO mode and will only attempt to get a fix every two minutes. This improves power saving while the display is off and the delay gives an opportunity to restore the display before the GPS power mode is switched.
The MAX values continue to be collected with the display off so may appear a little odd after the intermittent fixes of the low power mode.
## Waypoints
Waypoints are used in [D]istance mode. Create a file waypoints.json and write to storage on the Bangle.js using the IDE. The first 6 characters of the name are displayed in Speed+[D]istance mode.
The [GPS Navigation](https://banglejs.com/apps/#gps%20navigation) app in the App Loader has a really nice waypoints file editor. (Must be connected to your Bangle.JS and then click on the Download icon.)
Sample waypoints.json (My sailing waypoints)
<pre>
[
{
"name":"NONE"
},
{
"name":"Omori",
"lat":-38.9058670,
"lon":175.7613350
},
{
"name":"DeltaW",
"lat":-38.9438550,
"lon":175.7676930
},
{
"name":"DeltaE",
"lat":-38.9395240,
"lon":175.7814420
},
{
"name":"BtClub",
"lat":-38.9446020,
"lon":175.8475720
},
{
"name":"Hapua",
"lat":-38.8177750,
"lon":175.8088720
},
{
"name":"Nook",
"lat":-38.7848090,
"lon":175.7839440
},
{
"name":"ChryBy",
"lat":-38.7975050,
"lon":175.7551960
},
{
"name":"Waiha",
"lat":-38.7219630,
"lon":175.7481520
},
{
"name":"KwaKwa",
"lat":-38.6632310,
"lon":175.8670320
},
{
"name":"Hatepe",
"lat":-38.8547420,
"lon":176.0089124
},
{
"name":"Kinloc",
"lat":-38.6614442,
"lon":175.9161607
}
]
</pre>
## Comments and Feedback
Developed for my use in sailing, cycling and motorcycling. If you find this software useful or have feedback drop me a line mike[at]kereru.com. Enjoy!
( Many thanks to Gordon Williams. Awesome job. )
## Thanks
Many thanks to Gordon Williams. Awesome job.
Special thanks also to @jeffmer, for the [GPS Navigation](https://banglejs.com/apps/#gps%20navigation) app and @hughbarney for the Low power GPS code development.

View File

@ -1 +1 @@
require("heatshrink").decompress(atob("m02xH+AH4AJlgAMGWQ4lEw1Wq2BAAgHBG8QhFq+C1nXABGswQ4GGjhkBGJIAHOQI2ZDIcyGaQ3EmQ3WNAiaKABusNyoUDNCxuGGySdDNDBuGUoY0e2etAAWzGzoOCGheJxNlAA2J1o2LGprTNGRAAFbZw0LqwZI1pkGAAgJDUxdWGxTULFAmJFJGzURjaET6Q0DGZKYIrqjRT5Q0EGZwpEUZZqPaYaRMGg6LINhBJKNK40JAAI1Iq6fJGjDrIUQoVCwRqJDhA0OXYQRGwRsEAgWsNTCeIDYTwG1g1GqygJNROsq0ymVWq7TI2ZRJUQg1JUARkMAAg0FDhY1GDAxOKQwgAEKI6IKKAQ1KeAQ1IJ4VXAog1gC4Q1ImQVBAwYFBmQ1K1o1fMoQ1ORIQ1Ua5ahD1uzrqnEULo1L1gVBAAusGrDxHC4NlEY4aDAAZQGDhiHCGpZOJNodWmUyqxpIRBY1GQw7wCURAAPKIWtXhI1EwSFJNhIAMNQSgHwQ1EGwVXKBJsWDJSgENgjyKGyg0CNQ/XNQo1DwIRGbIS+HABYWLwI1GGwVWKhZtQChigGNhg2TCRhqIGwcy1g2YCBmsmQ0INgajIYgY1PdRKfCGpCjMG4ShNBxSfKGwyjIADOsGho1DbRI0YagQ1MG0Y0RGwjbLACLTDGh42FqxuY1lWGig2FmRuWwKdDGiZuHG6WBNC42JHAWCVBWswQyEGjQ3IHAJyBAAgHBCAwzbG5QAMGb44SGUgAkA"))
require("heatshrink").decompress(atob("mEwxH+AH4A/AE+sFtoABF12swItsF9QuFR4IwmFwwvnFw4vCGEYuIF4JgjFxIvkFxQvCGBfOAAQvqFwYwRFxYvDGBIvUFxgv/F6IuNF4n+0nB4TvXFxwvF4XBAALlPF7ZfBGC4uPF4rABGAYAGTQwvad4YwKFzYvIGBQvfFwgAE3Qvt4IvEFzgvCLxO7Lx7vULzIzTFwIvgGZheFRAiNRGSQvpGYouesYAGmQAKq3CE4PIC4wviq2eFwPCroveCRSGEC6Qv0DAwRLcoouWC4VdVYQXkr1eAgVdAoIABroNEB4gHHC5QvHwQSDAAOCA74vH1uICQIABxGtA74vIAEwv/F/4vXAH4A/AHY"))

View File

@ -1,110 +1,100 @@
/*
Speed and Altitude [speedalt]
Ver : 0.07
Mike Bennett mike[at]kereru.com
1.16 : Use new GPS settings module
*/
const dbg = 0;
var v = '1.20';
var buf = Graphics.createArrayBuffer(240,160,2,{msb:true});
// Load fonts
require("Font7x11Numeric7Seg").add(Graphics);
/*
var mainmenu = {
"" : { "title" : "-- Units --" },
"default" : function() { setUnits(0,''); },
"Kph (spd)" : function() { setUnits(1,'kph'); },
"Knots (spd)" : function() { setUnits(1.852,'knots'); },
"Mph (spd)" : function() { setUnits(1.60934,'mph'); },
"m/s (spd)" : function() { setUnits(3.6,'m/s'); },
"Meters (alt)" : function() { setUnitsAlt(1,'m'); },
"Feet (alt)" : function() { setUnitsAlt(0.3048,'feet'); },
"Exit" : function() { exitMenu(); }, // remove the menu and restore
};
*/
var lastFix = {fix:0,satellites:0};
var showSpeed = 1; // 1 = Speed in primary display. 0 = alt in primary
var lf = {fix:0,satellites:0};
var showMax = 0; // 1 = display the max values. 0 = display the cur fix
var maxPress = 0; // Time max button pressed. Used to calculate short or long press.
var pwrSav = 1; // 1 = default power saving with watch screen off and GPS to PMOO mode. 0 = screen kept on.
var canDraw = 1;
var lastBuzz = 0; // What sort of buzz was last performed. 0 = no fix, 1 = fix.
var timerBuzz2 = 0; // ID of timer for fix second buzz
var time = ''; // Last time string displayed. Re displayed in background colour to remove before drawing new time.
var tmrLP; // Timer for delay in switching to low power after screen turns off
var max = {};
max.spd = 0;
max.alt = 0;
var emulator = 0;
if (process.env.BOARD=="EMSCRIPTEN") emulator = 1; // 1 = running in emulator. Supplies test values;
var emulator = (process.env.BOARD=="EMSCRIPTEN")?1:0; // 1 = running in emulator. Supplies test values;
var wp = {}; // Waypoint to use for distance from cur position.
function nxtWp(inc){
if (cfg.modeA) return;
cfg.wp+=inc;
loadWp();
}
function loadWp() {
var w = require("Storage").readJSON('waypoints.json')||[{name:"NONE"}];
if (cfg.wp>=w.length) cfg.wp=0;
if (cfg.wp<0) cfg.wp = w.length-1;
savSettings();
wp = w[cfg.wp];
}
function radians(a) {
return a*Math.PI/180;
}
function distance(a,b){
var x = radians(a.lon-b.lon) * Math.cos(radians((a.lat+b.lat)/2));
var y = radians(b.lat-a.lat);
// Distance in selected units
var d = Math.sqrt(x*x + y*y) * 6371000;
d = (d/parseFloat(cfg.dist)).toFixed(2);
if ( d >= 100 ) d = parseFloat(d).toFixed(1);
if ( d >= 1000 ) d = parseFloat(d).toFixed(0);
return d;
}
function drawFix(dat) {
function drawFix(speed,units,sats,alt,alt_units) {
if (!canDraw) return;
buf.clear();
var val = '';
var v = '';
var u='';
// Primary Display
val = speed.toString();
if ( !showSpeed ) val = alt.toString();
v = (cfg.primSpd)?dat.speed.toString():dat.alt.toString();
// Primary Units
u = settings.spd_unit;
if ( !showSpeed ) u = alt_units;
u = (cfg.primSpd)?cfg.spd_unit:dat.alt_units;
drawPrimary(val,u);
drawPrimary(v,u);
// Secondary Display
val = alt.toString();
if ( !showSpeed ) val = speed.toString();
v = (cfg.primSpd)?dat.alt.toString():dat.speed.toString();
// Secondary Units
u = alt_units;
if ( !showSpeed ) u = settings.spd_unit;
u = (cfg.primSpd)?dat.alt_units:cfg.spd_unit;
drawSecondary(val,u);
drawSecondary(v,u);
// Time
drawTime();
// Waypoint name
drawWP();
//Sats
drawSats(sats);
if ( dat.age > 10 ) {
if ( dat.age > 90 ) dat.age = '>90';
drawSats('Age:'+dat.age);
}
else drawSats('Sats:'+dat.sats);
g.reset();
g.drawImage(img,0,40);
// g.flip();
}
function drawNoFix(sats) {
if (!canDraw) return;
var u;
buf.clear();
buf.setFontAlign(0,0);
buf.setColor(3);
buf.setFontVector(25);
buf.drawString("Waiting for GPS",120,56);
// Time
drawTime();
//Sats
drawSats(sats);
g.reset();
g.drawImage(img,0,40);
// g.flip();
}
@ -113,15 +103,16 @@ function drawPrimary(n,u) {
// Primary Display
var s=40; // Font size
if ( n.length <= 7 ) s=48;
if ( n.length <= 6 ) s=55;
if ( n.length <= 5 ) s=68;
if ( n.length <= 4 ) s=85;
if ( n.length <= 3 ) s=110;
var l=n.length;
if ( l <= 7 ) s=48;
if ( l <= 6 ) s=55;
if ( l <= 5 ) s=68;
if ( l <= 4 ) s=85;
if ( l <= 3 ) s=110;
buf.setFontAlign(0,-1); //Centre
buf.setColor(1);
buf.setFontVector(s);
buf.drawString(n,110,0);
@ -135,11 +126,12 @@ function drawPrimary(n,u) {
function drawSecondary(n,u) {
var s=180; // units X position
if ( n.length <= 5 ) s=155;
if ( n.length <= 4 ) s=125;
if ( n.length <= 3 ) s=100;
if ( n.length <= 2 ) s=65;
if ( n.length <= 1 ) s=35;
var l=n.length;
if ( l <= 5 ) s=155;
if ( l <= 4 ) s=125;
if ( l <= 3 ) s=100;
if ( l <= 2 ) s=65;
if ( l <= 1 ) s=35;
buf.setFontAlign(-1,1); //left, bottom
buf.setColor(1);
@ -153,7 +145,6 @@ function drawSecondary(n,u) {
buf.drawString(u,s,135);
}
function drawTime() {
var x = 0;
var y = 160;
@ -168,181 +159,225 @@ function drawTime() {
buf.drawString(time,x,y);
}
function drawWP() {
var nm = wp.name;
if ( nm == undefined || nm == 'NONE' || cfg.modeA ) nm = '';
buf.setFontAlign(-1,1); //left, bottom
buf.setColor(2);
buf.setFontVector(20);
buf.drawString(nm.substring(0,6),77,160);
}
function drawSats(sats) {
buf.setFontAlign(1,1); //right, bottom
buf.setColor(3);
buf.setFont("6x8", 2);
if ( showMax ) {
buf.setColor(2);
buf.drawString("MAX",240,160);
buf.setFontAlign(1,1); //right, bottom
buf.drawString(sats,240,160);
buf.setFontVector(20);
buf.setColor(2);
if ( cfg.modeA ) buf.drawString("A",240,140);
else buf.drawString("D",240,140);
if ( showMax && cfg.modeA ) {
buf.setFontAlign(0,1); //centre, bottom
buf.drawString("MAX",120,164);
}
else buf.drawString("Sats:"+sats,240,160);
}
function onGPS(fix) {
lastFix = fix;
if ( emulator ) {
fix.fix = 1;
fix.speed = 10;
fix.alt = 354;
fix.lat = -38.92;
fix.lon = 175.7613350;
fix.course = 245;
fix.satellites = 12;
fix.time = new Date();
}
var m;
if (fix.fix || emulator) {
doBuzz(1);
var sp = '---';
var al = '---';
var di = '---';
var age = '---';
//==== Speed ====
if ( settings.spd == 0 ) {
var strSpeed = require("locale").speed(fix.speed);
m = strSpeed.match(/([0-9,\.]+)(.*)/); // regex splits numbers from units
if (fix.fix) lf = fix;
if (lf.fix) {
if ( emulator ) {
speed = '125'; //testing only
settings.spd_unit = 'kph';
}
else {
speed = m[1];
settings.spd_unit = m[2];
}
}
// Calculate for selected units
else {
speed = fix.speed;
if ( emulator ) speed = '100';
speed = Math.round(parseFloat(speed)/parseFloat(settings.spd),0);
// Speed
if ( cfg.spd == 0 ) {
m = require("locale").speed(lf.speed).match(/([0-9,\.]+)(.*)/); // regex splits numbers from units
sp = parseFloat(m[1]);
cfg.spd_unit = m[2];
}
else sp = parseFloat(lf.speed)/parseFloat(cfg.spd); // Calculate for selected units
// ==== Altitude ====
alt = fix.alt;
if ( emulator ) alt = '360';
alt = Math.round(parseFloat(alt)/parseFloat(settings.alt),0);
if ( sp < 10 ) sp = sp.toFixed(1);
else sp = Math.round(sp);
if (parseFloat(sp) > parseFloat(max.spd) ) max.spd = parseFloat(sp);
// Record max values
if (parseFloat(speed) > parseFloat(max.spd) ) max.spd = parseFloat(speed);
if (parseFloat(alt) > parseFloat(max.alt) ) max.alt = parseFloat(alt);
// Altitude
al = lf.alt;
al = Math.round(parseFloat(al)/parseFloat(cfg.alt));
if (parseFloat(al) > parseFloat(max.alt) ) max.alt = parseFloat(al);
if ( showMax ) drawFix(max.spd,settings.spd_unit,fix.satellites,max.alt,settings.alt_unit);
else drawFix(speed,settings.spd_unit,fix.satellites,alt,settings.alt_unit);
// Distance to waypoint
di = distance(lf,wp);
if (isNaN(di)) di = 0;
} else {
doBuzz(0);
drawNoFix(fix.satellites);
// Age of last fix (secs)
age = Math.max(0,Math.round(getTime())-(lf.time.getTime()/1000));
}
}
// Vibrate watch when fix lost or gained.
function doBuzz(hasFix) {
// nothing to do
if ( lastBuzz === hasFix || !settings.buzz ) {
return;
if ( cfg.modeA ) {
if ( showMax )
drawFix({
speed:max.spd,
sats:lf.satellites,
alt:max.alt,
alt_units:cfg.alt_unit,
age:age,
fix:lf.fix
}); // Speed and alt maximums
else
drawFix({
speed:sp,
sats:lf.satellites,
alt:al,
alt_units:cfg.alt_unit,
age:age,
fix:lf.fix
}); // Show speed/altitude
}
else {
// Show speed/distance
if ( di <= 0 )
drawFix({
speed:sp,
sats:lf.satellites,
alt:'',
alt_units:'',
age:age,
fix:lf.fix
}); // No WP selected
else
drawFix({
speed:sp,
sats:lf.satellites,
alt:di,
alt_units:cfg.dist_unit,
age:age,
fix:lf.fix
});
}
// fix gained - double buzz
if ( !lastBuzz && hasFix ) {
if ( dbg ) print('Fix');
lastBuzz = 1;
Bangle.buzz();
timerBuzz2 = setInterval(doBuzz2, 600); // Trigger a second buzz
return;
}
// fix lost - single buzz
if ( lastBuzz && !hasFix ) {
if ( dbg ) print('Fix lost');
lastBuzz = 0;
Bangle.buzz();
return;
}
}
// Second buzz
function doBuzz2() {
if ( dbg ) print('Buzz2');
clearInterval(timerBuzz2);
Bangle.buzz();
}
function toggleDisplay() {
showSpeed = !showSpeed;
onGPS(lastFix); // Back to Speed display
}
function toggleMax() {
// if ( inMenu ) return;
showMax = !showMax;
onGPS(lastFix); // Back to Speed display
}
function setButtons(){
// Show launcher when middle button pressed
setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"});
// Spd+Dist : Select next waypoint
setWatch(function(e) {
var dur = e.time - e.lastTime;
if ( cfg.modeA ) {
// Spd+Alt mode - Switch between fix and MAX
if ( dur < 2 ) showMax = !showMax; // Short press toggle fix/max display
else { max.spd = 0; max.alt = 0; } // Long press resets max values.
}
else nxtWp(1); // Spd+Dist mode - Select next waypoint
onGPS(lf);
}, BTN1, { edge:"falling",repeat:true});
// Switch between fix and max display on short press or reset max values on long press
setWatch(maxPressed, BTN1,{repeat:true,edge:"rising"});
setWatch(maxReleased, BTN1,{repeat:true,edge:"falling"});
// Power saving on/off
setWatch(function(e){
pwrSav=!pwrSav;
if ( pwrSav ) {
LED1.reset();
var s = require('Storage').readJSON('setting.json',1)||{};
var t = s.timeout||10;
Bangle.setLCDTimeout(t);
}
else {
Bangle.setLCDTimeout(0);
Bangle.setLCDPower(1);
LED1.set();
}
}, BTN2, {repeat:true,edge:"falling"});
// Touch screen to toggle display
setWatch(toggleDisplay, BTN4, {repeat:true,edge:"falling"});
setWatch(toggleDisplay, BTN5, {repeat:true,edge:"falling"});
// Toggle between alt or dist
setWatch(function(e){
cfg.modeA = !cfg.modeA;
savSettings();
onGPS(lf);
}, BTN3, {repeat:true,edge:"falling"});
// Touch left screen to toggle display
setWatch(function(e){
cfg.primSpd = !cfg.primSpd;
savSettings();
onGPS(lf); // Update display
}, BTN4, {repeat:true,edge:"falling"});
}
function maxPressed() {
maxPress = getTime();
}
function maxReleased() {
var dur = getTime()-maxPress;
if ( dur < 2 ) toggleMax(); // Short press toggle fix/max display
else {
max.spd = 0; // Long press resets max values.
max.alt = 0;
onGPS(lastFix); // redraw display
}
}
function updateClock() {
if ( dbg ) print('Updating clock');
if (!canDraw) return;
drawTime();
g.reset();
g.drawImage(img,0,40);
// g.flip();
// Something different to display in the emulator
if ( emulator ) {
max.spd++;
max.alt++;
}
if ( emulator ) {max.spd++;max.alt++;}
}
function startDraw(){
canDraw=true;
setLpMode('SuperE'); // off
g.clear();
Bangle.drawWidgets();
onGPS(lastFix); // draw app screen
onGPS(lf); // draw app screen
}
function stopDraw() {
canDraw=false;
if (!tmrLP) tmrLP=setInterval(function () {if (lf.fix) setLpMode('PSMOO');}, 10000); //Drop to low power in 10 secs. Keep lp mode off until we have a first fix.
}
// ===== Main Prog =====
function savSettings() {
require("Storage").write('speedalt.json',cfg);
}
function setLpMode(m) {
if (tmrLP) {clearInterval(tmrLP);tmrLP = false;} // Stop any scheduled drop to low power
if ( !gpssetup ) return;
gpssetup.setPowerMode({power_mode:m})
}
// =Main Prog
// Read settings.
let settings = require('Storage').readJSON('speedalt.json',1)||{};
let cfg = require('Storage').readJSON('speedalt.json',1)||{};
settings.spd = settings.spd||0; // Multiplier for speed unit conversions. 0 = use the locale values for speed
settings.spd_unit = settings.spd_unit||''; // Displayed speed unit
settings.alt = settings.alt||0.3048;// Multiplier for altitude unit conversions.
settings.alt_unit = settings.alt_unit||'feet'; // Displayed altitude units
settings.colour = settings.colour||0; // Colour scheme.
settings.buzz = settings.buzz||0; // Buzz when fix lost or gained.
cfg.spd = cfg.spd||0; // Multiplier for speed unit conversions. 0 = use the locale values for speed
cfg.spd_unit = cfg.spd_unit||''; // Displayed speed unit
cfg.alt = cfg.alt||0.3048;// Multiplier for altitude unit conversions.
cfg.alt_unit = cfg.alt_unit||'feet'; // Displayed altitude units
cfg.dist = cfg.dist||1000;// Multiplier for distnce unit conversions.
cfg.dist_unit = cfg.dist_unit||'km'; // Displayed altitude units
cfg.colour = cfg.colour||0; // Colour scheme.
cfg.wp = cfg.wp||0; // Last selected waypoint for dist
cfg.modeA = cfg.modeA||0; // 0 = [D], 1 = [A]
cfg.primSpd = cfg.primSpd||0; // 1 = Spd in primary, 0 = Spd in secondary
loadWp();
/*
Colour Pallet Idx
@ -359,50 +394,43 @@ var img = {
palette:new Uint16Array([0,0x4FE0,0xEFE0,0x07DB])
};
if ( settings.colour == 1 ) img.palette = new Uint16Array([0,0xFFFF,0xFFFF,0xFFFF]);
if ( settings.colour == 2 ) img.palette = new Uint16Array([0,0xFF800,0xF800,0xF800]);
// Find speed unit if using locale speed
if ( settings.spd == 0 ) {
var strSpeed = require("locale").speed(1);
m = strSpeed.match(/([0-9,\.]+)(.*)/); // regex splits numbers from units
settings.spd_unit = m[2];
}
if ( cfg.colour == 1 ) img.palette = new Uint16Array([0,0xFFFF,0xFFF6,0xDFFF]);
if ( cfg.colour == 2 ) img.palette = new Uint16Array([0,0xFF800,0xFAE0,0xF813]);
var SCREENACCESS = {
withApp:true,
request:function(){
this.withApp=false;
stopDraw();
clearWatch();
},
release:function(){
this.withApp=true;
startDraw();
setButtons();
}
request:function(){this.withApp=false;stopDraw();},
release:function(){this.withApp=true;startDraw();}
};
Bangle.on('lcdPower',function(on) {
if (!SCREENACCESS.withApp) return;
if (on) {
startDraw();
} else {
stopDraw();
}
if (on) startDraw();
else stopDraw();
});
var gpssetup;
try {
gpssetup = require("gpssetup");
} catch(e) {
gpssetup = false;
}
// All set up. Lets go.
g.clear();
Bangle.setLCDBrightness(1);
Bangle.loadWidgets();
Bangle.drawWidgets();
onGPS(lf);
Bangle.setGPSPower(1);
onGPS(lastFix);
if ( gpssetup ) {
gpssetup.setPowerMode({power_mode:"SuperE"}).then(function() { Bangle.setGPSPower(1); });
}
else {
Bangle.setGPSPower(1);
}
Bangle.on('GPS', onGPS);
setButtons();
setInterval(updateClock, 30000);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
apps/speedalt/screen5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -19,6 +19,12 @@
writeSettings();
}
function setUnitsDist(d,u) {
settings.dist = d;
settings.dist_unit = u;
writeSettings();
}
function setColour(c) {
settings.colour = c;
writeSettings();
@ -27,13 +33,15 @@
const appMenu = {
'': {'title': 'GPS Speed Alt'},
'< Back': back,
'< Load GPS Adv Sport': ()=>{load('speedalt.app.js');},
'Units' : function() { E.showMenu(unitsMenu); },
'Colours' : function() { E.showMenu(colMenu); },
'Colours' : function() { E.showMenu(colMenu); }/*,
'Vibrate' : {
value : settings.buzz,
format : v => v?"On":"Off",
onchange : () => { settings.buzz = !settings.buzz; writeSettings(); }
}};
}*/
};
const unitsMenu = {
'': {'title': 'Units'},
@ -43,6 +51,9 @@
'Knots (spd)' : function() { setUnits(1.852,'knots'); },
'Mph (spd)' : function() { setUnits(1.60934,'mph'); },
'm/s (spd)' : function() { setUnits(3.6,'m/s'); },
'Km (dist)' : function() { setUnitsDist(1000,'km'); },
'Miles (dist)' : function() { setUnitsDist(1609.344,'miles'); },
'Nm (dist)' : function() { setUnitsDist(1852.001,'nm'); },
'Meters (alt)' : function() { setUnitsAlt(1,'m'); },
'Feet (alt)' : function() { setUnitsAlt(0.3048,'feet'); }
};