Skip to content

Commit c83ae88

Browse files
committed
Fix FC Storage data verification.
Former-commit-id: aefdf7f
1 parent 7c6bbbd commit c83ae88

File tree

3 files changed

+44
-21
lines changed

3 files changed

+44
-21
lines changed

cores/nRF5/FC_Store/FC_Store.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,8 @@ bool FCStore::write (uint32_t id, uint8_t* buf, uint16_t len) {
105105
uint8_t numWords = len / WORD_BYTES;
106106
uint8_t numBytes = len & (uint16_t)0x03;
107107

108-
// store the word length in the lower 16 bits
109-
if (numBytes > 0) {
110-
len += WORD_BYTES - numBytes;
111-
}
112-
storeDesc.setStoreLength(len);
113-
114-
if ((nextWriteAddr + sizeof(FCStoreDesc) + len) > lastPage) {
108+
// Make sure we check with +1 to the word count if there are stray bytes.
109+
if ((nextWriteAddr + sizeof(FCStoreDesc) + (numBytes ? len + 1 : len)) > lastPage) {
115110
STORE_PRINTF("Error not enough storage\n");
116111
return false;
117112
}
@@ -121,12 +116,11 @@ bool FCStore::write (uint32_t id, uint8_t* buf, uint16_t len) {
121116
nextWriteAddr += sizeof(storeDesc);
122117
cbf->flashWriteWords(nextWriteAddr, (uint32_t*)buf, numWords);
123118
nextWriteAddr += numWords * WORD_BYTES;
124-
buf += numWords * WORD_BYTES;
125119

126120
if (numBytes) {
127121
// convert the leftover bytes to a word to maintain alignment
128122
uint32_t val32 = 0;
129-
memcpy(&val32, buf, numBytes);
123+
memcpy(&val32, buf + (numWords * WORD_BYTES), numBytes);
130124
cbf->flashWriteWord(nextWriteAddr, val32);
131125
nextWriteAddr += WORD_BYTES;
132126
}
@@ -143,9 +137,10 @@ bool FCStore::write (uint32_t id, uint8_t* buf, uint16_t len) {
143137
return false;
144138
}
145139

146-
uint16_t datalen = desc->getByteLength();
140+
size_t datalen = desc->getByteLength();
147141
uint32_t dataAddr = (uint32_t)desc + sizeof(FCStoreDesc);
148142
if (datalen == len && memcmp(buf, (uint8_t*)dataAddr, datalen) == 0) {
143+
STORE_PRINTF("Data stored successfully\n");
149144
return true;
150145
}
151146

@@ -183,6 +178,7 @@ void FCStore::format() {
183178
eraseAll();
184179
cbf->flashWriteWord(firstPage, FC_STORE_MAGIC_VAL);
185180
nextWriteAddr = firstPage + WORD_BYTES;
181+
initialized = true;
186182
}
187183

188184
bool FCStore::defrag() {

cores/nRF5/FC_Store/FC_Store.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@
2424
#define FC_STORE_MAGIC_VAL 0xf1a5c0f5UL
2525
#define FC_STORE_EMPTY_VAL 0xFFFFFFFFUL
2626

27+
#ifndef FC_WORD_BYTES
2728
#define WORD_BYTES 4
29+
#else
30+
#define WORD_BYTES FC_WORD_BYTES
31+
#endif
2832

29-
//#define STORE_DEBUG
30-
31-
#ifdef STORE_DEBUG
33+
#ifdef FC_STORE_DEBUG
3234
#define STORE_PRINTF(msg, ...) printf((msg), ##__VA_ARGS__);
3335
#else
3436
#define STORE_PRINTF(msg, ...) void(msg)
@@ -51,10 +53,12 @@ class FCStoreDesc {
5153

5254
public:
5355
FCStoreDesc(uint32_t val) { id = val; newAddress = FC_STORE_EMPTY_VAL; length = 0; }
54-
uint16_t getByteLength(){ return (uint16_t)((length >> 16) & (uint32_t)0x0000FFFF); }
55-
uint16_t getStoreLength(){ return (uint16_t)(length & (uint32_t)0x0000FFFF); }
56-
void setByteLength(uint16_t len) { length = (uint32_t)((len << 16) & (uint32_t)0xFFFF0000); }
57-
void setStoreLength(uint16_t len) { length |= (uint32_t)(len & (uint32_t)0x0000FFFF); }
56+
uint16_t getByteLength() { return (uint16_t)((length >> 16) & (uint32_t)0x0000FFFF); }
57+
uint16_t getStoreLength() {
58+
uint16_t Blen = getByteLength();
59+
return (uint16_t)(Blen + WORD_BYTES - (Blen & (uint16_t)(WORD_BYTES - 1)));
60+
}
61+
void setByteLength(uint16_t len) { length = (uint32_t)((len << 16) | (uint32_t)0x0000FFFF); }
5862
void setId(uint32_t val) { id = val;}
5963
uint32_t getId() { return id; }
6064
uint32_t getNewAddress() { return newAddress; }

cores/nRF5/FC_Store/README.md

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,32 @@
1-
# Flash Config Store
2-
1+
# Flash Config Storage
32
This library was originally designed to support storing bond info from NimBLE and has been redesigned to allow use as an EEPROM emulation for storing config data.
43

54
## Design
5+
A **minimum** of 2 flash pages are required. Pages used for FC storage are identified with the value 0xf1a5c0f5UL as the first word in the page.
6+
7+
Wear leveling is accomplished by sequentially writing data across a number of flash pages. When data is updated the old data is marked with the location of the new data. When the end of the page is reached the original page is defragmented and valid data copied to the swap page which becomes the new data page and the old page is erased to be used for as the swap for the next defragmentation.
8+
9+
### Data format
10+
The data is stored with a header in the following format:
11+
12+
| Data ID | New Address | Length | Reserved | Data |
13+
|-----------|-------------|---------|----------|------------|
14+
| 32 bits | 32 bits | 16 bits | 16 bits | data bytes |
15+
16+
- The data ID can be any value from 0x00 to 0xFFFFFFFE (0xFFFFFFFFF is reserved as empty).
17+
- The New Address specifies the location of any updated data (0xFFFFFFFF if unchanged).
18+
- The length is the length of the data in Bytes.
19+
- Data is the stored data.
20+
21+
When a data value is written FC storage will write the header and data in the next available space. If there is not enough space for the new data a defragmentation will be triggered in an attempt to provide space.
22+
23+
When a data value is updated the New Address field of the previous data is updated to reflect the address of the new data location to read the updated data from. This continues for each time the value is updated.
24+
25+
When reading a value FC Storage will find the first instance of the ID and check the New Address field, if a new address has been set it will check the New Address field of that location, move to the next if set, and so on until the latest data is found.
26+
27+
### Defragmentation
28+
The defragmentation process consolidates all the current valid data to the swap page(s) and updates the page pointer to the beginning of the data. This sets all New Address header fields to empty and frees up space needed for new data. The old data page(s) will then be erased and become the swap page for the next defragmentation.
29+
30+
631

7-
A **minimum** of 2 flash pages are required.
832

9-
Wear leveling is accomplished by sequentially writing data accross a page of flash. When data is updated the old data is marked with the location of the new data. When the end of the page is reached the original page is defragmented and valid data copied to the swap page which becomes the new main page and the old page is erased.

0 commit comments

Comments
 (0)