Line data Source code
1 : /*
2 : Please contribute your ideas! See https://ardupilot.club/dev for details
3 :
4 : This program 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 :
9 : This program is distributed in the hope that it will be useful,
10 : but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : GNU General Public License for more details.
13 :
14 : You should have received a copy of the GNU General Public License
15 : along with this program. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include <AP_HAL/AP_HAL.h>
19 : #include <AP_FlashStorage/AP_FlashStorage.h>
20 : #include <AP_Math/AP_Math.h>
21 : #include <AP_InternalError/AP_InternalError.h>
22 : #include <stdio.h>
23 :
24 : #define FLASHSTORAGE_DEBUG 0
25 :
26 : #if FLASHSTORAGE_DEBUG
27 : #define debug(fmt, args...) do { printf(fmt, ##args); } while(0)
28 : #else
29 : #define debug(fmt, args...) do { } while(0)
30 : #endif
31 :
32 : // constructor.
33 2145 : AP_FlashStorage::AP_FlashStorage(uint8_t *_mem_buffer,
34 : uint32_t _flash_sector_size,
35 : FlashWrite _flash_write,
36 : FlashRead _flash_read,
37 : FlashErase _flash_erase,
38 2145 : FlashEraseOK _flash_erase_ok) :
39 2145 : mem_buffer(_mem_buffer),
40 2145 : flash_sector_size(_flash_sector_size),
41 2145 : flash_write(_flash_write),
42 2145 : flash_read(_flash_read),
43 2145 : flash_erase(_flash_erase),
44 2145 : flash_erase_ok(_flash_erase_ok) {}
45 :
46 : // initialise storage
47 3 : bool AP_FlashStorage::init(void)
48 : {
49 : debug("running init()\n");
50 :
51 : // start with empty memory buffer
52 3 : memset(mem_buffer, 0, storage_size);
53 :
54 : // find state of sectors
55 : struct sector_header header[2];
56 :
57 : // read headers and possibly initialise if bad signature
58 7 : for (uint8_t i=0; i<2; i++) {
59 5 : if (!flash_read(i, 0, (uint8_t *)&header[i], sizeof(header[i]))) {
60 0 : return false;
61 : }
62 5 : bool bad_header = !header[i].signature_ok();
63 5 : enum SectorState state = header[i].get_state();
64 5 : if (state != SECTOR_STATE_AVAILABLE &&
65 1 : state != SECTOR_STATE_IN_USE &&
66 : state != SECTOR_STATE_FULL) {
67 1 : bad_header = true;
68 : }
69 :
70 : // initialise if bad header
71 5 : if (bad_header) {
72 1 : return erase_all();
73 : }
74 : }
75 :
76 : // work out the first sector to read from using sector states
77 2 : enum SectorState states[2] {header[0].get_state(), header[1].get_state()};
78 : uint8_t first_sector;
79 :
80 2 : if (states[0] == states[1]) {
81 0 : if (states[0] != SECTOR_STATE_AVAILABLE) {
82 0 : return erase_all();
83 : }
84 0 : first_sector = 0;
85 2 : } else if (states[0] == SECTOR_STATE_FULL) {
86 0 : first_sector = 0;
87 2 : } else if (states[1] == SECTOR_STATE_FULL) {
88 0 : first_sector = 1;
89 2 : } else if (states[0] == SECTOR_STATE_IN_USE) {
90 2 : first_sector = 0;
91 0 : } else if (states[1] == SECTOR_STATE_IN_USE) {
92 0 : first_sector = 1;
93 : } else {
94 : // doesn't matter which is first
95 0 : first_sector = 0;
96 : }
97 :
98 : // update current sector in case first sector has changed
99 2 : current_sector = first_sector;
100 :
101 : // load data from any current sectors
102 6 : for (uint8_t i=0; i<2; i++) {
103 4 : uint8_t sector = (first_sector + i) & 1;
104 4 : if (states[sector] == SECTOR_STATE_IN_USE ||
105 2 : states[sector] == SECTOR_STATE_FULL) {
106 2 : if (!load_sector(sector)) {
107 0 : return erase_all();
108 : }
109 : }
110 : }
111 :
112 : // clear any write error
113 2 : write_error = false;
114 2 : reserved_space = 0;
115 :
116 : // if the first sector is full then write out all data so we can erase it
117 2 : if (states[first_sector] == SECTOR_STATE_FULL) {
118 0 : current_sector = first_sector ^ 1;
119 0 : if (!write_all()) {
120 0 : return erase_all();
121 : }
122 : }
123 :
124 : // erase any sectors marked full
125 6 : for (uint8_t i=0; i<2; i++) {
126 4 : if (states[i] == SECTOR_STATE_FULL) {
127 0 : if (!erase_sector(i, true)) {
128 0 : return false;
129 : }
130 : }
131 : }
132 :
133 2 : reserved_space = 0;
134 :
135 : // ready to use
136 2 : return true;
137 : }
138 :
139 :
140 :
141 : // switch full sector - should only be called when safe to have CPU
142 : // offline for considerable periods as an erase will be needed
143 0 : bool AP_FlashStorage::switch_full_sector(void)
144 : {
145 : debug("running switch_full_sector()\n");
146 :
147 0 : if (in_switch_full_sector) {
148 0 : INTERNAL_ERROR(AP_InternalError::error_t::switch_full_sector_recursion);
149 0 : return false;
150 : }
151 0 : in_switch_full_sector = true;
152 0 : bool ret = protected_switch_full_sector();
153 0 : in_switch_full_sector = false;
154 0 : return ret;
155 : }
156 :
157 : // protected_switch_full_sector is protected by switch_full_sector to
158 : // avoid an infinite recursion problem; switch_full_sector calls
159 : // write() which can call switch_full_sector. This has been seen in
160 : // practice, and while it might be caused by corruption... corruption
161 : // happens.
162 0 : bool AP_FlashStorage::protected_switch_full_sector(void)
163 : {
164 : // clear any write error
165 0 : write_error = false;
166 0 : reserved_space = 0;
167 :
168 0 : if (!write_all()) {
169 0 : return false;
170 : }
171 :
172 0 : if (!erase_sector(current_sector ^ 1, true)) {
173 0 : return false;
174 : }
175 :
176 0 : return switch_sectors();
177 : }
178 :
179 : // write some data to virtual EEPROM
180 63 : bool AP_FlashStorage::write(uint16_t offset, uint16_t length)
181 : {
182 63 : if (write_error) {
183 0 : return false;
184 : }
185 : //debug("write at %u for %u write_offset=%u\n", offset, length, write_offset);
186 :
187 80 : while (length > 0) {
188 78 : uint8_t n = max_write;
189 : #if AP_FLASHSTORAGE_TYPE != AP_FLASHSTORAGE_TYPE_H7 && AP_FLASHSTORAGE_TYPE != AP_FLASHSTORAGE_TYPE_G4
190 : if (length < n) {
191 : n = length;
192 : }
193 : #endif
194 :
195 78 : const uint32_t space_available = flash_sector_size - write_offset;
196 78 : const uint32_t space_required = sizeof(struct block_header) + max_write + reserved_space;
197 78 : if (space_available < space_required) {
198 0 : if (!switch_sectors()) {
199 0 : if (!flash_erase_ok()) {
200 0 : return false;
201 : }
202 0 : if (!switch_full_sector()) {
203 0 : return false;
204 : }
205 : }
206 : }
207 :
208 : struct PACKED {
209 : struct block_header header;
210 : uint8_t data[max_write];
211 : } blk;
212 :
213 78 : blk.header.state = BLOCK_STATE_WRITING;
214 78 : blk.header.block_num = offset / block_size;
215 78 : blk.header.num_blocks_minus_one = ((n + (block_size - 1)) / block_size)-1;
216 :
217 78 : uint16_t block_ofs = blk.header.block_num*block_size;
218 78 : uint16_t block_nbytes = (blk.header.num_blocks_minus_one+1)*block_size;
219 :
220 78 : memcpy(blk.data, &mem_buffer[block_ofs], block_nbytes);
221 :
222 : #if AP_FLASHSTORAGE_TYPE == AP_FLASHSTORAGE_TYPE_F4
223 : if (!flash_write(current_sector, write_offset, (uint8_t*)&blk.header, sizeof(blk.header))) {
224 : return false;
225 : }
226 : if (!flash_write(current_sector, write_offset+sizeof(blk.header), blk.data, block_nbytes)) {
227 : return false;
228 : }
229 : blk.header.state = BLOCK_STATE_VALID;
230 : if (!flash_write(current_sector, write_offset, (uint8_t*)&blk.header, sizeof(blk.header))) {
231 : return false;
232 : }
233 : #elif AP_FLASHSTORAGE_TYPE == AP_FLASHSTORAGE_TYPE_F1
234 : blk.header.state = BLOCK_STATE_VALID;
235 : if (!flash_write(current_sector, write_offset, (uint8_t*)&blk, sizeof(blk.header) + block_nbytes)) {
236 : return false;
237 : }
238 : #elif AP_FLASHSTORAGE_TYPE == AP_FLASHSTORAGE_TYPE_H7 || AP_FLASHSTORAGE_TYPE == AP_FLASHSTORAGE_TYPE_G4
239 78 : blk.header.state = BLOCK_STATE_VALID;
240 78 : if (!flash_write(current_sector, write_offset, (uint8_t*)&blk, sizeof(blk.header) + max_write)) {
241 0 : return false;
242 : }
243 : #endif
244 :
245 78 : write_offset += sizeof(blk.header) + block_nbytes;
246 :
247 78 : uint8_t n2 = block_nbytes - (offset % block_size);
248 : //debug("write_block at %u for %u n2=%u\n", block_ofs, block_nbytes, n2);
249 78 : if (n2 > length) {
250 61 : break;
251 : }
252 17 : offset += n2;
253 17 : length -= n2;
254 : }
255 :
256 : //debug("write_offset %u\n", write_offset);
257 :
258 : // handle wrap to next sector
259 : // write data
260 : // write header word
261 63 : return true;
262 : }
263 :
264 : /*
265 : load all data from a flash sector into mem_buffer
266 : */
267 2 : bool AP_FlashStorage::load_sector(uint8_t sector)
268 : {
269 2 : uint32_t ofs = sizeof(sector_header);
270 137 : while (ofs < flash_sector_size - sizeof(struct block_header)) {
271 : struct block_header header;
272 137 : if (!flash_read(sector, ofs, (uint8_t *)&header, sizeof(header))) {
273 2 : return false;
274 : }
275 137 : enum BlockState state = (enum BlockState)header.state;
276 :
277 137 : switch (state) {
278 2 : case BLOCK_STATE_AVAILABLE:
279 : // we've reached the end
280 2 : write_offset = ofs;
281 2 : return true;
282 :
283 0 : case BLOCK_STATE_WRITING: {
284 : /*
285 : we were interrupted while writing a block. We can't
286 : re-use the data in this block as it may have some bits
287 : that are not set to 1, so by flash rules can't be set to
288 : an arbitrary value. So we skip over this block, leaving
289 : a gap. The gap size is limited to (7+1)*8=64 bytes. That
290 : gap won't be recovered until we next do an erase of this
291 : sector
292 : */
293 0 : uint16_t block_nbytes = (header.num_blocks_minus_one+1)*block_size;
294 0 : ofs += block_nbytes + sizeof(header);
295 0 : break;
296 : }
297 :
298 135 : case BLOCK_STATE_VALID: {
299 135 : uint16_t block_nbytes = (header.num_blocks_minus_one+1)*block_size;
300 135 : uint16_t block_ofs = header.block_num*block_size;
301 135 : if (block_ofs + block_nbytes > storage_size) {
302 : // the data is invalid (out of range)
303 0 : return false;
304 : }
305 135 : if (!flash_read(sector, ofs+sizeof(header), &mem_buffer[block_ofs], block_nbytes)) {
306 0 : return false;
307 : }
308 : //debug("read at %u for %u\n", block_ofs, block_nbytes);
309 135 : ofs += block_nbytes + sizeof(header);
310 135 : break;
311 : }
312 0 : default:
313 : // invalid state
314 0 : return false;
315 : }
316 : #if AP_FLASHSTORAGE_TYPE == AP_FLASHSTORAGE_TYPE_H7
317 : // offsets must be advanced to a multiple of 32 on H7
318 135 : ofs = (ofs + 31U) & ~31U;
319 : #elif AP_FLASHSTORAGE_TYPE == AP_FLASHSTORAGE_TYPE_G4
320 : // offsets must be advanced to a multiple of 8 on G4
321 : ofs = (ofs + 7U) & ~7U;
322 : #endif
323 : }
324 0 : write_offset = ofs;
325 0 : return true;
326 : }
327 :
328 : /*
329 : erase one sector
330 : */
331 2 : bool AP_FlashStorage::erase_sector(uint8_t sector, bool mark_available)
332 : {
333 2 : if (!flash_erase(sector)) {
334 0 : return false;
335 : }
336 2 : if (!mark_available) {
337 1 : return true;
338 : }
339 : struct sector_header header;
340 1 : header.set_state(SECTOR_STATE_AVAILABLE);
341 1 : return flash_write(sector, 0, (const uint8_t *)&header, sizeof(header));
342 : }
343 :
344 : /*
345 : erase both sectors
346 : */
347 1 : bool AP_FlashStorage::erase_all(void)
348 : {
349 1 : write_error = false;
350 :
351 1 : current_sector = 0;
352 1 : write_offset = sizeof(struct sector_header);
353 :
354 1 : if (!erase_sector(0, current_sector!=0)) {
355 0 : return false;
356 : }
357 1 : if (!erase_sector(1, current_sector!=1)) {
358 0 : return false;
359 : }
360 :
361 : // mark current sector as in-use
362 : struct sector_header header;
363 1 : header.set_state(SECTOR_STATE_IN_USE);
364 1 : return flash_write(current_sector, 0, (const uint8_t *)&header, sizeof(header));
365 : }
366 :
367 : /*
368 : write all of mem_buffer to current sector
369 : */
370 0 : bool AP_FlashStorage::write_all()
371 : {
372 : debug("write_all to sector %u at %u with reserved_space=%u\n",
373 : current_sector, write_offset, reserved_space);
374 0 : for (uint16_t ofs=0; ofs<storage_size; ofs += max_write) {
375 : // local variable needed to overcome problem with MIN() macro and -O0
376 0 : const uint8_t max_write_local = max_write;
377 0 : uint8_t n = MIN(max_write_local, storage_size-ofs);
378 0 : if (!all_zero(ofs, n)) {
379 0 : if (!write(ofs, n)) {
380 0 : return false;
381 : }
382 : }
383 : }
384 0 : return true;
385 : }
386 :
387 : // return true if all bytes are zero
388 0 : bool AP_FlashStorage::all_zero(uint16_t ofs, uint16_t size)
389 : {
390 0 : while (size--) {
391 0 : if (mem_buffer[ofs++] != 0) {
392 0 : return false;
393 : }
394 : }
395 0 : return true;
396 : }
397 :
398 : // switch to next sector for writing
399 0 : bool AP_FlashStorage::switch_sectors(void)
400 : {
401 0 : if (reserved_space != 0) {
402 : // other sector is already full
403 : debug("both sectors are full\n");
404 0 : return false;
405 : }
406 :
407 : struct sector_header header;
408 :
409 0 : uint8_t new_sector = current_sector ^ 1;
410 : debug("switching to sector %u\n", new_sector);
411 :
412 : // check sector is available
413 0 : if (!flash_read(new_sector, 0, (uint8_t *)&header, sizeof(header))) {
414 0 : return false;
415 : }
416 0 : if (!header.signature_ok()) {
417 0 : write_error = true;
418 0 : return false;
419 : }
420 0 : if (SECTOR_STATE_AVAILABLE != header.get_state()) {
421 0 : write_error = true;
422 : debug("new sector unavailable; state=0x%02x\n", (unsigned)header.get_state());
423 0 : return false;
424 : }
425 :
426 : // mark current sector as full. This needs to be done before we
427 : // mark the new sector as in-use so that a power failure between
428 : // the two steps doesn't leave us with an erase on the
429 : // reboot. Thanks to night-ghost for spotting this.
430 0 : header.set_state(SECTOR_STATE_FULL);
431 0 : if (!flash_write(current_sector, 0, (const uint8_t *)&header, sizeof(header))) {
432 0 : return false;
433 : }
434 :
435 : // mark new sector as in-use
436 0 : header.set_state(SECTOR_STATE_IN_USE);
437 0 : if (!flash_write(new_sector, 0, (const uint8_t *)&header, sizeof(header))) {
438 0 : return false;
439 : }
440 :
441 : // switch sectors
442 0 : current_sector = new_sector;
443 :
444 : // we need to reserve some space in next sector to ensure we can successfully do a
445 : // full write out on init()
446 0 : reserved_space = reserve_size;
447 :
448 0 : write_offset = sizeof(header);
449 0 : return true;
450 : }
451 :
452 : /*
453 : re-initialise, using current mem_buffer
454 : */
455 0 : bool AP_FlashStorage::re_initialise(void)
456 : {
457 0 : if (!flash_erase_ok()) {
458 0 : return false;
459 : }
460 0 : if (!erase_all()) {
461 0 : return false;
462 : }
463 0 : return write_all();
464 : }
465 :
466 : #if AP_FLASHSTORAGE_TYPE == AP_FLASHSTORAGE_TYPE_H7
467 : /*
468 : H7 specific sector header functions
469 : */
470 5 : bool AP_FlashStorage::sector_header::signature_ok(void) const
471 : {
472 35 : for (uint8_t i=0; i<ARRAY_SIZE(pad1); i++) {
473 30 : if (pad1[i] != 0xFFFFFFFFU || pad2[i] != 0xFFFFFFFFU || pad3[i] != 0xFFFFFFFFU) {
474 0 : return false;
475 : }
476 : }
477 5 : return signature1 == signature;
478 : }
479 :
480 9 : AP_FlashStorage::SectorState AP_FlashStorage::sector_header::get_state(void) const
481 : {
482 9 : if (state1 == 0xFFFFFFF1 &&
483 8 : state2 == 0xFFFFFFFF &&
484 4 : state3 == 0xFFFFFFFF &&
485 4 : signature1 == signature &&
486 4 : signature2 == 0xFFFFFFFF &&
487 4 : signature3 == 0xFFFFFFFF) {
488 4 : return SECTOR_STATE_AVAILABLE;
489 : }
490 5 : if (state1 == 0xFFFFFFF1 &&
491 4 : state2 == 0xFFFFFFF2 &&
492 4 : state3 == 0xFFFFFFFF &&
493 4 : signature1 == signature &&
494 4 : signature2 == signature &&
495 4 : signature3 == 0xFFFFFFFF) {
496 4 : return SECTOR_STATE_IN_USE;
497 : }
498 1 : if (state1 == 0xFFFFFFF1 &&
499 0 : state2 == 0xFFFFFFF2 &&
500 0 : state3 == 0xFFFFFFF3 &&
501 0 : signature1 == signature &&
502 0 : signature2 == signature &&
503 0 : signature3 == signature) {
504 0 : return SECTOR_STATE_FULL;
505 : }
506 1 : return SECTOR_STATE_INVALID;
507 : }
508 :
509 2 : void AP_FlashStorage::sector_header::set_state(SectorState state)
510 : {
511 2 : memset(pad1, 0xff, sizeof(pad1));
512 2 : memset(pad2, 0xff, sizeof(pad2));
513 2 : memset(pad3, 0xff, sizeof(pad3));
514 2 : switch (state) {
515 1 : case SECTOR_STATE_AVAILABLE:
516 1 : signature1 = signature;
517 1 : signature2 = 0xFFFFFFFF;
518 1 : signature3 = 0xFFFFFFFF;
519 1 : state1 = 0xFFFFFFF1;
520 1 : state2 = 0xFFFFFFFF;
521 1 : state3 = 0xFFFFFFFF;
522 1 : break;
523 1 : case SECTOR_STATE_IN_USE:
524 1 : signature1 = signature;
525 1 : signature2 = signature;
526 1 : signature3 = 0xFFFFFFFF;
527 1 : state1 = 0xFFFFFFF1;
528 1 : state2 = 0xFFFFFFF2;
529 1 : state3 = 0xFFFFFFFF;
530 1 : break;
531 0 : case SECTOR_STATE_FULL:
532 0 : signature1 = signature;
533 0 : signature2 = signature;
534 0 : signature3 = signature;
535 0 : state1 = 0xFFFFFFF1;
536 0 : state2 = 0xFFFFFFF2;
537 0 : state3 = 0xFFFFFFF3;
538 0 : break;
539 0 : default:
540 0 : break;
541 : }
542 2 : }
543 :
544 : #elif AP_FLASHSTORAGE_TYPE == AP_FLASHSTORAGE_TYPE_G4
545 : /*
546 : G4 specific sector header functions
547 : */
548 : bool AP_FlashStorage::sector_header::signature_ok(void) const
549 : {
550 : return signature1 == signature;
551 : }
552 :
553 : AP_FlashStorage::SectorState AP_FlashStorage::sector_header::get_state(void) const
554 : {
555 : if (state1 == 0xFFFFFFF1 &&
556 : state2 == 0xFFFFFFFF &&
557 : state3 == 0xFFFFFFFF &&
558 : signature1 == signature &&
559 : signature2 == 0xFFFFFFFF &&
560 : signature3 == 0xFFFFFFFF) {
561 : return SECTOR_STATE_AVAILABLE;
562 : }
563 : if (state1 == 0xFFFFFFF1 &&
564 : state2 == 0xFFFFFFF2 &&
565 : state3 == 0xFFFFFFFF &&
566 : signature1 == signature &&
567 : signature2 == signature &&
568 : signature3 == 0xFFFFFFFF) {
569 : return SECTOR_STATE_IN_USE;
570 : }
571 : if (state1 == 0xFFFFFFF1 &&
572 : state2 == 0xFFFFFFF2 &&
573 : state3 == 0xFFFFFFF3 &&
574 : signature1 == signature &&
575 : signature2 == signature &&
576 : signature3 == signature) {
577 : return SECTOR_STATE_FULL;
578 : }
579 : return SECTOR_STATE_INVALID;
580 : }
581 :
582 : void AP_FlashStorage::sector_header::set_state(SectorState state)
583 : {
584 : switch (state) {
585 : case SECTOR_STATE_AVAILABLE:
586 : signature1 = signature;
587 : signature2 = 0xFFFFFFFF;
588 : signature3 = 0xFFFFFFFF;
589 : state1 = 0xFFFFFFF1;
590 : state2 = 0xFFFFFFFF;
591 : state3 = 0xFFFFFFFF;
592 : break;
593 : case SECTOR_STATE_IN_USE:
594 : signature1 = signature;
595 : signature2 = signature;
596 : signature3 = 0xFFFFFFFF;
597 : state1 = 0xFFFFFFF1;
598 : state2 = 0xFFFFFFF2;
599 : state3 = 0xFFFFFFFF;
600 : break;
601 : case SECTOR_STATE_FULL:
602 : signature1 = signature;
603 : signature2 = signature;
604 : signature3 = signature;
605 : state1 = 0xFFFFFFF1;
606 : state2 = 0xFFFFFFF2;
607 : state3 = 0xFFFFFFF3;
608 : break;
609 : default:
610 : break;
611 : }
612 : }
613 :
614 : #elif AP_FLASHSTORAGE_TYPE == AP_FLASHSTORAGE_TYPE_F1
615 : /*
616 : F1/F3 specific sector header functions
617 : */
618 : bool AP_FlashStorage::sector_header::signature_ok(void) const
619 : {
620 : return signature1 == signature;
621 : }
622 :
623 : AP_FlashStorage::SectorState AP_FlashStorage::sector_header::get_state(void) const
624 : {
625 : if (state1 == 0xFFFFFFFF) {
626 : return SECTOR_STATE_AVAILABLE;
627 : }
628 : if (state1 == 0xFFFFFFF1) {
629 : return SECTOR_STATE_IN_USE;
630 : }
631 : if (state1 == 0xFFF2FFF1) {
632 : return SECTOR_STATE_FULL;
633 : }
634 : return SECTOR_STATE_INVALID;
635 : }
636 :
637 : void AP_FlashStorage::sector_header::set_state(SectorState state)
638 : {
639 : signature1 = signature;
640 : switch (state) {
641 : case SECTOR_STATE_AVAILABLE:
642 : state1 = 0xFFFFFFFF;
643 : break;
644 : case SECTOR_STATE_IN_USE:
645 : state1 = 0xFFFFFFF1;
646 : break;
647 : case SECTOR_STATE_FULL:
648 : state1 = 0xFFF2FFF1;
649 : break;
650 : default:
651 : break;
652 : }
653 : }
654 : #elif AP_FLASHSTORAGE_TYPE == AP_FLASHSTORAGE_TYPE_F4
655 : /*
656 : F4 specific sector header functions
657 : */
658 : bool AP_FlashStorage::sector_header::signature_ok(void) const
659 : {
660 : return signature1 == signature;
661 : }
662 :
663 : AP_FlashStorage::SectorState AP_FlashStorage::sector_header::get_state(void) const
664 : {
665 : if (state1 == 0xFF) {
666 : return SECTOR_STATE_AVAILABLE;
667 : }
668 : if (state1 == 0xFE) {
669 : return SECTOR_STATE_IN_USE;
670 : }
671 : if (state1 == 0xFC) {
672 : return SECTOR_STATE_FULL;
673 : }
674 : return SECTOR_STATE_INVALID;
675 : }
676 :
677 : void AP_FlashStorage::sector_header::set_state(SectorState state)
678 : {
679 : signature1 = signature;
680 : switch (state) {
681 : case SECTOR_STATE_AVAILABLE:
682 : state1 = 0xFF;
683 : break;
684 : case SECTOR_STATE_IN_USE:
685 : state1 = 0xFE;
686 : break;
687 : case SECTOR_STATE_FULL:
688 : state1 = 0xFC;
689 : break;
690 : default:
691 : break;
692 : }
693 : }
694 : #endif
|