* Model templates - select and load after Create Model for color radios * Model templates - save model as template, only for color radios * Small fix to drawTextLines(...) to handle consecutive spaces * Change title of button for empty template folder * I found out why "no trailing slash = important" in path names! * Reworked file and path name string manipulation No longer using chdir, as Lua scripts etc. could be messing with the working dir Use buffers more and std::string less * Adjusting the size of buffers I think that I got it right now. Really hard to figure out the right size constants! Also added storageDirty(EE_MODEL) after reading the template file and renaming the model * Added storage checks * Slight simplification - all template buttons are similar * Added "Blank Model" button * Wizard Lua script If there is a Lua script with the same name as the template file in the folder, then it is run after reading the template.
227 lines
5.5 KiB
C++
227 lines
5.5 KiB
C++
/*
|
|
* Copyright (C) EdgeTX
|
|
*
|
|
* Based on code named
|
|
* opentx - https://github.com/opentx/opentx
|
|
* th9x - http://code.google.com/p/th9x
|
|
* er9x - http://code.google.com/p/er9x
|
|
* gruvin9x - http://code.google.com/p/gruvin9x
|
|
*
|
|
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
|
*
|
|
* 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"
|
|
#include "storage.h"
|
|
#include "sdcard_common.h"
|
|
#include "modelslist.h"
|
|
#include "conversions/conversions.h"
|
|
#include "model_init.h"
|
|
|
|
// defined either in sdcard_raw.cpp or sdcard_yaml.cpp
|
|
void storageCreateModelsList();
|
|
|
|
void getModelPath(char * path, const char * filename, const char* pathName)
|
|
{
|
|
unsigned int len = strlen(pathName);
|
|
strcpy(path, pathName);
|
|
path[len] = '/';
|
|
strcpy(&path[len + 1], filename);
|
|
}
|
|
|
|
void storageEraseAll(bool warn)
|
|
{
|
|
TRACE("storageEraseAll");
|
|
|
|
#if defined(COLORLCD)
|
|
// the theme has not been loaded before
|
|
static_cast<OpenTxTheme*>(theme)->load();
|
|
#endif
|
|
|
|
// Init backlight mode before entering alert screens
|
|
requiredBacklightBright = BACKLIGHT_FORCED_ON;
|
|
|
|
#if defined(PCBHORUS)
|
|
g_eeGeneral.blOffBright = 20;
|
|
#endif
|
|
|
|
if (warn) {
|
|
ALERT(STR_STORAGE_WARNING, STR_BAD_RADIO_DATA, AU_BAD_RADIODATA);
|
|
}
|
|
|
|
RAISE_ALERT(STR_STORAGE_WARNING, STR_STORAGE_FORMAT, NULL, AU_NONE);
|
|
|
|
storageFormat();
|
|
storageDirty(EE_GENERAL);
|
|
storageDirty(EE_MODEL);
|
|
storageCheck(true);
|
|
}
|
|
|
|
void storageFormat()
|
|
{
|
|
sdCheckAndCreateDirectory(RADIO_PATH);
|
|
sdCheckAndCreateDirectory(MODELS_PATH);
|
|
generalDefault();
|
|
setModelDefaults();
|
|
#if defined(STORAGE_MODELSLIST)
|
|
storageCreateModelsList();
|
|
#endif
|
|
}
|
|
|
|
void storageCheck(bool immediately)
|
|
{
|
|
if (storageDirtyMsk & EE_GENERAL) {
|
|
TRACE("eeprom write general");
|
|
storageDirtyMsk &= ~EE_GENERAL;
|
|
const char * error = writeGeneralSettings();
|
|
if (error) {
|
|
TRACE("writeGeneralSettings error=%s", error);
|
|
}
|
|
}
|
|
|
|
if (storageDirtyMsk & EE_MODEL) {
|
|
TRACE("eeprom write model");
|
|
storageDirtyMsk &= ~EE_MODEL;
|
|
const char * error = writeModel();
|
|
if (error) {
|
|
TRACE("writeModel error=%s", error);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(STORAGE_MODELSLIST)
|
|
const char * createModel()
|
|
{
|
|
preModelLoad();
|
|
|
|
char filename[LEN_MODEL_FILENAME+1];
|
|
memset(filename, 0, sizeof(filename));
|
|
strcpy(filename, MODEL_FILENAME_PATTERN);
|
|
|
|
int index = findNextFileIndex(filename, LEN_MODEL_FILENAME, MODELS_PATH);
|
|
if (index > 0) {
|
|
setModelDefaults(index);
|
|
memcpy(g_eeGeneral.currModelFilename, filename, sizeof(g_eeGeneral.currModelFilename));
|
|
|
|
storageDirty(EE_GENERAL);
|
|
storageDirty(EE_MODEL);
|
|
storageCheck(true);
|
|
}
|
|
postModelLoad(false);
|
|
|
|
return g_eeGeneral.currModelFilename;
|
|
}
|
|
#endif
|
|
|
|
const char* loadModel(char* filename, bool alarms)
|
|
{
|
|
preModelLoad();
|
|
|
|
const char* error = readModel(filename, (uint8_t*)&g_model, sizeof(g_model));
|
|
if (error) {
|
|
TRACE("loadModel error=%s", error);
|
|
|
|
// just get some clean memory state in "g_model"
|
|
// so the mixer can run safely
|
|
memset(&g_model, 0, sizeof(g_model));
|
|
applyDefaultTemplate();
|
|
|
|
storageCheck(true);
|
|
postModelLoad(false);
|
|
return error;
|
|
}
|
|
|
|
postModelLoad(alarms);
|
|
return nullptr;
|
|
}
|
|
|
|
const char* loadModelTemplate(const char* fileName, const char* filePath)
|
|
{
|
|
preModelLoad();
|
|
// Assuming that the template is located in current working directory
|
|
const char* error = readModel(fileName, (uint8_t*)&g_model, sizeof(g_model), filePath);
|
|
if (error) {
|
|
TRACE("loadModel error=%s", error);
|
|
// just get some clean memory state in "g_model" so the mixer can run safely
|
|
memset(&g_model, 0, sizeof(g_model));
|
|
applyDefaultTemplate();
|
|
|
|
storageCheck(true);
|
|
postModelLoad(false);
|
|
return error;
|
|
}
|
|
|
|
postModelLoad(false);
|
|
return nullptr;
|
|
}
|
|
|
|
void storageReadAll()
|
|
{
|
|
TRACE("storageReadAll");
|
|
|
|
#if defined(STORAGE_MODELSLIST)
|
|
// Wipe models list in case
|
|
// it's being reloaded after USB connection
|
|
modelslist.clear();
|
|
#endif
|
|
|
|
if (loadRadioSettings() != nullptr) {
|
|
storageEraseAll(true);
|
|
}
|
|
#if !defined(STORAGE_MODELSLIST)
|
|
else {
|
|
loadModelHeaders();
|
|
}
|
|
#endif
|
|
|
|
for (uint8_t i = 0; languagePacks[i] != nullptr; i++) {
|
|
if (!strncmp(g_eeGeneral.ttsLanguage, languagePacks[i]->id, 2)) {
|
|
currentLanguagePackIdx = i;
|
|
currentLanguagePack = languagePacks[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if defined(STORAGE_MODELSLIST)
|
|
// and reload the list
|
|
modelslist.load();
|
|
|
|
// Current model filename is empty...
|
|
// Let's fix it!
|
|
if (strlen(g_eeGeneral.currModelFilename) == 0) {
|
|
|
|
// sizeof(currModelFilename) == LEN_MODEL_FILENAME + 1
|
|
// make sure it is terminated (see doc for strncpy())
|
|
strncpy(g_eeGeneral.currModelFilename, DEFAULT_MODEL_FILENAME, LEN_MODEL_FILENAME);
|
|
g_eeGeneral.currModelFilename[LEN_MODEL_FILENAME] = '\0';
|
|
|
|
storageDirty(EE_GENERAL);
|
|
storageCheck(true);
|
|
}
|
|
|
|
if (loadModel(g_eeGeneral.currModelFilename, false) != nullptr) {
|
|
TRACE("No current model or SD card error");
|
|
}
|
|
#else
|
|
if (loadModel(g_eeGeneral.currModel, false) != nullptr) {
|
|
TRACE("No current model or SD card error");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if !defined(COLORLCD)
|
|
void checkModelIdUnique(uint8_t index, uint8_t module)
|
|
{
|
|
//TODO
|
|
}
|
|
#endif
|
|
|