diff --git a/.gitignore b/.gitignore index 757619ec5..a454fec09 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ package-lock.json *.js.bak appdates.csv .vscode +.idea/ diff --git a/README.md b/README.md index 22a12bd5b..240163f6c 100644 --- a/README.md +++ b/README.md @@ -219,7 +219,12 @@ and which gives information about the app for the Launcher. "shortName": "Short name", // short name for launcher "icon": "icon.png", // icon in apps/ "description": "...", // long description (can contain markdown) - "type":"...", // optional(if app) - 'app'/'widget'/'launch'/'bootloader' + "type":"...", // optional(if app) - + // 'app' - an application + // 'widget' - a widget + // 'launch' - replacement launcher app + // 'bootloader' - code that runs at startup only + // 'RAM' - code that runs and doesn't upload anything to storage "tags": "", // comma separated tag list for searching "dependencies" : { "notify":"type" } // optional, app 'types' we depend on // for instance this will use notify/notifyfs is they exist, or will pull in 'notify' @@ -241,7 +246,8 @@ and which gives information about the app for the Launcher. // add an icon to allow your app to be tested "storage": [ // list of files to add to storage - {"name":"appid.js", // filename to use in storage + {"name":"appid.js", // filename to use in storage. + // If name=='RAM', the code is sent directly to Bangle.js and is not saved to a file "url":"", // URL of file to load (currently relative to apps/) "content":"..." // if supplied, this content is loaded directly "evaluate":true // if supplied, data isn't quoted into a String before upload diff --git a/apps.json b/apps.json index 07aa644f6..50f76f875 100644 --- a/apps.json +++ b/apps.json @@ -80,7 +80,7 @@ "name": "Notifications (default)", "shortName":"Notifications", "icon": "notify.png", - "version":"0.03", + "version":"0.05", "description": "A handler for displaying notifications that displays them in a bar at the top of the screen", "tags": "widget", "type": "notify", @@ -93,7 +93,7 @@ "name": "Fullscreen Notifications", "shortName":"Notifications", "icon": "notify.png", - "version":"0.04", + "version":"0.06", "description": "A handler for displaying notifications that displays them fullscreen. This may not fully restore the screen after on some apps. See `Notifications (default)` for more information about the notifications library.", "tags": "widget", "type": "notify", @@ -692,6 +692,19 @@ {"name":"sclock.img","url":"clock-simple-icon.js","evaluate":true} ] }, + { "id": "vibrclock", + "name": "Vibrate Clock", + "icon": "app.png", + "version":"0.01", + "description": "When BTN1 is pressed, vibrate out the time as a series of buzzes, one digit at a time. Hours, then Minutes. Zero is signified by one long buzz. Otherwise a simple digital clock.", + "tags": "clock", + "type":"clock", + "allow_emulator":true, + "storage": [ + {"name":"vibrclock.app.js","url":"app.js"}, + {"name":"vibrclock.img","url":"app-icon.js","evaluate":true} + ] + }, { "id": "svclock", "name": "Simple V-Clock", "icon": "vclock-simple.png", @@ -882,6 +895,16 @@ {"name":"gpsinfo.img","url": "gps-info-icon.js","evaluate": true} ] }, + { "id": "assistedgps", + "name": "Assisted GPS Update", + "icon": "app.png", + "version":"0.01", + "description": "Downloads assisted GPS data to Bangle.js for faster GPS startup and more accurate fixes", + "custom": "custom.html", + "tags": "tool,outdoors", + "type": "RAM", + "storage": [ ] + }, { "id": "pomodo", "name":"Pomodoro", @@ -1421,7 +1444,7 @@ "name": "Digital Assistant, not EDITH", "shortName": "DANE", "icon": "app.png", - "version": "0.07", + "version": "0.10", "description": "A Watchface inspired by Tony Stark's EDITH", "tags": "clock", "type": "clock", diff --git a/apps/assistedgps/ChangeLog b/apps/assistedgps/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/assistedgps/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/assistedgps/app.png b/apps/assistedgps/app.png new file mode 100644 index 000000000..970e85139 Binary files /dev/null and b/apps/assistedgps/app.png differ diff --git a/apps/assistedgps/custom.html b/apps/assistedgps/custom.html new file mode 100644 index 000000000..e86c660b9 --- /dev/null +++ b/apps/assistedgps/custom.html @@ -0,0 +1,113 @@ + + + + + + +

Assisted GPS

+

GPS can take a long time (~5 minutes) to get an accurate position the first time it is used. + AGPS uploads a few hints to the GPS receiver about satellite positions that allow it + to get a faster, more accurate fix - however they are only valid for a short period of time.

+

You can upload data that covers a longer period of time, but the upload will take longer.

+
+ + + + + +
+

Click

+ + + + + + diff --git a/apps/dane/ChangeLog b/apps/dane/ChangeLog index 419109ec1..0ba1d848b 100644 --- a/apps/dane/ChangeLog +++ b/apps/dane/ChangeLog @@ -2,4 +2,7 @@ 0.04: Added Icon to watchface 0.05: bugfix 0.06: moved and resized icon -0.07: Added Description \ No newline at end of file +0.07: Added Description +0.08: Removed Image, Reduced RAM usage +0.09: Added Unix Time +0.10: Added Counter, Added Battery Display \ No newline at end of file diff --git a/apps/dane/app.js b/apps/dane/app.js index 5f7a48fbc..81e1bf5fa 100644 --- a/apps/dane/app.js +++ b/apps/dane/app.js @@ -1,66 +1,81 @@ const font = "6x8"; const timeFontSize = 4; +const unixTimeFontSize = 2; const dateFontSize = 3; const smallFontSize = 2; const yOffset = 23; -const xyCenter = g.getWidth()/2; +const width = g.getWidth(); +const height = g.getHeight(); +const xyCenter = width/2+4; const cornerSize = 14; const cornerOffset = 3; const borderWidth = 1; const yposTime = 27+yOffset; -const yposDate = 65+yOffset; +const yposDate = 65+yOffset+12; +const yposCounter = 58+yOffset+35+40; const mainColor = "#26dafd"; const mainColorDark = "#029dbb"; -const mainColorLight = "#8bebfe"; +// const mainColorLight = "#8bebfe"; const secondaryColor = "#df9527"; const secondaryColorDark = "#8b5c15"; -const secondaryColorLight = "#ecc180"; +// const secondaryColorLight = "#ecc180"; const success = "#00ff00"; -const successDark = "#000900"; -const successLight = "#060f06"; +// const successDark = "#000900"; +// const successLight = "#060f06"; const alert = "#ff0000"; -const alertDark = "#090000"; -const alertLight = "#0f0606"; +// const alertDark = "#090000"; +// const alertLight = "#0f0606"; + +let count = 100; + + +// function getImg() { +// return atob("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"); +// } + +// function makeImg() { +// return { +// width : 120, height : 120, bpp : 8, +// transparent : 254, +// buffer : require("heatshrink").decompress(getImg()) +// } +// } + -var img = { - width : 120, height : 120, bpp : 8, - transparent : 254, - buffer : require("heatshrink").decompress(atob("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")) -} function drawTopLeftCorner(x,y) { g.setColor(mainColor); - var x1 = x-cornerOffset; - var y1 = y-cornerOffset; + const x1 = x - cornerOffset; + const y1 = y - cornerOffset; g.fillRect(x1,y1,x1+cornerSize,y1+cornerSize); g.setColor("#000000"); g.fillRect(x,y,x+cornerSize-cornerOffset,y+cornerSize-cornerOffset); } function drawTopRightCorner(x,y) { g.setColor(mainColor); - var x1 = x+cornerOffset; - var y1 = y-cornerOffset; + const x1 = x + cornerOffset; + const y1 = y - cornerOffset; g.fillRect(x1,y1,x1-cornerSize,y1+cornerSize); g.setColor("#000000"); g.fillRect(x,y,x-cornerSize-cornerOffset,y+cornerSize-cornerOffset); } function drawBottomLeftCorner(x,y) { g.setColor(mainColor); - var x1 = x-cornerOffset; - var y1 = y+cornerOffset; + const x1 = x - cornerOffset; + const y1 = y + cornerOffset; g.fillRect(x1,y1,x1+cornerSize,y1-cornerSize); g.setColor("#000000"); g.fillRect(x,y,x+cornerSize-cornerOffset,y-cornerSize+cornerOffset); } function drawBottomRightCorner(x,y) { g.setColor(mainColor); - var x1 = x+cornerOffset; - var y1 = y+cornerOffset; + const x1 = x + cornerOffset; + const y1 = y + cornerOffset; g.fillRect(x1,y1,x1-cornerSize,y1-cornerSize); g.setColor("#000000"); g.fillRect(x,y,x-cornerSize+cornerOffset,y-cornerSize+cornerOffset); @@ -85,79 +100,137 @@ function drawTopFrame(x1,y1,x2,y2) { g.setColor("#000000"); g.fillRect(x1+borderWidth,y1+borderWidth,x2-borderWidth,y2-borderWidth); } -function drawBottomFrame(x1,y1,x2,y2) { - drawTopLeftCorner(x1,y1); - drawTopRightCorner(x2,y1); + +function drawFrameNoCorners(x1,y1,x2,y2) { g.setColor(mainColorDark); g.drawRect(x1,y1,x2,y2); g.setColor("#000000"); g.fillRect(x1+borderWidth,y1+borderWidth,x2-borderWidth,y2-borderWidth); } +// function drawBottomFrame(x1,y1,x2,y2) { +// drawTopLeftCorner(x1,y1); +// drawTopRightCorner(x2,y1); +// g.setColor(mainColorDark); +// g.drawRect(x1,y1,x2,y2); +// g.setColor("#000000"); +// g.fillRect(x1+borderWidth,y1+borderWidth,x2-borderWidth,y2-borderWidth); +// } -function getUTCTime(d) { - return d.toUTCString().split(' ')[4].split(':').map(function(d){return Number(d);}); -} +// function getUTCTime(d) { +// return d.toUTCString().split(' ')[4].split(':').map(function(d){return Number(d);}); +// } +function drawTimeText(d) { + const da = d.toString().split(" "); + // var dutc = getUTCTime(d); -function drawTimeText() { - g.setFontAlign(0, 0); - var d = new Date(); - var da = d.toString().split(" "); - var dutc = getUTCTime(d); - - var time = da[4].split(":"); - var hours = time[0], + const time = da[4].split(":"); + const hours = time[0], minutes = time[1], seconds = time[2]; g.setColor(mainColor); g.setFont(font, timeFontSize); g.drawString(`${hours}:${minutes}:${seconds}`, xyCenter, yposTime, true); + const unix = Math.round(d.getTime()); + + g.setFont(font, unixTimeFontSize); + g.setColor(secondaryColor); + g.drawString(`${unix}`, xyCenter, yposTime +22, true); g.setFont(font, smallFontSize); } -function drawDateText() { - g.setFontAlign(0, 0); - var d = new Date(); +function drawDateText(d) { + g.setColor(mainColor); g.setFont(font, dateFontSize); g.drawString(`${d.getDate()}.${d.getMonth()+1}.${d.getFullYear()}`, xyCenter, yposDate, true); } +function drawCounterText() { + if(count>999) count = 999; + if(count<0) count = 0; + g.setColor("#000000"); + g.fillRect(37,58+yOffset+36,203,58+80+yOffset+34); + g.setFontAlign(0, 0); + g.setColor(alert); + g.setFont(font, 8); + g.drawString(`${count}`, xyCenter, yposCounter, true); + + +} + +function levelColor(l) { + // no icon -> brightest green to indicate charging, even when showing percentage + if (Bangle.isCharging()) return success; + if (l >= 50) return success; + if (l >= 15) return secondaryColorDark; + return alert; +} + +function drawBattery() { + const l = E.getBattery(), c = levelColor(l); + const xl = 45+l*(194-46)/100; + g.setColor(c).fillRect(46,58+80+yOffset+37,xl, height-5); +} + function drawClock() { // main frame - drawFrame(3,10+yOffset,g.getWidth()-3,g.getHeight()-3); + drawFrame(3,10+yOffset,width-3,height-3); // time frame - drawTopFrame(20,10+yOffset,220,46+yOffset); + drawTopFrame(20,10+yOffset,220,58+yOffset); // date frame - drawTopFrame(28,46+yOffset,212,46+yOffset+35); + drawTopFrame(28,58+yOffset,212,58+yOffset+35); - // texts - drawTimeText(); - drawDateText(); - g.drawImage(img,g.getWidth()/2-(img.width/2),g.getHeight()/2); + // counter frame + drawTopFrame(36,58+yOffset+35,204,58+80+yOffset+35); + + // battery frame + drawFrameNoCorners(44,58+80+yOffset+35,196, height-3); + + + updateClock(); + + // const img = makeImg(); + // g.drawImage(img,width/2-(img.width/2),height/2); } function updateClock() { - drawTimeText(); - drawDateText(); + g.setFontAlign(0, 0); + const date = new Date(); + drawTimeText(date); + drawDateText(date); + drawCounterText(); + drawBattery(); } Bangle.on('lcdPower', function(on) { if (on) drawClock(); + }); + + g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); - drawClock(); + setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +setWatch(function() { + count+=1; + drawCounterText(); +}, BTN1, {repeat:true,edge:"falling"}); +setWatch(function() { + count--; + drawCounterText(); +}, BTN3, {repeat:true,edge:"falling"}); + // refesh every 100 milliseconds -setInterval(updateClock, 100); +setInterval(updateClock, 500); diff --git a/apps/notify/ChangeLog b/apps/notify/ChangeLog index cb974e12d..a1e8e4418 100644 --- a/apps/notify/ChangeLog +++ b/apps/notify/ChangeLog @@ -1,3 +1,4 @@ 0.01: New Library! 0.02: Add notification ID option -0.03: Pass `area{x,y,w,h}` to render callback instead of just `y` \ No newline at end of file +0.03: Pass `area{x,y,w,h}` to render callback instead of just `y` +0.05: Adjust position of notification src text diff --git a/apps/notify/notify.js b/apps/notify/notify.js index d8168e048..6f5261de1 100644 --- a/apps/notify/notify.js +++ b/apps/notify/notify.js @@ -94,8 +94,8 @@ exports.show = function(options) { g.setColor(-1).setFontAlign(-1, -1, 0).setFont("6x8", 2); g.drawString(title.trim().substring(0, 13), x+25,y+3); if (options.title && options.src) { - g.setFont("6x8", 1); - g.drawString(options.src.substring(0, 10), x+215,y+5); + g.setFont("6x8", 1).setFontAlign(1, 1, 0); + g.drawString(options.src.substring(0, 10), g.getWidth()-23,y+18); } y += 20;h -= 20; } diff --git a/apps/notifyfs/ChangeLog b/apps/notifyfs/ChangeLog index bf5c73161..16bc0ebb3 100644 --- a/apps/notifyfs/ChangeLog +++ b/apps/notifyfs/ChangeLog @@ -1,4 +1,6 @@ 0.01: New Library! 0.02: Add notification ID option 0.03: Fix custom render callback -0.04: Pass `area{x,y,w,h}` to render callback instead of just `y` \ No newline at end of file +0.04: Pass `area{x,y,w,h}` to render callback instead of just `y` +0.05: Fix `g` corruption issue if .hide gets called twice +0.06: Adjust position of notification src text and notifications without title diff --git a/apps/notifyfs/notify.js b/apps/notifyfs/notify.js index 7d317fa43..2c622f624 100644 --- a/apps/notifyfs/notify.js +++ b/apps/notifyfs/notify.js @@ -49,14 +49,13 @@ exports.show = function(options) { if (size>120) {size=120} Bangle.setLCDMode("direct"); let x = 0, - y = 0, + y = 40, w = 240, - h = 240; + h = size; // clear screen g.clear(1); // top bar if (options.title||options.src) { - y=40;h=size; const title = options.title || options.src g.setColor(0x39C7).fillRect(x, y, x+w-1, y+30); g.setColor(-1).setFontAlign(-1, -1, 0).setFont("6x8", 3); @@ -64,7 +63,8 @@ exports.show = function(options) { if (options.title && options.src) { g.setColor(-1).setFontAlign(1, 1, 0).setFont("6x8", 2); // above drawing area, but we are fullscreen - g.drawString(options.src.substring(0, 10), x+235, y-32); + print(options.src.substring(0, 10), w-23, y-4); + g.drawString(options.src.substring(0, 10), w-16, y-4); } y += 30;h -= 30; } @@ -106,8 +106,10 @@ exports.hide = function(options) { options = options||{}; if ("id" in options && options.id!==id) return; id = null; - g=oldg; - oldg = undefined; + if (oldg) { + g=oldg; + oldg = undefined; + } Bangle.removeListener("touch", exports.hide); g.clear(); Bangle.drawWidgets(); diff --git a/apps/vibrclock/ChangeLog b/apps/vibrclock/ChangeLog new file mode 100644 index 000000000..b4d1ae593 --- /dev/null +++ b/apps/vibrclock/ChangeLog @@ -0,0 +1 @@ +0.01: First commit diff --git a/apps/vibrclock/app-icon.js b/apps/vibrclock/app-icon.js new file mode 100644 index 000000000..c41aa0f9c --- /dev/null +++ b/apps/vibrclock/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4ATlgAGFlgylEQUyq1WwOB1msAYIHBmQxeDwQrB1nXABA0BqwxaP4eBFhIAFwIwYLgYtPAAZiWCgMrLhS7BMRUrGCQuN1gvBYxQwCF6S6LF5rEDFyC7MF5zDDF50rD5gvP1iRORpovRSJ6NNF6SRCLzQvSMBksmQdOF6OsmQvLRxwvSSBZqBF5+BmUyUJwvCGBC+QwMrCQMrCZ4vZxErLoJhBGAOsAAgvTwR6OH4QfBmTEBAAYwGwQv7R5uCR8DbOrrvSOoIuHF4VWDZ2CQwOICR3XFxAwCF54ATF5cyUo4vmYB4AM63P53O5/Q6wvKSDfW52j44AC0YFBMEnPFgYAGGBcrYKvWFAnP64wPMAKRV5wuE63W6HIMB6RU6y7E5HO6BfF0aRMGCS9D54EBF4I3BTIhgMGCSOCXYIwBSAICC6ySCF5QwCYYL0PF4fW53OAYjzDF5ZiTR4g0BR4OiR4LxDF5piEwJjLW4QACLgLvBFobvMGJEyqwzBwOCwQ3E6wvFXYLtEF6QxEAAtWBoYmEeYReERx4yNBYowFAAouWABouuAATDE0a7TAH4ASA")) diff --git a/apps/vibrclock/app.js b/apps/vibrclock/app.js new file mode 100644 index 000000000..188470cdc --- /dev/null +++ b/apps/vibrclock/app.js @@ -0,0 +1,97 @@ +// Simple clock from https://www.espruino.com/Bangle.js+Clock +// Load fonts +require("Font7x11Numeric7Seg").add(Graphics); +// Check settings for what type our clock should be +var is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; +// position on screen +const X = 160, Y = 140; + +function draw() { + // work out how to display the current time + var d = new Date(); + var h = d.getHours(), m = d.getMinutes(); + if (is12Hour) { + if (h == 0) h = 12; + else if (h>12) h -= 12; + } + var time = (" "+h).substr(-2) + ":" + ("0"+m).substr(-2); + // Reset the state of the graphics library + g.reset(); + // draw the current time (4x size 7 segment) + g.setFont("7x11Numeric7Seg",4); + g.setFontAlign(1,1); // align right bottom + g.drawString(time, X, Y, true /*clear background*/); + // draw the seconds (2x size 7 segment) + g.setFont("7x11Numeric7Seg",2); + g.drawString(("0"+d.getSeconds()).substr(-2), X+30, Y, true /*clear background*/); + // draw the date, in a normal font + g.setFont("6x8"); + g.setFontAlign(0,1); // align center bottom + // pad the date - this clears the background if the date were to change length + var dateStr = " "+require("locale").date(d)+" "; + g.drawString(dateStr, g.getWidth()/2, Y+15, true /*clear background*/); +} + +// Clear the screen once, at startup +g.clear(); +// draw immediately at first +draw(); +var secondInterval = setInterval(draw, 1000); +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (secondInterval) clearInterval(secondInterval); + secondInterval = undefined; + if (on) { + secondInterval = setInterval(draw, 1000); + draw(); // draw immediately + } +}); +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); + +// ====================================== Vibration +// vibrate 0..9 +function vibrateDigit(num) { + if (num==0) return Bangle.buzz(500); + return new Promise(function f(resolve){ + if (num--<=0) return resolve(); + Bangle.buzz(100).then(()=>{ + setTimeout(()=>f(resolve), 200); + }); + }); +} +// vibrate multiple digits (num must be a string) +function vibrateNumber(num) { + return new Promise(function f(resolve){ + if (!num.length) return resolve(); + var digit = num[0]; + num = num.substr(1); + vibrateDigit(digit).then(()=>{ + setTimeout(()=>f(resolve),500); + }); + }); +} + +var vibrateBusy; +function vibrateTime() { + if (vibrateBusy) return; + vibrateBusy = true; + + var d = new Date(); + var hours = d.getHours(), minutes = d.getMinutes(); + if (is12Hour) { + if (hours == 0) hours = 12; + else if (hours>12) hours -= 12; + } + + vibrateNumber(hours.toString()). + then(() => new Promise(resolve=>setTimeout(resolve,500))). + then(() => vibrateNumber(minutes.toString())). + then(() => vibrateBusy=false); +} + +// when BTN1 pressed, vibrate +setWatch(vibrateTime, BTN1, {repeat:true,edge:"rising"}); diff --git a/apps/vibrclock/app.png b/apps/vibrclock/app.png new file mode 100644 index 000000000..79ff0b992 Binary files /dev/null and b/apps/vibrclock/app.png differ diff --git a/bin/firmwaremaker.js b/bin/firmwaremaker.js index ce885c394..4e22dd168 100755 --- a/bin/firmwaremaker.js +++ b/bin/firmwaremaker.js @@ -19,6 +19,13 @@ var APPS = [ // IDs of apps to install var MINIFY = true; var fs = require("fs"); +global.Const = { + /* Are we only putting a single app on a device? If so + apps should all be saved as .bootcde and we write info + about the current app into app.info */ + SINGLE_APP_ONLY : false, +}; + var AppInfo = require(ROOTDIR+"/core/js/appinfo.js"); var appjson = JSON.parse(fs.readFileSync(APPJSON).toString()); var appfiles = []; diff --git a/core b/core index 9708e1a15..62615f6ea 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 9708e1a15ee20734a24f6f2913078aa8bba625dc +Subproject commit 62615f6ea4855381e0b4b4b74f8ca69aa594181e diff --git a/testing/GPS-comms.js b/testing/GPS-comms.js index 67df178f8..ca0db16b6 100644 --- a/testing/GPS-comms.js +++ b/testing/GPS-comms.js @@ -1,12 +1,3 @@ -/* This code allows you to communicate with the GPS -receiver in Bangle.js in order to set it up. - -Protocol spec: - -https://cdn.sparkfun.com/assets/0/b/0/f/7/u-blox8-M8_ReceiverDescrProtSpec__UBX-13003221__Public.pdf - -*/ - Bangle.setGPSPower(1) //Bangle.on('GPS',print); @@ -25,9 +16,26 @@ function writeGPScmd(cmd) { a += d[i]; b += a; } - d.push(a,b); + d.push(a&255,b&255); Serial1.write(d); } +function readGPScmd(cmd, callback) { + var prefix = String.fromCharCode(0xb5,0x62,cmd[0],cmd[1]); + function handler(d) { + if (!d.startsWith(prefix)) return; + clearInterval(timeout); + var a = E.toUint8Array(d); + // cut off id + length + a = new Uint8Array(a.buffer,6, a.length-8); + callback(a); + } + Bangle.on('GPS-raw',handler); + var timeout = setTimeout(function() { + callback(); + Bangle.removeListener('GPS-raw',handler); + }, 2000); + writeGPScmd(cmd); +} function UBX_CFG_PMS() { // UBX-CFG-PMS - enable power management - Super-E writeGPScmd([0x06,0x86, // msg class + type @@ -64,4 +72,70 @@ function UBX_CFG_MSG(msg,enable) { // Enter super-e low power // UBX_CFG_PMS() // Disable DTM messages (see UBX_CFG_MSG comments): -UBX_CFG_MSG("DTM",false); \ No newline at end of file +//UBX_CFG_MSG("DTM",false); +// UBX-CFG-HNR (0x06 0x5C) - high rate (up to 30hz) + + +// GPS 181,98,6,62,60,0,0,32,32,7,0,8,16,0,1,0,1,1,1,1,3,0,0,0,1,1,2,4,8,0,0,0,1,1,3,8,16,0,1,0,1,1,4,0,8,0,0,0,1,3,5,0,3,0,1,0,1,5,6,8,14,0,0,0,1,1,84,27 +//GPS ACK + +function getUBX_CFG_GNSS() { + // + readGPScmd([0x06,0x3E,0,0], function(a) { + print("CFG_GNSS",a.join(","), a.length); + var info = { + numTrkChHw : a[1], + numTrkChUse : a[2], + configs : [] + }; + for (var i=4;i