[Companion] Radio profile/current firmware handling: (#4737)
[opentx.git] / companion / src / firmwares / opentx / opentxinterface.cpp
blob7f9857cd9ef766dfe2bb5a2c13d7e4913eb0ea6c
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>
30 using namespace Board;
32 #define OPENTX_FIRMWARE_DOWNLOADS "http://downloads-22.open-tx.org/firmware"
33 #define OPENTX_NIGHT_FIRMWARE_DOWNLOADS "http://downloads-22.open-tx.org/nightly/firmware"
35 #define FILE_TYP_GENERAL 1
36 #define FILE_TYP_MODEL 2
38 /// fileId of general file
39 #define FILE_GENERAL 0
40 /// convert model number 0..MAX_MODELS-1 int fileId
41 #define FILE_MODEL(n) (1+n)
43 template<typename T, size_t N>
44 inline
45 size_t SizeOfArray(T(&)[N])
47 return N;
50 OpenTxEepromInterface::OpenTxEepromInterface(OpenTxFirmware * firmware):
51 EEPROMInterface(firmware->getBoard()),
52 efile(new RleFile()),
53 firmware(firmware)
57 OpenTxEepromInterface::~OpenTxEepromInterface()
59 delete efile;
62 const char * OpenTxEepromInterface::getName()
64 switch (board) {
65 case BOARD_STOCK:
66 return "OpenTX for 9X board";
67 case BOARD_M128:
68 return "OpenTX for M128 / 9X board";
69 case BOARD_MEGA2560:
70 return "OpenTX for MEGA2560 board";
71 case BOARD_GRUVIN9X:
72 return "OpenTX for Gruvin9x board / 9X";
73 case BOARD_TARANIS_X9D:
74 return "OpenTX for FrSky Taranis X9D";
75 case BOARD_TARANIS_X9DP:
76 return "OpenTX for FrSky Taranis X9D+";
77 case BOARD_TARANIS_X9E:
78 return "OpenTX for FrSky Taranis X9E";
79 case BOARD_TARANIS_X7:
80 return "OpenTX for FrSky Taranis X7";
81 case BOARD_SKY9X:
82 return "OpenTX for Sky9x board / 9X";
83 case BOARD_9XRPRO:
84 return "OpenTX for 9XR-PRO";
85 case BOARD_AR9X:
86 return "OpenTX for ar9x board / 9X";
87 case BOARD_FLAMENCO:
88 return "OpenTX for Flamenco experimental";
89 case BOARD_X12S:
90 return "OpenTX for FrSky Horus";
91 case BOARD_X10:
92 return "OpenTX for FrSky X10";
93 default:
94 return "OpenTX for an unknown board";
98 uint32_t OpenTxEepromInterface::getFourCC()
100 switch (board) {
101 case BOARD_X12S:
102 case BOARD_X10:
103 return 0x3478746F;
104 case BOARD_TARANIS_X7:
105 return 0x3678746F;
106 case BOARD_TARANIS_X9E:
107 return 0x3578746F;
108 case BOARD_TARANIS_X9D:
109 case BOARD_TARANIS_X9DP:
110 return 0x3378746F;
111 case BOARD_SKY9X:
112 case BOARD_AR9X:
113 return 0x3278746F;
114 case BOARD_MEGA2560:
115 case BOARD_GRUVIN9X:
116 return 0x3178746F;
117 default:
118 return 0;
122 bool OpenTxEepromInterface::loadRadioSettingsFromRLE(GeneralSettings & settings, RleFile * rleFile, uint8_t version)
124 QByteArray data(sizeof(settings), 0); // GeneralSettings should be always bigger than the EEPROM struct
125 OpenTxGeneralData open9xSettings(settings, board, version);
126 efile->openRd(FILE_GENERAL);
127 int size = rleFile->readRlc2((uint8_t *)data.data(), data.size());
128 if (size) {
129 open9xSettings.Import(data);
130 return checkVariant(settings.version, settings.variant);
132 else {
133 std::cout << " error when loading general settings";
134 return false;
138 bool OpenTxEepromInterface::loadModelFromRLE(ModelData & model, RleFile * rleFile, unsigned int index, uint8_t version, uint32_t variant)
140 QByteArray data(sizeof(model), 0); // ModelData should be always bigger than the EEPROM struct
141 rleFile->openRd(FILE_MODEL(index));
142 int size = rleFile->readRlc2((uint8_t *)data.data(), data.size());
143 if (size) {
144 if (loadFromByteArray<ModelData, OpenTxModelData>(model, data, version, variant)) {
145 model.used = true;
148 else {
149 model.clear();
151 return true;
154 template <class T, class M>
155 bool OpenTxEepromInterface::saveToByteArray(const T & src, QByteArray & data, uint8_t version)
157 if (version == 0) {
158 version = getLastDataVersion(getBoard());
160 QByteArray raw;
161 T srcCopy(src); // work on a copy of radio data, because Export() will modify it!
162 M manager(srcCopy, board, version, 0);
163 // manager.Dump();
164 manager.Export(raw);
165 data.resize(8);
166 *((uint32_t*)&data.data()[0]) = getFourCC();
167 data[4] = version;
168 data[5] = 'M';
169 *((uint16_t*)&data.data()[6]) = raw.size();
170 data.append(raw);
171 return true;
174 template <class T, class M>
175 bool OpenTxEepromInterface::loadFromByteArray(T & dest, const QByteArray & data, uint8_t version, uint32_t variant)
177 M manager(dest, board, version, variant);
178 if (manager.Import(data) != 0) {
179 return false;
181 // manager.Dump(); // Dumps the structure so that it's easy to check with firmware datastructs.h
182 return true;
185 template <class T, class M>
186 bool OpenTxEepromInterface::loadFromByteArray(T & dest, const QByteArray & data)
188 uint32_t fourcc = *((uint32_t*)&data.data()[0]);
189 if (getFourCC() != fourcc) {
190 if (IS_HORUS(board) && fourcc == 0x3178396F) {
191 qDebug() << QString().sprintf("%s: Deprecated fourcc used %x vs %x", getName(), fourcc, getFourCC());
193 else {
194 qDebug() << QString().sprintf("%s: Wrong fourcc %x vs %x", getName(), fourcc, getFourCC());
195 return false;
198 qDebug() << QString().sprintf("%s: OK", getName());
199 uint8_t version = data[4];
200 QByteArray raw = data.right(data.size() - 8);
201 return loadFromByteArray<T, M>(dest, raw, version);
204 unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t * eeprom, int size)
206 std::cout << "trying " << getName() << " import...";
208 std::bitset<NUM_ERRORS> errors;
210 if (size != Boards::getEEpromSize(board)) {
211 if (size == 4096) {
212 int notnull = false;
213 for (int i = 2048; i < 4096; i++) {
214 if (eeprom[i] != 255) {
215 notnull = true;
218 if (notnull) {
219 std::cout << " wrong size (" << size << ")\n";
220 errors.set(WRONG_SIZE);
221 return errors.to_ulong();
223 else {
224 errors.set(HAS_WARNINGS);
225 errors.set(WARNING_WRONG_FIRMWARE);
226 size = 2048;
229 else {
230 std::cout << " wrong size (" << size << "/" << Boards::getEEpromSize(board) << ")\n";
231 errors.set(WRONG_SIZE);
232 return errors.to_ulong();
236 if (!efile->EeFsOpen((uint8_t *) eeprom, size, board)) {
237 std::cout << " wrong file system\n";
238 errors.set(WRONG_FILE_SYSTEM);
239 return errors.to_ulong();
242 efile->openRd(FILE_GENERAL);
244 uint8_t version;
245 if (efile->readRlc2(&version, 1) != 1) {
246 std::cout << " no\n";
247 errors.set(UNKNOWN_ERROR);
248 return errors.to_ulong();
251 std::cout << " version " << (unsigned int) version;
253 EepromLoadErrors version_error = checkVersion(version);
254 if (version_error == OLD_VERSION) {
255 errors.set(version_error);
256 errors.set(HAS_WARNINGS);
257 ShowEepromWarnings(NULL, QObject::tr("Warning"), errors.to_ulong());
259 else if (version_error == NOT_OPENTX) {
260 std::cout << " not open9x\n";
261 errors.set(version_error);
262 return errors.to_ulong();
265 if (!loadRadioSettingsFromRLE(radioData.generalSettings, efile, version)) {
266 std::cout << " ko\n";
267 errors.set(UNKNOWN_ERROR);
268 return errors.to_ulong();
271 std::cout << " variant " << radioData.generalSettings.variant;
272 if (getCurrentFirmware()->getCapability(Models) == 0) {
273 radioData.models.resize(firmware->getCapability(Models));
275 for (int i = 0; i < firmware->getCapability(Models); i++) {
276 if (!loadModelFromRLE(radioData.models[i], efile, i, version, radioData.generalSettings.variant)) {
277 std::cout << " ko\n";
278 errors.set(UNKNOWN_ERROR);
279 if (getCurrentFirmware()->getCapability(Models) == 0) {
280 radioData.models.resize(i);
282 return errors.to_ulong();
285 std::cout << " ok\n";
286 errors.set(ALL_OK);
287 return errors.to_ulong();
290 uint8_t OpenTxEepromInterface::getLastDataVersion(Board::Type board)
292 switch (board) {
293 case BOARD_STOCK:
294 return 216;
295 case BOARD_GRUVIN9X:
296 case BOARD_MEGA2560:
297 case BOARD_M128:
298 return 217;
299 default:
300 return 218;
304 void OpenTxEepromInterface::showErrors(const QString & title, const QStringList & errors)
306 QString msg;
307 if (errors.empty()) {
308 msg = QObject::tr("Unknown error");
310 else {
311 int noErrorsToDisplay = std::min((int)errors.size(), 10);
312 for (int n = 0; n < noErrorsToDisplay; n++) {
313 msg += " -" + errors.at(n) + "\n";
315 if (noErrorsToDisplay < errors.size()) {
316 msg += QObject::tr(" ... plus %1 errors").arg(errors.size() - noErrorsToDisplay) + "\n" + msg;
320 QMessageBox::warning(NULL,
321 QObject::tr("Error"),
322 title + "\n" + msg);
325 int OpenTxEepromInterface::save(uint8_t * eeprom, const RadioData & radioData, uint8_t version, uint32_t variant)
327 // TODO QMessageBox::warning should not be called here
329 if (version == 0) {
330 version = getLastDataVersion(board);
333 int size = Boards::getEEpromSize(board);
335 efile->EeFsCreate(eeprom, size, board, version);
337 if (board == BOARD_M128) {
338 variant |= M128_VARIANT;
340 else if (IS_TARANIS_X9E(board)) {
341 variant |= TARANIS_X9E_VARIANT;
343 else if (IS_TARANIS_X7(board)) {
344 variant |= TARANIS_X7_VARIANT;
347 OpenTxGeneralData generator((GeneralSettings &)radioData.generalSettings, board, version, variant);
348 // generator.Dump();
349 QByteArray data;
350 generator.Export(data);
351 int sz = efile->writeRlc2(FILE_GENERAL, FILE_TYP_GENERAL, (const uint8_t *)data.constData(), data.size());
352 if (sz == 0 || generator.errors().count() > 0) {
353 showErrors(QObject::tr("Cannot write radio settings"), generator.errors());
354 return 0;
357 for (int i = 0; i < getCurrentFirmware()->getCapability(Models); i++) {
358 if (!radioData.models[i].isEmpty()) {
359 OpenTxModelData generator((ModelData &)radioData.models[i], board, version, variant);
360 // generator.Dump();
361 QByteArray data;
362 generator.Export(data);
363 int sz = efile->writeRlc2(FILE_MODEL(i), FILE_TYP_MODEL, (const uint8_t *)data.constData(), data.size());
364 if (sz == 0 || generator.errors().count() > 0) {
365 showErrors(QObject::tr("Cannot write model %1").arg(radioData.models[i].name), generator.errors());
366 return 0;
371 return size;
374 int OpenTxEepromInterface::getSize(const ModelData &model)
376 if (IS_SKY9X(board))
377 return 0;
379 if (model.isEmpty())
380 return 0;
382 QByteArray tmp(Boards::getEEpromSize(Board::BOARD_UNKNOWN), 0);
383 efile->EeFsCreate((uint8_t *) tmp.data(), Boards::getEEpromSize(Board::BOARD_UNKNOWN), board, 255/*version max*/);
385 OpenTxModelData open9xModel((ModelData &) model, board, 255/*version max*/, getCurrentFirmware()->getVariantNumber());
387 QByteArray eeprom;
388 open9xModel.Export(eeprom);
389 int sz = efile->writeRlc2(0, FILE_TYP_MODEL, (const uint8_t *) eeprom.constData(), eeprom.size());
390 if (sz != eeprom.size()) {
391 return -1;
393 return efile->size(0);
396 int OpenTxEepromInterface::getSize(const GeneralSettings &settings)
398 if (IS_SKY9X(board))
399 return 0;
401 QByteArray tmp(Boards::getEEpromSize(Board::BOARD_UNKNOWN), 0);
402 efile->EeFsCreate((uint8_t *) tmp.data(), Boards::getEEpromSize(Board::BOARD_UNKNOWN), board, 255);
404 OpenTxGeneralData open9xGeneral((GeneralSettings &) settings, board, 255, getCurrentFirmware()->getVariantNumber());
405 // open9xGeneral.Dump();
407 QByteArray eeprom;
408 open9xGeneral.Export(eeprom);
409 int sz = efile->writeRlc2(0, FILE_TYP_GENERAL, (const uint8_t *) eeprom.constData(), eeprom.size());
410 if (sz != eeprom.size()) {
411 return -1;
413 return efile->size(0);
416 Firmware * OpenTxFirmware::getFirmwareVariant(const QString &id)
418 if (id == getId()) {
419 return this;
421 else if (id.contains(getId() + "-") || (!id.contains("-") && id.contains(getId()))) {
422 Firmware * result = new OpenTxFirmware(id, this);
423 // TODO result.variant = firmware->getVariant(id);
424 return result;
426 else {
427 return NULL;
431 int OpenTxFirmware::getCapability(::Capability capability)
433 switch (capability) {
434 case Models:
435 if (IS_HORUS(board))
436 return 0;
437 else if (IS_ARM(board))
438 return 60;
439 else if (board == BOARD_M128)
440 return 30;
441 else if (IS_2560(board))
442 return 30;
443 else
444 return 16;
445 case Imperial:
446 if (IS_ARM(board))
447 return 0;
448 else
449 return id.contains("imperial") ? 1 : 0;
450 case ModelImage:
451 return (board == BOARD_TARANIS_X9D || IS_TARANIS_PLUS(board) || IS_HORUS(board));
452 case HasBeeper:
453 return (!IS_ARM(board));
454 case HasPxxCountry:
455 return 1;
456 case HasGeneralUnits:
457 if (IS_ARM(board))
458 return 1;
459 else
460 return 0;
461 case HasNegAndSwitches:
462 return IS_ARM(board);
463 case PPMExtCtrl:
464 return 1;
465 case PPMFrameLength:
466 return 40;
467 case FlightModes:
468 if (IS_ARM(board))
469 return 9;
470 else if (IS_2560(board))
471 return 6;
472 else
473 return 5;
474 case FlightModesHaveFades:
475 return 1;
476 case Heli:
477 if (IS_HORUS_OR_TARANIS(board))
478 return id.contains("noheli") ? 0 : 1;
479 else
480 return id.contains("heli") ? 1 : 0;
481 case Gvars:
482 if (IS_HORUS_OR_TARANIS(board))
483 return id.contains("nogvars") ? 0 : 9;
484 else if (id.contains("gvars"))
485 return IS_ARM(board) ? 9 : 5;
486 else
487 return 0;
488 case ModelName:
489 return (IS_HORUS(board) ? 15 : (HAS_LARGE_LCD(board) ? 12 : 10));
490 case FlightModesName:
491 return (IS_HORUS_OR_TARANIS(board) ? 10 : 6);
492 case GvarsName:
493 return (IS_9X(board) ? 0 : 3);
494 case GvarsInCS:
495 case HasFAIMode:
496 return 1;
497 case GvarsAreNamed:
498 case GvarsFlightModes:
499 return ((IS_ARM(board) || IS_2560(board)) ? 1 : 0);
500 case Mixes:
501 return (IS_ARM(board) ? 64 : 32);
502 case OffsetWeight:
503 return (IS_ARM(board) ? 500 : 245);
504 case Timers:
505 return (IS_ARM(board) ? 3 : 2);
506 case TimersName:
507 if (HAS_LARGE_LCD(board))
508 return 8;
509 else if (IS_ARM(board))
510 return 3;
511 else
512 return 0;
513 case PermTimers:
514 return (IS_2560(board) || IS_ARM(board));
515 case SwitchesPositions:
516 if (IS_HORUS_OR_TARANIS(board))
517 return getBoardCapability(board, Board::Switches) * 3;
518 else
519 return 9;
520 case CustomFunctions:
521 if (IS_ARM(board))
522 return 64;
523 else if (IS_2560(board) || board == BOARD_M128)
524 return 24;
525 else
526 return 16;
527 case SafetyChannelCustomFunction:
528 return id.contains("nooverridech") ? 0 : 1;
529 case LogicalSwitches:
530 if (IS_ARM(board))
531 return 64;
532 else
533 return 12;
534 case CustomAndSwitches:
535 if (IS_ARM(board))
536 return getCapability(LogicalSwitches);
537 else
538 return 15/*4bits*/- 9/*sw positions*/;
539 case LogicalSwitchesExt:
540 return (IS_ARM(board) ? true : false);
541 case RotaryEncoders:
542 if (board == BOARD_GRUVIN9X)
543 return 2;
544 else if (IS_SKY9X(board))
545 return 1;
546 else
547 return 0;
548 case Outputs:
549 return (IS_ARM(board) ? 32 : 16);
550 case NumCurvePoints:
551 return (IS_ARM(board) ? 512 : 104);
552 case VoicesAsNumbers:
553 return (IS_ARM(board) ? 0 : 1);
554 case VoicesMaxLength:
555 return (IS_ARM(board) ? (IS_TARANIS_X9(board) ? 8 : 6) : 0);
556 case MultiLangVoice:
557 return (IS_ARM(board) ? 1 : 0);
558 case SoundPitch:
559 return 1;
560 case Haptic:
561 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"));
562 case ModelTrainerEnable:
563 if (IS_HORUS_OR_TARANIS(board))
564 return 1;
565 else
566 return 0;
567 case MaxVolume:
568 return (IS_ARM(board) ? 23 : 7);
569 case HasSoundMixer:
570 return (IS_ARM(board) ? 1 : 0);
571 case ExtraInputs:
572 return 1;
573 case TrimsRange:
574 return 125;
575 case ExtendedTrimsRange:
576 return 500;
577 case Simulation:
578 return 1;
579 case NumCurves:
580 return (HAS_LARGE_LCD(board) ? 32 : (IS_ARM(board) ? 16 : 8));
581 case HasMixerNames:
582 return (IS_ARM(board) ? (IS_TARANIS_X9(board) ? 8 : 6) : false);
583 case HasExpoNames:
584 return (IS_ARM(board) ? (IS_TARANIS_X9(board) ? 8 : 6) : false);
585 case HasNoExpo:
586 return (IS_HORUS_OR_TARANIS(board) ? false : true);
587 case ChannelsName:
588 return (IS_ARM(board) ? (HAS_LARGE_LCD(board) ? 6 : 4) : 0);
589 case HasCvNames:
590 return (IS_HORUS_OR_TARANIS(board) ? 1 : 0);
591 case Telemetry:
592 if (IS_2560(board) || IS_ARM(board) || id.contains("frsky") || id.contains("telemetrez"))
593 return TM_HASTELEMETRY | TM_HASOFFSET | TM_HASWSHH;
594 else
595 return 0;
596 case TelemetryBars:
597 return 1;
598 case TelemetryCustomScreens:
599 if (IS_HORUS(board))
600 return 0;
601 else
602 return IS_ARM(board) ? 4 : 2;
603 case TelemetryCustomScreensFieldsPerLine:
604 return HAS_LARGE_LCD(board) ? 3 : 2;
605 case NoTelemetryProtocol:
606 return IS_HORUS_OR_TARANIS(board) ? 1 : 0;
607 case TelemetryUnits:
608 return 0;
609 case TelemetryMaxMultiplier:
610 return (IS_ARM(board) ? 32 : 8);
611 case PPMCenter:
612 return (IS_HORUS_OR_TARANIS(board) ? 500 : (id.contains("ppmca") ? 125 : 0));
613 case PPMUnitMicroseconds:
614 return id.contains("ppmus") ? 1 : 0;
615 case SYMLimits:
616 return 1;
617 case OptrexDisplay:
618 return (board == BOARD_SKY9X ? true : false);
619 case HasVario:
620 return 1;
621 case HasVarioSink:
622 return ((IS_2560(board) || IS_ARM(board)) ? true : false);
623 case HasFailsafe:
624 return (IS_ARM(board) ? 32 : 0);
625 case NumModules:
626 return (IS_ARM(board) ? 2 : 1);
627 case HasPPMStart:
628 return (IS_ARM(board) ? true : false);
629 case HastxCurrentCalibration:
630 return (IS_SKY9X(board) ? true : false);
631 case HasVolume:
632 return (IS_ARM(board) ? true : false);
633 case HasBrightness:
634 return (IS_ARM(board) ? true : false);
635 case PerModelTimers:
636 return 1;
637 case SlowScale:
638 return (IS_ARM(board) ? 10 : 2);
639 case SlowRange:
640 return (IS_ARM(board) ? 250 : 15);
641 case CSFunc:
642 return 18;
643 case HasSDLogs:
644 return ((IS_2560(board) || IS_ARM(board)) ? true : false);
645 case LcdWidth:
646 if (IS_HORUS(board))
647 return 480;
648 else if (IS_TARANIS_X7(board))
649 return 128;
650 else if (IS_TARANIS(board))
651 return 212;
652 else
653 return 128;
654 case LcdHeight:
655 if (IS_HORUS(board))
656 return 272;
657 else
658 return 64;
659 case LcdDepth:
660 if (IS_HORUS(board))
661 return 16;
662 else if (IS_TARANIS_X7(board))
663 return 1;
664 else if (IS_TARANIS(board))
665 return 4;
666 else
667 return 1;
668 case GetThrSwitch:
669 return (IS_HORUS_OR_TARANIS(board) ? SWITCH_SF1 : SWITCH_THR);
670 case HasDisplayText:
671 return IS_ARM(board) ? 1 : 0;
672 case HasTopLcd:
673 return IS_TARANIS_X9E(board) ? 1 : 0;
674 case GlobalFunctions:
675 return IS_ARM(board) ? 64 : 0;
676 case VirtualInputs:
677 return IS_ARM(board) ? 32 : 0;
678 case InputsLength:
679 return HAS_LARGE_LCD(board) ? 4 : 3;
680 case TrainerInputs:
681 return IS_ARM(board) ? 16 : 8;
682 case RtcTime:
683 return IS_ARM(board) || IS_2560(board) ? 1 : 0;
684 case LuaScripts:
685 return IS_HORUS_OR_TARANIS(board) && id.contains("lua") ? 7 : 0;
686 case LuaInputsPerScript:
687 return IS_HORUS_OR_TARANIS(board) ? 10 : 0;
688 case LuaOutputsPerScript:
689 return IS_HORUS_OR_TARANIS(board) ? 6 : 0;
690 case LimitsPer1000:
691 case EnhancedCurves:
692 return IS_ARM(board);
693 case HasFasOffset:
694 return (IS_STOCK(board) ? false : true);
695 case HasMahPersistent:
696 return (IS_ARM(board) ? true : false);
697 case MultiposPots:
698 return IS_HORUS_OR_TARANIS(board) ? 3 : 0;
699 case MultiposPotsPositions:
700 return IS_HORUS_OR_TARANIS(board) ? 6 : 0;
701 case SimulatorVariant:
702 if (board == BOARD_STOCK)
703 return SIMU_STOCK_VARIANTS;
704 else if (board == BOARD_M128)
705 return SIMU_M128_VARIANTS;
706 else if (IS_TARANIS_X9E(board))
707 return TARANIS_X9E_VARIANT;
708 else if (IS_TARANIS_X7(board))
709 return TARANIS_X7_VARIANT;
710 else
711 return 0;
712 case MavlinkTelemetry:
713 return id.contains("mavlink") ? 1 : 0;
714 case SportTelemetry:
715 return IS_ARM(board) ? 1 : 0;
716 case HasInputDiff:
717 case HasMixerExpo:
718 return (IS_HORUS_OR_TARANIS(board) ? true : false);
719 case HasBatMeterRange:
720 return (IS_HORUS_OR_TARANIS(board) ? true : id.contains("battgraph"));
721 case DangerousFunctions:
722 return id.contains("danger") ? 1 : 0;
723 case HasModelCategories:
724 return IS_HORUS(board);
725 default:
726 return 0;
730 QString OpenTxFirmware::getAnalogInputName(unsigned int index)
732 if ((int)index < getBoardCapability(board, Board::Sticks)) {
733 const QString sticks[] = {
734 QObject::tr("Rud"),
735 QObject::tr("Ele"),
736 QObject::tr("Thr"),
737 QObject::tr("Ail")
739 return sticks[index];
742 index -= getBoardCapability(board, Board::Sticks);
744 if (IS_9X(board) || IS_2560(board) || IS_SKY9X(board)) {
745 const QString pots[] = {
746 QObject::tr("P1"),
747 QObject::tr("P2"),
748 QObject::tr("P3")
750 return CHECK_IN_ARRAY(pots, index);
752 else if (IS_TARANIS_X9E(board)) {
753 const QString pots[] = {
754 QObject::tr("F1"),
755 QObject::tr("F2"),
756 QObject::tr("F3"),
757 QObject::tr("F4"),
758 QObject::tr("S1"),
759 QObject::tr("S2"),
760 QObject::tr("LS"),
761 QObject::tr("RS")
763 return CHECK_IN_ARRAY(pots, index);
765 else if (IS_TARANIS(board)) {
766 const QString pots[] = {
767 QObject::tr("S1"),
768 QObject::tr("S2"),
769 QObject::tr("S3"),
770 QObject::tr("LS"),
771 QObject::tr("RS")
773 return CHECK_IN_ARRAY(pots, index);
775 else if (IS_HORUS(board)) {
776 const QString pots[] = {
777 QObject::tr("S1"),
778 QObject::tr("6P"),
779 QObject::tr("S2"),
780 QObject::tr("L1"),
781 QObject::tr("L2"),
782 QObject::tr("LS"),
783 QObject::tr("RS"),
784 QObject::tr("JSx"),
785 QObject::tr("JSy")
787 return CHECK_IN_ARRAY(pots, index);
789 else {
790 return "???";
794 QTime OpenTxFirmware::getMaxTimerStart()
796 if (IS_HORUS_OR_TARANIS(board))
797 return QTime(23, 59, 59);
798 else if (IS_ARM(board))
799 return QTime(8, 59, 59);
800 else
801 return QTime(0, 59, 59);
804 int OpenTxFirmware::isAvailable(PulsesProtocol proto, int port)
806 if (IS_HORUS_OR_TARANIS(board)) {
807 switch (port) {
808 case 0:
809 switch (proto) {
810 case PULSES_OFF:
811 case PULSES_PXX_XJT_X16:
812 case PULSES_PXX_XJT_LR12:
813 return 1;
814 case PULSES_PXX_XJT_D8:
815 return id.contains("eu") ? 0 : 1;
816 case PULSES_PPM:
817 return id.contains("internalppm") ? 1 : 0;
818 default:
819 return 0;
821 break;
822 case 1:
823 switch (proto) {
824 case PULSES_OFF:
825 case PULSES_PPM:
826 case PULSES_PXX_XJT_X16:
827 case PULSES_PXX_XJT_D8:
828 case PULSES_PXX_XJT_LR12:
829 //case PULSES_PXX_DJT: // Unavailable for now
830 case PULSES_LP45:
831 case PULSES_DSM2:
832 case PULSES_DSMX:
833 case PULSES_CROSSFIRE:
834 return 1;
835 case PULSES_MULTIMODULE:
836 return id.contains("multimodule") ? 1 : 0;
837 default:
838 return 0;
840 break;
841 case -1:
842 switch (proto) {
843 case PULSES_PPM:
844 return 1;
845 default:
846 return 0;
848 break;
849 default:
850 return 0;
853 else if (IS_SKY9X(board)) {
854 switch (port) {
855 case 0:
856 switch (proto) {
857 case PULSES_PPM:
858 case PULSES_PXX_XJT_X16:
859 case PULSES_PXX_XJT_D8:
860 case PULSES_PXX_XJT_LR12:
861 case PULSES_LP45:
862 case PULSES_DSM2:
863 case PULSES_DSMX:
864 return 1;
865 case PULSES_MULTIMODULE:
866 return id.contains("multimodule") ? 1 : 0;
867 default:
868 return 0;
870 break;
871 case 1:
872 switch (proto) {
873 case PULSES_PPM:
874 return 1;
875 default:
876 return 0;
878 break;
879 default:
880 return 0;
883 else {
884 switch (proto) {
885 case PULSES_PPM:
886 case PULSES_DSMX:
887 case PULSES_LP45:
888 case PULSES_DSM2:
889 // case PULSES_PXX_DJT: // Unavailable for now
890 case PULSES_PPM16:
891 case PULSES_PPMSIM:
892 return 1;
893 default:
894 return 0;
899 template<typename T, size_t SIZE>
900 size_t getSizeA(T (&)[SIZE])
902 return SIZE;
905 EepromLoadErrors OpenTxEepromInterface::checkVersion(unsigned int version)
907 switch (version) {
908 case 201:
909 // first version
910 case 202:
911 // channel order is now always RUD - ELE - THR - AIL
912 // changes in timers
913 // ppmFrameLength added
914 // thrTraceSrc added
915 case 203:
916 // mixers changed (for the trims use for change the offset of a mix)
917 // telemetry offset raised to -127 +127
918 // function switches now have a param on 4 bits
919 case 204:
920 // telemetry changes (bars)
921 case 205:
922 // mixer changes (differential, negative curves)...
923 // case 206:
924 case 207:
925 // V4: Rotary Encoders position in FlightModes
926 case 208:
927 // Trim value in 16bits
928 // FrSky A1/A2 offset on 12bits
929 // ARM: More Mixers / Expos / CSW / FSW / CHNOUT
930 case 209:
931 // Add TrmR, TrmE, TrmT, TrmA as Mix sources
932 // Trims are now OFF / ON / Rud / Ele / Thr / Ail
933 case 210:
934 // Add names in Mixes / Expos
935 // Add a new telemetry screen
936 // Add support for Play Track <filename>
937 case 211:
938 // Curves big change
939 case 212:
940 // Big changes in mixers / limitse
941 case 213:
942 // GVARS / Variants introduction
943 case 214:
944 // Massive EEPROM change!
945 case 215:
946 // M128 revert because too much RAM used!
947 case 216:
948 // A lot of things (first github release)
949 case 217:
950 // 3 logical switches removed on M128 / gruvin9x boards
951 return OLD_VERSION;
952 case 218:
953 break;
954 default:
955 return NOT_OPENTX;
958 return ALL_OK;
961 bool OpenTxEepromInterface::checkVariant(unsigned int version, unsigned int variant)
963 if (board == BOARD_M128 && !(variant & M128_VARIANT)) {
964 if (version == 212) {
965 uint8_t tmp[1000];
966 for (int i = 1; i < 31; i++) {
967 efile->openRd(i);
968 int sz = efile->readRlc2(tmp, sizeof(tmp));
969 if (sz == 849) {
970 std::cout << " warning: M128 variant not set (but model size seems ok)";
971 return true;
975 std::cout << " wrong variant (" << variant << ")";
976 return false;
978 else if (IS_TARANIS_X9E(board)) {
979 if (variant != TARANIS_X9E_VARIANT) {
980 std::cout << " wrong variant (" << variant << ")";
981 return false;
984 else if (IS_TARANIS_X7(board)) {
985 if (variant != TARANIS_X7_VARIANT) {
986 std::cout << " wrong variant (" << variant << ")";
987 return false;
990 else if (IS_TARANIS(board)) {
991 if (variant != 0) {
992 std::cout << " wrong variant (" << variant << ")";
993 return false;
997 return true;
1000 bool
1001 OpenTxEepromInterface::loadModelFromBackup(ModelData & model, const uint8_t * data, unsigned int size, uint8_t version, uint32_t variant)
1003 QByteArray backupData((char *) data, size);
1004 QByteArray modelData;
1005 if (IS_SKY9X(board)) {
1006 modelData = QByteArray((char *) data, size);
1008 else {
1009 importRlc(modelData, backupData);
1011 if (modelData.size()) {
1012 if (loadFromByteArray<ModelData, OpenTxModelData>(model, modelData, version, variant)) {
1013 model.used = true;
1014 return true;
1017 model.clear();
1018 return false;
1021 unsigned long OpenTxEepromInterface::loadBackup(RadioData &radioData, const uint8_t * eeprom, int esize, int index)
1023 std::bitset<NUM_ERRORS> errors;
1025 std::cout << "trying " << getName() << " backup import...";
1027 if (esize < 8 || memcmp(eeprom, "o9x", 3) != 0) {
1028 std::cout << " no\n";
1029 errors.set(WRONG_SIZE);
1030 return errors.to_ulong();
1033 Type backupBoard = (Type) -1;
1034 switch (eeprom[3]) {
1035 case 0x33:
1036 backupBoard = BOARD_TARANIS_X9D;
1037 break;
1038 case 0x32:
1039 backupBoard = BOARD_SKY9X;
1040 break;
1041 case 0x31:
1042 backupBoard = BOARD_GRUVIN9X;
1043 break;
1044 default:
1045 std::cout << " unknown board\n";
1046 errors.set(UNKNOWN_BOARD);
1047 return errors.to_ulong();
1050 if (backupBoard != board) {
1051 std::cout << " not right board\n";
1052 errors.set(WRONG_BOARD);
1053 return errors.to_ulong();
1056 uint8_t version = eeprom[4];
1057 uint8_t bcktype = eeprom[5];
1058 uint16_t size = ((uint16_t) eeprom[7] << 8) + eeprom[6];
1059 uint16_t variant = ((uint16_t) eeprom[9] << 8) + eeprom[8];
1061 std::cout << " version " << (unsigned int) version << " ";
1063 EepromLoadErrors version_error = checkVersion(version);
1064 if (version_error == OLD_VERSION) {
1065 errors.set(version_error);
1066 errors.set(HAS_WARNINGS);
1068 else if (version_error == NOT_OPENTX) {
1069 std::cout << " not open9x\n";
1070 errors.set(version_error);
1071 return errors.to_ulong();
1074 if (size > esize - 8) {
1075 std::cout << " wrong size\n";
1076 errors.set(WRONG_SIZE);
1077 return errors.to_ulong();
1080 if (bcktype == 'M') {
1081 if (!loadModelFromBackup(radioData.models[index], &eeprom[8], size, version, variant)) {
1082 std::cout << " ko\n";
1083 errors.set(UNKNOWN_ERROR);
1084 return errors.to_ulong();
1087 else {
1088 std::cout << " backup type not supported\n";
1089 errors.set(BACKUP_NOT_SUPPORTED);
1090 return errors.to_ulong();
1093 std::cout << " ok\n";
1094 errors.set(ALL_OK);
1095 return errors.to_ulong();
1098 QString OpenTxFirmware::getFirmwareBaseUrl()
1100 #if defined(ALLOW_NIGHTLY_BUILDS)
1101 return (g.useFirmwareNightlyBuilds() ? OPENTX_NIGHT_FIRMWARE_DOWNLOADS : OPENTX_FIRMWARE_DOWNLOADS);
1102 #else
1103 return OPENTX_FIRMWARE_DOWNLOADS;
1104 #endif
1107 QString OpenTxFirmware::getFirmwareUrl()
1109 QString url = getFirmwareBaseUrl();
1110 QByteArray data = QUrl::toPercentEncoding(id);
1112 if (IS_ARM(board))
1113 url.append(QString("/getfw.php?fw=%1.bin").arg((QString) data));
1114 else
1115 url.append(QString("/getfw.php?fw=%1.hex").arg((QString) data));
1116 return url;
1119 QString OpenTxFirmware::getReleaseNotesUrl()
1121 QString url = getFirmwareBaseUrl();
1122 url.append("/releasenotes.txt");
1123 return url;
1126 QString OpenTxFirmware::getStampUrl()
1128 QString url = getFirmwareBaseUrl();
1129 url.append("/stamp-opentx.txt");
1130 return url;
1133 void addOpenTxCommonOptions(OpenTxFirmware * firmware)
1135 firmware->addOption("ppmus", QObject::tr("Channel values displayed in us"));
1136 firmware->addOption("nooverridech", QObject::tr("No OverrideCH functions available"));
1137 Option fai_options[] = {{"faichoice", QObject::tr("Possibility to enable FAI MODE (no telemetry) at field")},
1138 {"faimode", QObject::tr("FAI MODE (no telemetry) always enabled")},
1139 {NULL}};
1140 firmware->addOptions(fai_options);
1143 void addOpenTxArmOptions(OpenTxFirmware * firmware)
1145 firmware->addOption("multimodule", QObject::tr("Support for the DIY-Multiprotocol-TX-Module"));
1146 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"));
1149 void addOpenTxFrskyOptions(OpenTxFirmware * firmware)
1151 addOpenTxCommonOptions(firmware);
1152 addOpenTxArmOptions(firmware);
1153 firmware->addOption("noheli", QObject::tr("Disable HELI menu and cyclic mix support"));
1154 firmware->addOption("nogvars", QObject::tr("Disable Global variables"));
1155 firmware->addOption("lua", QObject::tr("Support for Lua model scripts"));
1156 firmware->addOption("luac", QObject::tr("Enable Lua compiler"));
1157 Option usb_options[] = {{"massstorage", QObject::tr("Instead of Joystick emulation, USB connection is Mass Storage (as in the Bootloader)")},
1158 {"cli", QObject::tr("Instead of Joystick emulation, USB connection is Command Line Interface")},
1159 {NULL}};
1160 firmware->addOptions(usb_options);
1163 void addOpenTxTaranisOptions(OpenTxFirmware * firmware)
1165 addOpenTxFrskyOptions(firmware);
1166 firmware->addOption("internalppm", QObject::tr("Support for PPM internal module hack"));
1167 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1170 void addOpenTxLcdOptions(OpenTxFirmware * firmware)
1172 Option lcd_options[] = {
1173 {"ST7565P", QObject::tr("ST7565P LCD or compatible")},
1174 {"ST7565R", QObject::tr("ST7565R LCD or compatible")},
1175 {"ERC12864FSF", QObject::tr("ERC12864FSF LCD")},
1176 {"ST7920", QObject::tr("ST7920 LCD")},
1177 {"KS108", QObject::tr("KS108 LCD")},
1178 {NULL}
1180 firmware->addOptions(lcd_options);
1183 void addOpenTxVoiceOptions(OpenTxFirmware * firmware)
1185 Option voice_options[] = {
1186 {"WTV20", QObject::tr("WTV20 voice module")},
1187 {"JQ6500", QObject::tr("JQ6500 voice module")},
1188 {NULL}
1190 firmware->addOptions(voice_options);
1193 QList<OpenTxEepromInterface *> opentxEEpromInterfaces;
1195 void registerOpenTxFirmware(OpenTxFirmware * firmware)
1197 OpenTxEepromInterface * eepromInterface = new OpenTxEepromInterface(firmware);
1198 firmware->setEEpromInterface(eepromInterface);
1199 opentxEEpromInterfaces.push_back(eepromInterface);
1200 eepromInterfaces.push_back(eepromInterface);
1201 Firmware::addRegisteredFirmware(firmware);
1204 void registerOpenTxFirmwares()
1206 OpenTxFirmware * firmware;
1208 Option ext_options[] = {{"frsky", QObject::tr("Support for frsky telemetry mod"), FRSKY_VARIANT},
1209 {"telemetrez", QObject::tr("Support for telemetry easy board"), FRSKY_VARIANT},
1210 {"jeti", QObject::tr("Support for jeti telemetry mod"), 0},
1211 {"ardupilot", QObject::tr("Support for receiving ardupilot data"), 0},
1212 {"nmea", QObject::tr("Support for receiving NMEA data"), 0},
1213 {"mavlink", QObject::tr("Support for MAVLINK devices"), MAVLINK_VARIANT},
1214 {NULL}};
1215 Option extr_options[] = {{"frsky", QObject::tr("Support for frsky telemetry mod"), FRSKY_VARIANT},
1216 {"jeti", QObject::tr("Support for jeti telemetry mod"), 0},
1217 {"ardupilot", QObject::tr("Support for receiving ardupilot data"), 0},
1218 {"nmea", QObject::tr("Support for receiving NMEA data"), 0},
1219 {"mavlink", QObject::tr("Support for MAVLINK devices"), MAVLINK_VARIANT},
1220 {NULL}};
1221 Option nav_options[] = {{"rotenc", QObject::tr("Rotary Encoder use in menus navigation")},
1222 {"potscroll", QObject::tr("Pots use in menus navigation")},
1223 {NULL}};
1224 Option dsm2_options[] = {{"DSM2", QObject::tr("Support for DSM2 modules"), 0},
1225 {"DSM2PPM", QObject::tr("Support for DSM2 modules using ppm instead of true serial"), 0},
1226 {NULL}};
1228 /* FrSky Taranis X9D+ board */
1229 firmware = new OpenTxFirmware("opentx-x9d+", QObject::tr("FrSky Taranis X9D+"), BOARD_TARANIS_X9DP);
1230 addOpenTxTaranisOptions(firmware);
1231 registerOpenTxFirmware(firmware);
1233 /* FrSky Taranis X9D board */
1234 firmware = new OpenTxFirmware("opentx-x9d", QObject::tr("FrSky Taranis X9D"), BOARD_TARANIS_X9D);
1235 firmware->addOption("haptic", QObject::tr("Haptic module installed"));
1236 addOpenTxTaranisOptions(firmware);
1237 registerOpenTxFirmware(firmware);
1239 /* FrSky Taranis X9E board */
1240 firmware = new OpenTxFirmware("opentx-x9e", QObject::tr("FrSky Taranis X9E"), BOARD_TARANIS_X9E);
1241 firmware->addOption("shutdownconfirm", QObject::tr("Confirmation before radio shutdown"));
1242 firmware->addOption("horussticks", QObject::tr("Horus gimbals installed (Hall sensors)"));
1243 addOpenTxTaranisOptions(firmware);
1244 registerOpenTxFirmware(firmware);
1246 /* FrSky X7 board */
1247 firmware = new OpenTxFirmware("opentx-x7", QObject::tr("FrSky Taranis X7"), BOARD_TARANIS_X7);
1248 // No mixersmon for now
1249 addOpenTxFrskyOptions(firmware);
1250 firmware->addOption("internalppm", QObject::tr("Support for PPM internal module hack"));
1251 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1252 registerOpenTxFirmware(firmware);
1254 /* FrSky Horus board */
1255 firmware = new OpenTxFirmware("opentx-x12s", QObject::tr("FrSky Horus"), BOARD_X12S);
1256 addOpenTxFrskyOptions(firmware);
1257 firmware->addOption("pcbdev", QObject::tr("Use ONLY with first DEV pcb version"));
1258 registerOpenTxFirmware(firmware);
1261 /* FrSky X10 board */
1262 /* Disabled for now
1263 firmware = new OpenTxFirmware("opentx-x10", QObject::tr("FrSky X10"), BOARD_X10);
1264 addOpenTxFrskyOptions(firmware);
1265 registerOpenTxFirmware(firmware);
1267 /* 9XR-Pro */
1268 firmware = new OpenTxFirmware("opentx-9xrpro", QObject::tr("Turnigy 9XR-PRO"), BOARD_9XRPRO);
1269 firmware->addOption("heli", QObject::tr("Enable HELI menu and cyclic mix support"));
1270 firmware->addOption("nofp", QObject::tr("No flight modes"));
1271 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1272 firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
1273 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1274 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1275 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1276 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1277 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1278 firmware->addOption("bluetooth", QObject::tr("Bluetooth interface"));
1279 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1280 addOpenTxArmOptions(firmware);
1281 addOpenTxCommonOptions(firmware);
1282 registerOpenTxFirmware(firmware);
1284 /* 9XR board with M128 chip */
1285 firmware = new OpenTxFirmware("opentx-9xr128", QObject::tr("Turnigy 9XR with m128 chip"), BOARD_M128);
1286 firmware->addOptions(extr_options);
1287 firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
1288 firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
1289 firmware->addOption("nosplash", QObject::tr("No splash screen"));
1290 firmware->addOption("nofp", QObject::tr("No flight modes"));
1291 firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
1292 firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
1293 firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
1294 firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
1295 // NOT TESTED firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
1296 firmware->addOption("DSM2", QObject::tr("Support for DSM2 modules"));
1297 firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
1298 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1299 firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
1300 firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
1301 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1302 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1303 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1304 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1305 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1306 firmware->addOption("thrtrace", QObject::tr("Enable the throttle trace in Statistics"));
1307 firmware->addOption("pgbar", QObject::tr("EEprom write Progress bar"));
1308 firmware->addOption("imperial", QObject::tr("Imperial units"));
1309 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1310 addOpenTxCommonOptions(firmware);
1311 registerOpenTxFirmware(firmware);
1313 /* 9XR board */
1314 firmware = new OpenTxFirmware("opentx-9xr", QObject::tr("Turnigy 9XR"), BOARD_STOCK);
1315 firmware->addOptions(extr_options);
1316 firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
1317 firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
1318 firmware->addOption("nosplash", QObject::tr("No splash screen"));
1319 firmware->addOption("nofp", QObject::tr("No flight modes"));
1320 firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
1321 firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
1322 firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
1323 firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
1324 // NOT TESTED firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
1325 firmware->addOption("DSM2", QObject::tr("Support for DSM2 modules"));
1326 firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
1327 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1328 firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
1329 firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
1330 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1331 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1332 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1333 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1334 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1335 firmware->addOption("thrtrace", QObject::tr("Enable the throttle trace in Statistics"));
1336 firmware->addOption("pgbar", QObject::tr("EEprom write Progress bar"));
1337 firmware->addOption("imperial", QObject::tr("Imperial units"));
1338 firmware->addOption("nowshh", QObject::tr("No Winged Shadow How High support"));
1339 firmware->addOption("novario", QObject::tr("No vario support"));
1340 firmware->addOption("nogps", QObject::tr("No GPS support"));
1341 firmware->addOption("nogauges", QObject::tr("No gauges in the custom telemetry screen"));
1342 firmware->addOption("stickrev", QObject::tr("Add support for reversing stick inputs (e.g. needed for FrSky gimbals)"));
1343 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1344 addOpenTxCommonOptions(firmware);
1345 registerOpenTxFirmware(firmware);
1347 /* 9x board */
1348 firmware = new OpenTxFirmware("opentx-9x", QObject::tr("9X with stock board"), BOARD_STOCK);
1349 firmware->addOptions(ext_options);
1350 firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
1351 firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
1352 firmware->addOption("nosplash", QObject::tr("No splash screen"));
1353 firmware->addOption("nofp", QObject::tr("No flight modes"));
1354 firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
1355 firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
1356 firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
1357 firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
1358 // NOT TESTED firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
1359 firmware->addOption("DSM2", QObject::tr("Support for DSM2 modules"));
1360 firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
1361 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1362 firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
1363 firmware->addOptions(nav_options);
1364 firmware->addOption("sp22", QObject::tr("SmartieParts 2.2 Backlight support"));
1365 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1366 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1367 firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
1368 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1369 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1370 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1371 firmware->addOption("thrtrace", QObject::tr("Enable the throttle trace in Statistics"));
1372 firmware->addOption("pgbar", QObject::tr("EEprom write progress bar"));
1373 firmware->addOption("imperial", QObject::tr("Imperial units"));
1374 firmware->addOption("nowshh", QObject::tr("No Winged Shadow How High support"));
1375 firmware->addOption("novario", QObject::tr("No vario support"));
1376 firmware->addOption("nogps", QObject::tr("No GPS support"));
1377 firmware->addOption("nogauges", QObject::tr("No gauges in the custom telemetry screen"));
1378 firmware->addOption("fasoffset", QObject::tr("Allow compensating for offset errors in FrSky FAS current sensors"));
1379 firmware->addOption("stickrev", QObject::tr("Add support for reversing stick inputs (e.g. needed for FrSky gimbals)"));
1380 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1381 addOpenTxCommonOptions(firmware);
1382 registerOpenTxFirmware(firmware);
1384 /* 9x board with M128 chip */
1385 firmware = new OpenTxFirmware("opentx-9x128", QObject::tr("9X with stock board and m128 chip"), BOARD_M128);
1386 firmware->addOptions(ext_options);
1387 firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
1388 firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
1389 firmware->addOption("nosplash", QObject::tr("No splash screen"));
1390 firmware->addOption("nofp", QObject::tr("No flight modes"));
1391 firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
1392 firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
1393 firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
1394 firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
1395 // NOT TESTED firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
1396 firmware->addOption("DSM2", QObject::tr("Support for DSM2 modules"));
1397 firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
1398 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1399 firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
1400 firmware->addOptions(nav_options);
1401 firmware->addOption("sp22", QObject::tr("SmartieParts 2.2 Backlight support"));
1402 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1403 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1404 firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
1405 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1406 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1407 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1408 firmware->addOption("thrtrace", QObject::tr("Enable the throttle trace in Statistics"));
1409 firmware->addOption("pgbar", QObject::tr("EEprom write Progress bar"));
1410 firmware->addOption("imperial", QObject::tr("Imperial units"));
1411 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1412 addOpenTxCommonOptions(firmware);
1413 registerOpenTxFirmware(firmware);
1415 /* ar9x board */
1416 firmware = new OpenTxFirmware("opentx-ar9x", QObject::tr("9X with AR9X board"), BOARD_AR9X);
1417 firmware->addOption("heli", QObject::tr("Enable HELI menu and cyclic mix support"));
1418 firmware->addOption("nofp", QObject::tr("No flight modes"));
1419 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1420 firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
1421 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1422 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1423 firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
1424 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1425 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1426 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1427 firmware->addOption("bluetooth", QObject::tr("Bluetooth interface"));
1428 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1429 // firmware->addOption("rtc", QObject::tr("Optional RTC added"));
1430 // firmware->addOption("volume", QObject::tr("i2c volume control added"));
1431 addOpenTxArmOptions(firmware);
1432 addOpenTxCommonOptions(firmware);
1433 registerOpenTxFirmware(firmware);
1435 /* Sky9x board */
1436 firmware = new OpenTxFirmware("opentx-sky9x", QObject::tr("9X with Sky9x board"), BOARD_SKY9X);
1437 firmware->addOption("heli", QObject::tr("Enable HELI menu and cyclic mix support"));
1438 firmware->addOption("nofp", QObject::tr("No flight modes"));
1439 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1440 firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
1441 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1442 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1443 firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
1444 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1445 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1446 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1447 firmware->addOption("bluetooth", QObject::tr("Bluetooth interface"));
1448 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1449 addOpenTxArmOptions(firmware);
1450 addOpenTxCommonOptions(firmware);
1451 registerOpenTxFirmware(firmware);
1453 /* Gruvin9x board */
1454 firmware = new OpenTxFirmware("opentx-gruvin9x", QObject::tr("9X with Gruvin9x board"), BOARD_GRUVIN9X);
1455 firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
1456 firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
1457 firmware->addOption("nofp", QObject::tr("No flight modes"));
1458 firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
1459 firmware->addOption("sdcard", QObject::tr("Support for SD memory card"));
1460 firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
1461 firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
1462 firmware->addOptions(dsm2_options);
1463 firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
1464 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1465 firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
1466 firmware->addOption("potscroll", QObject::tr("Pots use in menus navigation"));
1467 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1468 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1469 firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
1470 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1471 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1472 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1473 firmware->addOption("pgbar", QObject::tr("EEprom write Progress bar"));
1474 firmware->addOption("imperial", QObject::tr("Imperial units"));
1475 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1476 addOpenTxCommonOptions(firmware);
1477 registerOpenTxFirmware(firmware);
1479 /* MEGA2560 board */
1480 firmware = new OpenTxFirmware("opentx-mega2560", QObject::tr("DIY MEGA2560 radio"), BOARD_MEGA2560);
1481 addOpenTxLcdOptions(firmware);
1482 firmware->addOption("PWR", QObject::tr("Power management by soft-off circuitry"));
1483 firmware->addOptions(ext_options);
1484 firmware->addOption("PXX", QObject::tr("Support of FrSky PXX protocol"));
1485 firmware->addOptions(dsm2_options);
1486 firmware->addOption("heli", QObject::tr("Enable heli menu and cyclic mix support"));
1487 firmware->addOption("templates", QObject::tr("Enable TEMPLATES menu"));
1488 firmware->addOption("nofp", QObject::tr("No flight modes"));
1489 firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
1490 firmware->addOption("sdcard", QObject::tr("Support for SD memory card"));
1491 firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
1492 //firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
1493 addOpenTxVoiceOptions(firmware);
1494 firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
1495 firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
1496 firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);
1497 firmware->addOption("symlimits", QObject::tr("Symetrical Limits"));
1498 firmware->addOption("autosource", QObject::tr("In model setup menus automatically set source by moving the control"));
1499 firmware->addOption("autoswitch", QObject::tr("In model setup menus automatically set switch by moving the control"));
1500 firmware->addOption("dblkeys", QObject::tr("Enable resetting values by pressing up and down at the same time"));
1501 firmware->addOption("nographics", QObject::tr("No graphical check boxes and sliders"));
1502 firmware->addOption("battgraph", QObject::tr("Battery graph"));
1503 firmware->addOption("nobold", QObject::tr("Don't use bold font for highlighting active items"));
1504 firmware->addOption("pgbar", QObject::tr("EEprom write Progress bar"));
1505 firmware->addOption("imperial", QObject::tr("Imperial units"));
1506 firmware->addOption("sqt5font", QObject::tr("Use alternative SQT5 font"));
1507 addOpenTxCommonOptions(firmware);
1508 registerOpenTxFirmware(firmware);
1510 Firmware::setDefaultVariant(Firmware::getFirmwareForId("opentx-x9d+"));
1511 Firmware::setCurrentVariant(Firmware::getDefaultVariant());
1514 void unregisterOpenTxFirmwares()
1516 foreach (Firmware * f, Firmware::getRegisteredFirmwares()) {
1517 delete f;
1519 unregisterEEpromInterfaces();
1522 template <class T, class M>
1523 OpenTxEepromInterface * loadFromByteArray(T & dest, const QByteArray & data)
1525 foreach(OpenTxEepromInterface * eepromInterface, opentxEEpromInterfaces) {
1526 if (eepromInterface->loadFromByteArray<T, M>(dest, data)) {
1527 return eepromInterface;
1530 return NULL;
1533 template <class T, class M>
1534 bool saveToByteArray(const T & dest, QByteArray & data)
1536 Board::Type board = getCurrentBoard();
1537 foreach(OpenTxEepromInterface * eepromInterface, opentxEEpromInterfaces) {
1538 if (eepromInterface->getBoard() == board) {
1539 return eepromInterface->saveToByteArray<T, M>(dest, data);
1542 return false;
1545 OpenTxEepromInterface * loadModelFromByteArray(ModelData & model, const QByteArray & data)
1547 return loadFromByteArray<ModelData, OpenTxModelData>(model, data);
1550 OpenTxEepromInterface * loadRadioSettingsFromByteArray(GeneralSettings & settings, const QByteArray & data)
1552 return loadFromByteArray<GeneralSettings, OpenTxGeneralData>(settings, data);
1555 bool writeModelToByteArray(const ModelData & model, QByteArray & data)
1557 return saveToByteArray<ModelData, OpenTxModelData>(model, data);
1560 bool writeRadioSettingsToByteArray(const GeneralSettings & settings, QByteArray & data)
1562 return saveToByteArray<GeneralSettings, OpenTxGeneralData>(settings, data);