282 lines
8.7 KiB
C++
282 lines
8.7 KiB
C++
/*
|
|
* Copyright (C) EdgeTX
|
|
*
|
|
* Based on code named
|
|
* opentx - https://github.com/opentx/opentx
|
|
* th9x - http://code.google.com/p/th9x
|
|
* er9x - http://code.google.com/p/er9x
|
|
* gruvin9x - http://code.google.com/p/gruvin9x
|
|
*
|
|
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include "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 SectionType {
|
|
SEC_Unknown=0,
|
|
SEC_Labels=1,
|
|
SEC_Models=2,
|
|
SEC_Sort=3,
|
|
};
|
|
|
|
ModelCell *curmodel;
|
|
bool modeldatavalid; // Used to determine if reading yaml values is necessary
|
|
uint8_t level;
|
|
uint8_t section;
|
|
char current_attr[LABELS_LENGTH+1]; // set after find_node()
|
|
char current_label[LABELS_LENGTH+1]; // set after find_node()
|
|
};
|
|
|
|
static labelslist_iter __labelslist_iter_inst;
|
|
|
|
void* get_labelslist_iter()
|
|
{
|
|
__labelslist_iter_inst.modeldatavalid = false;
|
|
__labelslist_iter_inst.curmodel = NULL;
|
|
__labelslist_iter_inst.level = 0;
|
|
__labelslist_iter_inst.section = labelslist_iter::SEC_Unknown;
|
|
|
|
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 == 0)
|
|
return false;
|
|
|
|
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 %u", mi->level);
|
|
return true;
|
|
}
|
|
|
|
static bool to_next_elmt(void* ctx)
|
|
{
|
|
labelslist_iter* mi = (labelslist_iter*)ctx;
|
|
if (mi->level == 0) {
|
|
return false;
|
|
}
|
|
|
|
TRACE_LABELS_YAML("YAML Next Element. 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 Found Node. Level = %u, Section= %u, %s", mi->level, mi->section, mi->current_attr);
|
|
|
|
// Switch between the different maps in labels.yml
|
|
if (mi->level == 0) {
|
|
if (strcasecmp(mi->current_attr,"labels") == 0) {
|
|
mi->section = labelslist_iter::SEC_Labels;
|
|
TRACE_LABELS_YAML("YAML Set Section to Labels");
|
|
} else if (strcasecmp(mi->current_attr,"sort") == 0) {
|
|
mi->section = labelslist_iter::SEC_Sort;
|
|
TRACE_LABELS_YAML("YAML Set Section to Sort");
|
|
} else if (strcasecmp(mi->current_attr,"models") == 0) {
|
|
mi->section = labelslist_iter::SEC_Models;
|
|
TRACE_LABELS_YAML("YAML Set Section to Models");
|
|
}
|
|
}
|
|
|
|
// Model List
|
|
if(mi->level == 1 && mi->section == labelslist_iter::SEC_Models) {
|
|
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", mi->current_attr);
|
|
if(filehash.celladded) {
|
|
TRACE_LABELS_YAML(" Duplicate found labels.yml model cell %s already added", mi->current_attr);
|
|
break;
|
|
}
|
|
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 == 1 && mi->section == labelslist_iter::SEC_Labels) {
|
|
TRACE_LABELS_YAML("Label Found -- %s", mi->current_attr);
|
|
modelslabels.addLabel(mi->current_attr);
|
|
strncpy(mi->current_label,mi->current_attr, LABELS_LENGTH);
|
|
mi->current_label[LABELS_LENGTH] = '\0';
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void set_attr(void* ctx, char* buf, uint16_t len)
|
|
{
|
|
char value[LABELS_LENGTH + 1];
|
|
if(len > LABELS_LENGTH) {
|
|
TRACE("ERROR: YAML too long for buffer");
|
|
return;
|
|
}
|
|
memcpy(value, buf, len);
|
|
value[len] = '\0';
|
|
|
|
labelslist_iter* mi = (labelslist_iter*)ctx;
|
|
TRACE_LABELS_YAML("YAML Attr Level %u, Section %u, %s = %s", mi->level, mi->section, mi->current_attr, value);
|
|
|
|
// Model Section
|
|
if(mi->level == 2 && mi->section == labelslist_iter::SEC_Models && mi->curmodel != NULL) {
|
|
// File Hash
|
|
if(!strcasecmp(mi->current_attr, "hash")) {
|
|
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;
|
|
}
|
|
}
|
|
|
|
// Last Opened
|
|
// Hack: Always load this as the hash value is (currently) not in synch with the saved model file
|
|
// TODO: Ensure stored hash is up to date.
|
|
if (!strcasecmp(mi->current_attr, "lastopen")) {
|
|
mi->curmodel->lastOpened = (gtime_t)strtol(value, NULL, 0);
|
|
TRACE_LABELS_YAML(" Last Opened %lu", value);
|
|
} else if (mi->modeldatavalid) {
|
|
// Don't bother filling in values below if hash didn't match
|
|
|
|
// Model Name
|
|
if(!strcasecmp(mi->current_attr, "name")) {
|
|
mi->curmodel->setModelName(value);
|
|
TRACE_LABELS_YAML(" Set the models name");
|
|
|
|
// Model Bitmap
|
|
#if LEN_BITMAP_NAME > 0
|
|
} else if(!strcasecmp(mi->current_attr, "bitmap")) {
|
|
// TODO Check if it exists ?
|
|
strcpy(mi->curmodel->modelBitmap, value);
|
|
TRACE_LABELS_YAML(" Set the models bitmap");
|
|
#endif
|
|
|
|
// Model Labels
|
|
} else if(!strcasecmp(mi->current_attr, "labels")) {
|
|
LabelsVector labels = ModelMap::fromCSV(value);
|
|
for(const auto &lbl : labels ) {
|
|
modelslabels.addLabelToModel(lbl,mi->curmodel);
|
|
TRACE_LABELS_YAML(" Adding the label - %s", lbl.c_str());
|
|
}
|
|
|
|
// 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(!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(!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(!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 == 2 && mi->section == labelslist_iter::SEC_Labels) {
|
|
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 == 0 && mi->section == labelslist_iter::SEC_Sort) {
|
|
TRACE_LABELS_YAML(" Sort Order Found -- %s", value);
|
|
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;
|
|
}
|