Use PROTOCOL_TELEMETRY_MULTIMODULE for internal multi when available (#7147)
[opentx.git] / companion / src / multimodelprinter.cpp
blobf9d039d6915dd8c29ddc0e4c323a63fbaab2c804
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 "helpers.h"
22 #include "helpers_html.h"
23 #include "multimodelprinter.h"
24 #include "appdata.h"
25 #include <algorithm>
27 MultiModelPrinter::MultiColumns::MultiColumns(int count):
28 count(count),
29 compareColumns(NULL)
31 columns = new QString[count];
34 MultiModelPrinter::MultiColumns::~MultiColumns()
36 delete[] columns;
39 void MultiModelPrinter::MultiColumns::append(const QString & str)
41 for (int i=0; i<count; i++) {
42 append(i, str);
46 void MultiModelPrinter::MultiColumns::appendTitle(const QString & name)
48 append("<b>" + name + "</b>&nbsp;");
51 void MultiModelPrinter::MultiColumns::append(int idx, const QString & str)
53 if (compareColumns)
54 compareColumns[idx].append(str);
55 else
56 columns[idx].append(str);
59 void MultiModelPrinter::MultiColumns::beginCompare()
61 compareColumns = new QString[count];
64 void MultiModelPrinter::MultiColumns::endCompare()
66 for (int i=0; i<count; i++) {
67 QString style = "";
68 if (i==0 && count>1 && compareColumns[0]!=compareColumns[1])
69 style = "mpc-diff1";
70 else if (i>0 && compareColumns[i]!=compareColumns[0])
71 style = "mpc-diff2";
72 if (style!="")
73 columns[i].append(QString("<span class='%1'>%2</span>").arg(style).arg(compareColumns[i]));
74 else
75 columns[i].append(compareColumns[i]);
77 delete[] compareColumns;
78 compareColumns = NULL;
81 template <class T>
82 void MultiModelPrinter::MultiColumns::append(int idx, T val)
84 append(idx, QString("%1").arg(val));
87 QString MultiModelPrinter::MultiColumns::print()
89 QString result = "<tr>";
90 for (int i=0; i<count; i++) {
91 result.append(QString("<td width='%1%'>%2</td>").arg(100.0/count).arg(columns[i]));
93 result.append("</tr>");
94 return result;
97 bool MultiModelPrinter::MultiColumns::isEmpty()
99 for (int i=0; i<count; i++) {
100 if (!columns[i].isEmpty())
101 return false;
103 return true;
106 void MultiModelPrinter::MultiColumns::appendLineBreak()
108 append("<br/>");
111 void MultiModelPrinter::MultiColumns::appendSectionTableStart()
113 append("<table cellspacing='0' cellpadding='1' width='100%' border='0' style='border-collapse:collapse'>");
116 void MultiModelPrinter::MultiColumns::appendTableEnd()
118 append("</table>");
121 void MultiModelPrinter::MultiColumns::appendRowStart(const QString & title, const unsigned int titlewidth)
123 append("<tr>");
124 if (!(title.isEmpty()) || (titlewidth))
125 appendLabelCell(QString(title), titlewidth);
128 void MultiModelPrinter::MultiColumns::appendRowEnd()
130 append("</tr>");
133 void MultiModelPrinter::MultiColumns::appendCellStart(const unsigned int width, const bool bold)
135 QString str = "<td";
136 if (width)
137 str.append(QString(" width='%1%'").arg(QString::number(width)));
138 str.append(">");
139 str.append(bold ? "<b>" : "");
140 append(str);
143 void MultiModelPrinter::MultiColumns::appendCellEnd(const bool bold)
145 QString str;
146 str.append(bold ? "</b>" : "");
147 str.append("</td>");
148 append(str);
151 void MultiModelPrinter::MultiColumns::appendLabelCell(const QString & str, const unsigned int width, const QString & align, const QString & color)
153 append(doTableCell(str, width, align, color, true));
156 void MultiModelPrinter::MultiColumns::appendValueCell(const QString & str, const unsigned int width, const QString & align, const QString & color)
158 append(doTableCell(str, width, align, color, false));
161 void MultiModelPrinter::MultiColumns::appendRow(const QStringList & strl, const unsigned int width, const QString & align, const QString & color)
163 append(doTableRow(strl, width, align, color, false));
166 void MultiModelPrinter::MultiColumns::appendRowHeader(const QStringList & strl, const unsigned int width, const QString & align, const QString & color)
168 append(doTableRow(strl, width, align, color, true));
171 void MultiModelPrinter::MultiColumns::appendRowBlank()
173 append(doTableBlankRow());
176 void MultiModelPrinter::MultiColumns::appendFieldLabel(const QString & lbl)
178 if (!lbl.isEmpty())
179 appendTitle(QString("%1:").arg(lbl));
182 void MultiModelPrinter::MultiColumns::appendFieldSeparator(const bool sep)
184 if (sep)
185 append(";&nbsp;");
188 #define COMPARE(what) \
189 columns.beginCompare(); \
190 for (int cc=0; cc < modelPrinterMap.size(); cc++) { \
191 ModelPrinter * modelPrinter = modelPrinterMap.value(cc).second; \
192 const ModelData * model = modelPrinterMap.value(cc).first; \
193 (void)(model); (void)(modelPrinter); \
194 columns.append(cc, (what)); \
196 columns.endCompare();
198 #define COMPARECELL(what) \
199 columns.appendCellStart(); \
200 COMPARE(what); \
201 columns.appendCellEnd();
203 #define COMPARECELLWIDTH(what, width) \
204 columns.appendCellStart(width); \
205 COMPARE(what); \
206 columns.appendCellEnd();
208 #define LABELCOMPARECELL(lbl, what, width) \
209 columns.appendCellStart(width); \
210 columns.appendFieldLabel(lbl); \
211 COMPARE(what); \
212 columns.appendCellEnd();
214 #define ROWLABELCOMPARECELL(lbl, lblw, what, width) \
215 columns.appendRowStart(lbl, lblw); \
216 columns.appendCellStart(width); \
217 COMPARE(what); \
218 columns.appendCellEnd(); \
219 columns.appendRowEnd();
221 #define COMPARESTRING(lbl, what, sep) \
222 columns.appendFieldLabel(lbl); \
223 COMPARE(what); \
224 columns.appendFieldSeparator(sep);
226 QString MultiModelPrinter::printTitle(const QString & label)
228 return QString("<tr><td class=mpc-section-title colspan='%1'>").arg(modelPrinterMap.count()) + label + "</td></tr>";
231 MultiModelPrinter::MultiModelPrinter(Firmware * firmware):
232 firmware(firmware)
236 MultiModelPrinter::~MultiModelPrinter()
238 clearModels();
241 void MultiModelPrinter::setModel(int idx, const ModelData * model, const GeneralSettings * generalSettings)
243 if (modelPrinterMap.contains(idx) && modelPrinterMap.value(idx).second) {
244 // free existing model printer
245 delete modelPrinterMap.value(idx).second;
246 modelPrinterMap[idx].second = NULL;
249 QPair<const ModelData *, ModelPrinter *> pair(model, new ModelPrinter(firmware, *generalSettings, *model));
250 modelPrinterMap.insert(idx, pair); // QMap.insert will replace any existing key
253 void MultiModelPrinter::setModel(int idx, const ModelData * model)
255 setModel(idx, model, &defaultSettings);
258 void MultiModelPrinter::clearModels()
260 for(int i=0; i < modelPrinterMap.size(); i++) {
261 if (modelPrinterMap.value(i).second)
262 delete modelPrinterMap.value(i).second;
264 modelPrinterMap.clear();
267 QString MultiModelPrinter::print(QTextDocument * document)
269 if (document) document->clear();
270 Stylesheet css(MODEL_PRINT_CSS);
271 if (css.load(Stylesheet::StyleType::STYLE_TYPE_EFFECTIVE))
272 document->setDefaultStyleSheet(css.text());
273 QString str = "<table cellspacing='0' cellpadding='3' width='100%'>"; // attributes not settable via QT stylesheet
274 str.append(printSetup());
275 if (firmware->getCapability(HasDisplayText))
276 str.append(printChecklist());
277 if (firmware->getCapability(Timers)) {
278 str.append(printTimers());
280 str.append(printModules());
281 if (firmware->getCapability(Heli))
282 str.append(printHeliSetup());
283 if (firmware->getCapability(FlightModes))
284 str.append(printFlightModes());
285 str.append(printInputs());
286 str.append(printMixers());
287 str.append(printOutputs());
288 str.append(printCurves(document));
289 if (firmware->getCapability(Gvars) && !firmware->getCapability(GvarsFlightModes))
290 str.append(printGvars());
291 str.append(printLogicalSwitches());
292 if (firmware->getCapability(GlobalFunctions))
293 str.append(printGlobalFunctions());
294 str.append(printSpecialFunctions());
295 if (firmware->getCapability(Telemetry) & TM_HASTELEMETRY) {
296 str.append(printTelemetry());
297 str.append(printSensors());
298 if (firmware->getCapability(TelemetryCustomScreens)) {
299 str.append(printTelemetryScreens());
302 str.append("</table>");
303 return str;
306 QString MultiModelPrinter::printSetup()
308 QString str = printTitle(tr("General"));
310 MultiColumns columns(modelPrinterMap.size());
311 columns.appendSectionTableStart();
312 ROWLABELCOMPARECELL(tr("Name"), 20, model->name, 80);
313 ROWLABELCOMPARECELL(tr("EEprom Size"), 0, modelPrinter->printEEpromSize(), 0);
314 if (firmware->getCapability(ModelImage)) {
315 ROWLABELCOMPARECELL(tr("Model Image"), 0, model->bitmap, 0);
317 ROWLABELCOMPARECELL(tr("Throttle"), 0, modelPrinter->printThrottle(), 0);
318 ROWLABELCOMPARECELL(tr("Trims"), 0, modelPrinter->printSettingsTrim(), 0);
319 ROWLABELCOMPARECELL(tr("Center Beep"), 0, modelPrinter->printCenterBeep(), 0);
320 ROWLABELCOMPARECELL(tr("Switch Warnings"), 0, modelPrinter->printSwitchWarnings(), 0);
321 if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
322 ROWLABELCOMPARECELL(tr("Pot Warnings"), 0, modelPrinter->printPotWarnings(), 0);
324 ROWLABELCOMPARECELL(tr("Other"), 0, modelPrinter->printSettingsOther(), 0);
325 columns.appendTableEnd();
326 str.append(columns.print());
327 return str;
330 QString MultiModelPrinter::printTimers()
332 QString str;
333 MultiColumns columns(modelPrinterMap.size());
334 columns.appendSectionTableStart();
335 columns.appendRowHeader(QStringList() << tr("Timers") << tr("Time") << tr("Switch") << tr("Countdown") << tr("Min.call") << tr("Persist"));
337 for (int i=0; i<firmware->getCapability(Timers); i++) {
338 columns.appendRowStart();
339 columns.appendCellStart(20, true);
340 COMPARE(modelPrinter->printTimerName(i));
341 columns.appendCellEnd(true);
342 COMPARECELLWIDTH(modelPrinter->printTimerTimeValue(model->timers[i].val), 15);
343 COMPARECELLWIDTH(model->timers[i].mode.toString(), 15);
344 COMPARECELLWIDTH(modelPrinter->printTimerCountdownBeep(model->timers[i].countdownBeep), 15);
345 COMPARECELLWIDTH(modelPrinter->printTimerMinuteBeep(model->timers[i].minuteBeep), 15);
346 COMPARECELLWIDTH(modelPrinter->printTimerPersistent(model->timers[i].persistent), 20);
347 columns.appendRowEnd();
349 columns.appendTableEnd();
350 str.append(columns.print());
351 return str;
354 QString MultiModelPrinter::printModules()
356 QString str = printTitle(tr("Modules"));
357 MultiColumns columns(modelPrinterMap.size());
358 columns.appendSectionTableStart();
359 for (int i=0; i<firmware->getCapability(NumModules); i++) {
360 columns.appendRowStart();
361 columns.appendCellStart(20, true);
362 COMPARE(modelPrinter->printModuleType(i));
363 columns.appendCellEnd(true);
364 COMPARECELLWIDTH(modelPrinter->printModule(i), 80);
365 columns.appendRowEnd();
367 if (firmware->getCapability(ModelTrainerEnable))
368 columns.appendRowStart(tr("Trainer port"));
369 COMPARECELL(modelPrinter->printModule(-1));
370 columns.appendRowEnd();
371 columns.appendTableEnd();
372 str.append(columns.print());
373 return str;
376 QString MultiModelPrinter::printHeliSetup()
378 bool heliEnabled = false;
379 for (int k=0; k < modelPrinterMap.size(); k++) {
380 heliEnabled = heliEnabled || modelPrinterMap.value(k).first->swashRingData.type != HELI_SWASH_TYPE_NONE;
383 if (!heliEnabled)
384 return "";
386 QString str = printTitle(tr("Helicopter"));
387 MultiColumns columns(modelPrinterMap.size());
388 columns.appendSectionTableStart();
389 columns.appendRowStart(tr("Swash"), 20);
390 LABELCOMPARECELL(tr("Type"), modelPrinter->printHeliSwashType(), 20);
391 LABELCOMPARECELL(tr("Ring"), model->swashRingData.value, 20);
392 columns.appendRowEnd();
394 columns.appendRowBlank();
395 columns.appendRowHeader(QStringList() << "" << tr("Input") << tr("Weight"));
396 columns.appendRowStart(tr("Long. cyc"));
397 COMPARECELL(model->swashRingData.elevatorSource.toString(model));
398 COMPARECELL(model->swashRingData.elevatorWeight);
399 columns.appendRowEnd();
401 columns.appendRowStart(tr("Lateral cyc"));
402 COMPARECELL(model->swashRingData.aileronSource.toString(model));
403 COMPARECELL(model->swashRingData.aileronWeight)
404 columns.appendRowEnd();
406 columns.appendRowStart(tr("Collective"));
407 COMPARECELL(model->swashRingData.collectiveSource.toString(model));
408 COMPARECELL(model->swashRingData.collectiveWeight)
409 columns.appendRowEnd();
411 columns.appendTableEnd();
412 str.append(columns.print());
413 return str;
416 QString MultiModelPrinter::printFlightModes()
418 QString str = printTitle(tr("Flight modes"));
419 // Trims
421 MultiColumns columns(modelPrinterMap.size());
422 columns.appendSectionTableStart();
423 QStringList hd = QStringList() << tr("Flight mode") << tr("Switch") << tr("F.In") << tr("F.Out");
424 for (int i=0; i < getBoardCapability(getCurrentBoard(), Board::NumTrims); i++) {
425 hd << RawSource(SOURCE_TYPE_TRIM, i).toString();
427 columns.appendRowHeader(hd);
428 int wd = 80/(getBoardCapability(getCurrentBoard(), Board::NumTrims) + 3);
429 for (int i=0; i<firmware->getCapability(FlightModes); i++) {
430 columns.appendRowStart();
431 columns.appendCellStart(20,true);
432 COMPARE(modelPrinter->printFlightModeName(i));
433 columns.appendCellEnd(true);
434 COMPARECELLWIDTH(modelPrinter->printFlightModeSwitch(model->flightModeData[i].swtch), wd);
435 COMPARECELLWIDTH(model->flightModeData[i].fadeIn, wd);
436 COMPARECELLWIDTH(model->flightModeData[i].fadeOut, wd);
437 for (int k=0; k < getBoardCapability(getCurrentBoard(), Board::NumTrims); k++) {
438 COMPARECELLWIDTH(modelPrinter->printTrim(i, k), wd);
440 columns.appendRowEnd();
443 columns.appendTableEnd();
444 str.append(columns.print());
447 // GVars and Rotary Encoders
448 int gvars = firmware->getCapability(Gvars);
449 if ((gvars && firmware->getCapability(GvarsFlightModes)) || firmware->getCapability(RotaryEncoders)) {
450 MultiColumns columns(modelPrinterMap.size());
451 columns.appendSectionTableStart();
452 QStringList hd = QStringList() << tr("Global vars");
453 if (firmware->getCapability(GvarsFlightModes)) {
454 for (int i=0; i<gvars; i++) {
455 hd << tr("GV%1").arg(i+1);
458 for (int i=0; i<firmware->getCapability(RotaryEncoders); i++) {
459 hd << tr("RE%1").arg(i+1);
461 columns.appendRowHeader(hd);
462 int wd = 80/gvars;
463 if (firmware->getCapability(GvarsFlightModes)) {
464 columns.appendRowStart(tr("Name"), 20);
465 for (int i=0; i<gvars; i++) {
466 COMPARECELLWIDTH(model->gvarData[i].name, wd);
468 columns.appendRowEnd();
469 columns.appendRowStart(tr("Unit"));
470 for (int i=0; i<gvars; i++) {
471 COMPARECELL(modelPrinter->printGlobalVarUnit(i));
473 columns.appendRowEnd();
474 columns.appendRowStart(tr("Prec"));
475 for (int i=0; i<gvars; i++) {
476 COMPARECELL(modelPrinter->printGlobalVarPrec(i));
478 columns.appendRowEnd();
479 columns.appendRowStart(tr("Min"));
480 for (int i=0; i<gvars; i++) {
481 COMPARECELL(modelPrinter->printGlobalVarMin(i));
483 columns.appendRowEnd();
484 columns.appendRowStart(tr("Max"));
485 for (int i=0; i<gvars; i++) {
486 COMPARECELL(modelPrinter->printGlobalVarMax(i));
488 columns.appendRowEnd();
489 columns.appendRowStart(tr("Popup"));
490 for (int i=0; i<gvars; i++) {
491 COMPARECELL(modelPrinter->printGlobalVarPopup(i));
493 columns.appendRowEnd();
496 columns.appendRowHeader(QStringList() << tr("Flight mode"));
498 for (int i=0; i<firmware->getCapability(FlightModes); i++) {
499 columns.appendRowStart();
500 columns.appendCellStart(0,true);
501 COMPARE(modelPrinter->printFlightModeName(i));
502 columns.appendCellEnd(true);
503 if (firmware->getCapability(GvarsFlightModes)) {
504 for (int k=0; k<gvars; k++) {
505 COMPARECELL(modelPrinter->printGlobalVar(i, k));
508 for (int k=0; k<firmware->getCapability(RotaryEncoders); k++) {
509 COMPARECELL(modelPrinter->printRotaryEncoder(i, k));
511 columns.appendRowEnd();
513 columns.appendTableEnd();
514 str.append(columns.print());
517 return str;
520 QString MultiModelPrinter::printOutputs()
522 QString str = printTitle(tr("Outputs"));
523 MultiColumns columns(modelPrinterMap.size());
524 columns.appendSectionTableStart();
525 QStringList hd = QStringList() << tr("Channel") << tr("Subtrim") << tr("Min") << tr("Max") << tr("Direct");
526 if (IS_HORUS_OR_TARANIS(firmware->getBoard()))
527 hd << tr("Curve");
528 if (firmware->getCapability(PPMCenter))
529 hd << tr("PPM");
530 if (firmware->getCapability(SYMLimits))
531 hd << tr("Linear");
532 columns.appendRowHeader(hd);
533 int cols = 4;
534 if (IS_HORUS_OR_TARANIS(firmware->getBoard()))
535 cols++;
536 if (firmware->getCapability(PPMCenter))
537 cols++;
538 if (firmware->getCapability(SYMLimits))
539 cols++;
540 int wd = 80/cols;
541 for (int i=0; i<firmware->getCapability(Outputs); i++) {
542 int count = 0;
543 for (int k=0; k < modelPrinterMap.size(); k++)
544 count = std::max(count, modelPrinterMap.value(k).first->mixes(i).size());
545 if (!count)
546 continue;
547 columns.appendRowStart();
548 columns.appendCellStart(20, true);
549 COMPARE(modelPrinter->printChannelName(i));
550 columns.appendCellEnd(true);
551 COMPARECELLWIDTH(modelPrinter->printOutputOffset(i), wd);
552 COMPARECELLWIDTH(modelPrinter->printOutputMin(i), wd);
553 COMPARECELLWIDTH(modelPrinter->printOutputMax(i), wd);
554 COMPARECELLWIDTH(modelPrinter->printOutputRevert(i), wd);
555 if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
556 COMPARECELLWIDTH(modelPrinter->printOutputCurve(i), wd);
558 if (firmware->getCapability(PPMCenter)) {
559 COMPARECELLWIDTH(modelPrinter->printOutputPpmCenter(i), wd);
561 if (firmware->getCapability(SYMLimits)) {
562 COMPARECELLWIDTH(modelPrinter->printOutputSymetrical(i), wd);
564 columns.appendRowEnd();
566 columns.appendTableEnd();
567 str.append(columns.print());
568 return str;
571 QString MultiModelPrinter::printGvars()
573 QString str = printTitle(tr("Global Variables"));
574 int gvars = firmware->getCapability(Gvars);
575 MultiColumns columns(modelPrinterMap.size());
576 columns.appendSectionTableStart();
577 QStringList hd;
578 for (int i=0; i<gvars; i++) {
579 hd << tr("GV%1").arg(i+1);
581 columns.appendRowHeader(hd);
583 for (int i=0; i<gvars; i++) {
584 COMPARECELL(model->flightModeData[0].gvars[i]);
586 columns.appendRowEnd();
587 columns.appendTableEnd();
588 str.append(columns.print());
589 return str;
592 QString MultiModelPrinter::printInputs()
594 QString str = printTitle(tr("Inputs"));
595 MultiColumns columns(modelPrinterMap.size());
596 columns.appendSectionTableStart();
597 for (int i=0; i<std::max(4, firmware->getCapability(VirtualInputs)); i++) {
598 int count = 0;
599 for (int k=0; k < modelPrinterMap.size(); k++) {
600 count = std::max(count, modelPrinterMap.value(k).first->expos(i).size());
602 if (count > 0) {
603 columns.appendRowStart();
604 columns.appendCellStart(20, true);
605 COMPARE(modelPrinter->printInputName(i));
606 columns.appendCellEnd(true);
607 columns.appendCellStart(80);
608 for (int j=0; j<count; j++) {
609 if (j > 0)
610 columns.appendLineBreak();
611 COMPARE(j<model->expos(i).size() ? modelPrinter->printInputLine(*model->expos(i)[j]) : "");
613 columns.appendCellEnd();
614 columns.appendRowEnd();
617 columns.appendTableEnd();
618 str.append(columns.print());
619 return str;
622 QString MultiModelPrinter::printMixers()
624 QString str = printTitle(tr("Mixers"));
625 MultiColumns columns(modelPrinterMap.size());
626 columns.appendSectionTableStart();
627 for (int i=0; i<firmware->getCapability(Outputs); i++) {
628 int count = 0;
629 for (int k=0; k < modelPrinterMap.size(); k++) {
630 count = std::max(count, modelPrinterMap.value(k).first->mixes(i).size());
632 if (count > 0) {
633 columns.appendRowStart();
634 columns.appendCellStart(20, true);
635 COMPARE(modelPrinter->printChannelName(i));
636 columns.appendCellEnd(true);
637 columns.appendCellStart(80);
638 for (int j=0; j<count; j++) {
639 if (j > 0)
640 columns.appendLineBreak();
641 COMPARE((j < model->mixes(i).size()) ? modelPrinter->printMixerLine(*model->mixes(i)[j], (j>0)) : "&nbsp;");
643 columns.appendCellEnd();
644 columns.appendRowEnd();
647 columns.appendTableEnd();
648 str.append(columns.print());
649 return str;
652 QString MultiModelPrinter::printCurves(QTextDocument * document)
654 QString str;
655 MultiColumns columns(modelPrinterMap.size());
656 int count = 0;
657 columns.appendSectionTableStart();
658 for (int i=0; i<firmware->getCapability(NumCurves); i++) {
659 bool curveEmpty = true;
660 for (int k=0; k < modelPrinterMap.size(); k++) {
661 if (!modelPrinterMap.value(k).first->curves[i].isEmpty()) {
662 curveEmpty = false;
663 break;
666 if (!curveEmpty) {
667 count++;
668 columns.appendRowStart();
669 columns.appendCellStart(20, true);
670 COMPARE(modelPrinter->printCurveName(i));
671 columns.appendCellEnd(true);
672 COMPARECELL(modelPrinter->printCurve(i));
673 columns.appendRowEnd();
674 columns.appendRowStart("", 20);
675 columns.appendCellStart();
676 for (int k=0; k < modelPrinterMap.size(); k++)
677 columns.append(k, QString("<br/><img src='%1' border='0' /><br/>").arg(modelPrinterMap.value(k).second->createCurveImage(i, document)));
678 columns.appendCellEnd();
679 columns.appendRowEnd();
682 columns.appendTableEnd();
683 if (count > 0) {
684 str.append(printTitle(tr("Curves")));
685 str.append(columns.print());
687 return str;
690 QString MultiModelPrinter::printLogicalSwitches()
692 QString str;
693 MultiColumns columns(modelPrinterMap.size());
694 columns.appendSectionTableStart();
695 int count = 0;
696 for (int i=0; i<firmware->getCapability(LogicalSwitches); i++) {
697 bool lsEmpty = true;
698 for (int k=0; k < modelPrinterMap.size(); k++) {
699 if (!modelPrinterMap.value(k).first->logicalSw[i].isEmpty()) {
700 lsEmpty = false;
701 break;
704 if (!lsEmpty) {
705 count++;
706 columns.appendRowStart(tr("L%1").arg(i+1), 20);
707 COMPARECELL(modelPrinter->printLogicalSwitchLine(i));
708 columns.appendRowEnd();
711 columns.appendTableEnd();
712 if (count > 0) {
713 str.append(printTitle(tr("Logical Switches")));
714 str.append(columns.print());
716 return str;
719 QString MultiModelPrinter::printSpecialFunctions()
721 QString str;
722 MultiColumns columns(modelPrinterMap.size());
723 int count = 0;
724 columns.appendSectionTableStart();
725 for (int i=0; i < firmware->getCapability(CustomFunctions); i++) {
726 bool sfEmpty = true;
727 for (int k=0; k < modelPrinterMap.size(); k++) {
728 if (!modelPrinterMap.value(k).first->customFn[i].isEmpty()) {
729 sfEmpty = false;
730 break;
733 if (!sfEmpty) {
734 count++;
735 columns.appendRowStart(tr("SF%1").arg(i+1), 20);
736 COMPARECELL(modelPrinter->printCustomFunctionLine(i));
737 columns.appendRowEnd();
740 columns.appendTableEnd();
741 if (count > 0) {
742 str.append(printTitle(tr("Special Functions")));
743 str.append(columns.print());
745 return str;
748 QString MultiModelPrinter::printTelemetry()
750 QString str = printTitle(tr("Telemetry"));
751 MultiColumns columns(modelPrinterMap.size());
752 columns.appendSectionTableStart();
754 // Analogs on non ARM boards
755 if (!IS_ARM(firmware->getBoard())) {
756 columns.appendRowHeader(QStringList() << tr("Analogs") << tr("Unit") << tr("Scale") << tr("Offset"));
757 for (int i=0; i<2; i++) {
758 columns.appendRowStart(QString("A%1").arg(i+1), 20);
759 COMPARECELLWIDTH(FrSkyChannelData::unitString(model->frsky.channels[i].type), 20);
760 COMPARECELLWIDTH(QString::number((model->frsky.channels[i].ratio / (model->frsky.channels[i].type==0 ? 10.0 : 1)), 10, (model->frsky.channels[i].type==0 ? 1 : 0)), 20);
761 COMPARECELLWIDTH(QString::number((model->frsky.channels[i].offset*(model->frsky.channels[i].ratio / (model->frsky.channels[i].type==0 ?10.0 : 1)))/255, 10, (model->frsky.channels[i].type==0 ? 1 : 0)), 40);
762 columns.appendRowEnd();
765 else {
766 // Protocol
767 columns.appendRowStart(tr("Protocol"), 20);
768 COMPARECELL(modelPrinter->printTelemetryProtocol(model->telemetryProtocol));
769 columns.appendRowEnd();
772 // RSSI alarms
774 columns.appendRowStart(tr("RSSI Alarms"), 20);
775 columns.appendCellStart(80);
776 COMPARESTRING("", (IS_ARM(getCurrentBoard()) ? tr("Low") : FrSkyAlarmData::alarmLevelName(model->rssiAlarms.level[0])), false);
777 columns.append(": ");
778 COMPARESTRING("", QString("&lt; %1").arg(QString::number(model->rssiAlarms.warning, 10)), true);
779 COMPARESTRING("", (IS_ARM(getCurrentBoard()) ? tr("Critical") : FrSkyAlarmData::alarmLevelName(model->rssiAlarms.level[1])), false);
780 columns.append(": ");
781 COMPARESTRING("", QString("&lt; %1").arg(QString::number(model->rssiAlarms.critical, 10)), true);
782 COMPARESTRING(tr("Telemetry audio"), modelPrinter->printRssiAlarmsDisabled(model->rssiAlarms.disabled), false);
783 columns.appendCellEnd();
784 columns.appendRowEnd();
787 // Altimetry
788 if (firmware->getCapability(HasVario)) {
789 columns.appendRowStart(tr("Altimetry"), 20);
790 if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
791 LABELCOMPARECELL(tr("Vario source"), modelPrinter->printTelemetrySource(model->frsky.varioSource), 80);
793 else {
794 LABELCOMPARECELL(tr("Vario source"), modelPrinter->printVarioSource(model->frsky.varioSource), 80);
796 columns.appendRowEnd();
797 columns.appendRowStart("", 20);
798 columns.appendCellStart(80);
799 columns.appendTitle(tr("Vario limits >"));
800 if (firmware->getCapability(HasVarioSink)) {
801 COMPARESTRING(tr("Sink max"), QString::number(model->frsky.varioMin - 10), true);
802 COMPARESTRING(tr("Sink min"), QString::number((float(model->frsky.varioCenterMin) / 10.0) - 0.5), true);
804 COMPARESTRING(tr("Climb min"), QString::number((float(model->frsky.varioCenterMax) / 10.0) + 0.5), true);
805 COMPARESTRING(tr("Climb max"), QString::number(model->frsky.varioMax + 10), true);
806 COMPARESTRING(tr("Center silent"), modelPrinter->printVarioCenterSilent(model->frsky.varioCenterSilent), false);
807 columns.appendCellEnd();
808 columns.appendRowEnd();
811 // Top Bar
812 if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
813 columns.appendRowStart(tr("Top Bar"), 20);
814 columns.appendCellStart(80);
815 COMPARESTRING(tr("Volts source"), modelPrinter->printTelemetrySource(model->frsky.voltsSource), true);
816 COMPARESTRING(tr("Altitude source"), modelPrinter->printTelemetrySource(model->frsky.altitudeSource), false);
817 columns.appendCellEnd();
818 columns.appendRowEnd();
821 if (IS_ARM(firmware->getBoard())) {
822 ROWLABELCOMPARECELL("Multi sensors", 0, modelPrinter->printIgnoreSensorIds(!model->frsky.ignoreSensorIds), 0);
825 // Various
826 if (!IS_ARM(firmware->getBoard())) {
827 columns.appendRowHeader(QStringList() << tr("Various"));
828 if (!firmware->getCapability(NoTelemetryProtocol)) {
829 columns.appendRowStart("", 20);
830 LABELCOMPARECELL(tr("Serial protocol"), modelPrinter->printTelemetrySource(model->frsky.voltsSource), 80);
831 columns.appendRowEnd();
833 columns.appendRowStart("", 20);
834 columns.appendCellStart(80);
835 QString firmware_id = g.profile[g.id()].fwType();
836 if (firmware->getCapability(HasFasOffset) && firmware_id.contains("fasoffset")) {
837 COMPARESTRING(tr("FAS offset"), QString("%1 A").arg(model->frsky.fasOffset/10.0), true);
839 if (firmware->getCapability(HasMahPersistent)) {
840 COMPARESTRING(tr("mAh count"), QString("%1 mAh").arg(model->frsky.storedMah), true);
841 COMPARESTRING(tr("Persistent mAh"), modelPrinter->printMahPersistent(model->frsky.mAhPersistent), false);
843 columns.appendRowEnd();
844 columns.appendRowStart("", 20);
845 columns.appendCellStart(80);
846 COMPARESTRING(tr("Volts source"), modelPrinter->printVoltsSource(model->frsky.voltsSource), true);
847 COMPARESTRING(tr("Current source"), modelPrinter->printCurrentSource(model->frsky.currentSource), false);
848 columns.appendCellEnd();
849 columns.appendRowEnd();
850 columns.appendRowStart("", 20);
851 LABELCOMPARECELL(tr("Blades"), model->frsky.blades, 80);
852 columns.appendRowEnd();
854 columns.appendTableEnd();
855 str.append(columns.print());
856 return str;
859 QString MultiModelPrinter::printSensors()
861 MultiColumns columns(modelPrinterMap.size());
862 QString str;
863 int count = 0;
864 columns.appendSectionTableStart();
865 columns.appendRowHeader(QStringList() << tr("Name") << tr("Type") << tr("Parameters"));
866 for (unsigned i=0; i<CPN_MAX_SENSORS; ++i) {
867 bool tsEmpty = true;
868 for (int k=0; k < modelPrinterMap.size(); k++) {
869 if (modelPrinterMap.value(k).first->sensorData[i].isAvailable()) {
870 tsEmpty = false;
871 break;
874 if (!tsEmpty) {
875 count++;
876 columns.appendRowStart();
877 columns.appendCellStart(20, true);
878 COMPARE(model->sensorData[i].nameToString(i));
879 columns.appendCellEnd(true);
880 COMPARECELLWIDTH(modelPrinter->printSensorTypeCond(i), 15);
881 COMPARECELLWIDTH(modelPrinter->printSensorParams(i), 65);
882 columns.appendRowEnd();
885 columns.appendTableEnd();
886 if (count > 0) {
887 str.append(printTitle(tr("Telemetry Sensors")));
888 str.append(columns.print());
890 return str;
893 QString MultiModelPrinter::printTelemetryScreens()
895 MultiColumns columns(modelPrinterMap.size());
896 QString str;
897 int count = 0;
898 columns.appendSectionTableStart();
899 for (int i=0; i<firmware->getCapability(TelemetryCustomScreens); ++i) {
900 bool tsEmpty = true;
901 for (int k=0; k < modelPrinterMap.size(); k++) {
902 if (!(modelPrinterMap.value(k).first->frsky.screens[i].type == TELEMETRY_SCREEN_NONE)) {
903 tsEmpty = false;
904 break;
907 if (!tsEmpty) {
908 count++;
909 columns.appendRowStart();
910 LABELCOMPARECELL(QString("%1").arg(i+1), modelPrinter->printTelemetryScreenType(model->frsky.screens[i].type), 20);
911 columns.appendRowEnd();
912 for (int l=0; l<4; l++) {
913 COMPARE(modelPrinter->printTelemetryScreen(i, l, 80));
917 columns.appendTableEnd();
918 if (count > 0) {
919 str.append(printTitle(tr("Telemetry Screens")));
920 str.append(columns.print());
922 return str;
925 QString MultiModelPrinter::printGlobalFunctions()
927 QString str;
928 QString txt;
929 int count = 0;
930 int idx = -1;
931 MultiColumns columns(modelPrinterMap.size());
932 columns.appendSectionTableStart();
934 for (int k=0; k < modelPrinterMap.size(); k++) {
935 if (!modelPrinterMap.value(k).first->noGlobalFunctions) {
936 idx = k;
937 break;
941 if (idx > -1) {
942 ModelPrinter * modelPrinter = modelPrinterMap.value(idx).second;
943 (void)(modelPrinter);
945 for (int i=0; i < firmware->getCapability(GlobalFunctions); i++) {
946 txt = modelPrinter->printCustomFunctionLine(i, true);
947 if (!txt.isEmpty()) {
948 count++;
949 ROWLABELCOMPARECELL(tr("GF%1").arg(i+1), 20, modelPrinter->printCustomFunctionLine(i, true), 80);
952 columns.appendTableEnd();
953 if (count > 0) {
954 str.append(printTitle(tr("Global Functions")));
955 str.append(columns.print());
958 return str;
961 QString MultiModelPrinter::printChecklist()
963 QString str;
964 MultiColumns columns(modelPrinterMap.size());
965 bool isChecklist = false;
966 for (int k=0; k < modelPrinterMap.size(); k++) {
967 if (modelPrinterMap.value(k).first->displayChecklist) {
968 isChecklist = true;
969 break;
972 if (isChecklist) {
973 columns.appendSectionTableStart();
974 ROWLABELCOMPARECELL(tr("Checklist"), 20, modelPrinter->printChecklist(), 80);
975 columns.appendTableEnd();
976 str.append(columns.print());
978 return str;