mirror of https://github.com/espruino/BangleApps
Merge pull request #1394 from nujw/master
New Features : VMG and Android display mirroring over BLEpull/1052/head^2^2
commit
777914871c
|
@ -10,3 +10,5 @@
|
|||
0.10: Add Kalman filter to smooth the speed and altitude values. Can be disabled in settings.
|
||||
1.06: Misc memory and screen optimisations.
|
||||
1.10: Adds Kalman filter.
|
||||
1.14: Add VMG and coordinates screens
|
||||
1.43: Adds mirroring of the watch face to an Android device. See README.md
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
// Add this script to DroidScript on an android device.
|
||||
// Uses the PuckJS plugin to provide mirroring of the GPS Adv Sports II Bangle app face onto an android device.
|
||||
|
||||
app.LoadPlugin("PuckJS");
|
||||
|
||||
|
||||
//Called when application is started.
|
||||
function OnStart() {
|
||||
|
||||
v = '1.49' // Version of this script
|
||||
requiredBangleVer = '1.46'; // Minimum speedalt2 version required on Bangle
|
||||
curBangleVer = '-.--'
|
||||
isStopped = true; // Data receive turned off
|
||||
lastData = new Date().getTime() / 1000; // Time of last data received
|
||||
addr = ''; // Address of last connection
|
||||
|
||||
// Mode = 0 // 0=SPD, 1=ALT, 2=DST, 3=VMG, 4=POSN, 5=TIME
|
||||
btnOff = '#175A63'
|
||||
btnOn = '#4285F4'
|
||||
col = new Array(['black'],['#64FF00'],['#FCFA00'],['#00E4FF']) // bg, main, units, wp - 0xFFFF,0x007F,0x0054,0x0054
|
||||
|
||||
// Connect to Bangle
|
||||
puck = app.CreatePuckJS();
|
||||
puck.SetOnConnect(onConnect); // Callback.
|
||||
puck.SetOnReceive(readResponse); // Callback to capture console output from app.
|
||||
puck.Scan("Bangle");
|
||||
setInterval(checkConnection,5000) // Periodic check for data timeout and attempt a reconnect
|
||||
|
||||
// Controls
|
||||
app.SetScreenMode("Full")
|
||||
|
||||
//Create a layout with objects vertically centered.
|
||||
layVert = app.CreateLayout("Linear", "VCenter,FillXY")
|
||||
layVert.SetPadding(0.02, 0.02, 0.02, 0.02);
|
||||
layVert.SetBackColor(col[0])
|
||||
|
||||
//Create a text label and add it to layout.
|
||||
val = app.CreateText('', -1, -1, "Html,Multiline") // main value
|
||||
val.SetTextSize(120)
|
||||
val.SetTextColor(col[1]) // green
|
||||
layVert.AddChild(val)
|
||||
|
||||
val2 = app.CreateText('') // minor value or waypoint name
|
||||
val2.SetTextSize(50)
|
||||
val2.SetTextColor(col[3]) // cyan
|
||||
layVert.AddChild(val2)
|
||||
|
||||
// Units and status text
|
||||
layHor = app.CreateLayout("Linear", "Horizontal")
|
||||
layHor.SetMargins(-1, -1, -1, 10, 'px')
|
||||
unit = app.CreateText('')
|
||||
unit.SetSize(200, -1, "px")
|
||||
unit.SetTextSize(32)
|
||||
unit.SetTextColor('#FCFA00') // yellow
|
||||
layHor.AddChild(unit)
|
||||
|
||||
// mode = app.CreateText( '' ,.3,-1,"Center" )
|
||||
mode = app.CreateText('', -1, -1)
|
||||
mode.SetSize(200, -1, "px")
|
||||
mode.SetTextSize(32)
|
||||
mode.SetTextColor('#FCFA00') // yellow
|
||||
layHor.AddChild(mode)
|
||||
|
||||
// sats = app.CreateText( '' ,.3,-1,"Right")
|
||||
sats = app.CreateText('', -1, -1, "FillXY,Bottom")
|
||||
sats.SetSize(200, -1, "px")
|
||||
sats.SetTextSize(20)
|
||||
sats.SetTextColor(col[3]) // cyan
|
||||
layHor.AddChild(sats)
|
||||
|
||||
layVert.AddChild(layHor)
|
||||
|
||||
// Buttons
|
||||
layBtn = app.CreateLayout("Linear", "Horizontal")
|
||||
|
||||
btnAbout = app.CreateButton("About");
|
||||
btnAbout.SetOnTouch(btn_OnAbout);
|
||||
btnAbout.SetBackColor(btnOff)
|
||||
layBtn.AddChild(btnAbout);
|
||||
|
||||
btnStart = app.CreateButton("Start");
|
||||
btnStart.SetOnTouch(btn_OnStart);
|
||||
btnStart.SetBackColor(btnOff)
|
||||
layBtn.AddChild(btnStart);
|
||||
|
||||
btnStop = app.CreateButton("Stop");
|
||||
btnStop.SetOnTouch(btn_OnStop);
|
||||
btnStop.SetBackColor(btnOff)
|
||||
layBtn.AddChild(btnStop);
|
||||
|
||||
btnScan = app.CreateButton("Scan");
|
||||
btnScan.SetOnTouch(btn_OnScan);
|
||||
btnScan.SetBackColor(btnOff)
|
||||
layBtn.AddChild(btnScan);
|
||||
|
||||
// Status 'LED'
|
||||
led = app.AddCanvas(layBtn, 0.1, 0.1, "FillXY,Bottom")
|
||||
|
||||
layVert.AddChild(layBtn)
|
||||
|
||||
//Add layout to app.
|
||||
app.AddLayout(layVert)
|
||||
|
||||
}
|
||||
|
||||
function readResponse(data) {
|
||||
if (data.substring(0, 1) != '{') return; // ignore non JSON
|
||||
btnStart.SetBackColor(btnOn)
|
||||
|
||||
lastData = new Date().getTime() / 1000; // Time of last data received
|
||||
|
||||
d = JSON.parse(data);
|
||||
|
||||
if ( ( d.id != 'speedalt2' ) || (parseFloat(d.v) < parseFloat(requiredBangleVer)) || (typeof(d.v) == 'undefined')) {
|
||||
btn_OnStop()
|
||||
app.Alert('The GPS Adv Sports II app on your Bangle must be at least version ' + requiredBangleVer, 'Bangle App Upgrade Required')
|
||||
return
|
||||
}
|
||||
|
||||
curBangleVer = d.v
|
||||
|
||||
if (parseFloat(v) < parseFloat(d.vd)) {
|
||||
btn_OnStop()
|
||||
app.Alert('This GPS Adv Sports II script must be at least version ' + d.vd, 'Droidscript script Upgrade Required')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
isStopped = false; // Flag that we are running and receiving data
|
||||
|
||||
// Flash blue 'led' indicator when data packet received.
|
||||
setLED(led,true,"#0051FF")
|
||||
setTimeout(function() {setLED(led,false,-1)}, 500)
|
||||
|
||||
if (d.m == 0) { // Speed ( dont need pos or time here )
|
||||
val.SetTextSize(120)
|
||||
val2.SetTextSize(50)
|
||||
|
||||
val.SetText(d.sp)
|
||||
val2.SetText('')
|
||||
unit.SetText(d.spd_unit)
|
||||
mode.SetText('SPD')
|
||||
sats.SetText(d.sats)
|
||||
}
|
||||
|
||||
if (d.m == 1) { // Alt
|
||||
val.SetTextSize(120)
|
||||
val2.SetTextSize(50)
|
||||
|
||||
val.SetText(d.al)
|
||||
val2.SetText('')
|
||||
unit.SetText(d.alt_unit)
|
||||
mode.SetText('ALT')
|
||||
sats.SetText(d.sats)
|
||||
}
|
||||
|
||||
if (d.m == 2) { // Dist
|
||||
val.SetTextSize(120)
|
||||
val2.SetTextSize(50)
|
||||
|
||||
val.SetText(d.di)
|
||||
val2.SetText(d.wp)
|
||||
unit.SetText(d.dist_unit)
|
||||
mode.SetText('DST')
|
||||
sats.SetText(d.sats)
|
||||
}
|
||||
|
||||
if (d.m == 3) { // VMG
|
||||
val.SetTextSize(120)
|
||||
val2.SetTextSize(50)
|
||||
|
||||
val.SetText(d.vmg)
|
||||
val2.SetText(d.wp)
|
||||
unit.SetText(d.spd_unit)
|
||||
mode.SetText('VMG')
|
||||
sats.SetText(d.sats)
|
||||
}
|
||||
|
||||
if (d.m == 4) { // POS
|
||||
val.SetTextSize(80)
|
||||
val2.SetTextSize(10)
|
||||
|
||||
txt = d.lat +
|
||||
' <font color='+col[2]+'><small><small>' +
|
||||
d.ns +
|
||||
"</small></small></font><br>" +
|
||||
d.lon +
|
||||
' <font color='+col[2]+'><small><small>' +
|
||||
d.ew +
|
||||
"</small></small></font>"
|
||||
|
||||
val.SetHtml(txt)
|
||||
val2.SetText('')
|
||||
unit.SetText('')
|
||||
mode.SetText('')
|
||||
sats.SetText(d.sats)
|
||||
}
|
||||
|
||||
if (d.m == 5) { // Time
|
||||
val.SetTextSize(90)
|
||||
val2.SetTextSize(10)
|
||||
|
||||
dt = new Date();
|
||||
|
||||
val.SetText(String(dt.getHours()).padStart(2, '0') + "\n" + String(dt.getMinutes()).padStart(2, '0'))
|
||||
val2.SetText('')
|
||||
unit.SetText('')
|
||||
mode.SetText('')
|
||||
sats.SetText(d.sats)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function setLED(canvas,on,colour) {
|
||||
if ( on ) {
|
||||
canvas.SetPaintColor(colour)
|
||||
canvas.DrawCircle(0.5, 0.5, 0.1)
|
||||
}
|
||||
else {
|
||||
canvas.Clear()
|
||||
}
|
||||
canvas.Update()
|
||||
}
|
||||
|
||||
function onConnect(name, address, bonded, rssi) {
|
||||
addr = address
|
||||
console.log( "Connected to " + address );
|
||||
btn_OnStart() // Once connect tell app to start sending updates
|
||||
}
|
||||
|
||||
// Periodic check for data timeout and attempt a reconnect
|
||||
function checkConnection() {
|
||||
if (isStopped) return
|
||||
if ( parseFloat(new Date().getTime() / 1000) - lastData > 30 ) {
|
||||
|
||||
console.log( "Reconnecting to : "+addr);
|
||||
|
||||
// Flash orange 'led' indicator for connection attempts.
|
||||
setLED(led,true,"#FC8A00")
|
||||
setTimeout(function() {setLED(led,false,-1)}, 500)
|
||||
puck.Connect(addr)
|
||||
}
|
||||
}
|
||||
|
||||
function btn_OnAbout() {
|
||||
app.ShowPopup("GPS Adv Sports II\nAndroid Mirror : "+v+"\nBangle.js : "+curBangleVer,"Long")
|
||||
}
|
||||
|
||||
function btn_OnStart() {
|
||||
btnStart.SetBackColor(btnOn)
|
||||
btnStop.SetBackColor(btnOff)
|
||||
puck.SendCode('btOn(1)\n') // Enable the data send
|
||||
isStopped = false
|
||||
}
|
||||
|
||||
function btn_OnStop() {
|
||||
btnStart.SetBackColor(btnOff)
|
||||
btnStop.SetBackColor(btnOn)
|
||||
puck.SendCode('btOn(0)\n') // Disable the data send
|
||||
isStopped = true
|
||||
val.SetText('')
|
||||
val2.SetText('')
|
||||
unit.SetText('')
|
||||
mode.SetText('')
|
||||
sats.SetText('')
|
||||
}
|
||||
|
||||
function btn_OnScan() {
|
||||
btnStart.SetBackColor(btnOff)
|
||||
btnStop.SetBackColor(btnOff)
|
||||
puck.Scan("Bangle");
|
||||
}
|
||||
|
|
@ -1,12 +1,6 @@
|
|||
# GPS Speed, Altimeter and Distance to Waypoint
|
||||
# GPS Speed, Altitude, Distance and VMG
|
||||
|
||||
What is the difference between **GPS Adventure Sports** and **GPS Adventure Sports II** ?
|
||||
|
||||
**GPS Adventure Sports** has 3 screens, each of which display different sets of information.
|
||||
|
||||
**GPS Adventure Sports II** has 5 screens, each of which displays just one of Speed, Altitude, Distance to waypoint, Position or Time.
|
||||
|
||||
In all other respect they perform the same functions.
|
||||
**GPS Adventure Sports II** has 6 screens, each of which displays just one of Speed, Altitude, Distance to waypoint, VMG to waypoint, Position or Time.
|
||||
|
||||
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.
|
||||
|
||||
|
@ -14,17 +8,17 @@ The waypoints list is the same as that used with the [GPS Navigation](https://ba
|
|||
|
||||
**BTN1** ( Speed and Altitude ) Short press < 2 secs toggles the display between last reading and maximum recorded. Long press > 2 secs resets the recorded maximum values.
|
||||
|
||||
**BTN1** ( Distance ) Select next waypoint. Last fix distance from selected waypoint is displayed.
|
||||
**BTN1** ( Distance and VMG ) Select next waypoint. Last fix distance from selected waypoint or speed towards is displayed.
|
||||
|
||||
**BTN2** : Disables/Restores power saving timeout. Locks the screen on and GPS in SuperE mode 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** : Cycles the screens between Speed, Altitude, Distance to waypoint, Position and Time
|
||||
**BTN3** : Cycles the screens between Speed, Altitude, Distance to waypoint, VMG to waypoint, Position and Time
|
||||
|
||||
**BTN3** : Long press exit and return to watch.
|
||||
|
||||
**Touch Screen** If the 'Touch' setting is ON then :
|
||||
|
||||
Swipe Left/Right cycles between the five screens.
|
||||
Swipe Left/Right cycles between the six screens.
|
||||
|
||||
Touch functions as BTN1 short press.
|
||||
|
||||
|
@ -51,9 +45,36 @@ When using the GPS Setup App this app switches the GPS to SuperE (default) mode
|
|||
|
||||
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.
|
||||
|
||||
## Velocity Made Good - VMG
|
||||
|
||||
This implementation of VMG is very simplistic and is simply the component of your current vector ( course and speed ) that is towards your selected waypoint. It is displayed as negative if you are moving away from the waypoint. For it to be displayed you must be moving and the GPS must be able to detemrine a course. If not it will display '---' as the VMG.
|
||||
|
||||
## Mirroring to Android
|
||||
|
||||
This feature is an optional extra to solve and enhance a specific requirement for me. While sailing the Bangle.js watch screen is very difficult to read in bright sunlight while wearing the polaroid prescription lenses that I require on the water. The solution is to mirror the Bangle.js screen to an android device with a daylight readable OLED screen that I keep in a clear waterproof case on the boat. Using this mirroring feature I can see the GPS Adv Sports II app easily at all times, either on my wrist or on the bigger android device while still having full control over the display via the watch buttons.
|
||||
|
||||
There is a caveat. While in use the watch GPS stays in SuperE mode in order to keep the android screen updates going which means a higher battery use on the Bangle.js.
|
||||
|
||||
How is this mirroring done?
|
||||
|
||||
Install Droidscript on your Android device. Must have BLE suport and the PuckJS plugin installed. The Droidscript script can be found in the BangleApps GIT repository : https://github.com/espruino/BangleApps/tree/master/apps/speedalt2
|
||||
|
||||
The Droidscript script file is called : **GPS Adv Sports II.js**
|
||||
|
||||
**Important Gotcha :** For the BLE comms to find and connect to the Bangle.js it must be paired with the Android device but **NOT** connected. The Bangle.js must have been set in the Bluetooth settings as connectable.
|
||||
|
||||
Start/Stop buttons tell the Bangle.js to start or stop sending BLE data packets to the Android device. While stopped the Bangle.js reverts to full power saving mode when the screen is asleep.
|
||||
|
||||
When runnig a blue 'led' will flash each time a data packet is recieved to refresh the android display.
|
||||
|
||||
An orange 'led' will flash for each reconnection attempt if no data is received for 30 seconds. It will keep trying to reconnect so you can restart the Bangle, run another Bangle app or temprarily turn off bluetooth. The android mirror display will automatically reconnect when the GPS Adv Sports II app is running on the Bangle again. ( Designed to leave the Android device running as the display mirror in a sealed case all day while retaining the ability to do other functions on the Bangle.js and returning to the GPS Speed Alt II app. )
|
||||
|
||||
Android Screen Mirroring:<br>
|
||||
<p>
|
||||
|
||||
## 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.
|
||||
Waypoints are used in Distance and VMG modes. 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.)
|
||||
|
||||
|
|
|
@ -2,8 +2,12 @@
|
|||
Speed and Altitude [speedalt2]
|
||||
Mike Bennett mike[at]kereru.com
|
||||
1.10 : add inverted colours
|
||||
1.14 : Add VMG screen
|
||||
1.34 : Add bluetooth data stream for Droidscript
|
||||
1.43 : Keep GPS in SuperE mode while using Droiscript screen mirroring
|
||||
*/
|
||||
var v = '1.10';
|
||||
var v = '1.46';
|
||||
var vDroid = '1.46'; // Required DroidScript program version
|
||||
|
||||
/*kalmanjs, Wouter Bulten, MIT, https://github.com/wouterbulten/kalmanjs */
|
||||
var KalmanFilter = (function () {
|
||||
|
@ -180,14 +184,10 @@ let LED = // LED as minimal and only definition (as instance / singleton)
|
|||
, toggle: function() { this.set( ! this.isOn); } // toggle the LED
|
||||
}, LED1 = LED; // LED1 as 'synonym' for LED
|
||||
|
||||
// Load fonts
|
||||
//require("Font7x11Numeric7Seg").add(Graphics);
|
||||
|
||||
var lf = {fix:0,satellites:0};
|
||||
var showMax = 0; // 1 = display the max values. 0 = display the cur fix
|
||||
var pwrSav = 1; // 1 = default power saving with watch screen off and GPS to PMOO mode. 0 = screen kept on.
|
||||
var canDraw = 1;
|
||||
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 maxSpd = 0;
|
||||
|
@ -195,6 +195,8 @@ var maxAlt = 0;
|
|||
var maxN = 0; // counter. Only start comparing for max after a certain number of fixes to allow kalman filter to have smoohed the data.
|
||||
|
||||
var emulator = (process.env.BOARD=="EMSCRIPTEN")?1:0; // 1 = running in emulator. Supplies test values;
|
||||
var bt = 0; // 0 = bluetooth data feed off. 1 = on
|
||||
var btLast = 0; // time of last bt transmit
|
||||
|
||||
var wp = {}; // Waypoint to use for distance from cur position.
|
||||
|
||||
|
@ -215,16 +217,27 @@ function radians(a) {
|
|||
return a*Math.PI/180;
|
||||
}
|
||||
|
||||
function degrees(a) {
|
||||
var d = a*180/Math.PI;
|
||||
return (d+360)%360;
|
||||
}
|
||||
|
||||
function bearing(a,b){
|
||||
var delta = radians(b.lon-a.lon);
|
||||
var alat = radians(a.lat);
|
||||
var blat = radians(b.lat);
|
||||
var y = Math.sin(delta) * Math.cos(blat);
|
||||
var x = Math.cos(alat)*Math.sin(blat) -
|
||||
Math.sin(alat)*Math.cos(blat)*Math.cos(delta);
|
||||
return Math.round(degrees(Math.atan2(y, x)));
|
||||
}
|
||||
|
||||
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
|
||||
// Distance in metres
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -328,8 +341,8 @@ function drawClock() {
|
|||
function drawWP(wp) {
|
||||
buf.setColor(3);
|
||||
buf.setFontAlign(0,1); //left, bottom
|
||||
buf.setFontVector(48);
|
||||
buf.drawString(wp,120,140);
|
||||
buf.setFontVector(40);
|
||||
buf.drawString(wp,120,132);
|
||||
}
|
||||
|
||||
function drawSats(sats) {
|
||||
|
@ -362,14 +375,18 @@ if ( emulator ) {
|
|||
var m;
|
||||
|
||||
var sp = '---';
|
||||
var al = '---';
|
||||
var di = '---';
|
||||
var age = '---';
|
||||
var al = sp;
|
||||
var di = sp;
|
||||
var brg = ''; // bearing
|
||||
var crs = ''; // course
|
||||
var age = sp;
|
||||
var lat = '---.--';
|
||||
var ns = '';
|
||||
var ew = '';
|
||||
var lon = '---.--';
|
||||
var sats = '---';
|
||||
var sats = sp;
|
||||
var vmg = sp;
|
||||
|
||||
|
||||
// Waypoint name
|
||||
var wpName = wp.name;
|
||||
|
@ -387,21 +404,33 @@ if ( emulator ) {
|
|||
lf.smoothed = 1;
|
||||
if ( maxN <= 15 ) maxN++;
|
||||
}
|
||||
|
||||
// Bearing to waypoint
|
||||
brg = bearing(lf,wp);
|
||||
|
||||
// Current course
|
||||
crs = lf.course;
|
||||
|
||||
// Relative angle to wp
|
||||
var a = Math.max(crs,brg) - Math.min(crs,brg);
|
||||
if ( a >= 180 ) a = 360 -a;
|
||||
|
||||
// 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
|
||||
sp = parseFloat(lf.speed)/parseFloat(cfg.spd); // Calculate for selected units
|
||||
|
||||
// vmg
|
||||
if ( a >= 90 ) vmg = sp * Math.cos(radians(180-a)) * -1; // moving away from WP
|
||||
else vmg = sp * Math.cos(radians(a)); // towards wp
|
||||
|
||||
if ( sp < 10 ) sp = sp.toFixed(1);
|
||||
else sp = Math.round(sp);
|
||||
if (isNaN(sp)) sp = '---';
|
||||
|
||||
if (parseFloat(sp) > parseFloat(maxSpd) && maxN > 15 ) maxSpd = sp;
|
||||
|
||||
if ( Math.abs(vmg) >= 0.05 && Math.abs(vmg) < 10 ) vmg = vmg.toFixed(1);
|
||||
else vmg = Math.round(vmg);
|
||||
if (isNaN(vmg)) vmg = '---';
|
||||
|
||||
// Altitude
|
||||
al = lf.alt;
|
||||
al = Math.round(parseFloat(al)/parseFloat(cfg.alt));
|
||||
|
@ -410,8 +439,11 @@ if ( emulator ) {
|
|||
|
||||
// Distance to waypoint
|
||||
di = distance(lf,wp);
|
||||
if (isNaN(di)) di = '--------';
|
||||
|
||||
di = (di/parseFloat(cfg.dist)).toFixed(2);
|
||||
if ( di >= 100 ) di = parseFloat(di).toFixed(1);
|
||||
if ( di >= 1000 ) di = parseFloat(di).toFixed(0);
|
||||
if (isNaN(di)) di = '------';
|
||||
|
||||
// Age of last fix (secs)
|
||||
age = Math.max(0,Math.round(getTime())-(lf.time.getTime()/1000));
|
||||
|
||||
|
@ -433,9 +465,30 @@ if ( emulator ) {
|
|||
|
||||
}
|
||||
|
||||
// Bluetooth send data
|
||||
btSend({
|
||||
id:'speedalt2',
|
||||
v:v,
|
||||
vd:vDroid,
|
||||
m:cfg.modeA,
|
||||
spd_unit:cfg.spd_unit,
|
||||
alt_unit:cfg.alt_unit,
|
||||
dist_unit:cfg.dist_unit,
|
||||
wp:wpName,
|
||||
sp:sp,
|
||||
al:al,
|
||||
di:di,
|
||||
sats:sats,
|
||||
vmg:vmg,
|
||||
lat:lat,
|
||||
lon:lon,
|
||||
ns:ns,
|
||||
ew:ew
|
||||
});
|
||||
|
||||
if ( cfg.modeA == 0 ) {
|
||||
// Speed
|
||||
if ( showMax )
|
||||
if ( showMax ) {
|
||||
drawScrn({
|
||||
val:maxSpd,
|
||||
unit:cfg.spd_unit,
|
||||
|
@ -444,7 +497,8 @@ if ( emulator ) {
|
|||
max:'MAX',
|
||||
wp:''
|
||||
}); // Speed maximums
|
||||
else
|
||||
}
|
||||
else {
|
||||
drawScrn({
|
||||
val:sp,
|
||||
unit:cfg.spd_unit,
|
||||
|
@ -453,11 +507,12 @@ if ( emulator ) {
|
|||
max:'SPD',
|
||||
wp:''
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if ( cfg.modeA == 1 ) {
|
||||
// Alt
|
||||
if ( showMax )
|
||||
if ( showMax ) {
|
||||
drawScrn({
|
||||
val:maxAlt,
|
||||
unit:cfg.alt_unit,
|
||||
|
@ -466,7 +521,8 @@ if ( emulator ) {
|
|||
max:'MAX',
|
||||
wp:''
|
||||
}); // Alt maximums
|
||||
else
|
||||
}
|
||||
else {
|
||||
drawScrn({
|
||||
val:al,
|
||||
unit:cfg.alt_unit,
|
||||
|
@ -475,6 +531,7 @@ if ( emulator ) {
|
|||
max:'ALT',
|
||||
wp:''
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if ( cfg.modeA == 2 ) {
|
||||
|
@ -490,6 +547,18 @@ if ( emulator ) {
|
|||
}
|
||||
|
||||
if ( cfg.modeA == 3 ) {
|
||||
// VMG
|
||||
drawScrn({
|
||||
val:vmg,
|
||||
unit:cfg.spd_unit,
|
||||
sats:sats,
|
||||
age:age,
|
||||
max:'VMG',
|
||||
wp:wpName
|
||||
});
|
||||
}
|
||||
|
||||
if ( cfg.modeA == 4 ) {
|
||||
// Position
|
||||
drawPosn({
|
||||
sats:sats,
|
||||
|
@ -501,7 +570,7 @@ if ( emulator ) {
|
|||
});
|
||||
}
|
||||
|
||||
if ( cfg.modeA == 4 ) {
|
||||
if ( cfg.modeA == 5 ) {
|
||||
// Large clock
|
||||
drawClock();
|
||||
}
|
||||
|
@ -510,14 +579,14 @@ if ( emulator ) {
|
|||
|
||||
function prevScrn() {
|
||||
cfg.modeA = cfg.modeA-1;
|
||||
if ( cfg.modeA < 0 ) cfg.modeA = 4;
|
||||
if ( cfg.modeA < 0 ) cfg.modeA = 5;
|
||||
savSettings();
|
||||
onGPS(lf);
|
||||
}
|
||||
|
||||
function nextScrn() {
|
||||
cfg.modeA = cfg.modeA+1;
|
||||
if ( cfg.modeA > 4 ) cfg.modeA = 0;
|
||||
if ( cfg.modeA > 5 ) cfg.modeA = 0;
|
||||
savSettings();
|
||||
onGPS(lf);
|
||||
}
|
||||
|
@ -529,14 +598,14 @@ function nextFunc(dur) {
|
|||
if ( dur < 2 ) showMax = !showMax; // Short press toggle fix/max display
|
||||
else { maxSpd = 0; maxAlt = 0; } // Long press resets max values.
|
||||
}
|
||||
else if ( cfg.modeA == 2) nxtWp(); // Dist mode - Select next waypoint
|
||||
else if ( cfg.modeA == 2 || cfg.modeA == 3) nxtWp(); // Dist or VMG mode - Select next waypoint
|
||||
onGPS(lf);
|
||||
}
|
||||
|
||||
|
||||
function updateClock() {
|
||||
if (!canDraw) return;
|
||||
if ( cfg.modeA != 4 ) return;
|
||||
if ( cfg.modeA != 5 ) return;
|
||||
drawClock();
|
||||
if ( emulator ) {maxSpd++;maxAlt++;}
|
||||
}
|
||||
|
@ -551,6 +620,7 @@ function startDraw(){
|
|||
|
||||
function stopDraw() {
|
||||
canDraw=false;
|
||||
if ( bt ) return; // If bt screen mirror to Droidscript in use then keep GPS in SuperE mode to keep screen updates going.
|
||||
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.
|
||||
}
|
||||
|
||||
|
@ -564,6 +634,20 @@ function setLpMode(m) {
|
|||
gpssetup.setPowerMode({power_mode:m});
|
||||
}
|
||||
|
||||
// == Droidscript bluetooth data
|
||||
|
||||
function btOn(b) {
|
||||
bt = b; // Turn data transmit on/off
|
||||
}
|
||||
|
||||
function btSend(dat) {
|
||||
if ( ! bt ) return; // bt transmit off
|
||||
var dur = getTime() - btLast;
|
||||
if ( dur < 1.0 ) return; // Don't need to transmit more than every 1.0 secs.
|
||||
btLast = getTime();
|
||||
console.log(JSON.stringify(dat)); // transmit the data
|
||||
}
|
||||
|
||||
// == Events
|
||||
|
||||
function setButtons(){
|
||||
|
@ -593,17 +677,6 @@ function setButtons(){
|
|||
setWatch(function(e){
|
||||
nextScrn();
|
||||
}, BTN3, {repeat:true,edge:"falling"});
|
||||
|
||||
/*
|
||||
// Touch screen same as BTN1 short
|
||||
setWatch(function(e){
|
||||
nextFunc(1); // Same as BTN1 short
|
||||
}, BTN4, {repeat:true,edge:"falling"});
|
||||
setWatch(function(e){
|
||||
nextFunc(1); // Same as BTN1 short
|
||||
}, BTN5, {repeat:true,edge:"falling"});
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
Bangle.on('lcdPower',function(on) {
|
||||
|
@ -621,40 +694,22 @@ Bangle.on('swipe',function(dir) {
|
|||
Bangle.on('touch', function(button){
|
||||
if ( ! cfg.touch ) return;
|
||||
nextFunc(0); // Same function as short BTN1
|
||||
/*
|
||||
switch(button){
|
||||
case 1: // BTN4
|
||||
console.log('BTN4');
|
||||
prevScrn();
|
||||
break;
|
||||
case 2: // BTN5
|
||||
console.log('BTN5');
|
||||
nextScrn();
|
||||
break;
|
||||
case 3:
|
||||
console.log('MDL');
|
||||
nextFunc(0); // Centre - same function as short BTN1
|
||||
break;
|
||||
}
|
||||
*/
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
// == Main Prog
|
||||
|
||||
// Read settings.
|
||||
let cfg = require('Storage').readJSON('speedalt2.json',1)||{};
|
||||
|
||||
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.spd = cfg.spd||1; // Multiplier for speed unit conversions. 0 = use the locale values for speed
|
||||
cfg.spd_unit = cfg.spd_unit||'kph'; // 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=Speed 1=Alt 2=Dist 3=Position 4=Clock
|
||||
cfg.modeA = cfg.modeA||0; // 0=Speed 1=Alt 2=Dist 3 = vmg 4=Position 5=Clock
|
||||
cfg.primSpd = cfg.primSpd||0; // 1 = Spd in primary, 0 = Spd in secondary
|
||||
|
||||
cfg.spdFilt = cfg.spdFilt==undefined?true:cfg.spdFilt;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "speedalt2",
|
||||
"name": "GPS Adventure Sports II",
|
||||
"shortName":"GPS Adv Sport II",
|
||||
"version":"1.10",
|
||||
"version":"1.46",
|
||||
"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.",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
|
@ -48,7 +48,7 @@
|
|||
const unitsMenu = {
|
||||
'': {'title': 'Units'},
|
||||
'< Back': function() { E.showMenu(appMenu); },
|
||||
'default (spd)' : function() { setUnits(0,''); },
|
||||
// 'default (spd)' : function() { setUnits(0,''); },
|
||||
'Kph (spd)' : function() { setUnits(1,'kph'); },
|
||||
'Knots (spd)' : function() { setUnits(1.852,'kts'); },
|
||||
'Mph (spd)' : function() { setUnits(1.60934,'mph'); },
|
||||
|
|
Loading…
Reference in New Issue