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.
27 #define EEPROM_MARK 0x84697771 /* thanks ;) */
28 #define EEPROM_ZONE_SIZE (8*1024)
29 #define EEPROM_BUFFER_SIZE 256
30 #define EEPROM_FAT_SIZE 128
31 #define EEPROM_MAX_ZONES (EEPROM_SIZE / EEPROM_ZONE_SIZE)
32 #define EEPROM_MAX_FILES (EEPROM_MAX_ZONES - 1)
33 #define FIRST_FILE_AVAILABLE (1+MAX_MODELS)
35 PACK(struct EepromHeaderFile
41 PACK(struct EepromHeader
45 EepromHeaderFile files
[EEPROM_MAX_FILES
];
48 PACK(struct EepromFileHeader
54 EepromHeader eepromHeader __DMA
;
55 volatile EepromWriteState eepromWriteState
= EEPROM_IDLE
;
56 uint8_t eepromWriteZoneIndex
= FIRST_FILE_AVAILABLE
;
57 uint8_t eepromWriteFileIndex
;
58 uint16_t eepromWriteSize
;
59 uint8_t * eepromWriteSourceAddr
;
60 uint32_t eepromWriteDestinationAddr
;
61 uint16_t eepromFatAddr
= 0;
62 uint8_t eepromWriteBuffer
[EEPROM_BUFFER_SIZE
] __DMA
;
64 void eepromWaitReadStatus()
66 while (eepromReadStatus() == 0) {
71 void eepromWaitTransferComplete()
73 while (!eepromIsTransferComplete()) {
78 void eepromEraseBlock(uint32_t address
, bool blocking
=true)
80 // TRACE("eepromEraseBlock(%d)", address);
82 eepromBlockErase(address
);
85 eepromWaitTransferComplete();
86 eepromWaitReadStatus();
90 void eepromRead(uint8_t * buffer
, size_t address
, size_t size
)
92 // TRACE("eepromRead(%p, %d, %d)", buffer, address, size);
94 eepromStartRead(buffer
, address
, size
);
95 eepromWaitTransferComplete();
98 void eepromWrite(uint8_t * buffer
, size_t address
, size_t size
, bool blocking
=true)
100 // TRACE("eepromWrite(%p, %d, %d)", buffer, address, size);
102 eepromStartWrite(buffer
, address
, size
);
105 eepromWaitTransferComplete();
106 eepromWaitReadStatus();
114 int32_t bestFatAddr
= -1;
115 uint32_t bestFatIndex
= 0;
117 while (eepromFatAddr
< EEPROM_ZONE_SIZE
) {
118 eepromRead((uint8_t *)&eepromHeader
, eepromFatAddr
, sizeof(eepromHeader
.mark
) + sizeof(eepromHeader
.index
));
119 if (eepromHeader
.mark
== EEPROM_MARK
&& eepromHeader
.index
>= bestFatIndex
) {
120 bestFatAddr
= eepromFatAddr
;
121 bestFatIndex
= eepromHeader
.index
;
123 eepromFatAddr
+= EEPROM_FAT_SIZE
;
125 if (bestFatAddr
>= 0) {
126 eepromFatAddr
= bestFatAddr
;
127 eepromRead((uint8_t *)&eepromHeader
, eepromFatAddr
, sizeof(eepromHeader
));
135 uint32_t readFile(int index
, uint8_t * data
, uint32_t size
)
137 if (eepromHeader
.files
[index
].exists
) {
138 EepromFileHeader header
;
139 uint32_t address
= eepromHeader
.files
[index
].zoneIndex
* EEPROM_ZONE_SIZE
;
140 eepromRead((uint8_t *)&header
, address
, sizeof(header
));
141 if (size
< header
.size
) {
144 if (header
.size
> 0) {
145 eepromRead(data
, address
+ sizeof(header
), header
.size
);
149 memset(data
+ header
.size
, 0, size
);
158 void eepromIncFatAddr()
160 eepromHeader
.index
+= 1;
161 eepromFatAddr
+= EEPROM_FAT_SIZE
;
162 if (eepromFatAddr
>= EEPROM_ZONE_SIZE
) {
167 void writeFile(int index
, uint8_t * data
, uint32_t size
)
169 uint32_t zoneIndex
= eepromHeader
.files
[eepromWriteZoneIndex
].zoneIndex
;
170 eepromHeader
.files
[eepromWriteZoneIndex
].exists
= 0;
171 eepromHeader
.files
[eepromWriteZoneIndex
].zoneIndex
= eepromHeader
.files
[index
].zoneIndex
;
172 eepromHeader
.files
[index
].exists
= (size
> 0);
173 eepromHeader
.files
[index
].zoneIndex
= zoneIndex
;
174 eepromWriteFileIndex
= index
;
175 eepromWriteSourceAddr
= data
;
176 eepromWriteSize
= size
;
177 eepromWriteDestinationAddr
= zoneIndex
* EEPROM_ZONE_SIZE
;
178 eepromWriteState
= EEPROM_START_WRITE
;
179 eepromWriteZoneIndex
+= 1;
180 if (eepromWriteZoneIndex
>= EEPROM_MAX_FILES
) {
181 eepromWriteZoneIndex
= FIRST_FILE_AVAILABLE
;
186 void eeDeleteModel(uint8_t index
)
189 memclear(&modelHeaders
[index
], sizeof(ModelHeader
));
190 writeFile(index
+1, (uint8_t *)&g_model
, 0);
194 bool eeCopyModel(uint8_t dst
, uint8_t src
)
198 uint32_t eepromWriteSourceAddr
= eepromHeader
.files
[src
+1].zoneIndex
* EEPROM_ZONE_SIZE
;
199 uint32_t eepromWriteDestinationAddr
= eepromHeader
.files
[dst
+1].zoneIndex
* EEPROM_ZONE_SIZE
;
202 eepromEraseBlock(eepromWriteDestinationAddr
);
203 eepromEraseBlock(eepromWriteDestinationAddr
+EEPROM_BLOCK_SIZE
);
206 for (int pos
=0; pos
<EEPROM_ZONE_SIZE
; pos
+=EEPROM_BUFFER_SIZE
) {
207 eepromRead(eepromWriteBuffer
, eepromWriteSourceAddr
+pos
, EEPROM_BUFFER_SIZE
);
208 eepromWrite(eepromWriteBuffer
, eepromWriteDestinationAddr
+pos
, EEPROM_BUFFER_SIZE
);
212 eepromHeader
.files
[dst
+1].exists
= 1;
214 eepromWriteState
= EEPROM_WRITE_NEW_FAT
;
217 modelHeaders
[dst
] = modelHeaders
[src
];
222 void eeSwapModels(uint8_t id1
, uint8_t id2
)
226 EepromHeaderFile tmp
= eepromHeader
.files
[id1
+1];
227 eepromHeader
.files
[id1
+1] = eepromHeader
.files
[id2
+1];
228 eepromHeader
.files
[id2
+1] = tmp
;
231 eepromWriteState
= EEPROM_WRITE_NEW_FAT
;
235 ModelHeader tmp
= modelHeaders
[id1
];
236 modelHeaders
[id1
] = modelHeaders
[id2
];
237 modelHeaders
[id2
] = tmp
;
241 // For conversions ...
242 uint16_t eeLoadGeneralSettingsData()
244 return readFile(0, (uint8_t *)&g_eeGeneral
, sizeof(g_eeGeneral
));
247 uint16_t eeLoadModelData(uint8_t index
)
249 return readFile(index
+1, (uint8_t *)&g_model
, sizeof(g_model
));
252 void writeGeneralSettings()
254 writeFile(0, (uint8_t *)&g_eeGeneral
, sizeof(g_eeGeneral
));
257 void writeModel(int index
)
259 writeFile(index
+1, (uint8_t *)&g_model
, sizeof(g_model
));
264 eeLoadGeneralSettingsData();
266 if (g_eeGeneral
.version
!= EEPROM_VER
) {
267 TRACE("EEPROM version %d instead of %d", g_eeGeneral
.version
, EEPROM_VER
);
268 #if defined(PCBSKY9X)
279 bool eeModelExists(uint8_t id
)
281 return (eepromHeader
.files
[id
+1].exists
);
284 void eeLoadModelHeader(uint8_t id
, ModelHeader
* header
)
286 readFile(id
+1, (uint8_t *)header
, sizeof(ModelHeader
));
292 eepromHeader
.mark
= EEPROM_MARK
;
293 eepromHeader
.index
= 0;
294 for (int i
=0; i
<EEPROM_MAX_FILES
; i
++) {
295 eepromHeader
.files
[i
].exists
= 0;
296 eepromHeader
.files
[i
].zoneIndex
= i
+1;
299 eepromEraseBlock(EEPROM_BLOCK_SIZE
);
300 eepromWrite((uint8_t *)&eepromHeader
, 0, sizeof(eepromHeader
));
303 void eepromWriteWait(EepromWriteState state
/* = EEPROM_IDLE*/)
305 while (eepromWriteState
!= state
) {
307 // Waits a little bit for CS transitions
308 CoTickDelay(1/*2ms*/);
310 eepromWriteProcess();
317 void storageCheck(bool immediately
)
323 assert(eepromWriteState
== EEPROM_IDLE
);
325 if (storageDirtyMsk
& EE_GENERAL
) {
326 TRACE("eeprom write general");
327 storageDirtyMsk
-= EE_GENERAL
;
328 writeGeneralSettings();
335 if (storageDirtyMsk
& EE_MODEL
) {
336 TRACE("eeprom write model");
337 storageDirtyMsk
-= EE_MODEL
;
338 writeModel(g_eeGeneral
.currModel
);
344 void eepromWriteProcess()
346 // TRACE("eepromWriteProcess(state=%d)", eepromWriteState);
348 switch (eepromWriteState
) {
349 case EEPROM_ERASING_FILE_BLOCK1
:
350 case EEPROM_ERASING_FILE_BLOCK2
:
351 case EEPROM_WRITING_BUFFER
:
352 case EEPROM_ERASING_FAT_BLOCK
:
353 case EEPROM_WRITING_NEW_FAT
:
354 if (eepromIsTransferComplete()) {
355 eepromWriteState
= EepromWriteState(eepromWriteState
+ 1);
359 case EEPROM_ERASING_FILE_BLOCK1_WAIT
:
360 case EEPROM_ERASING_FILE_BLOCK2_WAIT
:
361 case EEPROM_WRITING_BUFFER_WAIT
:
362 case EEPROM_ERASING_FAT_BLOCK_WAIT
:
363 case EEPROM_WRITING_NEW_FAT_WAIT
:
364 if (eepromReadStatus()) {
365 eepromWriteState
= EepromWriteState(eepromWriteState
+ 1);
369 case EEPROM_START_WRITE
:
370 eepromWriteState
= EEPROM_ERASING_FILE_BLOCK1
;
371 eepromEraseBlock(eepromWriteDestinationAddr
, false);
374 case EEPROM_ERASE_FILE_BLOCK2
:
375 eepromWriteState
= EEPROM_ERASING_FILE_BLOCK2
;
376 eepromEraseBlock(eepromWriteDestinationAddr
+ EEPROM_BLOCK_SIZE
, false);
379 case EEPROM_WRITE_BUFFER
:
381 EepromFileHeader
* header
= (EepromFileHeader
*)eepromWriteBuffer
;
382 header
->fileIndex
= eepromWriteFileIndex
;
383 header
->size
= eepromWriteSize
;
384 uint32_t size
= min
<uint32_t>(EEPROM_BUFFER_SIZE
-sizeof(EepromFileHeader
), eepromWriteSize
);
385 memcpy(eepromWriteBuffer
+sizeof(EepromFileHeader
), eepromWriteSourceAddr
, size
);
386 eepromWriteState
= EEPROM_WRITING_BUFFER
;
387 eepromWrite(eepromWriteBuffer
, eepromWriteDestinationAddr
, sizeof(EepromFileHeader
)+size
, false);
388 eepromWriteSourceAddr
+= size
;
389 eepromWriteDestinationAddr
+= sizeof(EepromFileHeader
)+size
;
390 eepromWriteSize
-= size
;
394 case EEPROM_WRITE_NEXT_BUFFER
:
396 uint32_t size
= min
<uint32_t>(EEPROM_BUFFER_SIZE
, eepromWriteSize
);
398 memcpy(eepromWriteBuffer
, eepromWriteSourceAddr
, size
);
399 eepromWriteState
= EEPROM_WRITING_BUFFER
;
400 eepromWrite(eepromWriteBuffer
, eepromWriteDestinationAddr
, size
, false);
401 eepromWriteSourceAddr
+= size
;
402 eepromWriteDestinationAddr
+= size
;
403 eepromWriteSize
-= size
;
406 else if (eepromFatAddr
== 0 || eepromFatAddr
== EEPROM_BLOCK_SIZE
) {
407 eepromWriteState
= EEPROM_ERASING_FAT_BLOCK
;
408 eepromEraseBlock(eepromFatAddr
, false);
414 case EEPROM_WRITE_NEW_FAT
:
415 eepromWriteState
= EEPROM_WRITING_NEW_FAT
;
416 eepromWrite((uint8_t *)&eepromHeader
, eepromFatAddr
, sizeof(eepromHeader
), false);
419 case EEPROM_END_WRITE
:
420 eepromWriteState
= EEPROM_IDLE
;
428 uint16_t eeModelSize(uint8_t index
)
432 if (eepromHeader
.files
[index
+1].exists
) {
433 uint32_t address
= eepromHeader
.files
[index
+1].zoneIndex
* EEPROM_ZONE_SIZE
;
434 EepromFileHeader header
;
435 eepromRead((uint8_t *)&header
, address
, sizeof(header
));
436 result
= header
.size
;
443 const pm_char
* eeBackupModel(uint8_t i_fileSrc
)
445 char * buf
= reusableBuffer
.modelsel
.mainname
;
452 return STR_NO_SDCARD
;
455 // check and create folder here
456 strcpy(buf
, STR_MODELS_PATH
);
457 const char * error
= sdCheckAndCreateDirectory(buf
);
462 buf
[sizeof(MODELS_PATH
)-1] = '/';
463 strcpy(strcat_modelname(&buf
[sizeof(MODELS_PATH
)], i_fileSrc
), STR_MODELS_EXT
);
465 FRESULT result
= f_open(&archiveFile
, buf
, FA_CREATE_ALWAYS
| FA_WRITE
);
466 if (result
!= FR_OK
) {
467 return SDCARD_ERROR(result
);
470 #if defined(PCBSKY9X)
471 strcpy(statusLineMsg
, PSTR("File "));
472 strcpy(statusLineMsg
+5, &buf
[sizeof(MODELS_PATH
)]);
475 uint16_t size
= eeModelSize(i_fileSrc
);
477 *(uint32_t*)&buf
[0] = OTX_FOURCC
;
478 buf
[4] = g_eeGeneral
.version
;
480 *(uint16_t*)&buf
[6] = size
;
482 result
= f_write(&archiveFile
, buf
, 8, &written
);
483 if (result
!= FR_OK
|| written
!= 8) {
484 f_close(&archiveFile
);
485 return SDCARD_ERROR(result
);
488 uint32_t address
= eepromHeader
.files
[i_fileSrc
+1].zoneIndex
* EEPROM_ZONE_SIZE
+ sizeof(EepromFileHeader
);
490 uint16_t blockSize
= min
<uint16_t>(size
, EEPROM_BUFFER_SIZE
);
491 eepromRead(eepromWriteBuffer
, address
, blockSize
);
492 result
= f_write(&archiveFile
, eepromWriteBuffer
, blockSize
, &written
);
493 if (result
!= FR_OK
|| written
!= blockSize
) {
494 f_close(&archiveFile
);
495 return SDCARD_ERROR(result
);
498 address
+= blockSize
;
501 f_close(&archiveFile
);
503 #if defined(PCBSKY9X)
510 const pm_char
* eeRestoreModel(uint8_t i_fileDst
, char *model_name
)
512 char * buf
= reusableBuffer
.modelsel
.mainname
;
519 return STR_NO_SDCARD
;
522 strcpy(buf
, STR_MODELS_PATH
);
523 buf
[sizeof(MODELS_PATH
)-1] = '/';
524 strcpy(&buf
[sizeof(MODELS_PATH
)], model_name
);
525 strcpy(&buf
[strlen(buf
)], STR_MODELS_EXT
);
527 FRESULT result
= f_open(&restoreFile
, buf
, FA_OPEN_EXISTING
| FA_READ
);
528 if (result
!= FR_OK
) {
529 return SDCARD_ERROR(result
);
532 if (f_size(&restoreFile
) < 8) {
533 f_close(&restoreFile
);
534 return STR_INCOMPATIBLE
;
537 result
= f_read(&restoreFile
, (uint8_t *)buf
, 8, &read
);
538 if (result
!= FR_OK
|| read
!= 8) {
539 f_close(&restoreFile
);
540 return SDCARD_ERROR(result
);
543 uint8_t version
= (uint8_t)buf
[4];
544 if ((*(uint32_t*)&buf
[0] != OTX_FOURCC
&& *(uint32_t*)&buf
[0] != O9X_FOURCC
) || version
< FIRST_CONV_EEPROM_VER
|| version
> EEPROM_VER
|| buf
[5] != 'M') {
545 f_close(&restoreFile
);
546 return STR_INCOMPATIBLE
;
549 if (eeModelExists(i_fileDst
)) {
550 eeDeleteModel(i_fileDst
);
553 uint16_t size
= min
<uint16_t>(sizeof(g_model
), *(uint16_t*)&buf
[6]);
554 uint32_t address
= eepromHeader
.files
[i_fileDst
+1].zoneIndex
* EEPROM_ZONE_SIZE
;
557 eepromEraseBlock(address
);
558 eepromEraseBlock(address
+EEPROM_BLOCK_SIZE
);
561 EepromFileHeader
* header
= (EepromFileHeader
*)eepromWriteBuffer
;
562 header
->fileIndex
= i_fileDst
+1;
569 uint16_t blockSize
= min
<uint16_t>(size
, EEPROM_BUFFER_SIZE
-offset
);
570 result
= f_read(&restoreFile
, eepromWriteBuffer
+offset
, blockSize
, &read
);
571 if (result
!= FR_OK
|| read
!= blockSize
) {
572 f_close(&g_oLogFile
);
573 return SDCARD_ERROR(result
);
575 eepromWrite(eepromWriteBuffer
, address
, blockSize
+offset
);
577 address
+= EEPROM_BUFFER_SIZE
;
582 eepromHeader
.files
[i_fileDst
+1].exists
= 1;
584 eepromWriteState
= EEPROM_WRITE_NEW_FAT
;
587 eeLoadModelHeader(i_fileDst
, &modelHeaders
[i_fileDst
]);
589 #if defined(EEPROM_CONVERSIONS)
590 if (version
< EEPROM_VER
) {
591 ConvertModel(i_fileDst
, version
);
592 eeLoadModel(g_eeGeneral
.currModel
);