Fix doc path
[opentx.git] / companion / src / storage / categorized.cpp
blob9ca248cc45d85ad96c8a0f46b814803380e33610
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "categorized.h"
22 #include "firmwares/opentx/opentxinterface.h"
24 bool CategorizedStorageFormat::load(RadioData & radioData)
26 QByteArray radioSettingsBuffer;
27 if (!loadFile(radioSettingsBuffer, "RADIO/radio.bin")) {
28 setError(tr("Can't extract RADIO/radio.bin"));
29 return false;
32 OpenTxEepromInterface * loadInterface = loadRadioSettingsFromByteArray(radioData.generalSettings, radioSettingsBuffer);
33 if (!loadInterface) {
34 return false;
37 board = loadInterface->getBoard();
39 QByteArray modelsListBuffer;
40 if (!loadFile(modelsListBuffer, "RADIO/models.txt")) {
41 setError(tr("Can't extract RADIO/models.txt"));
42 return false;
45 QList<QByteArray> lines = modelsListBuffer.split('\n');
46 int modelIndex = 0;
47 int categoryIndex = -1;
48 foreach (const QByteArray & lineArray, lines) {
49 QString line = QString(lineArray).trimmed();
50 if (line.isEmpty()) continue;
51 // qDebug() << "parsing line" << line;
53 if (line.startsWith('[') && line.endsWith(']')) {
54 // ignore categories for boards that do not support them
55 if (getCurrentFirmware()->getCapability(HasModelCategories)) {
56 QString name = line.mid(1, line.size() - 2);
57 CategoryData category(qPrintable(name));
58 radioData.categories.push_back(category);
59 categoryIndex++;
60 qDebug() << "added category" << name;
62 continue;
65 // determine if we have a model number
66 QStringList parts = line.split(QRegExp("\\s+"), QString::SkipEmptyParts);
67 if (parts.size() == 2) {
68 // parse model number
69 int modelNumber = parts[0].toInt();
70 if (modelNumber > 0 && modelNumber > modelIndex && modelNumber < getCurrentFirmware()->getCapability(Models)) {
71 modelIndex = modelNumber;
72 qDebug() << "advanced model number to" << modelIndex;
74 else {
75 if (modelNumber != modelIndex) qDebug() << "Invalid model number" << parts[0];
77 parts.removeFirst();
79 if (parts.size() == 1) {
80 // parse model file name and load
81 QString fileName = parts[0];
82 qDebug() << "Loading model from file" << fileName << "into slot" << modelIndex;
83 QByteArray modelBuffer;
84 if (!loadFile(modelBuffer, QString("MODELS/%1").arg(fileName))) {
85 setError(tr("Can't extract %1").arg(fileName));
86 return false;
88 if ((int)radioData.models.size() <= modelIndex) {
89 radioData.models.resize(modelIndex + 1);
91 if (!loadModelFromByteArray(radioData.models[modelIndex], modelBuffer)) {
92 setError(tr("Error loading models"));
93 return false;
95 strncpy(radioData.models[modelIndex].filename, qPrintable(fileName), sizeof(radioData.models[modelIndex].filename));
96 if (IS_HORUS(board) && !strcmp(radioData.generalSettings.currModelFilename, qPrintable(fileName))) {
97 radioData.generalSettings.currModelIndex = modelIndex;
98 qDebug() << "currModelIndex =" << modelIndex;
100 if (getCurrentFirmware()->getCapability(HasModelCategories)) {
101 radioData.models[modelIndex].category = categoryIndex;
103 radioData.models[modelIndex].used = true;
104 modelIndex++;
105 continue;
108 // invalid line
109 // TODO add to parsing report
110 qDebug() << "Invalid line" <<line;
111 continue;
113 return true;
116 bool CategorizedStorageFormat::write(const RadioData & radioData)
118 QByteArray modelsList; // models.txt
119 QByteArray radioSettingsData; // radio.bin
120 size_t numModels = radioData.models.size();
121 size_t numCategories = radioData.categories.size();
122 std::vector<std::vector<QString>> sortedModels(numCategories);
124 writeRadioSettingsToByteArray(radioData.generalSettings, radioSettingsData);
125 if (!writeFile(radioSettingsData, "RADIO/radio.bin")) {
126 return false;
129 for (size_t m=0; m<numModels; m++) {
130 const ModelData & model = radioData.models[m];
131 if (model.isEmpty()) continue;
133 QString modelFilename = QString("MODELS/%1").arg(model.filename);
134 QByteArray modelData;
135 writeModelToByteArray(model, modelData);
136 if (!writeFile(modelData, modelFilename)) {
137 return false;
140 // For firmware that doesn't support categories, we can just construct
141 // models.txt as we iterate thru the models vector. For firmware that does
142 // support categories, we have a bit of work to do in order to sort the
143 // models first by category index, so we use the sortedModels data
144 // structure to do that.
145 if (!getCurrentFirmware()->getCapability(HasModelCategories)) {
146 // Use format with model number and file name. This is needed because
147 // radios without category support can have unused model slots
148 modelsList.append(QString("%1 %2\n").arg(m).arg(model.filename));
149 } else {
150 sortedModels[model.category].push_back(QString("%1\n").arg(model.filename));
154 if (getCurrentFirmware()->getCapability(HasModelCategories)) {
155 for (size_t c=0; c<numCategories; c++) {
156 modelsList.append(QString().sprintf("[%s]\n", radioData.categories[c].name));
157 numModels = sortedModels[c].size();
158 for (size_t m=0; m<numModels; m++) {
159 modelsList.append(sortedModels[c][m]);
164 if (!writeFile(modelsList, "RADIO/models.txt")) {
165 return false;
168 return true;