Skip to content

Commit

Permalink
require("Flash").write operations no longer need to be aligned
Browse files Browse the repository at this point in the history
            require("Storage").open added - for appendable files
  • Loading branch information
gfwilliams committed Oct 17, 2019
1 parent 06fad00 commit 738a9a9
Show file tree
Hide file tree
Showing 10 changed files with 338 additions and 78 deletions.
2 changes: 2 additions & 0 deletions ChangeLog
Expand Up @@ -20,6 +20,8 @@
nRF52: Fix alignment issue with Nordic's SDK12 code that stopped passkey pairing from working sometimes
Storage lib now doesn't bother reading to end of flash to ensure pages are clear
Allow heatshrink compress/decompress to work even if flat buffers can't be allocated
require("Flash").write operations no longer need to be aligned
require("Storage").open added - for appendable files

2v04 : Allow \1..\9 escape codes in RegExp
ESP8266: reading storage is not working for boot from user2 (fix #1507)
Expand Down
36 changes: 4 additions & 32 deletions src/jsflash.c
Expand Up @@ -158,11 +158,12 @@ static void jsfEraseFileInternal(uint32_t addr, JsfFileHeader *header) {
jshFlashWrite(&header->replacement,addr,(uint32_t)sizeof(JsfWord));
}

void jsfEraseFile(JsfFileName name) {
bool jsfEraseFile(JsfFileName name) {
JsfFileHeader header;
uint32_t addr = jsfFindFile(name, &header);
if (!addr) return;
if (!addr) return false;
jsfEraseFileInternal(addr, &header);
return true;
}

// Get the address of the page after the current one, or 0. THE NEXT PAGE MAY HAVE A PREVIOUS PAGE'S DATA SPANNING OVER IT
Expand Down Expand Up @@ -569,36 +570,7 @@ bool jsfWriteFile(JsfFileName name, JsVar *data, JsfFileFlags flags, JsVarInt of
return false;
}
DBG("jsfWriteFile write contents\n");
// Cope with unaligned first write
uint32_t alignOffset = addr & (JSF_ALIGNMENT-1);
if (alignOffset) {
char buf[JSF_ALIGNMENT];
jshFlashRead(buf, addr-alignOffset, JSF_ALIGNMENT);
uint32_t alignRemainder = JSF_ALIGNMENT-alignOffset;
if (alignRemainder > dLen)
alignRemainder = (uint32_t)dLen;
memcpy(&buf[alignOffset], dPtr, alignRemainder);
dPtr += alignRemainder;
jshFlashWrite(buf, addr-alignOffset, JSF_ALIGNMENT);
addr += alignRemainder;
if (alignRemainder >= dLen)
return true; // we're done!
dLen -= alignRemainder;
}
// Do aligned write
alignOffset = dLen & (JSF_ALIGNMENT-1);
dLen -= alignOffset;
if (dLen)
jshFlashWrite(dPtr, addr, (uint32_t)dLen);
addr += (uint32_t)dLen;
dPtr += dLen;
// Do final unaligned write
if (alignOffset) {
char buf[JSF_ALIGNMENT];
jshFlashRead(buf, addr, JSF_ALIGNMENT);
memcpy(buf, dPtr, alignOffset);
jshFlashWrite(buf, addr, JSF_ALIGNMENT);
}
jshFlashWriteAligned(dPtr, addr, (uint32_t)dLen);
DBG("jsfWriteFile written contents\n");
return true;
}
Expand Down
14 changes: 2 additions & 12 deletions src/jsflash.h
Expand Up @@ -22,16 +22,6 @@ typedef union {
char c[8];
} JsfFileName;

#ifdef FLASH_64BITS_ALIGNMENT
typedef uint64_t JsfWord;
#define JSF_ALIGNMENT 8
#define JSF_WORD_UNSET 0xFFFFFFFFFFFFFFFFULL
#else
typedef uint32_t JsfWord;
#define JSF_ALIGNMENT 4
#define JSF_WORD_UNSET 0xFFFFFFFF
#endif

/// Max length of filename in chars
#define JSF_MAX_FILENAME_LENGTH (sizeof(JsfFileName))

Expand Down Expand Up @@ -64,8 +54,8 @@ uint32_t jsfFindFile(JsfFileName name, JsfFileHeader *returnedHeader);
JsVar *jsfReadFile(JsfFileName name);
/// Write a file. For simple stuff just leave offset and size as 0
bool jsfWriteFile(JsfFileName name, JsVar *data, JsfFileFlags flags, JsVarInt offset, JsVarInt _size);
/// Erase the given file
void jsfEraseFile(JsfFileName name);
/// Erase the given file, return true on success
bool jsfEraseFile(JsfFileName name);
/// Erase the entire contents of the memory store
bool jsfEraseAll();
/// Try and compact saved data so it'll fit in Flash again
Expand Down
2 changes: 2 additions & 0 deletions src/jshardware.h
Expand Up @@ -352,6 +352,8 @@ void jshFlashRead(void *buf, uint32_t addr, uint32_t len);
/** Write data to flash memory from the buffer, the buffer address and flash address are
* guaranteed to be 4-byte aligned, and length is a multiple of 4. */
void jshFlashWrite(void *buf, uint32_t addr, uint32_t len);
/** Like FlashWrite but can be unaligned (it uses a read first). This is in jshardware_common.c */
void jshFlashWriteAligned(void *buf, uint32_t addr, uint32_t len);

/** On most platforms, the address of something really is that address.
* In ESP32/ESP8266 the flash memory is mapped up at a much higher address,
Expand Down
40 changes: 40 additions & 0 deletions src/jshardware_common.c
Expand Up @@ -13,6 +13,7 @@
*/
#include "jshardware.h"
#include "jsinteractive.h"
#include "platform_config.h"

void jshUSARTInitInfo(JshUSARTInfo *inf) {
inf->baudRate = DEFAULT_BAUD_RATE;
Expand Down Expand Up @@ -45,6 +46,45 @@ void jshI2CInitInfo(JshI2CInfo *inf) {
inf->started = false;
}

void jshFlashWriteAligned(void *buf, uint32_t addr, uint32_t len) {
#ifdef SPIFLASH_BASE
if (addr >= SPIFLASH_BASE) {
// If using external flash it doesn't care about alignment, so don't bother
jshFlashWriteAligned(buf, addr, len);
return;
}
#endif
unsigned char *dPtr = (unsigned char *)buf;
uint32_t alignOffset = addr & (JSF_ALIGNMENT-1);
if (alignOffset) {
char buf[JSF_ALIGNMENT];
jshFlashRead(buf, addr-alignOffset, JSF_ALIGNMENT);
uint32_t alignRemainder = JSF_ALIGNMENT-alignOffset;
if (alignRemainder > len)
alignRemainder = len;
memcpy(&buf[alignOffset], dPtr, alignRemainder);
dPtr += alignRemainder;
jshFlashWrite(buf, addr-alignOffset, JSF_ALIGNMENT);
addr += alignRemainder;
if (alignRemainder >= len)
return; // we're done!
len -= alignRemainder;
}
// Do aligned write
alignOffset = len & (JSF_ALIGNMENT-1);
len -= alignOffset;
if (len)
jshFlashWrite(dPtr, addr, len);
addr += len;
dPtr += len;
// Do final unaligned write
if (alignOffset) {
char buf[JSF_ALIGNMENT];
jshFlashRead(buf, addr, JSF_ALIGNMENT);
memcpy(buf, dPtr, alignOffset);
jshFlashWrite(buf, addr, JSF_ALIGNMENT);
}
}
/** Send data in tx through the given SPI device and return the response in
* rx (if supplied). Returns true on success */
__attribute__((weak)) bool jshSPISendMany(IOEventFlags device, unsigned char *tx, unsigned char *rx, size_t count, void (*callback)()) {
Expand Down
10 changes: 10 additions & 0 deletions src/jsutils.h
Expand Up @@ -103,6 +103,16 @@ int flash_strcmp(const char *mem, const char *flash);

#endif

#ifdef FLASH_64BITS_ALIGNMENT
typedef uint64_t JsfWord;
#define JSF_ALIGNMENT 8
#define JSF_WORD_UNSET 0xFFFFFFFFFFFFFFFFULL
#else
typedef uint32_t JsfWord;
#define JSF_ALIGNMENT 4
#define JSF_WORD_UNSET 0xFFFFFFFF
#endif


#if defined(ESP8266)
/** For the esp8266 we need to add CALLED_FROM_INTERRUPT to all functions that may execute at
Expand Down
12 changes: 4 additions & 8 deletions src/jswrap_flash.c
Expand Up @@ -115,11 +115,11 @@ void jswrap_flash_erasePage(JsVar *addr) {
"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)"]
["data","JsVar","The data to write"],
["addr","int","The address to start writing from"]
]
}
Write data into memory at the given address - IN MULTIPLES OF 4 BYTES.
Write data into memory at the given address
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`
Expand All @@ -133,13 +133,9 @@ void jswrap_flash_write(JsVar *data, int addr) {
}

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);
jshFlashWriteAligned(flashData, (unsigned int)addr, (unsigned int)flashDataLen);
}

/*JSON{
Expand Down

0 comments on commit 738a9a9

Please sign in to comment.