Skip to content

Commit

Permalink
First hack at E.setBootCode (fix #740)
Browse files Browse the repository at this point in the history
  • Loading branch information
gfwilliams committed Mar 30, 2016
1 parent dc21cae commit 3c76ff4
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 25 deletions.
11 changes: 7 additions & 4 deletions src/jsinteractive.c
Original file line number Diff line number Diff line change
Expand Up @@ -452,9 +452,12 @@ void jsiSoftInit() {
jsiLastIdleTime = jshGetSystemTime();
jsiTimeSinceCtrlC = 0xFFFFFFFF;

// Runw wrapper initialisation stuff
// Run wrapper initialisation stuff
jswInit();

// Run 'boot code' - textual JS in flash
jsfLoadBootCodeFromFlash();

// Now run initialisation code
JsVar *initCode = jsvObjectGetChild(execInfo.hiddenRoot, JSI_INIT_CODE_NAME, 0);
if (initCode) {
Expand Down Expand Up @@ -731,7 +734,7 @@ void jsiSemiInit(bool autoLoad) {
if (loadFlash) {
jspSoftKill();
jsvSoftKill();
jsfLoadFromFlash();
jsfLoadStateFromFlash();
jsvSoftInit();
jspSoftInit();
}
Expand Down Expand Up @@ -1955,7 +1958,7 @@ void jsiIdle() {
jsiSoftKill();
jspSoftKill();
jsvSoftKill();
jsfSaveToFlash();
jsfSaveToFlash(true, 0);
jshReset();
jsvSoftInit();
jspSoftInit();
Expand All @@ -1968,7 +1971,7 @@ void jsiIdle() {
jspSoftKill();
jsvSoftKill();
jshReset();
jsfLoadFromFlash();
jsfLoadStateFromFlash();
jsvSoftInit();
jspSoftInit();
jsiSoftInit();
Expand Down
7 changes: 5 additions & 2 deletions src/jsparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "jswrap_object.h" // for function_replacewith
#include "jswrap_functions.h" // insane check for eval in jspeFunctionCall
#include "jswrap_json.h" // for jsfPrintJSON
#include "jswrap_espruino.h" // for jswrap_espruino_memoryArea

/* Info about execution when Parsing - this saves passing it on the stack
* for each call */
Expand Down Expand Up @@ -2491,9 +2492,11 @@ JsVar *jspEvaluateVar(JsVar *str, JsVar *scope, uint16_t lineNumberOffset) {
}

JsVar *jspEvaluate(const char *str) {
JsVar *v = 0;
JsVar *evCode = jswrap_espruino_memoryArea((int)(size_t)str, (int)strlen(str));
if (!evCode) return 0;
// could always use jsvNewFromString, but not as efficient

JsVar *evCode = jsvNewFromString(str);
JsVar *v = 0;
if (!jsvIsMemoryFull())
v = jspEvaluateVar(evCode, 0, 0);
jsvUnLock(evCode);
Expand Down
22 changes: 21 additions & 1 deletion src/jswrap_espruino.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "jswrap_espruino.h"
#include "jswrap_math.h"
#include "jswrap_arraybuffer.h"
#include "jswrap_flash.h"
#include "jswrapper.h"
#include "jsinteractive.h"
#include "jstimer.h"
Expand Down Expand Up @@ -722,16 +723,34 @@ and Espruino Pico) at the moment.
*/
JsVar *jswrap_espruino_memoryArea(int addr, int len) {
if (len<0) return 0;
JsVar *v = jsvNewWithFlags(JSV_NATIVE_STRING);
if (len>65535) {
jsExceptionHere(JSET_ERROR, "Memory area too long! Max is 65535 bytes\n");
return 0;
}
JsVar *v = jsvNewWithFlags(JSV_NATIVE_STRING);
if (!v) return 0;
v->varData.nativeStr.ptr = (char*)addr;
v->varData.nativeStr.len = (uint16_t)len;
return v;
}

/*JSON{
"type" : "staticmethod",
"class" : "E",
"name" : "setBootCode",
"generate" : "jswrap_espruino_setBootCode",
"params" : [
["code","JsVar","The address of the memory area"]
]
}
This writes JavaScript code to Espruino, which will *always be executed
after a reset*.
*/
void jswrap_espruino_setBootCode(JsVar *code) {
jsfSaveToFlash(false, code);
}


/*JSON{
"type" : "staticmethod",
"ifndef" : "SAVE_ON_FLASH",
Expand Down Expand Up @@ -1117,4 +1136,5 @@ bool jswrap_espruino_sendUSBHID(JsVar *arr) {

return USBD_HID_SendReport(data, l) == USBD_OK;
}

#endif
3 changes: 3 additions & 0 deletions src/jswrap_espruino.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ JsVar *jswrap_espruino_toArrayBuffer(JsVar *str);
JsVar *jswrap_espruino_toUint8Array(JsVar *args);
JsVar *jswrap_espruino_toString(JsVar *args);
JsVar *jswrap_espruino_memoryArea(int addr, int len);
void jswrap_espruino_setBootCode(JsVar *code);
int jswrap_espruino_setClock(JsVar *options);

int jswrap_espruino_reverseByte(int v);
Expand All @@ -42,3 +43,5 @@ JsVarInt jswrap_espruino_HSBtoRGB(JsVarFloat hue, JsVarFloat sat, JsVarFloat bri

void jswrap_espruino_setUSBHID(JsVar *arr);
bool jswrap_espruino_sendUSBHID(JsVar *arr);


84 changes: 70 additions & 14 deletions src/jswrap_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ void jsfSaveToFlash_writecb(unsigned char ch, uint32_t *cbdata) {
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------

void jsfSaveToFlash() {
void jsfSaveToFlash(bool saveState, JsVar *bootCode) {
#ifdef LINUX
FILE *f = fopen("espruino.state","wb");
if (f) {
Expand Down Expand Up @@ -262,7 +262,7 @@ void jsfSaveToFlash() {
jsiConsolePrint("Done!\n>");
#endif
} else {
jsiConsolePrint("\nFile Open Failed... \n>");
jsiConsolePrint("\nFile open failed... \n>");
}
#else // !LINUX
unsigned int dataSize = jsvGetMemoryTotal() * sizeof(JsVar);
Expand All @@ -273,7 +273,6 @@ void jsfSaveToFlash() {
uint32_t writtenBytes;
uint32_t endOfData;
uint32_t cbData[3];
uint32_t rleStart;

while (tryAgain) {
tryAgain = false;
Expand All @@ -289,18 +288,35 @@ void jsfSaveToFlash() {

}
}
rleStart = FLASH_SAVED_CODE_START+4;
// Now start writing
cbData[0] = FLASH_MAGIC_LOCATION; // end of available flash
cbData[1] = rleStart;
cbData[1] = FLASH_SAVED_CODE_START+8;
cbData[2] = 0; // word data (can only save a word ata a time)
jsiConsolePrint("\nWriting...");
COMPRESS((unsigned char*)basePtr, dataSize, jsfSaveToFlash_writecb, cbData);
// boot code....
if (jsvIsString(bootCode)) {
uint32_t bootCodeLen = (uint32_t)jsvGetStringLength(bootCode)+1;
jshFlashWrite(&bootCodeLen, FLASH_SAVED_CODE_START, 4); // write size of boot code to flash

JsvStringIterator it;
jsvStringIteratorNew(&it, bootCode, 0);
while (jsvStringIteratorHasChar(&it)) {
jsfSaveToFlash_writecb(jsvStringIteratorGetChar(&it), cbData);
jsvStringIteratorNext(&it);
}
// terminate with a 0!
jsfSaveToFlash_writecb(0, cbData);
}
// state....
if (saveState) {
COMPRESS((unsigned char*)basePtr, dataSize, jsfSaveToFlash_writecb, cbData);
}
endOfData = cbData[1];
writtenBytes = endOfData - FLASH_SAVED_CODE_START;
// make sure we write everything in buffer
jsfSaveToFlash_writecb(0,cbData);
jsfSaveToFlash_writecb(0,cbData);
jsfSaveToFlash_writecb(0,cbData);
writtenBytes = endOfData - FLASH_SAVED_CODE_START;

if (cbData[1]>=cbData[0]) {
jsiConsolePrintf("\nERROR: Too big to save to flash (%d vs %d bytes)\n", writtenBytes, FLASH_MAGIC_LOCATION-FLASH_SAVED_CODE_START);
Expand All @@ -320,15 +336,22 @@ void jsfSaveToFlash() {

if (success) {
jsiConsolePrintf("\nCompressed %d bytes to %d", dataSize, writtenBytes);
jshFlashWrite(&endOfData, FLASH_SAVED_CODE_START, 4); // write position of end of data, at start of address space
jshFlashWrite(&endOfData, FLASH_SAVED_CODE_START+4, 4); // write position of end of data, at start of address space

uint32_t magic = FLASH_MAGIC;
jshFlashWrite(&magic, FLASH_MAGIC_LOCATION, 4);


jsiConsolePrint("\nChecking...");
cbData[0] = rleStart;
cbData[0] = FLASH_SAVED_CODE_START+8;
if (jsvIsString(bootCode)) {
uint32_t bootCodeLen = (uint32_t)jsvGetStringLength(bootCode)+1;
cbData[0] += bootCodeLen;
}
cbData[1] = 0; // increment if fails
COMPRESS((unsigned char*)basePtr, dataSize, jsfSaveToFlash_checkcb, cbData);
// TODO: check boot code written ok
if (saveState)
COMPRESS((unsigned char*)basePtr, dataSize, jsfSaveToFlash_checkcb, cbData);
uint32_t errors = cbData[1];

if (!jsfFlashContainsCode()) {
Expand All @@ -344,7 +367,9 @@ void jsfSaveToFlash() {
#endif
}

void jsfLoadFromFlash() {

/// Load the RAM image from flash (this is the actual interpreter state)
void jsfLoadStateFromFlash() {
#ifdef LINUX
FILE *f = fopen("espruino.state","rb");
if (f) {
Expand All @@ -360,7 +385,7 @@ void jsfLoadFromFlash() {
DECOMPRESS(jsfLoadFromFlash_readcb, (uint32_t*)f, (unsigned char*)_jsvGetAddressOf(1));
fclose(f);
} else {
jsiConsolePrint("\nFile Open Failed... \n");
jsiConsolePrint("\nFile open of espruino.state failed... \n");
}
#else // !LINUX
if (!jsfFlashContainsCode()) {
Expand All @@ -372,8 +397,11 @@ void jsfLoadFromFlash() {
uint32_t *basePtr = (uint32_t *)_jsvGetAddressOf(1);

uint32_t cbData[2];
jshFlashRead(&cbData[0], FLASH_SAVED_CODE_START, 4); // end address
cbData[1] = FLASH_SAVED_CODE_START+4; // start address
int32_t bootCodeLen;
jshFlashRead(&bootCodeLen, FLASH_SAVED_CODE_START, 4); // length of boot code
jshFlashRead(&cbData[0], FLASH_SAVED_CODE_START+4, 4); // end address
cbData[1] = FLASH_SAVED_CODE_START+8; // start address
if (bootCodeLen>0) cbData[1] += bootCodeLen;
uint32_t len = cbData[0]-FLASH_SAVED_CODE_START;
if (len>1000000) {
jsiConsolePrintf("Invalid saved code in flash!\n");
Expand All @@ -384,6 +412,34 @@ void jsfLoadFromFlash() {
#endif
}

/// Load bootup code from flash (this is textual JS code). return true if it exists
bool jsfLoadBootCodeFromFlash() {
const char *code = 0;
#ifdef LINUX
FILE *f = fopen("espruino.boot","rb");
if (!f) return false;

fseek(f, 0, SEEK_END);
long len = ftell(f);
fseek(f, 0, SEEK_SET);

code = malloc(len+1); // null
fread(code, len, 1, f);
code[len] = 0;
fclose(f);
#else // !LINUX
if (!jsfFlashContainsCode()) return false;

int32_t bootCodeLen;
jshFlashRead(&bootCodeLen, FLASH_SAVED_CODE_START, 4); // length of boot code
if (bootCodeLen<=0) return false;

code = (const char *)(FLASH_SAVED_CODE_START+8);
#endif
jsvUnLock(jspEvaluate(code));
return true;
}

bool jsfFlashContainsCode() {
#ifdef LINUX
FILE *f = fopen("espruino.state","rb");
Expand Down
10 changes: 6 additions & 4 deletions src/jswrap_flash.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ void jswrap_flash_erasePage(JsVar *addr);
void jswrap_flash_write(JsVar *data, int addr);
JsVar *jswrap_flash_read(int length, int addr);

/// Save contents of JsVars into Flash
void jsfSaveToFlash();
/// Load contents of JsVars from Flash
void jsfLoadFromFlash();
/// Save contents of JsVars into Flash. If bootCode is specified, save bootup code too.
void jsfSaveToFlash(bool saveState, JsVar *bootCode);
/// Load the RAM image from flash (this is the actual interpreter state)
void jsfLoadStateFromFlash();
/// Load bootup code from flash (this is textual JS code). return true if it exists
bool jsfLoadBootCodeFromFlash();
/// Returns true if flash contains something useful
bool jsfFlashContainsCode();

0 comments on commit 3c76ff4

Please sign in to comment.