diff options
-rw-r--r-- | os/ex/subsystems/mfs/mfs.c | 207 | ||||
-rw-r--r-- | os/ex/subsystems/mfs/mfs.h | 26 |
2 files changed, 188 insertions, 45 deletions
diff --git a/os/ex/subsystems/mfs/mfs.c b/os/ex/subsystems/mfs/mfs.c index 025831ffd..e4dbf77d7 100644 --- a/os/ex/subsystems/mfs/mfs.c +++ b/os/ex/subsystems/mfs/mfs.c @@ -174,7 +174,7 @@ static mfs_error_t mfs_flash_read(MFSDriver *mfsp, flash_offset_t offset, *
* @param[in] mfsp pointer to the @p MFSDriver object
* @param[in] offset flash offset
- * @param[in] n number of bytes to be writen
+ * @param[in] n number of bytes to be written
* @param[in] wp pointer to the data buffer
* @return The operation status.
* @retval MFS_NO_ERROR if the operation has been successfully completed.
@@ -194,6 +194,51 @@ static mfs_error_t mfs_flash_write(MFSDriver *mfsp, return MFS_ERR_FLASH_FAILURE;
}
+ /* TODO: Implement verify.*/
+
+ return MFS_NO_ERROR;
+}
+
+/**
+ * @brief Flash copy.
+ * @note If the option @p MFS_CFG_WRITE_VERIFY is enabled then the flash
+ * is also read back for verification.
+ *
+ * @param[in] mfsp pointer to the @p MFSDriver object
+ * @param[in] doffset destination flash offset
+ * @param[in] soffset source flash offset
+ * @param[in] n number of bytes to be copied
+ * @return The operation status.
+ * @retval MFS_NO_ERROR if the operation has been successfully completed.
+ * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
+ * failures.
+ *
+ * @notapi
+ */
+static mfs_error_t mfs_flash_copy(MFSDriver *mfsp,
+ flash_offset_t doffset,
+ flash_offset_t soffset,
+ uint32_t n) {
+
+ /* Splitting the operation in smaller operations because the buffer is
+ small.*/
+ while (n > 0U) {
+ /* Data size that can be written in a single program page operation.*/
+ size_t chunk = (size_t)(((doffset | (MFS_CFG_BUFFER_SIZE - 1U)) + 1U) -
+ doffset);
+ if (chunk > n) {
+ chunk = n;
+ }
+
+ RET_ON_ERROR(mfs_flash_read(mfsp, soffset, chunk, mfsp->buffer.data));
+ RET_ON_ERROR(mfs_flash_write(mfsp, doffset, chunk, mfsp->buffer.data));
+
+ /* Next page.*/
+ soffset += chunk;
+ doffset += chunk;
+ n -= chunk;
+ }
+
return MFS_NO_ERROR;
}
@@ -360,7 +405,7 @@ static mfs_error_t mfs_bank_write_header(MFSDriver *mfsp, }
bhdr.fields.magic1 = MFS_BANK_MAGIC_1;
- bhdr.fields.magic1 = MFS_BANK_MAGIC_1;
+ bhdr.fields.magic2 = MFS_BANK_MAGIC_2;
bhdr.fields.counter = cnt;
bhdr.fields.reserved1 = (uint16_t)mfsp->config->erased;
bhdr.fields.crc = crc16(0xFFFFU, bhdr.hdr8,
@@ -373,41 +418,26 @@ static mfs_error_t mfs_bank_write_header(MFSDriver *mfsp, }
/**
- * @brief Scans blocks searching for records.
- * @note The block integrity is strongly checked.
+ * @brief Determines the state of a flash bank.
*
* @param[in] mfsp pointer to the @p MFSDriver object
* @param[in] bank the bank identifier
- * @param[out] statep bank state
- * @param[out] cntp bank counter value, only valid if the bank is not
- * in the @p MFS_BANK_GARBAGE state.
- * @param[in] foundcb callback to be called for each found record or @p NULL
- * @param[in] endcb callback to be called after scanning or @p NULL
+ * @param[out] cntp bank counter value, only valid if the bank header is
+ * correct.
*
* @return The operation status.
* @retval MFS_NO_ERROR if the operation has been successfully completed.
+ * @retval MFS_ERR_HEADER if the header is corrupt or missing.
* @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
* failures.
*/
-static mfs_error_t mfs_bank_scan_records(MFSDriver *mfsp,
- mfs_bank_t bank,
- mfs_bank_state_t *statep,
- uint32_t *cntp,
- mfs_scan_cb_t foundcb,
- mfs_scan_cb_t endcb) {
- flash_offset_t hdr_offset, start_offset, end_offset;
- mfs_record_state_t sts;
+static mfs_error_t mfs_bank_verify_header(MFSDriver *mfsp,
+ mfs_bank_t bank,
+ uint32_t *cntp) {
uint16_t crc;
- bool warning = false;
-
- /* Default state.*/
- *statep = MFS_BANK_GARBAGE;
-
- start_offset = mfs_flash_get_bank_offset(mfsp, bank);
- end_offset = start_offset + mfsp->config->bank_size;
/* Reading the current bank header.*/
- RET_ON_ERROR(mfs_flash_read(mfsp, start_offset,
+ RET_ON_ERROR(mfs_flash_read(mfsp, mfs_flash_get_bank_offset(mfsp, bank),
sizeof (mfs_bank_header_t),
(void *)&mfsp->buffer.bhdr));
@@ -416,14 +446,14 @@ static mfs_error_t mfs_bank_scan_records(MFSDriver *mfsp, (mfsp->buffer.bhdr.fields.magic2 != MFS_BANK_MAGIC_2) ||
(mfsp->buffer.bhdr.fields.counter == mfsp->config->erased) ||
(mfsp->buffer.bhdr.fields.reserved1 != (uint16_t)mfsp->config->erased)) {
- return MFS_NO_ERROR;
+ return MFS_ERR_HEADER;
}
/* Verifying CRC.*/
crc = crc16(0xFFFFU, mfsp->buffer.bhdr.hdr8,
sizeof (mfs_bank_header_t) - sizeof (uint16_t));
if (crc != mfsp->buffer.bhdr.fields.crc) {
- return MFS_NO_ERROR;
+ return MFS_ERR_HEADER;
}
/* Returning the counter value.*/
@@ -431,6 +461,36 @@ static mfs_error_t mfs_bank_scan_records(MFSDriver *mfsp, *cntp = mfsp->buffer.bhdr.fields.counter;
}
+ return MFS_NO_ERROR;
+}
+
+/**
+ * @brief Scans blocks searching for records.
+ * @note The block integrity is strongly checked.
+ *
+ * @param[in] mfsp pointer to the @p MFSDriver object
+ * @param[in] bank the bank identifier
+ * @param[out] statep bank state
+ * @param[in] foundcb callback to be called for each found record or @p NULL
+ * @param[in] endcb callback to be called after scanning or @p NULL
+ *
+ * @return The operation status.
+ * @retval MFS_NO_ERROR if the operation has been successfully completed.
+ * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
+ * failures.
+ */
+static mfs_error_t mfs_bank_scan_records(MFSDriver *mfsp,
+ mfs_bank_t bank,
+ mfs_bank_state_t *statep,
+ mfs_scan_cb_t foundcb,
+ mfs_scan_cb_t endcb) {
+ flash_offset_t hdr_offset, start_offset, end_offset;
+ mfs_record_state_t sts;
+ bool warning = false;
+
+ start_offset = mfs_flash_get_bank_offset(mfsp, bank);
+ end_offset = start_offset + mfsp->config->bank_size;
+
/* Scanning records.*/
hdr_offset = start_offset + (flash_offset_t)sizeof(mfs_bank_header_t);
while (hdr_offset < end_offset) {
@@ -511,7 +571,11 @@ static mfs_error_t mfs_bank_get_state(MFSDriver *mfsp, return MFS_BANK_OK;
}
- return mfs_bank_scan_records(mfsp, bank, statep, cntp, NULL, NULL);
+ /* Bank header verification.*/
+ *statep = MFS_BANK_GARBAGE;
+ RET_ON_ERROR(mfs_bank_verify_header(mfsp, bank, cntp));
+
+ return mfs_bank_scan_records(mfsp, bank, statep, NULL, NULL);
}
/**
@@ -560,8 +624,12 @@ static mfs_error_t mfs_bank_mount(MFSDriver *mfsp, /* Resetting previous state.*/
mfs_state_reset(mfsp);
+ /* Bank header verification.*/
+ *statep = MFS_BANK_GARBAGE;
+ RET_ON_ERROR(mfs_bank_verify_header(mfsp, bank, &mfsp->current_counter));
+
+ /* Scanning for the most recent instance of all records.*/
RET_ON_ERROR(mfs_bank_scan_records(mfsp, bank, statep,
- &mfsp->current_counter,
mfs_bank_mount_found_cb,
mfs_bank_mount_end_cb));
@@ -592,10 +660,25 @@ static mfs_error_t mfs_bank_mount(MFSDriver *mfsp, static mfs_error_t mfs_bank_copy(MFSDriver *mfsp,
mfs_bank_t sbank,
mfs_bank_t dbank) {
+ unsigned i;
+ mfs_bank_state_t sts;
+ flash_offset_t dest_offset;
+
+ RET_ON_ERROR(mfs_bank_mount(mfsp, sbank, &sts));
+
+ /* Write address.*/
+ dest_offset = mfs_flash_get_bank_offset(mfsp, dbank) +
+ sizeof (mfs_bank_header_t);
- (void)mfsp;
- (void)sbank;
- (void)dbank;
+ /* Copying the most recent record instances only.*/
+ for (i = 0; i < MFS_CFG_MAX_RECORDS; i++) {
+ if (mfsp->descriptors[i].offset != 0) {
+ RET_ON_ERROR(mfs_flash_copy(mfsp, dest_offset,
+ mfsp->descriptors[i].offset,
+ mfsp->descriptors[i].size));
+ dest_offset += mfsp->descriptors[i].size;
+ }
+ }
return MFS_NO_ERROR;
}
@@ -616,7 +699,7 @@ static mfs_error_t mfs_bank_copy(MFSDriver *mfsp, static mfs_error_t mfs_try_mount(MFSDriver *mfsp) {
mfs_bank_state_t sts, sts0, sts1;
uint32_t cnt0 = 0, cnt1 = 0;
- mfs_error_t err = MFS_NO_ERROR;
+ mfs_error_t err;
/* Assessing the state of the two banks.*/
RET_ON_ERROR(mfs_bank_get_state(mfsp, MFS_BANK_0, &sts0, &cnt0));
@@ -630,11 +713,13 @@ static mfs_error_t mfs_try_mount(MFSDriver *mfsp) { /* Both banks erased, first initialization.*/
RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, 1));
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0, &sts));
+ err = MFS_NO_ERROR;
break;
case PAIR(MFS_BANK_ERASED, MFS_BANK_OK):
/* Normal situation, bank one is used.*/
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_1, &sts));
+ err = MFS_NO_ERROR;
break;
case PAIR(MFS_BANK_ERASED, MFS_BANK_PARTIAL):
@@ -657,6 +742,7 @@ static mfs_error_t mfs_try_mount(MFSDriver *mfsp) { case PAIR(MFS_BANK_OK, MFS_BANK_ERASED):
/* Normal situation, bank zero is used.*/
RET_ON_ERROR(mfs_bank_mount(mfsp, MFS_BANK_0, &sts));
+ err = MFS_NO_ERROR;
break;
case PAIR(MFS_BANK_OK, MFS_BANK_OK):
@@ -838,7 +924,8 @@ void mfsObjectInit(MFSDriver *mfsp) { void mfsStart(MFSDriver *mfsp, const MFSConfig *config) {
osalDbgCheck((mfsp != NULL) && (config != NULL));
- osalDbgAssert(mfsp->state != MFS_UNINIT, "invalid state");
+ osalDbgAssert((mfsp->state == MFS_STOP) || (mfsp->state == MFS_READY),
+ "invalid state");
if (mfsp->state == MFS_STOP) {
@@ -857,10 +944,12 @@ void mfsStart(MFSDriver *mfsp, const MFSConfig *config) { void mfsStop(MFSDriver *mfsp) {
osalDbgCheck(mfsp != NULL);
- osalDbgAssert(mfsp->state != MFS_UNINIT, "invalid state");
+ osalDbgAssert((mfsp->state == MFS_STOP) || (mfsp->state == MFS_READY),
+ "invalid state");
if (mfsp->state != MFS_STOP) {
-
+ mfsp->config = NULL;
+ mfs_state_reset(mfsp);
mfsp->state = MFS_STOP;
}
}
@@ -883,13 +972,17 @@ void mfsStop(MFSDriver *mfsp) { mfs_error_t mfsMount(MFSDriver *mfsp) {
unsigned i;
+ osalDbgAssert(mfsp->state == MFS_READY, "invalid state");
+
/* Attempting to mount the managed partition.*/
for (i = 0; i < MFS_CFG_MAX_REPAIR_ATTEMPTS; i++) {
mfs_error_t err;
err = mfs_try_mount(mfsp);
- if (!MFS_IS_ERROR(err))
+ if (!MFS_IS_ERROR(err)) {
+ mfsp->state = MFS_MOUNTED;
return err;
+ }
}
return MFS_ERR_FLASH_FAILURE;
@@ -900,7 +993,10 @@ mfs_error_t mfsMount(MFSDriver *mfsp) { */
mfs_error_t mfsUnmount(MFSDriver *mfsp) {
- (void)mfsp;
+ osalDbgAssert(mfsp->state == MFS_MOUNTED, "invalid state");
+
+ mfs_state_reset(mfsp);
+ mfsp->state = MFS_READY;
return MFS_NO_ERROR;
}
@@ -926,11 +1022,18 @@ mfs_error_t mfsUnmount(MFSDriver *mfsp) { mfs_error_t mfsReadRecord(MFSDriver *mfsp, uint32_t id,
uint32_t *np, uint8_t *buffer) {
- (void)mfsp;
+ osalDbgAssert(mfsp->state == MFS_MOUNTED, "invalid state");
+
+ /* Marking the start of the operation.*/
+ mfsp->state = MFS_ACTIVE;
+
(void)id;
(void)np;
(void)buffer;
+ /* Operation over.*/
+ mfsp->state = MFS_MOUNTED;
+
return MFS_NO_ERROR;
}
@@ -952,11 +1055,18 @@ mfs_error_t mfsReadRecord(MFSDriver *mfsp, uint32_t id, mfs_error_t mfsWriteRecord(MFSDriver *mfsp, uint32_t id,
uint32_t n, const uint8_t *buffer) {
- (void)mfsp;
+ osalDbgAssert(mfsp->state == MFS_MOUNTED, "invalid state");
+
+ /* Marking the start of the operation.*/
+ mfsp->state = MFS_ACTIVE;
+
(void)id;
(void)n;
(void)buffer;
+ /* Operation over.*/
+ mfsp->state = MFS_MOUNTED;
+
return MFS_NO_ERROR;
}
@@ -975,9 +1085,16 @@ mfs_error_t mfsWriteRecord(MFSDriver *mfsp, uint32_t id, */
mfs_error_t mfsEraseRecord(MFSDriver *mfsp, uint32_t id) {
- (void)mfsp;
+ osalDbgAssert(mfsp->state == MFS_MOUNTED, "invalid state");
+
+ /* Marking the start of the operation.*/
+ mfsp->state = MFS_ACTIVE;
+
(void)id;
+ /* Operation over.*/
+ mfsp->state = MFS_MOUNTED;
+
return MFS_NO_ERROR;
}
@@ -996,7 +1113,13 @@ mfs_error_t mfsEraseRecord(MFSDriver *mfsp, uint32_t id) { */
mfs_error_t mfsPerformGarbageCollection(MFSDriver *mfsp) {
- (void)mfsp;
+ osalDbgAssert(mfsp->state == MFS_MOUNTED, "invalid state");
+
+ /* Marking the start of the operation.*/
+ mfsp->state = MFS_ACTIVE;
+
+ /* Operation over.*/
+ mfsp->state = MFS_MOUNTED;
return MFS_NO_ERROR;
}
diff --git a/os/ex/subsystems/mfs/mfs.h b/os/ex/subsystems/mfs/mfs.h index 758800315..e8e1d168c 100644 --- a/os/ex/subsystems/mfs/mfs.h +++ b/os/ex/subsystems/mfs/mfs.h @@ -76,6 +76,17 @@ #if !defined(MFS_CFG_STRONG_CHECKING) || defined(__DOXYGEN__)
#define MFS_CFG_STRONG_CHECKING TRUE
#endif
+
+/**
+ * @brief Size of the buffer used for data copying.
+ * @note The buffer size must be a power of two and not smaller than
+ * 16 bytes.
+ * @note Larger buffers improve performance, buffers with size multiple
+ * of the flash program page size work better.
+ */
+#if !defined(MFS_CFG_BUFFER_SIZE) || defined(__DOXYGEN__)
+#define MFS_CFG_BUFFER_SIZE 32
+#endif
/** @} */
/*===========================================================================*/
@@ -94,6 +105,14 @@ #error "invalid MFS_MAX_REPAIR_ATTEMPTS value"
#endif
+#if MFS_CFG_BUFFER_SIZE <= 16
+#error "invalid MFS_CFG_BUFFER_SIZE value"
+#endif
+
+#if (MFS_CFG_BUFFER_SIZE & (MFS_CFG_BUFFER_SIZE - 1)) != 0
+#error "MFS_CFG_BUFFER_SIZE is not a power of two"
+#endif
+
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
@@ -129,8 +148,9 @@ typedef enum { MFS_ERR_NOT_ERASED = -1,
MFS_ERR_NOT_FOUND = -2,
MFS_ERR_CRC = -3,
- MFS_ERR_FLASH_FAILURE = -4,
- MFS_ERR_INTERNAL = -5
+ MFS_ERR_HEADER = -4,
+ MFS_ERR_FLASH_FAILURE = -5,
+ MFS_ERR_INTERNAL = -6
} mfs_error_t;
/**
@@ -307,7 +327,7 @@ typedef struct { union {
mfs_data_header_t dhdr;
mfs_bank_header_t bhdr;
- uint8_t data[32];
+ uint8_t data[MFS_CFG_BUFFER_SIZE];
} buffer;
} MFSDriver;
|