diff --git a/companion/src/firmwares/edgetx/yaml_generalsettings.cpp b/companion/src/firmwares/edgetx/yaml_generalsettings.cpp index 5646ed5aa..14e592067 100644 --- a/companion/src/firmwares/edgetx/yaml_generalsettings.cpp +++ b/companion/src/firmwares/edgetx/yaml_generalsettings.cpp @@ -148,6 +148,8 @@ Node convert::encode(const GeneralSettings& rhs) auto fw = getCurrentFirmware(); + bool hasColorLcd = Boards::getCapability(fw->getBoard(), Board::HasColorLcd); + node["semver"] = VERSION; std::string board = fw->getFlavour().toStdString(); @@ -281,6 +283,9 @@ Node convert::encode(const GeneralSettings& rhs) // OneBit sampling (X9D only?) node["uartSampleMode"] = rhs.uartSampleMode; + if (hasColorLcd) + node["selectedTheme"] = rhs.selectedTheme; + return node; } @@ -496,6 +501,8 @@ bool convert::decode(const Node& node, GeneralSettings& rhs) if (needsConversion) rhs.init(); + node["selectedTheme"] >> rhs.selectedTheme; + return true; } } // namespace YAML diff --git a/companion/src/firmwares/generalsettings.h b/companion/src/firmwares/generalsettings.h index b61138267..db873182d 100644 --- a/companion/src/firmwares/generalsettings.h +++ b/companion/src/firmwares/generalsettings.h @@ -101,6 +101,7 @@ constexpr int BLUETOOTH_NAME_LEN {10}; constexpr int TTS_LANGUAGE_LEN {2}; constexpr int HARDWARE_NAME_LEN {3}; constexpr int REGISTRATION_ID_LEN {8}; +constexpr int SELECTED_THEME_NAME_LEN {26}; class GeneralSettings { Q_DECLARE_TR_FUNCTIONS(GeneralSettings) @@ -283,6 +284,8 @@ class GeneralSettings { int pwrOnSpeed; int pwrOffSpeed; + char selectedTheme[SELECTED_THEME_NAME_LEN + 1]; + bool switchPositionAllowedTaranis(int index) const; bool switchSourceAllowedTaranis(int index) const; bool isPotAvailable(int index) const; diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h index f147326a9..85206545b 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -934,4 +934,6 @@ enum ModelOverridableEnable { OVERRIDE_ON }; +#define SELECTED_THEME_NAME_LEN 26 + #endif // _DATACONSTANTS_H_ diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index cd773470a..f94a917ba 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -139,14 +139,14 @@ static inline void check_struct() CHKSIZE(ModelData, 6661); #elif defined(PCBHORUS) #if defined(PCBX10) - CHKSIZE(RadioData, 924); + CHKSIZE(RadioData, 950); CHKSIZE(ModelData, 15431); #else - CHKSIZE(RadioData, 906); + CHKSIZE(RadioData, 932); CHKSIZE(ModelData, 15429); #endif #elif defined(PCBNV14) - CHKSIZE(RadioData, 852); + CHKSIZE(RadioData, 878); CHKSIZE(ModelData, 15245); #endif diff --git a/radio/src/datastructs_private.h b/radio/src/datastructs_private.h index f6cd6a276..d1a71726e 100644 --- a/radio/src/datastructs_private.h +++ b/radio/src/datastructs_private.h @@ -948,6 +948,10 @@ PACK(struct RadioData { NOBACKUP(int8_t imuMax); NOBACKUP(int8_t imuOffset); #endif + +#if defined(COLORLCD) + NOBACKUP(char selectedTheme[SELECTED_THEME_NAME_LEN]); +#endif }); #undef SWITCHES_WARNING_DATA diff --git a/radio/src/gui/colorlcd/radio_theme.cpp b/radio/src/gui/colorlcd/radio_theme.cpp index bed9717b7..b6eab0fea 100644 --- a/radio/src/gui/colorlcd/radio_theme.cpp +++ b/radio/src/gui/colorlcd/radio_theme.cpp @@ -143,7 +143,7 @@ class ThemeDetailsDialog: public Dialog auto line = form->newLine(&grid); new StaticText(line, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1); - auto te = new TextEdit(line, rect_t{}, this->theme.getName(), NAME_LENGTH); + auto te = new TextEdit(line, rect_t{}, this->theme.getName(), SELECTED_THEME_NAME_LEN); lv_obj_set_grid_cell(te->getLvObj(), LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1); line = form->newLine(&grid); @@ -540,7 +540,7 @@ void ThemeSetupPage::displayThemeMenu(Window *window, ThemePersistance *tp) *theme = editedTheme; theme->serialize(); - + // if the theme info currently displayed // were changed, update the UI if (themeIdx == currentTheme) { @@ -552,6 +552,8 @@ void ThemeSetupPage::displayThemeMenu(Window *window, ThemePersistance *tp) // if the active theme changed, re-apply it if (themeIdx == tp->getThemeIndex()) { + // Update saved them name in case it was changed. + tp->setDefaultTheme(themeIdx); theme->applyTheme(); TabsGroup::refreshTheme(); } @@ -564,8 +566,8 @@ void ThemeSetupPage::displayThemeMenu(Window *window, ThemePersistance *tp) new ThemeDetailsDialog(window, newTheme, [=](ThemeFile theme) { if (strlen(theme.getName()) != 0) { - char name[NAME_LENGTH + 20]; - strncpy(name, theme.getName(), NAME_LENGTH + 19); + char name[SELECTED_THEME_NAME_LEN + 20]; + strncpy(name, theme.getName(), SELECTED_THEME_NAME_LEN + 19); removeAllWhiteSpace(name); // use the selected themes color list to make the new theme diff --git a/radio/src/gui/colorlcd/theme_manager.cpp b/radio/src/gui/colorlcd/theme_manager.cpp index 2aaa2f87c..f07bed4a9 100644 --- a/radio/src/gui/colorlcd/theme_manager.cpp +++ b/radio/src/gui/colorlcd/theme_manager.cpp @@ -21,27 +21,125 @@ #include "theme_manager.h" #include "view_main.h" +#include "../../storage/yaml/yaml_tree_walker.h" +#include "../../storage/yaml/yaml_bits.h" +#include "../../storage/sdcard_common.h" + +#define SET_DIRTY() storageDirty(EE_GENERAL) + #define MAX_FILES 9 + +constexpr const char *RGBSTRING = "RGB("; + ThemePersistance themePersistance; +// prototype for SD card function to read a YAML file +// TODO: should this be in sdcard header file? +enum class ChecksumResult; +extern const char* readYamlFile(const char* fullpath, const YamlParserCalls* calls, void* parser_ctx, ChecksumResult* checksum_result); + +static uint32_t r_color(const YamlNode* node, const char* val, uint8_t val_len) +{ + if ((strncmp(val, RGBSTRING, strlen(RGBSTRING)) == 0) && (val[val_len - 1] == ')')) { + int r, g, b; + int numTokens = sscanf(val, "RGB(%d,%d,%d)", &r, &g, &b); + + if (numTokens == 3) + return RGB(r, g, b); + + } else if (val_len > 2 && val[0] == '0' && (val[1] == 'x' || val[1] == 'X')) { + val += 2; val_len -= 2; + + auto rgb24 = yaml_hex2uint(val, val_len); + return RGB((rgb24 & 0xFF0000) >> 16, (rgb24 & 0xFF00) >> 8, rgb24 & 0xFF); + } + + TRACE("Theme: Invalid color value"); + return 0; +} + +static bool w_color(const YamlNode* node, uint32_t val, yaml_writer_func wf, + void* opaque) +{ + uint32_t color = (uint32_t)GET_RED(val) << 16 | + (uint32_t)GET_GREEN(val) << 8 | + (uint32_t)GET_BLUE(val); + + if (!wf(opaque, "0x", 2)) return false; + return wf(opaque, yaml_rgb2hex(color), 3 * 2); +} + +PACK(struct YAMLThemeSummary +{ + char name[SELECTED_THEME_NAME_LEN + 1]; + char author[AUTHOR_LENGTH + 1]; + char info[INFO_LENGTH+1]; +}); + +PACK(struct YAMLThemeColors +{ + uint32_t colors[COLOR_COUNT - 2]; // We don't use DEFAULT or CUSTOM +}); + +PACK(struct YAMLTheme +{ + struct YAMLThemeSummary summary; + struct YAMLThemeColors colors; + + YAMLTheme() { + memset(this, 0, sizeof(YAMLTheme)); + } +}); + +static const struct YamlNode struct_YAMLThemeSummary[] = { + YAML_STRING("name", (SELECTED_THEME_NAME_LEN + 1)), + YAML_STRING("author", (AUTHOR_LENGTH + 1)), + YAML_STRING("info", (INFO_LENGTH + 1)), + YAML_END +}; + +static const struct YamlNode struct_YAMLThemeColors[] = { + YAML_UNSIGNED_CUST( "PRIMARY1", 32, r_color, w_color ), + YAML_UNSIGNED_CUST( "PRIMARY2", 32, r_color, w_color ), + YAML_UNSIGNED_CUST( "PRIMARY3", 32, r_color, w_color ), + YAML_UNSIGNED_CUST( "SECONDARY1", 32, r_color, w_color ), + YAML_UNSIGNED_CUST( "SECONDARY2", 32, r_color, w_color ), + YAML_UNSIGNED_CUST( "SECONDARY3", 32, r_color, w_color ), + YAML_UNSIGNED_CUST( "FOCUS", 32, r_color, w_color ), + YAML_UNSIGNED_CUST( "EDIT", 32, r_color, w_color ), + YAML_UNSIGNED_CUST( "ACTIVE", 32, r_color, w_color ), + YAML_UNSIGNED_CUST( "WARNING", 32, r_color, w_color ), + YAML_UNSIGNED_CUST( "DISABLED", 32, r_color, w_color ), + YAML_END +}; + +// This hack is required to ensure the YAML file written is backward compatible with +// the old parser. Otherwise older versions of EdgeTX will not load the theme files. +// TODO: Remove this sometime in the future +static const struct YamlNode w_struct_YAMLTheme[] = { + YAML_STRUCT("---\r\nsummary", (SELECTED_THEME_NAME_LEN + AUTHOR_LENGTH + INFO_LENGTH + 3) * 8, struct_YAMLThemeSummary, NULL), + YAML_STRUCT("colors", (COLOR_COUNT - 2) * 32, struct_YAMLThemeColors, NULL), + YAML_END +}; +static const struct YamlNode r_struct_YAMLTheme[] = { + YAML_STRUCT("summary", (SELECTED_THEME_NAME_LEN + AUTHOR_LENGTH + INFO_LENGTH + 3) * 8, struct_YAMLThemeSummary, NULL), + YAML_STRUCT("colors", (COLOR_COUNT - 2) * 32, struct_YAMLThemeColors, NULL), + YAML_END +}; + static const char *colorNames[COLOR_COUNT] = { "DEFAULT", "PRIMARY1", "PRIMARY2", "PRIMARY3", "SECONDARY1", "SECONDARY2", "SECONDARY3", "FOCUS", "EDIT", "ACTIVE", "WARNING", "DISABLED", "CUSTOM", }; -#define HEX_COLOR_VALUE_LEN 8 -constexpr const char *RGBSTRING = "RGB("; -constexpr const char* SELECTED_THEME_FILE = THEMES_PATH "/selectedtheme.txt"; - -ThemeFile::ThemeFile(std::string themePath) : +ThemeFile::ThemeFile(std::string themePath, bool loadYAML) : path(themePath) { - if (path.size()) { + if (loadYAML && path.size()) { deSerialize(); } - FIL file; auto found = path.rfind('/'); if (found != std::string::npos) { int n = 0; @@ -64,7 +162,7 @@ ThemeFile& ThemeFile::operator= (const ThemeFile& theme) return *this; path = theme.path; - strAppend(name, theme.name, NAME_LENGTH); + strAppend(name, theme.name, SELECTED_THEME_NAME_LEN); strAppend(author, theme.author, AUTHOR_LENGTH); strAppend(info, theme.info, INFO_LENGTH); colorList.assign(theme.colorList.begin(), theme.colorList.end()); @@ -80,195 +178,40 @@ std::vector ThemeFile::getThemeImageFileNames() void ThemeFile::serialize() { - FIL file; - FRESULT result = f_open(&file, path.c_str(), FA_CREATE_ALWAYS | FA_WRITE); - if (result == FR_OK) { - f_printf(&file, "---\n"); - f_printf(&file, "summary:\n"); - f_printf(&file, " name: %s\n", name); - f_printf(&file, " author: %s\n", author); - f_printf(&file, " info: %s\n", info); - f_printf(&file, "\n"); - f_printf(&file, "colors:\n"); + struct YAMLTheme yt; + struct YamlNode themeRootNode = YAML_ROOT(w_struct_YAMLTheme); - for (auto colorEntry : colorList) { - auto r = GET_RED(colorEntry.colorValue); - auto g = GET_GREEN(colorEntry.colorValue); - auto b = GET_BLUE(colorEntry.colorValue); + strAppend(yt.summary.name, name, SELECTED_THEME_NAME_LEN); + strAppend(yt.summary.author, author, AUTHOR_LENGTH); + strAppend(yt.summary.info, info, INFO_LENGTH); + for (auto colorEntry : colorList) { + yt.colors.colors[colorEntry.colorNumber-1] = colorEntry.colorValue; + } - std::string colorName(colorNames[colorEntry.colorNumber]); - colorName += ":"; - - f_printf(&file, " %-11s 0x%02X%02X%02X\n", colorName.c_str(), r,g,b); - } - f_close(&file); + auto err = writeFileYaml(path.c_str(), &themeRootNode, (uint8_t*)&yt, 0); + if (err != nullptr) { + ALERT(STR_WARNING, err, AU_WARNING1); } } void ThemeFile::deSerialize() { - char line[256 + 1]; - ScanState scanState = none; + struct YAMLTheme yt; + struct YamlNode themeRootNode = YAML_ROOT(r_struct_YAMLTheme); - FIL file; - FRESULT result = f_open(&file, path.c_str(), FA_OPEN_EXISTING | FA_READ); - if (result != FR_OK) return; + YamlTreeWalker tree; + tree.reset(&themeRootNode, (uint8_t*)&yt); + auto err = readYamlFile(path.c_str(), YamlTreeWalker::get_parser_calls(), &tree, nullptr); - int lineNo = 1; - while (readNextLine(file, line, 256)) { - int len = strlen(line); - if (len == 0) continue; - - if (lineNo == 1 && len != 3 && strcmp(line, "---") != 0) { - TRACE("invalid yml file at line %d", lineNo); - return; - } else if (lineNo != 1) { - if (line[0] != ' ' && line[0] != '\t') { - char *pline = trim(line); - if (line[strlen(line) - 1] != ':' && pline[0] != '#') { - TRACE("invalid yml file at line %d", lineNo); - return; - } - - if (strcmp(pline, "colors:") == 0) { - scanState = colors; - continue; - } else if (strcmp(pline, "summary:") == 0) { - scanState = summary; - continue; - } - } - - const char *ptr = strchr(line, ':'); - if (!ptr) continue; - - char lvalue[64]; - char rvalue[64]; - char *plvalue; - char *prvalue; - - strAppend(lvalue, line, min((int)(ptr - line), 63)); - strAppend(rvalue, ptr + 1, 63); - plvalue = trim(lvalue); - prvalue = trim(rvalue); - - switch (scanState) { - case colors: { - int colorIndex = findColorIndex(plvalue); - if (colorIndex >= 0) { - uint32_t color; - if (convertRGB(prvalue, color)) - colorList.emplace_back(ColorEntry{(LcdColorIndex)colorIndex, color}); - else - TRACE("Theme: Could not convert color value"); - } - } break; - - case summary: { - if (strcmp(plvalue, "name") == 0) { - strAppend(name, prvalue, NAME_LENGTH); - } else if (strcmp(plvalue, "author") == 0) { - strAppend(author, prvalue, AUTHOR_LENGTH); - } else if (strcmp(plvalue, "info") == 0) { - strAppend(info, prvalue, INFO_LENGTH); - } - } break; - - default: - break; - } + if (err == nullptr) { + strAppend(name, yt.summary.name, SELECTED_THEME_NAME_LEN); + strAppend(author, yt.summary.author, AUTHOR_LENGTH); + strAppend(info, yt.summary.info, INFO_LENGTH); + for (int i = 0; i < COLOR_COUNT - 2; i += 1) { + colorList.emplace_back(ColorEntry{(LcdColorIndex)(i+1), yt.colors.colors[i]}); } - - lineNo++; - } - - f_close(&file); -} - -bool ThemeFile::convertRGB(char *pColorRGB, uint32_t &color) -{ - if (strlen(pColorRGB) < strlen(RGBSTRING)) return false; - - if (strncmp(pColorRGB, RGBSTRING, strlen(RGBSTRING)) == 0) { - if (pColorRGB[strlen(pColorRGB) - 1] != ')') return false; - - pColorRGB[strlen(pColorRGB) - 1] = '\0'; - pColorRGB += strlen(RGBSTRING); - if (strlen(pColorRGB)) { - char *token = nullptr; - int numTokens = 0; - uint32_t tokens[3]; - - token = strtok(pColorRGB, ","); - while (token != nullptr) { - if (numTokens < 3) { - tokens[numTokens] = strtol(token, nullptr, 0); - numTokens++; - } else - break; - - token = strtok(nullptr, ","); - } - - if (numTokens != 3) return false; - - color = RGB(tokens[0], tokens[1], tokens[2]); - return true; - } - } else if (pColorRGB[0] == '0' && (pColorRGB[1] == 'x' || pColorRGB[1] == 'X')) { - if (strlen(pColorRGB) != HEX_COLOR_VALUE_LEN) return false; - pColorRGB += 2; - uint32_t tokens[3]; - char hexVal[3]; - for (int i = 0; i < 3; i++) { - strncpy(hexVal, pColorRGB, 2); - hexVal[2] = '\0'; - tokens[i] = strtol(hexVal, nullptr, 16); - pColorRGB += 2; - } - - color = RGB(tokens[0], tokens[1], tokens[2]); - return true; - } - - TRACE("Theme: Invalid color value"); - return false; -} - -LcdColorIndex ThemeFile::findColorIndex(const char *name) -{ - int i; - for (i = 0; i < COLOR_COUNT; i++) { - if (strcmp(name, colorNames[i]) == 0) break; - } - - if (i >= COLOR_COUNT) return DEFAULT_COLOR_INDEX; - - return (LcdColorIndex)i; -} - -bool ThemeFile::readNextLine(FIL &file, char *line, int maxlen) -{ - if (f_gets(line, maxlen, &file) != NULL) { - int curlen = strlen(line) - 1; - if (line[curlen] == '\n') { // remove unwanted chars if file was edited using windows - if (curlen > 0 && line[curlen - 1] == '\r') { - line[curlen - 1] = 0; - } else { - line[curlen] = 0; - } - } - - return true; - } - - return false; -} - -void ThemeFile::setColorByIndex(int index, uint32_t color) -{ - if (index >= 0 && index < (int) colorList.size()) { - colorList[index].colorValue = color; + } else { + ALERT(STR_WARNING, err, AU_WARNING1); } } @@ -393,37 +336,66 @@ void ThemePersistance::loadDefaultTheme() { refresh(); - FIL file; - FRESULT status = f_open(&file, SELECTED_THEME_FILE, FA_READ); - if (status != FR_OK) return; + int index = 0; + bool found = false; - char line[256]; - unsigned int len; + // Load theme from 'selectedtheme.txt' file, if not set in radio settings + // TODO: remove this sometime in the future + if (g_eeGeneral.selectedTheme[0] == 0) { + constexpr const char* SELECTED_THEME_FILE = THEMES_PATH "/selectedtheme.txt"; - status = f_read(&file, line, 256, &len); - if (status == FR_OK) { + FIL file; + FRESULT status = f_open(&file, SELECTED_THEME_FILE, FA_READ); - line[len] = '\0'; + if (status == FR_OK) { + char line[256]; + unsigned int len; - int index = 0; - bool found = false; - for (auto theme : themes) { - if (theme->getPath() == std::string(line)) { - found = true; - break; + status = f_read(&file, line, 256, &len); + if (status == FR_OK) { + line[len] = '\0'; + + for (auto theme : themes) { + if (theme->getPath() == std::string(line)) { + found = true; + break; + } + index++; + } + + // Force default if no match for last selected theme + if (!found) + index = 0; } - index++; + + f_close(&file); + + // Delete old file + f_unlink(SELECTED_THEME_FILE); } - // Force default if no match for last selected theme - if (!found) - index = 0; + // Save selected theme (sets to default if nothing found) + setDefaultTheme(index); - applyTheme(index); - setThemeIndex(index); + // Reset values (used below); + index = 0; + found = false; } - f_close(&file); + for (auto theme : themes) { + if (strncmp(theme->getName(), g_eeGeneral.selectedTheme, SELECTED_THEME_NAME_LEN) == 0) { + found = true; + break; + } + index++; + } + + // Force default if no match for last selected theme + if (!found) + index = 0; + + applyTheme(index); + setThemeIndex(index); } char ** ThemePersistance::getColorNames() @@ -472,23 +444,17 @@ bool ThemePersistance::createNewTheme(std::string name, ThemeFile &theme) void ThemePersistance::setDefaultTheme(int index) { - FIL file; if (index >= 0 && index < (int) themes.size()) { - auto theme = themes[index]; - FRESULT status = f_open(&file, SELECTED_THEME_FILE, FA_CREATE_ALWAYS | FA_WRITE); - if (status != FR_OK) return; - + strAppend(g_eeGeneral.selectedTheme, themes[index]->getName(), SELECTED_THEME_NAME_LEN); + SET_DIRTY(); currentTheme = index; - if (index > 0) - f_printf(&file, theme->getPath().c_str()); - f_close(&file); } } class DefaultEdgeTxTheme : public ThemeFile { public: - DefaultEdgeTxTheme() : ThemeFile(THEMES_PATH"/EdgeTX/") + DefaultEdgeTxTheme() : ThemeFile(THEMES_PATH"/EdgeTX/", false) { setName("EdgeTX Default"); setAuthor("EdgeTX Team"); @@ -514,4 +480,3 @@ void ThemePersistance::insertDefaultTheme() auto themeFile = new DefaultEdgeTxTheme(); themes.insert(themes.begin(), themeFile); } - diff --git a/radio/src/gui/colorlcd/theme_manager.h b/radio/src/gui/colorlcd/theme_manager.h index fe680a74f..c81e48fb5 100644 --- a/radio/src/gui/colorlcd/theme_manager.h +++ b/radio/src/gui/colorlcd/theme_manager.h @@ -29,11 +29,14 @@ #include "sdcard.h" #include "str_functions.h" +#define COLOR_COUNT 13 + +#define AUTHOR_LENGTH 50 +#define INFO_LENGTH 255 + class ThemePersistance; extern ThemePersistance themePersistance; -#define COLOR_COUNT 13 - struct ColorEntry { LcdColorIndex colorNumber; @@ -42,10 +45,6 @@ struct ColorEntry bool operator== (const ColorEntry &a) { return this->colorNumber == a.colorNumber; } }; - -#define AUTHOR_LENGTH 50 -#define INFO_LENGTH 255 -#define NAME_LENGTH 26 class ThemeFile { public: @@ -55,16 +54,8 @@ class ThemeFile info[0] = '\0'; } - ThemeFile(std::string themePath); - ThemeFile(const ThemeFile &theme) : - colorList(theme.colorList), - _imageFileNames(theme._imageFileNames) - { - path = theme.path; - strAppend(name, theme.name, NAME_LENGTH); - strAppend(author, theme.author, AUTHOR_LENGTH); - strAppend(info, theme.info, INFO_LENGTH); - } + ThemeFile(std::string themePath, bool loadYAML = true); + virtual ~ThemeFile() {} ThemeFile& operator= (const ThemeFile& theme); @@ -86,33 +77,21 @@ class ThemeFile return nullptr; } - - uint32_t getColorByName(std::string colorName) { - - auto colorIndex = findColorIndex(colorName.c_str()); - ColorEntry a = {colorIndex, 0}; - auto colorEntry = std::find(colorList.begin(), colorList.end(), a); - if (colorEntry != colorList.end()) - return colorEntry->colorValue; - - return 0; - } - void setName(std::string name) { strAppend(this->name, name.c_str(), NAME_LENGTH); } + void setName(std::string name) { strAppend(this->name, name.c_str(), SELECTED_THEME_NAME_LEN); } void setAuthor(std::string author) { strAppend(this->author, author.c_str(), AUTHOR_LENGTH); } void setInfo(std::string info) { strAppend(this->info, info.c_str(), INFO_LENGTH); } void setPath(std::string path) { this->path = path; } std::vector& getColorList() { return colorList; } void setColor(LcdColorIndex colorIndex, uint32_t color); - void setColorByIndex(int index, uint32_t color); virtual std::vector getThemeImageFileNames(); void applyTheme(); protected: std::string path; - char name[NAME_LENGTH + 1]; + char name[SELECTED_THEME_NAME_LEN + 1]; char author[AUTHOR_LENGTH + 1]; char info[INFO_LENGTH + 1]; std::vector colorList; @@ -120,17 +99,7 @@ class ThemeFile void applyColors(); virtual void applyBackground(); - enum ScanState - { - none, - summary, - colors - }; - void deSerialize(); - bool convertRGB(char *pColorRGB, uint32_t &color); - LcdColorIndex findColorIndex(const char *name); - bool readNextLine(FIL &file, char *line, int maxlen); }; diff --git a/radio/src/storage/yaml/yaml_datastructs_nv14.cpp b/radio/src/storage/yaml/yaml_datastructs_nv14.cpp index d9b0f55bb..495bd7ecf 100644 --- a/radio/src/storage/yaml/yaml_datastructs_nv14.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_nv14.cpp @@ -458,6 +458,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_SIGNED( "uartSampleMode", 2 ), YAML_UNSIGNED( "stickDeadZone", 3 ), YAML_PADDING( 1 ), + YAML_STRING("selectedTheme", 26), YAML_END }; static const struct YamlNode struct_unsigned_8[] = { diff --git a/radio/src/storage/yaml/yaml_datastructs_x10.cpp b/radio/src/storage/yaml/yaml_datastructs_x10.cpp index b97b67893..e7e88710f 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x10.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x10.cpp @@ -489,6 +489,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_PADDING( 1 ), YAML_SIGNED( "imuMax", 8 ), YAML_SIGNED( "imuOffset", 8 ), + YAML_STRING("selectedTheme", 26), YAML_END }; static const struct YamlNode struct_unsigned_8[] = { diff --git a/radio/src/storage/yaml/yaml_datastructs_x12s.cpp b/radio/src/storage/yaml/yaml_datastructs_x12s.cpp index 2312d3363..10cd695bf 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x12s.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x12s.cpp @@ -487,6 +487,7 @@ static const struct YamlNode struct_RadioData[] = { YAML_PADDING( 1 ), YAML_SIGNED( "imuMax", 8 ), YAML_SIGNED( "imuOffset", 8 ), + YAML_STRING("selectedTheme", 26), YAML_END }; static const struct YamlNode struct_unsigned_8[] = { diff --git a/radio/src/storage/yaml/yaml_labelslist.cpp b/radio/src/storage/yaml/yaml_labelslist.cpp index bbcdf256e..3fae65b37 100644 --- a/radio/src/storage/yaml/yaml_labelslist.cpp +++ b/radio/src/storage/yaml/yaml_labelslist.cpp @@ -165,7 +165,7 @@ static bool find_node(void* ctx, char* buf, uint8_t len) return true; } -static void set_attr(void* ctx, char* buf, uint8_t len) +static void set_attr(void* ctx, char* buf, uint16_t len) { char value[LABELS_LENGTH + 1]; if(len > LABELS_LENGTH) { diff --git a/radio/src/storage/yaml/yaml_modelslist.cpp b/radio/src/storage/yaml/yaml_modelslist.cpp index 29a782683..8bb906422 100644 --- a/radio/src/storage/yaml/yaml_modelslist.cpp +++ b/radio/src/storage/yaml/yaml_modelslist.cpp @@ -95,7 +95,7 @@ static bool find_node(void* ctx, char* buf, uint8_t len) return true; } -static void set_attr(void* ctx, char* buf, uint8_t len) +static void set_attr(void* ctx, char* buf, uint16_t len) { char fnamebuf[LEN_MODEL_FILENAME + 1]; modelslist_iter* mi = (modelslist_iter*)ctx; diff --git a/radio/src/storage/yaml/yaml_parser.cpp b/radio/src/storage/yaml/yaml_parser.cpp index 682151353..da111d719 100644 --- a/radio/src/storage/yaml/yaml_parser.cpp +++ b/radio/src/storage/yaml/yaml_parser.cpp @@ -115,7 +115,7 @@ YamlParser::parse(const char* buffer, unsigned int size) state = ps_CRLF; continue; } - + if (indent < getLastIndent()) { // go up as many levels as necessary do { @@ -303,8 +303,12 @@ YamlParser::parse(const char* buffer, unsigned int size) case ps_CRLF: if (*c == '\n') { + // Skip blank lines + while (c < end && (*c == '\r' || *c == '\n')) + c += 1; // reset state at EOL reset(); + continue; } break; } diff --git a/radio/src/storage/yaml/yaml_parser.h b/radio/src/storage/yaml/yaml_parser.h index d5964b198..39b32f2d8 100644 --- a/radio/src/storage/yaml/yaml_parser.h +++ b/radio/src/storage/yaml/yaml_parser.h @@ -24,7 +24,7 @@ #include -#define MAX_STR 100 +#define MAX_STR 256 #define MAX_DEPTH 16 // 12 real + 4 virtual struct YamlParserCalls @@ -33,7 +33,7 @@ struct YamlParserCalls bool (*to_child) (void* ctx); bool (*to_next_elmt) (void* ctx); bool (*find_node) (void* ctx, char* buf, uint8_t len); - void (*set_attr) (void* ctx, char* buf, uint8_t len); + void (*set_attr) (void* ctx, char* buf, uint16_t len); }; class YamlParser @@ -70,7 +70,7 @@ class YamlParser // scratch buffer w/ 16 bytes // used for attribute and values char scratch_buf[MAX_STR]; - uint8_t scratch_len; + uint16_t scratch_len; bool node_found; bool eof; diff --git a/radio/src/storage/yaml/yaml_tree_walker.cpp b/radio/src/storage/yaml/yaml_tree_walker.cpp index 8790b02bf..235bf68bd 100644 --- a/radio/src/storage/yaml/yaml_tree_walker.cpp +++ b/radio/src/storage/yaml/yaml_tree_walker.cpp @@ -29,7 +29,7 @@ #define MIN(a,b) (a < b ? a : b) -static void copy_string(char* dst, uint8_t dst_len, const char* src, +static void copy_string(char* dst, uint16_t dst_len, const char* src, uint8_t src_len) { if (src_len < dst_len) { @@ -57,7 +57,7 @@ uint32_t yaml_parse_enum(const struct YamlIdStr* choices, const char* val, uint8 static void yaml_set_attr(void* user, uint8_t* ptr, uint32_t bit_ofs, const YamlNode* node, const char* val, - uint8_t val_len) + uint16_t val_len) { uint32_t i = 0; @@ -265,7 +265,7 @@ bool YamlTreeWalker::findNode(const char* tag, uint8_t tag_len) setAttrValue((char*)tag, tag_len); return true; } - + while(attr && attr->type != YDT_NONE) { if ((tag_len == attr->tag_len) @@ -442,7 +442,7 @@ void YamlTreeWalker::toNextAttr() } } -void YamlTreeWalker::setAttrValue(char* buf, uint8_t len) +void YamlTreeWalker::setAttrValue(char* buf, uint16_t len) { if (!buf || !len || isIdxInvalid()) return; @@ -684,7 +684,7 @@ static bool find_node(void* ctx, char* buf, uint8_t len) return ((YamlTreeWalker*)ctx)->findNode(buf,len); } -static void set_attr(void* ctx, char* buf, uint8_t len) +static void set_attr(void* ctx, char* buf, uint16_t len) { ((YamlTreeWalker*)ctx)->setAttrValue(buf,len); } diff --git a/radio/src/storage/yaml/yaml_tree_walker.h b/radio/src/storage/yaml/yaml_tree_walker.h index b502c8dcc..369bc6f85 100644 --- a/radio/src/storage/yaml/yaml_tree_walker.h +++ b/radio/src/storage/yaml/yaml_tree_walker.h @@ -156,7 +156,7 @@ public: bool isElmtEmpty(uint8_t* data); - void setAttrValue(char* buf, uint8_t len); + void setAttrValue(char* buf, uint16_t len); bool generate(yaml_writer_func wf, void* opaque);