forked from FOSS/BangleApps
Merge branch 'espruino:master' into master
commit
c2286a91d8
|
@ -237,6 +237,11 @@ and which gives information about the app for the Launcher.
|
||||||
// like this one with 'storage','name' and 'id' set up
|
// like this one with 'storage','name' and 'id' set up
|
||||||
// see below for more info
|
// see below for more info
|
||||||
|
|
||||||
|
"customConnect": true, // if supplied, ensure we are connected to a device
|
||||||
|
// before the "custom.html" iframe is loaded. An
|
||||||
|
// onInit function in "custom.html" is then called
|
||||||
|
// with info on the currently connected device.
|
||||||
|
|
||||||
"interface": "interface.html", // if supplied, apps/interface.html is loaded in an
|
"interface": "interface.html", // if supplied, apps/interface.html is loaded in an
|
||||||
// iframe, and it may interact with the connected Bangle
|
// iframe, and it may interact with the connected Bangle
|
||||||
// to retrieve information from it
|
// to retrieve information from it
|
||||||
|
|
30
apps.json
30
apps.json
|
@ -4,7 +4,7 @@
|
||||||
"tags": "tool,system,b2",
|
"tags": "tool,system,b2",
|
||||||
"type":"bootloader",
|
"type":"bootloader",
|
||||||
"icon": "bootloader.png",
|
"icon": "bootloader.png",
|
||||||
"version":"0.28",
|
"version":"0.29",
|
||||||
"description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings",
|
"description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings",
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":".boot0","url":"boot0.js"},
|
{"name":".boot0","url":"boot0.js"},
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
"name": "Launcher (Bangle.js 2)",
|
"name": "Launcher (Bangle.js 2)",
|
||||||
"shortName":"Launcher",
|
"shortName":"Launcher",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.01",
|
"version":"0.02",
|
||||||
"description": "This is needed by Bangle.js 2.0 to display a menu allowing you to choose your own applications. It will not work on Bangle.js 1.0.",
|
"description": "This is needed by Bangle.js 2.0 to display a menu allowing you to choose your own applications. It will not work on Bangle.js 1.0.",
|
||||||
"tags": "tool,system,launcher,b2,bno1",
|
"tags": "tool,system,launcher,b2,bno1",
|
||||||
"type":"launch",
|
"type":"launch",
|
||||||
|
@ -402,9 +402,9 @@
|
||||||
{ "id": "trex",
|
{ "id": "trex",
|
||||||
"name": "T-Rex",
|
"name": "T-Rex",
|
||||||
"icon": "trex.png",
|
"icon": "trex.png",
|
||||||
"version":"0.03",
|
"version":"0.04",
|
||||||
"description": "T-Rex game in the style of Chrome's offline game",
|
"description": "T-Rex game in the style of Chrome's offline game",
|
||||||
"tags": "game",
|
"tags": "game,b2",
|
||||||
"allow_emulator":true,
|
"allow_emulator":true,
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"trex.app.js","url":"trex.js"},
|
{"name":"trex.app.js","url":"trex.js"},
|
||||||
|
@ -418,9 +418,9 @@
|
||||||
{ "id": "astroid",
|
{ "id": "astroid",
|
||||||
"name": "Asteroids!",
|
"name": "Asteroids!",
|
||||||
"icon": "asteroids.png",
|
"icon": "asteroids.png",
|
||||||
"version":"0.02",
|
"version":"0.03",
|
||||||
"description": "Retro asteroids game",
|
"description": "Retro asteroids game",
|
||||||
"tags": "game",
|
"tags": "game,b2",
|
||||||
"allow_emulator":true,
|
"allow_emulator":true,
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"astroid.app.js","url":"asteroids.js"},
|
{"name":"astroid.app.js","url":"asteroids.js"},
|
||||||
|
@ -814,8 +814,8 @@
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.02",
|
"version":"0.02",
|
||||||
"description": "Use this to upload a customised QR code to Bangle.js",
|
"description": "Use this to upload a customised QR code to Bangle.js",
|
||||||
"tags": "qrcode",
|
"tags": "qrcode,b2",
|
||||||
"custom": "custom.html",
|
"custom": "custom.html", "customConnect":true,
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"qrcode.app.js"},
|
{"name":"qrcode.app.js"},
|
||||||
{"name":"qrcode.img","url":"app-icon.js","evaluate":true}
|
{"name":"qrcode.img","url":"app-icon.js","evaluate":true}
|
||||||
|
@ -1096,9 +1096,9 @@
|
||||||
{ "id": "flappy",
|
{ "id": "flappy",
|
||||||
"name": "Flappy Bird",
|
"name": "Flappy Bird",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.04",
|
"version":"0.05",
|
||||||
"description": "A Flappy Bird game clone",
|
"description": "A Flappy Bird game clone",
|
||||||
"tags": "game",
|
"tags": "game,b2",
|
||||||
"allow_emulator":true,
|
"allow_emulator":true,
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"flappy.app.js","url":"app.js"},
|
{"name":"flappy.app.js","url":"app.js"},
|
||||||
|
@ -1183,7 +1183,7 @@
|
||||||
{ "id": "widpedom",
|
{ "id": "widpedom",
|
||||||
"name": "Pedometer widget",
|
"name": "Pedometer widget",
|
||||||
"icon": "widget.png",
|
"icon": "widget.png",
|
||||||
"version":"0.14",
|
"version":"0.17",
|
||||||
"description": "Daily pedometer widget",
|
"description": "Daily pedometer widget",
|
||||||
"tags": "widget,b2",
|
"tags": "widget,b2",
|
||||||
"type":"widget",
|
"type":"widget",
|
||||||
|
@ -1520,7 +1520,7 @@
|
||||||
"version":"0.08",
|
"version":"0.08",
|
||||||
"description": "[BETA] Loads map tiles from OpenStreetMap onto your Bangle.js and displays a map of where you are",
|
"description": "[BETA] Loads map tiles from OpenStreetMap onto your Bangle.js and displays a map of where you are",
|
||||||
"tags": "outdoors,gps,b2",
|
"tags": "outdoors,gps,b2",
|
||||||
"custom": "custom.html",
|
"custom": "custom.html", "customConnect":true,
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"openstmap","url":"openstmap.js"},
|
{"name":"openstmap","url":"openstmap.js"},
|
||||||
{"name":"openstmap.app.js","url":"app.js"},
|
{"name":"openstmap.app.js","url":"app.js"},
|
||||||
|
@ -2039,7 +2039,7 @@
|
||||||
"id": "beebclock",
|
"id": "beebclock",
|
||||||
"name": "Beeb Clock",
|
"name": "Beeb Clock",
|
||||||
"icon": "beebclock.png",
|
"icon": "beebclock.png",
|
||||||
"version":"0.04",
|
"version":"0.05",
|
||||||
"description": "Clock face that may be coincidentally familiar to BBC viewers",
|
"description": "Clock face that may be coincidentally familiar to BBC viewers",
|
||||||
"tags": "clock",
|
"tags": "clock",
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
|
@ -2735,7 +2735,7 @@
|
||||||
"name": "Heart Rate Variability monitor",
|
"name": "Heart Rate Variability monitor",
|
||||||
"shortName":"HRV monitor",
|
"shortName":"HRV monitor",
|
||||||
"icon": "hrv.png",
|
"icon": "hrv.png",
|
||||||
"version":"0.03",
|
"version":"0.04",
|
||||||
"description": "Heart Rate Variability monitor, see Readme for more info",
|
"description": "Heart Rate Variability monitor, see Readme for more info",
|
||||||
"tags": "",
|
"tags": "",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
|
@ -3208,7 +3208,7 @@
|
||||||
{ "id": "kitchen",
|
{ "id": "kitchen",
|
||||||
"name": "Kitchen Combo",
|
"name": "Kitchen Combo",
|
||||||
"icon": "kitchen.png",
|
"icon": "kitchen.png",
|
||||||
"version":"0.12",
|
"version":"0.13",
|
||||||
"description": "Combination of the Stepo, Walkersclock, Arrow and Waypointer apps into a multiclock format. 'Everything but the kitchen sink'. Requires firmware v2.08.167 or later",
|
"description": "Combination of the Stepo, Walkersclock, Arrow and Waypointer apps into a multiclock format. 'Everything but the kitchen sink'. Requires firmware v2.08.167 or later",
|
||||||
"tags": "tool,outdoors,gps",
|
"tags": "tool,outdoors,gps",
|
||||||
"type":"clock",
|
"type":"clock",
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
0.02: Added options to either run as a one-off reading, or a continuous mode to log data until the watch is reset
|
0.02: Added options to either run as a one-off reading, or a continuous mode to log data until the watch is reset
|
||||||
0.03: Add RMSSD recording
|
0.03: Add RMSSD recording
|
||||||
|
0.04: Modify to work with new heart rate API, but still not sure it's working correctly
|
||||||
|
|
162
apps/HRV/app.js
162
apps/HRV/app.js
|
@ -17,22 +17,23 @@ var csv = [
|
||||||
logfile.write(csv.join(",")+"\n");
|
logfile.write(csv.join(",")+"\n");
|
||||||
|
|
||||||
var debugging = true;
|
var debugging = true;
|
||||||
|
var samples = 0; // how many samples have we connected?
|
||||||
|
var collectData = false; // are we currently collecting data?
|
||||||
|
|
||||||
var first_signals = 0; // ignore the first several signals
|
|
||||||
var heartrate = [];
|
|
||||||
var BPM_array = [];
|
var BPM_array = [];
|
||||||
var raw_HR_array = new Float32Array(1536);
|
var raw_HR_array = new Float32Array(1536);
|
||||||
var alternate_array = new Float32Array(3072);
|
var alternate_array = new Float32Array(3072);
|
||||||
var pulse_array = [];
|
var pulse_array = [];
|
||||||
var pulsecount = 0;
|
|
||||||
var cutoff_threshold = 0.5;
|
var cutoff_threshold = 0.5;
|
||||||
var sample_frequency = 51.6;
|
var sample_frequency = 51.6;
|
||||||
var gap_threshold = 0.15;
|
var gap_threshold = 0.15;
|
||||||
var hr_min = 40;
|
|
||||||
var hr_max = 160;
|
|
||||||
var movement = 0;
|
var movement = 0;
|
||||||
|
|
||||||
function storeMyData(data, file_type) {
|
var px = g.getWidth()/2;
|
||||||
|
var py = g.getHeight()/2;
|
||||||
|
var accel; // interval for acceleration logging
|
||||||
|
|
||||||
|
function storeMyData(data, file_type) { "ram"
|
||||||
log = raw_HR_array;
|
log = raw_HR_array;
|
||||||
// shift elements backwards - note the 4, because a Float32 is 4 bytes
|
// shift elements backwards - note the 4, because a Float32 is 4 bytes
|
||||||
log.set(new Float32Array(log.buffer, 4 /*bytes*/));
|
log.set(new Float32Array(log.buffer, 4 /*bytes*/));
|
||||||
|
@ -41,59 +42,58 @@ function storeMyData(data, file_type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function average(samples) {
|
function average(samples) {
|
||||||
var sum = 0;
|
return E.sum(samples) / samples.length; // faster builtin
|
||||||
|
/* var sum = 0;
|
||||||
for (var i = 0; i < samples.length; i++) {
|
for (var i = 0; i < samples.length; i++) {
|
||||||
sum += parseFloat(samples[i]);
|
sum += parseFloat(samples[i]);
|
||||||
}
|
}
|
||||||
var avg = sum / samples.length;
|
var avg = sum / samples.length;
|
||||||
return avg;
|
return avg;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
function StandardDeviation (array) {
|
function StandardDeviation (array) {
|
||||||
const n = array.length;
|
const n = array.length;
|
||||||
const mean = array.reduce((a, b) => a + b) / n;
|
const mean = E.sum(array) / n; //array.reduce((a, b) => a + b) / n;
|
||||||
return Math.sqrt(array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n);
|
//return Math.sqrt(array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n);
|
||||||
|
return Math.sqrt(E.variance(array, mean));
|
||||||
}
|
}
|
||||||
|
|
||||||
function turn_off() {
|
function turn_off() {
|
||||||
Bangle.setHRMPower(0);
|
Bangle.setHRMPower(0);
|
||||||
|
|
||||||
var accel = setInterval(function () {
|
|
||||||
movement = movement + Bangle.getAccel().diff;
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
g.clear();
|
g.clear();
|
||||||
g.drawString("processing 1/5", 120, 120);
|
g.drawString("processing 1/5", px, py);
|
||||||
|
|
||||||
rolling_average(raw_HR_array,5);
|
rolling_average(raw_HR_array,5);
|
||||||
g.clear();
|
g.clear();
|
||||||
g.drawString("processing 2/5", 120, 120);
|
g.drawString("processing 2/5", px, py);
|
||||||
|
|
||||||
upscale();
|
upscale();
|
||||||
g.clear();
|
g.clear();
|
||||||
g.drawString("processing 3/5", 120, 120);
|
g.drawString("processing 3/5", px, py);
|
||||||
|
|
||||||
rolling_average(alternate_array,5);
|
rolling_average(alternate_array,5);
|
||||||
g.clear();
|
g.clear();
|
||||||
g.drawString("processing 4/5", 120, 120);
|
g.drawString("processing 4/5", px, py);
|
||||||
|
|
||||||
apply_cutoff();
|
apply_cutoff();
|
||||||
find_peaks();
|
find_peaks();
|
||||||
|
|
||||||
g.clear();
|
g.clear();
|
||||||
g.drawString("processing 5/5", 120, 120);
|
g.drawString("processing 5/5", px, py);
|
||||||
|
|
||||||
calculate_HRV();
|
calculate_HRV();
|
||||||
}
|
}
|
||||||
|
|
||||||
function bernstein(A, B, C, D, E, t) {
|
function bernstein(A, B, C, D, E, t) { "ram"
|
||||||
s = 1 - t;
|
s = 1 - t;
|
||||||
x = (A * Math.pow(s, 4)) + (B * 4 * Math.pow(s, 3) * t) + (C * 6 * s * s * t * t)
|
x = (A * Math.pow(s, 4)) + (B * 4 * Math.pow(s, 3) * t) + (C * 6 * s * s * t * t)
|
||||||
+ (D * 4 * s * Math.pow(t, 3)) + (E * Math.pow(t, 4));
|
+ (D * 4 * s * Math.pow(t, 3)) + (E * Math.pow(t, 4));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
function upscale() {
|
function upscale() { "ram"
|
||||||
var index = 0;
|
var index = 0;
|
||||||
for (let i = raw_HR_array.length - 1; i > 5; i -= 5) {
|
for (let i = raw_HR_array.length - 1; i > 5; i -= 5) {
|
||||||
p0 = raw_HR_array[i];
|
p0 = raw_HR_array[i];
|
||||||
|
@ -110,19 +110,18 @@ function upscale() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function rolling_average(values, count) {
|
function rolling_average(values, count) { "ram"
|
||||||
var temp_array = [];
|
var temp_array = [];
|
||||||
|
|
||||||
for (let i = 0; i < values.length; i++) {
|
for (let i = 0; i < values.length; i++) {
|
||||||
temp_array = [];
|
temp_array = [];
|
||||||
for (let x = 0; x < count; x++)
|
for (let x = 0; x < count; x++)
|
||||||
temp_array.push(values[i + x]);
|
temp_array.push(values[i + x]);
|
||||||
|
|
||||||
values[i] = average(temp_array);
|
values[i] = average(temp_array);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function apply_cutoff() {
|
function apply_cutoff() { "ram"
|
||||||
var x;
|
var x;
|
||||||
for (let i = 0; i < alternate_array.length; i++) {
|
for (let i = 0; i < alternate_array.length; i++) {
|
||||||
x = alternate_array[i];
|
x = alternate_array[i];
|
||||||
|
@ -132,7 +131,7 @@ function apply_cutoff() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function find_peaks() {
|
function find_peaks() { "ram"
|
||||||
var previous;
|
var previous;
|
||||||
var previous_slope = 0;
|
var previous_slope = 0;
|
||||||
var slope;
|
var slope;
|
||||||
|
@ -157,7 +156,7 @@ function find_peaks() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function RMSSD(samples){
|
function RMSSD(samples){ "ram"
|
||||||
var sum = 0;
|
var sum = 0;
|
||||||
var square = 0;
|
var square = 0;
|
||||||
var data = [];
|
var data = [];
|
||||||
|
@ -192,7 +191,7 @@ function calculate_HRV() {
|
||||||
gap_average = average(temp_array);
|
gap_average = average(temp_array);
|
||||||
var calculatedHR = (sample_frequency*60)/(gap_average/2);
|
var calculatedHR = (sample_frequency*60)/(gap_average/2);
|
||||||
if(option == 0)
|
if(option == 0)
|
||||||
g.flip();
|
Bangle.setLCDPower(1);
|
||||||
g.clear();
|
g.clear();
|
||||||
//var display_stdv = StandardDeviation(pulse_array).toFixed(1);
|
//var display_stdv = StandardDeviation(pulse_array).toFixed(1);
|
||||||
var SDNN = (StandardDeviation(temp_array) * (1 / (sample_frequency * 2) * 1000)).toFixed(0);
|
var SDNN = (StandardDeviation(temp_array) * (1 / (sample_frequency * 2) * 1000)).toFixed(0);
|
||||||
|
@ -200,14 +199,13 @@ function calculate_HRV() {
|
||||||
g.drawString("SDNN:" + SDNN
|
g.drawString("SDNN:" + SDNN
|
||||||
+"\nRMSSD:" + RMS_SD
|
+"\nRMSSD:" + RMS_SD
|
||||||
+ "\nHR:" + calculatedHR.toFixed(0)
|
+ "\nHR:" + calculatedHR.toFixed(0)
|
||||||
+"\nSample Count:" + temp_array.length, 120, 120);
|
+"\nSample Count:" + temp_array.length, px, py);
|
||||||
|
Bangle.setLCDPower(1);
|
||||||
if(option == 0){
|
if(option == 0) { // single run
|
||||||
Bangle.buzz(500,1);
|
Bangle.buzz(500,1);
|
||||||
clearInterval(routine);
|
option = null;
|
||||||
}
|
drawButtons();
|
||||||
|
} else {
|
||||||
else{
|
|
||||||
var csv = [
|
var csv = [
|
||||||
0|getTime(),
|
0|getTime(),
|
||||||
temp_array.length,
|
temp_array.length,
|
||||||
|
@ -219,85 +217,87 @@ function calculate_HRV() {
|
||||||
];
|
];
|
||||||
logfile.write(csv.join(",")+"\n");
|
logfile.write(csv.join(",")+"\n");
|
||||||
|
|
||||||
movement = 0;
|
|
||||||
// for (let i = 0; i < raw_HR_array.length; i++) {
|
// for (let i = 0; i < raw_HR_array.length; i++) {
|
||||||
// raw_HR_array[i] = null;
|
// raw_HR_array[i] = null;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
turn_on();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function btn1Pressed() {
|
function btn1Pressed() {
|
||||||
if(option === null){
|
if(option === null){
|
||||||
clearInterval(accel);
|
|
||||||
g.clear();
|
g.clear();
|
||||||
g.drawString("one-off assessment", 120, 120);
|
g.drawString("one-off assessment", px, py);
|
||||||
option = 0;
|
option = 0;
|
||||||
Bangle.setHRMPower(1);
|
|
||||||
|
turn_on();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function btn3Pressed() {
|
function btn3Pressed() {
|
||||||
if(option === null){
|
if(option === null){
|
||||||
logfile.write(""); //reset HRV log
|
logfile.write(""); //reset HRV log
|
||||||
clearInterval(accel);
|
|
||||||
g.clear();
|
g.clear();
|
||||||
g.drawString("continuous mode", 120, 120);
|
g.drawString("continuous mode", px, py);
|
||||||
option = 1;
|
option = 1;
|
||||||
Bangle.setHRMPower(1);
|
|
||||||
}
|
turn_on();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var routine = setInterval(function () {
|
function turn_on() {
|
||||||
clearInterval(accel);
|
|
||||||
first_signals = 0; // ignore the first several signals
|
|
||||||
pulsecount = 0;
|
|
||||||
BPM_array = [];
|
BPM_array = [];
|
||||||
heartrate = [];
|
|
||||||
pulse_array = [];
|
pulse_array = [];
|
||||||
|
samples = 0;
|
||||||
|
if (accel) clearInterval(accel);
|
||||||
|
movement = 0;
|
||||||
|
accel = setInterval(function () {
|
||||||
|
movement = movement + Bangle.getAccel().diff;
|
||||||
|
}, 1000);
|
||||||
Bangle.setHRMPower(1);
|
Bangle.setHRMPower(1);
|
||||||
}, 180000);
|
collectData = true;
|
||||||
|
}
|
||||||
|
|
||||||
var accel = setInterval(function () {
|
function drawButtons() {
|
||||||
movement = movement + Bangle.getAccel().diff;
|
g.setColor("#00ff7f");
|
||||||
}, 1000);
|
g.setFont("6x8", 2);
|
||||||
|
g.setFontAlign(-1,1);
|
||||||
|
g.drawString("continuous", 120, 210);
|
||||||
|
g.drawString("one-time", 140, 50);
|
||||||
|
g.setColor("#ffffff");
|
||||||
|
g.setFontAlign(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
g.clear();
|
g.clear();
|
||||||
g.setColor("#00ff7f");
|
|
||||||
g.setFont("6x8", 2);
|
|
||||||
g.setFontAlign(-1,1);
|
|
||||||
g.drawString("continuous", 120, 210);
|
|
||||||
g.setFontAlign(-1,1);
|
|
||||||
g.drawString("one-time", 140, 50);
|
|
||||||
|
|
||||||
|
drawButtons();
|
||||||
|
|
||||||
|
g.setFont("6x8", 2);
|
||||||
g.setColor("#ffffff");
|
g.setColor("#ffffff");
|
||||||
g.setFontAlign(0, 0); // center font
|
g.setFontAlign(0, 0); // center font
|
||||||
g.drawString("check app README", 120, 120);
|
g.drawString("check app README\nfor more info", px, py);
|
||||||
g.drawString("for more info", 120, 140);
|
|
||||||
|
|
||||||
setWatch(btn1Pressed, BTN1, {repeat:true});
|
setWatch(btn1Pressed, BTN1, {repeat:true});
|
||||||
setWatch(btn3Pressed, BTN3, {repeat:true});
|
setWatch(btn3Pressed, BTN3, {repeat:true});
|
||||||
|
|
||||||
Bangle.on('HRM', function (hrm) {
|
|
||||||
if(option == 0)
|
|
||||||
g.flip();
|
Bangle.on('HRM-raw', function (e) {
|
||||||
if (first_signals < 3) {
|
if (!collectData) return;
|
||||||
g.clear();
|
storeMyData(e.raw, 0);
|
||||||
g.drawString("setting up...\nremain still " + first_signals * 20 + "%", 120, 120);
|
if (!(samples & 7)) {
|
||||||
first_signals++;
|
Bangle.setLCDPower(1);
|
||||||
}
|
g.clearRect(0, py-10, g.getWidth(), py+22);
|
||||||
else {
|
if (samples < 100)
|
||||||
BPM_array = hrm.raw;
|
g.drawString("setting up...\nremain still " + samples + "%", px, py, true);
|
||||||
if(hrm.bpm > hr_min && hrm.bpm < hr_max)
|
else
|
||||||
heartrate.push(hrm.bpm);
|
g.drawString("logging: " + (samples*100/raw_HR_array.length).toFixed(0) + "%", px, py, true);
|
||||||
if (pulsecount < 7) {
|
}
|
||||||
for (let i = 0; i < 256; i++) {
|
if (samples > raw_HR_array.length) {
|
||||||
storeMyData(BPM_array[i], 0);
|
collectData = false;
|
||||||
}
|
turn_off();
|
||||||
g.clear();
|
}
|
||||||
g.drawString("logging: " + ((pulsecount/6)*100).toFixed(0) + "%", 120, 120);
|
samples++;
|
||||||
}
|
|
||||||
if(pulsecount == 6)
|
|
||||||
turn_off();
|
|
||||||
pulsecount++;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1 +1 @@
|
||||||
require("heatshrink").decompress(atob("oFAwhC/AH4A2xAedhGIwA+dAAI+dAAJAcEAJ/fD/4f5hAJIYSo6JIihaKxBATxAACC4YnBAAQ+TD7o/CFRJfTP5a/eb6pEOD/7JFwczAA0ybgwfUkUjD4QaDD6syiMSD4ZABCIa8JD547BCIY/ZHQQ+LD6Z/cHZYf/f6E4D6uCD4gACD6wgBkQACBAYfWABYf/D/4fPwf/ABgf/D6czABBf/P/5f/P/5f/D+WIABwfuAH4A/ADo="))
|
require("heatshrink").decompress(atob("mEwwgsphAXWxGACyoABDCwWVC/4XcXY8IDZsIxAXVXYQZDDwIGEC6gwMI5IvNGAJfVR5DXyPgczAAwSEC58iC4R3DC50xiMjC4QTBXY4XNGAIPCF6QTCI6gXCYYwXQcQ4XemUiC6IRBa4wXOABQX/C9OD/4AKC5WPC+Hzaw0zI/5H/C83zI/mIUo4ACnAXLABgXI"))
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.8 KiB |
|
@ -1 +1,2 @@
|
||||||
0.02: Add "ram" keyword to allow 2v06 Espruino builds to cache function that needs to be fast
|
0.02: Add "ram" keyword to allow 2v06 Espruino builds to cache function that needs to be fast
|
||||||
|
0.03: Bangle 2 support
|
||||||
|
|
|
@ -1,12 +1,24 @@
|
||||||
Bangle.setLCDMode("doublebuffered");
|
var BTNL, BTNR, BTNU, BTNA;
|
||||||
|
if (process.env.HWVERSION==2) {
|
||||||
|
var tap = {};
|
||||||
|
// use tapping on screen for left,right,accel
|
||||||
|
Bangle.on('drag',e=>tap=e);
|
||||||
|
BTNL = { read : _=>tap.b && tap.x < 58};
|
||||||
|
BTNR = { read : _=>tap.b && tap.x > 117};
|
||||||
|
BTNU = { read : _=>tap.b && tap.x > 58 && tap.x < 117};
|
||||||
|
// use button for fire
|
||||||
|
BTNA = BTN1;
|
||||||
|
} else {
|
||||||
|
// use hard buttons
|
||||||
|
BTNL = BTN4;
|
||||||
|
BTNR = BTN5;
|
||||||
|
BTNU = BTN1;
|
||||||
|
BTNA = BTN2;
|
||||||
|
Bangle.setLCDMode("doublebuffered");
|
||||||
|
}
|
||||||
var W = g.getWidth();
|
var W = g.getWidth();
|
||||||
var H = g.getHeight();
|
var H = g.getHeight();
|
||||||
g.setFontAlign(0,-1);
|
g.clear().setFontAlign(0,-1);
|
||||||
var BTNL = BTN4;
|
|
||||||
var BTNR = BTN5;
|
|
||||||
var BTNU = BTN1;
|
|
||||||
var BTNA = BTN2;
|
|
||||||
|
|
||||||
function newAst(x,y) {
|
function newAst(x,y) {
|
||||||
var a = {
|
var a = {
|
||||||
|
@ -92,8 +104,7 @@ function onFrame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
g.clear();
|
g.clear();
|
||||||
|
g.drawString(score,W-20,0);
|
||||||
g.drawString(score,120,0);
|
|
||||||
var rs = Math.PI*0.8;
|
var rs = Math.PI*0.8;
|
||||||
g.drawPoly([
|
g.drawPoly([
|
||||||
ship.x+Math.cos(ship.r)*4, ship.y+Math.sin(ship.r)*4,
|
ship.x+Math.cos(ship.r)*4, ship.y+Math.sin(ship.r)*4,
|
||||||
|
|
|
@ -2,3 +2,5 @@
|
||||||
0.02: Fixes; widget support
|
0.02: Fixes; widget support
|
||||||
0.03: Remove hardcoded hour buzz (you can install widchime if you miss it)
|
0.03: Remove hardcoded hour buzz (you can install widchime if you miss it)
|
||||||
0.04: Update to use Bangle.setUI instead of setWatch
|
0.04: Update to use Bangle.setUI instead of setWatch
|
||||||
|
0.05: Avoid 'loadWidgets' at LCD on, which will cause memory leak
|
||||||
|
Avoid clearTimeout() usage, as it may break other widgets
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
const storage = require("Storage");
|
const storage = require("Storage");
|
||||||
const filename = 'beebjson';
|
const filename = 'beebjson';
|
||||||
|
var timeout;
|
||||||
|
|
||||||
require('FontTeletext10x18Ascii').add(Graphics);
|
require('FontTeletext10x18Ascii').add(Graphics);
|
||||||
|
|
||||||
|
@ -153,15 +154,21 @@ let hours, minutes, seconds, date;
|
||||||
// Schedule event for calling at the start of the next second
|
// Schedule event for calling at the start of the next second
|
||||||
const inOneSecond = (cb) => {
|
const inOneSecond = (cb) => {
|
||||||
let now = new Date();
|
let now = new Date();
|
||||||
clearTimeout();
|
if (timeout) clearTimeout(timeout);
|
||||||
setTimeout(cb, 1000 - now.getMilliseconds());
|
timeout = setTimeout(function() {
|
||||||
|
timeout = undefined;
|
||||||
|
cb();
|
||||||
|
}, 1000 - now.getMilliseconds());
|
||||||
};
|
};
|
||||||
|
|
||||||
// Schedule event for calling at the start of the next minute
|
// Schedule event for calling at the start of the next minute
|
||||||
const inOneMinute = (cb) => {
|
const inOneMinute = (cb) => {
|
||||||
let now = new Date();
|
let now = new Date();
|
||||||
clearTimeout();
|
if (timeout) clearTimeout(timeout);
|
||||||
setTimeout(cb, 60000 - (now.getSeconds() * 1000 + now.getMilliseconds()));
|
timeout = setTimeout(function() {
|
||||||
|
timeout = undefined;
|
||||||
|
cb();
|
||||||
|
}, 60000 - (now.getSeconds() * 1000 + now.getMilliseconds()));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Draw a fat hour/minute hand
|
// Draw a fat hour/minute hand
|
||||||
|
@ -356,6 +363,7 @@ const changeSeconds = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
|
// widgets are drawn in drawAll()
|
||||||
|
|
||||||
// Restore mode
|
// Restore mode
|
||||||
try {
|
try {
|
||||||
|
@ -373,10 +381,9 @@ drawAll();
|
||||||
|
|
||||||
Bangle.on('lcdPower', (on) => {
|
Bangle.on('lcdPower', (on) => {
|
||||||
if (on) {
|
if (on) {
|
||||||
Bangle.loadWidgets();
|
|
||||||
Bangle.drawWidgets();
|
|
||||||
drawAll();
|
drawAll();
|
||||||
} else {
|
} else {
|
||||||
clearTimeout();
|
if (timeout) clearTimeout(timeout);
|
||||||
|
timeout = undefined;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -27,3 +27,5 @@
|
||||||
0.26: Remove buzz in setUI polyfill (#750)
|
0.26: Remove buzz in setUI polyfill (#750)
|
||||||
0.27: Update polyfill for most recent changes
|
0.27: Update polyfill for most recent changes
|
||||||
0.28: Fix double clock load after settings are changed
|
0.28: Fix double clock load after settings are changed
|
||||||
|
0.29: Update boot0 to avoid code block (faster execution)
|
||||||
|
Fix issues where 'Uncaught Error: Function not found' could happen with multiple .boot.js
|
||||||
|
|
|
@ -6,7 +6,7 @@ var s = require('Storage').readJSON('setting.json',1)||{};
|
||||||
var isB2 = process.env.HWVERSION; // Is Bangle.js 2
|
var isB2 = process.env.HWVERSION; // Is Bangle.js 2
|
||||||
var boot = "";
|
var boot = "";
|
||||||
var CRC = E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/));
|
var CRC = E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/));
|
||||||
boot += `if (E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/))!=${CRC}) { eval(require('Storage').read('bootupdate.js'));} else {\n`;
|
boot += `if (E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/))!=${CRC}) { eval(require('Storage').read('bootupdate.js')); throw "Storage Updated!"}\n`;
|
||||||
boot += `E.setFlags({pretokenise:1});\n`;
|
boot += `E.setFlags({pretokenise:1});\n`;
|
||||||
if (s.ble!==false) {
|
if (s.ble!==false) {
|
||||||
if (s.HID) { // Human interface device
|
if (s.HID) { // Human interface device
|
||||||
|
@ -133,9 +133,11 @@ else if (mode=="updown") {
|
||||||
}
|
}
|
||||||
// Append *.boot.js files
|
// Append *.boot.js files
|
||||||
require('Storage').list(/\.boot\.js/).forEach(bootFile=>{
|
require('Storage').list(/\.boot\.js/).forEach(bootFile=>{
|
||||||
boot += "//"+bootFile+"\n"+require('Storage').read(bootFile)+"\n";
|
// we add a semicolon so if the file is wrapped in (function(){ ... }()
|
||||||
|
// with no semicolon we don't end up with (function(){ ... }()(function(){ ... }()
|
||||||
|
// which would cause an error!
|
||||||
|
boot += require('Storage').read(bootFile)+";\n";
|
||||||
});
|
});
|
||||||
boot += "}\n";// initial 'if'
|
|
||||||
require('Storage').write('.boot0',boot);
|
require('Storage').write('.boot0',boot);
|
||||||
delete boot;
|
delete boot;
|
||||||
E.showMessage("Reloading...");
|
E.showMessage("Reloading...");
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
0.02: Tweaks to make flappy bird run with less RAM available
|
0.02: Tweaks to make flappy bird run with less RAM available
|
||||||
0.03: A few tweaks to improve rendering speed
|
0.03: A few tweaks to improve rendering speed
|
||||||
0.04: Add "ram" keyword to allow 2v06 Espruino builds to cache function that needs to be fast
|
0.04: Add "ram" keyword to allow 2v06 Espruino builds to cache function that needs to be fast
|
||||||
|
0.05: Don't use Bangle.setLCDMode, just use offscreen buffer (allows widgets)
|
||||||
|
|
|
@ -1,3 +1,21 @@
|
||||||
|
b = Graphics.createArrayBuffer(120,120,8);
|
||||||
|
var gimg = {
|
||||||
|
width:120,
|
||||||
|
height:104,
|
||||||
|
bpp:8,
|
||||||
|
buffer:b.buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
if (process.env.HWVERSION==2) {
|
||||||
|
b.flip = function() {
|
||||||
|
g.drawImage(gimg,28,50);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
b.flip = function() {
|
||||||
|
g.drawImage(gimg,0,24,{scale:2});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
var BIRDIMG = E.toArrayBuffer(atob("EQyI/v7+/v7+/gAAAAAAAP7+/v7+/v7+/gYG0tLS0gDXAP7+/v7+/v4A0tLS0tIA19fXAP7+/v4AAAAA0tLS0gDX1wDXAP7+ANfX19cA0tLSANfXANcA/v4A19fX19cA0tLSANfX1wD+/gDS19fX0gDS0tLSAAAAAAD+/gDS0tIA0tLS0gDAwMDAwAD+/gAAAM3Nzc0AwAAAAAAA/v7+/v4Azc3Nzc0AwMDAwAD+/v7+/v4AAM3Nzc0AAAAAAP7+/v7+/v7+AAAAAP7+/v7+/g=="))
|
var BIRDIMG = E.toArrayBuffer(atob("EQyI/v7+/v7+/gAAAAAAAP7+/v7+/v7+/gYG0tLS0gDXAP7+/v7+/v4A0tLS0tIA19fXAP7+/v4AAAAA0tLS0gDX1wDXAP7+ANfX19cA0tLSANfXANcA/v4A19fX19cA0tLSANfX1wD+/gDS19fX0gDS0tLSAAAAAAD+/gDS0tIA0tLS0gDAwMDAwAD+/gAAAM3Nzc0AwAAAAAAA/v7+/v4Azc3Nzc0AwMDAwAD+/v7+/v4AAM3Nzc0AAAAAAP7+/v7+/v7+AAAAAP7+/v7+/g=="))
|
||||||
var FLOORIMG = require("heatshrink").decompress(atob("iEKxH+kklABuLAAlgAAwNFB34OLmAAO0YAO5wAOA"));
|
var FLOORIMG = require("heatshrink").decompress(atob("iEKxH+kklABuLAAlgAAwNFB34OLmAAO0YAO5wAOA"));
|
||||||
|
|
||||||
|
@ -33,26 +51,26 @@ function gameStop() {
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
"ram"
|
"ram"
|
||||||
var H = g.getHeight()-24;
|
var H = b.getHeight()-24;
|
||||||
g.setColor("#71c6cf");
|
b.setColor("#71c6cf");
|
||||||
g.fillRect(0,0,g.getWidth(),H-1);
|
b.fillRect(0,0,b.getWidth(),H-1);
|
||||||
floorpos++;
|
floorpos++;
|
||||||
for (var x=-(floorpos&15);x<g.getWidth();x+=16)
|
for (var x=-(floorpos&15);x<b.getWidth();x+=16)
|
||||||
g.drawImage(FLOORIMG,x,H);
|
b.drawImage(FLOORIMG,x,H);
|
||||||
|
|
||||||
|
|
||||||
if (!running) {
|
if (!running) {
|
||||||
var x = g.getWidth()/2;
|
var x = b.getWidth()/2;
|
||||||
g.setColor("#000000");
|
b.setColor("#000000");
|
||||||
g.setFontAlign(0,0);
|
b.setFontAlign(0,0);
|
||||||
g.setFont("4x6",2);
|
b.setFont("4x6",2);
|
||||||
g.drawString("GAME OVER!",x,20);
|
b.drawString("GAME OVER!",x,20);
|
||||||
g.setFont("6x8",1);
|
b.setFont("6x8",1);
|
||||||
g.drawString("Score",x,40);
|
b.drawString("Score",x,40);
|
||||||
g.drawString(score,x,56);
|
b.drawString(score,x,56);
|
||||||
g.drawString("Tap screen to",x,76);
|
b.drawString("Tap screen to",x,76);
|
||||||
g.drawString("restart and flap",x,84);
|
b.drawString("restart and flap",x,84);
|
||||||
g.flip();
|
b.flip();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,30 +81,30 @@ function draw() {
|
||||||
if (birdy > H)
|
if (birdy > H)
|
||||||
gameStop();
|
gameStop();
|
||||||
// draw bird
|
// draw bird
|
||||||
g.drawImage(BIRDIMG, 6,birdy, {rotate:Math.atan2(birdvy,15)});
|
b.drawImage(BIRDIMG, 6,birdy, {rotate:Math.atan2(birdvy,15)});
|
||||||
// draw barriers
|
// draw barriers
|
||||||
barriers.forEach(function(b) {
|
barriers.forEach(function(r) {
|
||||||
b.x1--;
|
r.x1--;
|
||||||
b.x2--;
|
r.x2--;
|
||||||
var btop = b.y-b.gap;
|
var btop = r.y-r.gap;
|
||||||
var bbot = b.y+b.gap;
|
var bbot = r.y+r.gap;
|
||||||
g.setColor("#73bf2f"); // middle
|
b.setColor("#73bf2f"); // middle
|
||||||
g.fillRect(b.x1+4, 0, b.x2-4, btop-1);
|
b.fillRect(r.x1+4, 0, r.x2-4, btop-1);
|
||||||
g.fillRect(b.x1+4, bbot, b.x2-4, H-1);
|
b.fillRect(r.x1+4, bbot, r.x2-4, H-1);
|
||||||
g.setColor("#c0f181"); // left
|
b.setColor("#c0f181"); // left
|
||||||
g.fillRect(b.x1+1, 0, b.x1+3, btop-1);
|
b.fillRect(r.x1+1, 0, r.x1+3, btop-1);
|
||||||
g.fillRect(b.x1+1, bbot, b.x1+3, H-1);
|
b.fillRect(r.x1+1, bbot, r.x1+3, H-1);
|
||||||
g.setColor("#538917"); // right
|
b.setColor("#538917"); // right
|
||||||
g.fillRect(b.x2-3, 0, b.x2-1, btop-1);
|
b.fillRect(r.x2-3, 0, r.x2-1, btop-1);
|
||||||
g.fillRect(b.x2-3, bbot, b.x2-1, H-1);
|
b.fillRect(r.x2-3, bbot, r.x2-1, H-1);
|
||||||
g.setColor("#808080"); // outlines
|
b.setColor("#808080"); // outlines
|
||||||
g.drawRect(b.x1, btop-5, b.x2, btop); // top
|
b.drawRect(r.x1, btop-5, r.x2, btop); // top
|
||||||
g.drawLine(b.x1+1, 0, b.x1+1, btop-6);
|
b.drawLine(r.x1+1, 0, r.x1+1, btop-6);
|
||||||
g.drawLine(b.x2-2, 0, b.x2-2, btop-6);
|
b.drawLine(r.x2-2, 0, r.x2-2, btop-6);
|
||||||
g.drawRect(b.x1, bbot, b.x2, bbot+5); // bottom
|
b.drawRect(r.x1, bbot, r.x2, bbot+5); // bottom
|
||||||
g.drawLine(b.x1+1, bbot+6, b.x1+1, H-1);
|
b.drawLine(r.x1+1, bbot+6, r.x1+1, H-1);
|
||||||
g.drawLine(b.x2-1, bbot+6, b.x2-1, H-1);
|
b.drawLine(r.x2-1, bbot+6, r.x2-1, H-1);
|
||||||
if (b.x1<6 && (birdy-3<btop || birdy+3>bbot))
|
if (r.x1<6 && (birdy-3<btop || birdy+3>bbot))
|
||||||
gameStop();
|
gameStop();
|
||||||
});
|
});
|
||||||
while (barriers.length && barriers[0].x2<=0) {
|
while (barriers.length && barriers[0].x2<=0) {
|
||||||
|
@ -94,7 +112,7 @@ function draw() {
|
||||||
newBarrier(g.getWidth());
|
newBarrier(g.getWidth());
|
||||||
}
|
}
|
||||||
|
|
||||||
g.flip();
|
b.flip();
|
||||||
}
|
}
|
||||||
|
|
||||||
Bangle.on('touch', function(button) {
|
Bangle.on('touch', function(button) {
|
||||||
|
@ -105,11 +123,9 @@ Bangle.on('touch', function(button) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Finally, start everything going
|
Bangle.loadWidgets();
|
||||||
setTimeout(()=>{
|
g.clear();
|
||||||
Bangle.setLCDMode("120x120");
|
Bangle.drawWidgets();
|
||||||
g.setBgColor("#e3db9d");
|
b.setBgColor("#e3db9d");
|
||||||
g.clear();
|
gameStart();
|
||||||
gameStart();
|
setInterval(draw, 100);
|
||||||
setInterval(draw, 100);
|
|
||||||
},10);
|
|
||||||
|
|
|
@ -10,3 +10,4 @@
|
||||||
0.10: Converted Stepo to use direct screen writes, added a Trip Counter feature to stepo
|
0.10: Converted Stepo to use direct screen writes, added a Trip Counter feature to stepo
|
||||||
0.11: Detect when waypoints.json is not present, error E-WPT
|
0.11: Detect when waypoints.json is not present, error E-WPT
|
||||||
0.12: Added stepo2 as a replacement for stepo and digi
|
0.12: Added stepo2 as a replacement for stepo and digi
|
||||||
|
0.13: Added long press BTN2 toggle gpsrec status in GPS clock
|
||||||
|
|
|
@ -85,14 +85,19 @@
|
||||||
|
|
||||||
function onButtonLong(btn) {
|
function onButtonLong(btn) {
|
||||||
log_debug("markWaypoint()");
|
log_debug("markWaypoint()");
|
||||||
if (btn !== 1) return;
|
if (btn === 1) {
|
||||||
if (gpsObject.getState() !== gpsObject.GPS_RUNNING) return;
|
if (gpsObject.getState() !== gpsObject.GPS_RUNNING) return;
|
||||||
log_debug("markWaypoint()");
|
log_debug("markWaypoint()");
|
||||||
|
|
||||||
gpsObject.markWaypoint();
|
gpsObject.markWaypoint();
|
||||||
resetPrevious();
|
resetPrevious();
|
||||||
getWaypoint();
|
getWaypoint();
|
||||||
drawGPSData();
|
drawGPSData();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btn === 2)
|
||||||
|
Bangle.showLauncher();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWaypoint() {
|
function getWaypoint() {
|
||||||
|
|
|
@ -55,7 +55,10 @@
|
||||||
if (btn === 1) cycleInfoMode();
|
if (btn === 1) cycleInfoMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onButtonLong(btn) {}
|
function onButtonLong(btn) {
|
||||||
|
if (btn === 2) Bangle.showLauncher();
|
||||||
|
}
|
||||||
|
|
||||||
function getGPSfix() { return undefined; }
|
function getGPSfix() { return undefined; }
|
||||||
function setGPSfix(f) {}
|
function setGPSfix(f) {}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function onButtonLong(btn) {
|
function onButtonLong(btn) {
|
||||||
if (btn === 1) toggleGPSPower();
|
switch(btn) {
|
||||||
|
case 1:
|
||||||
|
toggleGPSPower();
|
||||||
|
return;
|
||||||
|
case 2:
|
||||||
|
if (gpsObject.getState() === gpsObject.GPS_RUNNING)
|
||||||
|
gpsObject.toggleGpsLogging();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function draw(){
|
function draw(){
|
||||||
|
@ -143,7 +151,8 @@
|
||||||
g.drawString(activityStr, 120, Y_ACTIVITY);
|
g.drawString(activityStr, 120, Y_ACTIVITY);
|
||||||
g.setFont("6x8",2);
|
g.setFont("6x8",2);
|
||||||
g.setColor(1,1,1);
|
g.setColor(1,1,1);
|
||||||
g.drawString(age, 120, Y_ACTIVITY + 46);
|
var age_and_logging = age + " logging " + gpsObject.loggingStatus();
|
||||||
|
g.drawString(age_and_logging, 120, Y_ACTIVITY + 46);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,8 @@ function buttonReleased(btn) {
|
||||||
face.onButtonLong(btn);
|
face.onButtonLong(btn);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
Bangle.showLauncher();
|
face.onButtonLong(btn);
|
||||||
|
//Bangle.showLauncher();
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
// do nothing
|
// do nothing
|
||||||
|
@ -94,8 +95,8 @@ function setButtons(){
|
||||||
}
|
}
|
||||||
|
|
||||||
Bangle.on('kill',()=>{
|
Bangle.on('kill',()=>{
|
||||||
Bangle.setCompassPower(0);
|
Bangle.setCompassPower(0,'kitchen');
|
||||||
Bangle.setGPSPower(0);
|
Bangle.setGPSPower(0,'kitchen');
|
||||||
});
|
});
|
||||||
|
|
||||||
Bangle.on('lcdPower',function(on) {
|
Bangle.on('lcdPower',function(on) {
|
||||||
|
@ -214,7 +215,7 @@ GPS.prototype.toggleGPSPower = function() {
|
||||||
this.log_debug("toggleGPSPower()");
|
this.log_debug("toggleGPSPower()");
|
||||||
this.gpsPowerState = Bangle.isGPSOn();
|
this.gpsPowerState = Bangle.isGPSOn();
|
||||||
this.gpsPowerState = !this.gpsPowerState;
|
this.gpsPowerState = !this.gpsPowerState;
|
||||||
Bangle.setGPSPower(this.gpsPowerState ? 1 : 0);
|
Bangle.setGPSPower((this.gpsPowerState ? 1 : 0), 'kitchen');
|
||||||
|
|
||||||
this.resetLastFix();
|
this.resetLastFix();
|
||||||
this.determineGPSState();
|
this.determineGPSState();
|
||||||
|
@ -369,6 +370,26 @@ GPS.prototype.nextWaypoint = function(inc) {
|
||||||
return this.wp_current;
|
return this.wp_current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GPS.prototype.toggleGpsLogging = function() {
|
||||||
|
var settings = require("Storage").readJSON("gpsrec.json",1)||{};
|
||||||
|
if (settings == {}) return false;
|
||||||
|
|
||||||
|
settings.recording = !settings.recording;
|
||||||
|
require("Storage").write("gpsrec.json", settings);
|
||||||
|
|
||||||
|
if (WIDGETS["gpsrec"])
|
||||||
|
WIDGETS["gpsrec"].reload();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
GPS.prototype.loggingStatus = function() {
|
||||||
|
var settings = require("Storage").readJSON("gpsrec.json",1)||{};
|
||||||
|
if (settings == {}) return "E-LOG";
|
||||||
|
if (settings.recording) return "ON";
|
||||||
|
return "OFF";
|
||||||
|
}
|
||||||
|
|
||||||
var gpsObj = new GPS();
|
var gpsObj = new GPS();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function onButtonLong(btn) {
|
function onButtonLong(btn) {
|
||||||
trip.resetTrip(getSteps());
|
if (btn === 1) {
|
||||||
trip.setTripState(true);
|
trip.resetTrip(getSteps());
|
||||||
drawStepText();
|
trip.setTripState(true);
|
||||||
|
drawStepText();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btn === 2) Bangle.showLauncher();
|
||||||
}
|
}
|
||||||
|
|
||||||
function radians(a) {
|
function radians(a) {
|
||||||
|
|
|
@ -62,10 +62,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function onButtonLong(btn) {
|
function onButtonLong(btn) {
|
||||||
trip.resetTrip(getSteps());
|
if (btn === 1) {
|
||||||
infoMode = INFO_TRIP;
|
trip.resetTrip(getSteps());
|
||||||
forceRedraw();
|
infoMode = INFO_TRIP;
|
||||||
draw();
|
forceRedraw();
|
||||||
|
draw();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btn === 2) Bangle.showLauncher();
|
||||||
}
|
}
|
||||||
|
|
||||||
function radians(a) {
|
function radians(a) {
|
||||||
|
@ -207,7 +212,8 @@
|
||||||
var midrot = -180 - (360 * percent);
|
var midrot = -180 - (360 * percent);
|
||||||
var endrot = -360 - 180;
|
var endrot = -360 - 180;
|
||||||
|
|
||||||
g.setColor(0x07FF); // light cyan
|
//g.setColor(0x07FF); // light cyan
|
||||||
|
g.setColor(0xFFC0); // yellow
|
||||||
|
|
||||||
// draw guauge
|
// draw guauge
|
||||||
for (i = startrot; i > midrot; i -= 3) {
|
for (i = startrot; i > midrot; i -= 3) {
|
||||||
|
@ -218,8 +224,8 @@
|
||||||
|
|
||||||
// change the remaining color to RED if battery is below 25%
|
// change the remaining color to RED if battery is below 25%
|
||||||
if (E.getBattery() > 25) {
|
if (E.getBattery() > 25) {
|
||||||
//g.setColor(0x7BEF); // grey
|
g.setColor(0x7BEF); // grey
|
||||||
g.setColor(0x000D); // dark navy
|
//g.setColor(0x000D); // dark navy
|
||||||
} else {
|
} else {
|
||||||
g.setColor(0xF800); // red
|
g.setColor(0xF800); // red
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onButtonLong(btn) {}
|
function onButtonLong(btn) {
|
||||||
|
if (btn === 2) Bangle.showLauncher();
|
||||||
|
}
|
||||||
|
|
||||||
return {init:init, freeResources:freeResources, startTimer:startTimer, stopTimer:stopTimer,
|
return {init:init, freeResources:freeResources, startTimer:startTimer, stopTimer:stopTimer,
|
||||||
onButtonShort:onButtonShort, onButtonLong:onButtonLong};
|
onButtonShort:onButtonShort, onButtonLong:onButtonLong};
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
|
0.02: Fix occasional missed image when scrolling up
|
||||||
|
|
|
@ -47,8 +47,13 @@ Bangle.on('drag',e=>{
|
||||||
g.reset().setClipRect(0,24,g.getWidth()-1,g.getHeight()-1);
|
g.reset().setClipRect(0,24,g.getWidth()-1,g.getHeight()-1);
|
||||||
g.scroll(0,dy);
|
g.scroll(0,dy);
|
||||||
menuScroll -= dy;
|
menuScroll -= dy;
|
||||||
if (e.dy < 0) drawApp(Math.floor((menuScroll+24)/APPH)+n-1);
|
if (e.dy < 0) {
|
||||||
else drawApp(Math.floor((menuScroll+24)/APPH));
|
drawApp(Math.floor((menuScroll+24+g.getHeight())/APPH)-1);
|
||||||
|
if (e.dy <= -APPH) drawApp(Math.floor((menuScroll+24+g.getHeight())/APPH)-2);
|
||||||
|
} else {
|
||||||
|
drawApp(Math.floor((menuScroll+24)/APPH));
|
||||||
|
if (e.dy >= APPH) drawApp(Math.floor((menuScroll+24)/APPH)+1);
|
||||||
|
}
|
||||||
g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1);
|
g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1);
|
||||||
});
|
});
|
||||||
Bangle.on("touch",(_,e)=>{
|
Bangle.on("touch",(_,e)=>{
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
<div id="map">
|
<div id="map">
|
||||||
</div>
|
</div>
|
||||||
<div id="controls">
|
<div id="controls">
|
||||||
<div style="display:inline-block;text-align:center;vertical-align: top;"> <input type="checkbox" id="3bit"></input><br/><span>3 bit</span></div>
|
<div style="display:inline-block;text-align:center;vertical-align: top;" id="3bitdiv"> <input type="checkbox" id="3bit"></input><br/><span>3 bit</span></div>
|
||||||
<button id="getmap" class="btn btn-primary">Get Map</button><br/>
|
<button id="getmap" class="btn btn-primary">Get Map</button><br/>
|
||||||
<canvas id="maptiles" style="display:none"></canvas>
|
<canvas id="maptiles" style="display:none"></canvas>
|
||||||
<div id="uploadbuttons" style="display:none"><button id="upload" class="btn btn-primary">Upload</button>
|
<div id="uploadbuttons" style="display:none"><button id="upload" class="btn btn-primary">Upload</button>
|
||||||
|
@ -72,6 +72,16 @@ TODO:
|
||||||
});
|
});
|
||||||
// Could optionally overlay trails: https://wiki.openstreetmap.org/wiki/Tiles
|
// Could optionally overlay trails: https://wiki.openstreetmap.org/wiki/Tiles
|
||||||
|
|
||||||
|
function onInit(device) {
|
||||||
|
if (device && device.info && device.info.g) {
|
||||||
|
// On 3 bit devices, don't even offer the option. 3 bit is the only way
|
||||||
|
if (device.info.g.bpp==3) {
|
||||||
|
document.getElementById("3bit").checked = true;
|
||||||
|
document.getElementById("3bitdiv").style = "display:none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var mapFiles = [];
|
var mapFiles = [];
|
||||||
tileLayer.addTo(map);
|
tileLayer.addTo(map);
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,23 @@
|
||||||
<script src="../../core/lib/imageconverter.js"></script>
|
<script src="../../core/lib/imageconverter.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
var targetWidth = 200;
|
||||||
|
var targetHeight = 200;
|
||||||
|
|
||||||
|
function onInit(device) {
|
||||||
|
if (device && device.info && device.info.g) {
|
||||||
|
targetWidth = device.info.g.width - 20;
|
||||||
|
targetHeight = device.info.g.height - 20;
|
||||||
|
}
|
||||||
|
qrcode = new QRCode("qrcode", {
|
||||||
|
text: document.getElementById("url").value,
|
||||||
|
width: targetWidth,
|
||||||
|
height: targetHeight,
|
||||||
|
colorDark : "#000000",
|
||||||
|
colorLight : "#ffffff",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
//https://github.com/evgeni/qifi/blob/gh-pages/index.html#L168
|
//https://github.com/evgeni/qifi/blob/gh-pages/index.html#L168
|
||||||
function escapeString (string) {
|
function escapeString (string) {
|
||||||
var to_escape = ['\\', ';', ',', ':', '"'];
|
var to_escape = ['\\', ';', ',', ':', '"'];
|
||||||
|
@ -70,13 +87,7 @@
|
||||||
qrcode.makeCode(document.getElementById("url").value);
|
qrcode.makeCode(document.getElementById("url").value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var qrcode = new QRCode("qrcode", {
|
var qrcode;
|
||||||
text: document.getElementById("url").value,
|
|
||||||
width: 200,
|
|
||||||
height: 200,
|
|
||||||
colorDark : "#000000",
|
|
||||||
colorLight : "#ffffff",
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById("url").addEventListener("change", refreshQRCode);
|
document.getElementById("url").addEventListener("change", refreshQRCode);
|
||||||
document.getElementById("ssid").addEventListener("change",refreshQRCode);
|
document.getElementById("ssid").addEventListener("change",refreshQRCode);
|
||||||
|
@ -93,13 +104,11 @@
|
||||||
var img = imageconverter.canvastoString(document.getElementsByTagName("canvas")[0],{mode:"1bit",output:"string",compression:true});
|
var img = imageconverter.canvastoString(document.getElementsByTagName("canvas")[0],{mode:"1bit",output:"string",compression:true});
|
||||||
var app = `var img = ${img};
|
var app = `var img = ${img};
|
||||||
var content = ${JSON.stringify(content)};
|
var content = ${JSON.stringify(content)};
|
||||||
g.setColor(1,1,1);
|
g.clear(1).setColor(1,1,1).setBgColor(0,0,0);
|
||||||
g.fillRect(0,0,239,239);
|
g.fillRect(0,0,g.getWidth()-1,g.getHeight()-1);
|
||||||
g.drawImage(img,20,20);
|
g.drawImage(img,(g.getWidth()-img[0])/2,(g.getHeight()-img[1])/2);
|
||||||
g.setFontAlign(0,0);
|
g.setFontAlign(0,0).setFont("6x8").setColor(0,0,0);
|
||||||
g.setFont("6x8");
|
g.drawString(content,g.getWidth()/2,g.getHeight()-(g.getHeight()-img[1])/4));
|
||||||
g.setColor(0,0,0);
|
|
||||||
g.drawString(content,120,230);
|
|
||||||
g.setColor(1,1,1);
|
g.setColor(1,1,1);
|
||||||
`;
|
`;
|
||||||
sendCustomizedApp({
|
sendCustomizedApp({
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
0.02: Add "ram" keyword to allow 2v06 Espruino builds to cache function that needs to be fast
|
0.02: Add "ram" keyword to allow 2v06 Espruino builds to cache function that needs to be fast
|
||||||
0.03: Enabled BTN2 and BTN3, added highscore (score is saved to storage and can be reset in app settings menu)
|
0.03: Enabled BTN2 and BTN3, added highscore (score is saved to storage and can be reset in app settings menu)
|
||||||
|
0.04: Bangle.js 2 support
|
||||||
|
|
|
@ -8,20 +8,42 @@ function saveHighScore(score) {
|
||||||
f.write(score + "\n");
|
f.write(score + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
greal = g;
|
|
||||||
g.clear();
|
g.clear();
|
||||||
g = Graphics.createArrayBuffer(120,64,1,{msb:true});
|
|
||||||
g.flip = function() {
|
var BTNL, BTNR, BTNU;
|
||||||
greal.drawImage({
|
if (process.env.HWVERSION==2) {
|
||||||
width:120,
|
var tap = {};
|
||||||
height:64,
|
// use tapping on screen for left and right
|
||||||
buffer:g.buffer
|
Bangle.on('drag',e=>tap=e);
|
||||||
},0,(240-128)/2,{scale:2});
|
BTNL = { read : _=>tap.b && tap.x < 88};
|
||||||
};
|
BTNR = { read : _=>tap.b && tap.x > 88};
|
||||||
|
// use button for jump
|
||||||
|
BTNU = BTN1;
|
||||||
|
greal = g;
|
||||||
|
g = Graphics.createArrayBuffer(88,64,1,{msb:true});
|
||||||
|
g.flip = function() {
|
||||||
|
greal.drawImage({
|
||||||
|
width:88,
|
||||||
|
height:64,
|
||||||
|
buffer:g.buffer
|
||||||
|
},0,(176-128)/2,{scale:2});
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// use hard buttons
|
||||||
|
BTNL = BTN2;
|
||||||
|
BTNR = BTN3;
|
||||||
|
BTNU = BTN1;
|
||||||
|
greal = g;
|
||||||
|
g = Graphics.createArrayBuffer(120,64,1,{msb:true});
|
||||||
|
g.flip = function() {
|
||||||
|
greal.drawImage({
|
||||||
|
width:120,
|
||||||
|
height:64,
|
||||||
|
buffer:g.buffer
|
||||||
|
},0,(240-128)/2,{scale:2});
|
||||||
|
};
|
||||||
|
}
|
||||||
var W = g.getWidth();
|
var W = g.getWidth();
|
||||||
var BTNL = BTN2;
|
|
||||||
var BTNR = BTN3;
|
|
||||||
var BTNU = BTN1;
|
|
||||||
|
|
||||||
// Images can be added like this in Espruino v2.00
|
// Images can be added like this in Espruino v2.00
|
||||||
var IMG = {
|
var IMG = {
|
||||||
|
|
|
@ -11,3 +11,6 @@
|
||||||
0.12: Respect Quiet Mode
|
0.12: Respect Quiet Mode
|
||||||
0.13: Now use system color theme
|
0.13: Now use system color theme
|
||||||
0.14: Improve memory usage
|
0.14: Improve memory usage
|
||||||
|
0.15: Settings option to hide the widget icon
|
||||||
|
0.16: Settings option to show large digits in widget area
|
||||||
|
0.17: Cope with 2v10+ firmware sometimes reporting >1 step
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
let s = {
|
let s = {
|
||||||
'goal': 10000,
|
'goal': 10000,
|
||||||
'progress': false,
|
'progress': false,
|
||||||
|
'large': false,
|
||||||
|
'hide': false
|
||||||
}
|
}
|
||||||
// ...and overwrite them with any saved values
|
// ...and overwrite them with any saved values
|
||||||
// This way saved values are preserved if a new version adds more settings
|
// This way saved values are preserved if a new version adds more settings
|
||||||
|
@ -41,6 +43,22 @@
|
||||||
save()
|
save()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'Large Digits': {
|
||||||
|
value: s.large,
|
||||||
|
format: () => (s.large ? 'Yes' : 'No'),
|
||||||
|
onchange: () => {
|
||||||
|
s.large = !s.large
|
||||||
|
save()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'Hide Widget': {
|
||||||
|
value: s.hide,
|
||||||
|
format: () => (s.hide ? 'Yes' : 'No'),
|
||||||
|
onchange: () => {
|
||||||
|
s.hide = !s.hide
|
||||||
|
save()
|
||||||
|
},
|
||||||
|
},
|
||||||
'< Back': back,
|
'< Back': back,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
(() => {
|
(() => {
|
||||||
const PEDOMFILE = "wpedom.json"
|
const PEDOMFILE = "wpedom.json"
|
||||||
|
// Last time Bangle.on('step' was called
|
||||||
let lastUpdate = new Date();
|
let lastUpdate = new Date();
|
||||||
|
// Last step count when Bangle.on('step' was called
|
||||||
|
var lastStepCount;
|
||||||
let stp_today = 0;
|
let stp_today = 0;
|
||||||
let settings;
|
let settings;
|
||||||
|
|
||||||
|
@ -14,11 +17,14 @@
|
||||||
const DEFAULTS = {
|
const DEFAULTS = {
|
||||||
'goal': 10000,
|
'goal': 10000,
|
||||||
'progress': false,
|
'progress': false,
|
||||||
|
'large': false,
|
||||||
|
'hide': false
|
||||||
}
|
}
|
||||||
return (key in settings) ? settings[key] : DEFAULTS[key];
|
return (key in settings) ? settings[key] : DEFAULTS[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawProgress(stps) {
|
function drawProgress(stps) {
|
||||||
|
if (setting('hide')) return;
|
||||||
const width = 24, half = width/2;
|
const width = 24, half = width/2;
|
||||||
const goal = setting('goal'), left = Math.max(goal-stps,0);
|
const goal = setting('goal'), left = Math.max(goal-stps,0);
|
||||||
const c = left ? "#00f" : "#090"; // blue or dark green
|
const c = left ? "#00f" : "#090"; // blue or dark green
|
||||||
|
@ -46,13 +52,29 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// show the step count in the widget area in a readable sized font
|
||||||
|
function draw_large(st) {
|
||||||
|
var width = 12 * st.length;
|
||||||
|
g.reset();
|
||||||
|
g.clearRect(this.x, this.y, this.x + width, this.y + 16); // erase background
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
|
g.setFont("6x8",2);
|
||||||
|
g.setFontAlign(-1, -1);
|
||||||
|
g.drawString(st, this.x + 4, this.y + 2);
|
||||||
|
}
|
||||||
|
|
||||||
// draw your widget
|
// draw your widget
|
||||||
function draw() {
|
function draw() {
|
||||||
|
if (setting('hide')) return;
|
||||||
var width = 24;
|
var width = 24;
|
||||||
if (stp_today > 99999){
|
if (stp_today > 99999){
|
||||||
stp_today = stp_today % 100000; // cap to five digits + comma = 6 characters
|
stp_today = stp_today % 100000; // cap to five digits + comma = 6 characters
|
||||||
}
|
}
|
||||||
let stps = stp_today.toString();
|
let stps = stp_today.toString();
|
||||||
|
if (setting('large')) {
|
||||||
|
draw_large.call(this, stps);
|
||||||
|
return;
|
||||||
|
}
|
||||||
g.reset().clearRect(this.x, this.y, this.x + width, this.y + 23); // erase background
|
g.reset().clearRect(this.x, this.y, this.x + width, this.y + 23); // erase background
|
||||||
if (setting('progress')){ drawProgress.call(this, stps); }
|
if (setting('progress')){ drawProgress.call(this, stps); }
|
||||||
g.setColor(g.theme.fg);
|
g.setColor(g.theme.fg);
|
||||||
|
@ -73,13 +95,16 @@
|
||||||
draw()
|
draw()
|
||||||
}
|
}
|
||||||
|
|
||||||
Bangle.on('step', (up) => {
|
Bangle.on('step', stepCount => {
|
||||||
|
var steps = stepCount-lastStepCount;
|
||||||
|
if (lastStepCount===undefined || steps<0) steps=1;
|
||||||
|
lastStepCount = stepCount;
|
||||||
let date = new Date();
|
let date = new Date();
|
||||||
if (lastUpdate.getDate() == date.getDate()){
|
if (lastUpdate.getDate() == date.getDate()){
|
||||||
stp_today ++;
|
stp_today += steps;
|
||||||
} else {
|
} else {
|
||||||
// TODO: could save this to PEDOMFILE for lastUpdate's day?
|
// TODO: could save this to PEDOMFILE for lastUpdate's day?
|
||||||
stp_today = 1;
|
stp_today = steps;
|
||||||
}
|
}
|
||||||
if (stp_today === setting('goal')
|
if (stp_today === setting('goal')
|
||||||
&& !(require('Storage').readJSON('setting.json',1)||{}).quiet) {
|
&& !(require('Storage').readJSON('setting.json',1)||{}).quiet) {
|
||||||
|
|
|
@ -51,7 +51,7 @@ try{
|
||||||
|
|
||||||
const APP_KEYS = [
|
const APP_KEYS = [
|
||||||
'id', 'name', 'shortName', 'version', 'icon', 'description', 'tags', 'type',
|
'id', 'name', 'shortName', 'version', 'icon', 'description', 'tags', 'type',
|
||||||
'sortorder', 'readme', 'custom', 'interface', 'storage', 'data', 'allow_emulator',
|
'sortorder', 'readme', 'custom', 'customConnect', 'interface', 'storage', 'data', 'allow_emulator',
|
||||||
'dependencies'
|
'dependencies'
|
||||||
];
|
];
|
||||||
const STORAGE_KEYS = ['name', 'url', 'content', 'evaluate', 'noOverwite'];
|
const STORAGE_KEYS = ['name', 'url', 'content', 'evaluate', 'noOverwite'];
|
||||||
|
@ -100,6 +100,7 @@ apps.forEach((app,appIdx) => {
|
||||||
if (!fs.existsSync(appDir+app.icon)) ERROR(`App ${app.id} icon doesn't exist`);
|
if (!fs.existsSync(appDir+app.icon)) ERROR(`App ${app.id} icon doesn't exist`);
|
||||||
if (app.readme && !fs.existsSync(appDir+app.readme)) ERROR(`App ${app.id} README file doesn't exist`);
|
if (app.readme && !fs.existsSync(appDir+app.readme)) ERROR(`App ${app.id} README file doesn't exist`);
|
||||||
if (app.custom && !fs.existsSync(appDir+app.custom)) ERROR(`App ${app.id} custom HTML doesn't exist`);
|
if (app.custom && !fs.existsSync(appDir+app.custom)) ERROR(`App ${app.id} custom HTML doesn't exist`);
|
||||||
|
if (app.customConnect && !app.custom) ERROR(`App ${app.id} has customConnect but no customn HTML`);
|
||||||
if (app.interface && !fs.existsSync(appDir+app.interface)) ERROR(`App ${app.id} interface HTML doesn't exist`);
|
if (app.interface && !fs.existsSync(appDir+app.interface)) ERROR(`App ${app.id} interface HTML doesn't exist`);
|
||||||
if (app.dependencies) {
|
if (app.dependencies) {
|
||||||
if (("object"==typeof app.dependencies) && !Array.isArray(app.dependencies)) {
|
if (("object"==typeof app.dependencies) && !Array.isArray(app.dependencies)) {
|
||||||
|
|
2
core
2
core
|
@ -1 +1 @@
|
||||||
Subproject commit 27f9a7125146a38c4357d679ec783f6e98a983c6
|
Subproject commit 39f89acf1468dc7d58ac54d15a092b2bd6d73cce
|
|
@ -3,14 +3,32 @@
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
|
```
|
||||||
|
var Layout = require("Layout");
|
||||||
var layout = new Layout( layoutObject, btns )
|
var layout = new Layout( layoutObject, btns )
|
||||||
layout.render(optionalObject);
|
layout.render(optionalObject);
|
||||||
|
```
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
var Layout = require("Layout");
|
||||||
|
var layout = new Layout( {
|
||||||
|
type:"v", c: [
|
||||||
|
{type:"txt", font:"20%", label:"12:00" },
|
||||||
|
{type:"txt", font:"6x8", label:"The Date" }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
g.clear();
|
||||||
|
layout.render();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
layoutObject has:
|
layoutObject has:
|
||||||
|
|
||||||
* A `type` field of:
|
* A `type` field of:
|
||||||
* `undefined` - blank, can be used for padding
|
* `undefined` - blank, can be used for padding
|
||||||
* `"txt"` - a text label, with value `label` and `r` for text rotation
|
* `"txt"` - a text label, with value `label` and `r` for text rotation. 'font' is required
|
||||||
* `"btn"` - a button, with value `label` and callback `cb`
|
* `"btn"` - a button, with value `label` and callback `cb`
|
||||||
* `"img"` - an image where the function `src` is called to return an image to draw
|
* `"img"` - an image where the function `src` is called to return an image to draw
|
||||||
* `"custom"` - a custom block where `render(layoutObj)` is called to render
|
* `"custom"` - a custom block where `render(layoutObj)` is called to render
|
||||||
|
@ -83,10 +101,12 @@ function Layout(layout, buttons) {
|
||||||
this._l,
|
this._l,
|
||||||
{type:"v", c: buttons.map(b=>(b.type="btn",b.h=btnHeight,b.w=32,b.r=1,b))}
|
{type:"v", c: buttons.map(b=>(b.type="btn",b.h=btnHeight,b.w=32,b.r=1,b))}
|
||||||
]};
|
]};
|
||||||
Bangle.touchHandler = (_,e) => touchHandler(this._l,e);
|
|
||||||
Bangle.on('touch',Bangle.touchHandler);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (process.env.HWVERSION==2) {
|
||||||
|
Bangle.touchHandler = (_,e) => touchHandler(layout,e);
|
||||||
|
Bangle.on('touch',Bangle.touchHandler);
|
||||||
|
}
|
||||||
|
|
||||||
// add IDs
|
// add IDs
|
||||||
var ll = this;
|
var ll = this;
|
||||||
|
@ -130,7 +150,7 @@ function updateMin(l) {
|
||||||
case "txt": {
|
case "txt": {
|
||||||
if (l.font.endsWith("%"))
|
if (l.font.endsWith("%"))
|
||||||
l.font = "Vector"+Math.round(g.getHeight()*l.font.slice(0,-1)/100);
|
l.font = "Vector"+Math.round(g.getHeight()*l.font.slice(0,-1)/100);
|
||||||
// Not needed in new firmwares - 'font' is enough
|
// FIXME ':'/fsz not needed in new firmwares - it's handled internally
|
||||||
if (l.font.includes(":")) {
|
if (l.font.includes(":")) {
|
||||||
var f = l.font.split(":");
|
var f = l.font.split(":");
|
||||||
l.font = f[0];
|
l.font = f[0];
|
||||||
|
@ -222,8 +242,8 @@ Layout.prototype.render = function (l) {
|
||||||
Layout.prototype.layout = function (l) {
|
Layout.prototype.layout = function (l) {
|
||||||
// l = current layout element
|
// l = current layout element
|
||||||
// exw,exh = extra width/height available
|
// exw,exh = extra width/height available
|
||||||
var fillx = l.c.reduce((a,l)=>a+(0|l.fillx),0);
|
var fillx = l.c && l.c.reduce((a,l)=>a+(0|l.fillx),0);
|
||||||
var filly = l.c.reduce((a,l)=>a+(0|l.filly),0);
|
var filly = l.c && l.c.reduce((a,l)=>a+(0|l.filly),0);
|
||||||
switch (l.type) {
|
switch (l.type) {
|
||||||
case "h": {
|
case "h": {
|
||||||
let x = l.x + (l.w-l._w)/2;
|
let x = l.x + (l.w-l._w)/2;
|
||||||
|
|
|
@ -3,14 +3,32 @@
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
|
```
|
||||||
|
var Layout = require("Layout");
|
||||||
var layout = new Layout( layoutObject, btns )
|
var layout = new Layout( layoutObject, btns )
|
||||||
layout.render(optionalObject);
|
layout.render(optionalObject);
|
||||||
|
```
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
var Layout = require("Layout");
|
||||||
|
var layout = new Layout( {
|
||||||
|
type:"v", c: [
|
||||||
|
{type:"txt", font:"20%", label:"12:00" },
|
||||||
|
{type:"txt", font:"6x8", label:"The Date" }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
g.clear();
|
||||||
|
layout.render();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
layoutObject has:
|
layoutObject has:
|
||||||
|
|
||||||
* A `type` field of:
|
* A `type` field of:
|
||||||
* `undefined` - blank, can be used for padding
|
* `undefined` - blank, can be used for padding
|
||||||
* `"txt"` - a text label, with value `label` and `r` for text rotation
|
* `"txt"` - a text label, with value `label` and `r` for text rotation. 'font' is required
|
||||||
* `"btn"` - a button, with value `label` and callback `cb`
|
* `"btn"` - a button, with value `label` and callback `cb`
|
||||||
* `"img"` - an image where the function `src` is called to return an image to draw
|
* `"img"` - an image where the function `src` is called to return an image to draw
|
||||||
* `"custom"` - a custom block where `render(layoutObj)` is called to render
|
* `"custom"` - a custom block where `render(layoutObj)` is called to render
|
||||||
|
@ -83,10 +101,12 @@ function Layout(layout, buttons) {
|
||||||
this._l,
|
this._l,
|
||||||
{type:"v", c: buttons.map(b=>(b.type="btn",b.h=btnHeight,b.w=32,b.r=1,b))}
|
{type:"v", c: buttons.map(b=>(b.type="btn",b.h=btnHeight,b.w=32,b.r=1,b))}
|
||||||
]};
|
]};
|
||||||
Bangle.touchHandler = (_,e) => touchHandler(this._l,e);
|
|
||||||
Bangle.on('touch',Bangle.touchHandler);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (process.env.HWVERSION==2) {
|
||||||
|
Bangle.touchHandler = (_,e) => touchHandler(layout,e);
|
||||||
|
Bangle.on('touch',Bangle.touchHandler);
|
||||||
|
}
|
||||||
|
|
||||||
// add IDs
|
// add IDs
|
||||||
var ll = this;
|
var ll = this;
|
||||||
|
@ -130,7 +150,7 @@ function updateMin(l) {
|
||||||
case "txt": {
|
case "txt": {
|
||||||
if (l.font.endsWith("%"))
|
if (l.font.endsWith("%"))
|
||||||
l.font = "Vector"+Math.round(g.getHeight()*l.font.slice(0,-1)/100);
|
l.font = "Vector"+Math.round(g.getHeight()*l.font.slice(0,-1)/100);
|
||||||
// Not needed in new firmwares - 'font' is enough
|
// FIXME ':'/fsz not needed in new firmwares - it's handled internally
|
||||||
if (l.font.includes(":")) {
|
if (l.font.includes(":")) {
|
||||||
var f = l.font.split(":");
|
var f = l.font.split(":");
|
||||||
l.font = f[0];
|
l.font = f[0];
|
||||||
|
@ -222,8 +242,8 @@ Layout.prototype.render = function (l) {
|
||||||
Layout.prototype.layout = function (l) {
|
Layout.prototype.layout = function (l) {
|
||||||
// l = current layout element
|
// l = current layout element
|
||||||
// exw,exh = extra width/height available
|
// exw,exh = extra width/height available
|
||||||
var fillx = l.c.reduce((a,l)=>a+(0|l.fillx),0);
|
var fillx = l.c && l.c.reduce((a,l)=>a+(0|l.fillx),0);
|
||||||
var filly = l.c.reduce((a,l)=>a+(0|l.filly),0);
|
var filly = l.c && l.c.reduce((a,l)=>a+(0|l.filly),0);
|
||||||
switch (l.type) {
|
switch (l.type) {
|
||||||
case "h": {
|
case "h": {
|
||||||
let x = l.x + (l.w-l._w)/2;
|
let x = l.x + (l.w-l._w)/2;
|
||||||
|
|
Loading…
Reference in New Issue