[Horus] SD Storage started. UI continued.
+ Some boyscout work on LCD functions
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Andre Bernet <bernet.andre@gmail.com>
|
||||
* - Andreas Weitl
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
* - Cameron Weeks <th9xer@gmail.com>
|
||||
* - Erez Raviv
|
||||
* - Gabriel Birkus
|
||||
* - Jean-Pierre Parisy
|
||||
* - Karl Szmutny
|
||||
* - Michael Blandford
|
||||
* - Michal Hlavinka
|
||||
* - Pat Mackenzie
|
||||
* - Philip Moss
|
||||
* - Rob Thomson
|
||||
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
||||
* - Thomas Husterer
|
||||
*
|
||||
* opentx is based on code named
|
||||
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
||||
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
||||
* and the original (and ongoing) project by
|
||||
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include "opentx.h"
|
||||
#include "timers.h"
|
||||
|
||||
void eeLoadModel(uint8_t index)
|
||||
{
|
||||
if (index < MAX_MODELS) {
|
||||
|
||||
preModelLoad();
|
||||
|
||||
uint16_t size = eeLoadModelData(index);
|
||||
|
||||
#if defined(SIMU) && defined(EEPROM_ZONE_SIZE)
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SIMU)
|
||||
if (size > 0 && size != sizeof(g_model)) {
|
||||
TRACE("Model data read=%d bytes vs %d bytes\n", size, (int)sizeof(ModelData));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool newModel = false;
|
||||
if (size < EEPROM_MIN_MODEL_SIZE) { // if not loaded a fair amount
|
||||
modelDefault(index) ;
|
||||
storageCheck(true);
|
||||
newModel = true;
|
||||
}
|
||||
|
||||
postModelLoad(newModel);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t eeFindEmptyModel(uint8_t id, bool down)
|
||||
{
|
||||
uint8_t i = id;
|
||||
for (;;) {
|
||||
i = (MAX_MODELS + (down ? i+1 : i-1)) % MAX_MODELS;
|
||||
if (!eeModelExists(i)) break;
|
||||
if (i == id) return 0xff; // no free space in directory left
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void selectModel(uint8_t sub)
|
||||
{
|
||||
#if !defined(COLORLCD)
|
||||
displayPopup(STR_LOADINGMODEL);
|
||||
#endif
|
||||
saveTimers();
|
||||
storageCheck(true); // force writing of current model data before this is changed
|
||||
g_eeGeneral.currModel = sub;
|
||||
storageDirty(EE_GENERAL);
|
||||
eeLoadModel(sub);
|
||||
}
|
||||
|
||||
#if defined(CPUARM)
|
||||
ModelHeader modelHeaders[MAX_MODELS];
|
||||
void eeLoadModelHeaders()
|
||||
{
|
||||
for (uint32_t i=0; i<MAX_MODELS; i++) {
|
||||
eeLoadModelHeader(i, &modelHeaders[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void storageReadAll()
|
||||
{
|
||||
if (!eepromOpen() || !eeLoadGeneral()) {
|
||||
storageEraseAll(true);
|
||||
}
|
||||
else {
|
||||
eeLoadModelHeaders();
|
||||
}
|
||||
|
||||
stickMode = g_eeGeneral.stickMode;
|
||||
|
||||
#if defined(CPUARM)
|
||||
for (uint8_t i=0; languagePacks[i]!=NULL; i++) {
|
||||
if (!strncmp(g_eeGeneral.ttsLanguage, languagePacks[i]->id, 2)) {
|
||||
currentLanguagePackIdx = i;
|
||||
currentLanguagePack = languagePacks[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
eeLoadModel(g_eeGeneral.currModel);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Andre Bernet <bernet.andre@gmail.com>
|
||||
* - Andreas Weitl
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
* - Cameron Weeks <th9xer@gmail.com>
|
||||
* - Erez Raviv
|
||||
* - Gabriel Birkus
|
||||
* - Jean-Pierre Parisy
|
||||
* - Karl Szmutny
|
||||
* - Michael Blandford
|
||||
* - Michal Hlavinka
|
||||
* - Pat Mackenzie
|
||||
* - Philip Moss
|
||||
* - Rob Thomson
|
||||
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
||||
* - Thomas Husterer
|
||||
*
|
||||
* opentx is based on code named
|
||||
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
||||
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
||||
* and the original (and ongoing) project by
|
||||
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#define EEPROM_MIN_MODEL_SIZE 256
|
||||
|
||||
uint16_t eeLoadModelData(uint8_t id);
|
||||
uint16_t eeLoadGeneralSettingsData();
|
||||
|
||||
bool eeModelExists(uint8_t id);
|
||||
void eeLoadModel(uint8_t id);
|
||||
bool eeConvert();
|
||||
void ConvertModel(int id, int version);
|
||||
uint8_t eeFindEmptyModel(uint8_t id, bool down);
|
||||
void selectModel(uint8_t sub);
|
||||
|
||||
#if defined(CPUARM)
|
||||
extern ModelHeader modelHeaders[MAX_MODELS];
|
||||
void eeLoadModelHeader(uint8_t id, ModelHeader *header);
|
||||
void eeLoadModelHeaders();
|
||||
#else
|
||||
#define eeLoadModelHeaders()
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,648 @@
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Andre Bernet <bernet.andre@gmail.com>
|
||||
* - Andreas Weitl
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
* - Cameron Weeks <th9xer@gmail.com>
|
||||
* - Erez Raviv
|
||||
* - Gabriel Birkus
|
||||
* - Jean-Pierre Parisy
|
||||
* - Karl Szmutny
|
||||
* - Michael Blandford
|
||||
* - Michal Hlavinka
|
||||
* - Pat Mackenzie
|
||||
* - Philip Moss
|
||||
* - Rob Thomson
|
||||
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
||||
* - Thomas Husterer
|
||||
*
|
||||
* opentx is based on code named
|
||||
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
||||
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
||||
* and the original (and ongoing) project by
|
||||
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include "opentx.h"
|
||||
#include "timers.h"
|
||||
|
||||
#define EEPROM_SIZE (4*1024*1024/8)
|
||||
#define EEPROM_BLOCK_SIZE (4*1024)
|
||||
#define EEPROM_MARK 0x84697771 /* thanks ;) */
|
||||
#define EEPROM_ZONE_SIZE (8*1024)
|
||||
#define EEPROM_BUFFER_SIZE 256
|
||||
#define EEPROM_FAT_SIZE 128
|
||||
#define EEPROM_MAX_ZONES (EEPROM_SIZE / EEPROM_ZONE_SIZE)
|
||||
#define EEPROM_MAX_FILES (EEPROM_MAX_ZONES - 1)
|
||||
#define FIRST_FILE_AVAILABLE (1+MAX_MODELS)
|
||||
|
||||
PACK(struct EepromHeaderFile
|
||||
{
|
||||
uint8_t zoneIndex:7;
|
||||
uint8_t exists:1;
|
||||
});
|
||||
|
||||
PACK(struct EepromHeader
|
||||
{
|
||||
uint32_t mark;
|
||||
uint32_t index;
|
||||
EepromHeaderFile files[EEPROM_MAX_FILES];
|
||||
});
|
||||
|
||||
PACK(struct EepromFileHeader
|
||||
{
|
||||
uint16_t fileIndex;
|
||||
uint16_t size;
|
||||
});
|
||||
|
||||
EepromHeader eepromHeader __DMA;
|
||||
volatile EepromWriteState eepromWriteState = EEPROM_IDLE;
|
||||
uint8_t eepromWriteZoneIndex = FIRST_FILE_AVAILABLE;
|
||||
uint8_t eepromWriteFileIndex;
|
||||
uint16_t eepromWriteSize;
|
||||
uint8_t * eepromWriteSourceAddr;
|
||||
uint32_t eepromWriteDestinationAddr;
|
||||
uint16_t eepromFatAddr = 0;
|
||||
uint8_t eepromWriteBuffer[EEPROM_BUFFER_SIZE] __DMA;
|
||||
|
||||
void eepromWaitSpiComplete()
|
||||
{
|
||||
while (!Spi_complete) {
|
||||
SIMU_SLEEP(5/*ms*/);
|
||||
}
|
||||
Spi_complete = false;
|
||||
}
|
||||
|
||||
void eepromWaitReadStatus()
|
||||
{
|
||||
while ((eepromReadStatus() & 1) != 0) {
|
||||
SIMU_SLEEP(5/*ms*/);
|
||||
}
|
||||
}
|
||||
|
||||
void eepromEraseBlock(uint32_t address, bool blocking=true)
|
||||
{
|
||||
// TRACE("eepromEraseBlock(%d)", address);
|
||||
|
||||
#if defined(SIMU)
|
||||
static uint8_t erasedBlock[EEPROM_BLOCK_SIZE]; // can't be on the stack!
|
||||
memset(erasedBlock, 0xff, sizeof(erasedBlock));
|
||||
eeprom_pointer = address;
|
||||
eeprom_buffer_data = erasedBlock;
|
||||
eeprom_buffer_size = EEPROM_BLOCK_SIZE;
|
||||
eeprom_read_operation = false;
|
||||
Spi_complete = false;
|
||||
sem_post(eeprom_write_sem);
|
||||
#else
|
||||
eepromWriteEnable();
|
||||
eepromBlockErase(address);
|
||||
#endif
|
||||
|
||||
if (blocking) {
|
||||
eepromWaitSpiComplete();
|
||||
eepromWaitReadStatus();
|
||||
}
|
||||
}
|
||||
|
||||
void eepromRead(uint32_t address, uint8_t * buffer, uint32_t size, bool blocking=true)
|
||||
{
|
||||
// TRACE("eepromRead(%d, %p, %d)", address, buffer, size);
|
||||
|
||||
#if defined(SIMU)
|
||||
assert(size);
|
||||
eeprom_pointer = address;
|
||||
eeprom_buffer_data = buffer;
|
||||
eeprom_buffer_size = size;
|
||||
eeprom_read_operation = true;
|
||||
Spi_complete = false;
|
||||
sem_post(eeprom_write_sem);
|
||||
#else
|
||||
eepromReadArray(address, buffer, size);
|
||||
#endif
|
||||
|
||||
if (blocking) {
|
||||
eepromWaitSpiComplete();
|
||||
}
|
||||
}
|
||||
|
||||
void eepromWrite(uint32_t address, uint8_t * buffer, uint32_t size, bool blocking=true)
|
||||
{
|
||||
// TRACE("eepromWrite(%d, %p, %d)", address, buffer, size);
|
||||
|
||||
#if defined(SIMU)
|
||||
assert(size);
|
||||
eeprom_pointer = address;
|
||||
eeprom_buffer_data = buffer;
|
||||
eeprom_buffer_size = size+1;
|
||||
eeprom_read_operation = false;
|
||||
Spi_complete = false;
|
||||
sem_post(eeprom_write_sem);
|
||||
#else
|
||||
eepromWriteEnable();
|
||||
eepromByteProgram(address, buffer, size);
|
||||
#endif
|
||||
|
||||
if (blocking) {
|
||||
eepromWaitSpiComplete();
|
||||
eepromWaitReadStatus();
|
||||
}
|
||||
}
|
||||
|
||||
bool eepromOpen()
|
||||
{
|
||||
int32_t bestFatAddr = -1;
|
||||
uint32_t bestFatIndex = 0;
|
||||
eepromFatAddr = 0;
|
||||
while (eepromFatAddr < EEPROM_ZONE_SIZE) {
|
||||
eepromRead(eepromFatAddr, (uint8_t *)&eepromHeader, sizeof(eepromHeader.mark) + sizeof(eepromHeader.index));
|
||||
if (eepromHeader.mark == EEPROM_MARK && eepromHeader.index >= bestFatIndex) {
|
||||
bestFatAddr = eepromFatAddr;
|
||||
bestFatIndex = eepromHeader.index;
|
||||
}
|
||||
eepromFatAddr += EEPROM_FAT_SIZE;
|
||||
}
|
||||
if (bestFatAddr >= 0) {
|
||||
eepromFatAddr = bestFatAddr;
|
||||
eepromRead(eepromFatAddr, (uint8_t *)&eepromHeader, sizeof(eepromHeader));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t readFile(int index, uint8_t * data, uint32_t size)
|
||||
{
|
||||
if (eepromHeader.files[index].exists) {
|
||||
EepromFileHeader header;
|
||||
uint32_t address = eepromHeader.files[index].zoneIndex * EEPROM_ZONE_SIZE;
|
||||
eepromRead(address, (uint8_t *)&header, sizeof(header));
|
||||
if (size < header.size) {
|
||||
header.size = size;
|
||||
}
|
||||
if (header.size > 0) {
|
||||
eepromRead(address + sizeof(header), data, header.size);
|
||||
size -= header.size;
|
||||
}
|
||||
if (size > 0) {
|
||||
memset(data + header.size, 0, size);
|
||||
}
|
||||
return header.size;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void eepromIncFatAddr()
|
||||
{
|
||||
eepromHeader.index += 1;
|
||||
eepromFatAddr += EEPROM_FAT_SIZE;
|
||||
if (eepromFatAddr >= EEPROM_ZONE_SIZE) {
|
||||
eepromFatAddr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void writeFile(int index, uint8_t * data, uint32_t size)
|
||||
{
|
||||
uint32_t zoneIndex = eepromHeader.files[eepromWriteZoneIndex].zoneIndex;
|
||||
eepromHeader.files[eepromWriteZoneIndex].exists = 0;
|
||||
eepromHeader.files[eepromWriteZoneIndex].zoneIndex = eepromHeader.files[index].zoneIndex;
|
||||
eepromHeader.files[index].exists = (size > 0);
|
||||
eepromHeader.files[index].zoneIndex = zoneIndex;
|
||||
eepromWriteFileIndex = index;
|
||||
eepromWriteSourceAddr = data;
|
||||
eepromWriteSize = size;
|
||||
eepromWriteDestinationAddr = zoneIndex * EEPROM_ZONE_SIZE;
|
||||
eepromWriteState = EEPROM_START_WRITE;
|
||||
eepromWriteZoneIndex += 1;
|
||||
if (eepromWriteZoneIndex >= EEPROM_MAX_FILES) {
|
||||
eepromWriteZoneIndex = FIRST_FILE_AVAILABLE;
|
||||
}
|
||||
eepromIncFatAddr();
|
||||
}
|
||||
|
||||
void eeDeleteModel(uint8_t index)
|
||||
{
|
||||
storageCheck(true);
|
||||
memclear(&modelHeaders[index], sizeof(ModelHeader));
|
||||
writeFile(index+1, (uint8_t *)&g_model, 0);
|
||||
eepromWriteWait();
|
||||
}
|
||||
|
||||
bool eeCopyModel(uint8_t dst, uint8_t src)
|
||||
{
|
||||
storageCheck(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 eeSwapModels(uint8_t id1, uint8_t id2)
|
||||
{
|
||||
storageCheck(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;
|
||||
}
|
||||
}
|
||||
|
||||
// For conversions ...
|
||||
uint16_t eeLoadGeneralSettingsData()
|
||||
{
|
||||
return readFile(0, (uint8_t *)&g_eeGeneral, sizeof(g_eeGeneral));
|
||||
}
|
||||
|
||||
uint16_t eeLoadModelData(uint8_t index)
|
||||
{
|
||||
return readFile(index+1, (uint8_t *)&g_model, sizeof(g_model));
|
||||
}
|
||||
|
||||
void writeGeneralSettings()
|
||||
{
|
||||
writeFile(0, (uint8_t *)&g_eeGeneral, sizeof(g_eeGeneral));
|
||||
}
|
||||
|
||||
void writeModel(int index)
|
||||
{
|
||||
writeFile(index+1, (uint8_t *)&g_model, sizeof(g_model));
|
||||
}
|
||||
|
||||
bool eeLoadGeneral()
|
||||
{
|
||||
eeLoadGeneralSettingsData();
|
||||
|
||||
if (g_eeGeneral.version != EEPROM_VER) {
|
||||
TRACE("EEPROM version %d instead of %d", g_eeGeneral.version, EEPROM_VER);
|
||||
#if defined(PCBSKY9X)
|
||||
if (!eeConvert()) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool eeModelExists(uint8_t id)
|
||||
{
|
||||
return (eepromHeader.files[id+1].exists);
|
||||
}
|
||||
|
||||
void eeLoadModelHeader(uint8_t id, ModelHeader * header)
|
||||
{
|
||||
readFile(id+1, (uint8_t *)header, sizeof(ModelHeader));
|
||||
}
|
||||
|
||||
void storageFormat()
|
||||
{
|
||||
eepromFatAddr = 0;
|
||||
eepromHeader.mark = EEPROM_MARK;
|
||||
eepromHeader.index = 0;
|
||||
for (int i=0; i<EEPROM_MAX_FILES; i++) {
|
||||
eepromHeader.files[i].exists = 0;
|
||||
eepromHeader.files[i].zoneIndex = i+1;
|
||||
}
|
||||
eepromEraseBlock(0);
|
||||
eepromEraseBlock(EEPROM_BLOCK_SIZE);
|
||||
eepromWrite(0, (uint8_t *)&eepromHeader, sizeof(eepromHeader));
|
||||
}
|
||||
|
||||
void eepromWriteWait(EepromWriteState state/* = EEPROM_IDLE*/)
|
||||
{
|
||||
while (eepromWriteState != state) {
|
||||
#if defined(CPUSTM32)
|
||||
// Waits a little bit for CS transitions
|
||||
CoTickDelay(1/*2ms*/);
|
||||
#endif
|
||||
eepromWriteProcess();
|
||||
#ifdef SIMU
|
||||
sleep(5/*ms*/);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void storageCheck(bool immediately)
|
||||
{
|
||||
if (immediately) {
|
||||
eepromWriteWait();
|
||||
}
|
||||
|
||||
assert(eepromWriteState == EEPROM_IDLE);
|
||||
|
||||
if (s_storageDirtyMsk & EE_GENERAL) {
|
||||
TRACE("eeprom write general");
|
||||
s_storageDirtyMsk -= EE_GENERAL;
|
||||
writeGeneralSettings();
|
||||
if (immediately)
|
||||
eepromWriteWait();
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_storageDirtyMsk & EE_MODEL) {
|
||||
TRACE("eeprom write model");
|
||||
s_storageDirtyMsk -= EE_MODEL;
|
||||
writeModel(g_eeGeneral.currModel);
|
||||
if (immediately)
|
||||
eepromWriteWait();
|
||||
}
|
||||
}
|
||||
|
||||
void eepromWriteProcess()
|
||||
{
|
||||
// TRACE("eepromWriteProcess(state=%d)", eepromWriteState);
|
||||
|
||||
switch (eepromWriteState) {
|
||||
case EEPROM_ERASING_FILE_BLOCK1:
|
||||
case EEPROM_ERASING_FILE_BLOCK2:
|
||||
case EEPROM_WRITING_BUFFER:
|
||||
case EEPROM_ERASING_FAT_BLOCK:
|
||||
case EEPROM_WRITING_NEW_FAT:
|
||||
if (Spi_complete) {
|
||||
eepromWriteState = EepromWriteState(eepromWriteState + 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case EEPROM_ERASING_FILE_BLOCK1_WAIT:
|
||||
case EEPROM_ERASING_FILE_BLOCK2_WAIT:
|
||||
case EEPROM_WRITING_BUFFER_WAIT:
|
||||
case EEPROM_ERASING_FAT_BLOCK_WAIT:
|
||||
case EEPROM_WRITING_NEW_FAT_WAIT:
|
||||
if ((eepromReadStatus() & 1) == 0) {
|
||||
eepromWriteState = EepromWriteState(eepromWriteState + 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case EEPROM_START_WRITE:
|
||||
eepromWriteState = EEPROM_ERASING_FILE_BLOCK1;
|
||||
eepromEraseBlock(eepromWriteDestinationAddr, false);
|
||||
break;
|
||||
|
||||
case EEPROM_ERASE_FILE_BLOCK2:
|
||||
eepromWriteState = EEPROM_ERASING_FILE_BLOCK2;
|
||||
eepromEraseBlock(eepromWriteDestinationAddr + EEPROM_BLOCK_SIZE, false);
|
||||
break;
|
||||
|
||||
case EEPROM_WRITE_BUFFER:
|
||||
{
|
||||
EepromFileHeader * header = (EepromFileHeader *)eepromWriteBuffer;
|
||||
header->fileIndex = eepromWriteFileIndex;
|
||||
header->size = eepromWriteSize;
|
||||
uint32_t size = min<uint32_t>(EEPROM_BUFFER_SIZE-sizeof(EepromFileHeader), eepromWriteSize);
|
||||
memcpy(eepromWriteBuffer+sizeof(EepromFileHeader), eepromWriteSourceAddr, size);
|
||||
eepromWriteState = EEPROM_WRITING_BUFFER;
|
||||
eepromWrite(eepromWriteDestinationAddr, eepromWriteBuffer, sizeof(EepromFileHeader)+size, false);
|
||||
eepromWriteSourceAddr += size;
|
||||
eepromWriteDestinationAddr += sizeof(EepromFileHeader)+size;
|
||||
eepromWriteSize -= size;
|
||||
break;
|
||||
}
|
||||
|
||||
case EEPROM_WRITE_NEXT_BUFFER:
|
||||
{
|
||||
uint32_t size = min<uint32_t>(EEPROM_BUFFER_SIZE, eepromWriteSize);
|
||||
if (size > 0) {
|
||||
memcpy(eepromWriteBuffer, eepromWriteSourceAddr, size);
|
||||
eepromWriteState = EEPROM_WRITING_BUFFER;
|
||||
eepromWrite(eepromWriteDestinationAddr, eepromWriteBuffer, size, false);
|
||||
eepromWriteSourceAddr += size;
|
||||
eepromWriteDestinationAddr += size;
|
||||
eepromWriteSize -= size;
|
||||
break;
|
||||
}
|
||||
else if (eepromFatAddr == 0 || eepromFatAddr == EEPROM_BLOCK_SIZE) {
|
||||
eepromWriteState = EEPROM_ERASING_FAT_BLOCK;
|
||||
eepromEraseBlock(eepromFatAddr, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* no break */
|
||||
|
||||
case EEPROM_WRITE_NEW_FAT:
|
||||
eepromWriteState = EEPROM_WRITING_NEW_FAT;
|
||||
eepromWrite(eepromFatAddr, (uint8_t *)&eepromHeader, sizeof(eepromHeader), false);
|
||||
break;
|
||||
|
||||
case EEPROM_END_WRITE:
|
||||
eepromWriteState = EEPROM_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t eeModelSize(uint8_t index)
|
||||
{
|
||||
uint16_t result = 0;
|
||||
|
||||
if (eepromHeader.files[index+1].exists) {
|
||||
uint32_t address = eepromHeader.files[index+1].zoneIndex * EEPROM_ZONE_SIZE;
|
||||
EepromFileHeader header;
|
||||
eepromRead(address, (uint8_t *)&header, sizeof(header));
|
||||
result = header.size;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(SDCARD)
|
||||
const pm_char * eeBackupModel(uint8_t i_fileSrc)
|
||||
{
|
||||
char * buf = reusableBuffer.modelsel.mainname;
|
||||
FIL archiveFile;
|
||||
UINT written;
|
||||
|
||||
storageCheck(true);
|
||||
|
||||
if (!sdMounted()) {
|
||||
return STR_NO_SDCARD;
|
||||
}
|
||||
|
||||
// check and create folder here
|
||||
strcpy(buf, STR_MODELS_PATH);
|
||||
const char * error = sdCheckAndCreateDirectory(buf);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
buf[sizeof(MODELS_PATH)-1] = '/';
|
||||
strcpy(strcat_modelname(&buf[sizeof(MODELS_PATH)], i_fileSrc), STR_MODELS_EXT);
|
||||
|
||||
FRESULT 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;
|
||||
}
|
||||
|
||||
const pm_char * eeRestoreModel(uint8_t i_fileDst, char *model_name)
|
||||
{
|
||||
char *buf = reusableBuffer.modelsel.mainname;
|
||||
FIL restoreFile;
|
||||
UINT read;
|
||||
|
||||
storageCheck(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 = { uint16_t(i_fileDst+1), size };
|
||||
eepromWrite(address, (uint8_t *)&header, sizeof(header));
|
||||
address += sizeof(header);
|
||||
|
||||
// write model
|
||||
while (size > 0) {
|
||||
uint16_t blockSize = min<uint16_t>(size, EEPROM_BUFFER_SIZE);
|
||||
result = f_read(&restoreFile, eepromWriteBuffer, blockSize, &read);
|
||||
if (result != FR_OK || read != blockSize) {
|
||||
f_close(&g_oLogFile);
|
||||
return SDCARD_ERROR(result);
|
||||
}
|
||||
eepromWrite(address, eepromWriteBuffer, blockSize);
|
||||
size -= blockSize;
|
||||
address += blockSize;
|
||||
}
|
||||
|
||||
// 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);
|
||||
eeLoadModel(g_eeGeneral.currModel);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Andre Bernet <bernet.andre@gmail.com>
|
||||
* - Andreas Weitl
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
* - Cameron Weeks <th9xer@gmail.com>
|
||||
* - Erez Raviv
|
||||
* - Gabriel Birkus
|
||||
* - Jean-Pierre Parisy
|
||||
* - Karl Szmutny
|
||||
* - Michael Blandford
|
||||
* - Michal Hlavinka
|
||||
* - Pat Mackenzie
|
||||
* - Philip Moss
|
||||
* - Rob Thomson
|
||||
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
||||
* - Thomas Husterer
|
||||
*
|
||||
* opentx is based on code named
|
||||
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
||||
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
||||
* and the original (and ongoing) project by
|
||||
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef eeprom_arm_h
|
||||
#define eeprom_arm_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
|
||||
bool eeLoadGeneral( void ) ;
|
||||
void eeDeleteModel( uint8_t id ) ;
|
||||
bool eeCopyModel(uint8_t dst, uint8_t src);
|
||||
void eeSwapModels(uint8_t id1, uint8_t id2);
|
||||
|
||||
#define DISPLAY_PROGRESS_BAR(x)
|
||||
|
||||
#if defined(SDCARD)
|
||||
const pm_char * eeBackupModel(uint8_t i_fileSrc);
|
||||
const pm_char * eeRestoreModel(uint8_t i_fileDst, char *model_name);
|
||||
#endif
|
||||
|
||||
enum EepromWriteState {
|
||||
EEPROM_IDLE = 0,
|
||||
EEPROM_START_WRITE,
|
||||
EEPROM_ERASING_FILE_BLOCK1,
|
||||
EEPROM_ERASING_FILE_BLOCK1_WAIT,
|
||||
EEPROM_ERASE_FILE_BLOCK2,
|
||||
EEPROM_ERASING_FILE_BLOCK2,
|
||||
EEPROM_ERASING_FILE_BLOCK2_WAIT,
|
||||
EEPROM_WRITE_BUFFER,
|
||||
EEPROM_WRITING_BUFFER,
|
||||
EEPROM_WRITING_BUFFER_WAIT,
|
||||
EEPROM_WRITE_NEXT_BUFFER,
|
||||
EEPROM_ERASING_FAT_BLOCK,
|
||||
EEPROM_ERASING_FAT_BLOCK_WAIT,
|
||||
EEPROM_WRITE_NEW_FAT,
|
||||
EEPROM_WRITING_NEW_FAT,
|
||||
EEPROM_WRITING_NEW_FAT_WAIT,
|
||||
EEPROM_END_WRITE
|
||||
};
|
||||
|
||||
extern volatile EepromWriteState eepromWriteState;
|
||||
inline bool eepromIsWriting()
|
||||
{
|
||||
return (eepromWriteState != EEPROM_IDLE);
|
||||
}
|
||||
void eepromWriteProcess();
|
||||
void eepromWriteWait(EepromWriteState state = EEPROM_IDLE);
|
||||
bool eepromOpen();
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,993 @@
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Andre Bernet <bernet.andre@gmail.com>
|
||||
* - Andreas Weitl
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
* - Cameron Weeks <th9xer@gmail.com>
|
||||
* - Erez Raviv
|
||||
* - Gabriel Birkus
|
||||
* - Jean-Pierre Parisy
|
||||
* - Karl Szmutny
|
||||
* - Michael Blandford
|
||||
* - Michal Hlavinka
|
||||
* - Pat Mackenzie
|
||||
* - Philip Moss
|
||||
* - Rob Thomson
|
||||
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
||||
* - Thomas Husterer
|
||||
*
|
||||
* opentx is based on code named
|
||||
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
||||
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
||||
* and the original (and ongoing) project by
|
||||
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include "opentx.h"
|
||||
#include "timers.h"
|
||||
|
||||
uint8_t s_write_err = 0; // error reasons
|
||||
RlcFile theFile; //used for any file operation
|
||||
EeFs eeFs;
|
||||
|
||||
#if defined(CPUARM)
|
||||
blkid_t freeBlocks = 0;
|
||||
#endif
|
||||
|
||||
uint8_t s_sync_write = false;
|
||||
|
||||
#if !defined(CPUARM)
|
||||
uint16_t eeprom_pointer;
|
||||
uint8_t * eeprom_buffer_data;
|
||||
volatile int8_t eeprom_buffer_size = 0;
|
||||
|
||||
#if !defined(SIMU)
|
||||
inline void eeprom_write_byte()
|
||||
{
|
||||
EEAR = eeprom_pointer;
|
||||
EEDR = *eeprom_buffer_data;
|
||||
// TODO add some define here
|
||||
#if defined (CPUM2560) || defined(CPUM2561)
|
||||
EECR |= 1<<EEMPE;
|
||||
EECR |= 1<<EEPE;
|
||||
#else
|
||||
EECR |= 1<<EEMWE;
|
||||
EECR |= 1<<EEWE;
|
||||
#endif
|
||||
eeprom_pointer++;
|
||||
eeprom_buffer_data++;
|
||||
}
|
||||
|
||||
ISR(EE_READY_vect)
|
||||
{
|
||||
if (--eeprom_buffer_size > 0) {
|
||||
eeprom_write_byte();
|
||||
}
|
||||
else {
|
||||
#if defined(CPUM2560) || defined(CPUM2561)
|
||||
EECR &= ~(1<<EERIE);
|
||||
#else
|
||||
EECR &= ~(1<<EERIE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void eepromWriteBlock(uint8_t * i_pointer_ram, uint16_t i_pointer_eeprom, size_t size)
|
||||
{
|
||||
assert(!eeprom_buffer_size);
|
||||
|
||||
eeprom_pointer = i_pointer_eeprom;
|
||||
eeprom_buffer_data = i_pointer_ram;
|
||||
eeprom_buffer_size = size+1;
|
||||
|
||||
#if defined(SIMU)
|
||||
sem_post(eeprom_write_sem);
|
||||
#elif defined (CPUM2560) || defined(CPUM2561)
|
||||
EECR |= (1<<EERIE);
|
||||
#else
|
||||
EECR |= (1<<EERIE);
|
||||
#endif
|
||||
|
||||
if (s_sync_write) {
|
||||
while (eeprom_buffer_size > 0) wdt_reset();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint8_t EeFsRead(blkid_t blk, uint8_t ofs)
|
||||
{
|
||||
uint8_t ret;
|
||||
eepromReadBlock(&ret, (uint16_t)(blk*BS+ofs+BLOCKS_OFFSET), 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static blkid_t EeFsGetLink(blkid_t blk)
|
||||
{
|
||||
#if defined(CPUARM)
|
||||
blkid_t ret;
|
||||
eepromReadBlock((uint8_t *)&ret, blk*BS+BLOCKS_OFFSET, sizeof(blkid_t));
|
||||
return ret;
|
||||
#else
|
||||
return EeFsRead(blk, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void EeFsSetLink(blkid_t blk, blkid_t val)
|
||||
{
|
||||
static blkid_t s_link; // we write asynchronously, then nothing on the stack!
|
||||
s_link = val;
|
||||
eepromWriteBlock((uint8_t *)&s_link, (blk*BS)+BLOCKS_OFFSET, sizeof(blkid_t));
|
||||
}
|
||||
|
||||
static uint8_t EeFsGetDat(blkid_t blk, uint8_t ofs)
|
||||
{
|
||||
return EeFsRead(blk, ofs+sizeof(blkid_t));
|
||||
}
|
||||
|
||||
static void EeFsSetDat(blkid_t blk, uint8_t ofs, uint8_t *buf, uint8_t len)
|
||||
{
|
||||
eepromWriteBlock(buf, (blk*BS)+ofs+sizeof(blkid_t)+BLOCKS_OFFSET, len);
|
||||
}
|
||||
|
||||
static void EeFsFlushFreelist()
|
||||
{
|
||||
eepromWriteBlock((uint8_t *)&eeFs.freeList, offsetof(EeFs, freeList), sizeof(eeFs.freeList));
|
||||
}
|
||||
|
||||
static void EeFsFlushDirEnt(uint8_t i_fileId)
|
||||
{
|
||||
eepromWriteBlock((uint8_t *)&eeFs.files[i_fileId], offsetof(EeFs, files) + sizeof(DirEnt)*i_fileId, sizeof(DirEnt));
|
||||
}
|
||||
|
||||
static void EeFsFlush()
|
||||
{
|
||||
eepromWriteBlock((uint8_t *)&eeFs, 0, sizeof(eeFs));
|
||||
}
|
||||
|
||||
uint16_t EeFsGetFree()
|
||||
{
|
||||
#if defined(CPUARM)
|
||||
int32_t ret = freeBlocks * (BS-sizeof(blkid_t));
|
||||
#else
|
||||
int16_t ret = 0;
|
||||
blkid_t i = eeFs.freeList;
|
||||
while (i) {
|
||||
ret += BS-sizeof(blkid_t);
|
||||
i = EeFsGetLink(i);
|
||||
}
|
||||
#endif
|
||||
ret += eeFs.files[FILE_TMP].size;
|
||||
ret -= eeFs.files[FILE_MODEL(g_eeGeneral.currModel)].size;
|
||||
return (ret > 0 ? ret : 0);
|
||||
}
|
||||
|
||||
/// free one or more blocks
|
||||
static void EeFsFree(blkid_t blk)
|
||||
{
|
||||
blkid_t i = blk;
|
||||
blkid_t tmp;
|
||||
|
||||
#if defined(CPUARM)
|
||||
freeBlocks++;
|
||||
#endif
|
||||
|
||||
while ((tmp=EeFsGetLink(i))) {
|
||||
i = tmp;
|
||||
#if defined(CPUARM)
|
||||
freeBlocks++;
|
||||
#endif
|
||||
}
|
||||
|
||||
EeFsSetLink(i, eeFs.freeList);
|
||||
eeFs.freeList = blk; //chain in front
|
||||
EeFsFlushFreelist();
|
||||
}
|
||||
|
||||
void eepromCheck()
|
||||
{
|
||||
ENABLE_SYNC_WRITE(true);
|
||||
|
||||
uint8_t *bufp = (uint8_t *)&g_model;
|
||||
memclear(bufp, BLOCKS);
|
||||
blkid_t blk ;
|
||||
|
||||
#if defined(CPUARM)
|
||||
blkid_t blocksCount;
|
||||
#endif
|
||||
for (uint8_t i=0; i<=MAXFILES; i++) {
|
||||
#if defined(CPUARM)
|
||||
blocksCount = 0;
|
||||
#endif
|
||||
blkid_t *startP = (i==MAXFILES ? &eeFs.freeList : &eeFs.files[i].startBlk);
|
||||
blkid_t lastBlk = 0;
|
||||
blk = *startP;
|
||||
while (blk) {
|
||||
if (blk < FIRSTBLK || // bad blk index
|
||||
blk >= BLOCKS || // bad blk indexchan
|
||||
bufp[blk]) // blk double usage
|
||||
{
|
||||
if (lastBlk) {
|
||||
EeFsSetLink(lastBlk, 0);
|
||||
}
|
||||
else {
|
||||
*startP = 0; // interrupt chain at startpos
|
||||
EeFsFlush();
|
||||
}
|
||||
blk = 0; // abort
|
||||
}
|
||||
else {
|
||||
#if defined(CPUARM)
|
||||
blocksCount++;
|
||||
#endif
|
||||
bufp[blk] = i+1;
|
||||
lastBlk = blk;
|
||||
blk = EeFsGetLink(blk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CPUARM)
|
||||
freeBlocks = blocksCount;
|
||||
#endif
|
||||
|
||||
for (blk=FIRSTBLK; blk<BLOCKS; blk++) {
|
||||
if (!bufp[blk]) { // unused block
|
||||
#if defined(CPUARM)
|
||||
freeBlocks++;
|
||||
#endif
|
||||
EeFsSetLink(blk, eeFs.freeList);
|
||||
eeFs.freeList = blk; // chain in front
|
||||
EeFsFlushFreelist();
|
||||
}
|
||||
}
|
||||
|
||||
ENABLE_SYNC_WRITE(false);
|
||||
}
|
||||
|
||||
void storageFormat()
|
||||
{
|
||||
ENABLE_SYNC_WRITE(true);
|
||||
|
||||
#ifdef SIMU
|
||||
// write zero to the end of the new EEPROM file to set it's proper size
|
||||
uint8_t dummy = 0;
|
||||
eepromWriteBlock(&dummy, EESIZE-1, 1);
|
||||
#endif
|
||||
|
||||
memclear(&eeFs, sizeof(eeFs));
|
||||
eeFs.version = EEFS_VERS;
|
||||
eeFs.mySize = sizeof(eeFs);
|
||||
eeFs.freeList = 0;
|
||||
eeFs.bs = BS;
|
||||
for (blkid_t i=FIRSTBLK; i<BLOCKS-1; i++) {
|
||||
EeFsSetLink(i, i+1);
|
||||
}
|
||||
EeFsSetLink(BLOCKS-1, 0);
|
||||
eeFs.freeList = FIRSTBLK;
|
||||
#if defined(CPUARM)
|
||||
freeBlocks = BLOCKS;
|
||||
#endif
|
||||
EeFsFlush();
|
||||
|
||||
ENABLE_SYNC_WRITE(false);
|
||||
}
|
||||
|
||||
bool eepromOpen()
|
||||
{
|
||||
eepromReadBlock((uint8_t *)&eeFs, 0, sizeof(eeFs));
|
||||
|
||||
#ifdef SIMU
|
||||
if (eeFs.version != EEFS_VERS) {
|
||||
TRACE("bad eeFs.version (%d instead of %d)", eeFs.version, EEFS_VERS);
|
||||
}
|
||||
if (eeFs.mySize != sizeof(eeFs)) {
|
||||
TRACE("bad eeFs.mySize (%d instead of %d)", (int)eeFs.mySize, (int)sizeof(eeFs));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (eeFs.version != EEFS_VERS || eeFs.mySize != sizeof(eeFs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
eepromCheck();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EFile::exists(uint8_t i_fileId)
|
||||
{
|
||||
return eeFs.files[i_fileId].startBlk;
|
||||
}
|
||||
|
||||
/*
|
||||
* Swap two files in eeprom
|
||||
*/
|
||||
void EFile::swap(uint8_t i_fileId1, uint8_t i_fileId2)
|
||||
{
|
||||
DirEnt tmp = eeFs.files[i_fileId1];
|
||||
eeFs.files[i_fileId1] = eeFs.files[i_fileId2];
|
||||
eeFs.files[i_fileId2] = tmp;
|
||||
|
||||
ENABLE_SYNC_WRITE(true);
|
||||
EeFsFlushDirEnt(i_fileId1);
|
||||
EeFsFlushDirEnt(i_fileId2);
|
||||
ENABLE_SYNC_WRITE(false);
|
||||
}
|
||||
|
||||
void EFile::rm(uint8_t i_fileId)
|
||||
{
|
||||
blkid_t i = eeFs.files[i_fileId].startBlk;
|
||||
memclear(&eeFs.files[i_fileId], sizeof(eeFs.files[i_fileId]));
|
||||
ENABLE_SYNC_WRITE(true);
|
||||
EeFsFlushDirEnt(i_fileId);
|
||||
if (i) EeFsFree(i); //chain in
|
||||
ENABLE_SYNC_WRITE(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open file i_fileId for reading.
|
||||
* Return the file's type
|
||||
*/
|
||||
void EFile::openRd(uint8_t i_fileId)
|
||||
{
|
||||
m_fileId = i_fileId;
|
||||
m_pos = 0;
|
||||
m_currBlk = eeFs.files[m_fileId].startBlk;
|
||||
m_ofs = 0;
|
||||
s_write_err = ERR_NONE; // error reasons */
|
||||
}
|
||||
|
||||
void RlcFile::openRlc(uint8_t i_fileId)
|
||||
{
|
||||
EFile::openRd(i_fileId);
|
||||
m_zeroes = 0;
|
||||
m_bRlc = 0;
|
||||
}
|
||||
|
||||
uint8_t EFile::read(uint8_t *buf, uint8_t i_len)
|
||||
{
|
||||
uint16_t len = eeFs.files[m_fileId].size - m_pos;
|
||||
if (i_len > len) i_len = len;
|
||||
|
||||
uint8_t remaining = i_len;
|
||||
while (remaining) {
|
||||
if (!m_currBlk) break;
|
||||
|
||||
*buf++ = EeFsGetDat(m_currBlk, m_ofs++);
|
||||
if (m_ofs >= BS-sizeof(blkid_t)) {
|
||||
m_ofs = 0;
|
||||
m_currBlk = EeFsGetLink(m_currBlk);
|
||||
}
|
||||
remaining--;
|
||||
}
|
||||
|
||||
i_len -= remaining;
|
||||
m_pos += i_len;
|
||||
return i_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read runlength (RLE) compressed bytes into buf.
|
||||
*/
|
||||
uint16_t RlcFile::readRlc(uint8_t *buf, uint16_t i_len)
|
||||
{
|
||||
uint16_t i = 0;
|
||||
for( ; 1; ) {
|
||||
uint8_t ln = min<uint16_t>(m_zeroes, i_len-i);
|
||||
memclear(&buf[i], ln);
|
||||
i += ln;
|
||||
m_zeroes -= ln;
|
||||
if (m_zeroes) break;
|
||||
|
||||
ln = min<uint16_t>(m_bRlc, i_len-i);
|
||||
uint8_t lr = read(&buf[i], ln);
|
||||
i += lr ;
|
||||
m_bRlc -= lr;
|
||||
if(m_bRlc) break;
|
||||
|
||||
if (read(&m_bRlc, 1) !=1) break; // read how many bytes to read
|
||||
|
||||
assert(m_bRlc & 0x7f);
|
||||
|
||||
if (m_bRlc&0x80) { // if contains high byte
|
||||
m_zeroes =(m_bRlc>>4) & 0x7;
|
||||
m_bRlc = m_bRlc & 0x0f;
|
||||
}
|
||||
else if(m_bRlc&0x40) {
|
||||
m_zeroes = m_bRlc & 0x3f;
|
||||
m_bRlc = 0;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void RlcFile::write1(uint8_t b)
|
||||
{
|
||||
m_write1_byte = b;
|
||||
write(&m_write1_byte, 1);
|
||||
}
|
||||
|
||||
void RlcFile::write(uint8_t *buf, uint8_t i_len)
|
||||
{
|
||||
m_write_len = i_len;
|
||||
m_write_buf = buf;
|
||||
|
||||
do {
|
||||
nextWriteStep();
|
||||
} while (IS_SYNC_WRITE_ENABLE() && m_write_len && !s_write_err);
|
||||
}
|
||||
|
||||
void RlcFile::nextWriteStep()
|
||||
{
|
||||
if (!m_currBlk && m_pos==0) {
|
||||
eeFs.files[FILE_TMP].startBlk = m_currBlk = eeFs.freeList;
|
||||
if (m_currBlk) {
|
||||
#if defined(CPUARM)
|
||||
freeBlocks--;
|
||||
#endif
|
||||
eeFs.freeList = EeFsGetLink(m_currBlk);
|
||||
m_write_step |= WRITE_FIRST_LINK;
|
||||
EeFsFlushFreelist();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_write_step & 0x0f) == WRITE_FIRST_LINK) {
|
||||
m_write_step -= WRITE_FIRST_LINK;
|
||||
EeFsSetLink(m_currBlk, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
while (m_write_len) {
|
||||
if (!m_currBlk) {
|
||||
s_write_err = ERR_FULL;
|
||||
break;
|
||||
}
|
||||
if (m_ofs >= (BS-sizeof(blkid_t))) {
|
||||
m_ofs = 0;
|
||||
blkid_t nextBlk = EeFsGetLink(m_currBlk);
|
||||
if (!nextBlk) {
|
||||
if (!eeFs.freeList) {
|
||||
s_write_err = ERR_FULL;
|
||||
break;
|
||||
}
|
||||
m_write_step += WRITE_NEXT_LINK_1;
|
||||
EeFsSetLink(m_currBlk, eeFs.freeList);
|
||||
// TODO not good
|
||||
return;
|
||||
}
|
||||
m_currBlk = nextBlk;
|
||||
}
|
||||
switch (m_write_step & 0x0f) {
|
||||
case WRITE_NEXT_LINK_1:
|
||||
m_currBlk = eeFs.freeList;
|
||||
#if defined(CPUARM)
|
||||
freeBlocks--;
|
||||
#endif
|
||||
eeFs.freeList = EeFsGetLink(eeFs.freeList);
|
||||
m_write_step += 1;
|
||||
EeFsFlushFreelist();
|
||||
return;
|
||||
case WRITE_NEXT_LINK_2:
|
||||
m_write_step -= WRITE_NEXT_LINK_2;
|
||||
EeFsSetLink(m_currBlk, 0);
|
||||
return;
|
||||
}
|
||||
uint8_t tmp = BS-sizeof(blkid_t)-m_ofs; if(tmp>m_write_len) tmp = m_write_len;
|
||||
m_write_buf += tmp;
|
||||
m_write_len -= tmp;
|
||||
m_ofs += tmp;
|
||||
m_pos += tmp;
|
||||
EeFsSetDat(m_currBlk, m_ofs-tmp, m_write_buf-tmp, tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_write_err == ERR_FULL) {
|
||||
POPUP_WARNING(STR_EEPROMOVERFLOW);
|
||||
m_write_step = 0;
|
||||
m_write_len = 0;
|
||||
m_cur_rlc_len = 0;
|
||||
}
|
||||
else if (!IS_SYNC_WRITE_ENABLE()) {
|
||||
nextRlcWriteStep();
|
||||
}
|
||||
}
|
||||
|
||||
void RlcFile::create(uint8_t i_fileId, uint8_t typ, uint8_t sync_write)
|
||||
{
|
||||
// all write operations will be executed on FILE_TMP
|
||||
openRlc(FILE_TMP); // internal use
|
||||
eeFs.files[FILE_TMP].typ = typ;
|
||||
eeFs.files[FILE_TMP].size = 0;
|
||||
m_fileId = i_fileId;
|
||||
ENABLE_SYNC_WRITE(sync_write);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy file src to dst
|
||||
*/
|
||||
bool RlcFile::copy(uint8_t i_fileDst, uint8_t i_fileSrc)
|
||||
{
|
||||
EFile theFile2;
|
||||
theFile2.openRd(i_fileSrc);
|
||||
|
||||
create(i_fileDst, FILE_TYP_MODEL/*optimization, only model files are copied. should be eeFs.files[i_fileSrc].typ*/, true);
|
||||
|
||||
uint8_t buf[BS-sizeof(blkid_t)];
|
||||
uint8_t len;
|
||||
while ((len=theFile2.read(buf, sizeof(buf))))
|
||||
{
|
||||
write(buf, len);
|
||||
if (write_errno() != 0) {
|
||||
ENABLE_SYNC_WRITE(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
blkid_t fri=0;
|
||||
if (m_currBlk && (fri=EeFsGetLink(m_currBlk)))
|
||||
EeFsSetLink(m_currBlk, 0);
|
||||
|
||||
if (fri) EeFsFree(fri); //chain in
|
||||
|
||||
eeFs.files[FILE_TMP].size = m_pos;
|
||||
EFile::swap(m_fileId, FILE_TMP);
|
||||
|
||||
assert(!m_write_step);
|
||||
|
||||
// s_sync_write is set to false in swap();
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(SDCARD)
|
||||
const pm_char * eeBackupModel(uint8_t i_fileSrc)
|
||||
{
|
||||
char *buf = reusableBuffer.modelsel.mainname;
|
||||
UINT written;
|
||||
|
||||
// we must close the logs as we reuse the same FIL structure
|
||||
closeLogs();
|
||||
|
||||
// check and create folder here
|
||||
strcpy_P(buf, STR_MODELS_PATH);
|
||||
const char * error = sdCheckAndCreateDirectory(buf);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
buf[sizeof(MODELS_PATH)-1] = '/';
|
||||
eeLoadModelName(i_fileSrc, &buf[sizeof(MODELS_PATH)]);
|
||||
buf[sizeof(MODELS_PATH)+sizeof(g_model.header.name)] = '\0';
|
||||
|
||||
uint8_t i = sizeof(MODELS_PATH)+sizeof(g_model.header.name)-1;
|
||||
uint8_t len = 0;
|
||||
while (i>sizeof(MODELS_PATH)-1) {
|
||||
if (!len && buf[i])
|
||||
len = i+1;
|
||||
if (len) {
|
||||
if (buf[i])
|
||||
buf[i] = idx2char(buf[i]);
|
||||
else
|
||||
buf[i] = '_';
|
||||
}
|
||||
i--;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
uint8_t num = i_fileSrc + 1;
|
||||
strcpy_P(&buf[sizeof(MODELS_PATH)], STR_MODEL);
|
||||
buf[sizeof(MODELS_PATH) + PSIZE(TR_MODEL)] = (char)((num / 10) + '0');
|
||||
buf[sizeof(MODELS_PATH) + PSIZE(TR_MODEL) + 1] = (char)((num % 10) + '0');
|
||||
len = sizeof(MODELS_PATH) + PSIZE(TR_MODEL) + 2;
|
||||
}
|
||||
|
||||
#if defined(RTCLOCK) && LCD_W >= 212
|
||||
char * tmp = strAppendDate(&buf[len]);
|
||||
len = tmp - buf;
|
||||
#endif
|
||||
|
||||
strcpy_P(&buf[len], STR_MODELS_EXT);
|
||||
|
||||
#ifdef SIMU
|
||||
TRACE("SD-card backup filename=%s", buf);
|
||||
#endif
|
||||
|
||||
FRESULT result = f_open(&g_oLogFile, buf, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if (result != FR_OK) {
|
||||
return SDCARD_ERROR(result);
|
||||
}
|
||||
|
||||
EFile theFile2;
|
||||
theFile2.openRd(FILE_MODEL(i_fileSrc));
|
||||
|
||||
*(uint32_t*)&buf[0] = O9X_FOURCC;
|
||||
buf[4] = g_eeGeneral.version;
|
||||
buf[5] = 'M';
|
||||
*(uint16_t*)&buf[6] = eeModelSize(i_fileSrc);
|
||||
|
||||
result = f_write(&g_oLogFile, buf, 8, &written);
|
||||
if (result != FR_OK || written != 8) {
|
||||
f_close(&g_oLogFile);
|
||||
return SDCARD_ERROR(result);
|
||||
}
|
||||
|
||||
while ((len=theFile2.read((uint8_t *)buf, 15))) {
|
||||
result = f_write(&g_oLogFile, (uint8_t *)buf, len, &written);
|
||||
if (result != FR_OK || written != len) {
|
||||
f_close(&g_oLogFile);
|
||||
return SDCARD_ERROR(result);
|
||||
}
|
||||
}
|
||||
|
||||
f_close(&g_oLogFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const pm_char * eeRestoreModel(uint8_t i_fileDst, char *model_name)
|
||||
{
|
||||
char *buf = reusableBuffer.modelsel.mainname;
|
||||
UINT read;
|
||||
|
||||
// we must close the logs as we reuse the same FIL structure
|
||||
closeLogs();
|
||||
|
||||
strcpy_P(buf, STR_MODELS_PATH);
|
||||
buf[sizeof(MODELS_PATH)-1] = '/';
|
||||
strcpy(&buf[sizeof(MODELS_PATH)], model_name);
|
||||
strcpy_P(&buf[strlen(buf)], STR_MODELS_EXT);
|
||||
|
||||
FRESULT result = f_open(&g_oLogFile, buf, FA_OPEN_EXISTING | FA_READ);
|
||||
if (result != FR_OK) {
|
||||
return SDCARD_ERROR(result);
|
||||
}
|
||||
|
||||
if (f_size(&g_oLogFile) < 8) {
|
||||
f_close(&g_oLogFile);
|
||||
return STR_INCOMPATIBLE;
|
||||
}
|
||||
|
||||
result = f_read(&g_oLogFile, (uint8_t *)buf, 8, &read);
|
||||
if (result != FR_OK || read != 8) {
|
||||
f_close(&g_oLogFile);
|
||||
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(&g_oLogFile);
|
||||
return STR_INCOMPATIBLE;
|
||||
}
|
||||
|
||||
if (eeModelExists(i_fileDst)) {
|
||||
eeDeleteModel(i_fileDst);
|
||||
}
|
||||
|
||||
theFile.create(FILE_MODEL(i_fileDst), FILE_TYP_MODEL, true);
|
||||
|
||||
do {
|
||||
result = f_read(&g_oLogFile, (uint8_t *)buf, 15, &read);
|
||||
if (result != FR_OK) {
|
||||
ENABLE_SYNC_WRITE(false);
|
||||
f_close(&g_oLogFile);
|
||||
return SDCARD_ERROR(result);
|
||||
}
|
||||
if (read > 0) {
|
||||
theFile.write((uint8_t *)buf, read);
|
||||
if (write_errno() != 0) {
|
||||
ENABLE_SYNC_WRITE(false);
|
||||
f_close(&g_oLogFile);
|
||||
return STR_EEPROMOVERFLOW;
|
||||
}
|
||||
}
|
||||
} while (read == 15);
|
||||
|
||||
blkid_t fri=0;
|
||||
if (theFile.m_currBlk && (fri=EeFsGetLink(theFile.m_currBlk)))
|
||||
EeFsSetLink(theFile.m_currBlk, 0);
|
||||
|
||||
if (fri) EeFsFree(fri); //chain in
|
||||
|
||||
eeFs.files[FILE_TMP].size = theFile.m_pos;
|
||||
EFile::swap(theFile.m_fileId, FILE_TMP); // s_sync_write is set to false in swap();
|
||||
|
||||
f_close(&g_oLogFile);
|
||||
|
||||
#if defined(PCBTARANIS)
|
||||
if (version < EEPROM_VER) {
|
||||
storageCheck(true);
|
||||
ConvertModel(i_fileDst, version);
|
||||
eeLoadModel(g_eeGeneral.currModel);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CPUARM)
|
||||
eeLoadModelHeader(i_fileDst, &modelHeaders[i_fileDst]);
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
void RlcFile::writeRlc(uint8_t i_fileId, uint8_t typ, uint8_t *buf, uint16_t i_len, uint8_t sync_write)
|
||||
{
|
||||
create(i_fileId, typ, sync_write);
|
||||
|
||||
m_write_step = WRITE_START_STEP;
|
||||
m_rlc_buf = buf;
|
||||
m_rlc_len = i_len;
|
||||
m_cur_rlc_len = 0;
|
||||
#if defined (EEPROM_PROGRESS_BAR)
|
||||
m_ratio = (typ == FILE_TYP_MODEL ? 100 : 10);
|
||||
#endif
|
||||
|
||||
do {
|
||||
nextRlcWriteStep();
|
||||
} while (IS_SYNC_WRITE_ENABLE() && m_write_step && !s_write_err);
|
||||
}
|
||||
|
||||
void RlcFile::nextRlcWriteStep()
|
||||
{
|
||||
uint8_t cnt = 1;
|
||||
uint8_t cnt0 = 0;
|
||||
uint16_t i = 0;
|
||||
|
||||
if (m_cur_rlc_len) {
|
||||
uint8_t tmp1 = m_cur_rlc_len;
|
||||
uint8_t *tmp2 = m_rlc_buf;
|
||||
m_rlc_buf += m_cur_rlc_len;
|
||||
m_cur_rlc_len = 0;
|
||||
write(tmp2, tmp1);
|
||||
return;
|
||||
}
|
||||
|
||||
bool run0 = (m_rlc_buf[0] == 0);
|
||||
|
||||
if (m_rlc_len==0) goto close;
|
||||
|
||||
for (i=1; 1; i++) { // !! laeuft ein byte zu weit !!
|
||||
bool cur0 = m_rlc_buf[i] == 0;
|
||||
if (cur0 != run0 || cnt==0x3f || (cnt0 && cnt==0x0f) || i==m_rlc_len) {
|
||||
if (run0) {
|
||||
assert(cnt0==0);
|
||||
if (cnt<8 && i!=m_rlc_len)
|
||||
cnt0 = cnt; //aufbew fuer spaeter
|
||||
else {
|
||||
m_rlc_buf+=cnt;
|
||||
m_rlc_len-=cnt;
|
||||
write1(cnt|0x40);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_rlc_buf+=cnt0;
|
||||
m_rlc_len-=cnt0+cnt;
|
||||
m_cur_rlc_len=cnt;
|
||||
if(cnt0){
|
||||
write1(0x80 | (cnt0<<4) | cnt);
|
||||
}
|
||||
else{
|
||||
write1(cnt);
|
||||
}
|
||||
return;
|
||||
}
|
||||
cnt=0;
|
||||
if (i==m_rlc_len) break;
|
||||
run0 = cur0;
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
|
||||
close:
|
||||
|
||||
switch(m_write_step) {
|
||||
case WRITE_START_STEP: {
|
||||
blkid_t fri = 0;
|
||||
|
||||
if (m_currBlk && (fri = EeFsGetLink(m_currBlk))) {
|
||||
// TODO reuse EeFsFree!!!
|
||||
blkid_t prev_freeList = eeFs.freeList;
|
||||
eeFs.freeList = fri;
|
||||
#if defined(CPUARM)
|
||||
freeBlocks++;
|
||||
#endif
|
||||
while (EeFsGetLink(fri)) {
|
||||
fri = EeFsGetLink(fri);
|
||||
#if defined(CPUARM)
|
||||
freeBlocks++;
|
||||
#endif
|
||||
}
|
||||
m_write_step = WRITE_FREE_UNUSED_BLOCKS_STEP1;
|
||||
EeFsSetLink(fri, prev_freeList);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
case WRITE_FINAL_DIRENT_STEP: {
|
||||
m_currBlk = eeFs.files[FILE_TMP].startBlk;
|
||||
DirEnt & f = eeFs.files[m_fileId];
|
||||
eeFs.files[FILE_TMP].startBlk = f.startBlk;
|
||||
eeFs.files[FILE_TMP].size = f.size;
|
||||
f.startBlk = m_currBlk;
|
||||
f.size = m_pos;
|
||||
f.typ = eeFs.files[FILE_TMP].typ;
|
||||
m_write_step = WRITE_TMP_DIRENT_STEP;
|
||||
EeFsFlushDirEnt(m_fileId);
|
||||
return;
|
||||
}
|
||||
|
||||
case WRITE_TMP_DIRENT_STEP:
|
||||
m_write_step = 0;
|
||||
EeFsFlushDirEnt(FILE_TMP);
|
||||
return;
|
||||
|
||||
case WRITE_FREE_UNUSED_BLOCKS_STEP1:
|
||||
m_write_step = WRITE_FREE_UNUSED_BLOCKS_STEP2;
|
||||
EeFsSetLink(m_currBlk, 0);
|
||||
return;
|
||||
|
||||
case WRITE_FREE_UNUSED_BLOCKS_STEP2:
|
||||
m_write_step = WRITE_FINAL_DIRENT_STEP;
|
||||
EeFsFlushFreelist();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void RlcFile::flush()
|
||||
{
|
||||
#if !defined(CPUARM)
|
||||
while (eeprom_buffer_size > 0) wdt_reset();
|
||||
#endif
|
||||
|
||||
ENABLE_SYNC_WRITE(true);
|
||||
|
||||
while (m_write_len && !s_write_err)
|
||||
nextWriteStep();
|
||||
|
||||
while (isWriting() && !s_write_err)
|
||||
nextRlcWriteStep();
|
||||
|
||||
ENABLE_SYNC_WRITE(false);
|
||||
}
|
||||
|
||||
#if defined (EEPROM_PROGRESS_BAR)
|
||||
void RlcFile::DisplayProgressBar(uint8_t x)
|
||||
{
|
||||
if (s_storageDirtyMsk || isWriting() || eeprom_buffer_size) {
|
||||
uint8_t len = s_storageDirtyMsk ? 1 : limit((uint8_t)1, (uint8_t)(7 - (m_rlc_len/m_ratio)), (uint8_t)7);
|
||||
drawFilledRect(x+1, 0, 5, FH, SOLID, ERASE);
|
||||
drawFilledRect(x+2, 7-len, 3, len);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// For conversions ...
|
||||
#if defined(CPUARM)
|
||||
uint16_t eeLoadGeneralSettingsData()
|
||||
{
|
||||
memset(&g_eeGeneral, 0, sizeof(g_eeGeneral));
|
||||
theFile.openRlc(FILE_GENERAL);
|
||||
return theFile.readRlc((uint8_t*)&g_eeGeneral, sizeof(g_eeGeneral));
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t eeLoadModelData(uint8_t index)
|
||||
{
|
||||
#if defined(CPUARM)
|
||||
memset(&g_model, 0, sizeof(g_model));
|
||||
#endif
|
||||
theFile.openRlc(FILE_MODEL(index));
|
||||
return theFile.readRlc((uint8_t*)&g_model, sizeof(g_model));
|
||||
}
|
||||
|
||||
bool eeLoadGeneral()
|
||||
{
|
||||
theFile.openRlc(FILE_GENERAL);
|
||||
if (theFile.readRlc((uint8_t*)&g_eeGeneral, 3) == 3 && g_eeGeneral.version == EEPROM_VER) {
|
||||
theFile.openRlc(FILE_GENERAL);
|
||||
if (theFile.readRlc((uint8_t*)&g_eeGeneral, sizeof(g_eeGeneral)) <= sizeof(EEGeneral) && g_eeGeneral.variant == EEPROM_VARIANT) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(PCBTARANIS)
|
||||
if (g_eeGeneral.variant != EEPROM_VARIANT) {
|
||||
TRACE("EEPROM variant %d instead of %d", g_eeGeneral.variant, EEPROM_VARIANT);
|
||||
return false;
|
||||
}
|
||||
else if (g_eeGeneral.version != EEPROM_VER) {
|
||||
TRACE("EEPROM version %d instead of %d", g_eeGeneral.version, EEPROM_VER);
|
||||
if (!eeConvert()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
TRACE("EEPROM version %d (%d) instead of %d (%d)", g_eeGeneral.version, g_eeGeneral.variant, EEPROM_VER, EEPROM_VARIANT);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void eeLoadModelName(uint8_t id, char *name)
|
||||
{
|
||||
memclear(name, sizeof(g_model.header.name));
|
||||
if (id < MAX_MODELS) {
|
||||
theFile.openRlc(FILE_MODEL(id));
|
||||
theFile.readRlc((uint8_t*)name, sizeof(g_model.header.name));
|
||||
}
|
||||
}
|
||||
|
||||
bool eeModelExists(uint8_t id)
|
||||
{
|
||||
return EFile::exists(FILE_MODEL(id));
|
||||
}
|
||||
|
||||
void storageCheck(bool immediately)
|
||||
{
|
||||
if (immediately) {
|
||||
eeFlush();
|
||||
}
|
||||
|
||||
if (s_storageDirtyMsk & EE_GENERAL) {
|
||||
TRACE("eeprom write general");
|
||||
s_storageDirtyMsk -= EE_GENERAL;
|
||||
theFile.writeRlc(FILE_GENERAL, FILE_TYP_GENERAL, (uint8_t*)&g_eeGeneral, sizeof(EEGeneral), immediately);
|
||||
if (!immediately) return;
|
||||
}
|
||||
|
||||
if (s_storageDirtyMsk & EE_MODEL) {
|
||||
TRACE("eeprom write model");
|
||||
s_storageDirtyMsk = 0;
|
||||
theFile.writeRlc(FILE_MODEL(g_eeGeneral.currModel), FILE_TYP_MODEL, (uint8_t*)&g_model, sizeof(g_model), immediately);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CPUARM)
|
||||
void eeLoadModelHeader(uint8_t id, ModelHeader *header)
|
||||
{
|
||||
memclear(header, sizeof(ModelHeader));
|
||||
if (id < MAX_MODELS) {
|
||||
theFile.openRlc(FILE_MODEL(id));
|
||||
theFile.readRlc((uint8_t*)header, sizeof(ModelHeader));
|
||||
}
|
||||
}
|
||||
|
||||
bool eeCopyModel(uint8_t dst, uint8_t src)
|
||||
{
|
||||
if (theFile.copy(FILE_MODEL(dst), FILE_MODEL(src))) {
|
||||
memcpy(&modelHeaders[dst], &modelHeaders[src], sizeof(ModelHeader));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void eeSwapModels(uint8_t id1, uint8_t id2)
|
||||
{
|
||||
EFile::swap(FILE_MODEL(id1), FILE_MODEL(id2));
|
||||
|
||||
char tmp[sizeof(g_model.header)];
|
||||
memcpy(tmp, &modelHeaders[id1], sizeof(ModelHeader));
|
||||
memcpy(&modelHeaders[id1], &modelHeaders[id2], sizeof(ModelHeader));
|
||||
memcpy(&modelHeaders[id2], tmp, sizeof(ModelHeader));
|
||||
}
|
||||
|
||||
void eeDeleteModel(uint8_t idx)
|
||||
{
|
||||
EFile::rm(FILE_MODEL(idx));
|
||||
memset(&modelHeaders[idx], 0, sizeof(ModelHeader));
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Andre Bernet <bernet.andre@gmail.com>
|
||||
* - Andreas Weitl
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
* - Cameron Weeks <th9xer@gmail.com>
|
||||
* - Erez Raviv
|
||||
* - Gabriel Birkus
|
||||
* - Jean-Pierre Parisy
|
||||
* - Karl Szmutny
|
||||
* - Michael Blandford
|
||||
* - Michal Hlavinka
|
||||
* - Pat Mackenzie
|
||||
* - Philip Moss
|
||||
* - Rob Thomson
|
||||
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
||||
* - Thomas Husterer
|
||||
*
|
||||
* opentx is based on code named
|
||||
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
||||
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
||||
* and the original (and ongoing) project by
|
||||
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _EEPROM_RLC_H_
|
||||
#define _EEPROM_RLC_H_
|
||||
|
||||
// TODO duplicated
|
||||
#ifndef PACK
|
||||
#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__))
|
||||
#endif
|
||||
|
||||
#if defined(PCBTARANIS)
|
||||
#define blkid_t uint16_t
|
||||
#if !defined(EESIZE)
|
||||
#if defined(REV4a)
|
||||
#define EESIZE (64*1024)
|
||||
#else
|
||||
#define EESIZE (32*1024)
|
||||
#endif
|
||||
#else
|
||||
#define EESIZE_SIMU (64*1024)
|
||||
#endif
|
||||
#define EEFS_VERS 5
|
||||
#define MAXFILES 62
|
||||
#define BS 64
|
||||
#elif defined(CPUM2560) || defined(CPUM2561) || defined(CPUM128)
|
||||
#define blkid_t uint8_t
|
||||
#define EESIZE 4096
|
||||
#define EEFS_VERS 5
|
||||
#define MAXFILES 36
|
||||
#define BS 16
|
||||
#else
|
||||
#define blkid_t uint8_t
|
||||
#define EESIZE 2048
|
||||
#define EEFS_VERS 4
|
||||
#define MAXFILES 20
|
||||
#define BS 16
|
||||
#endif
|
||||
|
||||
PACK(struct DirEnt {
|
||||
blkid_t startBlk;
|
||||
uint16_t size:12;
|
||||
uint16_t typ:4;
|
||||
});
|
||||
|
||||
#if defined(CPUARM)
|
||||
#define EEFS_EXTRA_FIELDS uint8_t spare[2];
|
||||
#else
|
||||
#define EEFS_EXTRA_FIELDS
|
||||
#endif
|
||||
|
||||
PACK(struct EeFs {
|
||||
uint8_t version;
|
||||
blkid_t mySize;
|
||||
blkid_t freeList;
|
||||
uint8_t bs;
|
||||
EEFS_EXTRA_FIELDS
|
||||
DirEnt files[MAXFILES];
|
||||
});
|
||||
|
||||
extern EeFs eeFs;
|
||||
|
||||
#define FILE_TYP_GENERAL 1
|
||||
#define FILE_TYP_MODEL 2
|
||||
|
||||
/// fileId of general file
|
||||
#define FILE_GENERAL 0
|
||||
/// convert model number 0..MAX_MODELS-1 int fileId
|
||||
#define FILE_MODEL(n) (1+(n))
|
||||
#define FILE_TMP (1+MAX_MODELS)
|
||||
|
||||
#define RESV sizeof(EeFs) //reserv for eeprom header with directory (eeFs)
|
||||
|
||||
#if defined(CPUM64)
|
||||
#define FIRSTBLK (RESV/BS)
|
||||
#define BLOCKS (EESIZE/BS)
|
||||
#define BLOCKS_OFFSET 0
|
||||
#else
|
||||
#define FIRSTBLK 1
|
||||
#define BLOCKS (1+(EESIZE-RESV)/BS)
|
||||
#define BLOCKS_OFFSET (RESV-BS)
|
||||
#endif
|
||||
|
||||
uint16_t EeFsGetFree();
|
||||
|
||||
#if !defined(CPUARM)
|
||||
extern volatile int8_t eeprom_buffer_size;
|
||||
#endif
|
||||
|
||||
class EFile
|
||||
{
|
||||
public:
|
||||
|
||||
///remove contents of given file
|
||||
static void rm(uint8_t i_fileId);
|
||||
|
||||
///swap contents of file1 with them of file2
|
||||
static void swap(uint8_t i_fileId1, uint8_t i_fileId2);
|
||||
|
||||
///return true if the file with given fileid exists
|
||||
static bool exists(uint8_t i_fileId);
|
||||
|
||||
///open file for reading, no close necessary
|
||||
void openRd(uint8_t i_fileId);
|
||||
|
||||
uint8_t read(uint8_t *buf, uint8_t len);
|
||||
|
||||
// protected:
|
||||
|
||||
uint8_t m_fileId; //index of file in directory = filename
|
||||
uint16_t m_pos; //over all filepos
|
||||
blkid_t m_currBlk; //current block.id
|
||||
uint8_t m_ofs; //offset inside of the current block
|
||||
};
|
||||
|
||||
#define eeFileSize(f) eeFs.files[f].size
|
||||
#define eeModelSize(id) eeFileSize(FILE_MODEL(id))
|
||||
|
||||
#define ERR_NONE 0
|
||||
#define ERR_FULL 1
|
||||
extern uint8_t s_write_err; // error reasons
|
||||
|
||||
extern uint8_t s_sync_write;
|
||||
#define ENABLE_SYNC_WRITE(val) s_sync_write = val;
|
||||
#define IS_SYNC_WRITE_ENABLE() s_sync_write
|
||||
|
||||
///deliver current errno, this is reset in open
|
||||
inline uint8_t write_errno() { return s_write_err; }
|
||||
|
||||
class RlcFile: public EFile
|
||||
{
|
||||
uint8_t m_bRlc; // control byte for run length decoder
|
||||
uint8_t m_zeroes;
|
||||
|
||||
uint8_t m_flags;
|
||||
#define WRITE_FIRST_LINK 0x01
|
||||
#define WRITE_NEXT_LINK_1 0x02
|
||||
#define WRITE_NEXT_LINK_2 0x03
|
||||
#define WRITE_START_STEP 0x10
|
||||
#define WRITE_FREE_UNUSED_BLOCKS_STEP1 0x20
|
||||
#define WRITE_FREE_UNUSED_BLOCKS_STEP2 0x30
|
||||
#define WRITE_FINAL_DIRENT_STEP 0x40
|
||||
#define WRITE_TMP_DIRENT_STEP 0x50
|
||||
uint8_t m_write_step;
|
||||
uint16_t m_rlc_len;
|
||||
uint8_t * m_rlc_buf;
|
||||
uint8_t m_cur_rlc_len;
|
||||
uint8_t m_write1_byte;
|
||||
uint8_t m_write_len;
|
||||
uint8_t * m_write_buf;
|
||||
#if defined (EEPROM_PROGRESS_BAR)
|
||||
uint8_t m_ratio;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
void openRlc(uint8_t i_fileId);
|
||||
|
||||
void create(uint8_t i_fileId, uint8_t typ, uint8_t sync_write);
|
||||
|
||||
/// copy contents of i_fileSrc to i_fileDst
|
||||
bool copy(uint8_t i_fileDst, uint8_t i_fileSrc);
|
||||
|
||||
inline bool isWriting() { return m_write_step != 0; }
|
||||
void write(uint8_t *buf, uint8_t i_len);
|
||||
void write1(uint8_t b);
|
||||
void nextWriteStep();
|
||||
void nextRlcWriteStep();
|
||||
void writeRlc(uint8_t i_fileId, uint8_t typ, uint8_t *buf, uint16_t i_len, uint8_t sync_write);
|
||||
|
||||
// flush the current write operation if any
|
||||
void flush();
|
||||
|
||||
// read from opened file and decode rlc-coded data
|
||||
uint16_t readRlc(uint8_t *buf, uint16_t i_len);
|
||||
|
||||
#if defined (EEPROM_PROGRESS_BAR)
|
||||
void DisplayProgressBar(uint8_t x);
|
||||
#endif
|
||||
};
|
||||
|
||||
extern RlcFile theFile; //used for any file operation
|
||||
|
||||
inline void eeFlush()
|
||||
{
|
||||
theFile.flush();
|
||||
}
|
||||
|
||||
inline bool eepromIsWriting()
|
||||
{
|
||||
return theFile.isWriting();
|
||||
}
|
||||
|
||||
inline void eepromWriteProcess()
|
||||
{
|
||||
theFile.nextWriteStep();
|
||||
}
|
||||
|
||||
#if defined (EEPROM_PROGRESS_BAR)
|
||||
#define DISPLAY_PROGRESS_BAR(x) theFile.DisplayProgressBar(x)
|
||||
#else
|
||||
#define DISPLAY_PROGRESS_BAR(x)
|
||||
#endif
|
||||
|
||||
#if defined(CPUARM)
|
||||
bool eeCopyModel(uint8_t dst, uint8_t src);
|
||||
void eeSwapModels(uint8_t id1, uint8_t id2);
|
||||
void eeDeleteModel(uint8_t idx);
|
||||
#else
|
||||
#define eeCopyModel(dst, src) theFile.copy(FILE_MODEL(dst), FILE_MODEL(src))
|
||||
#define eeSwapModels(id1, id2) EFile::swap(FILE_MODEL(id1), FILE_MODEL(id2))
|
||||
#define eeDeleteModel(idx) EFile::rm(FILE_MODEL(idx))
|
||||
#endif
|
||||
|
||||
#if defined(SDCARD)
|
||||
const pm_char * eeBackupModel(uint8_t i_fileSrc);
|
||||
const pm_char * eeRestoreModel(uint8_t i_fileDst, char *model_name);
|
||||
#endif
|
||||
|
||||
// For conversions
|
||||
#if defined(CPUARM)
|
||||
void loadGeneralSettings();
|
||||
void loadModel(int index);
|
||||
#endif
|
||||
|
||||
bool eepromOpen();
|
||||
void eeLoadModelName(uint8_t id, char *name);
|
||||
bool eeLoadGeneral();
|
||||
|
||||
// For EEPROM backup/restore
|
||||
#if defined(CPUARM)
|
||||
inline bool isEepromStart(const void * buffer)
|
||||
{
|
||||
// OpenTX EEPROM
|
||||
{
|
||||
const EeFs * eeprom = (const EeFs *)buffer;
|
||||
if (eeprom->version==EEFS_VERS && eeprom->mySize==sizeof(eeFs) && eeprom->bs==BS)
|
||||
return true;
|
||||
}
|
||||
|
||||
// ersky9x EEPROM
|
||||
{
|
||||
const uint8_t * eeprom = (const uint8_t *)buffer;
|
||||
uint8_t size = eeprom[1] ;
|
||||
uint8_t bs = eeprom[3] ;
|
||||
if (size==0x80 && bs==0x80)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Andre Bernet <bernet.andre@gmail.com>
|
||||
* - Andreas Weitl
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
* - Cameron Weeks <th9xer@gmail.com>
|
||||
* - Erez Raviv
|
||||
* - Gabriel Birkus
|
||||
* - Jean-Pierre Parisy
|
||||
* - Karl Szmutny
|
||||
* - Michael Blandford
|
||||
* - Michal Hlavinka
|
||||
* - Pat Mackenzie
|
||||
* - Philip Moss
|
||||
* - Rob Thomson
|
||||
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
||||
* - Thomas Husterer
|
||||
*
|
||||
* opentx is based on code named
|
||||
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
||||
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
||||
* and the original (and ongoing) project by
|
||||
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../opentx.h"
|
||||
|
||||
const char * writeFile(const char * filename, const uint8_t * data, uint16_t size)
|
||||
{
|
||||
FIL file;
|
||||
char buf[8];
|
||||
UINT written;
|
||||
|
||||
FRESULT result = f_open(&file, filename, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if (result != FR_OK) {
|
||||
return SDCARD_ERROR(result);
|
||||
}
|
||||
|
||||
*(uint32_t*)&buf[0] = O9X_FOURCC;
|
||||
buf[4] = EEPROM_VER;
|
||||
buf[5] = 'M';
|
||||
*(uint16_t*)&buf[6] = size;
|
||||
|
||||
result = f_write(&file, buf, 8, &written);
|
||||
if (result != FR_OK || written != 8) {
|
||||
f_close(&file);
|
||||
return SDCARD_ERROR(result);
|
||||
}
|
||||
|
||||
result = f_write(&file, data, size, &written);
|
||||
if (result != FR_OK || written != size) {
|
||||
f_close(&file);
|
||||
return SDCARD_ERROR(result);
|
||||
}
|
||||
|
||||
f_close(&file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char * writeModel()
|
||||
{
|
||||
char path[256];
|
||||
strcpy(path, STR_MODELS_PATH);
|
||||
path[sizeof(MODELS_PATH)-1] = '/';
|
||||
strAppend(&path[sizeof(MODELS_PATH)], g_eeGeneral.currModelFilename, sizeof(g_eeGeneral.currModelFilename));
|
||||
return writeFile(path, (uint8_t *)&g_model, sizeof(g_model));
|
||||
}
|
||||
|
||||
const char * loadFile(const char * filename, uint8_t * data, uint16_t maxsize)
|
||||
{
|
||||
FIL file;
|
||||
char buf[8];
|
||||
UINT read;
|
||||
|
||||
FRESULT result = f_open(&file, filename, FA_OPEN_EXISTING | FA_READ);
|
||||
if (result != FR_OK) {
|
||||
return SDCARD_ERROR(result);
|
||||
}
|
||||
|
||||
if (f_size(&file) < 8) {
|
||||
f_close(&file);
|
||||
return STR_INCOMPATIBLE;
|
||||
}
|
||||
|
||||
result = f_read(&file, (uint8_t *)buf, 8, &read);
|
||||
if (result != FR_OK || read != 8) {
|
||||
f_close(&file);
|
||||
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(&file);
|
||||
return STR_INCOMPATIBLE;
|
||||
}
|
||||
|
||||
uint16_t size = min<uint16_t>(maxsize, *(uint16_t*)&buf[6]);
|
||||
result = f_read(&file, data, size, &read);
|
||||
if (result != FR_OK || read != size) {
|
||||
f_close(&file);
|
||||
return SDCARD_ERROR(result);
|
||||
}
|
||||
|
||||
f_close(&file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char * loadModel(const char * filename)
|
||||
{
|
||||
char path[256];
|
||||
strcpy(path, STR_MODELS_PATH);
|
||||
path[sizeof(MODELS_PATH)-1] = '/';
|
||||
strcpy(&path[sizeof(MODELS_PATH)], filename);
|
||||
|
||||
preModelLoad();
|
||||
|
||||
const char * error = loadFile(path, (uint8_t *)&g_model, sizeof(g_model));
|
||||
if (error) {
|
||||
TRACE("loadModel error=%s", error);
|
||||
}
|
||||
|
||||
bool newModel = false;
|
||||
if (error) {
|
||||
modelDefault(0) ;
|
||||
storageCheck(true);
|
||||
newModel = true;
|
||||
}
|
||||
|
||||
postModelLoad(newModel);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
const char RADIO_SETTINGS_PATH[] = RADIO_PATH "/radio.bin";
|
||||
|
||||
const char * loadGeneralSettings()
|
||||
{
|
||||
const char * error = loadFile(RADIO_SETTINGS_PATH, (uint8_t *)&g_eeGeneral, sizeof(g_eeGeneral));
|
||||
if (error) {
|
||||
TRACE("loadGeneralSettings error=%s", error);
|
||||
}
|
||||
// TODO this is temporary, we only have one model for now
|
||||
return error;
|
||||
}
|
||||
|
||||
const char * writeGeneralSettings()
|
||||
{
|
||||
return writeFile(RADIO_SETTINGS_PATH, (uint8_t *)&g_eeGeneral, sizeof(g_eeGeneral));
|
||||
}
|
||||
|
||||
void storageCheck(bool immediately)
|
||||
{
|
||||
// if (immediately) {
|
||||
// eepromWriteWait();
|
||||
// }
|
||||
|
||||
if (s_storageDirtyMsk & EE_GENERAL) {
|
||||
TRACE("eeprom write general");
|
||||
s_storageDirtyMsk -= EE_GENERAL;
|
||||
writeGeneralSettings();
|
||||
// if (immediately)
|
||||
// eepromWriteWait();
|
||||
// else
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_storageDirtyMsk & EE_MODEL) {
|
||||
TRACE("eeprom write model");
|
||||
s_storageDirtyMsk -= EE_MODEL;
|
||||
const char * error = writeModel();
|
||||
if (error) {
|
||||
TRACE("writeModel error=%s", error);
|
||||
}
|
||||
// if (immediately)
|
||||
// eepromWriteWait();
|
||||
}
|
||||
}
|
||||
|
||||
void storageReadAll()
|
||||
{
|
||||
if (loadGeneralSettings() != NULL) {
|
||||
storageEraseAll(true);
|
||||
strcpy(g_eeGeneral.currModelFilename, "model.bin");
|
||||
}
|
||||
|
||||
stickMode = g_eeGeneral.stickMode;
|
||||
|
||||
#if defined(CPUARM)
|
||||
for (uint8_t i=0; languagePacks[i]!=NULL; i++) {
|
||||
if (!strncmp(g_eeGeneral.ttsLanguage, languagePacks[i]->id, 2)) {
|
||||
currentLanguagePackIdx = i;
|
||||
currentLanguagePack = languagePacks[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
loadModel(g_eeGeneral.currModelFilename);
|
||||
}
|
||||
|
||||
void storageFormat()
|
||||
{
|
||||
sdCheckAndCreateDirectory(RADIO_PATH);
|
||||
sdCheckAndCreateDirectory(MODELS_PATH);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Andre Bernet <bernet.andre@gmail.com>
|
||||
* - Andreas Weitl
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
* - Cameron Weeks <th9xer@gmail.com>
|
||||
* - Erez Raviv
|
||||
* - Gabriel Birkus
|
||||
* - Jean-Pierre Parisy
|
||||
* - Karl Szmutny
|
||||
* - Michael Blandford
|
||||
* - Michal Hlavinka
|
||||
* - Pat Mackenzie
|
||||
* - Philip Moss
|
||||
* - Rob Thomson
|
||||
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
||||
* - Thomas Husterer
|
||||
*
|
||||
* opentx is based on code named
|
||||
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
||||
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
||||
* and the original (and ongoing) project by
|
||||
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
const char * loadModel(const char * filename);
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Andre Bernet <bernet.andre@gmail.com>
|
||||
* - Andreas Weitl
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
* - Cameron Weeks <th9xer@gmail.com>
|
||||
* - Erez Raviv
|
||||
* - Gabriel Birkus
|
||||
* - Jean-Pierre Parisy
|
||||
* - Karl Szmutny
|
||||
* - Michael Blandford
|
||||
* - Michal Hlavinka
|
||||
* - Pat Mackenzie
|
||||
* - Philip Moss
|
||||
* - Rob Thomson
|
||||
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
||||
* - Thomas Husterer
|
||||
*
|
||||
* opentx is based on code named
|
||||
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
||||
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
||||
* and the original (and ongoing) project by
|
||||
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _STORAGE_H_
|
||||
#define _STORAGE_H_
|
||||
|
||||
#if defined(SIMU)
|
||||
#define WRITE_DELAY_10MS 200
|
||||
#elif defined(PCBTARANIS)
|
||||
#define WRITE_DELAY_10MS 500
|
||||
#elif defined(PCBSKY9X) && !defined(REV0)
|
||||
#define WRITE_DELAY_10MS 500
|
||||
#elif defined(PCBGRUVIN9X) && !defined(REV0)
|
||||
#define WRITE_DELAY_10MS 500
|
||||
#else
|
||||
#define WRITE_DELAY_10MS 200
|
||||
#endif
|
||||
|
||||
extern uint8_t s_storageDirtyMsk;
|
||||
extern tmr10ms_t s_storageDirtyTime10ms;
|
||||
|
||||
#define TIME_TO_WRITE() (s_storageDirtyMsk && (tmr10ms_t)(get_tmr10ms() - s_storageDirtyTime10ms) >= (tmr10ms_t)WRITE_DELAY_10MS)
|
||||
|
||||
void storageEraseAll(bool warn);
|
||||
void storageFormat();
|
||||
void storageReadAll();
|
||||
void storageDirty(uint8_t msk);
|
||||
void storageCheck(bool immediately);
|
||||
|
||||
void preModelLoad();
|
||||
void postModelLoad(bool newModel);
|
||||
|
||||
#if defined(EEPROM_RLC)
|
||||
#include "eeprom_common.h"
|
||||
#include "eeprom_rlc.h"
|
||||
#elif defined(EEPROM)
|
||||
#include "eeprom_common.h"
|
||||
#include "eeprom_raw.h"
|
||||
#elif defined(SDCARD)
|
||||
#include "sdcard_raw.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Andre Bernet <bernet.andre@gmail.com>
|
||||
* - Andreas Weitl
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
* - Cameron Weeks <th9xer@gmail.com>
|
||||
* - Erez Raviv
|
||||
* - Gabriel Birkus
|
||||
* - Jean-Pierre Parisy
|
||||
* - Karl Szmutny
|
||||
* - Michael Blandford
|
||||
* - Michal Hlavinka
|
||||
* - Pat Mackenzie
|
||||
* - Philip Moss
|
||||
* - Rob Thomson
|
||||
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
||||
* - Thomas Husterer
|
||||
*
|
||||
* opentx is based on code named
|
||||
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
||||
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
||||
* and the original (and ongoing) project by
|
||||
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../opentx.h"
|
||||
|
||||
uint8_t s_storageDirtyMsk;
|
||||
tmr10ms_t s_storageDirtyTime10ms;
|
||||
|
||||
void storageDirty(uint8_t msk)
|
||||
{
|
||||
s_storageDirtyMsk |= msk;
|
||||
s_storageDirtyTime10ms = get_tmr10ms() ;
|
||||
}
|
||||
|
||||
void preModelLoad()
|
||||
{
|
||||
#if defined(CPUARM)
|
||||
watchdogSetTimeout(500/*5s*/);
|
||||
#endif
|
||||
|
||||
#if defined(SDCARD)
|
||||
closeLogs();
|
||||
#endif
|
||||
|
||||
if (pulsesStarted()) {
|
||||
pausePulses();
|
||||
}
|
||||
|
||||
pauseMixerCalculations();
|
||||
}
|
||||
|
||||
void postModelLoad(bool newModel)
|
||||
{
|
||||
AUDIO_FLUSH();
|
||||
flightReset();
|
||||
logicalSwitchesReset();
|
||||
|
||||
if (pulsesStarted()) {
|
||||
#if defined(GUI)
|
||||
if (!newModel) {
|
||||
checkAll();
|
||||
}
|
||||
#endif
|
||||
resumePulses();
|
||||
}
|
||||
|
||||
customFunctionsReset();
|
||||
|
||||
restoreTimers();
|
||||
|
||||
#if defined(CPUARM)
|
||||
for (int i=0; i<MAX_SENSORS; i++) {
|
||||
TelemetrySensor & sensor = g_model.telemetrySensors[i];
|
||||
if (sensor.type == TELEM_TYPE_CALCULATED && sensor.persistent) {
|
||||
telemetryItems[i].value = sensor.persistentValue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
LOAD_MODEL_CURVES();
|
||||
|
||||
resumeMixerCalculations();
|
||||
// TODO pulses should be started after mixer calculations ...
|
||||
|
||||
#if defined(FRSKY)
|
||||
frskySendAlarms();
|
||||
#endif
|
||||
|
||||
#if defined(CPUARM) && defined(SDCARD)
|
||||
referenceModelAudioFiles();
|
||||
#endif
|
||||
|
||||
LOAD_MODEL_BITMAP();
|
||||
LUA_LOAD_MODEL_SCRIPTS();
|
||||
SEND_FAILSAFE_1S();
|
||||
PLAY_MODEL_NAME();
|
||||
}
|
||||
|
||||
void storageEraseAll(bool warn)
|
||||
{
|
||||
TRACE("storageEraseAll()");
|
||||
|
||||
generalDefault();
|
||||
modelDefault(0);
|
||||
|
||||
if (warn) {
|
||||
ALERT(STR_EEPROMWARN, STR_BADEEPROMDATA, AU_BAD_EEPROM);
|
||||
}
|
||||
|
||||
MESSAGE(STR_EEPROMWARN, STR_EEPROMFORMATTING, NULL, AU_EEPROM_FORMATTING);
|
||||
|
||||
storageFormat();
|
||||
storageDirty(EE_GENERAL);
|
||||
storageDirty(EE_MODEL);
|
||||
storageCheck(true);
|
||||
}
|
||||
Reference in New Issue
Block a user