feat(color): New label based Model Selector (#1374)

* Model Labels Selector

* Portrait Layout

* Receiver ID Check

* Fix Labels .yml format

* Companion Initial Commit

commit 967ddf3979b4954402fe62c858faba4b7a416bba
Author: dlktdr <cblackburn320@gmail.com>
Date:   Mon Aug 29 01:49:15 2022 -0700

    Fix Labels .yml format

commit 534221cad9e01146c47a9ac1080a655e04f1f6c8
Author: dlktdr <cblackburn320@gmail.com>
Date:   Mon Aug 29 01:20:57 2022 -0700

    Receiver ID Check

commit f32c0939d44e9ae60bc0705a9176354c23fec198
Author: dlktdr <cblackburn320@gmail.com>
Date:   Sun Aug 28 23:13:25 2022 -0700

    Portrait Layout

commit 961181217c7841ff3f21299ac6aa419b810f80e9
Author: dlktdr <cblackburn320@gmail.com>
Date:   Sat Dec 11 16:56:13 2021 -0800

    Model Labels Selector

commit dc99dd40d2
Author: David PHAM-VAN <1387855+DavBfr@users.noreply.github.com>
Date:   Fri Aug 26 03:04:34 2022 -0300

    feat: Allow Lua widget to override built-in widget with same name (#2208)

    * Allow CPP Widgets Override with LUA

    * Reset a widget option it the type differs

commit 4b747caff9
Author: eshifri <46511024+eshifri@users.noreply.github.com>
Date:   Thu Aug 25 19:47:53 2022 -0700

    fix: Write model name into models.yml when duplicating model (#2224)

    * Update model name in the models.yml file (#2214)

    * Fix the length of the name.

commit e97f23a305
Author: eshifri <46511024+eshifri@users.noreply.github.com>
Date:   Wed Aug 24 21:19:52 2022 -0700

    fix(cpn): Fix full path to model notes for Simulator (#2223)

* Correct Highlighted Column

* labels .yml indentation

* Update da.h

New defines translated to Danish

* Update dataconstants.h

Omit warnings due to difference of LEN_MODEL_FILENAME and LEN_MODEL_NAME in modellist.cpp

* Update modelslist.cpp

Wonder if this are the right file in PR #1374 (?), seems a lot are changed to the better in #1374

* Update dataconstants.h

Restore #define for LEN_MODEL_FILENAME to 16

* Rebase, Correct Issues

Delete now deletes instead of select
New model stores correct information
Duplicate save all information in cell
Rework items to use cell over button
Reword function variables

* CMPN: Add context menu

Fix output not functional. Removed Yaml::null at some point :)
Fix some compiler warnings

* CMPN: Compiler warning, replace ,->_ in list

* FW: Various Changes

Change view to a grid
Don't allow comma in label name
Add scroll indicators
Save sort order

Co-authored-by: HThuren <99370924+HThuren@users.noreply.github.com>
This commit is contained in:
Cliff
2022-09-03 09:01:19 +10:00
committed by GitHub
co-authored by HThuren
parent 20dc9c4d26
commit c8693569b0
85 changed files with 4006 additions and 2067 deletions
+22 -41
View File
@@ -105,56 +105,37 @@ void convertBinRadioData(const char * path, int version)
#endif
const char* error = nullptr;
for (auto category_ptr : modelslist.getCategories()) {
for(auto model_it = modelslist.begin(); model_it != modelslist.end(); ++model_it) {
uint8_t model_version = 0;
auto* model_ptr = *model_it;
char* filename = model_ptr->modelFilename;
auto model_it = category_ptr->begin();
TRACE("converting '%s' (%d/%d)", filename, converted, to_convert);
drawProgressScreen(filename, converted, to_convert);
while(model_it != category_ptr->end()) {
// read only the version number (size=0)
error = readModelBin(filename, nullptr, 0, &model_version);
if (!error) {
// TODO: error handling
error = convertBinModelData(filename, model_version);
uint8_t model_version = 0;
auto* model_ptr = *model_it;
char* filename = model_ptr->modelFilename;
TRACE("converting '%s' (%d/%d)", filename, converted, to_convert);
drawProgressScreen(filename, converted, to_convert);
// read only the version number (size=0)
error = readModelBin(filename, nullptr, 0, &model_version);
if (!error) {
// TODO: error handling
error = convertBinModelData(filename, model_version);
++model_it;
if (error) {
TRACE("ERROR converting '%s': %s", filename, error);
category_ptr->removeModel(model_ptr);
} else {
PartialModel partial;
memclear(&partial, sizeof(PartialModel));
readModelYaml(filename, reinterpret_cast<uint8_t*>(&partial), sizeof(partial));
model_ptr->setModelName(partial.header.name);
}
} else {
TRACE("ERROR reading '%s': %s", filename, error);
// remove that file from the models list
++model_it;
category_ptr->removeModel(model_ptr);
if (error) {
TRACE("ERROR converting '%s': %s", filename, error);
}
} else {
TRACE("ERROR reading '%s': %s", filename, error);
}
converted++;
converted++;
#if defined(SIMU)
RTOS_WAIT_MS(200);
RTOS_WAIT_MS(200);
#endif
}
}
#if defined(SDCARD_YAML) || defined(STORAGE_MODELSLIST)
modelslist.save();
// trigger models list reload
modelslist.clear();
modelslist.load();
#endif
}
@@ -179,7 +160,7 @@ const char* convertBinModelData(char* filename, int version)
memcpy(path, MODELS_PATH, sizeof(MODELS_PATH)-1);
path[sizeof(MODELS_PATH)-1] = '/';
strcpy(&path[sizeof(MODELS_PATH)], filename);
#if STORAGE_CONVERSIONS < 220
if (version == 219) {
const char* error = convertModelData_219_to_220(path);
@@ -206,7 +187,7 @@ const char* convertBinModelData(char* filename, int version)
void eeConvertModel(int id, int version)
{
TRACE("eeConvertModel(%d,%d)", id, version);
#if STORAGE_CONVERSIONS < 220
if (version == 219) {
convertModelData_219_to_220(id);
@@ -269,7 +250,7 @@ bool eeConvert(uint8_t start_version)
#if defined(STORAGE_MODELSLIST)
modelslist.clear();
#endif
#if LCD_W >= 212
lcdDrawRect(60, 6*FH+4, 132, 3);
#else
File diff suppressed because it is too large Load Diff
+172 -88
View File
@@ -23,86 +23,189 @@
#define _MODELSLIST_H_
#include <stdint.h>
#include <algorithm>
#include <functional>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include "sdcard.h"
#if !defined(SDCARD_YAML)
#include "sdcard_raw.h"
#endif
#include "dataconstants.h"
// #define MODELCELL_WIDTH 172
// #define MODELCELL_HEIGHT 59
#include "rtc.h"
// modelXXXXXXX.bin F,FF F,3F,FF\r\n
#define LEN_MODELS_IDX_LINE (LEN_MODEL_FILENAME + sizeof(" F,FF F,3F,FF\r\n")-1)
#define LEN_MODELS_IDX_LINE \
(LEN_MODEL_FILENAME + sizeof(" F,FF F,3F,FF\r\n") - 1)
#define DEFAULT_MODEL_SORT NAME_ASC
struct ModelData;
struct ModuleData;
struct SimpleModuleData
{
uint8_t type;
uint8_t subType;
struct SimpleModuleData {
uint8_t type = 0;
uint8_t subType = 0;
};
typedef struct PACKED {
FSIZE_t fsize; /* File size */
WORD fdate; /* Modified date */
WORD ftime; /* Modified time */
} FInfoH;
#define FILE_HASH_LENGTH (sizeof(FInfoH) * 2) // Hex string output
class ModelCell
{
public:
char modelFilename[LEN_MODEL_FILENAME + 1];
char modelName[LEN_MODEL_NAME + 1] = {};
public:
char modelFilename[LEN_MODEL_FILENAME + 1] = "";
char modelName[LEN_MODEL_NAME + 1] = "";
char modelFinfoHash[FILE_HASH_LENGTH + 1] = "";
#if LEN_BITMAP_NAME > 0
char modelBitmap[LEN_BITMAP_NAME] = "";
#endif
gtime_t lastOpened = 0;
bool _isDirty = true;
bool valid_rfData;
uint8_t modelId[NUM_MODULES];
SimpleModuleData moduleData[NUM_MODULES];
bool valid_rfData;
uint8_t modelId[NUM_MODULES] = {0, 0};
SimpleModuleData moduleData[NUM_MODULES];
explicit ModelCell(const char * name);
explicit ModelCell(const char * name, uint8_t len);
~ModelCell();
explicit ModelCell(const char *fileName);
explicit ModelCell(const char *fileName, uint8_t len);
void save(FIL * file);
void setModelName(char *name);
void setModelName(char *name, uint8_t len);
void setRfData(ModelData *model);
void setModelName(char * name);
void setModelName(char* name, uint8_t len);
void setRfData(ModelData * model);
void setModelId(uint8_t moduleIdx, uint8_t id);
void setRfModuleData(uint8_t moduleIdx, ModuleData* modData);
bool fetchRfData();
void setModelId(uint8_t moduleIdx, uint8_t id);
void setRfModuleData(uint8_t moduleIdx, ModuleData *modData);
bool fetchRfData();
};
class ModelsCategory: public std::list<ModelCell *>
typedef struct {
std::string icon;
// Anything else?
} SLabelDetail;
typedef std::vector<std::pair<uint16_t, ModelCell *>> ModelLabelsVector;
typedef std::vector<std::string> LabelsVector;
typedef std::vector<ModelCell *> ModelsVector;
typedef enum {
NO_SORT,
NAME_ASC,
NAME_DES,
DATE_ASC,
DATE_DES,
SORT_COUNT
} ModelsSortBy;
/**
* @brief ModelMap is a multimap of all models and their cooresponding
* labels. Lables are referenced by index, stored in var labels
*/
class ModelMap : protected std::multimap<uint16_t, ModelCell *>
{
public:
char name[LEN_MODEL_FILENAME + 1];
public:
ModelsVector getUnlabeledModels();
ModelsVector getAllModels();
ModelsVector getModelsByLabel(const std::string &);
ModelsVector getModelsByLabels(const LabelsVector &);
ModelsVector getModelsInLabels(const LabelsVector &lbls);
LabelsVector getLabelsByModel(ModelCell *);
std::map<std::string, bool> getSelectedLabels(ModelCell *);
bool isLabelSelected(const std::string &, ModelCell *);
LabelsVector getLabels();
int addLabel(std::string lbl);
bool addLabelToModel(const std::string &, ModelCell *, bool update = false);
bool removeLabelFromModel(const std::string &label, ModelCell *,
bool update = false);
bool removeLabel(
const std::string &,
std::function<void(const char *file, int progress)> progress = nullptr);
bool moveLabelTo(unsigned current, unsigned newind);
bool renameLabel(
const std::string &from, const std::string &to,
std::function<void(const char *file, int progress)> progress = nullptr);
std::string getCurrentLabel() { return currentlabel; };
void setCurrentLabel(const std::string &lbl)
{
currentlabel = lbl;
setDirty();
}
std::string getLabelString(ModelCell *, const char *noresults = "");
void setDirty(bool save = false);
bool isDirty() { return _isDirty; }
explicit ModelsCategory(const char * name);
explicit ModelsCategory(const char * name, uint8_t len);
~ModelsCategory();
// Currently selected labels in the GUI
void setFilteredLabels(std::set<uint32_t> filtlbls)
{
this->filtlbls = std::move(filtlbls);
}
void addFilteredLabel(const std::string &lbl);
bool isLabelFiltered(const std::string &lbl);
std::set<uint32_t> filteredLabels() { return filtlbls; }
ModelCell* addModel(const char* fileName, const char* modelName = nullptr);
void removeModel(ModelCell * model);
void moveModel(ModelCell * model, int8_t step);
void setSortOrder(ModelsSortBy sortby);
ModelsSortBy sortOrder() {return _sortOrder;}
int getModelIndex(const ModelCell* model);
protected:
ModelsSortBy _sortOrder = DEFAULT_MODEL_SORT;
bool _isDirty = true;
std::set<uint32_t> filtlbls;
std::string currentlabel = "";
void save(FIL * file);
void updateModelCell(ModelCell *);
bool removeModels(
ModelCell *); // Should only be called from ModelsList remove model
bool updateModelFile(ModelCell *);
void sortModelsBy(ModelsVector &mv, ModelsSortBy sortby);
void clear()
{
_isDirty = true;
labels.clear();
std::multimap<uint16_t, ModelCell *>::clear();
}
int getIndexByLabel(const std::string &str)
{
auto a = std::find(labels.begin(), labels.end(), str);
return a == labels.end() ? -1 : a - labels.begin();
}
std::string getLabelByIndex(uint16_t index)
{
if (index < (uint16_t)labels.size())
return labels.at(index);
else
return std::string();
}
friend class ModelsList;
private:
LabelsVector labels; // Storage space for discovered labels
};
class ModelsList
class ModelsList : public ModelsVector
{
bool loaded;
std::list<ModelsCategory *> categories;
ModelsCategory * currentCategory;
ModelCell * currentModel;
unsigned int modelsCount;
ModelCell *currentModel;
void init();
public:
public:
enum class Format {
txt,
#if defined(SDCARD_YAML)
@@ -113,73 +216,54 @@ public:
load_default = txt,
#endif
};
ModelsList();
~ModelsList();
bool load(Format fmt = Format::load_default);
void save();
const char *save(LabelsVector newOrder=LabelsVector());
void clear();
const std::list<ModelsCategory *> & getCategories() const
{
return categories;
}
std::list<ModelsCategory *>& getCategories()
{
return categories;
}
void setCurrentModel(ModelCell *cell);
void updateCurrentModelCell();
void setCurrentCategory(ModelsCategory * cat);
ModelsCategory * getCurrentCategory() const
{
return currentCategory;
}
int getCurrentCategoryIdx() const;
void setCurrentModel(ModelCell * cell);
ModelCell * getCurrentModel() const
{
return currentModel;
}
void incModelsCount() {
modelsCount++;
}
ModelCell *getCurrentModel() const { return currentModel; }
unsigned int getModelsCount() const
{
return modelsCount;
return std::vector<ModelCell *>::size();
}
bool readNextLine(char * line, int maxlen);
bool readNextLine(char *line, int maxlen);
ModelsCategory * createCategory(bool save=true);
ModelsCategory * createCategory(const char * name, bool save=true);
void removeCategory(ModelsCategory * category);
ModelCell *addModel(const char *name, bool save = true, ModelCell *copyCell = nullptr);
bool removeModel(ModelCell *model);
bool moveModelTo(unsigned curindex, unsigned toindex);
ModelCell * addModel(ModelsCategory * category, const char * name, const char* modelName = nullptr, bool save=true);
void removeModel(ModelsCategory * category, ModelCell * model);
void moveModel(ModelsCategory * category, ModelCell * model, int8_t step);
void moveModel(ModelCell * model, ModelsCategory * previous_category, ModelsCategory * new_category);
bool isModelIdUnique(uint8_t moduleIdx, char* warn_buf, size_t warn_buf_len);
bool isModelIdUnique(uint8_t moduleIdx, char *warn_buf, size_t warn_buf_len);
uint8_t findNextUnusedModelId(uint8_t moduleIdx);
void onNewModelCreated(ModelCell* cell, ModelData* model);
typedef struct {
std::string name;
char hash[FILE_HASH_LENGTH + 1];
bool curmodel = false;
bool celladded = false;
} filedat;
std::vector<filedat> fileHashInfo;
protected:
protected:
FIL file;
bool loadTxt();
#if defined(SDCARD_YAML)
bool loadYaml();
bool loadYamlDirScanner();
#endif
};
extern ModelsList modelslist;
ModelLabelsVector getUniqueLabels();
#endif // _MODELSLIST_H_
extern ModelsList modelslist;
extern ModelMap modelslabels;
#endif // _MODELSLIST_H_
+16 -8
View File
@@ -26,9 +26,6 @@
#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);
@@ -71,9 +68,6 @@ void storageFormat()
sdCheckAndCreateDirectory(MODELS_PATH);
generalDefault();
setModelDefaults();
#if defined(STORAGE_MODELSLIST)
storageCreateModelsList();
#endif
}
void storageCheck(bool immediately)
@@ -87,10 +81,24 @@ void storageCheck(bool immediately)
}
}
#if defined(STORAGE_MODELSLIST)
if (storageDirtyMsk & EE_LABELS) {
TRACE("SD card write labels");
storageDirtyMsk &= ~EE_LABELS;
const char * error = modelslist.save();
if (error) {
TRACE("writeLabels error=%s", error);
}
}
#endif
if (storageDirtyMsk & EE_MODEL) {
TRACE("eeprom write model");
storageDirtyMsk &= ~EE_MODEL;
const char * error = writeModel();
#if defined(STORAGE_MODELSLIST)
modelslist.updateCurrentModelCell();
#endif
if (error) {
TRACE("writeModel error=%s", error);
}
@@ -206,14 +214,14 @@ void storageReadAll()
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
}
-2
View File
@@ -25,8 +25,6 @@
#include "ff.h"
#include "translations.h"
#define DEFAULT_CATEGORY "Models"
#define MODEL_FILENAME_PREFIX "model"
#if defined(SDCARD_RAW)
#define MODEL_FILENAME_SUFFIX ".bin"
-12
View File
@@ -191,15 +191,3 @@ const char * writeGeneralSettingsBin()
return writeFileBin(RADIO_SETTINGS_PATH, (uint8_t *)&g_eeGeneral, sizeof(g_eeGeneral));
}
#if !defined(SDCARD_YAML)
void storageCreateModelsList()
{
FIL file;
FRESULT result = f_open(&file, RADIO_MODELSLIST_PATH, FA_CREATE_ALWAYS | FA_WRITE);
if (result == FR_OK) {
f_puts("[" DEFAULT_CATEGORY "]\n" DEFAULT_MODEL_FILENAME "\n", &file);
f_close(&file);
}
}
#endif
+6 -23
View File
@@ -122,27 +122,6 @@ const char * readYamlFile(const char* fullpath, const YamlParserCalls* calls, vo
return NULL;
}
//
// Generic storage interface
//
#if defined(STORAGE_MODELSLIST)
void storageCreateModelsList()
{
modelslist.clear();
ModelsCategory* cat = modelslist.createCategory(DEFAULT_CATEGORY, false);
ModelCell* model = nullptr;
if (g_eeGeneral.currModelFilename[0] != '\0') {
model = modelslist.addModel(cat, g_eeGeneral.currModelFilename, nullptr, false);
} else {
model = modelslist.addModel(cat, DEFAULT_MODEL_FILENAME, nullptr, false);
}
model->setModelName(g_model.header.name);
modelslist.save();
}
#endif
//
// SDCARD storage interface
//
@@ -224,12 +203,16 @@ const char * loadRadioSettings()
#endif
}
#if defined(DEFAULT_INTERNAL_MODULE)
g_eeGeneral.internalModule = DEFAULT_INTERNAL_MODULE;
#endif
const char* error = loadRadioSettingsYaml();
if (!error) {
g_eeGeneral.chkSum = evalChkSum();
}
postRadioSettingsLoad();
return error;
}
@@ -345,7 +328,7 @@ const char * writeGeneralSettings()
return p;
}
f_unlink(RADIO_SETTINGS_YAML_PATH);
FRESULT result = f_rename(RADIO_SETTINGS_TMPFILE_YAML_PATH, RADIO_SETTINGS_YAML_PATH);
if(result != FR_OK)
return SDCARD_ERROR(result);
+1
View File
@@ -22,6 +22,7 @@
#pragma once
enum class ChecksumResult {Success, Failed, None};
#include "sdcard_common.h" // TODO CHECK REQUIRED
constexpr uint8_t MODELIDX_STRLEN = sizeof(MODEL_FILENAME_PREFIX "00");
+3 -2
View File
@@ -6,9 +6,10 @@ set(SRC ${SRC} storage/yaml/yaml_tree_walker.cpp
storage/yaml/yaml_datastructs.cpp)
if(STORAGE_MODELSLIST)
set(SRC ${SRC} storage/yaml/yaml_modelslist.cpp)
set(SRC ${SRC} storage/yaml/yaml_labelslist.cpp)
add_definitions(-DSTORAGE_MODELSLIST)
endif()
# Warning: this file must be kept in sync with 'yaml_datastructs.cpp'
# in the same directory.
@@ -455,6 +455,7 @@ static const struct YamlNode struct_ModelHeader[] = {
YAML_STRING("name", 15),
YAML_ARRAY("modelId", 8, 2, struct_unsigned_8, NULL),
YAML_STRING("bitmap", 14),
YAML_STRING("labels", 100),
YAML_END
};
static const struct YamlNode struct_TimerData[] = {
@@ -837,7 +838,7 @@ static const struct YamlNode struct_TopBarPersistentData[] = {
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 248, struct_ModelHeader, NULL),
YAML_STRUCT("header", 1048, struct_ModelHeader, NULL),
YAML_ARRAY("timers", 136, 3, struct_TimerData, NULL),
YAML_UNSIGNED( "telemetryProtocol", 3 ),
YAML_UNSIGNED( "thrTrim", 1 ),
@@ -889,7 +890,7 @@ static const struct YamlNode struct_ModelData[] = {
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
YAML_STRUCT("header", 248, struct_ModelHeader, NULL),
YAML_STRUCT("header", 1048, struct_ModelHeader, NULL),
YAML_ARRAY("timers", 136, 3, struct_TimerData, NULL),
YAML_END
};
@@ -480,6 +480,7 @@ static const struct YamlNode struct_ModelHeader[] = {
YAML_STRING("name", 15),
YAML_ARRAY("modelId", 8, 2, struct_unsigned_8, NULL),
YAML_STRING("bitmap", 14),
YAML_STRING("labels", 100),
YAML_END
};
static const struct YamlNode struct_TimerData[] = {
@@ -862,7 +863,7 @@ static const struct YamlNode struct_TopBarPersistentData[] = {
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 248, struct_ModelHeader, NULL),
YAML_STRUCT("header", 1048, struct_ModelHeader, NULL),
YAML_ARRAY("timers", 136, 3, struct_TimerData, NULL),
YAML_UNSIGNED( "telemetryProtocol", 3 ),
YAML_UNSIGNED( "thrTrim", 1 ),
@@ -914,7 +915,7 @@ static const struct YamlNode struct_ModelData[] = {
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
YAML_STRUCT("header", 248, struct_ModelHeader, NULL),
YAML_STRUCT("header", 1048, struct_ModelHeader, NULL),
YAML_ARRAY("timers", 136, 3, struct_TimerData, NULL),
YAML_END
};
@@ -478,6 +478,7 @@ static const struct YamlNode struct_ModelHeader[] = {
YAML_STRING("name", 15),
YAML_ARRAY("modelId", 8, 2, struct_unsigned_8, NULL),
YAML_STRING("bitmap", 14),
YAML_STRING("labels", 100),
YAML_END
};
static const struct YamlNode struct_TimerData[] = {
@@ -860,7 +861,7 @@ static const struct YamlNode struct_TopBarPersistentData[] = {
};
static const struct YamlNode struct_ModelData[] = {
YAML_CUSTOM("semver",nullptr,w_semver),
YAML_STRUCT("header", 248, struct_ModelHeader, NULL),
YAML_STRUCT("header", 1048, struct_ModelHeader, NULL),
YAML_ARRAY("timers", 136, 3, struct_TimerData, NULL),
YAML_UNSIGNED( "telemetryProtocol", 3 ),
YAML_UNSIGNED( "thrTrim", 1 ),
@@ -912,7 +913,7 @@ static const struct YamlNode struct_ModelData[] = {
YAML_END
};
static const struct YamlNode struct_PartialModel[] = {
YAML_STRUCT("header", 248, struct_ModelHeader, NULL),
YAML_STRUCT("header", 1048, struct_ModelHeader, NULL),
YAML_ARRAY("timers", 136, 3, struct_TimerData, NULL),
YAML_END
};
+301
View File
@@ -0,0 +1,301 @@
/*
* 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 "yaml_labelslist.h"
#include "yaml_parser.h"
#include "debug.h"
#include "storage/modelslist.h"
#include <cstring>
#ifdef DEBUG_LABELS
#define TRACE_LABELS_YAML(...) TRACE(__VA_ARGS__)
#else
#define TRACE_LABELS_YAML(...)
#endif
using std::list;
struct labelslist_iter
{
enum ItemData {
Root=0,
ModelsRoot=1,
ModelName=2,
ModelData=3,
LabelsRoot=4,
LabelName=5,
LabelData=6,
SortRoot=7,
};
ModelCell *curmodel;
bool modeldatavalid; // Used to determine if reading yaml values is necessary
uint8_t level;
char current_attr[LABEL_LENGTH+1]; // set after find_node()
char current_label[LABEL_LENGTH+1]; // set after find_node()
};
static labelslist_iter __labelslist_iter_inst;
void* get_labelslist_iter()
{
// Thoughts... record the time here.
// If time > xxx while parsing models. pop up a window showing updating?
__labelslist_iter_inst.modeldatavalid = false;
__labelslist_iter_inst.curmodel = NULL;
__labelslist_iter_inst.level = 0;
TRACE_LABELS_YAML("YAML Label Reader Start %u", 0);
return &__labelslist_iter_inst;
}
static bool to_parent(void* ctx)
{
labelslist_iter* mi = (labelslist_iter*)ctx;
if (mi->level == labelslist_iter::Root)
return false;
if(mi->level == labelslist_iter::ModelName ||
mi->level == labelslist_iter::LabelName) {
mi->level = labelslist_iter::Root;
}
else
mi->level--;
TRACE_LABELS_YAML("YAML To Parent %u", mi->level);
return true;
}
static bool to_child(void* ctx)
{
labelslist_iter* mi = (labelslist_iter*)ctx;
mi->level++;
TRACE_LABELS_YAML("YAML To Child");
TRACE_LABELS_YAML("YAML Level %u", mi->level);
return true;
}
static bool to_next_elmt(void* ctx)
{
labelslist_iter* mi = (labelslist_iter*)ctx;
if (mi->level == labelslist_iter::Root) {
return false;
}
TRACE_LABELS_YAML("YAML To Next Element");
TRACE_LABELS_YAML("YAML Current Level %u", mi->level);
return true;
}
static bool find_node(void* ctx, char* buf, uint8_t len)
{
labelslist_iter* mi = (labelslist_iter*)ctx;
memcpy(mi->current_attr, buf, len);
mi->current_attr[len] = '\0';
TRACE_LABELS_YAML("YAML On Node %s", mi->current_attr);
TRACE_LABELS_YAML("YAML Current Level %u", mi->level);
// If in the labels node, force to labelsroot enum
if(mi->level == labelslist_iter::Root && strcasecmp(mi->current_attr,"labels") == 0) {
TRACE_LABELS_YAML("Forced root");
mi->level = labelslist_iter::LabelsRoot;
TRACE_LABELS_YAML("YAML New Level %u", mi->level);
}
if(mi->level == labelslist_iter::Root && strcasecmp(mi->current_attr,"models") == 0) {
TRACE_LABELS_YAML("Forced root");
mi->level = labelslist_iter::ModelsRoot;
TRACE_LABELS_YAML("YAML New Level %u", mi->level);
}
if(mi->level == labelslist_iter::Root && strcasecmp(mi->current_attr,"sort") == 0) {
TRACE_LABELS_YAML("Forced root");
mi->level = labelslist_iter::SortRoot;
TRACE_LABELS_YAML("YAML New Level %u", mi->level);
}
// Model List
if(mi->level == labelslist_iter::ModelName) {
bool found=false;
for(auto &filehash : modelslist.fileHashInfo) {
if(filehash.name == mi->current_attr) {
TRACE_LABELS_YAML(" Model %s has a real file, creating a modelcell");
ModelCell *model = new ModelCell(mi->current_attr);
strcpy(model->modelFinfoHash, filehash.hash);
modelslist.push_back(model);
filehash.celladded = true;
if(filehash.curmodel == true)
modelslist.setCurrentModel(model);
mi->curmodel = model;
mi->modeldatavalid = false;
mi->curmodel->_isDirty = true;
found = true;
break;
}
}
if(!found) {
mi->curmodel = NULL;
TRACE_LABELS_YAML("File does not exist in /MODELS");
}
}
// Labels List
if(mi->level == labelslist_iter::LabelName) {
TRACE_LABELS_YAML("Label Found -- %s", mi->current_attr);
modelslabels.addLabel(mi->current_attr);
strncpy(mi->current_label,mi->current_attr, LABEL_LENGTH);
mi->current_label[LABEL_LENGTH] = '\0';
}
return true;
}
static void set_attr(void* ctx, char* buf, uint8_t len)
{
char value[40];
memcpy(value, buf, len);
value[len] = '\0';
labelslist_iter* mi = (labelslist_iter*)ctx;
TRACE_LABELS_YAML("YAML Attr Level %u, %s = %s", mi->level, mi->current_attr, value);
// Model Section
if(mi->level == labelslist_iter::ModelData) {
// File Hash
if(!strcasecmp(mi->current_attr, "hash")) {
if(mi->curmodel != NULL) {
if(!strcmp(mi->curmodel->modelFinfoHash, value)) {
TRACE_LABELS_YAML("FILE HASH MATCHES, No need to scan this model, just load the settings");
mi->modeldatavalid = true;
mi->curmodel->valid_rfData = true;
mi->curmodel->_isDirty = false;
} else {
TRACE_LABELS_YAML("FILE HASH Does not Match, Open model and rebuild modelcell");
mi->modeldatavalid = false;
mi->curmodel->_isDirty = true;
}
}
// Model Name
} else if(mi->modeldatavalid && !strcasecmp(mi->current_attr, "name")) {
if(mi->curmodel != NULL) {
mi->curmodel->setModelName(value);
TRACE_LABELS_YAML("Set the models name");
}
// Last Opened
} else if(mi->modeldatavalid && !strcasecmp(mi->current_attr, "lastopen")) {
if(mi->curmodel != NULL) {
mi->curmodel->lastOpened = (gtime_t)strtol(value, NULL, 0);
TRACE_LABELS_YAML("Last Opened %lu", value);
}
// Model Bitmap
#if LEN_BITMAP_NAME > 0
} else if(mi->modeldatavalid && !strcasecmp(mi->current_attr, "bitmap")) {
if(mi->curmodel != NULL) {
// TODO Check if it exists ?
strcpy(mi->curmodel->modelBitmap, value);
TRACE_LABELS_YAML("Set the models bitmap");
}
#endif
// Model Labels
} else if(mi->modeldatavalid && !strcasecmp(mi->current_attr, "labels")) {
if(mi->curmodel != NULL) {
char *cma;
cma = strtok(value, ",");
int numTokens = 0;
while(cma != NULL) {
modelslabels.addLabelToModel(cma,mi->curmodel);
TRACE_LABELS_YAML(" Adding the label - %s", cma);
cma = strtok(NULL, ",");
numTokens++;
}
}
// RF Module Data
} else {
char cmp[15];
for(int i=0; i < NUM_MODULES; i++) {
snprintf(cmp, sizeof(cmp), MODULE_ID_STR, i);
cmp[sizeof(cmp)-1] = '\0';
if(mi->curmodel != NULL && mi->modeldatavalid && !strcasecmp(mi->current_attr, cmp)) {
mi->curmodel->modelId[i] = strtol(value,NULL,10);
TRACE_LABELS_YAML("Set the module %d rfId to %s", i, value);
}
snprintf(cmp, sizeof(cmp), MODULE_TYPE_STR, i);
cmp[sizeof(cmp)-1] = '\0';
if(mi->curmodel != NULL && mi->modeldatavalid && !strcasecmp(mi->current_attr, cmp)) {
mi->curmodel->moduleData[i].type = strtol(value,NULL,10);
TRACE_LABELS_YAML("Set the module %d rfType to %s", i, value);
}
snprintf(cmp, sizeof(cmp), MODULE_RFPROTOCOL_STR, i);
cmp[sizeof(cmp)-1] = '\0';
if(mi->curmodel != NULL && mi->modeldatavalid && !strcasecmp(mi->current_attr, cmp)) {
mi->curmodel->moduleData[i].subType = strtol(value,NULL,10);
TRACE_LABELS_YAML("Set the module %d rfProtocol to %s", i, value);
}
}
}
// Label Section
} else if(mi->level == labelslist_iter::LabelData) {
if(!strcasecmp(mi->current_attr, "icon")) {
TRACE_LABELS_YAML("Label Icon - %s", value);
// TODO - Check icon exists, or ignore it.
} else if(!strcasecmp(mi->current_attr, "selected")) {
TRACE("FOUND %s Label is selected", mi->current_label);
modelslabels.addFilteredLabel(mi->current_label);
}
// Sort Order
} else if (mi->level == labelslist_iter::SortRoot) {
TRACE("Sort Order Found -- %s", mi->current_attr);
mi->level = labelslist_iter::Root;
modelslabels.setSortOrder((ModelsSortBy)strtol(value,NULL,10));
}
}
static const YamlParserCalls labelslistCalls = {
to_parent,
to_child,
to_next_elmt,
find_node,
set_attr
};
const YamlParserCalls* get_labelslist_parser_calls()
{
return &labelslistCalls;
}
@@ -19,12 +19,16 @@
* GNU General Public License for more details.
*/
#ifndef _YAML_MODELSLIST_H_
#define _YAML_MODELSLIST_H_
#ifndef _YAML_LABELSLIST_H_
#define _YAML_LABELSLIST_H_
#define MODULE_ID_STR "mod%did"
#define MODULE_TYPE_STR "mod%dtype"
#define MODULE_RFPROTOCOL_STR "mod%drf"
struct YamlParserCalls;
void* get_modelslist_iter(const char* currentModel, unsigned currentModel_len);
const YamlParserCalls* get_modelslist_parser_calls();
void* get_labelslist_iter();
const YamlParserCalls* get_labelslist_parser_calls();
#endif
-153
View File
@@ -1,153 +0,0 @@
/*
* 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 "yaml_modelslist.h"
#include "yaml_parser.h"
#include "storage/modelslist.h"
#include <cstring>
using std::list;
struct modelslist_iter
{
enum Level {
Root=0,
Category=1,
Model=2
};
ModelsList* root;
const char* currentModel;
unsigned currentModel_len;
uint8_t level;
char current_attr[16]; // set after find_node()
};
static modelslist_iter __modelslist_iter_inst;
void* get_modelslist_iter(const char* currentModel, unsigned currentModel_len)
{
__modelslist_iter_inst.root = &modelslist;
__modelslist_iter_inst.currentModel = currentModel;
__modelslist_iter_inst.currentModel_len = currentModel_len;
__modelslist_iter_inst.level = 0;
return &__modelslist_iter_inst;
}
static bool to_parent(void* ctx)
{
modelslist_iter* mi = (modelslist_iter*)ctx;
if (mi->level == modelslist_iter::Root) {
return false;
}
mi->level--;
return true;
}
static bool to_child(void* ctx)
{
modelslist_iter* mi = (modelslist_iter*)ctx;
if (mi->level == modelslist_iter::Model) {
return false;
}
mi->level++;
return true;
}
static bool to_next_elmt(void* ctx)
{
modelslist_iter* mi = (modelslist_iter*)ctx;
if (mi->level == modelslist_iter::Root) {
return false;
}
return true;
}
static bool find_node(void* ctx, char* buf, uint8_t len)
{
modelslist_iter* mi = (modelslist_iter*)ctx;
if (len > sizeof(modelslist_iter::current_attr)-1)
len = sizeof(modelslist_iter::current_attr)-1;
memcpy(mi->current_attr, buf, len);
mi->current_attr[len] = '\0';
list<ModelsCategory *>& cats = mi->root->getCategories();
if (mi->level == modelslist_iter::Category) {
ModelsCategory* cat = new ModelsCategory(buf,len);
cats.push_back(cat);
}
return true;
}
static void set_attr(void* ctx, char* buf, uint8_t len)
{
modelslist_iter* mi = (modelslist_iter*)ctx;
auto ml = mi->root;
list<ModelsCategory*>& cats = ml->getCategories();
switch (mi->level) {
case modelslist_iter::Model:
if (!strcmp(mi->current_attr, "filename")) {
if (!cats.empty()) {
ModelCell* model = new ModelCell(buf, len);
auto cat = cats.back();
cat->push_back(model);
ml->incModelsCount();
if (!strncmp(model->modelFilename, mi->currentModel,
mi->currentModel_len)) {
ml->setCurrentCategory(cat);
ml->setCurrentModel(model);
}
}
} else if (!strcmp(mi->current_attr, "name")) {
if (!cats.empty()) {
auto cat = cats.back();
if (!cat->empty()) {
auto model = cat->back();
model->setModelName(buf, len);
}
}
}
break;
}
}
static const YamlParserCalls modelslistCalls = {
to_parent,
to_child,
to_next_elmt,
find_node,
set_attr
};
const YamlParserCalls* get_modelslist_parser_calls()
{
return &modelslistCalls;
}