2022-01-20 17:33:48 +00:00
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<title>Bangle.js Accelerometer streaming</title>
|
2022-07-02 23:58:52 +00:00
|
|
|
<link rel="stylesheet" href="../../css/spectre.min.css">
|
2022-01-20 17:33:48 +00:00
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<script src="https://www.puck-js.com/puck.js"></script>
|
2022-06-18 10:10:52 +00:00
|
|
|
<p>
|
2022-07-02 23:58:52 +00:00
|
|
|
<div class="form-group">
|
|
|
|
<label class="form-switch">
|
|
|
|
<input type="checkbox" id="chkLocal">
|
|
|
|
<i class="form-icon"></i> Store on bangle (file named log.csv)
|
|
|
|
</label>
|
|
|
|
</div>
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
<button id="btnConnect" class="btn btn-primary">Start</button>
|
|
|
|
<button id="btnStop" class="btn btn-secondary">Stop</button>
|
|
|
|
<button id="btnReset" class="btn btn-secondary">Reset</button>
|
|
|
|
<button id="btnSave" class="btn btn-primary">Save CSV</button>
|
|
|
|
<button id="btnDownload" class="btn btn-primary">Download CSV</button>
|
2022-06-18 10:10:52 +00:00
|
|
|
</p>
|
2022-01-20 17:33:48 +00:00
|
|
|
<p id="result"></p>
|
|
|
|
<script>
|
2022-07-02 23:58:52 +00:00
|
|
|
|
|
|
|
function saveCSV(filename, csvData) {
|
|
|
|
let a = document.createElement("a"),
|
|
|
|
file = new Blob([csvData], {type: "Comma-separated value file"});
|
|
|
|
let url = URL.createObjectURL(file);
|
|
|
|
a.href = url;
|
|
|
|
a.download = filename+".csv";
|
|
|
|
document.body.appendChild(a);
|
|
|
|
a.click();
|
|
|
|
setTimeout(function() {
|
|
|
|
document.body.removeChild(a);
|
|
|
|
window.URL.revokeObjectURL(url);
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
|
2022-06-18 10:10:52 +00:00
|
|
|
function createCode(){
|
2022-06-19 13:36:05 +00:00
|
|
|
//modes: 1 BT, 2 File
|
2022-06-18 10:10:52 +00:00
|
|
|
return "var method=" + (document.getElementById("chkLocal").checked ? 2 : 1) + ";\n" + String.raw`
|
|
|
|
var accData=[];
|
|
|
|
var maxSize=0;
|
|
|
|
var filename="log.csv";
|
|
|
|
|
|
|
|
var gotHRMraw = false;
|
|
|
|
var gotBTHRM = false;
|
|
|
|
var gotHRM = false;
|
|
|
|
var gotAcc = false;
|
2022-06-19 13:36:05 +00:00
|
|
|
|
|
|
|
var events = -1;
|
|
|
|
var hrmRaw,hrmPulse,bthrmPulse
|
2022-06-18 10:10:52 +00:00
|
|
|
|
|
|
|
function gotAll(){
|
2022-06-19 13:36:05 +00:00
|
|
|
return gotBTHRM && gotHRM && gotHRMraw && gotAcc;
|
2022-06-18 10:10:52 +00:00
|
|
|
}
|
2022-01-20 17:33:48 +00:00
|
|
|
|
2022-06-18 10:10:52 +00:00
|
|
|
Bangle.setHRMPower(1);
|
|
|
|
if (Bangle.setBTHRMPower){
|
|
|
|
Bangle.setBTHRMPower(1);
|
|
|
|
} else {
|
|
|
|
gotBTHRM = true;
|
|
|
|
}
|
2022-01-20 17:33:48 +00:00
|
|
|
|
2022-06-18 10:10:52 +00:00
|
|
|
var write=null;
|
|
|
|
|
|
|
|
if (method == 2){
|
|
|
|
var f = require('Storage').open(filename,"w");
|
|
|
|
f.erase();
|
|
|
|
f = require('Storage').open(filename,"a");
|
2022-06-19 13:36:05 +00:00
|
|
|
write = function(str){f.write(str);events++;};
|
2022-06-18 10:10:52 +00:00
|
|
|
} else if (method == 1){
|
2022-06-19 13:36:05 +00:00
|
|
|
write = function(str){Bluetooth.print("DATA: " + str);events++;};
|
2022-06-18 10:10:52 +00:00
|
|
|
}
|
2022-01-20 17:33:48 +00:00
|
|
|
|
2022-06-18 10:10:52 +00:00
|
|
|
write("Time,Acc_x,Acc_y,Acc_z,HRM_b,HRM_c,HRM_r,HRM_f,PPG_r,PPG_o,BTHRM\n");
|
2022-01-20 17:33:48 +00:00
|
|
|
|
|
|
|
|
2022-06-18 10:10:52 +00:00
|
|
|
function writeAcc(e){
|
|
|
|
gotAcc = true;
|
2022-06-19 13:36:05 +00:00
|
|
|
acc = e;
|
2022-06-18 10:10:52 +00:00
|
|
|
e.date=Date.now();
|
|
|
|
accData.push(e);
|
|
|
|
accData.splice(0, accData.length - maxSize);
|
|
|
|
}
|
2022-01-20 17:33:48 +00:00
|
|
|
|
2022-06-18 10:10:52 +00:00
|
|
|
function writeAccDirect(e){
|
|
|
|
gotAcc = true;
|
2022-06-19 13:36:05 +00:00
|
|
|
acc = e;
|
2022-06-18 10:10:52 +00:00
|
|
|
if (!gotAll()) return;
|
|
|
|
write(Date.now()+","+e.x+","+e.y+","+e.z+",,,,,,,,\n");
|
|
|
|
}
|
2022-01-20 17:33:48 +00:00
|
|
|
|
2022-06-18 10:10:52 +00:00
|
|
|
function writeBTHRM(e){
|
|
|
|
gotBTHRM = true;
|
2022-06-19 13:36:05 +00:00
|
|
|
bthrmPulse = e.bpm;
|
2022-06-18 10:10:52 +00:00
|
|
|
if (!gotAll()) return;
|
|
|
|
write(Date.now()+",,,,,,,,,,"+e.bpm+"\n");
|
|
|
|
}
|
2022-01-20 17:33:48 +00:00
|
|
|
|
2022-06-18 10:10:52 +00:00
|
|
|
function writeHRM(e){
|
|
|
|
gotHRM = true;
|
2022-06-19 13:36:05 +00:00
|
|
|
hrmPulse = e.bpm;
|
2022-06-18 10:10:52 +00:00
|
|
|
if (!gotAll()) return;
|
|
|
|
while(accData.length > 0){
|
|
|
|
var c = accData.shift();
|
|
|
|
if (c) write(c.date+","+c.x+","+c.y+","+c.z+",,,,,,,,\n");
|
|
|
|
}
|
|
|
|
write(Date.now()+",,,,"+e.bpm+","+e.confidence+",,,,\n");
|
2022-01-20 17:33:48 +00:00
|
|
|
}
|
|
|
|
|
2022-06-18 10:10:52 +00:00
|
|
|
function writeHRMraw(e){
|
|
|
|
gotHRMraw = true;
|
2022-06-19 13:36:05 +00:00
|
|
|
hrmRaw = e.raw;
|
2022-06-18 10:10:52 +00:00
|
|
|
if (!gotAll()) return;
|
|
|
|
write(Date.now()+",,,,,,"+e.raw+","+e.filt+","+e.vcPPG+","+e.vcPPGoffs+",\n");
|
|
|
|
}
|
2022-01-20 17:33:48 +00:00
|
|
|
|
2022-06-18 10:10:52 +00:00
|
|
|
if(maxSize){
|
|
|
|
Bangle.on("accel", writeAcc);
|
|
|
|
} else {
|
|
|
|
Bangle.on("accel", writeAccDirect);
|
2022-01-20 17:33:48 +00:00
|
|
|
}
|
2022-06-18 10:10:52 +00:00
|
|
|
Bangle.on("HRM-raw", writeHRMraw);
|
|
|
|
Bangle.on("HRM", writeHRM);
|
|
|
|
Bangle.on("BTHRM", writeBTHRM);
|
|
|
|
|
|
|
|
g.clear();
|
|
|
|
|
2022-06-19 13:36:05 +00:00
|
|
|
function drawStatusText(name, y){
|
|
|
|
g.setFont12x20();
|
|
|
|
g.setColor(g.theme.fg);
|
|
|
|
g.drawString(name, 24, y * 22 + 2);
|
|
|
|
}
|
2022-01-20 17:33:48 +00:00
|
|
|
|
2022-06-19 13:36:05 +00:00
|
|
|
function drawStatus(isOk, y, value){
|
|
|
|
g.setFont12x20();
|
|
|
|
if (isOk) g.setColor(0,1,0); else g.setColor(1,0,0);
|
|
|
|
g.fillRect(0,y * 22, 20, y * 22 + 20);
|
|
|
|
g.setColor(g.theme.bg);
|
|
|
|
let x = 120
|
|
|
|
g.fillRect(x,y*22,g.getWidth(),y*22+20);
|
|
|
|
g.setColor(g.theme.fg);
|
|
|
|
if (value) g.drawString(value, x, y * 22 + 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateStatus(){
|
|
|
|
let h = 1;
|
|
|
|
drawStatus(gotAcc, h++);
|
|
|
|
drawStatus(gotBTHRM, h++, bthrmPulse); bthrmPulse = null;
|
|
|
|
drawStatus(gotHRM, h++, hrmPulse); hrmPulse = null;
|
|
|
|
drawStatus(gotHRMraw, h++, hrmRaw); hrmRaw = null;
|
|
|
|
drawStatus(events>0, h++, Math.max(events,0));
|
|
|
|
if (method == 2){
|
|
|
|
let free = require('Storage').getFree();
|
|
|
|
drawStatus(free>0.25*process.env.STORAGE, h++, Math.floor(free/1024) + "K");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-18 10:10:52 +00:00
|
|
|
var intervalId = -1;
|
2022-06-19 13:36:05 +00:00
|
|
|
|
|
|
|
g.setFont12x20();
|
|
|
|
g.setColor(g.theme.fg);
|
|
|
|
g.drawString("Target " + (method==2?"log.csv":"Bluetooth"), 0, 2);
|
|
|
|
|
|
|
|
let h = 1;
|
|
|
|
drawStatusText("Acc", h++);
|
|
|
|
drawStatusText("BTHRM", h++);
|
|
|
|
drawStatusText("HRM", h++);
|
|
|
|
drawStatusText("HRM_r", h++);
|
|
|
|
drawStatusText("Events", h++);
|
|
|
|
if (method == 2) drawStatusText("Storage", h++);
|
|
|
|
updateStatus();
|
|
|
|
|
2022-01-20 17:33:48 +00:00
|
|
|
intervalId = setInterval(()=>{
|
2022-06-19 13:36:05 +00:00
|
|
|
updateStatus();
|
2022-06-18 10:10:52 +00:00
|
|
|
}, 1000);
|
|
|
|
|
|
|
|
if (Bangle.setBTHRMPower){
|
|
|
|
intervalId = setInterval(()=>{
|
|
|
|
if (!Bangle.isBTHRMOn()) Bangle.setBTHRMPower(1);
|
|
|
|
}, 5000);
|
|
|
|
}
|
|
|
|
`;
|
2022-01-20 17:33:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var connection;
|
|
|
|
var lineCount=-1;
|
|
|
|
|
|
|
|
function stop (){
|
2022-06-18 10:10:52 +00:00
|
|
|
connection.reconnect((c)=>{
|
|
|
|
c.write("load();\n");
|
|
|
|
c.close();
|
2022-01-20 17:33:48 +00:00
|
|
|
connection = undefined;
|
2022-06-18 10:10:52 +00:00
|
|
|
});
|
2022-01-20 17:33:48 +00:00
|
|
|
}
|
|
|
|
|
2022-07-02 23:58:52 +00:00
|
|
|
function updateButtons(){
|
2022-06-18 10:10:52 +00:00
|
|
|
document.getElementById("btnSave").disabled = document.getElementById("chkLocal").checked;
|
2022-07-02 23:58:52 +00:00
|
|
|
document.getElementById("btnDownload").disabled = !document.getElementById("chkLocal").checked;
|
2022-06-18 10:10:52 +00:00
|
|
|
document.getElementById("btnReset").disabled = document.getElementById("chkLocal").checked;
|
|
|
|
document.getElementById("btnStop").disabled = document.getElementById("chkLocal").checked;
|
2022-07-02 23:58:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
updateButtons();
|
|
|
|
|
|
|
|
document.getElementById("chkLocal").addEventListener("click", function() {
|
|
|
|
reset();
|
|
|
|
updateButtons();
|
|
|
|
});
|
|
|
|
|
|
|
|
window.addEventListener("message", function(event) {
|
|
|
|
let msg = event.data;
|
|
|
|
if (msg.type=="readstoragefilersp") {
|
|
|
|
saveCSV("log.csv", msg.data);
|
|
|
|
}
|
|
|
|
}, false);
|
|
|
|
|
|
|
|
document.getElementById("btnDownload").addEventListener("click", function() {
|
|
|
|
if (connection) {
|
|
|
|
stop();
|
|
|
|
}
|
|
|
|
console.log("Loading data from BangleJs...");
|
|
|
|
try {
|
|
|
|
window.postMessage({type:"readstoragefile",data:"log.csv",id:0});
|
|
|
|
} catch(ex) {
|
|
|
|
console.log("(Warning) Could not load apikey from BangleJs.");
|
|
|
|
console.log(ex);
|
|
|
|
}
|
2022-06-18 10:10:52 +00:00
|
|
|
});
|
|
|
|
|
2022-01-20 17:33:48 +00:00
|
|
|
document.getElementById("btnSave").addEventListener("click", function() {
|
2022-07-02 23:58:52 +00:00
|
|
|
saveCSV("log.csv", localStorage.getItem("data"));
|
2022-01-20 17:33:48 +00:00
|
|
|
});
|
2022-07-02 23:58:52 +00:00
|
|
|
|
|
|
|
function reset(){
|
|
|
|
document.getElementById("result").innerText="";
|
|
|
|
}
|
|
|
|
|
2022-01-20 17:33:48 +00:00
|
|
|
document.getElementById("btnReset").addEventListener("click", function() {
|
|
|
|
if (connection) {
|
|
|
|
stop();
|
|
|
|
}
|
|
|
|
lineCount=-1;
|
|
|
|
localStorage.removeItem("data");
|
2022-07-02 23:58:52 +00:00
|
|
|
reset();
|
2022-01-20 17:33:48 +00:00
|
|
|
});
|
2022-07-02 23:58:52 +00:00
|
|
|
|
2022-01-20 17:33:48 +00:00
|
|
|
document.getElementById("btnStop").addEventListener("click", function() {
|
|
|
|
if (connection) {
|
|
|
|
stop();
|
|
|
|
}
|
|
|
|
});
|
2022-07-02 23:58:52 +00:00
|
|
|
|
|
|
|
function connect(connectionHandler){
|
|
|
|
Puck.connect(function(c) {
|
|
|
|
if (!c) {
|
|
|
|
console.log("Couldn't connect!\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
connection = c;
|
|
|
|
connectionHandler(c);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-01-20 17:33:48 +00:00
|
|
|
document.getElementById("btnConnect").addEventListener("click", function() {
|
|
|
|
localStorage.setItem("data", "");
|
2022-06-19 13:36:05 +00:00
|
|
|
lineCount=-1;
|
2022-01-20 17:33:48 +00:00
|
|
|
if (connection) {
|
|
|
|
stop();
|
|
|
|
document.getElementById("result").innerText="0";
|
|
|
|
}
|
2022-07-02 23:58:52 +00:00
|
|
|
connect(function(connection) {
|
2022-01-20 17:33:48 +00:00
|
|
|
var buf = "";
|
|
|
|
connection.on("data", function(d) {
|
|
|
|
buf += d;
|
|
|
|
var l = buf.split("\n");
|
|
|
|
buf = l.pop();
|
|
|
|
l.forEach(onLine);
|
|
|
|
});
|
|
|
|
connection.write("reset();\n", function() {
|
|
|
|
setTimeout(function() {
|
2022-06-18 10:10:52 +00:00
|
|
|
connection.write("\x03\x10if(1){"+createCode()+"}\n",
|
2022-01-20 17:33:48 +00:00
|
|
|
function() { console.log("Ready..."); });
|
|
|
|
}, 1500);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
function onLine(line) {
|
|
|
|
console.log("RECEIVED:"+line);
|
|
|
|
if (line.startsWith("DATA:")){
|
|
|
|
localStorage.setItem("data", localStorage.getItem("data") + line.substr(5) + "\n");
|
|
|
|
lineCount++;
|
|
|
|
document.getElementById("result").innerText="Captured events: " + lineCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html>
|