0.02: Add 'pre' code that can erase the device

Wait more between sending code snippets
      Now force use of 'Storage' (assume 2v00 or later)
master
Gordon Williams 2022-08-02 11:28:14 +01:00
parent 2288b4d029
commit 73bafd4b5d
5 changed files with 66 additions and 22 deletions

View File

@ -1 +1,4 @@
0.01: New App! 0.01: New App!
0.02: Add 'pre' code that can erase the device
Wait more between sending code snippets
Now force use of 'Storage' (assume 2v00 or later)

View File

@ -13,6 +13,9 @@ 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 * 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 the text that should match the Bluetooth advertising name. So `Puck.js` for Puck.js
devices, or `Bangle.js` for Bangles. devices, or `Bangle.js` for Bangles.
* In the next box, you have code to run before the upload of the main code. By default
the code `require("Storage").list().forEach(f=>require("Storage").erase(f));reset();` will
erase all files on the device and reset it.
* Now paste in the code you want to write to the device. This is automatically * 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- written to flash (`.bootcde`). See https://www.espruino.com/Saving#save-on-send-to-flash-
for more information. for more information.
@ -35,8 +38,6 @@ To stop scanning, long-press the button to return to the clock.
## Notes ## Notes
* Right now the Espruino Tools used here are unaware of the device they're writing to, * This assumes the device being written to is at least version 2v00 of Espruino
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 * Currently, code is not minified before upload (so you need to supply pre-minified
code if you want that) code if you want that)

View File

@ -58,21 +58,31 @@ function scanAndConnect() {
term.print("Connected...\r\n"); term.print("Connected...\r\n");
uart.removeAllListeners(); uart.removeAllListeners();
uart.on('data', function(d) { term.print(d); }); uart.on('data', function(d) { term.print(d); });
uart.write(json.code+"\n").then(() => { term.print("Upload initial...\r\n");
term.print("\r\nUpload Complete...\r\n"); uart.write((json.pre||"")+"\n").then(() => {
term.print("\r\Done.\r\n");
uploadTimeout = setTimeout(function() {
uploadTimeout = undefined;
term.print("\r\nUpload Code...\r\n");
uart.write((json.code||"")+"\n").then(() => {
term.print("\r\Done.\r\n");
// main upload completed - wait a bit // main upload completed - wait a bit
uploadTimeout = setTimeout(function() { uploadTimeout = setTimeout(function() {
term.print("\r\nFinal Upload...\r\n"); uploadTimeout = undefined;
term.print("\r\Upload final...\r\n");
// now upload the code to run after... // now upload the code to run after...
uart.write(json.post+"\n").then(() => { uart.write((json.post||"")+"\n").then(() => {
term.print("\r\nDone.\r\n"); term.print("\r\nDone.\r\n");
// now wait and disconnect (if not already done!) // now wait and disconnect (if not already done!)
uploadTimeout = setTimeout(function() { uploadTimeout = setTimeout(function() {
uploadTimeout = undefined;
term.print("\r\nDisconnecting...\r\n"); term.print("\r\nDisconnecting...\r\n");
if (uart) uart.disconnect(); if (uart) uart.disconnect();
}, 500); }, 500);
}); });
}, 1000); }, 2000);
});
}, 2000);
}); });
}); });
}).catch(err => { }).catch(err => {

View File

@ -17,6 +17,8 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/jshint/2.11.0/jshint.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>Upload code to devices with names starting with:</p>
<p><input type="text" id="nameprefix"></input></p> <p><input type="text" id="nameprefix"></input></p>
<p>Enter the code to send before upload here:</p>
<p><textarea id="pre-code"></textarea></p>
<p>Enter your program to upload here:</p> <p>Enter your program to upload here:</p>
<p><textarea id="js-code"></textarea></p> <p><textarea id="js-code"></textarea></p>
<p>Enter the code to send after upload here:</p> <p>Enter the code to send after upload here:</p>
@ -24,12 +26,17 @@
<p>Then click <button id="upload" class="btn btn-primary">Upload</button>&nbsp;<span id="btninfo" style="color:orange"></span> </p> <p>Then click <button id="upload" class="btn btn-primary">Upload</button>&nbsp;<span id="btninfo" style="color:orange"></span> </p>
<p><a id="setdefault">Click here</a> to reset to defaults.</p> <p><a id="setdefault">Click here</a> to reset to defaults.</p>
<script> <script>
const LS_PRECODE = "espruinoprog.precode";
const LS_JSCODE = "espruinoprog.code"; const LS_JSCODE = "espruinoprog.code";
const LS_POSTCODE = "espruinoprog.postcode"; const LS_POSTCODE = "espruinoprog.postcode";
const LS_NAMEPREFIX = "espruinoprog.namePrefix"; const LS_NAMEPREFIX = "espruinoprog.namePrefix";
var jseditor,posteditor; var preeditor,jseditor,posteditor;
function setDefaults() { function setDefaults() {
if (localStorage.getItem(LS_PRECODE) === null) {
localStorage.setItem(LS_PRECODE, `// Erase all files (faster than eraseall)
require("Storage").list().forEach(f=>require("Storage").erase(f));reset();`);
}
if (localStorage.getItem(LS_JSCODE) === null) { if (localStorage.getItem(LS_JSCODE) === null) {
localStorage.setItem(LS_JSCODE, `// Flash LED2 every 2 seconds localStorage.setItem(LS_JSCODE, `// Flash LED2 every 2 seconds
setInterval(function() { setInterval(function() {
@ -47,6 +54,8 @@ LED.set();NRF.sleep();`);
if (localStorage.getItem(LS_NAMEPREFIX) === null) { if (localStorage.getItem(LS_NAMEPREFIX) === null) {
localStorage.setItem(LS_NAMEPREFIX, "Puck.js"); localStorage.setItem(LS_NAMEPREFIX, "Puck.js");
} }
document.getElementById("pre-code").value = localStorage.getItem(LS_PRECODE);
if (preeditor) preeditor.setValue(document.getElementById("pre-code").value);
document.getElementById("js-code").value = localStorage.getItem(LS_JSCODE); document.getElementById("js-code").value = localStorage.getItem(LS_JSCODE);
if (jseditor) jseditor.setValue(document.getElementById("js-code").value); if (jseditor) jseditor.setValue(document.getElementById("js-code").value);
document.getElementById("post-code").value = localStorage.getItem(LS_POSTCODE); document.getElementById("post-code").value = localStorage.getItem(LS_POSTCODE);
@ -55,8 +64,6 @@ LED.set();NRF.sleep();`);
} }
setDefaults(); setDefaults();
// The code editor // The code editor
var lintFlags = { var lintFlags = {
esversion: 6, // Enable ES6 for literals, arrow fns, binary esversion: 6, // Enable ES6 for literals, arrow fns, binary
@ -64,6 +71,17 @@ LED.set();NRF.sleep();`);
laxbreak: true, // don't warn about newlines in expressions laxbreak: true, // don't warn about newlines in expressions
laxcomma: true // don't warn about commas at the start of the line laxcomma: true // don't warn about commas at the start of the line
}; };
preeditor = CodeMirror.fromTextArea(document.getElementById("pre-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
});
jseditor = CodeMirror.fromTextArea(document.getElementById("js-code"), { jseditor = CodeMirror.fromTextArea(document.getElementById("js-code"), {
width: "100%", width: "100%",
height: "auto", height: "auto",
@ -87,7 +105,9 @@ LED.set();NRF.sleep();`);
lineNumbers: true lineNumbers: true
}); });
function hasWarnings() { function hasWarnings() {
return jseditor.state.lint.marked.length!=0 || posteditor.state.lint.marked.length!=0; return preeditor.state.lint.marked.length!=0 ||
jseditor.state.lint.marked.length!=0 ||
posteditor.state.lint.marked.length!=0;
} }
var editorChangedTimeout; var editorChangedTimeout;
function editorChanged() { function editorChanged() {
@ -95,26 +115,34 @@ LED.set();NRF.sleep();`);
editorChangedTimeout = setTimeout(function() { editorChangedTimeout = setTimeout(function() {
if (hasWarnings()) { if (hasWarnings()) {
document.getElementById("btninfo").innerHTML = "There are warnings in the code to be uploaded"; document.getElementById("btninfo").innerHTML = "There are warnings in the code to be uploaded";
document.getElementById("upload").classList.add("disabled"); //document.getElementById("upload").classList.add("disabled");
} else { } else {
document.getElementById("btninfo").innerHTML = ""; document.getElementById("btninfo").innerHTML = "";
document.getElementById("upload").classList.remove("disabled"); //document.getElementById("upload").classList.remove("disabled");
} }
}, 500); }, 500);
} }
preeditor.on("change", editorChanged);
jseditor.on("change", editorChanged); jseditor.on("change", editorChanged);
posteditor.on("change", editorChanged); posteditor.on("change", editorChanged);
document.getElementById("upload").addEventListener("click", function() { document.getElementById("upload").addEventListener("click", function() {
if (!hasWarnings()) { if (!hasWarnings()) {
var precode = preeditor.getValue();
var jscode = jseditor.getValue(); var jscode = jseditor.getValue();
var postcode = posteditor.getValue(); var postcode = posteditor.getValue();
var namePrefix = document.getElementById("nameprefix").value; var namePrefix = document.getElementById("nameprefix").value;
localStorage.setItem(LS_PRECODE, precode);
localStorage.setItem(LS_JSCODE, jscode); localStorage.setItem(LS_JSCODE, jscode);
localStorage.setItem(LS_POSTCODE, postcode); localStorage.setItem(LS_POSTCODE, postcode);
localStorage.setItem(LS_NAMEPREFIX, namePrefix); localStorage.setItem(LS_NAMEPREFIX, namePrefix);
// force version - as long as we're above 1v96 we get the ability to upload to different storage files
var ENV = Espruino.Core.Env.getData();
ENV.VERSION_MAJOR = 2;
ENV.VERSION_MINOR = 0;
// Now compile
Espruino.transform(jscode, { Espruino.transform(jscode, {
SET_TIME_ON_WRITE : false, // time would just be out of date SET_TIME_ON_WRITE : false, // time would just be out of date
SAVE_ON_SEND : 1, // save to flash SAVE_ON_SEND : 1, // save to flash
@ -125,6 +153,7 @@ LED.set();NRF.sleep();`);
sendCustomizedApp({ sendCustomizedApp({
storage: [{ name: "espruinoprog.json", content: JSON.stringify({ storage: [{ name: "espruinoprog.json", content: JSON.stringify({
namePrefix : namePrefix, namePrefix : namePrefix,
pre : Espruino.Core.CodeWriter.reformatCode(precode),
code : Espruino.Core.CodeWriter.reformatCode(content), code : Espruino.Core.CodeWriter.reformatCode(content),
post : Espruino.Core.CodeWriter.reformatCode(postcode) post : Espruino.Core.CodeWriter.reformatCode(postcode)
})}] })}]
@ -134,6 +163,7 @@ LED.set();NRF.sleep();`);
}); });
document.getElementById("setdefault").addEventListener("click", function(e) { document.getElementById("setdefault").addEventListener("click", function(e) {
e.preventDefault(); e.preventDefault();
localStorage.removeItem(LS_PRECODE);
localStorage.removeItem(LS_JSCODE); localStorage.removeItem(LS_JSCODE);
localStorage.removeItem(LS_POSTCODE); localStorage.removeItem(LS_POSTCODE);
localStorage.removeItem(LS_NAMEPREFIX); localStorage.removeItem(LS_NAMEPREFIX);

View File

@ -2,7 +2,7 @@
"id": "espruinoprog", "id": "espruinoprog",
"name": "Espruino Programmer", "name": "Espruino Programmer",
"shortName": "Programmer", "shortName": "Programmer",
"version": "0.01", "version": "0.02",
"description": "Finds Bluetooth devices with a specific name (eg 'Puck.js'), connects and uploads code. Great for programming many devices at once!", "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", "icon": "app.png",
"tags": "tool,bluetooth", "tags": "tool,bluetooth",