5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
26 uint8_t s_write_err
= 0; // error reasons
27 RlcFile theFile
; //used for any file operation
31 blkid_t freeBlocks
= 0;
34 uint8_t s_sync_write
= false;
36 static uint8_t EeFsRead(blkid_t blk
, uint8_t ofs
)
39 eepromReadBlock(&byte
, (size_t)(blk
*BS
+ofs
+BLOCKS_OFFSET
), 1);
43 static blkid_t
EeFsGetLink(blkid_t blk
)
47 eepromReadBlock((uint8_t *)&ret
, blk
*BS
+BLOCKS_OFFSET
, sizeof(blkid_t
));
50 return EeFsRead(blk
, 0);
54 static void EeFsSetLink(blkid_t blk
, blkid_t val
)
56 static blkid_t s_link
; // we write asynchronously, then nothing on the stack!
58 eepromWriteBlock((uint8_t *)&s_link
, (blk
*BS
)+BLOCKS_OFFSET
, sizeof(blkid_t
));
61 static uint8_t EeFsGetDat(blkid_t blk
, uint8_t ofs
)
63 return EeFsRead(blk
, ofs
+sizeof(blkid_t
));
66 static void EeFsSetDat(blkid_t blk
, uint8_t ofs
, uint8_t *buf
, uint8_t len
)
68 eepromWriteBlock(buf
, (blk
*BS
)+ofs
+sizeof(blkid_t
)+BLOCKS_OFFSET
, len
);
71 static void EeFsFlushFreelist()
73 eepromWriteBlock((uint8_t *)&eeFs
.freeList
, offsetof(EeFs
, freeList
), sizeof(eeFs
.freeList
));
76 static void EeFsFlushDirEnt(uint8_t i_fileId
)
78 eepromWriteBlock((uint8_t *)&eeFs
.files
[i_fileId
], offsetof(EeFs
, files
) + sizeof(DirEnt
)*i_fileId
, sizeof(DirEnt
));
81 static void EeFsFlush()
83 eepromWriteBlock((uint8_t *)&eeFs
, 0, sizeof(eeFs
));
86 uint16_t EeFsGetFree()
89 int32_t ret
= freeBlocks
* (BS
-sizeof(blkid_t
));
92 blkid_t i
= eeFs
.freeList
;
94 ret
+= BS
-sizeof(blkid_t
);
98 ret
+= eeFs
.files
[FILE_TMP
].size
;
99 ret
-= eeFs
.files
[FILE_MODEL(g_eeGeneral
.currModel
)].size
;
100 return (ret
> 0 ? ret
: 0);
103 /// free one or more blocks
104 static void EeFsFree(blkid_t blk
)
113 while ((tmp
=EeFsGetLink(i
))) {
120 EeFsSetLink(i
, eeFs
.freeList
);
121 eeFs
.freeList
= blk
; //chain in front
127 ENABLE_SYNC_WRITE(true);
129 uint8_t *bufp
= (uint8_t *)&g_model
;
130 memclear(bufp
, BLOCKS
);
136 for (uint8_t i
=0; i
<=MAXFILES
; i
++) {
140 blkid_t blk
= (i
==MAXFILES
? eeFs
.freeList
: eeFs
.files
[i
].startBlk
);
143 if (blk
< FIRSTBLK
|| // bad blk index
144 blk
>= BLOCKS
|| // bad blk indexchan
145 bufp
[blk
]) // blk double usage
148 EeFsSetLink(lastBlk
, 0);
161 blk
= EeFsGetLink(blk
);
167 freeBlocks
= blocksCount
;
170 for (blk
=FIRSTBLK
; blk
<BLOCKS
; blk
++) {
171 if (!bufp
[blk
]) { // unused block
175 EeFsSetLink(blk
, eeFs
.freeList
);
176 eeFs
.freeList
= blk
; // chain in front
181 ENABLE_SYNC_WRITE(false);
186 ENABLE_SYNC_WRITE(true);
189 // write zero to the end of the new EEPROM file to set it's proper size
190 static uint8_t dummy
= 0;
191 eepromWriteBlock(&dummy
, EEPROM_SIZE
-1, 1);
194 memclear(&eeFs
, sizeof(eeFs
));
195 eeFs
.version
= EEFS_VERS
;
196 eeFs
.mySize
= sizeof(eeFs
);
199 for (blkid_t i
=FIRSTBLK
; i
<BLOCKS
-1; i
++) {
202 EeFsSetLink(BLOCKS
-1, 0);
203 eeFs
.freeList
= FIRSTBLK
;
209 ENABLE_SYNC_WRITE(false);
214 eepromReadBlock((uint8_t *)&eeFs
, 0, sizeof(eeFs
));
217 if (eeFs
.version
!= EEFS_VERS
) {
218 TRACE("bad eeFs.version (%d instead of %d)", eeFs
.version
, EEFS_VERS
);
220 if (eeFs
.mySize
!= sizeof(eeFs
)) {
221 TRACE("bad eeFs.mySize (%d instead of %d)", (int)eeFs
.mySize
, (int)sizeof(eeFs
));
225 if (eeFs
.version
!= EEFS_VERS
|| eeFs
.mySize
!= sizeof(eeFs
)) {
233 bool EFile::exists(uint8_t i_fileId
)
235 return eeFs
.files
[i_fileId
].startBlk
;
239 * Swap two files in eeprom
241 void EFile::swap(uint8_t i_fileId1
, uint8_t i_fileId2
)
243 DirEnt tmp
= eeFs
.files
[i_fileId1
];
244 eeFs
.files
[i_fileId1
] = eeFs
.files
[i_fileId2
];
245 eeFs
.files
[i_fileId2
] = tmp
;
247 ENABLE_SYNC_WRITE(true);
248 EeFsFlushDirEnt(i_fileId1
);
249 EeFsFlushDirEnt(i_fileId2
);
250 ENABLE_SYNC_WRITE(false);
253 void EFile::rm(uint8_t i_fileId
)
255 blkid_t i
= eeFs
.files
[i_fileId
].startBlk
;
256 memclear(&eeFs
.files
[i_fileId
], sizeof(eeFs
.files
[i_fileId
]));
257 ENABLE_SYNC_WRITE(true);
258 EeFsFlushDirEnt(i_fileId
);
259 if (i
) EeFsFree(i
); //chain in
260 ENABLE_SYNC_WRITE(false);
264 * Open file i_fileId for reading.
265 * Return the file's type
267 void EFile::openRd(uint8_t i_fileId
)
271 m_currBlk
= eeFs
.files
[m_fileId
].startBlk
;
273 s_write_err
= ERR_NONE
; // error reasons */
276 void RlcFile::openRlc(uint8_t i_fileId
)
278 EFile::openRd(i_fileId
);
283 uint8_t EFile::read(uint8_t *buf
, uint8_t i_len
)
285 uint16_t len
= eeFs
.files
[m_fileId
].size
- m_pos
;
286 if (i_len
> len
) i_len
= len
;
288 uint8_t remaining
= i_len
;
290 if (!m_currBlk
) break;
292 *buf
++ = EeFsGetDat(m_currBlk
, m_ofs
++);
293 if (m_ofs
>= BS
-sizeof(blkid_t
)) {
295 m_currBlk
= EeFsGetLink(m_currBlk
);
306 * Read runlength (RLE) compressed bytes into buf.
308 uint16_t RlcFile::readRlc(uint8_t *buf
, uint16_t i_len
)
312 uint8_t ln
= min
<uint16_t>(m_zeroes
, i_len
-i
);
313 memclear(&buf
[i
], ln
);
318 ln
= min
<uint16_t>(m_bRlc
, i_len
-i
);
319 uint8_t lr
= read(&buf
[i
], ln
);
324 if (read(&m_bRlc
, 1) !=1) break; // read how many bytes to read
326 assert(m_bRlc
& 0x7f);
328 if (m_bRlc
&0x80) { // if contains high byte
329 m_zeroes
=(m_bRlc
>>4) & 0x7;
330 m_bRlc
= m_bRlc
& 0x0f;
332 else if(m_bRlc
&0x40) {
333 m_zeroes
= m_bRlc
& 0x3f;
340 void RlcFile::write1(uint8_t b
)
343 write(&m_write1_byte
, 1);
346 void RlcFile::write(uint8_t *buf
, uint8_t i_len
)
353 } while (IS_SYNC_WRITE_ENABLE() && m_write_len
&& !s_write_err
);
356 void RlcFile::nextWriteStep()
358 if (!m_currBlk
&& m_pos
==0) {
359 eeFs
.files
[FILE_TMP
].startBlk
= m_currBlk
= eeFs
.freeList
;
364 eeFs
.freeList
= EeFsGetLink(m_currBlk
);
365 m_write_step
|= WRITE_FIRST_LINK
;
371 if ((m_write_step
& 0x0f) == WRITE_FIRST_LINK
) {
372 m_write_step
-= WRITE_FIRST_LINK
;
373 EeFsSetLink(m_currBlk
, 0);
377 while (m_write_len
) {
379 s_write_err
= ERR_FULL
;
382 if (m_ofs
>= (BS
-sizeof(blkid_t
))) {
384 blkid_t nextBlk
= EeFsGetLink(m_currBlk
);
386 if (!eeFs
.freeList
) {
387 s_write_err
= ERR_FULL
;
390 m_write_step
+= WRITE_NEXT_LINK_1
;
391 EeFsSetLink(m_currBlk
, eeFs
.freeList
);
397 switch (m_write_step
& 0x0f) {
398 case WRITE_NEXT_LINK_1
:
399 m_currBlk
= eeFs
.freeList
;
403 eeFs
.freeList
= EeFsGetLink(eeFs
.freeList
);
407 case WRITE_NEXT_LINK_2
:
408 m_write_step
-= WRITE_NEXT_LINK_2
;
409 EeFsSetLink(m_currBlk
, 0);
412 uint8_t tmp
= BS
-sizeof(blkid_t
)-m_ofs
; if(tmp
>m_write_len
) tmp
= m_write_len
;
417 EeFsSetDat(m_currBlk
, m_ofs
-tmp
, m_write_buf
-tmp
, tmp
);
421 if (s_write_err
== ERR_FULL
) {
422 POPUP_WARNING(STR_EEPROMOVERFLOW
);
427 else if (!IS_SYNC_WRITE_ENABLE()) {
432 void RlcFile::create(uint8_t i_fileId
, uint8_t typ
, uint8_t sync_write
)
434 // all write operations will be executed on FILE_TMP
435 openRlc(FILE_TMP
); // internal use
436 eeFs
.files
[FILE_TMP
].typ
= typ
;
437 eeFs
.files
[FILE_TMP
].size
= 0;
439 ENABLE_SYNC_WRITE(sync_write
);
443 * Copy file src to dst
445 bool RlcFile::copy(uint8_t i_fileDst
, uint8_t i_fileSrc
)
448 theFile2
.openRd(i_fileSrc
);
450 create(i_fileDst
, FILE_TYP_MODEL
/*optimization, only model files are copied. should be eeFs.files[i_fileSrc].typ*/, true);
452 uint8_t buf
[BS
-sizeof(blkid_t
)];
454 while ((len
=theFile2
.read(buf
, sizeof(buf
))))
457 if (write_errno() != 0) {
458 ENABLE_SYNC_WRITE(false);
464 if (m_currBlk
&& (fri
=EeFsGetLink(m_currBlk
)))
465 EeFsSetLink(m_currBlk
, 0);
467 if (fri
) EeFsFree(fri
); //chain in
469 eeFs
.files
[FILE_TMP
].size
= m_pos
;
470 EFile::swap(m_fileId
, FILE_TMP
);
472 assert(!m_write_step
);
474 // s_sync_write is set to false in swap();
479 const pm_char
* eeBackupModel(uint8_t i_fileSrc
)
481 char * buf
= reusableBuffer
.modelsel
.mainname
;
484 // we must close the logs as we reuse the same FIL structure
487 // check and create folder here
488 strcpy_P(buf
, STR_MODELS_PATH
);
489 const char * error
= sdCheckAndCreateDirectory(buf
);
494 buf
[sizeof(MODELS_PATH
)-1] = '/';
495 eeLoadModelName(i_fileSrc
, &buf
[sizeof(MODELS_PATH
)]);
496 buf
[sizeof(MODELS_PATH
)+sizeof(g_model
.header
.name
)] = '\0';
498 uint8_t i
= sizeof(MODELS_PATH
)+sizeof(g_model
.header
.name
)-1;
500 while (i
>sizeof(MODELS_PATH
)-1) {
505 buf
[i
] = idx2char(buf
[i
]);
513 uint8_t num
= i_fileSrc
+ 1;
514 strcpy_P(&buf
[sizeof(MODELS_PATH
)], STR_MODEL
);
515 buf
[sizeof(MODELS_PATH
) + PSIZE(TR_MODEL
)] = (char)((num
/ 10) + '0');
516 buf
[sizeof(MODELS_PATH
) + PSIZE(TR_MODEL
) + 1] = (char)((num
% 10) + '0');
517 len
= sizeof(MODELS_PATH
) + PSIZE(TR_MODEL
) + 2;
521 char * tmp
= strAppendDate(&buf
[len
]);
525 strcpy_P(&buf
[len
], STR_MODELS_EXT
);
528 TRACE("SD-card backup filename=%s", buf
);
531 FRESULT result
= f_open(&g_oLogFile
, buf
, FA_CREATE_ALWAYS
| FA_WRITE
);
532 if (result
!= FR_OK
) {
533 return SDCARD_ERROR(result
);
537 theFile2
.openRd(FILE_MODEL(i_fileSrc
));
539 *(uint32_t*)&buf
[0] = OTX_FOURCC
;
540 buf
[4] = g_eeGeneral
.version
;
542 *(uint16_t*)&buf
[6] = eeModelSize(i_fileSrc
);
544 result
= f_write(&g_oLogFile
, buf
, 8, &written
);
545 if (result
!= FR_OK
|| written
!= 8) {
546 f_close(&g_oLogFile
);
547 return SDCARD_ERROR(result
);
550 while ((len
=theFile2
.read((uint8_t *)buf
, 15))) {
551 result
= f_write(&g_oLogFile
, (uint8_t *)buf
, len
, &written
);
552 if (result
!= FR_OK
|| written
!= len
) {
553 f_close(&g_oLogFile
);
554 return SDCARD_ERROR(result
);
558 f_close(&g_oLogFile
);
562 const pm_char
* eeRestoreModel(uint8_t i_fileDst
, char *model_name
)
564 char * buf
= reusableBuffer
.modelsel
.mainname
;
567 // we must close the logs as we reuse the same FIL structure
570 strcpy_P(buf
, STR_MODELS_PATH
);
571 buf
[sizeof(MODELS_PATH
)-1] = '/';
572 strcpy(&buf
[sizeof(MODELS_PATH
)], model_name
);
573 strcpy_P(&buf
[strlen(buf
)], STR_MODELS_EXT
);
575 FRESULT result
= f_open(&g_oLogFile
, buf
, FA_OPEN_EXISTING
| FA_READ
);
576 if (result
!= FR_OK
) {
577 return SDCARD_ERROR(result
);
580 if (f_size(&g_oLogFile
) < 8) {
581 f_close(&g_oLogFile
);
582 return STR_INCOMPATIBLE
;
585 result
= f_read(&g_oLogFile
, (uint8_t *)buf
, 8, &read
);
586 if (result
!= FR_OK
|| read
!= 8) {
587 f_close(&g_oLogFile
);
588 return SDCARD_ERROR(result
);
591 uint8_t version
= (uint8_t)buf
[4];
592 if ((*(uint32_t*)&buf
[0] != OTX_FOURCC
&& *(uint32_t*)&buf
[0] != O9X_FOURCC
) || version
< FIRST_CONV_EEPROM_VER
|| version
> EEPROM_VER
|| buf
[5] != 'M') {
593 f_close(&g_oLogFile
);
594 return STR_INCOMPATIBLE
;
597 if (eeModelExists(i_fileDst
)) {
598 eeDeleteModel(i_fileDst
);
601 theFile
.create(FILE_MODEL(i_fileDst
), FILE_TYP_MODEL
, true);
604 result
= f_read(&g_oLogFile
, (uint8_t *)buf
, 15, &read
);
605 if (result
!= FR_OK
) {
606 ENABLE_SYNC_WRITE(false);
607 f_close(&g_oLogFile
);
608 return SDCARD_ERROR(result
);
611 theFile
.write((uint8_t *)buf
, read
);
612 if (write_errno() != 0) {
613 ENABLE_SYNC_WRITE(false);
614 f_close(&g_oLogFile
);
615 return STR_EEPROMOVERFLOW
;
618 } while (read
== 15);
621 if (theFile
.m_currBlk
&& (fri
=EeFsGetLink(theFile
.m_currBlk
)))
622 EeFsSetLink(theFile
.m_currBlk
, 0);
624 if (fri
) EeFsFree(fri
); //chain in
626 eeFs
.files
[FILE_TMP
].size
= theFile
.m_pos
;
627 EFile::swap(theFile
.m_fileId
, FILE_TMP
); // s_sync_write is set to false in swap();
629 f_close(&g_oLogFile
);
631 #if defined(EEPROM_CONVERSIONS)
632 if (version
< EEPROM_VER
) {
634 ConvertModel(i_fileDst
, version
);
635 eeLoadModel(g_eeGeneral
.currModel
);
640 eeLoadModelHeader(i_fileDst
, &modelHeaders
[i_fileDst
]);
647 void RlcFile::writeRlc(uint8_t i_fileId
, uint8_t typ
, uint8_t *buf
, uint16_t i_len
, uint8_t sync_write
)
649 create(i_fileId
, typ
, sync_write
);
651 m_write_step
= WRITE_START_STEP
;
655 #if defined (EEPROM_PROGRESS_BAR)
656 m_ratio
= (typ
== FILE_TYP_MODEL
? 100 : 10);
661 } while (IS_SYNC_WRITE_ENABLE() && m_write_step
&& !s_write_err
);
664 void RlcFile::nextRlcWriteStep()
671 uint8_t tmp1
= m_cur_rlc_len
;
672 uint8_t *tmp2
= m_rlc_buf
;
673 m_rlc_buf
+= m_cur_rlc_len
;
681 bool run0
= (m_rlc_buf
[0] == 0);
684 bool cur0
= (i
<m_rlc_len
) ? (m_rlc_buf
[i
] == 0) : false;
685 if (cur0
!= run0
|| cnt
==0x3f || (cnt0
&& cnt
==0x0f) || i
==m_rlc_len
) {
688 if (cnt
<8 && i
!=m_rlc_len
)
689 cnt0
= cnt
; //aufbew fuer spaeter
702 write1(0x80 | (cnt0
<<4) | cnt
);
710 if (i
==m_rlc_len
) break;
717 switch(m_write_step
) {
718 case WRITE_START_STEP
: {
721 if (m_currBlk
&& (fri
= EeFsGetLink(m_currBlk
))) {
722 // TODO reuse EeFsFree!!!
723 blkid_t prev_freeList
= eeFs
.freeList
;
728 while (EeFsGetLink(fri
)) {
729 fri
= EeFsGetLink(fri
);
734 m_write_step
= WRITE_FREE_UNUSED_BLOCKS_STEP1
;
735 EeFsSetLink(fri
, prev_freeList
);
740 case WRITE_FINAL_DIRENT_STEP
: {
741 m_currBlk
= eeFs
.files
[FILE_TMP
].startBlk
;
742 DirEnt
& f
= eeFs
.files
[m_fileId
];
743 eeFs
.files
[FILE_TMP
].startBlk
= f
.startBlk
;
744 eeFs
.files
[FILE_TMP
].size
= f
.size
;
745 f
.startBlk
= m_currBlk
;
747 f
.typ
= eeFs
.files
[FILE_TMP
].typ
;
748 m_write_step
= WRITE_TMP_DIRENT_STEP
;
749 EeFsFlushDirEnt(m_fileId
);
753 case WRITE_TMP_DIRENT_STEP
:
755 EeFsFlushDirEnt(FILE_TMP
);
758 case WRITE_FREE_UNUSED_BLOCKS_STEP1
:
759 m_write_step
= WRITE_FREE_UNUSED_BLOCKS_STEP2
;
760 EeFsSetLink(m_currBlk
, 0);
763 case WRITE_FREE_UNUSED_BLOCKS_STEP2
:
764 m_write_step
= WRITE_FINAL_DIRENT_STEP
;
770 void RlcFile::flush()
772 while (!eepromIsTransferComplete())
775 ENABLE_SYNC_WRITE(true);
777 while (m_write_len
&& !s_write_err
)
780 while (isWriting() && !s_write_err
)
783 ENABLE_SYNC_WRITE(false);
786 #if defined (EEPROM_PROGRESS_BAR)
787 void RlcFile::drawProgressBar(uint8_t x
)
789 if (storageDirtyMsk
|| isWriting() || eeprom_buffer_size
) {
790 uint8_t len
= storageDirtyMsk
? 1 : limit((uint8_t)1, (uint8_t)(7 - (m_rlc_len
/m_ratio
)), (uint8_t)7);
791 lcdDrawFilledRect(x
+1, 0, 5, FH
, SOLID
, ERASE
);
792 lcdDrawFilledRect(x
+2, 7-len
, 3, len
);
797 // For conversions ...
799 uint16_t eeLoadGeneralSettingsData()
801 memset(&g_eeGeneral
, 0, sizeof(g_eeGeneral
));
802 theFile
.openRlc(FILE_GENERAL
);
803 return theFile
.readRlc((uint8_t*)&g_eeGeneral
, sizeof(g_eeGeneral
));
807 uint16_t eeLoadModelData(uint8_t index
)
810 memset(&g_model
, 0, sizeof(g_model
));
812 theFile
.openRlc(FILE_MODEL(index
));
813 return theFile
.readRlc((uint8_t*)&g_model
, sizeof(g_model
));
818 theFile
.openRlc(FILE_GENERAL
);
819 if (theFile
.readRlc((uint8_t*)&g_eeGeneral
, 3) == 3 && g_eeGeneral
.version
== EEPROM_VER
) {
820 theFile
.openRlc(FILE_GENERAL
);
821 if (theFile
.readRlc((uint8_t*)&g_eeGeneral
, sizeof(g_eeGeneral
)) <= sizeof(g_eeGeneral
) && g_eeGeneral
.variant
== EEPROM_VARIANT
) {
827 if (g_eeGeneral
.variant
== 0) {
828 TRACE("Pre release EEPROM detected, variant %d instead of %d for X7 radio. Loading anyway", g_eeGeneral
.variant
, EEPROM_VARIANT
);
829 g_eeGeneral
.variant
= EEPROM_VARIANT
;
830 storageDirty(EE_GENERAL
);
835 #if defined(PCBTARANIS)
836 if (g_eeGeneral
.variant
!= EEPROM_VARIANT
) {
837 TRACE("EEPROM variant %d instead of %d", g_eeGeneral
.variant
, EEPROM_VARIANT
);
841 #if defined(EEPROM_CONVERSIONS)
842 if (g_eeGeneral
.version
!= EEPROM_VER
) {
843 TRACE("EEPROM version %d instead of %d", g_eeGeneral
.version
, EEPROM_VER
);
850 TRACE("EEPROM version %d (%d) instead of %d (%d)", g_eeGeneral
.version
, g_eeGeneral
.variant
, EEPROM_VER
, EEPROM_VARIANT
);
855 void eeLoadModelName(uint8_t id
, char *name
)
857 memclear(name
, sizeof(g_model
.header
.name
));
858 if (id
< MAX_MODELS
) {
859 theFile
.openRlc(FILE_MODEL(id
));
860 theFile
.readRlc((uint8_t*)name
, sizeof(g_model
.header
.name
));
864 bool eeModelExists(uint8_t id
)
866 return EFile::exists(FILE_MODEL(id
));
869 void storageCheck(bool immediately
)
875 if (storageDirtyMsk
& EE_GENERAL
) {
876 TRACE("eeprom write general");
877 storageDirtyMsk
-= EE_GENERAL
;
878 theFile
.writeRlc(FILE_GENERAL
, FILE_TYP_GENERAL
, (uint8_t*)&g_eeGeneral
, sizeof(g_eeGeneral
), immediately
);
879 if (!immediately
) return;
882 if (storageDirtyMsk
& EE_MODEL
) {
883 TRACE("eeprom write model");
885 theFile
.writeRlc(FILE_MODEL(g_eeGeneral
.currModel
), FILE_TYP_MODEL
, (uint8_t*)&g_model
, sizeof(g_model
), immediately
);
890 void eeLoadModelHeader(uint8_t id
, ModelHeader
*header
)
892 memclear(header
, sizeof(ModelHeader
));
893 if (id
< MAX_MODELS
) {
894 theFile
.openRlc(FILE_MODEL(id
));
895 theFile
.readRlc((uint8_t*)header
, sizeof(ModelHeader
));
899 bool eeCopyModel(uint8_t dst
, uint8_t src
)
901 if (theFile
.copy(FILE_MODEL(dst
), FILE_MODEL(src
))) {
902 memcpy(&modelHeaders
[dst
], &modelHeaders
[src
], sizeof(ModelHeader
));
910 void eeSwapModels(uint8_t id1
, uint8_t id2
)
912 EFile::swap(FILE_MODEL(id1
), FILE_MODEL(id2
));
914 char tmp
[sizeof(g_model
.header
)];
915 memcpy(tmp
, &modelHeaders
[id1
], sizeof(ModelHeader
));
916 memcpy(&modelHeaders
[id1
], &modelHeaders
[id2
], sizeof(ModelHeader
));
917 memcpy(&modelHeaders
[id2
], tmp
, sizeof(ModelHeader
));
920 void eeDeleteModel(uint8_t idx
)
922 EFile::rm(FILE_MODEL(idx
));
923 memset(&modelHeaders
[idx
], 0, sizeof(ModelHeader
));
931 uint8_t buffer
[1024];
934 // reset unexpectedShutdown to prevent warning when user restores EEPROM backup
935 g_eeGeneral
.unexpectedShutdown
= 0;
936 storageDirty(EE_GENERAL
);
939 // create the directory if needed...
940 const char * error
= sdCheckAndCreateDirectory(EEPROMS_PATH
);
942 POPUP_WARNING(error
);
946 // prepare the filename...
947 char * tmp
= strAppend(filename
, EEPROMS_PATH
"/eeprom");
949 tmp
= strAppendDate(tmp
, true);
951 strAppend(tmp
, EEPROM_EXT
);
953 // open the file for writing...
954 f_open(&file
, filename
, FA_WRITE
| FA_CREATE_ALWAYS
);
956 for (int i
=0; i
<EEPROM_SIZE
; i
+=1024) {
958 eepromReadBlock(buffer
, i
, 1024);
959 f_write(&file
, buffer
, 1024, &count
);
960 drawProgressBar(STR_WRITING
, i
, EEPROM_SIZE
);
961 SIMU_SLEEP(100/*ms*/);
966 //set back unexpectedShutdown
967 g_eeGeneral
.unexpectedShutdown
= 1;
968 storageDirty(EE_GENERAL
);