-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from espruino/master
Merge
- Loading branch information
Showing
29 changed files
with
575 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
0.01: New App! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# Espruino Programmer | ||
|
||
Finds Bluetooth devices with a specific name (eg `Puck.js`), connects and uploads code. Great for programming many devices at once! | ||
|
||
**WARNING:** This will reprogram **any matching Espruino device within range** while | ||
the app is running. Unless you are careful to remove other devices from the area or | ||
turn them off, you could find some of your devices unexpectedly get programmed! | ||
|
||
## Customising | ||
|
||
Click on the Customise button in the app loader to set up the programmer. | ||
|
||
* First you need to choose the kind of devices you want to upload to. This is | ||
the text that should match the Bluetooth advertising name. So `Puck.js` for Puck.js | ||
devices, or `Bangle.js` for Bangles. | ||
* Now paste in the code you want to write to the device. This is automatically | ||
written to flash (`.bootcde`). See https://www.espruino.com/Saving#save-on-send-to-flash- | ||
for more information. | ||
* Now enter the code that should be sent **after** programming. This code | ||
should make the device so it doesn't advertise on Bluetooth with the Bluetooth | ||
name you entered for the first item. It may also help if it indicates to you that | ||
the device is programmed properly. | ||
* You could turn advertising off with `NRF.sleep()` | ||
* You could change the advertising name with `NRF.setAdvertising({},{name:"Ok"});` | ||
* On a Bangle, you could turn it off with `Bangle.off()` | ||
* Finally scroll down and click `Upload` | ||
* Now you can run the new `Programmer` app on the Bangle. | ||
|
||
## Usage | ||
|
||
Just run the app, and as soon as it starts it'll start scanning for | ||
devices to upload to! | ||
|
||
To stop scanning, long-press the button to return to the clock. | ||
|
||
## Notes | ||
|
||
* Right now the Espruino Tools used here are unaware of the device they're writing to, | ||
and as a result they don't use Storage and so the size of the files you can | ||
write to the device are quite limited. You should be find with up to 4k of code. | ||
* Currently, code is not minified before upload (so you need to supply pre-minified | ||
code if you want that) |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
var uart; // require("ble_uart") | ||
var device; // BluetoothDevice | ||
var uploadTimeout; // a timeout used during upload - if we disconnect, kill this | ||
Bangle.loadWidgets(); | ||
|
||
var json = require("Storage").readJSON("espruinoprog.json",1); | ||
/*var json = { // for example | ||
namePrefix : "Puck.js ", | ||
code : "E.setBootCode('digitalPulse(LED2,1,100);')", | ||
post : "LED.set();NRF.sleep()", | ||
};*/ | ||
|
||
if ("object" != typeof json) { | ||
E.showAlert("JSON not found","Programmer").then(() => load()); | ||
throw new Error("JSON not found"); | ||
// stops execution | ||
} | ||
|
||
// Set up terminal | ||
var R = Bangle.appRect; | ||
var termg = Graphics.createArrayBuffer(R.w, R.h, 1, {msb:true}); | ||
termg.setFont("6x8"); | ||
var term; | ||
|
||
function showTerminal() { | ||
E.showMenu(); // clear anything that was drawn | ||
if (term) term.print(""); // redraw terminal | ||
} | ||
|
||
function scanAndConnect() { | ||
termg.clear(); | ||
term = require("VT100").connect(termg, { | ||
charWidth : 6, | ||
charHeight : 8 | ||
}); | ||
term.print = str => { | ||
for (var i of str) term.char(i); | ||
g.reset().drawImage(termg,R.x,R.y); | ||
}; | ||
term.print(`\r\nScanning...\r\n`); | ||
NRF.requestDevice({ filters: [{ namePrefix: json.namePrefix }] }).then(function(dev) { | ||
term.print(`Found ${dev.name||dev.id.substr(0,17)}\r\n`); | ||
device = dev; | ||
|
||
term.print(`Connect to ${dev.name||dev.id.substr(0,17)}...\r\n`); | ||
device.removeAllListeners(); | ||
device.on('gattserverdisconnected', function(reason) { | ||
if (!uart) return; | ||
term.print(`\r\nDISCONNECTED (${reason})\r\n`); | ||
uart = undefined; | ||
device = undefined; | ||
if (uploadTimeout) clearTimeout(uploadTimeout); | ||
uploadTimeout = undefined; | ||
setTimeout(scanAndConnect, 1000); | ||
}); | ||
require("ble_uart").connect(device).then(function(u) { | ||
uart = u; | ||
term.print("Connected...\r\n"); | ||
uart.removeAllListeners(); | ||
uart.on('data', function(d) { term.print(d); }); | ||
uart.write(json.code+"\n").then(() => { | ||
term.print("\r\nUpload Complete...\r\n"); | ||
// main upload completed - wait a bit | ||
uploadTimeout = setTimeout(function() { | ||
term.print("\r\nFinal Upload...\r\n"); | ||
// now upload the code to run after... | ||
uart.write(json.post+"\n").then(() => { | ||
term.print("\r\nDone.\r\n"); | ||
// now wait and disconnect (if not already done!) | ||
uploadTimeout = setTimeout(function() { | ||
term.print("\r\nDisconnecting...\r\n"); | ||
if (uart) uart.disconnect(); | ||
}, 500); | ||
}); | ||
}, 1000); | ||
}); | ||
}); | ||
}).catch(err => { | ||
if (err.toString().startsWith("No device found")) { | ||
// expected - try again | ||
scanAndConnect(); | ||
} else | ||
term.print(`\r\ERROR ${err.toString()}\r\n`); | ||
}); | ||
} | ||
|
||
// now start | ||
Bangle.drawWidgets(); | ||
showTerminal(); | ||
scanAndConnect(); |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
<html> | ||
|
||
<head> | ||
<link rel="stylesheet" href="../../css/spectre.min.css"> | ||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.32.0/codemirror.min.css"> | ||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.52.2/addon/lint/lint.min.css"> | ||
</head> | ||
|
||
<body> | ||
<script src="../../core/lib/customize.js"></script> | ||
<script src="../../core/lib/espruinotools.js"></script> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.32.0/codemirror.min.js"></script> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.52.2/mode/javascript/javascript.min.js"></script> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.52.2/addon/lint/lint.min.js"></script> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.52.2/addon/lint/javascript-lint.min.js"></script> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.52.2/addon/hint/javascript-hint.min.js"></script> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jshint/2.11.0/jshint.min.js"></script> | ||
<p>Upload code to devices with names starting with:</p> | ||
<p><input type="text" id="nameprefix"></input></p> | ||
<p>Enter your program to upload here:</p> | ||
<p><textarea id="js-code"></textarea></p> | ||
<p>Enter the code to send after upload here:</p> | ||
<p><textarea id="post-code"></textarea></p> | ||
<p>Then click <button id="upload" class="btn btn-primary">Upload</button> <span id="btninfo" style="color:orange"></span> </p> | ||
<p><a id="setdefault">Click here</a> to reset to defaults.</p> | ||
<script> | ||
const LS_JSCODE = "espruinoprog.code"; | ||
const LS_POSTCODE = "espruinoprog.postcode"; | ||
const LS_NAMEPREFIX = "espruinoprog.namePrefix"; | ||
var jseditor,posteditor; | ||
|
||
function setDefaults() { | ||
if (localStorage.getItem(LS_JSCODE) === null) { | ||
localStorage.setItem(LS_JSCODE, `// Flash LED2 every 2 seconds | ||
setInterval(function() { | ||
LED2.set(); | ||
setTimeout(function() { | ||
LED2.reset(); | ||
}, 100); | ||
}, 2000);`); | ||
} | ||
if (localStorage.getItem(LS_POSTCODE) === null) { | ||
localStorage.setItem(LS_POSTCODE, `// Turn red LED on to show programmed | ||
// Bluetooth off to stop this getting re-programmed | ||
LED.set();NRF.sleep();`); | ||
} | ||
if (localStorage.getItem(LS_NAMEPREFIX) === null) { | ||
localStorage.setItem(LS_NAMEPREFIX, "Puck.js"); | ||
} | ||
document.getElementById("js-code").value = localStorage.getItem(LS_JSCODE); | ||
if (jseditor) jseditor.setValue(document.getElementById("js-code").value); | ||
document.getElementById("post-code").value = localStorage.getItem(LS_POSTCODE); | ||
if (posteditor) posteditor.setValue(document.getElementById("post-code").value); | ||
document.getElementById("nameprefix").value = localStorage.getItem(LS_NAMEPREFIX); | ||
} | ||
setDefaults(); | ||
|
||
|
||
|
||
// The code editor | ||
var lintFlags = { | ||
esversion: 6, // Enable ES6 for literals, arrow fns, binary | ||
evil: true, // don't warn on use of strings in setInterval | ||
laxbreak: true, // don't warn about newlines in expressions | ||
laxcomma: true // don't warn about commas at the start of the line | ||
}; | ||
jseditor = CodeMirror.fromTextArea(document.getElementById("js-code"), { | ||
width: "100%", | ||
height: "auto", | ||
matchBrackets: true, | ||
mode: { name: "javascript", globalVars: false }, | ||
lineWrapping: true, | ||
showTrailingSpace: true, | ||
lint: lintFlags, | ||
gutters: ["CodeMirror-linenumbers", "CodeMirror-lint-markers"], | ||
lineNumbers: true | ||
}); | ||
posteditor = CodeMirror.fromTextArea(document.getElementById("post-code"), { | ||
width: "100%", | ||
height: "auto", | ||
matchBrackets: true, | ||
mode: { name: "javascript", globalVars: false }, | ||
lineWrapping: true, | ||
showTrailingSpace: true, | ||
lint: lintFlags, | ||
gutters: ["CodeMirror-linenumbers", "CodeMirror-lint-markers"], | ||
lineNumbers: true | ||
}); | ||
function hasWarnings() { | ||
return jseditor.state.lint.marked.length!=0 || posteditor.state.lint.marked.length!=0; | ||
} | ||
var editorChangedTimeout; | ||
function editorChanged() { | ||
if (editorChangedTimeout) clearTimeout(editorChangedTimeout); | ||
editorChangedTimeout = setTimeout(function() { | ||
if (hasWarnings()) { | ||
document.getElementById("btninfo").innerHTML = "There are warnings in the code to be uploaded"; | ||
document.getElementById("upload").classList.add("disabled"); | ||
} else { | ||
document.getElementById("btninfo").innerHTML = ""; | ||
document.getElementById("upload").classList.remove("disabled"); | ||
} | ||
}, 500); | ||
} | ||
|
||
jseditor.on("change", editorChanged); | ||
posteditor.on("change", editorChanged); | ||
|
||
document.getElementById("upload").addEventListener("click", function() { | ||
if (!hasWarnings()) { | ||
var jscode = jseditor.getValue(); | ||
var postcode = posteditor.getValue(); | ||
var namePrefix = document.getElementById("nameprefix").value; | ||
localStorage.setItem(LS_JSCODE, jscode); | ||
localStorage.setItem(LS_POSTCODE, postcode); | ||
localStorage.setItem(LS_NAMEPREFIX, namePrefix); | ||
|
||
Espruino.transform(jscode, { | ||
SET_TIME_ON_WRITE : false, // time would just be out of date | ||
SAVE_ON_SEND : 1, // save to flash | ||
LOAD_STORAGE_FILE : 0, // do not load from storage after saving | ||
// PRETOKENISE : true, | ||
// MINIFICATION_LEVEL : "ESPRIMA", // maybe? | ||
}).then(content => { | ||
sendCustomizedApp({ | ||
storage: [{ name: "espruinoprog.json", content: JSON.stringify({ | ||
namePrefix : namePrefix, | ||
code : Espruino.Core.CodeWriter.reformatCode(content), | ||
post : Espruino.Core.CodeWriter.reformatCode(postcode) | ||
})}] | ||
}); | ||
}); | ||
} | ||
}); | ||
document.getElementById("setdefault").addEventListener("click", function(e) { | ||
e.preventDefault(); | ||
localStorage.removeItem(LS_JSCODE); | ||
localStorage.removeItem(LS_POSTCODE); | ||
localStorage.removeItem(LS_NAMEPREFIX); | ||
setDefaults(); | ||
}); | ||
</script> | ||
</body> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"id": "espruinoprog", | ||
"name": "Espruino Programmer", | ||
"shortName": "Programmer", | ||
"version": "0.01", | ||
"description": "Finds Bluetooth devices with a specific name (eg 'Puck.js'), connects and uploads code. Great for programming many devices at once!", | ||
"icon": "app.png", | ||
"tags": "tool,bluetooth", | ||
"supports": ["BANGLEJS","BANGLEJS2"], | ||
"readme": "README.md", | ||
"custom": "custom.html", | ||
"storage": [ | ||
{"name":"espruinoprog.app.js","url":"app.js"}, | ||
{"name":"espruinoprog.img","url":"app-icon.js","evaluate":true}, | ||
{"name":"espruinoprog.json"} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
0.01: New App! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Espruino Terminal | ||
|
||
Send commands to other Espruino devices via the Bluetooth UART interface and | ||
see the result on a terminal. | ||
|
||
## Customising | ||
|
||
Once installed and you're connected to the Bangle you can click the button next to the app in the app loader | ||
to change the commands (they will be read from the device). | ||
|
||
When done, click `Save to Bangle.js` and your changes will be saved to the same device. | ||
|
||
## Usage | ||
|
||
* Load the app and after a few seconds you'll see a menu with Espruino devices | ||
in the vicinity. | ||
* Tap on the device you want to connect to | ||
* A terminal will pop up showing `Connecting...` and then `Connected` | ||
* Now tap on the right (or press the button) to bring up a menu with options for commands, or the option to disconnect. | ||
|
||
You can also choose `Custom` in which case a keyboard (using the currently installed text input method) will | ||
be displayed and you can enter the command you would like to send. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
require("heatshrink").decompress(atob("mEwwcCpMkyQC/AVW//4AK/oR/COD8LCP4R/CK8DCKNsCKFt2BHPhu2CJ8BCKAjQI4OQNaIUB23bsCPMCJzp/CP4Rf/4AKCKwC/AVIA==")) |
Oops, something went wrong.