Permalink
Fetching contributors…
Cannot retrieve contributors at this time
174 lines (158 sloc) 5.58 KB
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2018 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* JavaScript Flash IO functions
* ----------------------------------------------------------------------------
*/
#include "jswrap_flash.h"
#include "jshardware.h"
#include "jsflash.h"
#include "jsvar.h"
#include "jsvariterator.h"
/*JSON{
"type" : "library",
"class" : "Flash",
"ifndef" : "SAVE_ON_FLASH"
}
This module allows you to read and write the nonvolatile flash memory of your device.
Also see the `Storage` library, which provides a safer file-like
interface to nonvolatile storage.
It should be used with extreme caution, as it is easy to overwrite parts of Flash
memory belonging to Espruino or even its bootloader. If you damage the bootloader
then you may need external hardware such as a USB-TTL converter to restore it. For
more information on restoring the bootloader see `Advanced Reflashing` in your
board's reference pages.
To see which areas of memory you can and can't overwrite, look at the values
reported by `process.memory()`.
**Note:** On Nordic platforms there are checks in place to help you avoid
'bricking' your device be damaging the bootloader. You can disable these with `E.setFlags({unsafeFlash:1})`
*/
/*JSON{
"type" : "staticmethod",
"ifndef" : "SAVE_ON_FLASH",
"class" : "Flash",
"name" : "getPage",
"generate" : "jswrap_flash_getPage",
"params" : [
["addr","int","An address in memory"]
],
"return" : ["JsVar","An object of the form `{ addr : #, length : #}`, where `addr` is the start address of the page, and `length` is the length of it (in bytes). Returns undefined if no page at address"]
}
Returns the start and length of the flash page containing the given address.
*/
JsVar *jswrap_flash_getPage(int addr) {
uint32_t pageStart, pageLength;
if (!jshFlashGetPage((uint32_t)addr, &pageStart, &pageLength))
return 0;
JsVar *obj = jsvNewObject();
if (!obj) return 0;
jsvObjectSetChildAndUnLock(obj, "addr", jsvNewFromInteger((JsVarInt)pageStart));
jsvObjectSetChildAndUnLock(obj, "length", jsvNewFromInteger((JsVarInt)pageLength));
return obj;
}
/*JSON{
"type" : "staticmethod",
"ifndef" : "SAVE_ON_FLASH",
"class" : "Flash",
"name" : "getFree",
"generate" : "jswrap_flash_getFree",
"return" : ["JsVar", "Array of objects with `addr` and `length` properties"]
}
This method returns an array of objects of the form `{addr : #, length : #}`, representing
contiguous areas of flash memory in the chip that are not used for anything.
The memory areas returned are on page boundaries. This means that you can
safely erase the page containing any address here, and you won't risk
deleting part of the Espruino firmware.
*/
JsVar *jswrap_flash_getFree() {
JsVar *arr = jshFlashGetFree();
if (!arr) arr=jsvNewEmptyArray();
return arr;
}
/*JSON{
"type" : "staticmethod",
"ifndef" : "SAVE_ON_FLASH",
"class" : "Flash",
"name" : "erasePage",
"generate" : "jswrap_flash_erasePage",
"params" : [
["addr","JsVar","An address in the page that is to be erased"]
]
}
Erase a page of flash memory
*/
void jswrap_flash_erasePage(JsVar *addr) {
if (!jsvIsInt(addr)) {
jsExceptionHere(JSET_ERROR, "Address should be an integer, got %t", addr);
return;
}
jshFlashErasePage((uint32_t)jsvGetInteger(addr));
}
/*JSON{
"type" : "staticmethod",
"ifndef" : "SAVE_ON_FLASH",
"class" : "Flash",
"name" : "write",
"generate" : "jswrap_flash_write",
"params" : [
["data","JsVar","The data to write. This must be a multiple of 4 bytes."],
["addr","int","The address to start writing from, this must be on a word boundary (a multiple of 4)"]
]
}
Write data into memory at the given address - IN MULTIPLES OF 4 BYTES.
In flash memory you may only turn bits that are 1 into bits that are 0. If
you're writing data into an area that you have already written (so `read`
doesn't return all `0xFF`) you'll need to call `erasePage` to clear the
entire page.
*/
void jswrap_flash_write(JsVar *data, int addr) {
if (jsvIsUndefined(data)) {
jsExceptionHere(JSET_ERROR, "Data is not defined");
return;
}
JSV_GET_AS_CHAR_ARRAY(flashData, flashDataLen, data);
if ((addr&3) || (flashDataLen&3)) {
jsExceptionHere(JSET_ERROR, "Data and address must be multiples of 4");
return;
}
if (flashData && flashDataLen)
jshFlashWrite(flashData, (unsigned int)addr, (unsigned int)flashDataLen);
}
/*JSON{
"type" : "staticmethod",
"ifndef" : "SAVE_ON_FLASH",
"class" : "Flash",
"name" : "read",
"generate" : "jswrap_flash_read",
"params" : [
["length","int","The amount of data to read (in bytes)"],
["addr","int","The address to start reading from"]
],
"return" : ["JsVar","A Uint8Array of data"]
}
Read flash memory from the given address
*/
JsVar *jswrap_flash_read(int length, int addr) {
if (length<=0) return 0;
JsVar *arr = jsvNewTypedArray(ARRAYBUFFERVIEW_UINT8, length);
if (!arr) return 0;
JsvArrayBufferIterator it;
jsvArrayBufferIteratorNew(&it, arr, 0);
while (jsvArrayBufferIteratorHasElement(&it)) {
char c;
jshFlashRead(&c, (uint32_t)(addr++), 1);
jsvArrayBufferIteratorSetByteValue(&it, c);
jsvArrayBufferIteratorNext(&it);
}
jsvArrayBufferIteratorFree(&it);
return arr;
}