|
29 | 29 | type : "boolean", |
30 | 30 | defaultValue : true |
31 | 31 | }); |
| 32 | + Espruino.Core.Config.add("SAVE_ON_SEND", { |
| 33 | + section : "Communications", |
| 34 | + subSection: "Storage", |
| 35 | + name : "Save on Send", |
| 36 | + descriptionHTML : 'How should code be uploaded? See <a href="http://www.espruino.com/Saving" target="_blank">espruino.com/Saving</a> for more information.<br>'+ |
| 37 | + "<b>NOTE:</b> Avoid 'Direct to flash, even after <code>reset()</code>' for normal development - it can make it hard to recover if your code crashes the device.", |
| 38 | + type : { |
| 39 | + // -1: is used by the app loader to signify that we want the code as-is (app loader adds write statements). Allows pretokenise to correctly check if we're writing to RAM or not |
| 40 | + 0: "To RAM (default) - execute code while uploading. Use 'save()' to save a RAM image to Flash", |
| 41 | + 1: "Direct to Flash (execute code at boot)", |
| 42 | + 2: "Direct to Flash (execute code at boot, even after 'reset()') - USE WITH CARE", |
| 43 | + 3: "To Storage File (see 'File in Storage to send to')", |
| 44 | + }, |
| 45 | + defaultValue : 0 |
| 46 | + }); |
| 47 | + Espruino.Core.Config.add("SAVE_STORAGE_FILE", { |
| 48 | + section : "Communications", |
| 49 | + subSection: "Storage", |
| 50 | + name : "Send to File in Storage", |
| 51 | + descriptionHTML : "If <code>Save on Send</code> is set to <code>To Storage File</code>, this is the name of the file to write to.", |
| 52 | + type : "string", |
| 53 | + defaultValue : "myapp" |
| 54 | + }); |
| 55 | + Espruino.Core.Config.add("LOAD_STORAGE_FILE", { |
| 56 | + section : "Communications", |
| 57 | + subSection: "Storage", |
| 58 | + name : "Load after saving", |
| 59 | + descriptionHTML : "This applies only if saving to Flash (not RAM)", |
| 60 | + type : { |
| 61 | + 0: "Don't load", |
| 62 | + 1: "Load default application", |
| 63 | + 2: "Load the Storage File just written to" |
| 64 | + }, |
| 65 | + defaultValue : 2 |
| 66 | + }); |
| 67 | + } |
| 68 | + |
| 69 | + /** Convert code into the JS commands needed to upload that code */ |
| 70 | + function getUploadCommands(code) { |
| 71 | + // convert any non-0..255 charcodes to UTF8 encoding |
| 72 | + code = Espruino.Core.Utils.asUTF8Bytes(code); |
| 73 | + // Depending on settings, choose how we package code for upload (see Espruino.Core.Send.SEND_MODE_* constants) |
| 74 | + var isFlashPersistent = Espruino.Config.SAVE_ON_SEND == 2; |
| 75 | + var isStorageUpload = Espruino.Config.SAVE_ON_SEND == 3; |
| 76 | + var isSDCardUpload = Espruino.Config.SAVE_ON_SEND == 4; |
| 77 | + var isFlashUpload = Espruino.Config.SAVE_ON_SEND == 1 || isFlashPersistent || isStorageUpload; |
| 78 | + if (!isFlashUpload && !isSDCardUpload) { |
| 79 | + // Just uploading to RAM |
| 80 | + /* hack around non-K&R code formatting that would have |
| 81 | + broken Espruino CLI's bracket counting */ |
| 82 | + return reformatCodeForREPL(code); |
| 83 | + } |
| 84 | + |
| 85 | + var asJS = Espruino.Core.Utils.toJSONishString; |
32 | 86 |
|
| 87 | + // Check environment vars |
| 88 | + var hasStorage = false; |
| 89 | + var ENV = Espruino.Core.Env.getData(); |
| 90 | + if (ENV && |
| 91 | + ENV.VERSION_MAJOR && |
| 92 | + ENV.VERSION_MINOR!==undefined) { |
| 93 | + if (ENV.VERSION_MAJOR>1 || |
| 94 | + ENV.VERSION_MINOR>=96) { |
| 95 | + hasStorage = true; |
| 96 | + } |
| 97 | + } |
| 98 | + const CHUNKSIZE = 1024; |
| 99 | + |
| 100 | + // Now create the commands to do the upload |
| 101 | + console.log("Uploading "+code.length+" bytes to flash"); |
| 102 | + // FIXME: We should use Serial's Connection class packet stuff for file uploads |
| 103 | + if (!hasStorage) { // old style |
| 104 | + if (isStorageUpload || isSDCardUpload) { |
| 105 | + Espruino.Core.Notifications.error("You have pre-1v96 firmware - unable to upload to Storage"); |
| 106 | + code = ""; |
| 107 | + } else { |
| 108 | + Espruino.Core.Notifications.error("You have pre-1v96 firmware. Upload size is limited by available RAM"); |
| 109 | + code = "E.setBootCode("+asJS(code)+(isFlashPersistent?",true":"")+");"; |
| 110 | + } |
| 111 | + } else if (isSDCardUpload) { |
| 112 | + var filename = Espruino.Config.SAVE_STORAGE_FILE;; |
| 113 | + var newCode = [ `let _ul = E.openFile(${asJS(filename)},"w");` ]; |
| 114 | + var len = code.length; |
| 115 | + for (var i=0;i<len;i+=CHUNKSIZE) |
| 116 | + newCode.push(`_ul.write(${asJS(code.substr(i,CHUNKSIZE))});`); |
| 117 | + newCode.push(`_ul.close();delete _ul;`); |
| 118 | + code = "\x10"+newCode.join("\n\x10")+"\n"; |
| 119 | + } else { // new style |
| 120 | + var filename; |
| 121 | + if (isStorageUpload) |
| 122 | + filename = Espruino.Config.SAVE_STORAGE_FILE; |
| 123 | + else |
| 124 | + filename = isFlashPersistent ? ".bootrst" : ".bootcde"; |
| 125 | + if (!filename || filename.length>28) { |
| 126 | + Espruino.Core.Notifications.error("Invalid Storage file name "+JSON.stringify(filename)); |
| 127 | + code = ""; |
| 128 | + } else { |
| 129 | + var newCode = []; |
| 130 | + var len = code.length; |
| 131 | + newCode.push('require("Storage").write('+asJS(filename)+','+asJS(code.substr(0,CHUNKSIZE))+',0,'+len+');'); |
| 132 | + for (var i=CHUNKSIZE;i<len;i+=CHUNKSIZE) |
| 133 | + newCode.push('require("Storage").write('+asJS(filename)+','+asJS(code.substr(i,CHUNKSIZE))+','+i+');'); |
| 134 | + code = "\x10"+newCode.join("\n\x10")+"\n"; |
| 135 | + } |
| 136 | + } |
| 137 | + if (Espruino.Config.LOAD_STORAGE_FILE==2 && isStorageUpload) |
| 138 | + code += "\x10load("+asJS(filename)+")\n"; |
| 139 | + else if (Espruino.Config.LOAD_STORAGE_FILE!=0) |
| 140 | + code += "\x10load()\n"; |
| 141 | + return code; |
33 | 142 | } |
34 | 143 |
|
| 144 | + |
35 | 145 | function writeToEspruino(code, callback) { |
36 | | - /* hack around non-K&R code formatting that would have |
37 | | - broken Espruino CLI's bracket counting */ |
38 | | - code = reformatCode(code); |
39 | 146 | if (code === undefined) return; // it should already have errored |
40 | 147 |
|
| 148 | + /* If needed, convert code to upload to a set of JS commands |
| 149 | + which will upload the code into Espruino's flash/etc */ |
| 150 | + code = getUploadCommands(code); |
| 151 | + |
41 | 152 | // We want to make sure we've got a prompt before sending. If not, |
42 | 153 | // this will issue a Ctrl+C |
43 | 154 | Espruino.Core.Utils.getEspruinoPrompt(function() { |
|
81 | 192 | * @param {string} code |
82 | 193 | * @returns {string | undefined} |
83 | 194 | */ |
84 | | - function reformatCode(code) { |
| 195 | + function reformatCodeForREPL(code) { |
85 | 196 | var APPLY_LINE_NUMBERS = false; |
86 | 197 | var lineNumberOffset = 0; |
87 | 198 | var ENV = Espruino.Core.Env.getData(); |
|
211 | 322 | if (previousBrackets==0 && |
212 | 323 | previousString.indexOf("\n")>=0 && |
213 | 324 | previousString.indexOf("\x1B\x0A")<0) { |
214 | | - previousString = "\n\x10"; |
| 325 | + previousString = "\n\x10";//FIXME |
215 | 326 | // Apply line numbers to each new line sent, to aid debugger |
216 | 327 | if (APPLY_LINE_NUMBERS && tok.lineNumber && (tok.lineNumber+lineNumberOffset)>0) { |
217 | 328 | // Esc [ 1234 d |
|
242 | 353 | Espruino.Core.CodeWriter = { |
243 | 354 | init : init, |
244 | 355 | writeToEspruino : writeToEspruino, // call this to send to Espruino |
245 | | - reformatCode : reformatCode // Parse and fix issues like `if (false)\n foo` in the root scope |
| 356 | + reformatCodeForREPL : reformatCodeForREPL // Parse and fix issues like `if (false)\n foo` in the root scope |
246 | 357 | }; |
247 | 358 | }()); |
0 commit comments