Detect sdcard format and split processing of otx and etx
This commit is contained in:
committed by
Raphael Coeffic
parent
4f284bc79c
commit
0f6db9c5cb
@@ -61,8 +61,8 @@
|
||||
#define EEPE_FILES_FILTER "EEPE " % CPN_STR_FILES % " (*.eepe);;"
|
||||
#define OTX_FILES_FILTER "OpenTX " % CPN_STR_FILES % " (*.otx);;"
|
||||
#define ETX_FILES_FILTER "EdgeTX " % CPN_STR_FILES % " (*.etx);;"
|
||||
#define YML_FILES_FILTER "YAML " % CPN_STR_FILES % " (*.yml);;"
|
||||
#define EEPROM_FILES_FILTER CPN_STR_RAD_MOD_SETTINGS % " " % CPN_STR_FILES % " (*.etx *.otx *.eepe *.bin *.hex);;" % ETX_FILES_FILTER % OTX_FILES_FILTER % EEPE_FILES_FILTER % BIN_FILES_FILTER % HEX_FILES_FILTER
|
||||
#define YML_FILES_FILTER "EdgeTX YAML " % CPN_STR_FILES % " (*.yml);;"
|
||||
#define EEPROM_FILES_FILTER CPN_STR_RAD_MOD_SETTINGS % " " % CPN_STR_FILES % " (*.etx *.yml *.otx *.eepe *.bin *.hex);;" % ETX_FILES_FILTER % YML_FILES_FILTER % OTX_FILES_FILTER % EEPE_FILES_FILTER % BIN_FILES_FILTER % HEX_FILES_FILTER
|
||||
#define FLASH_FILES_FILTER "FLASH " % CPN_STR_FILES % " (*.bin *.hex *.dfu);;" % BIN_FILES_FILTER % HEX_FILES_FILTER % DFU_FILES_FILTER
|
||||
#define EXTERNAL_EEPROM_FILES_FILTER "EEPROM " % CPN_STR_FILES % " (*.bin *.hex);;" % BIN_FILES_FILTER % HEX_FILES_FILTER
|
||||
#define ER9X_EEPROM_FILE_TYPE "ER9X_EEPROM_FILE"
|
||||
|
||||
@@ -1375,7 +1375,7 @@ bool MdiChild::saveAs(bool isNew)
|
||||
#ifdef __APPLE__
|
||||
QString filter;
|
||||
#else
|
||||
QString filter(ETX_FILES_FILTER);
|
||||
QString filter(ETX_FILES_FILTER % YML_FILES_FILTER);
|
||||
#endif
|
||||
|
||||
QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), g.eepromDir() + "/" + fi.fileName(), filter);
|
||||
|
||||
@@ -23,6 +23,34 @@
|
||||
#include "miniz.c" // Can only be included once!
|
||||
|
||||
bool CategorizedStorageFormat::load(RadioData & radioData)
|
||||
{
|
||||
if (getStorageType(filename) == STORAGE_TYPE_ETX ||
|
||||
(getStorageType(filename) == STORAGE_TYPE_UNKNOWN && probeFormat() == STORAGE_TYPE_ETX))
|
||||
return loadYaml(radioData);
|
||||
else
|
||||
return loadBin(radioData);
|
||||
}
|
||||
|
||||
bool CategorizedStorageFormat::write(const RadioData & radioData)
|
||||
{
|
||||
if (getStorageType(filename) == STORAGE_TYPE_ETX ||
|
||||
(getStorageType(filename) == STORAGE_TYPE_UNKNOWN && probeFormat() == STORAGE_TYPE_ETX))
|
||||
return writeYaml(radioData);
|
||||
else
|
||||
return writeBin(radioData);
|
||||
}
|
||||
|
||||
StorageType CategorizedStorageFormat::probeFormat()
|
||||
{
|
||||
if (QFile(filename + "/RADIO/radio.yml").exists()) // converted
|
||||
return getStorageType("radio.yml");
|
||||
else if (QFile(filename + "/RADIO/radio.bin").exists()) // unconverted
|
||||
return getStorageType("radio.bin");
|
||||
else
|
||||
return getStorageType(filename);
|
||||
}
|
||||
|
||||
bool CategorizedStorageFormat::loadBin(RadioData & radioData)
|
||||
{
|
||||
QByteArray radioSettingsBuffer;
|
||||
if (!loadFile(radioSettingsBuffer, "RADIO/radio.bin")) {
|
||||
@@ -114,7 +142,7 @@ bool CategorizedStorageFormat::load(RadioData & radioData)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CategorizedStorageFormat::write(const RadioData & radioData)
|
||||
bool CategorizedStorageFormat::writeBin(const RadioData & radioData)
|
||||
{
|
||||
QByteArray modelsList; // models.txt
|
||||
QByteArray radioSettingsData; // radio.bin
|
||||
@@ -168,3 +196,185 @@ bool CategorizedStorageFormat::write(const RadioData & radioData)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CategorizedStorageFormat::loadYaml(RadioData & radioData)
|
||||
{
|
||||
if (getStorageType(filename) == STORAGE_TYPE_UNKNOWN && probeFormat() == STORAGE_TYPE_ETX) {
|
||||
if (!QFile(filename + "/" + "RADIO/radio.yml").exists())
|
||||
qDebug() << tr("Can't find %1/RADIO/radio.yml").arg(filename);
|
||||
else
|
||||
qDebug() << tr("Found %1/RADIO/radio.yml").arg(filename);
|
||||
|
||||
if (!QFile(filename + "/" + "MODELS/models.yml").exists())
|
||||
qDebug() << tr("Can't find %1/MODELS/models.yml").arg(filename);
|
||||
else
|
||||
qDebug() << tr("Found %1/MODELS/models.yml").arg(filename);
|
||||
}
|
||||
else {
|
||||
if (!QFile(filename).exists())
|
||||
qDebug() << tr("Can't find %1").arg(filename);
|
||||
else
|
||||
qDebug() << tr("Found %1").arg(filename);
|
||||
}
|
||||
|
||||
setError(tr("Error: Yaml format ignored - under development"));
|
||||
return false; // force failure until fully developed
|
||||
|
||||
/*
|
||||
This code a copy of loadBin with yaml file extensions ONLY
|
||||
*/
|
||||
|
||||
QByteArray radioSettingsBuffer;
|
||||
if (!loadFile(radioSettingsBuffer, "RADIO/radio.yml")) {
|
||||
setError(tr("Can't extract RADIO/radio.yml"));
|
||||
return false;
|
||||
}
|
||||
|
||||
OpenTxEepromInterface * loadInterface = loadRadioSettingsFromByteArray(radioData.generalSettings, radioSettingsBuffer);
|
||||
if (!loadInterface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
board = loadInterface->getBoard();
|
||||
|
||||
QByteArray modelsListBuffer;
|
||||
if (!loadFile(modelsListBuffer, "MODELS/models.yml")) {
|
||||
setError(tr("Can't extract MODELS/models.yml"));
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<QByteArray> lines = modelsListBuffer.split('\n');
|
||||
int modelIndex = 0;
|
||||
int categoryIndex = -1;
|
||||
foreach (const QByteArray & lineArray, lines) {
|
||||
QString line = QString(lineArray).trimmed();
|
||||
if (line.isEmpty()) continue;
|
||||
// qDebug() << "parsing line" << line;
|
||||
|
||||
if (line.startsWith('[') && line.endsWith(']')) {
|
||||
// ignore categories for boards that do not support them
|
||||
if (getCurrentFirmware()->getCapability(HasModelCategories)) {
|
||||
QString name = line.mid(1, line.size() - 2);
|
||||
CategoryData category(qPrintable(name));
|
||||
radioData.categories.push_back(category);
|
||||
categoryIndex++;
|
||||
qDebug() << "added category" << name;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// determine if we have a model number
|
||||
QStringList parts = line.split(QRegExp("\\s+"), QString::SkipEmptyParts);
|
||||
if (parts.size() == 2) {
|
||||
// parse model number
|
||||
int modelNumber = parts[0].toInt();
|
||||
if (modelNumber > 0 && modelNumber > modelIndex && modelNumber < getCurrentFirmware()->getCapability(Models)) {
|
||||
modelIndex = modelNumber;
|
||||
qDebug() << "advanced model number to" << modelIndex;
|
||||
}
|
||||
else {
|
||||
if (modelNumber != modelIndex) qDebug() << "Invalid model number" << parts[0];
|
||||
}
|
||||
parts.removeFirst();
|
||||
}
|
||||
if (parts.size() == 1) {
|
||||
// parse model file name and load
|
||||
QString fileName = parts[0];
|
||||
qDebug() << "Loading model from file" << fileName << "into slot" << modelIndex;
|
||||
QByteArray modelBuffer;
|
||||
if (!loadFile(modelBuffer, QString("MODELS/%1").arg(fileName))) {
|
||||
setError(tr("Can't extract %1").arg(fileName));
|
||||
return false;
|
||||
}
|
||||
if ((int)radioData.models.size() <= modelIndex) {
|
||||
radioData.models.resize(modelIndex + 1);
|
||||
}
|
||||
if (!loadModelFromByteArray(radioData.models[modelIndex], modelBuffer)) {
|
||||
setError(tr("Error loading models"));
|
||||
return false;
|
||||
}
|
||||
strncpy(radioData.models[modelIndex].filename, qPrintable(fileName), sizeof(radioData.models[modelIndex].filename));
|
||||
if (IS_FAMILY_HORUS_OR_T16(board) && !strcmp(radioData.generalSettings.currModelFilename, qPrintable(fileName))) {
|
||||
radioData.generalSettings.currModelIndex = modelIndex;
|
||||
qDebug() << "currModelIndex =" << modelIndex;
|
||||
}
|
||||
if (getCurrentFirmware()->getCapability(HasModelCategories)) {
|
||||
radioData.models[modelIndex].category = categoryIndex;
|
||||
}
|
||||
radioData.models[modelIndex].used = true;
|
||||
modelIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// invalid line
|
||||
// TODO add to parsing report
|
||||
qDebug() << "Invalid line" <<line;
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CategorizedStorageFormat::writeYaml(const RadioData & radioData)
|
||||
{
|
||||
setError("Error: Yaml format ignored - under development");
|
||||
return false; // force failure until fully developed
|
||||
|
||||
|
||||
/*
|
||||
|
||||
This is a copy of writeBin with changed file yml extensions ONLY
|
||||
|
||||
*/
|
||||
|
||||
QByteArray modelsList; // models.txt
|
||||
QByteArray radioSettingsData; // radio.bin
|
||||
size_t numModels = radioData.models.size();
|
||||
size_t numCategories = radioData.categories.size();
|
||||
std::vector<std::vector<QString>> sortedModels(numCategories);
|
||||
|
||||
writeRadioSettingsToByteArray(radioData.generalSettings, radioSettingsData);
|
||||
if (!writeFile(radioSettingsData, "RADIO/radio.yml")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t m=0; m<numModels; m++) {
|
||||
const ModelData & model = radioData.models[m];
|
||||
if (model.isEmpty()) continue;
|
||||
|
||||
QString modelFilename = QString("MODELS/%1").arg(model.filename);
|
||||
QByteArray modelData;
|
||||
writeModelToByteArray(model, modelData);
|
||||
if (!writeFile(modelData, modelFilename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For firmware that doesn't support categories, we can just construct
|
||||
// models.txt as we iterate thru the models vector. For firmware that does
|
||||
// support categories, we have a bit of work to do in order to sort the
|
||||
// models first by category index, so we use the sortedModels data
|
||||
// structure to do that.
|
||||
if (!getCurrentFirmware()->getCapability(HasModelCategories)) {
|
||||
// Use format with model number and file name. This is needed because
|
||||
// radios without category support can have unused model slots
|
||||
modelsList.append(QString("%1 %2\n").arg(m).arg(model.filename));
|
||||
} else {
|
||||
sortedModels[model.category].push_back(QString("%1\n").arg(model.filename));
|
||||
}
|
||||
}
|
||||
|
||||
if (getCurrentFirmware()->getCapability(HasModelCategories)) {
|
||||
for (size_t c=0; c<numCategories; c++) {
|
||||
modelsList.append(QString().sprintf("[%s]\n", radioData.categories[c].name));
|
||||
numModels = sortedModels[c].size();
|
||||
for (size_t m=0; m<numModels; m++) {
|
||||
modelsList.append(sortedModels[c][m]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!writeFile(modelsList, "MODELS/models.yml")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,13 @@ class CategorizedStorageFormat : public StorageFormat
|
||||
protected:
|
||||
virtual bool loadFile(QByteArray & fileData, const QString & fileName) = 0;
|
||||
virtual bool writeFile(const QByteArray & fileData, const QString & fileName) = 0;
|
||||
|
||||
virtual bool loadBin(RadioData & radioData);
|
||||
virtual bool writeBin(const RadioData & radioData);
|
||||
virtual bool loadYaml(RadioData & radioData);
|
||||
virtual bool writeYaml(const RadioData & radioData);
|
||||
|
||||
StorageType probeFormat();
|
||||
};
|
||||
|
||||
#endif // _CATEGORIZED_H_
|
||||
|
||||
@@ -61,4 +61,3 @@ bool SdcardStorageFactory::probe(const QString & path)
|
||||
{
|
||||
return QDir(path).exists();
|
||||
}
|
||||
|
||||
|
||||
@@ -37,8 +37,8 @@ enum StorageType
|
||||
STORAGE_TYPE_XML,
|
||||
STORAGE_TYPE_SDCARD,
|
||||
STORAGE_TYPE_OTX,
|
||||
STORAGE_TYPE_YML,
|
||||
STORAGE_TYPE_ETX
|
||||
STORAGE_TYPE_ETX,
|
||||
STORAGE_TYPE_YML
|
||||
};
|
||||
|
||||
StorageType getStorageType(const QString & filename);
|
||||
|
||||
Reference in New Issue
Block a user