void backupEeprom() { char filename[60]; uint8_t buffer[1024]; FIL file; lcd_clear(); displayProgressBar(STR_WRITING); // reset unexpectedShutdown to prevent warning when user restores EEPROM backup g_eeGeneral.unexpectedShutdown = 0; eeDirty(EE_GENERAL); eeCheck(true); // create the directory if needed... DIR folder; FRESULT result = f_opendir(&folder, EEPROMS_PATH); if (result != FR_OK) { if (result == FR_NO_PATH) result = f_mkdir(EEPROMS_PATH); if (result != FR_OK) { POPUP_WARNING(SDCARD_ERROR(result)); return; } } // prepare the filename... char * tmp = strAppend(filename, EEPROMS_PATH "/eeprom"); tmp = strAppendDate(tmp, true); strAppend(tmp, EEPROM_EXT); // open the file for writing... f_open(&file, filename, FA_WRITE | FA_CREATE_ALWAYS); for (int i=0; i<EESIZE; i+=1024) { UINT count; eepromReadBlock(buffer, i, 1024); f_write(&file, buffer, 1024, &count); updateProgressBar(i, EESIZE); SIMU_SLEEP(100/*ms*/); } f_close(&file); //set back unexpectedShutdown g_eeGeneral.unexpectedShutdown = 1; eeDirty(EE_GENERAL); eeCheck(true); }
bool eeCopyModel(uint8_t dst, uint8_t src) { eeCheck(true); uint32_t eepromWriteSourceAddr = eepromHeader.files[src+1].zoneIndex * EEPROM_ZONE_SIZE; uint32_t eepromWriteDestinationAddr = eepromHeader.files[dst+1].zoneIndex * EEPROM_ZONE_SIZE; // erase blocks eepromEraseBlock(eepromWriteDestinationAddr); eepromEraseBlock(eepromWriteDestinationAddr+EEPROM_BLOCK_SIZE); // write model for (int pos=0; pos<EEPROM_ZONE_SIZE; pos+=EEPROM_BUFFER_SIZE) { eepromRead(eepromWriteSourceAddr+pos, eepromWriteBuffer, EEPROM_BUFFER_SIZE); eepromWrite(eepromWriteDestinationAddr+pos, eepromWriteBuffer, EEPROM_BUFFER_SIZE); } // write FAT eepromHeader.files[dst+1].exists = 1; eepromIncFatAddr(); eepromWriteState = EEPROM_WRITE_NEW_FAT; eepromWriteWait(); modelHeaders[dst] = modelHeaders[src]; return true; }
void eeDeleteModel(uint8_t index) { eeCheck(true); memclear(&modelHeaders[index], sizeof(ModelHeader)); writeFile(index+1, (uint8_t *)&g_model, 0); eepromWriteWait(); }
void eeLoadModel(uint8_t id) { if(id<MAX_MODELS) { theFile.openRlc(FILE_MODEL(id)); uint16_t sz = theFile.readRlc((uint8_t*)&g_model, sizeof(g_model)); #ifdef SIMU if (sz > 0 && sz != sizeof(g_model)) { printf("Model data read=%d bytes vs %d bytes\n", sz, (int)sizeof(ModelData)); } #endif if (sz < 730/*sizeof(last compatible eeprom)*/) { modelDefault(id); eeCheck(true); } resetTimer1(); resetTimer2(); resetProto(); #ifdef TELEMLOGS initTelemLog(); #endif } }
void checkEeprom() { if (!usbPlugged()) { if (eepromIsWriting()) eepromWriteProcess(); else if (TIME_TO_WRITE()) eeCheck(false); } }
void eeLoadModel(uint8_t id) { if (id<MAX_MODELS) { #if defined(SDCARD) closeLogs(); #endif if (pulsesStarted()) { pausePulses(); } pauseMixerCalculations(); uint32_t size = loadModel(id); #if defined(SIMU) if (sizeof(uint16_t) + sizeof(g_model) > EEPROM_ZONE_SIZE) TRACE("Model data size can't exceed %d bytes (%d bytes)", int(EEPROM_ZONE_SIZE-sizeof(uint16_t)), (int)sizeof(g_model)); if (size > 0 && size != sizeof(g_model)) TRACE("Model data read=%d bytes vs %d bytes\n", size, (int)sizeof(ModelData)); #endif if (size < EEPROM_BUFFER_SIZE) { // if not loaded a fair amount modelDefault(id) ; eeCheck(true); } AUDIO_FLUSH(); flightReset(); logicalSwitchesReset(); if (pulsesStarted()) { checkAll(); resumePulses(); } customFunctionsReset(); restoreTimers(); resumeMixerCalculations(); // TODO pulses should be started after mixer calculations ... #if defined(FRSKY) frskySendAlarms(); #endif #if defined(SDCARD) referenceModelAudioFiles(); #endif LOAD_MODEL_BITMAP(); SEND_FAILSAFE_1S(); PLAY_MODEL_NAME(); } }
void eeDeleteModel(uint8_t id) { eeCheck(true); memset(modelHeaders[id].name, 0, sizeof(g_model.header.name)); Eeprom32_source_address = (uint8_t *)&g_model ; // Get data from here Eeprom32_data_size = 0 ; // This much Eeprom32_file_index = id + 1 ; // This file system entry Eeprom32_process_state = E32_BLANKCHECK ; eeWaitFinished(); }
void eeWaitComplete() { while(s_eeDirtyMsk) { eeCheck(true) ; if(heartbeat == 0x3) { wdt_reset(); heartbeat = 0; } } }
void onModelSelectMenu(const char *result) { int8_t sub = m_posVert; if (result == STR_SELECT_MODEL || result == STR_CREATE_MODEL) { selectModel(sub); } else if (result == STR_COPY_MODEL) { s_copyMode = COPY_MODE; s_copyTgtOfs = 0; s_copySrcRow = -1; } else if (result == STR_MOVE_MODEL) { s_copyMode = MOVE_MODE; s_copyTgtOfs = 0; s_copySrcRow = -1; } #if defined(SDCARD) else if (result == STR_BACKUP_MODEL) { eeCheck(true); // force writing of current model data before this is changed POPUP_WARNING(eeBackupModel(sub)); } else if (result == STR_RESTORE_MODEL || result == STR_UPDATE_LIST) { if (!listSdFiles(MODELS_PATH, MODELS_EXT, MENU_LINE_LENGTH-1, NULL)) { POPUP_WARNING(STR_NO_MODELS_ON_SD); s_menu_flags = 0; } } #endif else if (result == STR_DELETE_MODEL) { POPUP_CONFIRMATION(STR_DELETEMODEL); #if defined(CPUARM) SET_WARNING_INFO(modelHeaders[sub].name, sizeof(g_model.header.name), ZCHAR); #else char * name = reusableBuffer.modelsel.mainname; eeLoadModelName(sub, name); SET_WARNING_INFO(name, sizeof(g_model.header.name), ZCHAR); #endif } #if defined(SDCARD) else { // The user choosed a file on SD to restore POPUP_WARNING(eeRestoreModel(sub, (char *)result)); if (!s_warning && g_eeGeneral.currModel == sub) { eeLoadModel(sub); } } #endif }
void eeErase(bool warn) { generalDefault(); modelDefault(0); if (warn) { ALERT(STR_EEPROMWARN, STR_BADEEPROMDATA, AU_BAD_EEPROM); } MESSAGE(STR_EEPROMWARN, STR_EEPROMFORMATTING, NULL, AU_EEPROM_FORMATTING); eepromFormat(); eeDirty(EE_GENERAL); eeDirty(EE_MODEL); eeCheck(true); }
void eeSwapModels(uint8_t id1, uint8_t id2) { eeCheck(true); { EepromHeaderFile tmp = eepromHeader.files[id1+1]; eepromHeader.files[id1+1] = eepromHeader.files[id2+1]; eepromHeader.files[id2+1] = tmp; } eepromIncFatAddr(); eepromWriteState = EEPROM_WRITE_NEW_FAT; eepromWriteWait(); { ModelHeader tmp = modelHeaders[id1]; modelHeaders[id1] = modelHeaders[id2]; modelHeaders[id2] = tmp; } }
const pm_char * eeRestoreModel(uint8_t i_fileDst, char *model_name) { char *buf = reusableBuffer.modelsel.mainname; FIL restoreFile; UINT read; eeCheck(true); if (!sdMounted()) { return STR_NO_SDCARD; } strcpy(buf, STR_MODELS_PATH); buf[sizeof(MODELS_PATH)-1] = '/'; strcpy(&buf[sizeof(MODELS_PATH)], model_name); strcpy(&buf[strlen(buf)], STR_MODELS_EXT); FRESULT result = f_open(&restoreFile, buf, FA_OPEN_EXISTING | FA_READ); if (result != FR_OK) { return SDCARD_ERROR(result); } if (f_size(&restoreFile) < 8) { f_close(&restoreFile); return STR_INCOMPATIBLE; } result = f_read(&restoreFile, (uint8_t *)buf, 8, &read); if (result != FR_OK || read != 8) { f_close(&restoreFile); return SDCARD_ERROR(result); } uint8_t version = (uint8_t)buf[4]; if (*(uint32_t*)&buf[0] != O9X_FOURCC || version < FIRST_CONV_EEPROM_VER || version > EEPROM_VER || buf[5] != 'M') { f_close(&restoreFile); return STR_INCOMPATIBLE; } if (eeModelExists(i_fileDst)) { eeDeleteModel(i_fileDst); } uint16_t size = min<uint16_t>(sizeof(g_model), *(uint16_t*)&buf[6]); uint32_t address = eepromHeader.files[i_fileDst+1].zoneIndex * EEPROM_ZONE_SIZE; // erase blocks eepromEraseBlock(address); eepromEraseBlock(address+EEPROM_BLOCK_SIZE); // write header EepromFileHeader * header = (EepromFileHeader *)eepromWriteBuffer; header->fileIndex = i_fileDst+1; header->size = size; int offset = 4; // write model do { uint16_t blockSize = min<uint16_t>(size, EEPROM_BUFFER_SIZE-offset); result = f_read(&restoreFile, eepromWriteBuffer+offset, blockSize, &read); if (result != FR_OK || read != blockSize) { f_close(&g_oLogFile); return SDCARD_ERROR(result); } eepromWrite(address, eepromWriteBuffer, blockSize+offset); size -= blockSize; address += EEPROM_BUFFER_SIZE; offset = 0; } while (size > 0); // write FAT eepromHeader.files[i_fileDst+1].exists = 1; eepromIncFatAddr(); eepromWriteState = EEPROM_WRITE_NEW_FAT; eepromWriteWait(); eeLoadModelHeader(i_fileDst, &modelHeaders[i_fileDst]); #if defined(PCBSKY9X) if (version < EEPROM_VER) { ConvertModel(i_fileDst, version); loadModel(g_eeGeneral.currModel); } #endif return NULL; }
const pm_char * eeBackupModel(uint8_t i_fileSrc) { char *buf = reusableBuffer.modelsel.mainname; FIL archiveFile; DIR archiveFolder; UINT written; eeCheck(true); if (!sdMounted()) { return STR_NO_SDCARD; } // check and create folder here strcpy(buf, STR_MODELS_PATH); FRESULT result = f_opendir(&archiveFolder, buf); if (result != FR_OK) { if (result == FR_NO_PATH) result = f_mkdir(buf); if (result != FR_OK) return SDCARD_ERROR(result); } else { f_closedir(&archiveFolder); } buf[sizeof(MODELS_PATH)-1] = '/'; strcpy(strcat_modelname(&buf[sizeof(MODELS_PATH)], i_fileSrc), STR_MODELS_EXT); result = f_open(&archiveFile, buf, FA_CREATE_ALWAYS | FA_WRITE); if (result != FR_OK) { return SDCARD_ERROR(result); } #if defined(PCBSKY9X) strcpy(statusLineMsg, PSTR("File ")); strcpy(statusLineMsg+5, &buf[sizeof(MODELS_PATH)]); #endif uint16_t size = eeModelSize(i_fileSrc); *(uint32_t*)&buf[0] = O9X_FOURCC; buf[4] = g_eeGeneral.version; buf[5] = 'M'; *(uint16_t*)&buf[6] = size; result = f_write(&archiveFile, buf, 8, &written); if (result != FR_OK || written != 8) { f_close(&archiveFile); return SDCARD_ERROR(result); } uint32_t address = eepromHeader.files[i_fileSrc+1].zoneIndex * EEPROM_ZONE_SIZE + sizeof(EepromFileHeader); while (size > 0) { uint16_t blockSize = min<uint16_t>(size, EEPROM_BUFFER_SIZE); eepromRead(address, eepromWriteBuffer, blockSize); result = f_write(&archiveFile, eepromWriteBuffer, blockSize, &written); if (result != FR_OK || written != blockSize) { f_close(&archiveFile); return SDCARD_ERROR(result); } size -= blockSize; address += blockSize; } f_close(&archiveFile); #if defined(PCBSKY9X) showStatusLine(); #endif return NULL; }
void menuModelSelect(uint8_t event) { if (s_warning_result) { s_warning_result = 0; eeDeleteModel(m_posVert); // delete file s_copyMode = 0; event = EVT_ENTRY_UP; } uint8_t _event_ = (IS_ROTARY_BREAK(event) || IS_ROTARY_LONG(event) ? 0 : event); if ((s_copyMode && EVT_KEY_MASK(event) == KEY_EXIT) || event == EVT_KEY_BREAK(KEY_EXIT)) { _event_ -= KEY_EXIT; } int8_t oldSub = m_posVert; check_submenu_simple(_event_, MAX_MODELS-1); #if defined(NAVIGATION_POT2) if (event==0 && p2valdiff<0) { event = EVT_KEY_FIRST(KEY_RIGHT); } #endif if (s_editMode > 0) s_editMode = 0; #if !defined(CPUARM) if (event) { eeFlush(); // flush eeprom write } #endif int8_t sub = m_posVert; switch (event) { case EVT_ENTRY: m_posVert = sub = g_eeGeneral.currModel; if (sub >= LCD_LINES-1) s_pgOfs = sub-LCD_LINES+2; s_copyMode = 0; s_editMode = EDIT_MODE_INIT; eeCheck(true); break; case EVT_KEY_LONG(KEY_EXIT): killEvents(event); if (s_copyMode && s_copyTgtOfs == 0 && g_eeGeneral.currModel != sub && eeModelExists(sub)) { POPUP_CONFIRMATION(STR_DELETEMODEL); #if defined(CPUARM) SET_WARNING_INFO(modelHeaders[sub].name, sizeof(g_model.header.name), ZCHAR); #else char * name = reusableBuffer.modelsel.mainname; eeLoadModelName(sub, name); SET_WARNING_INFO(name, sizeof(g_model.header.name), ZCHAR); #endif } else { s_copyMode = 0; m_posVert = g_eeGeneral.currModel; } break; #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_LONG: killEvents(event); if (s_editMode < 0) { popMenu(); break; } else if (!s_copyMode) { m_posVert = sub = g_eeGeneral.currModel; s_copyMode = 0; s_editMode = EDIT_MODE_INIT; } // no break #endif case EVT_KEY_BREAK(KEY_EXIT): if (s_copyMode) { sub = m_posVert = (s_copyMode == MOVE_MODE || s_copySrcRow<0) ? (MAX_MODELS+sub+s_copyTgtOfs) % MAX_MODELS : s_copySrcRow; s_copyMode = 0; } else if (m_posVert != g_eeGeneral.currModel) { m_posVert = g_eeGeneral.currModel; } else { popMenu(); } break; #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_BREAK: if (s_editMode == -1) { s_editMode = 0; break; } // no break; #endif case EVT_KEY_LONG(KEY_ENTER): case EVT_KEY_BREAK(KEY_ENTER): s_editMode = 0; if (READ_ONLY()) { if (g_eeGeneral.currModel != sub && eeModelExists(sub)) { selectModel(sub); } } else if (s_copyMode && (s_copyTgtOfs || s_copySrcRow>=0)) { displayPopup(s_copyMode==COPY_MODE ? STR_COPYINGMODEL : STR_MOVINGMODEL); eeCheck(true); // force writing of current model data before this is changed uint8_t cur = (MAX_MODELS + sub + s_copyTgtOfs) % MAX_MODELS; if (s_copyMode == COPY_MODE) { if (!eeCopyModel(cur, s_copySrcRow)) { cur = sub; } } s_copySrcRow = g_eeGeneral.currModel; // to update the currModel value while (sub != cur) { uint8_t src = cur; cur = (s_copyTgtOfs > 0 ? cur+MAX_MODELS-1 : cur+1) % MAX_MODELS; eeSwapModels(src, cur); if (src == s_copySrcRow) s_copySrcRow = cur; else if (cur == s_copySrcRow) s_copySrcRow = src; } if (s_copySrcRow != g_eeGeneral.currModel) { g_eeGeneral.currModel = s_copySrcRow; eeDirty(EE_GENERAL); } s_copyMode = 0; event = EVT_ENTRY_UP; } else if (event == EVT_KEY_LONG(KEY_ENTER) || IS_ROTARY_BREAK(event)) { s_copyMode = 0; killEvents(event); #if defined(NAVIGATION_MENUS) if (g_eeGeneral.currModel != sub) { if (eeModelExists(sub)) { MENU_ADD_ITEM(STR_SELECT_MODEL); MENU_ADD_SD_ITEM(STR_BACKUP_MODEL); MENU_ADD_ITEM(STR_COPY_MODEL); MENU_ADD_ITEM(STR_MOVE_MODEL); MENU_ADD_ITEM(STR_DELETE_MODEL); } else { #if defined(SDCARD) MENU_ADD_ITEM(STR_CREATE_MODEL); MENU_ADD_ITEM(STR_RESTORE_MODEL); #else selectModel(sub); #endif } } else { MENU_ADD_SD_ITEM(STR_BACKUP_MODEL); MENU_ADD_ITEM(STR_COPY_MODEL); MENU_ADD_ITEM(STR_MOVE_MODEL); } menuHandler = onModelSelectMenu; #else if (g_eeGeneral.currModel != sub) { selectModel(sub); } #endif } else if (eeModelExists(sub)) { s_copyMode = (s_copyMode == COPY_MODE ? MOVE_MODE : COPY_MODE); s_copyTgtOfs = 0; s_copySrcRow = -1; } break; #if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_LEFT: case EVT_ROTARY_RIGHT: #endif case EVT_KEY_FIRST(KEY_LEFT): case EVT_KEY_FIRST(KEY_RIGHT): #if defined(ROTARY_ENCODER_NAVIGATION) if ((!IS_ROTARY_RIGHT(event) && !IS_ROTARY_LEFT(event)) || s_editMode < 0) { #endif if (sub == g_eeGeneral.currModel) { chainMenu((IS_ROTARY_RIGHT(event) || event == EVT_KEY_FIRST(KEY_RIGHT)) ? menuModelSetup : menuTabModel[DIM(menuTabModel)-1]); } else { AUDIO_WARNING2(); } break; #if defined(ROTARY_ENCODER_NAVIGATION) } // no break #endif case EVT_KEY_FIRST(KEY_MOVE_UP): case EVT_KEY_REPT(KEY_MOVE_UP): case EVT_KEY_FIRST(KEY_MOVE_DOWN): case EVT_KEY_REPT(KEY_MOVE_DOWN): if (s_copyMode) { int8_t next_ofs = s_copyTgtOfs + oldSub - m_posVert; if (next_ofs == MAX_MODELS || next_ofs == -MAX_MODELS) next_ofs = 0; if (s_copySrcRow < 0 && s_copyMode==COPY_MODE) { s_copySrcRow = oldSub; // find a hole (in the first empty slot above / below) sub = eeFindEmptyModel(s_copySrcRow, IS_ROTARY_DOWN(event) || event==EVT_KEY_FIRST(KEY_MOVE_DOWN)); if (sub < 0) { // no free room for duplicating the model AUDIO_ERROR(); sub = oldSub; s_copyMode = 0; } next_ofs = 0; m_posVert = sub; } s_copyTgtOfs = next_ofs; } break; } #if !defined(PCBSKY9X) lcd_puts(9*FW-(LEN_FREE-4)*FW, 0, STR_FREE); if (event) reusableBuffer.modelsel.eepromfree = EeFsGetFree(); lcd_outdezAtt(17*FW, 0, reusableBuffer.modelsel.eepromfree, 0); #endif #if defined(ROTARY_ENCODER_NAVIGATION) displayScreenIndex(e_ModelSelect, DIM(menuTabModel), (sub == g_eeGeneral.currModel) ? ((IS_RE_NAVIGATION_ENABLE() && s_editMode < 0) ? INVERS|BLINK : INVERS) : 0); #else displayScreenIndex(e_ModelSelect, DIM(menuTabModel), (sub == g_eeGeneral.currModel) ? INVERS : 0); #endif TITLE(STR_MENUMODELSEL); for (uint8_t i=0; i<LCD_LINES-1; i++) { coord_t y = MENU_HEADER_HEIGHT + 1 + i*FH; uint8_t k = i+s_pgOfs; lcd_outdezNAtt(3*FW+2, y, k+1, LEADING0+((!s_copyMode && sub==k) ? INVERS : 0), 2); if (s_copyMode == MOVE_MODE || (s_copyMode == COPY_MODE && s_copySrcRow >= 0)) { if (k == sub) { if (s_copyMode == COPY_MODE) { k = s_copySrcRow; lcd_putc(MODELSEL_W-FW, y, '+'); } else { k = sub + s_copyTgtOfs; } } else if (s_copyTgtOfs < 0 && ((k < sub && k >= sub+s_copyTgtOfs) || (k-MAX_MODELS < sub && k-MAX_MODELS >= sub+s_copyTgtOfs))) k += 1; else if (s_copyTgtOfs > 0 && ((k > sub && k <= sub+s_copyTgtOfs) || (k+MAX_MODELS > sub && k+MAX_MODELS <= sub+s_copyTgtOfs))) k += MAX_MODELS-1; } k %= MAX_MODELS; if (eeModelExists(k)) { #if defined(PCBSKY9X) putsModelName(4*FW, y, modelHeaders[k].name, k, 0); #else char * name = reusableBuffer.modelsel.listnames[i]; if (event) eeLoadModelName(k, name); putsModelName(4*FW, y, name, k, 0); lcd_outdezAtt(20*FW, y, eeModelSize(k), 0); #endif if (k==g_eeGeneral.currModel && (s_copyMode!=COPY_MODE || s_copySrcRow<0 || i+s_pgOfs!=(vertpos_t)sub)) lcd_putc(1, y, '*'); } if (s_copyMode && (vertpos_t)sub==i+s_pgOfs) { drawFilledRect(9, y, MODELSEL_W-1-9, 7); lcd_rect(8, y-1, MODELSEL_W-1-7, 9, s_copyMode == COPY_MODE ? SOLID : DOTTED); } } }
void eeLoadModel(uint8_t id) { if (id<MAX_MODELS) { #if defined(SDCARD) closeLogs(); #endif if (pulsesStarted()) { pausePulses(); } pauseMixerCalculations(); uint16_t size = File_system[id+1].size ; memset(&g_model, 0, sizeof(g_model)); #if defined(SIMU) if (sizeof(struct t_eeprom_header) + sizeof(g_model) > 4096) TRACE("Model data size can't exceed %d bytes (%d bytes)", int(4096-sizeof(struct t_eeprom_header)), (int)sizeof(g_model)); else if (size > 0 && size != sizeof(g_model)) TRACE("Model data read=%d bytes vs %d bytes\n", size, (int)sizeof(ModelData)); #endif if (size > sizeof(g_model)) { size = sizeof(g_model) ; } if(size < 256) { // if not loaded a fair amount modelDefault(id) ; eeCheck(true); } else { read32_eeprom_data((File_system[id+1].block_no << 12) + sizeof(struct t_eeprom_header), (uint8_t *)&g_model, size) ; } AUDIO_FLUSH(); flightReset(); logicalSwitchesReset(); if (pulsesStarted()) { checkAll(); resumePulses(); } activeFnSwitches = 0; activeFunctions = 0; memclear(lastFunctionTime, sizeof(lastFunctionTime)); restoreTimers(); resumeMixerCalculations(); // TODO pulses should be started after mixer calculations ... #if defined(FRSKY) frskySendAlarms(); #endif #if defined(CPUARM) && defined(SDCARD) referenceModelAudioFiles(); #endif LOAD_MODEL_BITMAP(); SEND_FAILSAFE_1S(); } }