ChibiOS  0.0.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  (void)mfsp;
280  }
281 #else
282  (void)mfsp;
283 #endif
284  }
285  }
286 
287  /* It is fully erased.*/
288  *sts = MFS_RECORD_ERASED;
289  return MFS_NO_ERROR;
290 }
291 
292 /**
293  * @brief Erases and verifies all sectors belonging to a bank.
294  *
295  * @param[in] mfsp pointer to the @p MFSDriver object
296  * @param[in] bank bank to be erased
297  * @return The operation status.
298  *
299  * @notapi
300  */
302  flash_sector_t sector, end;
303 
304  if (bank == MFS_BANK_0) {
305  sector = mfsp->config->bank0_start;
306  end = mfsp->config->bank0_start + mfsp->config->bank0_sectors;
307  }
308  else {
309  sector = mfsp->config->bank1_start;
310  end = mfsp->config->bank1_start + mfsp->config->bank1_sectors;
311  }
312 
313  while (sector < end) {
314  flash_error_t ferr;
315 
316  ferr = flashStartEraseSector(mfsp->config->flashp, sector);
317  if (ferr != FLASH_NO_ERROR) {
318  mfsp->state = MFS_ERROR;
319  return MFS_ERR_FLASH_FAILURE;
320  }
321  ferr = flashWaitErase(mfsp->config->flashp);
322  if (ferr != FLASH_NO_ERROR) {
323  mfsp->state = MFS_ERROR;
324  return MFS_ERR_FLASH_FAILURE;
325  }
326  ferr = flashVerifyErase(mfsp->config->flashp, sector);
327  if (ferr != FLASH_NO_ERROR) {
328  mfsp->state = MFS_ERROR;
329  return MFS_ERR_FLASH_FAILURE;
330  }
331 
332  sector++;
333  }
334 
335  return MFS_NO_ERROR;
336 }
337 
338 /**
339  * @brief Erases and verifies all sectors belonging to a bank.
340  *
341  * @param[in] mfsp pointer to the @p MFSDriver object
342  * @param[in] bank bank to be verified
343  * @return The operation status.
344  *
345  * @notapi
346  */
348  flash_sector_t sector, end;
349 
350  if (bank == MFS_BANK_0) {
351  sector = mfsp->config->bank0_start;
352  end = mfsp->config->bank0_start + mfsp->config->bank0_sectors;
353  }
354  else {
355  sector = mfsp->config->bank1_start;
356  end = mfsp->config->bank1_start + mfsp->config->bank1_sectors;
357  }
358 
359  while (sector < end) {
360  flash_error_t ferr;
361 
362  ferr = flashVerifyErase(mfsp->config->flashp, sector);
363  if (ferr == FLASH_ERROR_VERIFY) {
364  return MFS_ERR_NOT_ERASED;
365  }
366  if (ferr != FLASH_NO_ERROR) {
367  mfsp->state = MFS_ERROR;
368  return MFS_ERR_FLASH_FAILURE;
369  }
370 
371  sector++;
372  }
373 
374  return MFS_NO_ERROR;
375 }
376 
377 /**
378  * @brief Writes the validation header in a bank.
379  *
380  * @param[in] mfsp pointer to the @p MFSDriver object
381  * @param[in] bank bank to be validated
382  * @param[in] cnt value for the flash usage counter
383  * @return The operation status.
384  * @retval MFS_NO_ERROR if the operation has been successfully completed.
385  *
386  * @notapi
387  */
389  mfs_bank_t bank,
390  uint32_t cnt) {
391  flash_sector_t sector;
392  mfs_bank_header_t bhdr;
393 
394  if (bank == MFS_BANK_0) {
395  sector = mfsp->config->bank0_start;
396  }
397  else {
398  sector = mfsp->config->bank1_start;
399  }
400 
401  bhdr.fields.magic1 = MFS_BANK_MAGIC_1;
402  bhdr.fields.magic2 = MFS_BANK_MAGIC_2;
403  bhdr.fields.counter = cnt;
404  bhdr.fields.reserved1 = (uint16_t)mfsp->config->erased;
405  bhdr.fields.crc = crc16(0xFFFFU, bhdr.hdr8,
406  sizeof (mfs_bank_header_t) - sizeof (uint16_t));
407 
408  return mfs_flash_write(mfsp,
409  flashGetSectorOffset(mfsp->config->flashp, sector),
410  sizeof (mfs_bank_header_t),
411  bhdr.hdr8);
412 }
413 
414 /**
415  * @brief Scans blocks searching for records.
416  * @note The block integrity is strongly checked.
417  *
418  * @param[in] mfsp pointer to the @p MFSDriver object
419  * @param[in] bank the bank identifier
420  * @param[out] statep bank state, it can be:
421  * - MFS_BANK_PARTIAL
422  * - MFS_BANK_OK
423  * .
424  *
425  * @return The operation status.
426  *
427  * @notapi
428  */
430  mfs_bank_t bank,
431  mfs_bank_state_t *statep) {
432  flash_offset_t hdr_offset, start_offset, end_offset;
433  mfs_record_state_t sts;
434  bool warning = false;
435 
436  start_offset = mfs_flash_get_bank_offset(mfsp, bank);
437  end_offset = start_offset + mfsp->config->bank_size;
438 
439  /* Scanning records.*/
440  hdr_offset = start_offset + (flash_offset_t)sizeof(mfs_bank_header_t);
441  while (hdr_offset < end_offset) {
442  /* Reading the current record header.*/
443  RET_ON_ERROR(mfs_flash_read(mfsp, hdr_offset,
444  sizeof (mfs_data_header_t),
445  (void *)&mfsp->buffer.dhdr));
446 
447  /* Checking header/data integrity.*/
448  RET_ON_ERROR(mfs_record_check(mfsp, &mfsp->buffer.dhdr,
449  hdr_offset, end_offset, &sts));
450  if (sts == MFS_RECORD_ERASED) {
451  /* Record area fully erased, stopping scan.*/
452  break;
453  }
454  else if (sts == MFS_RECORD_OK) {
455  /* Record OK.*/
456  uint32_t size = mfsp->buffer.dhdr.fields.size;
457 
458  /* Zero-sized records are erase markers.*/
459  if (size == 0U) {
460  mfsp->descriptors[mfsp->buffer.dhdr.fields.id - 1U].offset = 0U;
461  mfsp->descriptors[mfsp->buffer.dhdr.fields.id - 1U].size = 0U;
462  }
463  else {
464  mfsp->descriptors[mfsp->buffer.dhdr.fields.id - 1U].offset = hdr_offset;
465  mfsp->descriptors[mfsp->buffer.dhdr.fields.id - 1U].size = size;
466  }
467  }
468  else if (sts == MFS_RECORD_CRC) {
469  /* Record payload corrupted, scan can continue because the header
470  is OK.*/
471  warning = true;
472  }
473  else {
474  /* Unrecognized header, scanning cannot continue.*/
475  warning = true;
476  break;
477  }
478  }
479 
480  if (hdr_offset > end_offset) {
481  return MFS_ERR_INTERNAL;
482  }
483 
484  /* Final.*/
485  mfsp->next_offset = hdr_offset;
486 
487  if (warning) {
488  *statep = MFS_BANK_PARTIAL;
489  }
490  else {
491  *statep = MFS_BANK_OK;
492  }
493 
494  return MFS_NO_ERROR;
495 }
496 
497 /**
498  * @brief Determines the state of a bank.
499  * @note This function does not test the bank integrity by scanning
500  * the data area, it just checks the header.
501  *
502  * @param[in] mfsp pointer to the @p MFSDriver object
503  * @param[in] bank bank to be checked
504  * @param[out] statep bank state, it can be:
505  * - MFS_BANK_ERASED
506  * - MFS_BANK_GARBAGE
507  * - MFS_BANK_OK
508  * .
509  * @param[out] cntp bank counter
510  * @return The operation status.
511  *
512  * @notapi
513  */
515  mfs_bank_t bank,
516  mfs_bank_state_t *statep,
517  uint32_t * cntp) {
518  unsigned i;
519  mfs_error_t err;
520  uint16_t crc;
521 
522  /* Worst case is default.*/
523  *statep = MFS_BANK_GARBAGE;
524  *cntp = 0U;
525 
526  /* Reading the current bank header.*/
527  RET_ON_ERROR(mfs_flash_read(mfsp, mfs_flash_get_bank_offset(mfsp, bank),
528  sizeof (mfs_bank_header_t),
529  (void *)&mfsp->buffer.bhdr));
530 
531  /* Checking the special case where the header is erased.*/
532  for (i = 0; i < 4; i++) {
533  if (mfsp->buffer.bhdr.hdr32[i] != mfsp->config->erased) {
534 
535  /* Checking header fields integrity.*/
536  if ((mfsp->buffer.bhdr.fields.magic1 != MFS_BANK_MAGIC_1) ||
537  (mfsp->buffer.bhdr.fields.magic2 != MFS_BANK_MAGIC_2) ||
538  (mfsp->buffer.bhdr.fields.counter == mfsp->config->erased) ||
539  (mfsp->buffer.bhdr.fields.reserved1 != (uint16_t)mfsp->config->erased)) {
540  return MFS_NO_ERROR;
541  }
542 
543  /* Verifying header CRC.*/
544  crc = crc16(0xFFFFU, mfsp->buffer.bhdr.hdr8,
545  sizeof (mfs_bank_header_t) - sizeof (uint16_t));
546  if (crc != mfsp->buffer.bhdr.fields.crc) {
547  return MFS_NO_ERROR;
548  }
549 
550  *statep = MFS_BANK_OK;
551  *cntp = mfsp->buffer.bhdr.fields.counter;
552 
553  return MFS_NO_ERROR;
554  }
555  }
556 
557  /* If the header is erased then it could be the whole block erased.*/
558  err = mfs_bank_verify_erase(mfsp, bank);
559  if (err == MFS_NO_ERROR) {
560  *statep = MFS_BANK_ERASED;
561  }
562 
563  return err;
564 }
565 
566 /**
567  * @brief Selects a bank as current.
568  * @note The bank header is assumed to be valid.
569  *
570  * @param[in] mfsp pointer to the @p MFSDriver object
571  * @param[in] bank bank to be scanned
572  * @param[out] statep bank state, it can be:
573  * - MFS_BANK_ERASED
574  * - MFS_BANK_GARBAGE
575  * - MFS_BANK_PARTIAL
576  * - MFS_BANK_OK
577  * .
578  * @return The operation status.
579  *
580  * @notapi
581  */
583  mfs_bank_t bank,
584  mfs_bank_state_t *statep) {
585  unsigned i;
586 
587  /* Resetting the bank state, then reading the required header data.*/
588  mfs_state_reset(mfsp);
589  RET_ON_ERROR(mfs_bank_get_state(mfsp, bank, statep, &mfsp->current_counter));
590  mfsp->current_bank = bank;
591 
592  /* Scanning for the most recent instance of all records.*/
593  RET_ON_ERROR(mfs_bank_scan_records(mfsp, bank, statep));
594 
595  /* Calculating the effective used size.*/
596  mfsp->used_space = sizeof (mfs_bank_header_t);
597  for (i = 0; i < MFS_CFG_MAX_RECORDS; i++) {
598  if (mfsp->descriptors[i].offset != 0U) {
599  mfsp->used_space += mfsp->descriptors[i].size + sizeof (mfs_data_header_t);
600  }
601  }
602 
603  return MFS_NO_ERROR;
604 }
605 
606 /**
607  * @brief Enforces a garbage collection.
608  * @details Storage data is compacted into a single bank.
609  *
610  * @param[out] mfsp pointer to the @p MFSDriver object
611  * @return The operation status.
612  *
613  * @notapi
614  */
616  unsigned i;
617  mfs_bank_t sbank, dbank;
618  flash_offset_t dest_offset;
619 
620  sbank = mfsp->current_bank;
621  if (sbank == MFS_BANK_0) {
622  dbank = MFS_BANK_1;
623  }
624  else {
625  dbank = MFS_BANK_0;
626  }
627 
628  /* Write address.*/
629  dest_offset = mfs_flash_get_bank_offset(mfsp, dbank) +
630  sizeof (mfs_bank_header_t);
631 
632  /* Copying the most recent record instances only.*/
633  for (i = 0; i < MFS_CFG_MAX_RECORDS; i++) {
634  uint32_t totsize = mfsp->descriptors[i].size + sizeof (mfs_data_header_t);
635  if (mfsp->descriptors[i].offset != 0) {
636  RET_ON_ERROR(mfs_flash_copy(mfsp, dest_offset,
637  mfsp->descriptors[i].offset,
638  totsize));
639  mfsp->descriptors[i].offset = dest_offset;
640  dest_offset += totsize;
641  }
642  }
643 
644  /* New current bank.*/
645  mfsp->current_bank = dbank;
646  mfsp->current_counter += 1U;
647  mfsp->next_offset = dest_offset;
648 
649  /* The header is written after the data.*/
651 
652  /* The source bank is erased last.*/
653  RET_ON_ERROR(mfs_bank_erase(mfsp, sbank));
654 
655  return MFS_NO_ERROR;
656 }
657 
658 /**
659  * @brief Performs a flash partition mount attempt.
660  *
661  * @param[in] mfsp pointer to the @p MFSDriver object
662  * @return The operation status.
663  *
664  * @api
665  */
667  mfs_bank_state_t sts, sts0, sts1;
668  mfs_bank_t bank;
669  uint32_t cnt0 = 0, cnt1 = 0;
670  bool warning = false;
671 
672  /* Assessing the state of the two banks.*/
673  RET_ON_ERROR(mfs_bank_get_state(mfsp, MFS_BANK_0, &sts0, &cnt0));
674  RET_ON_ERROR(mfs_bank_get_state(mfsp, MFS_BANK_1, &sts1, &cnt1));
675 
676  /* Handling all possible scenarios, each one requires its own recovery
677  strategy.*/
678  switch (PAIR(sts0, sts1)) {
679 
680  case PAIR(MFS_BANK_ERASED, MFS_BANK_ERASED):
681  /* Both banks erased, first initialization.*/
682  RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, 1));
683  bank = MFS_BANK_0;
684  break;
685 
686  case PAIR(MFS_BANK_OK, MFS_BANK_OK):
687  /* Both banks appear to be valid but one must be newer, erasing the
688  older one.*/
689  if (cnt0 > cnt1) {
690  /* Bank 0 is newer.*/
691  RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
692  bank = MFS_BANK_0;
693  }
694  else {
695  /* Bank 1 is newer.*/
696  RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
697  bank = MFS_BANK_1;
698  }
699  warning = true;
700  break;
701 
702  case PAIR(MFS_BANK_GARBAGE, MFS_BANK_GARBAGE):
703  /* Both banks are unreadable, reinitializing.*/
704  RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
705  RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
706  RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, 1));
707  bank = MFS_BANK_0;
708  warning = true;
709  break;
710 
711  case PAIR(MFS_BANK_ERASED, MFS_BANK_OK):
712  /* Normal situation, bank one is used.*/
713  bank = MFS_BANK_1;
714  break;
715 
716  case PAIR(MFS_BANK_OK, MFS_BANK_ERASED):
717  /* Normal situation, bank zero is used.*/
718  bank = MFS_BANK_0;
719  break;
720 
721  case PAIR(MFS_BANK_ERASED, MFS_BANK_GARBAGE):
722  /* Bank zero is erased, bank one is not readable.*/
723  RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
724  RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_0, 1));
725  bank = MFS_BANK_0;
726  warning = true;
727  break;
728 
729  case PAIR(MFS_BANK_GARBAGE, MFS_BANK_ERASED):
730  /* Bank zero is not readable, bank one is erased.*/
731  RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
732  RET_ON_ERROR(mfs_bank_write_header(mfsp, MFS_BANK_1, 1));
733  bank = MFS_BANK_1;
734  warning = true;
735  break;
736 
737  case PAIR(MFS_BANK_OK, MFS_BANK_GARBAGE):
738  /* Bank zero is normal, bank one is unreadable.*/
739  RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
740  bank = MFS_BANK_0;
741  warning = true;
742  break;
743 
744  case PAIR(MFS_BANK_GARBAGE, MFS_BANK_OK):
745  /* Bank zero is unreadable, bank one is normal.*/
746  RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
747  bank = MFS_BANK_1;
748  warning = true;
749  break;
750 
751  default:
752  return MFS_ERR_INTERNAL;
753  }
754 
755  /* Mounting the bank.*/
756  RET_ON_ERROR(mfs_bank_mount(mfsp, bank, &sts));
757 
758  /* This condition should not occur, the bank has just been repaired.*/
759  if ((sts == MFS_BANK_ERASED) || (sts == MFS_BANK_GARBAGE)) {
760  return MFS_ERR_INTERNAL;
761  }
762 
763  /* In case of detected problems then a garbage collection is performed in
764  order to repair/remove anomalies.*/
765  if (sts == MFS_BANK_PARTIAL) {
767  warning = true;
768  }
769 
770  return warning ? MFS_WARN_REPAIR : MFS_NO_ERROR;
771 }
772 
773 /**
774  * @brief Configures and activates a MFS driver.
775  *
776  * @param[in] mfsp pointer to the @p MFSDriver object
777  * @return The operation status.
778  * @retval MFS_NO_ERROR if the operation has been successfully completed.
779  * @retval MFS_WARN_GC if the operation triggered a garbage collection.
780  * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
781  * failures. Makes the driver enter the @p MFS_ERROR state.
782  * @retval MFS_ERR_INTERNAL if an internal logic failure is detected.
783  *
784  * @api
785  */
787  unsigned i;
788 
789  /* Resetting previous state.*/
790  mfs_state_reset(mfsp);
791 
792  /* Attempting to mount the managed partition.*/
793  for (i = 0; i < MFS_CFG_MAX_REPAIR_ATTEMPTS; i++) {
794  mfs_error_t err;
795 
796  err = mfs_try_mount(mfsp);
797  if (err == MFS_ERR_INTERNAL) {
798  /* Special case, do not retry on internal errors but report
799  immediately.*/
800  mfsp->state = MFS_ERROR;
801  return err;
802  }
803  if (!MFS_IS_ERROR(err)) {
804  mfsp->state = MFS_READY;
805  return err;
806  }
807  }
808 
809  /* Driver start failed.*/
810  mfsp->state = MFS_ERROR;
811  return MFS_ERR_FLASH_FAILURE;
812 }
813 
814 /*===========================================================================*/
815 /* Driver exported functions. */
816 /*===========================================================================*/
817 
818 /**
819  * @brief Initializes an instance.
820  *
821  * @param[out] mfsp pointer to the @p MFSDriver object
822  *
823  * @init
824  */
826 
827  osalDbgCheck(mfsp != NULL);
828 
829  mfsp->state = MFS_STOP;
830  mfsp->config = NULL;
831 }
832 
833 /**
834  * @brief Configures and activates a MFS driver.
835  *
836  * @param[in] mfsp pointer to the @p MFSDriver object
837  * @param[in] config pointer to the configuration
838  * @return The operation status.
839  * @retval MFS_NO_ERROR if the operation has been successfully completed.
840  * @retval MFS_WARN_GC if the operation triggered a garbage collection.
841  * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
842  * failures. Makes the driver enter the @p MFS_ERROR state.
843  * @retval MFS_ERR_INTERNAL if an internal logic failure is detected.
844  *
845  * @api
846  */
847 mfs_error_t mfsStart(MFSDriver *mfsp, const MFSConfig *config) {
848 
849  osalDbgCheck((mfsp != NULL) && (config != NULL));
850  osalDbgAssert((mfsp->state == MFS_STOP) || (mfsp->state == MFS_READY) ||
851  (mfsp->state == MFS_ERROR), "invalid state");
852 
853  /* Storing configuration.*/
854  mfsp->config = config;
855 
856  return mfs_mount(mfsp);
857 }
858 
859 /**
860  * @brief Deactivates a MFS driver.
861  *
862  * @param[in] mfsp pointer to the @p MFSDriver object
863  *
864  * @api
865  */
866 void mfsStop(MFSDriver *mfsp) {
867 
868  osalDbgCheck(mfsp != NULL);
869  osalDbgAssert((mfsp->state == MFS_STOP) || (mfsp->state == MFS_READY) ||
870  (mfsp->state == MFS_ERROR), "invalid state");
871 
872  mfsp->config = NULL;
873  mfsp->state = MFS_STOP;
874 }
875 
876 /**
877  * @brief Destroys the state of the managed storage by erasing the flash.
878  *
879  * @param[in] mfsp pointer to the @p MFSDriver object
880  * @return The operation status.
881  * @retval MFS_ERR_INV_STATE if the driver is in not in @p MSG_READY state.
882  * @retval MFS_NO_ERROR if the operation has been successfully completed.
883  * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
884  * failures. Makes the driver enter the @p MFS_ERROR state.
885  * @retval MFS_ERR_INTERNAL if an internal logic failure is detected.
886  *
887  * @api
888  */
890 
891  osalDbgCheck(mfsp != NULL);
892 
893  if (mfsp->state != MFS_READY) {
894  return MFS_ERR_INV_STATE;
895  }
896 
897  RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_0));
898  RET_ON_ERROR(mfs_bank_erase(mfsp, MFS_BANK_1));
899 
900  return mfs_mount(mfsp);
901 }
902 
903 /**
904  * @brief Retrieves and reads a data record.
905  *
906  * @param[in] mfsp pointer to the @p MFSDriver object
907  * @param[in] id record numeric identifier, the valid range is between
908  * @p 1 and @p MFS_CFG_MAX_RECORDS
909  * @param[in,out] np on input is the maximum buffer size, on return it is
910  * the size of the data copied into the buffer
911  * @param[out] buffer pointer to a buffer for record data
912  * @return The operation status.
913  * @retval MFS_NO_ERROR if the operation has been successfully completed.
914  * @retval MFS_ERR_INV_STATE if the driver is in not in @p MSG_READY state.
915  * @retval MFS_ERR_INV_SIZE if the passed buffer is not large enough to
916  * contain the record data.
917  * @retval MFS_ERR_NOT_FOUND if the specified id does not exists.
918  * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
919  * failures. Makes the driver enter the @p MFS_ERROR state.
920  * @retval MFS_ERR_INTERNAL if an internal logic failure is detected.
921  *
922  * @api
923  */
925  size_t *np, uint8_t *buffer) {
926  uint16_t crc;
927 
928  osalDbgCheck((mfsp != NULL) &&
929  (id >= 1) && (id <= (mfs_id_t)MFS_CFG_MAX_RECORDS) &&
930  (np != NULL) && (buffer != NULL));
931 
932  if (mfsp->state != MFS_READY) {
933  return MFS_ERR_INV_STATE;
934  }
935 
936  /* Checking if the requested record actually exists.*/
937  if (mfsp->descriptors[id - 1U].offset == 0U) {
938  return MFS_ERR_NOT_FOUND;
939  }
940 
941  /* Making sure to not overflow the buffer.*/
942  if (*np < mfsp->descriptors[id - 1U].size) {
943  return MFS_ERR_INV_SIZE;
944  }
945 
946  /* Header read from flash.*/
948  mfsp->descriptors[id - 1U].offset,
949  sizeof (mfs_data_header_t),
950  mfsp->buffer.data8));
951 
952  /* Data read from flash.*/
953  *np = mfsp->descriptors[id - 1U].size;
955  mfsp->descriptors[id - 1U].offset + sizeof (mfs_data_header_t),
956  *np,
957  buffer));
958 
959  /* Checking CRC.*/
960  crc = crc16(0xFFFFU, buffer, *np);
961  if (crc != mfsp->buffer.dhdr.fields.crc) {
962  mfsp->state = MFS_ERROR;
963  return MFS_ERR_FLASH_FAILURE;
964  }
965 
966  return MFS_NO_ERROR;
967 }
968 
969 /**
970  * @brief Creates or updates a data record.
971  *
972  * @param[in] mfsp pointer to the @p MFSDriver object
973  * @param[in] id record numeric identifier, the valid range is between
974  * @p 1 and @p MFS_CFG_MAX_RECORDS
975  * @param[in] n size of data to be written, it cannot be zero
976  * @param[in] buffer pointer to a buffer for record data
977  * @return The operation status.
978  * @retval MFS_NO_ERROR if the operation has been successfully completed.
979  * @retval MFS_WARN_GC if the operation triggered a garbage collection.
980  * @retval MFS_ERR_INV_STATE if the driver is in not in @p MSG_READY state.
981  * @retval MFS_ERR_OUT_OF_MEM if there is not enough flash space for the
982  * operation.
983  * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
984  * failures. Makes the driver enter the @p MFS_ERROR state.
985  * @retval MFS_ERR_INTERNAL if an internal logic failure is detected.
986  *
987  * @api
988  */
990  size_t n, const uint8_t *buffer) {
991  flash_offset_t free, required;
992  bool warning = false;
993 
994  osalDbgCheck((mfsp != NULL) &&
995  (id >= 1) && (id <= (mfs_id_t)MFS_CFG_MAX_RECORDS) &&
996  (n > 0U) && (buffer != NULL));
997 
998  if (mfsp->state != MFS_READY) {
999  return MFS_ERR_INV_STATE;
1000  }
1001 
1002  /* If the required space is beyond the available (compacted) block
1003  size then an error is returned.
1004  NOTE: The space for one extra header is reserved in order to allow
1005  for an erase operation after the space has been fully allocated.*/
1006  required = ((flash_offset_t)sizeof (mfs_data_header_t) * 2U) +
1007  (flash_offset_t)n;
1008  if (required > mfsp->config->bank_size - mfsp->used_space) {
1009  return MFS_ERR_OUT_OF_MEM;
1010  }
1011 
1012  /* Checking for immediately (not compacted) available space.*/
1013  free = (mfs_flash_get_bank_offset(mfsp, mfsp->current_bank) +
1014  mfsp->config->bank_size) - mfsp->next_offset;
1015  if (required > free) {
1016  /* We need to perform a garbage collection, there is enough space
1017  but it has to be freed.*/
1018  warning = true;
1020  }
1021 
1022  /* Writing the data header without the magic, it will be written last.*/
1023  mfsp->buffer.dhdr.fields.magic = (uint32_t)mfsp->config->erased;
1024  mfsp->buffer.dhdr.fields.id = (uint16_t)id;
1025  mfsp->buffer.dhdr.fields.size = (uint32_t)n;
1026  mfsp->buffer.dhdr.fields.crc = crc16(0xFFFFU, buffer, n);
1028  mfsp->next_offset,
1029  sizeof (mfs_data_header_t),
1030  mfsp->buffer.data8));
1031 
1032  /* Writing the data part.*/
1034  mfsp->next_offset + sizeof (mfs_data_header_t),
1035  n,
1036  buffer));
1037 
1038  /* Finally writing the magic number, it seals the transaction.*/
1039  mfsp->buffer.dhdr.fields.magic = (uint32_t)MFS_HEADER_MAGIC;
1041  mfsp->next_offset,
1042  sizeof (uint32_t),
1043  mfsp->buffer.data8));
1044 
1045  /* The size of the old record instance, if present, must be subtracted
1046  to the total used size.*/
1047  if (mfsp->descriptors[id - 1U].offset != 0U) {
1048  mfsp->used_space -= sizeof (mfs_data_header_t) +
1049  mfsp->descriptors[id - 1U].size;
1050  }
1051 
1052  /* Adjusting bank-related metadata.*/
1053  mfsp->descriptors[id - 1U].offset = mfsp->next_offset;
1054  mfsp->descriptors[id - 1U].size = (uint32_t)n;
1055  mfsp->next_offset += sizeof (mfs_data_header_t) + n;
1056  mfsp->used_space += sizeof (mfs_data_header_t) + n;
1057 
1058  return warning ? MFS_WARN_GC : MFS_NO_ERROR;
1059 }
1060 
1061 /**
1062  * @brief Erases a data record.
1063  *
1064  * @param[in] mfsp pointer to the @p MFSDriver object
1065  * @param[in] id record numeric identifier, the valid range is between
1066  * @p 1 and @p MFS_CFG_MAX_RECORDS
1067  * @return The operation status.
1068  * @retval MFS_NO_ERROR if the operation has been successfully completed.
1069  * @retval MFS_WARN_GC if the operation triggered a garbage collection.
1070  * @retval MFS_ERR_INV_STATE if the driver is in not in @p MSG_READY state.
1071  * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
1072  * failures. Makes the driver enter the @p MFS_ERROR state.
1073  * @retval MFS_ERR_INTERNAL if an internal logic failure is detected.
1074  *
1075  * @api
1076  */
1078  flash_offset_t free, required;
1079  bool warning = false;
1080 
1081  osalDbgCheck((mfsp != NULL) &&
1082  (id >= 1U) && (id <= (mfs_id_t)MFS_CFG_MAX_RECORDS));
1083 
1084  if (mfsp->state != MFS_READY) {
1085  return MFS_ERR_INV_STATE;
1086  }
1087 
1088  /* Checking if the requested record actually exists.*/
1089  if (mfsp->descriptors[id - 1U].offset == 0U) {
1090  return MFS_ERR_NOT_FOUND;
1091  }
1092 
1093  /* If the required space is beyond the available (compacted) block
1094  size then an internal error is returned, it should never happen.*/
1095  required = (flash_offset_t)sizeof (mfs_data_header_t);
1096  if (required > mfsp->config->bank_size - mfsp->used_space) {
1097  return MFS_ERR_INTERNAL;
1098  }
1099 
1100  /* Checking for immediately (not compacted) available space.*/
1101  free = (mfs_flash_get_bank_offset(mfsp, mfsp->current_bank) +
1102  mfsp->config->bank_size) - mfsp->next_offset;
1103  if (required > free) {
1104  /* We need to perform a garbage collection, there is enough space
1105  but it has to be freed.*/
1106  warning = true;
1108  }
1109 
1110  /* Writing the data header with size set to zero, it means that the
1111  record is logically erased.*/
1112  mfsp->buffer.dhdr.fields.magic = (uint32_t)MFS_HEADER_MAGIC;
1113  mfsp->buffer.dhdr.fields.id = (uint16_t)id;
1114  mfsp->buffer.dhdr.fields.size = (uint32_t)0;
1115  mfsp->buffer.dhdr.fields.crc = (uint16_t)0;
1117  mfsp->next_offset,
1118  sizeof (mfs_data_header_t),
1119  mfsp->buffer.data8));
1120 
1121  /* Adjusting bank-related metadata.*/
1122  mfsp->used_space -= sizeof (mfs_data_header_t) +
1123  mfsp->descriptors[id - 1U].size;
1124  mfsp->next_offset += sizeof (mfs_data_header_t);
1125  mfsp->descriptors[id - 1U].offset = 0U;
1126  mfsp->descriptors[id - 1U].size = 0U;
1127 
1128  return warning ? MFS_WARN_GC : MFS_NO_ERROR;
1129 }
1130 
1131 /**
1132  * @brief Enforces a garbage collection operation.
1133  * @details Garbage collection involves: integrity check, optionally repairs,
1134  * obsolete data removal, data compaction and a flash bank swap.
1135  *
1136  * @param[in] mfsp pointer to the @p MFSDriver object
1137  * @return The operation status.
1138  * @retval MFS_NO_ERROR if the operation has been successfully completed.
1139  * @retval MFS_ERR_INV_STATE if the driver is in not in @p MSG_READY state.
1140  * @retval MFS_ERR_FLASH_FAILURE if the flash memory is unusable because HW
1141  * failures. Makes the driver enter the @p MFS_ERROR state.
1142  * @retval MFS_ERR_INTERNAL if an internal logic failure is detected.
1143  *
1144  * @api
1145  */
1147 
1148  osalDbgCheck(mfsp != NULL);
1149 
1150  if (mfsp->state != MFS_READY) {
1151  return MFS_ERR_INV_STATE;
1152  }
1153 
1154  return mfs_garbage_collect(mfsp);
1155 }
1156 
1157 /** @} */
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
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:866
#define flashProgram(ip, offset, n, pp)
Program operation.
Definition: hal_flash.h:253
static mfs_error_t mfs_garbage_collect(MFSDriver *mfsp)
Enforces a garbage collection.
Definition: mfs.c:615
#define flashVerifyErase(ip, sector)
Returns the erase state of a sector.
Definition: hal_flash.h:315
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:347
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:388
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:301
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:924
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:666
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:989
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:847
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:235
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:282
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:514
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:429
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:889
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:1077
mfs_error_t mfsPerformGarbageCollection(MFSDriver *mfsp)
Enforces a garbage collection operation.
Definition: mfs.c:1146
union MFSDriver::@11 buffer
Transient buffer.
void mfsObjectInit(MFSDriver *mfsp)
Initializes an instance.
Definition: mfs.c:825
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:786
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:582
const MFSConfig * config
Current configuration data.
Definition: mfs.h:300
uint16_t id
Data identifier.
Definition: mfs.h:224