added support for min/max contrast to eeprom interface and use it (#5473)
[opentx.git] / companion / src / firmwares / opentx / opentxinterface.cpp
blobba17d4d1be528b76bf4ab5fb5b4685fdee0c3e62
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 "opentxinterface.h"
22 #include "opentxeeprom.h"
23 #include "rlefile.h"
24 #include "appdata.h"
25 #include <bitset>
26 #include <QMessageBox>
27 #include <QTime>
28 #include <QUrl>
29 #include <companion/src/storage/storage.h>
31 using namespace Board;
33 const char * const OPENTX_FIRMWARE_DOWNLOAD_URL[] = {
34 "https://downloads.open-tx.org/2.2/release/firmware",
35 "https://downloads.open-tx.org/2.2/rc/firmware",
36 "https://downloads.open-tx.org/2.2/nightlies/firmware"
39 #define FILE_TYP_GENERAL 1
40 #define FILE_TYP_MODEL 2
42 /// fileId of general file
43 #define FILE_GENERAL 0
44 /// convert model number 0..MAX_MODELS-1 int fileId
45 #define FILE_MODEL(n) (1+n)
47 template<typename T, size_t N>
48 inline
49 size_t SizeOfArray(T(&)[N])
51 return N;
54 OpenTxEepromInterface::OpenTxEepromInterface(OpenTxFirmware * firmware):
55 EEPROMInterface(firmware->getBoard()),
56 efile(new RleFile()),
57 firmware(firmware)
61 OpenTxEepromInterface::~OpenTxEepromInterface()
63 delete efile;
66 const char * OpenTxEepromInterface::getName()
68 switch (board) {
69 case BOARD_STOCK:
70 return "OpenTX for 9X board";
71 case BOARD_M128:
72 return "OpenTX for M128 / 9X board";
73 case BOARD_MEGA2560:
74 return "OpenTX for MEGA2560 board";
75 case BOARD_GRUVIN9X:
76 return "OpenTX for Gruvin9x board / 9X";
77 case BOARD_TARANIS_X9D:
78 return "OpenTX for FrSky Taranis X9D";
79 case BOARD_TARANIS_X9DP:
80 return "OpenTX for FrSky Taranis X9D+";
81 case BOARD_TARANIS_X9E:
82 return "OpenTX for FrSky Taranis X9E";
83 case BOARD_TARANIS_X7:
84 return "OpenTX for FrSky Taranis X7";
85 case BOARD_SKY9X:
86 return "OpenTX for Sky9x board / 9X";
87 case BOARD_9XRPRO:
88 return "OpenTX for 9XR-PRO";
89 case BOARD_AR9X:
90 return "OpenTX for ar9x board / 9X";
91 case BOARD_FLAMENCO:
92 return "OpenTX for Flamenco experimental";
93 case BOARD_X12S:
94 return "OpenTX for FrSky Horus";
95 case BOARD_X10:
96 return "OpenTX for FrSky X10";
97 default:
98 return "OpenTX for an unknown board";
102 bool OpenTxEepromInterface::loadRadioSettingsFromRLE(GeneralSettings & settings, RleFile * rleFile, uint8_t version)
104 QByteArray data(sizeof(settings), 0); // GeneralSettings should be always bigger than the EEPROM struct
105 OpenTxGeneralData open9xSettings(settings, board, version);
106 efile->openRd(FILE_GENERAL);
107 int size = rleFile->readRlc2((uint8_t *)data.data(), data.size());
108 if (size) {
109 open9xSettings.Import(data);
110 return checkVariant(settings.version, settings.variant);
112 else {
113 qWarning() << " error when loading general settings";
114 return false;
118 bool OpenTxEepromInterface::loadModelFromRLE(ModelData & model, RleFile * rleFile, unsigned int index, uint8_t version, uint32_t variant)
120 QByteArray data(sizeof(model), 0); // ModelData should be always bigger than the EEPROM struct
121 rleFile->openRd(FILE_MODEL(index));
122 int size = rleFile->readRlc2((uint8_t *)data.data(), data.size());
123 if (size) {
124 if (loadFromByteArray<ModelData, OpenTxModelData>(model, data, version, variant)) {
125 model.used = true;
128 else {
129 model.clear();
131 return true;
134 template <class T, class M>
135 bool OpenTxEepromInterface::saveToByteArray(const T & src, QByteArray & data, uint8_t version)
137 if (version == 0) {
138 version = getLastDataVersion(getBoard());
140 QByteArray raw;
141 T srcCopy(src); // work on a copy of radio data, because Export() will modify it!
142 M manager(srcCopy, board, version, 0);
143 // manager.Dump();
144 manager.Export(raw);
145 data.resize(8);
146 *((uint32_t*)&data.data()[0]) = StorageFormat::getFourCC(board);
147 data[4] = version;
148 data[5] = 'M';
149 *((uint16_t*)&data.data()[6]) = raw.size();
150 data.append(raw);
151 return true;
154 template <class T, class M>
155 bool OpenTxEepromInterface::loadFromByteArray(T & dest, const QByteArray & data, uint8_t version, uint32_t variant)
157 M manager(dest, board, version, variant);
158 if (manager.Import(data) != 0) {
159 return false;
161 // manager.Dump(); // Dumps the structure so that it's easy to check with firmware datastructs.h
162 return true;
165 template <class T, class M>
166 bool OpenTxEepromInterface::loadFromByteArray(T & dest, const QByteArray & data)
168 uint32_t fourcc = *((uint32_t*)&data.data()[0]);
169 if (StorageFormat::getFourCC(board) != fourcc) {
170 if (IS_HORUS(board) && fourcc == 0x3178396F) {
171 qDebug() << QString().sprintf("%s: Deprecated fourcc used %x vs %x", getName(), fourcc, StorageFormat::getFourCC(board));
173 else {
174 qDebug() << QString().sprintf("%s: Wrong fourcc %x vs %x", getName(), fourcc, StorageFormat::getFourCC(board));
175 return false;
178 qDebug() << QString().sprintf("%s: OK", getName());
179 uint8_t version = data[4];
180 QByteArray raw = data.right(data.size() - 8);
181 return loadFromByteArray<T, M>(dest, raw, version);
184 unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t * eeprom, int size)
186 QDebug dbg = qDebug();
187 dbg.setAutoInsertSpaces(false);
188 dbg << "trying " << getName() << " import...";
190 std::bitset<NUM_ERRORS> errors;
192 if (size != Boards::getEEpromSize(board)) {
193 if (size == 4096) {
194 int notnull = false;
195 for (int i = 2048; i < 4096; i++) {
196 if (eeprom[i] != 255) {
197 notnull = true;
200 if (notnull) {
201 dbg << " wrong size (" << size << ")";
202 errors.set(WRONG_SIZE);
203 return errors.to_ulong();
205 else {
206 errors.set(HAS_WARNINGS);
207 errors.set(WARNING_WRONG_FIRMWARE);
208 size = 2048;
211 else {
212 dbg << " wrong size (" << size << "/" << Boards::getEEpromSize(board) << ")";
213 errors.set(WRONG_SIZE);
214 return errors.to_ulong();
218 if (!efile->EeFsOpen((uint8_t *) eeprom, size, board)) {
219 dbg << " wrong file system";
220 errors.set(WRONG_FILE_SYSTEM);
221 return errors.to_ulong();
224 efile->openRd(FILE_GENERAL);
226 uint8_t version;
227 if (efile->readRlc2(&version, 1) != 1) {
228 dbg << " no";
229 errors.set(UNKNOWN_ERROR);
230 return errors.to_ulong();
233 dbg << " version " << (unsigned int) version;
235 EepromLoadErrors version_error = checkVersion(version);
236 if (version_error == OLD_VERSION) {
237 errors.set(version_error);
238 errors.set(HAS_WARNINGS);
239 ShowEepromWarnings(NULL, QObject::tr("Warning"), errors.to_ulong());
241 else if (version_error == NOT_OPENTX) {
242 dbg << " not open9x";
243 errors.set(version_error);
244 return errors.to_ulong();
247 if (!loadRadioSettingsFromRLE(radioData.generalSettings, efile, version)) {
248 dbg << " ko";
249 errors.set(UNKNOWN_ERROR);
250 return errors.to_ulong();
253 dbg << " variant " << radioData.generalSettings.variant;
254 if (getCurrentFirmware()->getCapability(Models) == 0) {
255 radioData.models.resize(firmware->getCapability(Models));
257 for (int i = 0; i < firmware->getCapability(Models); i++) {
258 if (i < (int)radioData.models.size() && !loadModelFromRLE(radioData.models[i], efile, i, version, radioData.generalSettings.variant)) {
259 dbg << " ko";
260 errors.set(UNKNOWN_ERROR);
261 if (getCurrentFirmware()->getCapability(Models) == 0) {
262 radioData.models.resize(i);
264 return errors.to_ulong();
267 dbg << " ok";
268 errors.set(ALL_OK);
269 return errors.to_ulong();
272 uint8_t OpenTxEepromInterface::getLastDataVersion(Board::Type board)
274 switch (board) {
275 case BOARD_STOCK:
276 return 216;
277 case BOARD_GRUVIN9X:
278 case BOARD_MEGA2560:
279 case BOARD_M128:
280 return 217;
281 default:
282 return 218;
286 void OpenTxEepromInterface::showErrors(const QString & title, const QStringList & errors)
288 QString msg;
289 if (errors.empty()) {
290 msg = QObject::tr("Unknown error");
292 else {
293 int noErrorsToDisplay = std::min((int)errors.size(), 10);
294 for (int n = 0; n < noErrorsToDisplay; n++) {
295 msg += " -" + errors.at(n) + "\n";
297 if (noErrorsToDisplay < errors.size()) {
298 msg += QObject::tr(" ... plus %1 errors").arg(errors.size() - noErrorsToDisplay) + "\n" + msg;
302 QMessageBox::warning(NULL,
303 QObject::tr("Error"),
304 title + "\n" + msg);
307 int OpenTxEepromInterface::save(uint8_t * eeprom, const RadioData & radioData, uint8_t version, uint32_t variant)
309 // TODO QMessageBox::warning should not be called here
311 if (version == 0) {
312 version = getLastDataVersion(board);
315 int size = Boards::getEEpromSize(board);
317 efile->EeFsCreate(eeprom, size, board, version);
319 if (board == BOARD_M128) {
320 variant |= M128_VARIANT;
322 else if (IS_TARANIS_X9E(board)) {
323 variant |= TARANIS_X9E_VARIANT;
325 else if (IS_TARANIS_X7(board)) {
326 variant |= TARANIS_X7_VARIANT;
329 OpenTxGeneralData generator((GeneralSettings &)radioData.generalSettings, board, version, variant);
330 // generator.Dump();
331 QByteArray data;
332 generator.Export(data);
333 int sz = efile->writeRlc2(FILE_GENERAL, FILE_TYP_GENERAL, (const uint8_t *)data.constData(), data.size());
334 if (sz == 0 || generator.errors().count() > 0) {
335 showErrors(QObject::tr("Cannot write radio settings"), generator.errors());
336 return 0;
339 for (int i = 0; i < getCurrentFirmware()->getCapability(Models); i++) {
340 if (!radioData.models[i].isEmpty()) {
341 OpenTxModelData generator((ModelData &)radioData.models[i], board, version, variant);
342 // generator.Dump();
343 QByteArray data;
344 generator.Export(data);
345 int sz = efile->writeRlc2(FILE_MODEL(i), FILE_TYP_MODEL, (const uint8_t *)data.constData(), data.size());
346 if (sz == 0 || generator.errors().count() > 0) {
347 showErrors(QObject::tr("Cannot write model %1").arg(radioData.models[i].name), generator.errors());
348 return 0;
353 return size;
356 int OpenTxEepromInterface::getSize(const ModelData &model)
358 if (IS_SKY9X(board))
359 return 0;
361 if (model.isEmpty())
362 return 0;
364 QByteArray tmp(Boards::getEEpromSize(Board::BOARD_UNKNOWN), 0);
365 efile->EeFsCreate((uint8_t *) tmp.data(), Boards::getEEpromSize(Board::BOARD_UNKNOWN), board, 255/*version max*/);
367 OpenTxModelData open9xModel((ModelData &) model, board, 255/*version max*/, getCurrentFirmware()->getVariantNumber());
369 QByteArray eeprom;
370 open9xModel.Export(eeprom);
371 int sz = efile->writeRlc2(0, FILE_TYP_MODEL, (const uint8_t *) eeprom.constData(), eeprom.size());
372 if (sz != eeprom.size()) {
373 return -1;
375 return efile->size(0);
378 int OpenTxEepromInterface::getSize(const GeneralSettings &settings)
380 if (IS_SKY9X(board))
381 return 0;
383 QByteArray tmp(Boards::getEEpromSize(Board::BOARD_UNKNOWN), 0);
384 efile->EeFsCreate((uint8_t *) tmp.data(), Boards::getEEpromSize(Board::BOARD_UNKNOWN), board, 255);
386 OpenTxGeneralData open9xGeneral((GeneralSettings &) settings, board, 255, getCurrentFirmware()->getVariantNumber());
387 // open9xGeneral.Dump();
389 QByteArray eeprom;
390 open9xGeneral.Export(eeprom);
391 int sz = efile->writeRlc2(0, FILE_TYP_GENERAL, (const uint8_t *) eeprom.constData(), eeprom.size());
392 if (sz != eeprom.size()) {
393 return -1;
395 return efile->size(0);
398 Firmware * OpenTxFirmware::getFirmwareVariant(const QString &id)
400 if (id == getId()) {
401 return this;
403 else if (id.contains(getId() + "-") || (!id.contains("-") && id.contains(getId()))) {
404 Firmware * result = new OpenTxFirmware(id, this);
405 // TODO result.variant = firmware->getVariant(id);
406 return result;
408 else {
409 return NULL;
413 int OpenTxFirmware::getCapability(::Capability capability)
415 switch (capability) {
416 case Models:
417 if (IS_HORUS(board))
418 return 0;
419 else if (IS_ARM(board))
420 return 60;
421 else if (board == BOARD_M128)
422 return 30;
423 else if (IS_2560(board))
424 return 30;
425 else
426 return 16;
427 case Imperial:
428 if (IS_ARM(board))
429 return 0;
430 else
431 return id.contains("imperial") ? 1 : 0;
432 case ModelImage:
433 return (board == BOARD_TARANIS_X9D || IS_TARANIS_PLUS(board) || IS_HORUS(board));
434 case HasBeeper:
435 return (!IS_ARM(board));
436 case HasPxxCountry:
437 return 1;
438 case HasGeneralUnits:
439 if (IS_ARM(board))
440 return 1;
441 else
442 return 0;
443 case HasNegAndSwitches:
444 return IS_ARM(board);
445 case PPMExtCtrl:
446 return 1;
447 case PPMFrameLength:
448 return 40;
449 case FlightModes:
450 if (IS_ARM(board))
451 return 9;
452 else if (IS_2560(board))
453 return 6;
454 else
455 return 5;
456 case FlightModesHaveFades:
457 return 1;
458 case Heli:
459 if (IS_HORUS_OR_TARANIS(board))
460 return id.contains("noheli") ? 0 : 1;
461 else
462 return id.contains("heli") ? 1 : 0;
463 case Gvars:
464 if (IS_HORUS_OR_TARANIS(board))
465 return id.contains("nogvars") ? 0 : 9;
466 else if (id.contains("gvars"))
467 return IS_ARM(board) ? 9 : 5;
468 else
469 return 0;
470 case ModelName:
471 return (IS_HORUS(board) ? 15 : (HAS_LARGE_LCD(board) ? 12 : 10));
472 case FlightModesName:
473 return (IS_HORUS_OR_TARANIS(board) ? 10 : 6);
474 case GvarsName:
475 return (IS_9X(board) ? 0 : 3);
476 case GvarsInCS:
477 case HasFAIMode:
478 return 1;
479 case GvarsAreNamed:
480 case GvarsFlightModes:
481 return ((IS_ARM(board) || IS_2560(board)) ? 1 : 0);
482 case Mixes:
483 return (IS_ARM(board) ? 64 : 32);
484 case OffsetWeight:
485 return (IS_ARM(board) ? 500 : 245);
486 case Timers:
487 return (IS_ARM(board) ? 3 : 2);
488 case TimersName:
489 if (HAS_LARGE_LCD(board))
490 return 8;
491 else if (IS_ARM(board))
492 return 3;
493 else
494 return 0;
495 case PermTimers:
496 return (IS_2560(board) || IS_ARM(board));
497 case CustomFunctions:
498 if (IS_ARM(board))
499 return 64;
500 else if (IS_2560(board) || board == BOARD_M128)
501 return 24;
502 else
503 return 16;
504 case SafetyChannelCustomFunction:
505 return id.contains("nooverridech") ? 0 : 1;
506 case LogicalSwitches:
507 if (IS_ARM(board))
508 return 64;
509 else
510 return 12;
511 case CustomAndSwitches:
512 if (IS_ARM(board))
513 return getCapability(LogicalSwitches);
514 else
515 return 15/*4bits*/- 9/*sw positions*/;
516 case LogicalSwitchesExt:
517 return (IS_ARM(board) ? true : false);
518 case RotaryEncoders:
519 if (board == BOARD_GRUVIN9X)
520 return 2;
521 else if (IS_SKY9X(board))
522 return 1;
523 else
524 return 0;
525 case Outputs:
526 return (IS_ARM(board) ? 32 : 16);
527 case NumCurvePoints:
528 return (IS_ARM(board) ? 512 : 104);
529 case VoicesAsNumbers:
530 return (IS_ARM(board) ? 0 : 1);
531 case VoicesMaxLength:
532 return (IS_ARM(board) ? (IS_TARANIS_X9(board) ? 8 : 6) : 0);
533 case MultiLangVoice:
534 return (IS_ARM(board) ? 1 : 0);
535 case SoundPitch:
536 return 1;
537 case Haptic:
538 return (IS_2560(board) || IS_SKY9X(board) || IS_TARANIS_PLUS(board) || IS_TARANIS_X7(board) || IS_TARANIS_X9E(board) || IS_HORUS(board) || id.contains("haptic"));
539 case ModelTrainerEnable:
540 if (IS_HORUS_OR_TARANIS(board))
541 return 1;
542 else
543 return 0;
544 case MaxVolume:
545 return (IS_ARM(board) ? 23 : 7);
546 case MaxContrast:
547 if (IS_TARANIS_X7(board))
548 return 30;
549 else
550 return 45;
551 case MinContrast:
552 if (IS_TARANIS_X9(board))
553 return 0;
554 else
555 return 10;
556 case HasSoundMixer:
557 return (IS_ARM(board) ? 1 : 0);
558 case ExtraInputs:
559 return 1;
560 case TrimsRange:
561 return 125;
562 case ExtendedTrimsRange:
563 return 500;
564 case Simulation:
565 return 1;
566 case NumCurves:
567 return (HAS_LARGE_LCD(board) ? 32 : (IS_ARM(board) ? 16 : 8));
568 case HasMixerNames:
569 return (IS_ARM(board) ? (IS_TARANIS_X9(board) ? 8 : 6) : false);
570 case HasExpoNames:
571 return (IS_ARM(board) ? (IS_TARANIS_X9(board) ? 8 : 6) : false);
572 case HasNoExpo:
573 return (IS_HORUS_OR_TARANIS(board) ? false : true);
574 case ChannelsName:
575 return (IS_ARM(board) ? (HAS_LARGE_LCD(board) ? 6 : 4) : 0);
576 case HasCvNames:
577 return (IS_ARM(board) ? 1 : 0);
578 case Telemetry:
579 if (IS_2560(board) || IS_ARM(board) || id.contains("frsky") || id.contains("telemetrez"))
580 return TM_HASTELEMETRY | TM_HASOFFSET | TM_HASWSHH;
581 else
582 return 0;
583 case TelemetryBars:
584 return 1;
585 case TelemetryCustomScreens:
586 if (IS_HORUS(board))
587 return 0;
588 else
589 return IS_ARM(board) ? 4 : 2;
590 case TelemetryCustomScreensFieldsPerLine:
591 return HAS_LARGE_LCD(board) ? 3 : 2;
592 case NoTelemetryProtocol:
593 return IS_HORUS_OR_TARANIS(board) ? 1 : 0;
594 case TelemetryUnits:
595 return 0;
596 case TelemetryMaxMultiplier:
597 return (IS_ARM(board) ? 32 : 8);
598 case PPMCenter:
599 return (IS_HORUS_OR_TARANIS(board) ? 500 : (id.contains("ppmca") ? 125 : 0));
600 case PPMUnitMicroseconds:
601 return id.contains("ppmus") ? 1 : 0;
602 case SYMLimits:
603 return 1;
604 case OptrexDisplay:
605 return (board == BOARD_SKY9X ? true : false);
606 case HasVario:
607 return 1;
608 case HasVarioSink:
609 return ((IS_2560(board) || IS_ARM(board)) ? true : false);
610 case HasFailsafe:
611 return (IS_ARM(board) ? 32 : 0);
612 case NumModules:
613 return (IS_ARM(board) ? 2 : 1);
614 case HasPPMStart:
615 return (IS_ARM(board) ? true : false);
616 case HastxCurrentCalibration:
617 return (IS_SKY9X(board) ? true : false);
618 case HasVolume:
619 return (IS_ARM(board) ? true : false);
620 case HasBrightness:
621 return (IS_ARM(board) ? true : false);
622 case PerModelTimers:
623 return 1;
624 case SlowScale:
625 return (IS_ARM(board) ? 10 : 2);
626 case SlowRange:
627 return (IS_ARM(board) ? 250 : 15);
628 case CSFunc:
629 return 18;
630 case HasSDLogs:
631 return ((IS_2560(board) || IS_ARM(board)) ? true : false);
632 case LcdWidth:
633 if (IS_HORUS(board))
634 return 480;
635 else if (IS_TARANIS_X7(board))
636 return 128;
637 else if (IS_TARANIS(board))
638 return 212;
639 else
640 return 128;
641 case LcdHeight:
642 if (IS_HORUS(board))
643 return 272;
644 else
645 return 64;
646 case LcdDepth:
647 if (IS_HORUS(board))
648 return 16;
649 else if (IS_TARANIS_X7(board))
650 return 1;
651 else if (IS_TARANIS(board))
652 return 4;
653 else
654 return 1;
655 case GetThrSwitch:
656 return (IS_HORUS_OR_TARANIS(board) ? SWITCH_SF1 : SWITCH_THR);
657 case HasDisplayText:
658 return IS_ARM(board) ? 1 : 0;
659 case HasTopLcd:
660 return IS_TARANIS_X9E(board) ? 1 : 0;
661 case GlobalFunctions:
662 return IS_ARM(board) ? 64 : 0;
663 case VirtualInputs:
664 return IS_ARM(board) ? 32 : 0;
665 case InputsLength:
666 return HAS_LARGE_LCD(board) ? 4 : 3;
667 case TrainerInputs:
668 return IS_ARM(board) ? 16 : 8;
669 case RtcTime:
670 return IS_ARM(board) || IS_2560(board) ? 1 : 0;
671 case LuaScripts:
672 return IS_HORUS_OR_TARANIS(board) && id.contains("lua") ? 7 : 0;
673 case LuaInputsPerScript:
674 return IS_HORUS_OR_TARANIS(board) ? 10 : 0;
675 case LuaOutputsPerScript:
676 return IS_HORUS_OR_TARANIS(board) ? 6 : 0;
677 case LimitsPer1000:
678 case EnhancedCurves:
679 return IS_ARM(board);
680 case HasFasOffset:
681 return (IS_STOCK(board) ? false : true);
682 case HasMahPersistent:
683 return (IS_ARM(board) ? true : false);
684 case MultiposPots:
685 return IS_HORUS_OR_TARANIS(board) ? 3 : 0;
686 case MultiposPotsPositions:
687 return IS_HORUS_OR_TARANIS(board) ? 6 : 0;
688 case SimulatorVariant:
689 if (board == BOARD_STOCK)
690 return SIMU_STOCK_VARIANTS;
691 else if (board == BOARD_M128)
692 return SIMU_M128_VARIANTS;
693 else if (IS_TARANIS_X9E(board))
694 return TARANIS_X9E_VARIANT;
695 else if (IS_TARANIS_X7(board))
696 return TARANIS_X7_VARIANT;
697 else
698 return 0;
699 case MavlinkTelemetry:
700 return id.contains("mavlink") ? 1 : 0;
701 case SportTelemetry:
702 return IS_ARM(board) ? 1 : 0;
703 case HasInputDiff:
704 case HasMixerExpo:
705 return (IS_HORUS_OR_TARANIS(board) ? true : false);
706 case HasBatMeterRange:
707 return (IS_HORUS_OR_TARANIS(board) ? true : id.contains("battgraph"));
708 case DangerousFunctions:
709 return id.contains("danger") ? 1 : 0;
710 case HasModelCategories:
711 return IS_HORUS(board);
712 default:
713 return 0;
717 QString OpenTxFirmware::getAnalogInputName(unsigned int index)
719 if ((int)index < getBoardCapability(board, Board::Sticks)) {
720 const QString sticks[] = {
721 QObject::tr("Rud"),
722 QObject::tr("Ele"),
723 QObject::tr("Thr"),
724 QObject::tr("Ail")
726 return sticks[index];
729 index -= getBoardCapability(board, Board::Sticks);
731 if (IS_9X(board) || IS_2560(board) || IS_SKY9X(board)) {
732 const QString pots[] = {
733 QObject::tr("P1"),
734 QObject::tr("P2"),
735 QObject::tr("P3")
737 return CHECK_IN_ARRAY(pots, index);
739 else if (IS_TARANIS_X9E(board)) {
740 const QString pots[] = {
741 QObject::tr("F1"),
742 QObject::tr("F2"),
743 QObject::tr("F3"),
744 QObject::tr("F4"),
745 QObject::tr("S1"),
746 QObject::tr("S2"),
747 QObject::tr("LS"),
748 QObject::tr("RS")
750 return CHECK_IN_ARRAY(pots, index);
752 else if (IS_TARANIS(board)) {
753 const QString pots[] = {
754 QObject::tr("S1"),
755 QObject::tr("S2"),
756 QObject::tr("S3"),
757 QObject::tr("LS"),
758 QObject::tr("RS")
760 return CHECK_IN_ARRAY(pots, index);
762 else if (IS_HORUS(board)) {
763 const QString pots[] = {
764 QObject::tr("S1"),
765 QObject::tr("6P"),
766 QObject::tr("S2"),
767 QObject::tr("L1"),
768 QObject::tr("L2"),
769 QObject::tr("LS"),
770 QObject::tr("RS"),
771 QObject::tr("JSx"),
772 QObject::tr("JSy")
774 return CHECK_IN_ARRAY(pots, index);
776 else {
777 return "???";
781 QTime OpenTxFirmware::getMaxTimerStart()
783 if (IS_HORUS_OR_TARANIS(board))
784 return QTime(23, 59, 59);
785 else if (IS_ARM(board))
786 return QTime(8, 59, 59);
787 else
788 return QTime(0, 59, 59);
791 int OpenTxFirmware::isAvailable(PulsesProtocol proto, int port)
793 if (IS_HORUS_OR_TARANIS(board)) {
794 switch (port) {
795 case 0:
796 switch (proto) {
797 case PULSES_OFF:
798 case PULSES_PXX_XJT_X16:
799 case PULSES_PXX_XJT_LR12:
800 return 1;
801 case PULSES_PXX_XJT_D8:
802 return id.contains("eu") ? 0 : 1;
803 case PULSES_PPM:
804 return id.contains("internalppm") ? 1 : 0;
805 default:
806 return 0;
808 break;
809 case 1:
810 switch (proto) {
811 case PULSES_OFF:
812 case PULSES_PPM:
813 case PULSES_PXX_XJT_X16:
814 case PULSES_PXX_XJT_D8:
815 case PULSES_PXX_XJT_LR12:
816 case PULSES_PXX_R9M:
817 //case PULSES_PXX_DJT: // Unavailable for now
818 case PULSES_LP45:
819 case PULSES_DSM2:
820 case PULSES_DSMX:
821 case PULSES_CROSSFIRE:
822 case PULSES_SBUS:
823 return 1;
824 case PULSES_MULTIMODULE:
825 return id.contains("multimodule") ? 1 : 0;
826 default:
827 return 0;
829 break;
830 case -1:
831 switch (proto) {
832 case PULSES_PPM:
833 return 1;
834 default:
835 return 0;
837 break;
838 default:
839 return 0;
842 else if (IS_SKY9X(board)) {
843 switch (port) {
844 case 0:
845 switch (proto) {
846 case PULSES_PPM:
847 case PULSES_PXX_XJT_X16:
848 case PULSES_PXX_XJT_D8:
849 case PULSES_PXX_XJT_LR12:
850 case PULSES_PXX_R9M:
851 case PULSES_LP45:
852 case PULSES_DSM2:
853 case PULSES_DSMX:
854 case PULSES_SBUS:
855 return 1;
856 case PULSES_MULTIMODULE:
857 return id.contains("multimodule") ? 1 : 0;
858 default:
859 return 0;
861 break;
862 case 1:
863 switch (proto) {
864 case PULSES_PPM:
865 return 1;
866 default:
867 return 0;
869 break;
870 default:
871 return 0;
874 else {
875 switch (proto) {
876 case PULSES_PPM:
877 case PULSES_DSMX:
878 case PULSES_LP45:
879 case PULSES_DSM2:
880 // case PULSES_PXX_DJT: // Unavailable for now
881 case PULSES_PPM16:
882 case PULSES_PPMSIM:
883 return 1;
884 default:
885 return 0;
890 template<typename T, size_t SIZE>
891 size_t getSizeA(T (&)[SIZE])
893 return SIZE;
896 EepromLoadErrors OpenTxEepromInterface::checkVersion(unsigned int version)
898 switch (version) {
899 case 201:
900 // first version
901 case 202:
902 // channel order is now always RUD - ELE - THR - AIL
903 // changes in timers
904 // ppmFrameLength added
905 // thrTraceSrc added
906 case 203:
907 // mixers changed (for the trims use for change the offset of a mix)
908 // telemetry offset raised to -127 +127
909 // function switches now have a param on 4 bits
910 case 204:
911 // telemetry changes (bars)
912 case 205:
913 // mixer changes (differential, negative curves)...
914 // case 206:
915 case 207:
916 // V4: Rotary Encoders position in FlightModes
917 case 208:
918 // Trim value in 16bits
919 // FrSky A1/A2 offset on 12bits
920 // ARM: More Mixers / Expos / CSW / FSW / CHNOUT
921 case 209:
922 // Add TrmR, TrmE, TrmT, TrmA as Mix sources
923 // Trims are now OFF / ON / Rud / Ele / Thr / Ail
924 case 210:
925 // Add names in Mixes / Expos
926 // Add a new telemetry screen
927 // Add support for Play Track <filename>
928 case 211:
929 // Curves big change
930 case 212:
931 // Big changes in mixers / limitse
932 case 213:
933 // GVARS / Variants introduction
934 case 214:
935 // Massive EEPROM change!
936 case 215:
937 // M128 revert because too much RAM used!
938 case 216:
939 // A lot of things (first github release)
940 case 217:
941 // 3 logical switches removed on M128 / gruvin9x boards
942 return OLD_VERSION;
943 case 218:
944 break;
945 default:
946 return NOT_OPENTX;
949 return ALL_OK;
952 bool OpenTxEepromInterface::checkVariant(unsigned int version, unsigned int variant)
954 if (board == BOARD_M128 && !(variant & M128_VARIANT)) {
955 if (version == 212) {
956 uint8_t tmp[1000];
957 for (int i = 1; i < 31; i++) {
958 efile->openRd(i);
959 int sz = efile->readRlc2(tmp, sizeof(tmp));
960 if (sz == 849) {
961 qWarning() << " warning: M128 variant not set (but model size seems ok)";
962 return true;
966 qWarning() << " wrong variant (" << variant << ")";
967 return false;
969 else if (IS_TARANIS_X9E(board)) {
970 if (variant != TARANIS_X9E_VARIANT) {
971 qWarning() << " wrong variant (" << variant << ")";
972 return false;
975 else if (IS_TARANIS_X7(board)) {
976 if (variant != TARANIS_X7_VARIANT) {
977 qWarning() << " wrong variant (" << variant << ")";
978 return false;
981 else if (IS_TARANIS(board)) {
982 if (variant != 0) {
983 qWarning() << " wrong variant (" << variant << ")";
984 return false;
988 return true;
991 bool
992 OpenTxEepromInterface::loadModelFromBackup(ModelData & model, const uint8_t * data, unsigned int size, uint8_t version, uint32_t variant)
994 QByteArray backupData((char *) data, size);
995 QByteArray modelData;
996 if (IS_SKY9X(board)) {
997 modelData = QByteArray((char *) data, size);
999 else {
1000 importRlc(modelData, backupData);
1002 if (modelData.size()) {
1003 if (loadFromByteArray<ModelData, OpenTxModelData>(model, modelData, version, variant)) {
1004 model.used = true;
1005 return true;
1008 model.clear();
1009 return false;
1012 unsigned long OpenTxEepromInterface::loadBackup(RadioData &radioData, const uint8_t * eeprom, int esize, int index)
1014 std::bitset<NUM_ERRORS> errors;
1016 QDebug dbg = qDebug();
1017 dbg.setAutoInsertSpaces(false);
1018 dbg << "trying " << getName() << " backup import...";
1020 if (esize < 8 || memcmp(eeprom, "o9x", 3) != 0) {
1021 dbg << " no\n";
1022 errors.set(WRONG_SIZE);
1023 return errors.to_ulong();
1026 Type backupBoard = (Type) -1;
1027 switch (eeprom[3]) {
1028 case 0x33:
1029 backupBoard = BOARD_TARANIS_X9D;
1030 break;
1031 case 0x32:
1032 backupBoard = BOARD_SKY9X;
1033 break;
1034 case 0x31:
1035 backupBoard = BOARD_GRUVIN9X;
1036 break;
1037 default:
1038 dbg << " unknown board";
1039 errors.set(UNKNOWN_BOARD);
1040 return errors.to_ulong();
1043 if (backupBoard != board) {
1044 dbg << " not right board";
1045 errors.set(WRONG_BOARD);
1046 return errors.to_ulong();
1049 uint8_t version = eeprom[4];
1050 uint8_t bcktype = eeprom[5];
1051 uint16_t size = ((uint16_t) eeprom[7] << 8) + eeprom[6];
1052 uint16_t variant = ((uint16_t) eeprom[9] << 8) + eeprom[8];
1054 dbg << " version " << (unsigned int) version << " ";
1056 EepromLoadErrors version_error = checkVersion(version);
1057 if (version_error == OLD_VERSION) {
1058 errors.set(version_error);
1059 errors.set(HAS_WARNINGS);
1061 else if (version_error == NOT_OPENTX) {
1062 dbg << " not open9x";
1063 errors.set(version_error);
1064 return errors.to_ulong();
1067 if (size > esize - 8) {
1068 dbg << " wrong size";
1069 errors.set(WRONG_SIZE);
1070 return errors.to_ulong();
1073 if (bcktype == 'M') {
1074 if (!loadModelFromBackup(radioData.models[index], &eeprom[8], size, version, variant)) {
1075 dbg << " ko";
1076 errors.set(UNKNOWN_ERROR);
1077 return errors.to_ulong();
1080 else {
1081 dbg << " backup type not supported";
1082 errors.set(BACKUP_NOT_SUPPORTED);
1083 return errors.to_ulong();
1086 dbg << " ok";
1087 errors.set(ALL_OK);
1088 return errors.to_ulong();
1091 QString OpenTxFirmware::getFirmwareBaseUrl()
1093 return OPENTX_FIRMWARE_DOWNLOAD_URL[g.boundedOpenTxBranch()];
1096 QString OpenTxFirmware::getFirmwareUrl()
1098 QString url = getFirmwareBaseUrl();
1099 QByteArray data = QUrl::toPercentEncoding(id);
1101 if (IS_ARM(board))
1102 url.append(QString("/getfw.php?fw=%1.bin").arg((QString) data));
1103 else
1104 url.append(QString("/getfw.php?fw=%1.hex").arg((QString) data));
1105 return url;
1108 QString OpenTxFirmware::getReleaseNotesUrl()
1110 QString url = getFirmwareBaseUrl();
1111 url.append("/releasenotes.txt");
1112 return url;
1115 QString OpenTxFirmware::getStampUrl()
1117 QString url = getFirmwareBaseUrl();
1118 url.append("/stamp-opentx.txt");
1119 return url;
1122 void addOpenTxCommonOptions(OpenTxFirmware * firmware)
1124 firmware->addOption("ppmus", QObject::tr("Channel values displayed in us"));
1125 firmware->addOption("nooverridech", QObject::tr("No OverrideCH functions available"));
1126 Option fai_options[] = {{"faichoice", QObject::tr("Possibility to enable FAI MODE (no telemetry) at field")},
1127 {"faimode", QObject::tr("FAI MODE (no telemetry) always enabled")},
1128 {NULL}};
1129 firmware->addOptions(fai_options);
1132 void addOpenTxArmOptions(OpenTxFirmware * firmware)
1134 firmware->addOption("multimodule", QObject::tr("Support for the DIY-Multiprotocol-TX-Module"));
1135 firmware->addOption("eu", QObject::tr("Removes D8 FrSky protocol support which is not legal for use in the EU on radios sold after Jan 1st, 2015"));
1138 void addOpenTxFrskyOptions(OpenTxFirmware * firmware)
1140 addOpenTxCommonOptions(firmware);
1141 addOpenTxArmOptions(firmware);
1142 firmware->addOption("noheli", QObject::tr("Disable HELI menu and cyclic mix support"));
1143 firmware->addOption("nogvars", QObject::tr("Disable Global variables"));
1144 firmware->addOption("lua", QObject::tr("Enable Lua custom scripts screen"));
1145 firmware->addOption("luac", QObject::tr("Enable Lua compiler"));
1146 firmware->addOption("bindopt", QObject::tr("Enable bindings options"));
1149 void addOpenTxTaranisOptions(OpenTxFirmware * firmware)
1151 addOpenTxFrskyOptions(firmware);
1152 firmware->addOption("internalppm", QObject::tr("Support for PPM internal module hack"));
1153 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1156 void addOpenTxLcdOptions(OpenTxFirmware * firmware)
1158 Option lcd_options[] = {
1159 {"ST7565P", QObject::tr("ST7565P LCD or compatible")},
1160 {"ST7565R", QObject::tr("ST7565R LCD or compatible")},
1161 {"ERC12864FSF", QObject::tr("ERC12864FSF LCD")},
1162 {"ST7920", QObject::tr("ST7920 LCD")},
1163 {"KS108", QObject::tr("KS108 LCD")},
1164 {NULL}
1166 firmware->addOptions(lcd_options);
1169 void addOpenTxVoiceOptions(OpenTxFirmware * firmware)
1171 Option voice_options[] = {
1172 {"WTV20", QObject::tr("WTV20 voice module")},
1173 {"JQ6500", QObject::tr("JQ6500 voice module")},
1174 {NULL}
1176 firmware->addOptions(voice_options);
1179 QList<OpenTxEepromInterface *> opentxEEpromInterfaces;
1181 void registerOpenTxFirmware(OpenTxFirmware * firmware)
1183 OpenTxEepromInterface * eepromInterface = new OpenTxEepromInterface(firmware);
1184 firmware->setEEpromInterface(eepromInterface);
1185 opentxEEpromInterfaces.push_back(eepromInterface);
1186 eepromInterfaces.push_back(eepromInterface);
1187 Firmware::addRegisteredFirmware(firmware);
1190 void registerOpenTxFirmwares()
1192 OpenTxFirmware * firmware;
1194 Option ext_options[] = {{"frsky", QObject::tr("Support for frsky telemetry mod"), FRSKY_VARIANT},
1195 {"telemetrez", QObject::tr("Support for telemetry easy board"), FRSKY_VARIANT},
1196 {"jeti", QObject::tr("Support for jeti telemetry mod"), 0},
1197 {"ardupilot", QObject::tr("Support for receiving ardupilot data"), 0},
1198 {"nmea", QObject::tr("Support for receiving NMEA data"), 0},
1199 {"mavlink", QObject::tr("Support for MAVLINK devices"), MAVLINK_VARIANT},
1200 {NULL}};
1201 Option extr_options[] = {{"frsky", QObject::tr("Support for frsky telemetry mod"), FRSKY_VARIANT},
1202 {"jeti", QObject::tr("Support for jeti telemetry mod"), 0},
1203 {"ardupilot", QObject::tr("Support for receiving ardupilot data"), 0},
1204 {"nmea", QObject::tr("Support for receiving NMEA data"), 0},
1205 {"mavlink", QObject::tr("Support for MAVLINK devices"), MAVLINK_VARIANT},
1206 {NULL}};
1207 Option nav_options[] = {{"rotenc", QObject::tr("Rotary Encoder use in menus navigation")},
1208 {"potscroll", QObject::tr("Pots use in menus navigation")},
1209 {NULL}};
1210 Option dsm2_options[] = {{"DSM2", QObject::tr("Support for DSM2 modules"), 0},
1211 {"DSM2PPM", QObject::tr("Support for DSM2 modules using ppm instead of true serial"), 0},
1212 {NULL}};
1214 /* FrSky Taranis X9D+ board */
1215 firmware = new OpenTxFirmware("opentx-x9d+", QObject::tr("FrSky Taranis X9D+"), BOARD_TARANIS_X9DP);
1216 addOpenTxTaranisOptions(firmware);
1217 registerOpenTxFirmware(firmware);
1219 /* FrSky Taranis X9D board */
1220 firmware = new OpenTxFirmware("opentx-x9d", QObject::tr("FrSky Taranis X9D"), BOARD_TARANIS_X9D);
1221 firmware->addOption("haptic", QObject::tr("Haptic module installed"));
1222 addOpenTxTaranisOptions(firmware);
1223 registerOpenTxFirmware(firmware);
1225 /* FrSky Taranis X9E board */
1226 firmware = new OpenTxFirmware("opentx-x9e", QObject::tr("FrSky Taranis X9E"), BOARD_TARANIS_X9E);
1227 firmware->addOption("shutdownconfirm", QObject::tr("Confirmation before radio shutdown"));
1228 firmware->addOption("horussticks", QObject::tr("Horus gimbals installed (Hall sensors)"));
1229 addOpenTxTaranisOptions(firmware);
1230 registerOpenTxFirmware(firmware);
1232 /* FrSky X7 board */
1233 firmware = new OpenTxFirmware("opentx-x7", QObject::tr("FrSky Taranis X7 / X7S"), BOARD_TARANIS_X7);
1234 // No mixersmon for now
1235 addOpenTxFrskyOptions(firmware);
1236 firmware->addOption("internalppm", QObject::tr("Support for PPM internal module hack"));
1237 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1238 registerOpenTxFirmware(firmware);
1240 /* FrSky X10 board */
1241 firmware = new OpenTxFirmware("opentx-x10", QObject::tr("FrSky Horus X10 / X10S"), BOARD_X10);
1242 addOpenTxFrskyOptions(firmware);
1243 registerOpenTxFirmware(firmware);
1245 /* FrSky Horus board */
1246 firmware = new OpenTxFirmware("opentx-x12s", QObject::tr("FrSky Horus X12S"), BOARD_X12S);
1247 addOpenTxFrskyOptions(firmware);
1248 firmware->addOption("pcbdev", QObject::tr("Use ONLY with first DEV pcb version"));
1249 registerOpenTxFirmware(firmware);
1251 /* 9XR-Pro */
1252 firmware = new OpenTxFirmware("opentx-9xrpro", QObject::tr("Turnigy 9XR-PRO"), BOARD_9XRPRO);
1253 firmware->addOption("heli", QObject::tr("Enable HELI menu and cyclic mix support"));
1254 firmware->addOption("nofp", QObject::tr("No flight modes"));
1255 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1256 firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
1257 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1258 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1259 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1260 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1261 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1262 firmware->addOption("bluetooth", QObject::tr("Bluetooth interface"));
1263 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1264 addOpenTxArmOptions(firmware);
1265 addOpenTxCommonOptions(firmware);
1266 registerOpenTxFirmware(firmware);
1268 /* 9XR board with M128 chip */
1269 firmware = new OpenTxFirmware("opentx-9xr128", QObject::tr("Turnigy 9XR with m128 chip"), BOARD_M128);
1270 firmware->addOptions(extr_options);
1271 firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
1272 firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
1273 firmware->addOption("nosplash", QObject::tr("No splash screen"));
1274 firmware->addOption("nofp", QObject::tr("No flight modes"));
1275 firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
1276 firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
1277 firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
1278 firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
1279 // NOT TESTED firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
1280 firmware->addOption("DSM2", QObject::tr("Support for DSM2 modules"));
1281 firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
1282 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1283 firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
1284 firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
1285 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1286 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1287 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1288 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1289 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1290 firmware->addOption("thrtrace", QObject::tr("Enable the throttle trace in Statistics"));
1291 firmware->addOption("pgbar", QObject::tr("EEprom write Progress bar"));
1292 firmware->addOption("imperial", QObject::tr("Imperial units"));
1293 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1294 addOpenTxCommonOptions(firmware);
1295 registerOpenTxFirmware(firmware);
1297 /* 9XR board */
1298 firmware = new OpenTxFirmware("opentx-9xr", QObject::tr("Turnigy 9XR"), BOARD_STOCK);
1299 firmware->addOptions(extr_options);
1300 firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
1301 firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
1302 firmware->addOption("nosplash", QObject::tr("No splash screen"));
1303 firmware->addOption("nofp", QObject::tr("No flight modes"));
1304 firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
1305 firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
1306 firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
1307 firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
1308 // NOT TESTED firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
1309 firmware->addOption("DSM2", QObject::tr("Support for DSM2 modules"));
1310 firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
1311 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1312 firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
1313 firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
1314 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1315 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1316 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1317 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1318 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1319 firmware->addOption("thrtrace", QObject::tr("Enable the throttle trace in Statistics"));
1320 firmware->addOption("pgbar", QObject::tr("EEprom write Progress bar"));
1321 firmware->addOption("imperial", QObject::tr("Imperial units"));
1322 firmware->addOption("nowshh", QObject::tr("No Winged Shadow How High support"));
1323 firmware->addOption("novario", QObject::tr("No vario support"));
1324 firmware->addOption("nogps", QObject::tr("No GPS support"));
1325 firmware->addOption("nogauges", QObject::tr("No gauges in the custom telemetry screen"));
1326 firmware->addOption("stickrev", QObject::tr("Add support for reversing stick inputs (e.g. needed for FrSky gimbals)"));
1327 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1328 addOpenTxCommonOptions(firmware);
1329 registerOpenTxFirmware(firmware);
1331 /* 9x board */
1332 firmware = new OpenTxFirmware("opentx-9x", QObject::tr("9X with stock board"), BOARD_STOCK);
1333 firmware->addOptions(ext_options);
1334 firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
1335 firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
1336 firmware->addOption("nosplash", QObject::tr("No splash screen"));
1337 firmware->addOption("nofp", QObject::tr("No flight modes"));
1338 firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
1339 firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
1340 firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
1341 firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
1342 // NOT TESTED firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
1343 firmware->addOption("DSM2", QObject::tr("Support for DSM2 modules"));
1344 firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
1345 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1346 firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
1347 firmware->addOptions(nav_options);
1348 firmware->addOption("sp22", QObject::tr("SmartieParts 2.2 Backlight support"));
1349 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1350 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1351 firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
1352 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1353 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1354 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1355 firmware->addOption("thrtrace", QObject::tr("Enable the throttle trace in Statistics"));
1356 firmware->addOption("pgbar", QObject::tr("EEprom write progress bar"));
1357 firmware->addOption("imperial", QObject::tr("Imperial units"));
1358 firmware->addOption("nowshh", QObject::tr("No Winged Shadow How High support"));
1359 firmware->addOption("novario", QObject::tr("No vario support"));
1360 firmware->addOption("nogps", QObject::tr("No GPS support"));
1361 firmware->addOption("nogauges", QObject::tr("No gauges in the custom telemetry screen"));
1362 firmware->addOption("fasoffset", QObject::tr("Allow compensating for offset errors in FrSky FAS current sensors"));
1363 firmware->addOption("stickrev", QObject::tr("Add support for reversing stick inputs (e.g. needed for FrSky gimbals)"));
1364 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1365 addOpenTxCommonOptions(firmware);
1366 registerOpenTxFirmware(firmware);
1368 /* 9x board with M128 chip */
1369 firmware = new OpenTxFirmware("opentx-9x128", QObject::tr("9X with stock board and m128 chip"), BOARD_M128);
1370 firmware->addOptions(ext_options);
1371 firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
1372 firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
1373 firmware->addOption("nosplash", QObject::tr("No splash screen"));
1374 firmware->addOption("nofp", QObject::tr("No flight modes"));
1375 firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
1376 firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
1377 firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
1378 firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
1379 // NOT TESTED firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
1380 firmware->addOption("DSM2", QObject::tr("Support for DSM2 modules"));
1381 firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
1382 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1383 firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
1384 firmware->addOptions(nav_options);
1385 firmware->addOption("sp22", QObject::tr("SmartieParts 2.2 Backlight support"));
1386 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1387 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1388 firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
1389 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1390 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1391 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1392 firmware->addOption("thrtrace", QObject::tr("Enable the throttle trace in Statistics"));
1393 firmware->addOption("pgbar", QObject::tr("EEprom write Progress bar"));
1394 firmware->addOption("imperial", QObject::tr("Imperial units"));
1395 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1396 addOpenTxCommonOptions(firmware);
1397 registerOpenTxFirmware(firmware);
1399 /* ar9x board */
1400 firmware = new OpenTxFirmware("opentx-ar9x", QObject::tr("9X with AR9X board"), BOARD_AR9X);
1401 firmware->addOption("heli", QObject::tr("Enable HELI menu and cyclic mix support"));
1402 firmware->addOption("nofp", QObject::tr("No flight modes"));
1403 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1404 firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
1405 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1406 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1407 firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
1408 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1409 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1410 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1411 firmware->addOption("bluetooth", QObject::tr("Bluetooth interface"));
1412 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1413 // firmware->addOption("rtc", QObject::tr("Optional RTC added"));
1414 // firmware->addOption("volume", QObject::tr("i2c volume control added"));
1415 addOpenTxArmOptions(firmware);
1416 addOpenTxCommonOptions(firmware);
1417 registerOpenTxFirmware(firmware);
1419 /* Sky9x board */
1420 firmware = new OpenTxFirmware("opentx-sky9x", QObject::tr("9X with Sky9x board"), BOARD_SKY9X);
1421 firmware->addOption("heli", QObject::tr("Enable HELI menu and cyclic mix support"));
1422 firmware->addOption("nofp", QObject::tr("No flight modes"));
1423 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1424 firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
1425 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1426 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1427 firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
1428 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1429 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1430 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1431 firmware->addOption("bluetooth", QObject::tr("Bluetooth interface"));
1432 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1433 addOpenTxArmOptions(firmware);
1434 addOpenTxCommonOptions(firmware);
1435 registerOpenTxFirmware(firmware);
1437 /* Gruvin9x board */
1438 firmware = new OpenTxFirmware("opentx-gruvin9x", QObject::tr("9X with Gruvin9x board"), BOARD_GRUVIN9X);
1439 firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
1440 firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
1441 firmware->addOption("nofp", QObject::tr("No flight modes"));
1442 firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
1443 firmware->addOption("sdcard", QObject::tr("Support for SD memory card"));
1444 firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
1445 firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
1446 firmware->addOptions(dsm2_options);
1447 firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
1448 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1449 firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
1450 firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
1451 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1452 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1453 firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
1454 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1455 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1456 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1457 firmware->addOption("pgbar", QObject::tr("EEprom write Progress bar"));
1458 firmware->addOption("imperial", QObject::tr("Imperial units"));
1459 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1460 addOpenTxCommonOptions(firmware);
1461 registerOpenTxFirmware(firmware);
1463 /* MEGA2560 board */
1464 firmware = new OpenTxFirmware("opentx-mega2560", QObject::tr("DIY MEGA2560 radio"), BOARD_MEGA2560);
1465 addOpenTxLcdOptions(firmware);
1466 firmware->addOption("PWR", QObject::tr("Power management by soft-off circuitry"));
1467 firmware->addOptions(ext_options);
1468 firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
1469 firmware->addOptions(dsm2_options);
1470 firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
1471 firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
1472 firmware->addOption("nofp", QObject::tr("No flight modes"));
1473 firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
1474 firmware->addOption("sdcard", QObject::tr("Support for SD memory card"));
1475 firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
1476 //firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
1477 addOpenTxVoiceOptions(firmware);
1478 firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
1479 firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
1480 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1481 firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
1482 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1483 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1484 firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
1485 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1486 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1487 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1488 firmware->addOption("pgbar", QObject::tr("EEprom write Progress bar"));
1489 firmware->addOption("imperial", QObject::tr("Imperial units"));
1490 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1491 addOpenTxCommonOptions(firmware);
1492 registerOpenTxFirmware(firmware);
1494 Firmware::setDefaultVariant(Firmware::getFirmwareForId("opentx-x9d+"));
1495 Firmware::setCurrentVariant(Firmware::getDefaultVariant());
1498 void unregisterOpenTxFirmwares()
1500 foreach (Firmware * f, Firmware::getRegisteredFirmwares()) {
1501 delete f;
1503 unregisterEEpromInterfaces();
1506 template <class T, class M>
1507 OpenTxEepromInterface * loadFromByteArray(T & dest, const QByteArray & data)
1509 foreach(OpenTxEepromInterface * eepromInterface, opentxEEpromInterfaces) {
1510 if (eepromInterface->loadFromByteArray<T, M>(dest, data)) {
1511 return eepromInterface;
1514 return NULL;
1517 template <class T, class M>
1518 bool saveToByteArray(const T & dest, QByteArray & data)
1520 Board::Type board = getCurrentBoard();
1521 foreach(OpenTxEepromInterface * eepromInterface, opentxEEpromInterfaces) {
1522 if (eepromInterface->getBoard() == board) {
1523 return eepromInterface->saveToByteArray<T, M>(dest, data);
1526 return false;
1529 OpenTxEepromInterface * loadModelFromByteArray(ModelData & model, const QByteArray & data)
1531 return loadFromByteArray<ModelData, OpenTxModelData>(model, data);
1534 OpenTxEepromInterface * loadRadioSettingsFromByteArray(GeneralSettings & settings, const QByteArray & data)
1536 return loadFromByteArray<GeneralSettings, OpenTxGeneralData>(settings, data);
1539 bool writeModelToByteArray(const ModelData & model, QByteArray & data)
1541 return saveToByteArray<ModelData, OpenTxModelData>(model, data);
1544 bool writeRadioSettingsToByteArray(const GeneralSettings & settings, QByteArray & data)
1546 return saveToByteArray<GeneralSettings, OpenTxGeneralData>(settings, data);