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