Fix doc path
[opentx.git] / companion / src / firmwares / er9x / er9xinterface.cpp
blobe3ef6d4246ebcba0893c305720cc4a0218cbe87c
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 "er9xinterface.h"
22 #include "er9xeeprom.h"
23 #include "rlefile.h"
24 // #include "appdata.h"
25 // #include <iostream>
26 #include <bitset>
28 #define FILE_TYP_GENERAL 1
29 #define FILE_TYP_MODEL 2
31 #define FILE_GENERAL 0
32 #define FILE_MODEL(n) (1+n)
34 Er9xInterface::Er9xInterface():
35 EEPROMInterface(Board::BOARD_STOCK),
36 efile(new RleFile())
40 Er9xInterface::~Er9xInterface()
42 delete efile;
45 const char * Er9xInterface::getName()
47 return "Er9x";
50 inline void applyStickModeToModel(Er9xModelData & model, unsigned int mode)
52 for (int i=0; i<2; i++) {
53 int stick = applyStickMode(i+1, mode) - 1;
55 int tmp = model.trim[i];
56 model.trim[i] = model.trim[stick];
57 model.trim[stick] = tmp;
60 Er9xExpoData tmp = model.expoData[i];
61 model.expoData[i] = model.expoData[stick];
62 model.expoData[stick] = tmp;
65 for (int i=0; i<ER9X_MAX_MIXERS; i++)
66 model.mixData[i].srcRaw = applyStickMode(model.mixData[i].srcRaw, mode);
67 for (int i=0; i<ER9X_NUM_CSW; i++) {
68 switch (LogicalSwitchData(model.logicalSw[i].func).getFunctionFamily()) {
69 case LS_FAMILY_VCOMP:
70 model.logicalSw[i].v2 = applyStickMode(model.logicalSw[i].v2, mode);
71 // no break
72 case LS_FAMILY_VOFS:
73 model.logicalSw[i].v1 = applyStickMode(model.logicalSw[i].v1, mode);
74 break;
75 default:
76 break;
79 model.swashCollectiveSource = applyStickMode(model.swashCollectiveSource, mode);
82 #if 0
83 unsigned long Er9xInterface::loadxml(RadioData &radioData, QDomDocument &doc)
85 QDebug dbg = qDebug();
86 dbg.setAutoInsertSpaces(false);
87 dbg << "trying er9x xml import... ";
89 std::bitset<NUM_ERRORS> errors;
91 Er9xGeneral er9xGeneral;
92 memset(&er9xGeneral,0,sizeof(er9xGeneral));
93 if (!loadRadioSettingsDataXML(&doc, &er9xGeneral)) {
94 errors.set(UNKNOWN_ERROR);
95 return errors.to_ulong();
97 else {
98 radioData.generalSettings=er9xGeneral;
99 dbg << "version " << (unsigned int)er9xGeneral.myVers << " ";
101 for (int i=0; i<getCapability(Models); i++) {
102 Er9xModelData er9xModel;
103 memset(&er9xModel,0,sizeof(er9xModel));
104 if(loadModelDataXML(&doc, &er9xModel, i)) {
105 applyStickModeToModel(er9xModel, radioData.generalSettings.stickMode+1);
106 radioData.models[i] = er9xModel;
109 dbg << "ok";
110 errors.set(ALL_OK);
111 return errors.to_ulong();
113 #endif
115 unsigned long Er9xInterface::load(RadioData &radioData, const uint8_t *eeprom, int size)
117 QDebug dbg = qDebug();
118 dbg.setAutoInsertSpaces(false);
119 dbg << "trying er9x import... ";
121 std::bitset<NUM_ERRORS> errors;
123 if (size != Boards::getEEpromSize(Board::BOARD_STOCK)) {
124 dbg << "wrong size";
125 errors.set(WRONG_SIZE);
126 return errors.to_ulong();
129 if (!efile->EeFsOpen((uint8_t *)eeprom, size, Board::BOARD_STOCK)) {
130 dbg << "wrong file system";
131 errors.set(WRONG_FILE_SYSTEM);
132 return errors.to_ulong();
135 efile->openRd(FILE_GENERAL);
136 Er9xGeneral er9xGeneral;
138 if (efile->readRlc1((uint8_t*)&er9xGeneral, 1) != 1) {
139 dbg << "no";
140 errors.set(UNKNOWN_ERROR);
141 return errors.to_ulong();
144 dbg << "version " << (unsigned int)er9xGeneral.myVers << " ";
146 switch(er9xGeneral.myVers) {
147 case 3:
148 dbg << "(old gruvin9x) ";
149 case 4:
150 // case 5:
151 case 6:
152 case 7:
153 case 8:
154 case 9:
155 case 10:
156 break;
157 default:
158 dbg << "not er9x";
159 errors.set(NOT_ER9X);
160 return errors.to_ulong();
163 efile->openRd(FILE_GENERAL);
164 if (!efile->readRlc1((uint8_t*)&er9xGeneral, sizeof(Er9xGeneral))) {
165 dbg << "ko";
166 errors.set(UNKNOWN_ERROR);
167 return errors.to_ulong();
170 radioData.generalSettings = er9xGeneral;
172 for (int i=0; i<getCapability(Models); i++) {
173 Er9xModelData er9xModel;
174 efile->openRd(FILE_MODEL(i));
175 if (!efile->readRlc1((uint8_t*)&er9xModel, sizeof(Er9xModelData))) {
176 radioData.models[i].clear();
178 else {
179 applyStickModeToModel(er9xModel, radioData.generalSettings.stickMode+1);
180 radioData.models[i] = er9xModel;
184 dbg << "ok";
185 errors.set(ALL_OK);
186 return errors.to_ulong();
189 unsigned long Er9xInterface::loadBackup(RadioData &radioData, const uint8_t *eeprom, int esize, int index)
191 std::bitset<NUM_ERRORS> errors;
192 errors.set(UNKNOWN_ERROR);
193 return errors.to_ulong();
196 int Er9xInterface::getSize(const ModelData &model)
198 return 0;
201 int Er9xInterface::getSize(const GeneralSettings &settings)
203 return 0;
206 int Er9xInterface::isAvailable(PulsesProtocol prot, int port)
208 switch (prot) {
209 case PULSES_PPM:
210 case PULSES_DSM2:
211 case PULSES_PXX_DJT:
212 case PULSES_PPM16:
213 return 1;
214 default:
215 return 0;
219 void Er9xInterface::appendTextElement(QDomDocument * qdoc, QDomElement * pe, QString name, QString value)
221 QDomElement e = qdoc->createElement(name);
222 QDomText t = qdoc->createTextNode(name);
223 t.setNodeValue(value);
224 e.appendChild(t);
225 pe->appendChild(e);
228 void Er9xInterface::appendNumberElement(QDomDocument * qdoc, QDomElement * pe,QString name, int value, bool forceZeroWrite)
230 if(value || forceZeroWrite) {
231 QDomElement e = qdoc->createElement(name);
232 QDomText t = qdoc->createTextNode(name);
233 t.setNodeValue(QString("%1").arg(value));
234 e.appendChild(t);
235 pe->appendChild(e);
239 void Er9xInterface::appendCDATAElement(QDomDocument * qdoc, QDomElement * pe,QString name, const char * data, int size)
241 QDomElement e = qdoc->createElement(name);
242 QDomCDATASection t = qdoc->createCDATASection(name);
243 t.setData(QByteArray(data, size).toBase64());
244 e.appendChild(t);
245 pe->appendChild(e);
248 QDomElement Er9xInterface::getGeneralDataXML(QDomDocument * qdoc, Er9xGeneral * tgen)
250 QDomElement gd = qdoc->createElement("GENERAL_DATA");
251 appendNumberElement(qdoc, &gd, "Version", tgen->myVers, true); // have to write value here
252 appendTextElement(qdoc, &gd, "Owner", QString::fromLatin1(tgen->ownerName,sizeof(tgen->ownerName)).trimmed());
253 appendCDATAElement(qdoc, &gd, "Data", (const char *)tgen,sizeof(Er9xGeneral));
254 return gd;
257 QDomElement Er9xInterface::getModelDataXML(QDomDocument * qdoc, Er9xModelData * tmod, int modelNum, int mdver)
259 QDomElement md = qdoc->createElement("MODEL_DATA");
260 md.setAttribute("number", modelNum);
261 appendNumberElement(qdoc, &md, "Version", mdver, true); // have to write value here
262 appendTextElement(qdoc, &md, "Name", QString::fromLatin1(tmod->name,sizeof(tmod->name)).trimmed());
263 appendCDATAElement(qdoc, &md, "Data", (const char *)tmod,sizeof(Er9xModelData));
264 return md;
267 bool Er9xInterface::loadRadioSettingsDataXML(QDomDocument * qdoc, Er9xGeneral * tgen)
269 // look for "GENERAL_DATA" tag
270 QDomElement gde = qdoc->elementsByTagName("GENERAL_DATA").at(0).toElement();
272 if(gde.isNull()) // couldn't find
273 return false;
275 // load cdata into tgen
276 QDomNode n = gde.elementsByTagName("Data").at(0).firstChild();// get all children in Data
277 while (!n.isNull()) {
278 if (n.isCDATASection()) {
279 QString ds = n.toCDATASection().data();
280 QByteArray ba = QByteArray::fromBase64(ds.toLatin1());
281 const char * data = ba.data();
282 memcpy(tgen, data, sizeof(Er9xGeneral));
283 break;
285 n = n.nextSibling();
287 // check version?
288 return true;
291 bool Er9xInterface::loadModelDataXML(QDomDocument * qdoc, Er9xModelData * tmod, int modelNum)
293 // look for MODEL_DATA with modelNum attribute.
294 // if modelNum = -1 then just pick the first one
295 QDomNodeList ndl = qdoc->elementsByTagName("MODEL_DATA");
297 // cycle through nodes to find correct model number
298 QDomNode k = ndl.at(0);
299 if(modelNum>=0) {
300 while(!k.isNull()) {
301 int a = k.toElement().attribute("number").toInt();
302 if(a==modelNum)
303 break;
304 k = k.nextSibling();
308 if (k.isNull()) // couldn't find
309 return false;
312 // load cdata into tgen
313 QDomNode n = k.toElement().elementsByTagName("Data").at(0).firstChild();// get all children in Data
314 while (!n.isNull()) {
315 if (n.isCDATASection()) {
316 QString ds = n.toCDATASection().data();
317 QByteArray ba = QByteArray::fromBase64(ds.toLatin1());
318 const char * data = ba.data();
319 memcpy(tmod, data, sizeof(Er9xModelData));
320 break;
322 n = n.nextSibling();
324 // check version?
325 return true;
328 int Er9xInterface::getCapability(Capability capability)
330 switch (capability) {
331 case Models:
332 return 16;
333 default:
334 return 0;