Merge pull request #8437 from opentx/raphaelcoeffic/fix-startup
2.4: empty SD card startup fixes and clean-up
This commit is contained in:
@@ -419,6 +419,7 @@ set(SRC
|
||||
stamp.cpp
|
||||
timers.cpp
|
||||
trainer.cpp
|
||||
model_init.cpp
|
||||
)
|
||||
|
||||
if(GUI)
|
||||
|
||||
@@ -550,9 +550,9 @@ typedef uint8_t swarnenable_t;
|
||||
#elif defined(COLORLCD)
|
||||
#include "gui/colorlcd/layout.h"
|
||||
#include "gui/colorlcd/topbar.h"
|
||||
#define LAYOUT_NAME_LEN 10
|
||||
#define LAYOUT_ID_LEN 10
|
||||
PACK(struct CustomScreenData {
|
||||
char layoutName[LAYOUT_NAME_LEN];
|
||||
char LayoutId[LAYOUT_ID_LEN];
|
||||
Layout::PersistentData layoutData;
|
||||
});
|
||||
#define CUSTOM_SCREENS_DATA \
|
||||
|
||||
@@ -75,7 +75,7 @@ void loadDefaultLayout()
|
||||
auto& screenData = g_model.screenData[0];
|
||||
|
||||
if (screen == nullptr && defaultLayout != nullptr) {
|
||||
strcpy(screenData.layoutName, defaultLayout->getName());
|
||||
strcpy(screenData.LayoutId, defaultLayout->getId());
|
||||
screen = defaultLayout->create(&screenData.layoutData);
|
||||
if (screen) {
|
||||
screen->attach(ViewMain::instance());
|
||||
@@ -88,7 +88,7 @@ void loadCustomScreens()
|
||||
for (unsigned int i = 0; i < MAX_CUSTOM_SCREENS; i++) {
|
||||
|
||||
auto& screen = customScreens[i];
|
||||
screen = loadLayout(g_model.screenData[i].layoutName,
|
||||
screen = loadLayout(g_model.screenData[i].LayoutId,
|
||||
&g_model.screenData[i].layoutData);
|
||||
|
||||
if (screen) {
|
||||
|
||||
@@ -286,14 +286,7 @@ class ModelCategoryPageBody: public FormWindow {
|
||||
update(); // modelslist.getModelIndex(modelCell));
|
||||
});
|
||||
}
|
||||
menu->addLine(STR_CREATE_MODEL, [=]() {
|
||||
storageCheck(true);
|
||||
modelslist.setCurrentModel(modelslist.addModel(category, createModel()));
|
||||
#if defined(LUA)
|
||||
// chainMenu(menuModelWizard);
|
||||
#endif
|
||||
update(category->size() - 1);
|
||||
});
|
||||
menu->addLine(STR_CREATE_MODEL, getCreateModelAction());
|
||||
menu->addLine(STR_DUPLICATE_MODEL, [=]() {
|
||||
char duplicatedFilename[LEN_MODEL_FILENAME + 1];
|
||||
memcpy(duplicatedFilename, model->modelFilename, sizeof(duplicatedFilename));
|
||||
@@ -342,11 +335,55 @@ class ModelCategoryPageBody: public FormWindow {
|
||||
}
|
||||
|
||||
setInnerHeight(y);
|
||||
|
||||
if (category->empty()) {
|
||||
setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override
|
||||
{
|
||||
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
|
||||
Menu * menu = new Menu(this);
|
||||
menu->addLine(STR_CREATE_MODEL, getCreateModelAction());
|
||||
//TODO: create category?
|
||||
}
|
||||
else {
|
||||
FormWindow::onEvent(event);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void setFocus(uint8_t flag = SET_FOCUS_DEFAULT, Window * from = nullptr) override
|
||||
{
|
||||
if (category->empty()) {
|
||||
// use Window::setFocus() to avoid forwarding focus to nowhere
|
||||
// this crashes currently in libopenui
|
||||
Window::setFocus(flag, from);
|
||||
}
|
||||
else {
|
||||
FormWindow::setFocus(flag, from);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
ModelsCategory * category;
|
||||
ModelSelectFooter * footer;
|
||||
|
||||
std::function<void(void)> getCreateModelAction()
|
||||
{
|
||||
return [=]() {
|
||||
storageCheck(true);
|
||||
modelslist.setCurrentModel(modelslist.addModel(category, createModel()));
|
||||
#if defined(LUA)
|
||||
// chainMenu(menuModelWizard);
|
||||
#endif
|
||||
update(category->size() - 1);
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class ModelCategoryPage: public PageTab {
|
||||
|
||||
@@ -276,8 +276,11 @@ void RadioCalibrationPage::nextStep()
|
||||
g_eeGeneral.chkSum = evalChkSum();
|
||||
storageDirty(EE_GENERAL);
|
||||
menuCalibrationState = CALIB_FINISHED;
|
||||
|
||||
// initial calibration completed
|
||||
// -> exit
|
||||
if (initial)
|
||||
text->getParent()->getParent()->deleteLater();
|
||||
deleteLater();
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -289,5 +292,5 @@ void RadioCalibrationPage::nextStep()
|
||||
|
||||
void startCalibration()
|
||||
{
|
||||
new RadioCalibrationPage();
|
||||
new RadioCalibrationPage(true);
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ void ScreenAddPage::build(FormWindow * window)
|
||||
const LayoutFactory * factory = getRegisteredLayouts().front();
|
||||
|
||||
screen = factory->create(&screenData.layoutData);
|
||||
strncpy(screenData.layoutName, factory->getId(), sizeof(screenData.layoutName));
|
||||
strncpy(screenData.LayoutId, factory->getId(), sizeof(screenData.LayoutId));
|
||||
|
||||
auto tab = new ScreenSetupPage(menu, screen, screenData);
|
||||
std::string title(STR_MAIN_VIEW_X);
|
||||
@@ -257,8 +257,10 @@ class SetupWidgetsPage: public FormWindow
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
Keyboard::hide();
|
||||
#endif
|
||||
// give it back to its old parent before it gets deleted
|
||||
screen->attach(oldParent);
|
||||
if (oldParent) {
|
||||
// give it back to its old parent before it gets deleted
|
||||
screen->attach(oldParent);
|
||||
}
|
||||
|
||||
FormWindow::deleteLater(detach, trash);
|
||||
}
|
||||
@@ -299,7 +301,7 @@ void ScreenSetupPage::build(FormWindow * window)
|
||||
layoutChoice = new LayoutChoice(window, layoutSlot, GET_VALUE(screen->getFactory()), [=](const LayoutFactory *factory) {
|
||||
delete screen;
|
||||
screen = factory->create(&screenData.layoutData);
|
||||
strncpy(screenData.layoutName, factory->getId(), sizeof(CustomScreenData::layoutName));
|
||||
strncpy(screenData.LayoutId, factory->getId(), sizeof(CustomScreenData::LayoutId));
|
||||
SET_DIRTY();
|
||||
updateLayoutOptions();
|
||||
});
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "opentx.h"
|
||||
#include "lua_api.h"
|
||||
#include "timers.h"
|
||||
#include "model_init.h"
|
||||
|
||||
/*luadoc
|
||||
@function model.getInfo()
|
||||
@@ -664,7 +665,8 @@ Set all inputs to defaults
|
||||
*/
|
||||
static int luaModelDefaultInputs(lua_State *L)
|
||||
{
|
||||
defaultInputs();
|
||||
clearInputs();
|
||||
setDefaultInputs();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* 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"
|
||||
|
||||
void clearInputs()
|
||||
{
|
||||
memset(g_model.expoData, 0, sizeof(g_model.expoData));
|
||||
}
|
||||
|
||||
void setDefaultInputs()
|
||||
{
|
||||
for (int i=0; i<NUM_STICKS; i++) {
|
||||
uint8_t stick_index = channelOrder(i+1);
|
||||
ExpoData *expo = expoAddress(i);
|
||||
expo->srcRaw = MIXSRC_Rud - 1 + stick_index;
|
||||
expo->curve.type = CURVE_REF_EXPO;
|
||||
expo->chn = i;
|
||||
expo->weight = 100;
|
||||
expo->mode = 3; // TODO constant
|
||||
for (int c = 0; c < 3; c++) {
|
||||
g_model.inputNames[i][c] = STR_VSRCRAW[2 + 4 * stick_index + c];
|
||||
}
|
||||
#if LEN_INPUT_NAME > 3
|
||||
g_model.inputNames[i][3] = '\0';
|
||||
#endif
|
||||
}
|
||||
storageDirty(EE_MODEL);
|
||||
}
|
||||
|
||||
void clearMixes()
|
||||
{
|
||||
memset(g_model.mixData, 0, sizeof(g_model.mixData));
|
||||
}
|
||||
|
||||
void setDefaultMixes()
|
||||
{
|
||||
for (int i=0; i<NUM_STICKS; i++) {
|
||||
MixData * mix = mixAddress(i);
|
||||
mix->destCh = i;
|
||||
mix->weight = 100;
|
||||
mix->srcRaw = i+1;
|
||||
}
|
||||
storageDirty(EE_MODEL);
|
||||
}
|
||||
|
||||
void setDefaultModelRegistrationID()
|
||||
{
|
||||
memcpy(g_model.modelRegistrationID, g_eeGeneral.ownerRegistrationID, PXX2_LEN_REGISTRATION_ID);
|
||||
}
|
||||
|
||||
void setDefaultGVars()
|
||||
{
|
||||
#if defined(FLIGHT_MODES) && defined(GVARS)
|
||||
for (int fmIdx = 1; fmIdx < MAX_FLIGHT_MODES; fmIdx++) {
|
||||
for (int gvarIdx = 0; gvarIdx < MAX_GVARS; gvarIdx++) {
|
||||
g_model.flightModeData[fmIdx].gvars[gvarIdx] = GVAR_MAX + 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void setVendorSpecificModelDefaults()
|
||||
{
|
||||
#if defined(FRSKY_RELEASE)
|
||||
g_model.moduleData[INTERNAL_MODULE].type = IS_PXX2_INTERNAL_ENABLED() ? MODULE_TYPE_ISRM_PXX2 : MODULE_TYPE_XJT_PXX1;
|
||||
g_model.moduleData[INTERNAL_MODULE].channelsCount = defaultModuleChannels_M8(INTERNAL_MODULE);
|
||||
#if defined(EEPROM)
|
||||
g_model.header.modelId[INTERNAL_MODULE] = findNextUnusedModelId(id, INTERNAL_MODULE);
|
||||
modelHeaders[id].modelId[INTERNAL_MODULE] = g_model.header.modelId[INTERNAL_MODULE];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// TODO: we should probably have some default trainer mode
|
||||
// per radio, depending on what is supported
|
||||
//
|
||||
#if defined(PCBXLITE)
|
||||
g_model.trainerData.mode = TRAINER_MODE_MASTER_BLUETOOTH;
|
||||
#endif
|
||||
|
||||
#if defined(RADIOMASTER_RTF_RELEASE)
|
||||
// Those settings are for headless radio
|
||||
g_model.trainerData.mode = TRAINER_MODE_SLAVE;
|
||||
g_model.moduleData[INTERNAL_MODULE].type = MODULE_TYPE_MULTIMODULE;
|
||||
g_model.moduleData[INTERNAL_MODULE].setMultiProtocol(MODULE_SUBTYPE_MULTI_FRSKY);
|
||||
g_model.moduleData[INTERNAL_MODULE].subType = MM_RF_FRSKY_SUBTYPE_D8;
|
||||
g_model.moduleData[INTERNAL_MODULE].failsafeMode = FAILSAFE_NOPULSES;
|
||||
#endif
|
||||
}
|
||||
|
||||
void applyDefaultTemplate()
|
||||
{
|
||||
setDefaultInputs();
|
||||
setDefaultMixes();
|
||||
setDefaultGVars();
|
||||
|
||||
setDefaultModelRegistrationID();
|
||||
|
||||
#if defined(COLORLCD)
|
||||
//TODO: not sure yet we need it here
|
||||
loadDefaultLayout();
|
||||
|
||||
// enable switch warnings
|
||||
for (int i = 0; i < NUM_SWITCHES; i++) {
|
||||
g_model.switchWarningState |= (1 << (3*i));
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: what about switch warnings in non-color LCD radios?
|
||||
}
|
||||
|
||||
|
||||
void setModelDefaults(uint8_t id)
|
||||
{
|
||||
memset(&g_model, 0, sizeof(g_model));
|
||||
applyDefaultTemplate();
|
||||
|
||||
setVendorSpecificModelDefaults();
|
||||
|
||||
strAppendUnsigned(strAppend(g_model.header.name, STR_MODEL), id + 1, 2);
|
||||
|
||||
#if defined(LUA) && defined(PCBTARANIS) // Horus uses menuModelWizard() for wizard
|
||||
if (isFileAvailable(WIZARD_PATH "/" WIZARD_NAME)) {
|
||||
f_chdir(WIZARD_PATH);
|
||||
luaExec(WIZARD_NAME);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
+6
-177
@@ -23,7 +23,7 @@
|
||||
|
||||
#if defined(LIBOPENUI)
|
||||
// #include "shutdown_animation.h"
|
||||
// #include "radio_calibration.h"
|
||||
#include "radio_calibration.h"
|
||||
#include "view_main.h"
|
||||
#endif
|
||||
|
||||
@@ -364,178 +364,6 @@ uint16_t evalChkSum()
|
||||
return sum;
|
||||
}
|
||||
|
||||
void clearInputs()
|
||||
{
|
||||
memset(g_model.expoData, 0, sizeof(g_model.expoData)); // clear all expos
|
||||
}
|
||||
|
||||
void defaultInputs()
|
||||
{
|
||||
clearInputs();
|
||||
|
||||
for (int i=0; i<NUM_STICKS; i++) {
|
||||
uint8_t stick_index = channelOrder(i+1);
|
||||
ExpoData *expo = expoAddress(i);
|
||||
expo->srcRaw = MIXSRC_Rud - 1 + stick_index;
|
||||
expo->curve.type = CURVE_REF_EXPO;
|
||||
expo->chn = i;
|
||||
expo->weight = 100;
|
||||
expo->mode = 3; // TODO constant
|
||||
for (int c = 0; c < 3; c++) {
|
||||
g_model.inputNames[i][c] = STR_VSRCRAW[2 + 4 * stick_index + c];
|
||||
}
|
||||
#if LEN_INPUT_NAME > 3
|
||||
g_model.inputNames[i][3] = '\0';
|
||||
#endif
|
||||
}
|
||||
storageDirty(EE_MODEL);
|
||||
}
|
||||
|
||||
void applyDefaultTemplate()
|
||||
{
|
||||
defaultInputs(); // calls storageDirty internally
|
||||
|
||||
for (int i=0; i<NUM_STICKS; i++) {
|
||||
MixData * mix = mixAddress(i);
|
||||
mix->destCh = i;
|
||||
mix->weight = 100;
|
||||
mix->srcRaw = i+1;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(EEPROM)
|
||||
void checkModelIdUnique(uint8_t index, uint8_t module)
|
||||
{
|
||||
if (isModuleXJTD8(module))
|
||||
return;
|
||||
|
||||
uint8_t modelId = g_model.header.modelId[module];
|
||||
uint8_t additionalOnes = 0;
|
||||
char * name = reusableBuffer.moduleSetup.msg;
|
||||
|
||||
memset(reusableBuffer.moduleSetup.msg, 0, sizeof(reusableBuffer.moduleSetup.msg));
|
||||
|
||||
if (modelId != 0) {
|
||||
for (uint8_t i = 0; i < MAX_MODELS; i++) {
|
||||
if (i != index) {
|
||||
if (modelId == modelHeaders[i].modelId[module]) {
|
||||
if ((WARNING_LINE_LEN - 4 - (name - reusableBuffer.moduleSetup.msg)) > (signed)(modelHeaders[i].name[0] ? zlen(modelHeaders[i].name, LEN_MODEL_NAME) : sizeof(TR_MODEL) + 2)) { // you cannot rely exactly on WARNING_LINE_LEN so using WARNING_LINE_LEN-2 (-2 for the ",")
|
||||
if (reusableBuffer.moduleSetup.msg[0] != '\0') {
|
||||
name = strAppend(name, ", ");
|
||||
}
|
||||
if (modelHeaders[i].name[0] == 0) {
|
||||
name = strAppend(name, STR_MODEL);
|
||||
name = strAppendUnsigned(name+strlen(name), i + 1, 2);
|
||||
}
|
||||
else {
|
||||
name += zchar2str(name, modelHeaders[i].name, LEN_MODEL_NAME);
|
||||
}
|
||||
}
|
||||
else {
|
||||
additionalOnes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (additionalOnes) {
|
||||
name = strAppend(name, " (+");
|
||||
name = strAppendUnsigned(name, additionalOnes);
|
||||
strAppend(name, ")");
|
||||
}
|
||||
|
||||
if (reusableBuffer.moduleSetup.msg[0]) {
|
||||
POPUP_WARNING(STR_MODELIDUSED, reusableBuffer.moduleSetup.msg);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t findNextUnusedModelId(uint8_t index, uint8_t module)
|
||||
{
|
||||
uint8_t usedModelIds[(MAX_RXNUM + 7) / 8];
|
||||
memset(usedModelIds, 0, sizeof(usedModelIds));
|
||||
|
||||
for (uint8_t modelIndex = 0; modelIndex < MAX_MODELS; modelIndex++) {
|
||||
if (modelIndex == index)
|
||||
continue;
|
||||
|
||||
uint8_t id = modelHeaders[modelIndex].modelId[module];
|
||||
if (id == 0)
|
||||
continue;
|
||||
|
||||
uint8_t mask = 1u << (id & 7u);
|
||||
usedModelIds[id >> 3u] |= mask;
|
||||
}
|
||||
|
||||
for (uint8_t id = 1; id <= getMaxRxNum(module); id++) {
|
||||
uint8_t mask = 1u << (id & 7u);
|
||||
if (!(usedModelIds[id >> 3u] & mask)) {
|
||||
// found free ID
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
// failed finding something...
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void modelDefault(uint8_t id)
|
||||
{
|
||||
memset(&g_model, 0, sizeof(g_model));
|
||||
|
||||
applyDefaultTemplate();
|
||||
|
||||
memcpy(g_model.modelRegistrationID, g_eeGeneral.ownerRegistrationID, PXX2_LEN_REGISTRATION_ID);
|
||||
|
||||
#if defined(LUA) && defined(PCBTARANIS) // Horus uses menuModelWizard() for wizard
|
||||
if (isFileAvailable(WIZARD_PATH "/" WIZARD_NAME)) {
|
||||
f_chdir(WIZARD_PATH);
|
||||
luaExec(WIZARD_NAME);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FRSKY_RELEASE)
|
||||
g_model.moduleData[INTERNAL_MODULE].type = IS_PXX2_INTERNAL_ENABLED() ? MODULE_TYPE_ISRM_PXX2 : MODULE_TYPE_XJT_PXX1;
|
||||
g_model.moduleData[INTERNAL_MODULE].channelsCount = defaultModuleChannels_M8(INTERNAL_MODULE);
|
||||
#if defined(EEPROM)
|
||||
g_model.header.modelId[INTERNAL_MODULE] = findNextUnusedModelId(id, INTERNAL_MODULE);
|
||||
modelHeaders[id].modelId[INTERNAL_MODULE] = g_model.header.modelId[INTERNAL_MODULE];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(PCBXLITE)
|
||||
g_model.trainerData.mode = TRAINER_MODE_MASTER_BLUETOOTH;
|
||||
#endif
|
||||
|
||||
#if defined(FLIGHT_MODES) && defined(GVARS)
|
||||
for (int fmIdx = 1; fmIdx < MAX_FLIGHT_MODES; fmIdx++) {
|
||||
for (int gvarIdx = 0; gvarIdx < MAX_GVARS; gvarIdx++) {
|
||||
g_model.flightModeData[fmIdx].gvars[gvarIdx] = GVAR_MAX + 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
strAppendUnsigned(strAppend(g_model.header.name, STR_MODEL), id + 1, 2);
|
||||
|
||||
#if defined(COLORLCD)
|
||||
loadDefaultLayout();
|
||||
|
||||
// enable switch warnings
|
||||
for (int i = 0; i < NUM_SWITCHES; i++) {
|
||||
g_model.switchWarningState |= (1 << (3*i));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(RADIOMASTER_RTF_RELEASE)
|
||||
// Those settings are for headless radio
|
||||
g_model.trainerData.mode = TRAINER_MODE_SLAVE;
|
||||
g_model.moduleData[INTERNAL_MODULE].type = MODULE_TYPE_MULTIMODULE;
|
||||
g_model.moduleData[INTERNAL_MODULE].setMultiProtocol(MODULE_SUBTYPE_MULTI_FRSKY);
|
||||
g_model.moduleData[INTERNAL_MODULE].subType = MM_RF_FRSKY_SUBTYPE_D8;
|
||||
g_model.moduleData[INTERNAL_MODULE].failsafeMode = FAILSAFE_NOPULSES;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isInputRecursive(int index)
|
||||
{
|
||||
@@ -1632,8 +1460,7 @@ void opentxStart(const uint8_t startOptions = OPENTX_START_DEFAULT_ARGS)
|
||||
#if defined(GUI)
|
||||
if (calibration_needed) {
|
||||
#if defined(LIBOPENUI)
|
||||
#warning "TODO add a startCalibration function"
|
||||
// startCalibration();
|
||||
startCalibration();
|
||||
#else
|
||||
chainMenu(menuFirstCalib);
|
||||
#endif
|
||||
@@ -1927,8 +1754,10 @@ void moveTrimsToOffsets() // copy state of 3 primary to subtrim
|
||||
void opentxInit()
|
||||
{
|
||||
TRACE("opentxInit");
|
||||
|
||||
#if defined(GUI) && !defined(LIBOPENUI)
|
||||
#if defined(LIBOPENUI)
|
||||
// create ViewMain
|
||||
ViewMain::instance();
|
||||
#elif defined(GUI)
|
||||
// TODO add a function for this (duplicated)
|
||||
menuHandlers[0] = menuMainView;
|
||||
#if MENUS_LOCK != 2/*no menus*/
|
||||
|
||||
@@ -665,12 +665,6 @@ inline void resumeMixerCalculations()
|
||||
|
||||
void setDefaultOwnerId();
|
||||
void generalDefault();
|
||||
void modelDefault(uint8_t id);
|
||||
|
||||
#if defined(EEPROM)
|
||||
void checkModelIdUnique(uint8_t index, uint8_t module);
|
||||
uint8_t findNextUnusedModelId(uint8_t index, uint8_t module);
|
||||
#endif
|
||||
|
||||
uint32_t hash(const void * ptr, uint32_t size);
|
||||
|
||||
@@ -786,12 +780,6 @@ inline void getGVarIncDecRange(int16_t & valMin, int16_t & valMax)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
void clearInputs();
|
||||
void defaultInputs();
|
||||
|
||||
void applyExpos(int16_t * anas, uint8_t mode, uint8_t ovwrIdx=0, int16_t ovwrValue=0);
|
||||
int16_t applyLimits(uint8_t channel, int32_t value);
|
||||
|
||||
|
||||
@@ -323,7 +323,7 @@ void convertModelData_218_to_219(ModelData &model)
|
||||
|
||||
for (int screen=0; screen<MAX_CUSTOM_SCREENS; screen++) {
|
||||
CustomScreenData& screenData = g_model.screenData[screen];
|
||||
if (screenData.layoutName[0] == '\0')
|
||||
if (screenData.LayoutId[0] == '\0')
|
||||
continue;
|
||||
for (int zone=0; zone<MAX_LAYOUT_ZONES; zone++) {
|
||||
Layout::ZonePersistentData * zoneData = &screenData.layoutData.zones[zone];
|
||||
|
||||
@@ -397,7 +397,7 @@ PACK(struct TelemetrySensor_218 {
|
||||
|
||||
#if defined(PCBHORUS)
|
||||
PACK(struct CustomScreenData_v218 {
|
||||
char layoutName[10];
|
||||
char LayoutId[10];
|
||||
Layout::PersistentData layoutData;
|
||||
});
|
||||
#define VIEW_DATA \
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <string.h>
|
||||
#include "opentx.h"
|
||||
#include "timers.h"
|
||||
#include "model_init.h"
|
||||
|
||||
void eeLoadModel(uint8_t index)
|
||||
{
|
||||
@@ -45,7 +46,7 @@ void eeLoadModel(uint8_t index)
|
||||
|
||||
bool alarms = true;
|
||||
if (size < EEPROM_MIN_MODEL_SIZE) { // if not loaded a fair amount
|
||||
modelDefault(index) ;
|
||||
setModelDefaults(index);
|
||||
storageCheck(true);
|
||||
alarms = false;
|
||||
}
|
||||
@@ -131,7 +132,7 @@ void storageEraseAll(bool warn)
|
||||
TRACE("storageEraseAll");
|
||||
|
||||
generalDefault();
|
||||
modelDefault(0);
|
||||
setModelDefault(0);
|
||||
|
||||
if (warn) {
|
||||
ALERT(STR_STORAGE_WARNING, STR_BAD_RADIO_DATA, AU_BAD_RADIODATA);
|
||||
@@ -143,3 +144,78 @@ void storageEraseAll(bool warn)
|
||||
storageDirty(EE_GENERAL|EE_MODEL);
|
||||
storageCheck(true);
|
||||
}
|
||||
|
||||
void checkModelIdUnique(uint8_t index, uint8_t module)
|
||||
{
|
||||
if (isModuleXJTD8(module))
|
||||
return;
|
||||
|
||||
uint8_t modelId = g_model.header.modelId[module];
|
||||
uint8_t additionalOnes = 0;
|
||||
char * name = reusableBuffer.moduleSetup.msg;
|
||||
|
||||
memset(reusableBuffer.moduleSetup.msg, 0, sizeof(reusableBuffer.moduleSetup.msg));
|
||||
|
||||
if (modelId != 0) {
|
||||
for (uint8_t i = 0; i < MAX_MODELS; i++) {
|
||||
if (i != index) {
|
||||
if (modelId == modelHeaders[i].modelId[module]) {
|
||||
if ((WARNING_LINE_LEN - 4 - (name - reusableBuffer.moduleSetup.msg)) > (signed)(modelHeaders[i].name[0] ? zlen(modelHeaders[i].name, LEN_MODEL_NAME) : sizeof(TR_MODEL) + 2)) { // you cannot rely exactly on WARNING_LINE_LEN so using WARNING_LINE_LEN-2 (-2 for the ",")
|
||||
if (reusableBuffer.moduleSetup.msg[0] != '\0') {
|
||||
name = strAppend(name, ", ");
|
||||
}
|
||||
if (modelHeaders[i].name[0] == 0) {
|
||||
name = strAppend(name, STR_MODEL);
|
||||
name = strAppendUnsigned(name+strlen(name), i + 1, 2);
|
||||
}
|
||||
else {
|
||||
name += zchar2str(name, modelHeaders[i].name, LEN_MODEL_NAME);
|
||||
}
|
||||
}
|
||||
else {
|
||||
additionalOnes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (additionalOnes) {
|
||||
name = strAppend(name, " (+");
|
||||
name = strAppendUnsigned(name, additionalOnes);
|
||||
strAppend(name, ")");
|
||||
}
|
||||
|
||||
if (reusableBuffer.moduleSetup.msg[0]) {
|
||||
POPUP_WARNING(STR_MODELIDUSED, reusableBuffer.moduleSetup.msg);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t findNextUnusedModelId(uint8_t index, uint8_t module)
|
||||
{
|
||||
uint8_t usedModelIds[(MAX_RXNUM + 7) / 8];
|
||||
memset(usedModelIds, 0, sizeof(usedModelIds));
|
||||
|
||||
for (uint8_t modelIndex = 0; modelIndex < MAX_MODELS; modelIndex++) {
|
||||
if (modelIndex == index)
|
||||
continue;
|
||||
|
||||
uint8_t id = modelHeaders[modelIndex].modelId[module];
|
||||
if (id == 0)
|
||||
continue;
|
||||
|
||||
uint8_t mask = 1u << (id & 7u);
|
||||
usedModelIds[id >> 3u] |= mask;
|
||||
}
|
||||
|
||||
for (uint8_t id = 1; id <= getMaxRxNum(module); id++) {
|
||||
uint8_t mask = 1u << (id & 7u);
|
||||
if (!(usedModelIds[id >> 3u] & mask)) {
|
||||
// found free ID
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
// failed finding something...
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,9 @@ void storageClearRadioSettings();
|
||||
bool storageReadRadioSettings(bool allowFixes = true);
|
||||
void storageReadCurrentModel();
|
||||
|
||||
void checkModelIdUnique(uint8_t index, uint8_t module);
|
||||
uint8_t findNextUnusedModelId(uint8_t index, uint8_t module);
|
||||
|
||||
#if defined(EEPROM_RLC)
|
||||
#include "eeprom_rlc.h"
|
||||
#else
|
||||
|
||||
@@ -441,14 +441,12 @@ bool ModelsList::load()
|
||||
if (!currentModel) {
|
||||
if (model) {
|
||||
currentModel = model;
|
||||
currentCategory = category;
|
||||
}
|
||||
else {
|
||||
model = new ModelCell(line);
|
||||
category = new ModelsCategory("Models");
|
||||
categories.push_back(category);
|
||||
category->push_back(model);
|
||||
}
|
||||
currentCategory = category;
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#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();
|
||||
@@ -43,9 +44,6 @@ void storageEraseAll(bool warn)
|
||||
static_cast<OpenTxTheme*>(theme)->load();
|
||||
#endif
|
||||
|
||||
generalDefault();
|
||||
modelDefault(1);
|
||||
|
||||
if (warn) {
|
||||
ALERT(STR_STORAGE_WARNING, STR_BAD_RADIO_DATA, AU_BAD_RADIODATA);
|
||||
}
|
||||
@@ -53,7 +51,7 @@ void storageEraseAll(bool warn)
|
||||
RAISE_ALERT(STR_STORAGE_WARNING, STR_STORAGE_FORMAT, NULL, AU_NONE);
|
||||
|
||||
storageFormat();
|
||||
storageDirty(EE_GENERAL|EE_MODEL);
|
||||
storageDirty(EE_GENERAL);
|
||||
storageCheck(true);
|
||||
}
|
||||
|
||||
@@ -68,7 +66,7 @@ void storageCheck(bool immediately)
|
||||
{
|
||||
if (storageDirtyMsk & EE_GENERAL) {
|
||||
TRACE("eeprom write general");
|
||||
storageDirtyMsk -= EE_GENERAL;
|
||||
storageDirtyMsk &= ~EE_GENERAL;
|
||||
const char * error = writeGeneralSettings();
|
||||
if (error) {
|
||||
TRACE("writeGeneralSettings error=%s", error);
|
||||
@@ -77,7 +75,7 @@ void storageCheck(bool immediately)
|
||||
|
||||
if (storageDirtyMsk & EE_MODEL) {
|
||||
TRACE("eeprom write model");
|
||||
storageDirtyMsk -= EE_MODEL;
|
||||
storageDirtyMsk &= ~EE_MODEL;
|
||||
const char * error = writeModel();
|
||||
if (error) {
|
||||
TRACE("writeModel error=%s", error);
|
||||
@@ -95,7 +93,7 @@ const char * createModel()
|
||||
|
||||
int index = findNextFileIndex(filename, LEN_MODEL_FILENAME, MODELS_PATH);
|
||||
if (index > 0) {
|
||||
modelDefault(index);
|
||||
setModelDefaults(index);
|
||||
memcpy(g_eeGeneral.currModelFilename, filename, sizeof(g_eeGeneral.currModelFilename));
|
||||
storageDirty(EE_GENERAL);
|
||||
storageDirty(EE_MODEL);
|
||||
@@ -109,18 +107,20 @@ const char * createModel()
|
||||
const char * loadModel(const char * filename, bool alarms)
|
||||
{
|
||||
uint8_t version;
|
||||
|
||||
preModelLoad();
|
||||
|
||||
const char * error = readModel(filename, (uint8_t *)&g_model, sizeof(g_model), &version);
|
||||
if (error) {
|
||||
TRACE("loadModel error=%s", error);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
modelDefault(0) ;
|
||||
|
||||
// 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);
|
||||
alarms = false;
|
||||
postModelLoad(false);
|
||||
return error;
|
||||
}
|
||||
|
||||
#if defined(STORAGE_CONVERSIONS)
|
||||
@@ -130,8 +130,7 @@ const char * loadModel(const char * filename, bool alarms)
|
||||
#endif
|
||||
|
||||
postModelLoad(alarms);
|
||||
|
||||
return error;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void storageReadAll()
|
||||
@@ -150,8 +149,7 @@ void storageReadAll()
|
||||
}
|
||||
|
||||
if (loadModel(g_eeGeneral.currModelFilename, false) != nullptr) {
|
||||
sdCheckAndCreateDirectory(MODELS_PATH);
|
||||
createModel();
|
||||
TRACE("No current model or SD card error");
|
||||
}
|
||||
|
||||
// Wipe models list in case
|
||||
|
||||
@@ -60,6 +60,8 @@ const char * writeModel()
|
||||
{
|
||||
char path[256];
|
||||
getModelPath(path, g_eeGeneral.currModelFilename);
|
||||
|
||||
sdCheckAndCreateDirectory(MODELS_PATH);
|
||||
return writeFile(path, (uint8_t *)&g_model, sizeof(g_model));
|
||||
}
|
||||
|
||||
|
||||
@@ -697,7 +697,7 @@ static const struct YamlNode struct_Layout__PersistentData[] = {
|
||||
};
|
||||
static const struct YamlNode struct_CustomScreenData[] = {
|
||||
YAML_IDX,
|
||||
YAML_STRING("layoutName", 10),
|
||||
YAML_STRING("LayoutId", 10),
|
||||
YAML_STRUCT("layoutData", 6720, struct_Layout__PersistentData, NULL),
|
||||
YAML_END
|
||||
};
|
||||
|
||||
@@ -698,7 +698,7 @@ static const struct YamlNode struct_Layout__PersistentData[] = {
|
||||
};
|
||||
static const struct YamlNode struct_CustomScreenData[] = {
|
||||
YAML_IDX,
|
||||
YAML_STRING("layoutName", 10),
|
||||
YAML_STRING("LayoutId", 10),
|
||||
YAML_STRUCT("layoutData", 6720, struct_Layout__PersistentData, NULL),
|
||||
YAML_END
|
||||
};
|
||||
|
||||
+3
-4
@@ -293,6 +293,9 @@ void tasksStart()
|
||||
{
|
||||
RTOS_INIT();
|
||||
|
||||
RTOS_CREATE_MUTEX(audioMutex);
|
||||
RTOS_CREATE_MUTEX(mixerMutex);
|
||||
|
||||
#if defined(CLI)
|
||||
cliStart();
|
||||
#endif
|
||||
@@ -303,9 +306,5 @@ void tasksStart()
|
||||
#if !defined(SIMU)
|
||||
RTOS_CREATE_TASK(audioTaskId, audioTask, "audio", audioStack, AUDIO_STACK_SIZE, AUDIO_TASK_PRIO);
|
||||
#endif
|
||||
|
||||
RTOS_CREATE_MUTEX(audioMutex);
|
||||
RTOS_CREATE_MUTEX(mixerMutex);
|
||||
|
||||
RTOS_START();
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ extern RTOS_TASK_HANDLE audioTaskId;
|
||||
extern RTOS_DEFINE_STACK(audioStack, AUDIO_STACK_SIZE);
|
||||
|
||||
extern RTOS_MUTEX_HANDLE mixerMutex;
|
||||
extern RTOS_FLAG_HANDLE openTxInitCompleteFlag;
|
||||
|
||||
void stackPaint();
|
||||
void tasksStart();
|
||||
|
||||
@@ -291,7 +291,7 @@ TEST(Conversions, ConversionX10From22)
|
||||
EXPECT_EQ(9, g_model.telemetrySensors[0].frskyInstance.physID);
|
||||
EXPECT_EQ((NUM_POTS + NUM_SLIDERS + 3), g_model.thrTraceSrc); // CH3
|
||||
|
||||
EXPECT_STREQ("Layout2P1", g_model.screenData[0].layoutName);
|
||||
EXPECT_STREQ("Layout2P1", g_model.screenData[0].LayoutId);
|
||||
EXPECT_STREQ("ModelBmp", g_model.screenData[0].layoutData.zones[0].widgetName);
|
||||
EXPECT_STREQ("Value", g_model.topbarData.zones[0].widgetName);
|
||||
EXPECT_EQ(MIXSRC_FIRST_TELEM, g_model.topbarData.zones[0].widgetData.options[0].value.unsignedValue);
|
||||
@@ -358,7 +358,7 @@ TEST(Conversions, ConversionX12SFrom22)
|
||||
EXPECT_EQ(9, g_model.telemetrySensors[0].frskyInstance.physID);
|
||||
EXPECT_EQ((NUM_POTS + NUM_SLIDERS + 3), g_model.thrTraceSrc); // CH3
|
||||
|
||||
EXPECT_STREQ("Layout2P1", g_model.screenData[0].layoutName);
|
||||
EXPECT_STREQ("Layout2P1", g_model.screenData[0].LayoutId);
|
||||
EXPECT_STREQ("ModelBmp", g_model.screenData[0].layoutData.zones[0].widgetName);
|
||||
EXPECT_STREQ("Value", g_model.topbarData.zones[0].widgetName);
|
||||
EXPECT_EQ(MIXSRC_FIRST_TELEM, g_model.topbarData.zones[0].widgetData.options[0].unsignedValue);
|
||||
|
||||
@@ -104,7 +104,7 @@ class OpenTxTest : public testing::Test
|
||||
SYSTEM_RESET();
|
||||
MODEL_RESET();
|
||||
MIXER_RESET();
|
||||
modelDefault(0);
|
||||
setModelDefaults(0);
|
||||
RADIO_RESET();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -466,7 +466,7 @@ TEST(Curves, LinearIntpol)
|
||||
SYSTEM_RESET();
|
||||
MODEL_RESET();
|
||||
MIXER_RESET();
|
||||
modelDefault(0);
|
||||
setModelDefaults(0);
|
||||
for (int8_t i=-2; i<=2; i++) {
|
||||
g_model.points[2+i] = 50*i;
|
||||
}
|
||||
@@ -672,7 +672,7 @@ TEST_F(TrimsTest, throttleTrimEle) {
|
||||
SYSTEM_RESET();
|
||||
MODEL_RESET();
|
||||
MIXER_RESET();
|
||||
modelDefault(0);
|
||||
setModelDefaults(0);
|
||||
g_eeGeneral.templateSetup = 17;
|
||||
applyDefaultTemplate();
|
||||
g_model.thrTrim = 1;
|
||||
@@ -685,7 +685,7 @@ TEST_F(TrimsTest, throttleTrimEle) {
|
||||
SYSTEM_RESET();
|
||||
MODEL_RESET();
|
||||
MIXER_RESET();
|
||||
modelDefault(0);
|
||||
setModelDefaults(0);
|
||||
g_eeGeneral.templateSetup = 0;
|
||||
applyDefaultTemplate();
|
||||
}
|
||||
@@ -696,7 +696,7 @@ TEST(Heli, BasicTest)
|
||||
SYSTEM_RESET();
|
||||
MODEL_RESET();
|
||||
MIXER_RESET();
|
||||
modelDefault(0);
|
||||
setModelDefaults(0);
|
||||
g_model.swashR.collectiveSource = MIXSRC_Thr;
|
||||
g_model.swashR.elevatorSource = MIXSRC_Ele;
|
||||
g_model.swashR.aileronSource = MIXSRC_Ail;
|
||||
@@ -728,7 +728,7 @@ TEST(Heli, Mode2Test)
|
||||
SYSTEM_RESET();
|
||||
MODEL_RESET();
|
||||
MIXER_RESET();
|
||||
modelDefault(0);
|
||||
setModelDefaults(0);
|
||||
g_eeGeneral.templateSetup = 2;
|
||||
applyDefaultTemplate();
|
||||
g_model.swashR.collectiveSource = MIXSRC_Thr;
|
||||
@@ -764,7 +764,7 @@ TEST(Trainer, UnpluggedTest)
|
||||
SYSTEM_RESET();
|
||||
MODEL_RESET();
|
||||
MIXER_RESET();
|
||||
modelDefault(0);
|
||||
setModelDefaults(0);
|
||||
g_model.mixData[0].destCh = 0;
|
||||
g_model.mixData[0].mltpx = MLTPX_ADD;
|
||||
g_model.mixData[0].srcRaw = MIXSRC_FIRST_TRAINER;
|
||||
@@ -781,7 +781,7 @@ TEST_F(MixerTest, flightModeTransition)
|
||||
SYSTEM_RESET();
|
||||
MODEL_RESET();
|
||||
MIXER_RESET();
|
||||
modelDefault(0);
|
||||
setModelDefaults(0);
|
||||
g_model.flightModeData[1].swtch = TR(SWSRC_ID2, SWSRC_SA2);
|
||||
g_model.flightModeData[0].fadeIn = 100;
|
||||
g_model.flightModeData[0].fadeOut = 100;
|
||||
@@ -807,7 +807,7 @@ TEST_F(MixerTest, flightModeOverflow)
|
||||
SYSTEM_RESET();
|
||||
MODEL_RESET();
|
||||
MIXER_RESET();
|
||||
modelDefault(0);
|
||||
setModelDefaults(0);
|
||||
g_model.flightModeData[1].swtch = TR(SWSRC_ID2, SWSRC_SA2);
|
||||
g_model.flightModeData[0].fadeIn = 100;
|
||||
g_model.flightModeData[0].fadeOut = 100;
|
||||
|
||||
@@ -77,7 +77,7 @@ TEST(getSwitch, nullSW)
|
||||
TEST(getSwitch, inputWithTrim)
|
||||
{
|
||||
MODEL_RESET();
|
||||
modelDefault(0);
|
||||
setModelDefaults(0);
|
||||
MIXER_RESET();
|
||||
|
||||
// g_model.logicalSw[0] = { LS_FUNC_VPOS, MIXSRC_FIRST_INPUT, 0, 0 };
|
||||
@@ -99,7 +99,7 @@ TEST(evalLogicalSwitches, playFile)
|
||||
{
|
||||
SYSTEM_RESET();
|
||||
MODEL_RESET();
|
||||
modelDefault(0);
|
||||
setModelDefaults(0);
|
||||
MIXER_RESET();
|
||||
|
||||
extern BitField<(MAX_LOGICAL_SWITCHES * 2/*on, off*/)> sdAvailableLogicalSwitchAudioFiles;
|
||||
|
||||
Reference in New Issue
Block a user