hal_mfs.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164
  1. /*
  2. ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
  3. This file is part of ChibiOS.
  4. ChibiOS is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. ChibiOS is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. /**
  16. * @file hal_mfs.c
  17. * @brief Managed Flash Storage module code.
  18. * @details This module manages a flash partition as a generic storage where
  19. * arbitrary data records can be created, updated, deleted and
  20. * retrieved.<br>
  21. * A managed partition is composed of two banks of equal size, a
  22. * bank is composed of one or more erasable sectors, a sector is
  23. * divided in writable pages.<br>
  24. * The module handles flash wear leveling and recovery of damaged
  25. * banks (where possible) caused by power loss during operations.
  26. * Both operations are transparent to the user.
  27. *
  28. * @addtogroup HAL_MFS
  29. * @{
  30. */
  31. #include <string.h>
  32. #include "hal.h"
  33. #include "hal_mfs.h"
  34. /*===========================================================================*/
  35. /* Driver local definitions. */
  36. /*===========================================================================*/
  37. #define PAIR(a, b) (((unsigned)(a) << 2U) | (unsigned)(b))
  38. /**
  39. * @brief Error check helper.
  40. */
  41. #define RET_ON_ERROR(err) do { \
  42. mfs_error_t e = (err); \
  43. if (e != MFS_NO_ERROR) { \
  44. return e; \
  45. } \
  46. } while (false)
  47. /*===========================================================================*/
  48. /* Driver exported variables. */
  49. /*===========================================================================*/
  50. /*===========================================================================*/
  51. /* Driver local variables and types. */
  52. /*===========================================================================*/
  53. static const uint16_t crc16_table[256] = {
  54. 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
  55. 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
  56. 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
  57. 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
  58. 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
  59. 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
  60. 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
  61. 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
  62. 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
  63. 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
  64. 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
  65. 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
  66. 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
  67. 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
  68. 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
  69. 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
  70. 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
  71. 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
  72. 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
  73. 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
  74. 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
  75. 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
  76. 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
  77. 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
  78. 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
  79. 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
  80. 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
  81. 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
  82. 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
  83. 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
  84. 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
  85. 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
  86. };
  87. /*===========================================================================*/
  88. /* Driver local functions. */
  89. /*===========================================================================*/
  90. uint16_t crc16(uint16_t crc, const uint8_t *data, size_t n) {
  91. while (n > 0U) {
  92. crc = (crc << 8U) ^ crc16_table[(crc >> 8U) ^ (uint16_t)*data];
  93. data++;
  94. n--;
  95. }
  96. return crc;
  97. }
  98. static void mfs_state_reset(MFSDriver *mfsp) {
  99. unsigned i;
  100. mfsp->current_bank = MFS_BANK_0;
  101. mfsp->current_counter = 0U;
  102. mfsp->next_offset = 0U;
  103. mfsp->used_space = 0U;
  104. for (i = 0; i < MFS_CFG_MAX_RECORDS; i++) {
  105. mfsp->descriptors[i].offset = 0U;
  106. mfsp->descriptors[i].size = 0U;
  107. }
  108. }
  109. static flash_offset_t mfs_flash_get_bank_offset(MFSDriver *mfsp,
  110. mfs_bank_t bank) {
  111. return bank == MFS_BANK_0 ? flashGetSectorOffset(mfsp->config->flashp,
  112. mfsp->config->bank0_start) :
  113. flashGetSectorOffset(mfsp->config->flashp,
  114. mfsp->config->bank1_start);
  115. }
  116. /**
  117. * @brief Flash read.
  118. *
  119. * @param[in] mfsp pointer to the @p MFSDriver object
  120. * @param[in] offset flash offset
  121. * @param[in] n number of bytes to be read
  122. * @param[out] rp pointer to the data buffer
  123. * @return The operation status.
  124. *
  125. * @notapi
  126. */
  127. static mfs_error_t mfs_flash_read(MFSDriver *mfsp, flash_offset_t offset,
  128. size_t n, uint8_t *rp) {
  129. flash_error_t ferr;
  130. ferr = flashRead(mfsp->config->flashp, offset, n, rp);
  131. if (ferr != FLASH_NO_ERROR) {
  132. mfsp->state = MFS_ERROR;
  133. return MFS_ERR_FLASH_FAILURE;
  134. }
  135. return MFS_NO_ERROR;
  136. }
  137. /**
  138. * @brief Flash write.
  139. * @note If the option @p MFS_CFG_WRITE_VERIFY is enabled then the flash
  140. * is also read back for verification.
  141. *
  142. * @param[in] mfsp pointer to the @p MFSDriver object
  143. * @param[in] offset flash offset
  144. * @param[in] n number of bytes to be written
  145. * @param[in] wp pointer to the data buffer
  146. * @return The operation status.
  147. *
  148. * @notapi
  149. */
  150. static mfs_error_t mfs_flash_write(MFSDriver *mfsp,
  151. flash_offset_t offset,
  152. size_t n,
  153. const uint8_t *wp) {
  154. flash_error_t ferr;
  155. ferr = flashProgram(mfsp->config->flashp, offset, n, wp);
  156. if (ferr != FLASH_NO_ERROR) {
  157. mfsp->state = MFS_ERROR;
  158. return MFS_ERR_FLASH_FAILURE;
  159. }
  160. #if MFS_CFG_WRITE_VERIFY == TRUE
  161. /* Verifying the written data by reading it back and comparing.*/
  162. while (n > 0U) {
  163. size_t chunk = n <= MFS_CFG_BUFFER_SIZE ? n : MFS_CFG_BUFFER_SIZE;
  164. RET_ON_ERROR(mfs_flash_read(mfsp, offset, chunk, mfsp->buffer.data8));
  165. if (memcmp((void *)mfsp->buffer.data8, (void *)wp, chunk)) {
  166. mfsp->state = MFS_ERROR;
  167. return MFS_ERR_FLASH_FAILURE;
  168. }
  169. n -= chunk;
  170. offset += (flash_offset_t)chunk;
  171. wp += chunk;
  172. }
  173. #endif
  174. return MFS_NO_ERROR;
  175. }
  176. /**
  177. * @brief Flash copy.
  178. * @note If the option @p MFS_CFG_WRITE_VERIFY is enabled then the flash
  179. * is also read back for verification.
  180. *
  181. * @param[in] mfsp pointer to the @p MFSDriver object
  182. * @param[in] doffset destination flash offset
  183. * @param[in] soffset source flash offset
  184. * @param[in] n number of bytes to be copied
  185. * @return The operation status.
  186. *
  187. * @notapi
  188. */
  189. static mfs_error_t mfs_flash_copy(MFSDriver *mfsp,
  190. flash_offset_t doffset,
  191. flash_offset_t soffset,
  192. uint32_t n) {
  193. /* Splitting the operation in smaller operations because the buffer is
  194. small.*/
  195. while (n > 0U) {
  196. /* Data size that can be written in a single program page operation.*/
  197. size_t chunk = (size_t)(((doffset | (MFS_CFG_BUFFER_SIZE - 1U)) + 1U) -
  198. doffset);
  199. if (chunk > n) {
  200. chunk = n;
  201. }
  202. RET_ON_ERROR(mfs_flash_read(mfsp, soffset, chunk, mfsp->buffer.data8));
  203. RET_ON_ERROR(mfs_flash_write(mfsp, doffset, chunk, mfsp->buffer.data8));
  204. /* Next page.*/
  205. soffset += chunk;
  206. doffset += chunk;
  207. n -= chunk;
  208. }
  209. return MFS_NO_ERROR;
  210. }
  211. /**
  212. * @brief Verifies integrity of a record.
  213. *
  214. * @param[in] mfsp pointer to the @p MFSDriver object
  215. * @param[in] dhdrp pointer to the header to be checked
  216. * @param[in] offset flash offset of the header to be checked
  217. * @param[in] limit flash limit offset
  218. * @param[out] sts assessed record state
  219. * @return The operation status.
  220. *
  221. * @notapi
  222. */
  223. static mfs_error_t mfs_record_check(MFSDriver *mfsp,
  224. mfs_data_header_t *dhdrp,
  225. flash_offset_t offset,
  226. flash_offset_t limit,
  227. mfs_record_state_t *sts) {
  228. unsigned i;
  229. for (i = 0; i < 3; i++) {
  230. if (dhdrp->hdr32[i] != mfsp->config->erased) {
  231. /* Not erased must verify the header.*/
  232. if ((dhdrp->fields.magic != MFS_HEADER_MAGIC) ||
  233. (dhdrp->fields.id < (uint16_t)1) ||
  234. (dhdrp->fields.id > (uint16_t)MFS_CFG_MAX_RECORDS) ||
  235. (dhdrp->fields.size + sizeof (mfs_data_header_t) > limit - offset)) {
  236. *sts = MFS_RECORD_GARBAGE;
  237. return MFS_NO_ERROR;
  238. }
  239. #if MFS_CFG_STRONG_CHECKING == TRUE
  240. {
  241. /* TODO: Checking the CRC while reading the record data.*/
  242. /* *sts = MFS_RECORD_CRC;
  243. return MFS_NO_ERROR;*/
  244. }
  245. #endif
  246. *sts = MFS_RECORD_OK;
  247. return MFS_NO_ERROR;
  248. }
  249. }
  250. /* It is fully erased.*/
  251. *sts = MFS_RECORD_ERASED;
  252. return MFS_NO_ERROR;
  253. }
  254. /**
  255. * @brief Erases and verifies all sectors belonging to a bank.
  256. *
  257. * @param[in] mfsp pointer to the @p MFSDriver object
  258. * @param[in] bank bank to be erased
  259. * @return The operation status.
  260. *
  261. * @notapi
  262. */
  263. static mfs_error_t mfs_bank_erase(MFSDriver *mfsp, mfs_bank_t bank) {
  264. flash_sector_t sector, end;
  265. if (bank == MFS_BANK_0) {
  266. sector = mfsp->config->bank0_start;
  267. end = mfsp->config->bank0_start + mfsp->config->bank0_sectors;
  268. }
  269. else {
  270. sector = mfsp->config->bank1_start;
  271. end = mfsp->config->bank1_start + mfsp->config->bank1_sectors;
  272. }
  273. while (sector < end) {
  274. flash_error_t ferr;
  275. ferr = flashStartEraseSector(mfsp->config->flashp, sector);
  276. if (ferr != FLASH_NO_ERROR) {
  277. mfsp->state = MFS_ERROR;
  278. return MFS_ERR_FLASH_FAILURE;
  279. }
  280. ferr = flashWaitErase(mfsp->config->flashp);
  281. if (ferr != FLASH_NO_ERROR) {
  282. mfsp->state = MFS_ERROR;
  283. return MFS_ERR_FLASH_FAILURE;
  284. }
  285. ferr = flashVerifyErase(mfsp->config->flashp, sector);
  286. if (ferr != FLASH_NO_ERROR) {
  287. mfsp->state = MFS_ERROR;
  288. return MFS_ERR_FLASH_FAILURE;
  289. }
  290. sector++;
  291. }
  292. return MFS_NO_ERROR;
  293. }
  294. /**
  295. * @brief Erases and verifies all sectors belonging to a bank.
  296. *
  297. * @param[in] mfsp pointer to the @p MFSDriver object
  298. * @param[in] bank bank to be verified
  299. * @return The operation status.
  300. *
  301. * @notapi
  302. */
  303. static mfs_error_t mfs_bank_verify_erase(MFSDriver *mfsp, mfs_bank_t bank) {
  304. flash_sector_t sector, end;
  305. if (bank == MFS_BANK_0) {
  306. sector = mfsp->config->bank0_start;
  307. end = mfsp->config->bank0_start + mfsp->config->bank0_sectors;
  308. }
  309. else {
  310. sector = mfsp->config->bank1_start;
  311. end = mfsp->config->bank1_start + mfsp->config->bank1_sectors;
  312. }
  313. while (sector < end) {
  314. flash_error_t ferr;
  315. ferr = flashVerifyErase(mfsp->config->flashp, sector);
  316. if (ferr == FLASH_ERROR_VERIFY) {
  317. return MFS_ERR_NOT_ERASED;
  318. }
  319. if (ferr != FLASH_NO_ERROR) {
  320. mfsp->state = MFS_ERROR;
  321. return MFS_ERR_FLASH_FAILURE;
  322. }
  323. sector++;
  324. }
  325. return MFS_NO_ERROR;
  326. }
  327. /**
  328. * @brief Writes the validation header in a bank.
  329. *
  330. * @param[in] mfsp pointer to the @p MFSDriver object
  331. * @param[in] bank bank to be validated
  332. * @param[in] cnt value for the flash usage counter
  333. * @return The operation status.
  334. * @retval MFS_NO_ERROR if the operation has been successfully completed.
  335. *
  336. * @notapi
  337. */
  338. static mfs_error_t mfs_bank_write_header(MFSDriver *mfsp,
  339. mfs_bank_t bank,
  340. uint32_t cnt) {
  341. flash_sector_t sector;
  342. mfs_bank_header_t bhdr;
  343. if (bank == MFS_BANK_0) {
  344. sector = mfsp->config->bank0_start;
  345. }
  346. else {
  347. sector = mfsp->config->bank1_start;
  348. }
  349. bhdr.fields.magic1 = MFS_BANK_MAGIC_1;
  350. bhdr.fields.magic2 = MFS_BANK_MAGIC_2;
  351. bhdr.fields.counter = cnt;
  352. bhdr.fields.reserved1 = (uint16_t)mfsp->config->erased;
  353. bhdr.fields.crc = crc16(0xFFFFU, bhdr.hdr8,
  354. sizeof (mfs_bank_header_t) - sizeof (uint16_t));
  355. return mfs_flash_write(mfsp,
  356. flashGetSectorOffset(mfsp->config->flashp, sector),
  357. sizeof (mfs_bank_header_t),
  358. bhdr.hdr8);
  359. }
  360. /**
  361. * @brief Scans blocks searching for records.
  362. * @note The block integrity is strongly checked.
  363. *
  364. * @param[in] mfsp pointer to the @p MFSDriver object
  365. * @param[in] bank the bank identifier
  366. * @param[out] statep bank state, it can be:
  367. * - MFS_BANK_PARTIAL
  368. * - MFS_BANK_OK
  369. * .
  370. *
  371. * @return The operation status.
  372. *
  373. * @notapi
  374. */
  375. static mfs_error_t mfs_bank_scan_records(MFSDriver *mfsp,
  376. mfs_bank_t bank,
  377. mfs_bank_state_t *statep) {
  378. flash_offset_t hdr_offset, start_offset, end_offset;
  379. mfs_record_state_t sts;
  380. bool warning = false;
  381. start_offset = mfs_flash_get_bank_offset(mfsp, bank);
  382. end_offset = start_offset + mfsp->config->bank_size;
  383. /* Scanning records.*/
  384. hdr_offset = start_offset + (flash_offset_t)sizeof(mfs_bank_header_t);
  385. while (hdr_offset < end_offset) {
  386. uint32_t size;
  387. /* Reading the current record header.*/
  388. RET_ON_ERROR(mfs_flash_read(mfsp, hdr_offset,
  389. sizeof (mfs_data_header_t),
  390. (void *)&mfsp->buffer.dhdr));
  391. /* Checking header/data integrity.*/
  392. RET_ON_ERROR(mfs_record_check(mfsp, &mfsp->buffer.dhdr,
  393. hdr_offset, end_offset, &sts));
  394. if (sts == MFS_RECORD_ERASED) {
  395. /* Record area fully erased, stopping scan.*/
  396. break;
  397. }
  398. else if (sts == MFS_RECORD_OK) {
  399. /* Record OK.*/
  400. size = mfsp->buffer.dhdr.fields.size;
  401. /* Zero-sized records are erase markers.*/
  402. if (size == 0U) {
  403. mfsp->descriptors[mfsp->buffer.dhdr.fields.id - 1U].offset = 0U;
  404. mfsp->descriptors[mfsp->buffer.dhdr.fields.id - 1U].size = 0U;
  405. }
  406. else {
  407. mfsp->descriptors[mfsp->buffer.dhdr.fields.id - 1U].offset = hdr_offset;
  408. mfsp->descriptors[mfsp->buffer.dhdr.fields.id - 1U].size = size;
  409. }
  410. }
  411. else if (sts == MFS_RECORD_CRC) {
  412. /* Record payload corrupted, scan can continue because the header
  413. is OK.*/
  414. size = mfsp->buffer.dhdr.fields.size;
  415. warning = true;
  416. }
  417. else {
  418. /* Unrecognized header, scanning cannot continue.*/
  419. warning = true;
  420. break;
  421. }
  422. hdr_offset = hdr_offset +
  423. (flash_offset_t)sizeof(mfs_data_header_t) +
  424. (flash_offset_t)size;
  425. }
  426. if (hdr_offset > end_offset) {
  427. return MFS_ERR_INTERNAL;
  428. }
  429. /* Final.*/
  430. mfsp->next_offset = hdr_offset;
  431. if (warning) {
  432. *statep = MFS_BANK_PARTIAL;
  433. }
  434. else {
  435. *statep = MFS_BANK_OK;
  436. }
  437. return MFS_NO_ERROR;
  438. }
  439. /**
  440. * @brief Determines the state of a bank.
  441. * @note This function does not test the bank integrity by scanning
  442. * the data area, it just checks the header.
  443. *
  444. * @param[in] mfsp pointer to the @p MFSDriver object
  445. * @param[in] bank bank to be checked
  446. * @param[out] statep bank state, it can be:
  447. * - MFS_BANK_ERASED
  448. * - MFS_BANK_GARBAGE
  449. * - MFS_BANK_OK
  450. * .
  451. * @param[out] cntp bank counter
  452. * @return The operation status.
  453. *
  454. * @notapi
  455. */
  456. static mfs_error_t mfs_bank_get_state(MFSDriver *mfsp,
  457. mfs_bank_t bank,
  458. mfs_bank_state_t *statep,
  459. uint32_t * cntp) {
  460. unsigned i;
  461. mfs_error_t err;
  462. uint16_t crc;
  463. /* Worst case is default.*/
  464. *statep = MFS_BANK_GARBAGE;
  465. *cntp = 0U;
  466. /* Reading the current bank header.*/
  467. RET_ON_ERROR(mfs_flash_read(mfsp, mfs_flash_get_bank_offset(mfsp, bank),
  468. sizeof (mfs_bank_header_t),
  469. (void *)&mfsp->buffer.bhdr));
  470. /* Checking the special case where the header is erased.*/
  471. for (i = 0; i < 4; i++) {
  472. if (mfsp->buffer.bhdr.hdr32[i] != mfsp->config->erased) {
  473. /* Checking header fields integrity.*/
  474. if ((mfsp->buffer.bhdr.fields.magic1 != MFS_BANK_MAGIC_1) ||
  475. (mfsp->buffer.bhdr.fields.magic2 != MFS_BANK_MAGIC_2) ||
  476. (mfsp->buffer.bhdr.fields.counter == mfsp->config->erased) ||
  477. (mfsp->buffer.bhdr.fields.reserved1 != (uint16_t)mfsp->config->erased)) {
  478. return MFS_NO_ERROR;
  479. }
  480. /* Verifying header CRC.*/
  481. crc = crc16(0xFFFFU, mfsp->buffer.bhdr.hdr8,
  482. sizeof (mfs_bank_header_t) - sizeof (uint16_t));
  483. if (crc != mfsp->buffer.bhdr.fields.crc) {
  484. return MFS_NO_ERROR;
  485. }
  486. *statep = MFS_BANK_OK;
  487. *cntp = mfsp->buffer.bhdr.fields.counter;
  488. return MFS_NO_ERROR;
  489. }
  490. }
  491. /* If the header is erased then it could be the whole block erased.*/
  492. err = mfs_bank_verify_erase(mfsp, bank);
  493. if (err == MFS_NO_ERROR) {
  494. *statep = MFS_BANK_ERASED;
  495. }
  496. return err;
  497. }
  498. /**
  499. * @brief Selects a bank as current.
  500. * @note The bank header is assumed to be valid.
  501. *
  502. * @param[in] mfsp pointer to the @p MFSDriver object
  503. * @param[in] bank bank to be scanned
  504. * @param[out] statep bank state, it can be:
  505. * - MFS_BANK_ERASED
  506. * - MFS_BANK_GARBAGE
  507. * - MFS_BANK_PARTIAL
  508. * - MFS_BANK_OK
  509. * .
  510. * @return The operation status.
  511. *
  512. * @notapi
  513. */
  514. static mfs_error_t mfs_bank_mount(MFSDriver *mfsp,
  515. mfs_bank_t bank,
  516. mfs_bank_state_t *statep) {
  517. unsigned i;
  518. /* Resetting the bank state, then reading the required header data.*/
  519. mfs_state_reset(mfsp);
  520. RET_ON_ERROR(mfs_bank_get_state(mfsp, bank, statep, &mfsp->current_counter));
  521. mfsp->current_bank = bank;
  522. /* Scanning for the most recent instance of all records.*/
  523. RET_ON_ERROR(mfs_bank_scan_records(mfsp, bank, statep));
  524. /* Calculating the effective used size.*/
  525. mfsp->used_space = sizeof (mfs_bank_header_t);
  526. for (i = 0; i < MFS_CFG_MAX_RECORDS; i++) {
  527. if (mfsp->descriptors[i].offset != 0U) {
  528. mfsp->used_space += mfsp->descriptors[i].size + sizeof (mfs_data_header_t);
  529. }
  530. }
  531. return MFS_NO_ERROR;
  532. }
  533. /**
  534. * @brief Enforces a garbage collection.
  535. * @details Storage data is compacted into a single bank.
  536. *
  537. * @param[out] mfsp pointer to the @p MFSDriver object
  538. * @return The operation status.
  539. *
  540. * @notapi
  541. */
  542. static mfs_error_t mfs_garbage_collect(MFSDriver *mfsp) {
  543. unsigned i;
  544. mfs_bank_t sbank, dbank;
  545. flash_offset_t dest_offset;
  546. sbank = mfsp->current_bank;
  547. if (sbank == MFS_BANK_0) {
  548. dbank = MFS_BANK_1;
  549. }
  550. else {
  551. dbank = MFS_BANK_0;
  552. }
  553. /* Write address.*/
  554. dest_offset = mfs_flash_get_bank_offset(mfsp, dbank) +
  555. sizeof (mfs_bank_header_t);
  556. /* Copying the most recent record instances only.*/
  557. for (i = 0; i < MFS_CFG_MAX_RECORDS; i++) {
  558. uint32_t totsize = mfsp->descriptors[i].size + sizeof (mfs_data_header_t);
  559. if (mfsp->descriptors[i].offset != 0) {
  560. RET_ON_ERROR(mfs_flash_copy(mfsp, dest_offset,
  561. mfsp->descriptors[i].offset,
  562. totsize));
  563. mfsp->descriptors[i].offset = dest_offset;
  564. dest_offset += totsize;
  565. }
  566. }
  567. /* New current bank.*/
  568. mfsp->current_bank = dbank;
  569. mfsp->current_counter += 1U;
  570. mfsp->next_offset = dest_offset;
  571. /* The header is written after the data.*/
  572. RET_ON_ERROR(mfs_bank_write_header(mfsp, dbank, mfsp->current_counter));
  573. /* The source bank is erased last.*/
  574. RET_ON_ERROR(mfs_bank_erase(mfsp, sbank));
  575. return MFS_NO_ERROR;
  576. }
  577. /**
  578. * @brief Performs a flash partition mount attempt.
  579. *
  580. * @param[in] mfsp pointer to the @p MFSDriver object
  581. * @return The operation status.
  582. *
  583. * @api
  584. */
  585. static mfs_error_t mfs_try_mount(MFSDriver *mfsp) {
  586. mfs_bank_state_t sts, sts0, sts1;
  587. mfs_bank_t bank;
  588. uint32_t cnt0 = 0, cnt1 = 0;
  589. bool warning = false;
  590. /* Assessing the state of the two banks.*/
  591. RET_ON_ERROR(mfs_bank_get_state(mfsp, MFS_BANK_0, &sts0, &cnt0));
  592. RET_ON_ERROR(mfs_bank_get_state(mfsp, MFS_BANK_1, &sts1, &cnt1));
  593. /* Handling all possible scenarios, each one requires its own recovery
  594. strategy.*/
  595. switch (PAIR(sts0, sts1)) {
  596. case PAIR(MFS_BANK_ERASED, MFS_BANK_ERASED):
  597. /* Both banks erased, first initialization.*/
  598. RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, 1));
  599. bank = MFS_BANK_0;
  600. break;
  601. case PAIR(MFS_BANK_OK, MFS_BANK_OK):
  602. /* Both banks appear to be valid but one must be newer, erasing the
  603. older one.*/
  604. if (cnt0 > cnt1) {
  605. /* Bank 0 is newer.*/
  606. RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
  607. bank = MFS_BANK_0;
  608. }
  609. else {
  610. /* Bank 1 is newer.*/
  611. RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
  612. bank = MFS_BANK_1;
  613. }
  614. warning = true;
  615. break;
  616. case PAIR(MFS_BANK_GARBAGE, MFS_BANK_GARBAGE):
  617. /* Both banks are unreadable, reinitializing.*/
  618. RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
  619. RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
  620. RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, 1));
  621. bank = MFS_BANK_0;
  622. warning = true;
  623. break;
  624. case PAIR(MFS_BANK_ERASED, MFS_BANK_OK):
  625. /* Normal situation, bank one is used.*/
  626. bank = MFS_BANK_1;
  627. break;
  628. case PAIR(MFS_BANK_OK, MFS_BANK_ERASED):
  629. /* Normal situation, bank zero is used.*/
  630. bank = MFS_BANK_0;
  631. break;
  632. case PAIR(MFS_BANK_ERASED, MFS_BANK_GARBAGE):
  633. /* Bank zero is erased, bank one is not readable.*/
  634. RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
  635. RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, 1));
  636. bank = MFS_BANK_0;
  637. warning = true;
  638. break;
  639. case PAIR(MFS_BANK_GARBAGE, MFS_BANK_ERASED):
  640. /* Bank zero is not readable, bank one is erased.*/
  641. RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
  642. RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_1, 1));
  643. bank = MFS_BANK_1;
  644. warning = true;
  645. break;
  646. case PAIR(MFS_BANK_OK, MFS_BANK_GARBAGE):
  647. /* Bank zero is normal, bank one is unreadable.*/
  648. RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
  649. bank = MFS_BANK_0;
  650. warning = true;
  651. break;
  652. case PAIR(MFS_BANK_GARBAGE, MFS_BANK_OK):
  653. /* Bank zero is unreadable, bank one is normal.*/
  654. RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
  655. bank = MFS_BANK_1;
  656. warning = true;
  657. break;
  658. default:
  659. return MFS_ERR_INTERNAL;
  660. }
  661. /* Mounting the bank.*/
  662. RET_ON_ERROR(mfs_bank_mount(mfsp, bank, &sts));
  663. /* This condition should not occur, the bank has just been repaired.*/
  664. if ((sts == MFS_BANK_ERASED) || (sts == MFS_BANK_GARBAGE)) {
  665. return MFS_ERR_INTERNAL;
  666. }
  667. /* In case of detected problems then a garbage collection is performed in
  668. order to repair/remove anomalies.*/
  669. if (sts == MFS_BANK_PARTIAL) {
  670. RET_ON_ERROR(mfs_garbage_collect(mfsp));
  671. warning = true;
  672. }
  673. return warning ? MFS_WARN_REPAIR : MFS_NO_ERROR;
  674. }
  675. /**
  676. * @brief Configures and activates a MFS driver.
  677. *
  678. * @param[in] mfsp pointer to the @p MFSDriver object
  679. * @return The operation status.
  680. * @retval MFS_NO_ERROR if the operation has been successfully completed.
  681. * @retval MFS_WARN_GC if the operation triggered a garbage collection.
  682. * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
  683. * failures. Makes the driver enter the @p MFS_ERROR state.
  684. * @retval MFS_ERR_INTERNAL if an internal logic failure is detected.
  685. *
  686. * @api
  687. */
  688. mfs_error_t mfs_mount(MFSDriver *mfsp) {
  689. unsigned i;
  690. /* Resetting previous state.*/
  691. mfs_state_reset(mfsp);
  692. /* Attempting to mount the managed partition.*/
  693. for (i = 0; i < MFS_CFG_MAX_REPAIR_ATTEMPTS; i++) {
  694. mfs_error_t err;
  695. err = mfs_try_mount(mfsp);
  696. if (err == MFS_ERR_INTERNAL) {
  697. /* Special case, do not retry on internal errors but report
  698. immediately.*/
  699. mfsp->state = MFS_ERROR;
  700. return err;
  701. }
  702. if (!MFS_IS_ERROR(err)) {
  703. mfsp->state = MFS_READY;
  704. return err;
  705. }
  706. }
  707. /* Driver start failed.*/
  708. mfsp->state = MFS_ERROR;
  709. return MFS_ERR_FLASH_FAILURE;
  710. }
  711. /*===========================================================================*/
  712. /* Driver exported functions. */
  713. /*===========================================================================*/
  714. /**
  715. * @brief Initializes an instance.
  716. *
  717. * @param[out] mfsp pointer to the @p MFSDriver object
  718. *
  719. * @init
  720. */
  721. void mfsObjectInit(MFSDriver *mfsp) {
  722. osalDbgCheck(mfsp != NULL);
  723. mfsp->state = MFS_STOP;
  724. mfsp->config = NULL;
  725. }
  726. /**
  727. * @brief Configures and activates a MFS driver.
  728. *
  729. * @param[in] mfsp pointer to the @p MFSDriver object
  730. * @param[in] config pointer to the configuration
  731. * @return The operation status.
  732. * @retval MFS_NO_ERROR if the operation has been successfully completed.
  733. * @retval MFS_WARN_GC if the operation triggered a garbage collection.
  734. * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
  735. * failures. Makes the driver enter the @p MFS_ERROR state.
  736. * @retval MFS_ERR_INTERNAL if an internal logic failure is detected.
  737. *
  738. * @api
  739. */
  740. mfs_error_t mfsStart(MFSDriver *mfsp, const MFSConfig *config) {
  741. osalDbgCheck((mfsp != NULL) && (config != NULL));
  742. osalDbgAssert((mfsp->state == MFS_STOP) || (mfsp->state == MFS_READY) ||
  743. (mfsp->state == MFS_ERROR), "invalid state");
  744. /* Storing configuration.*/
  745. mfsp->config = config;
  746. return mfs_mount(mfsp);
  747. }
  748. /**
  749. * @brief Deactivates a MFS driver.
  750. *
  751. * @param[in] mfsp pointer to the @p MFSDriver object
  752. *
  753. * @api
  754. */
  755. void mfsStop(MFSDriver *mfsp) {
  756. osalDbgCheck(mfsp != NULL);
  757. osalDbgAssert((mfsp->state == MFS_STOP) || (mfsp->state == MFS_READY) ||
  758. (mfsp->state == MFS_ERROR), "invalid state");
  759. mfsp->config = NULL;
  760. mfsp->state = MFS_STOP;
  761. }
  762. /**
  763. * @brief Destroys the state of the managed storage by erasing the flash.
  764. *
  765. * @param[in] mfsp pointer to the @p MFSDriver object
  766. * @return The operation status.
  767. * @retval MFS_ERR_INV_STATE if the driver is in not in @p MSG_READY state.
  768. * @retval MFS_NO_ERROR if the operation has been successfully completed.
  769. * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
  770. * failures. Makes the driver enter the @p MFS_ERROR state.
  771. * @retval MFS_ERR_INTERNAL if an internal logic failure is detected.
  772. *
  773. * @api
  774. */
  775. mfs_error_t mfsErase(MFSDriver *mfsp) {
  776. osalDbgCheck(mfsp != NULL);
  777. if (mfsp->state != MFS_READY) {
  778. return MFS_ERR_INV_STATE;
  779. }
  780. RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
  781. RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
  782. return mfs_mount(mfsp);
  783. }
  784. /**
  785. * @brief Retrieves and reads a data record.
  786. *
  787. * @param[in] mfsp pointer to the @p MFSDriver object
  788. * @param[in] id record numeric identifier, the valid range is between
  789. * @p 1 and @p MFS_CFG_MAX_RECORDS
  790. * @param[in,out] np on input is the maximum buffer size, on return it is
  791. * the size of the data copied into the buffer
  792. * @param[out] buffer pointer to a buffer for record data
  793. * @return The operation status.
  794. * @retval MFS_NO_ERROR if the operation has been successfully completed.
  795. * @retval MFS_ERR_INV_STATE if the driver is in not in @p MSG_READY state.
  796. * @retval MFS_ERR_INV_SIZE if the passed buffer is not large enough to
  797. * contain the record data.
  798. * @retval MFS_ERR_NOT_FOUND if the specified id does not exists.
  799. * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
  800. * failures. Makes the driver enter the @p MFS_ERROR state.
  801. * @retval MFS_ERR_INTERNAL if an internal logic failure is detected.
  802. *
  803. * @api
  804. */
  805. mfs_error_t mfsReadRecord(MFSDriver *mfsp, mfs_id_t id,
  806. size_t *np, uint8_t *buffer) {
  807. uint16_t crc;
  808. osalDbgCheck((mfsp != NULL) &&
  809. (id >= 1U) && (id <= (mfs_id_t)MFS_CFG_MAX_RECORDS) &&
  810. (np != NULL) && (buffer != NULL));
  811. if (mfsp->state != MFS_READY) {
  812. return MFS_ERR_INV_STATE;
  813. }
  814. /* Checking if the requested record actually exists.*/
  815. if (mfsp->descriptors[id - 1U].offset == 0U) {
  816. return MFS_ERR_NOT_FOUND;
  817. }
  818. /* Making sure to not overflow the buffer.*/
  819. if (*np < mfsp->descriptors[id - 1U].size) {
  820. return MFS_ERR_INV_SIZE;
  821. }
  822. /* Header read from flash.*/
  823. RET_ON_ERROR(mfs_flash_read(mfsp,
  824. mfsp->descriptors[id - 1U].offset,
  825. sizeof (mfs_data_header_t),
  826. mfsp->buffer.data8));
  827. /* Data read from flash.*/
  828. *np = mfsp->descriptors[id - 1U].size;
  829. RET_ON_ERROR(mfs_flash_read(mfsp,
  830. mfsp->descriptors[id - 1U].offset + sizeof (mfs_data_header_t),
  831. *np,
  832. buffer));
  833. /* Checking CRC.*/
  834. crc = crc16(0xFFFFU, buffer, *np);
  835. if (crc != mfsp->buffer.dhdr.fields.crc) {
  836. mfsp->state = MFS_ERROR;
  837. return MFS_ERR_FLASH_FAILURE;
  838. }
  839. return MFS_NO_ERROR;
  840. }
  841. /**
  842. * @brief Creates or updates a data record.
  843. *
  844. * @param[in] mfsp pointer to the @p MFSDriver object
  845. * @param[in] id record numeric identifier, the valid range is between
  846. * @p 1 and @p MFS_CFG_MAX_RECORDS
  847. * @param[in] n size of data to be written, it cannot be zero
  848. * @param[in] buffer pointer to a buffer for record data
  849. * @return The operation status.
  850. * @retval MFS_NO_ERROR if the operation has been successfully completed.
  851. * @retval MFS_WARN_GC if the operation triggered a garbage collection.
  852. * @retval MFS_ERR_INV_STATE if the driver is in not in @p MSG_READY state.
  853. * @retval MFS_ERR_OUT_OF_MEM if there is not enough flash space for the
  854. * operation.
  855. * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
  856. * failures. Makes the driver enter the @p MFS_ERROR state.
  857. * @retval MFS_ERR_INTERNAL if an internal logic failure is detected.
  858. *
  859. * @api
  860. */
  861. mfs_error_t mfsWriteRecord(MFSDriver *mfsp, mfs_id_t id,
  862. size_t n, const uint8_t *buffer) {
  863. flash_offset_t free, required;
  864. bool warning = false;
  865. osalDbgCheck((mfsp != NULL) &&
  866. (id >= 1U) && (id <= (mfs_id_t)MFS_CFG_MAX_RECORDS) &&
  867. (n > 0U) && (buffer != NULL));
  868. if (mfsp->state != MFS_READY) {
  869. return MFS_ERR_INV_STATE;
  870. }
  871. /* If the required space is beyond the available (compacted) block
  872. size then an error is returned.
  873. NOTE: The space for one extra header is reserved in order to allow
  874. for an erase operation after the space has been fully allocated.*/
  875. required = ((flash_offset_t)sizeof (mfs_data_header_t) * 2U) +
  876. (flash_offset_t)n;
  877. if (required > mfsp->config->bank_size - mfsp->used_space) {
  878. return MFS_ERR_OUT_OF_MEM;
  879. }
  880. /* Checking for immediately (not compacted) available space.*/
  881. free = (mfs_flash_get_bank_offset(mfsp, mfsp->current_bank) +
  882. mfsp->config->bank_size) - mfsp->next_offset;
  883. if (required > free) {
  884. /* We need to perform a garbage collection, there is enough space
  885. but it has to be freed.*/
  886. warning = true;
  887. RET_ON_ERROR(mfs_garbage_collect(mfsp));
  888. }
  889. /* Writing the data header without the magic, it will be written last.*/
  890. mfsp->buffer.dhdr.fields.magic = (uint32_t)mfsp->config->erased;
  891. mfsp->buffer.dhdr.fields.id = (uint16_t)id;
  892. mfsp->buffer.dhdr.fields.size = (uint32_t)n;
  893. mfsp->buffer.dhdr.fields.crc = crc16(0xFFFFU, buffer, n);
  894. RET_ON_ERROR(mfs_flash_write(mfsp,
  895. mfsp->next_offset,
  896. sizeof (mfs_data_header_t),
  897. mfsp->buffer.data8));
  898. /* Writing the data part.*/
  899. RET_ON_ERROR(mfs_flash_write(mfsp,
  900. mfsp->next_offset + sizeof (mfs_data_header_t),
  901. n,
  902. buffer));
  903. /* Finally writing the magic number, it seals the transaction.*/
  904. mfsp->buffer.dhdr.fields.magic = (uint32_t)MFS_HEADER_MAGIC;
  905. RET_ON_ERROR(mfs_flash_write(mfsp,
  906. mfsp->next_offset,
  907. sizeof (uint32_t),
  908. mfsp->buffer.data8));
  909. /* The size of the old record instance, if present, must be subtracted
  910. to the total used size.*/
  911. if (mfsp->descriptors[id - 1U].offset != 0U) {
  912. mfsp->used_space -= sizeof (mfs_data_header_t) +
  913. mfsp->descriptors[id - 1U].size;
  914. }
  915. /* Adjusting bank-related metadata.*/
  916. mfsp->descriptors[id - 1U].offset = mfsp->next_offset;
  917. mfsp->descriptors[id - 1U].size = (uint32_t)n;
  918. mfsp->next_offset += sizeof (mfs_data_header_t) + n;
  919. mfsp->used_space += sizeof (mfs_data_header_t) + n;
  920. return warning ? MFS_WARN_GC : MFS_NO_ERROR;
  921. }
  922. /**
  923. * @brief Erases a data record.
  924. *
  925. * @param[in] mfsp pointer to the @p MFSDriver object
  926. * @param[in] id record numeric identifier, the valid range is between
  927. * @p 1 and @p MFS_CFG_MAX_RECORDS
  928. * @return The operation status.
  929. * @retval MFS_NO_ERROR if the operation has been successfully completed.
  930. * @retval MFS_WARN_GC if the operation triggered a garbage collection.
  931. * @retval MFS_ERR_INV_STATE if the driver is in not in @p MSG_READY state.
  932. * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
  933. * failures. Makes the driver enter the @p MFS_ERROR state.
  934. * @retval MFS_ERR_INTERNAL if an internal logic failure is detected.
  935. *
  936. * @api
  937. */
  938. mfs_error_t mfsEraseRecord(MFSDriver *mfsp, mfs_id_t id) {
  939. flash_offset_t free, required;
  940. bool warning = false;
  941. osalDbgCheck((mfsp != NULL) &&
  942. (id >= 1U) && (id <= (mfs_id_t)MFS_CFG_MAX_RECORDS));
  943. if (mfsp->state != MFS_READY) {
  944. return MFS_ERR_INV_STATE;
  945. }
  946. /* Checking if the requested record actually exists.*/
  947. if (mfsp->descriptors[id - 1U].offset == 0U) {
  948. return MFS_ERR_NOT_FOUND;
  949. }
  950. /* If the required space is beyond the available (compacted) block
  951. size then an internal error is returned, it should never happen.*/
  952. required = (flash_offset_t)sizeof (mfs_data_header_t);
  953. if (required > mfsp->config->bank_size - mfsp->used_space) {
  954. return MFS_ERR_INTERNAL;
  955. }
  956. /* Checking for immediately (not compacted) available space.*/
  957. free = (mfs_flash_get_bank_offset(mfsp, mfsp->current_bank) +
  958. mfsp->config->bank_size) - mfsp->next_offset;
  959. if (required > free) {
  960. /* We need to perform a garbage collection, there is enough space
  961. but it has to be freed.*/
  962. warning = true;
  963. RET_ON_ERROR(mfs_garbage_collect(mfsp));
  964. }
  965. /* Writing the data header with size set to zero, it means that the
  966. record is logically erased.*/
  967. mfsp->buffer.dhdr.fields.magic = (uint32_t)MFS_HEADER_MAGIC;
  968. mfsp->buffer.dhdr.fields.id = (uint16_t)id;
  969. mfsp->buffer.dhdr.fields.size = (uint32_t)0;
  970. mfsp->buffer.dhdr.fields.crc = (uint16_t)0;
  971. RET_ON_ERROR(mfs_flash_write(mfsp,
  972. mfsp->next_offset,
  973. sizeof (mfs_data_header_t),
  974. mfsp->buffer.data8));
  975. /* Adjusting bank-related metadata.*/
  976. mfsp->used_space -= sizeof (mfs_data_header_t) +
  977. mfsp->descriptors[id - 1U].size;
  978. mfsp->next_offset += sizeof (mfs_data_header_t);
  979. mfsp->descriptors[id - 1U].offset = 0U;
  980. mfsp->descriptors[id - 1U].size = 0U;
  981. return warning ? MFS_WARN_GC : MFS_NO_ERROR;
  982. }
  983. /**
  984. * @brief Enforces a garbage collection operation.
  985. * @details Garbage collection involves: integrity check, optionally repairs,
  986. * obsolete data removal, data compaction and a flash bank swap.
  987. *
  988. * @param[in] mfsp pointer to the @p MFSDriver object
  989. * @return The operation status.
  990. * @retval MFS_NO_ERROR if the operation has been successfully completed.
  991. * @retval MFS_ERR_INV_STATE if the driver is in not in @p MSG_READY state.
  992. * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
  993. * failures. Makes the driver enter the @p MFS_ERROR state.
  994. * @retval MFS_ERR_INTERNAL if an internal logic failure is detected.
  995. *
  996. * @api
  997. */
  998. mfs_error_t mfsPerformGarbageCollection(MFSDriver *mfsp) {
  999. osalDbgCheck(mfsp != NULL);
  1000. if (mfsp->state != MFS_READY) {
  1001. return MFS_ERR_INV_STATE;
  1002. }
  1003. return mfs_garbage_collect(mfsp);
  1004. }
  1005. /** @} */