Fix X7 R9M power line not enabled (#5973)
[opentx.git] / companion / src / multimodelprinter.cpp
blob94038e17f489c68fe21251330b53ac1d926d2df2
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(Timers)) {
276 str.append(printTimers());
278 str.append(printModules());
279 if (firmware->getCapability(Heli))
280 str.append(printHeliSetup());
281 if (firmware->getCapability(FlightModes))
282 str.append(printFlightModes());
283 str.append(printInputs());
284 str.append(printMixers());
285 str.append(printOutputs());
286 str += printCurves(document);
287 if (firmware->getCapability(Gvars) && !firmware->getCapability(GvarsFlightModes))
288 str.append(printGvars());
289 str.append(printLogicalSwitches());
290 str.append(printSpecialFunctions());
291 if (firmware->getCapability(Telemetry) & TM_HASTELEMETRY) {
292 str.append(printTelemetry());
293 str.append(printSensors());
294 if (firmware->getCapability(TelemetryCustomScreens)) {
295 str.append(printTelemetryScreens());
298 str.append("</table>");
299 return str;
302 QString MultiModelPrinter::printSetup()
304 QString str = printTitle(tr("General"));
306 MultiColumns columns(modelPrinterMap.size());
307 columns.appendSectionTableStart();
308 ROWLABELCOMPARECELL(tr("Name"), 20, model->name, 80);
309 ROWLABELCOMPARECELL(tr("EEprom Size"), 0, modelPrinter->printEEpromSize(), 0);
310 if (firmware->getCapability(ModelImage)) {
311 ROWLABELCOMPARECELL(tr("Model Image"), 0, model->bitmap, 0);
313 ROWLABELCOMPARECELL(tr("Throttle"), 0, modelPrinter->printThrottle(), 0);
314 ROWLABELCOMPARECELL(tr("Trims"), 0, modelPrinter->printSettingsTrim(), 0);
315 ROWLABELCOMPARECELL(tr("Center Beep"), 0, modelPrinter->printCenterBeep(), 0);
316 ROWLABELCOMPARECELL(tr("Switch Warnings"), 0, modelPrinter->printSwitchWarnings(), 0);
317 if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
318 ROWLABELCOMPARECELL(tr("Pot Warnings"), 0, modelPrinter->printPotWarnings(), 0);
320 ROWLABELCOMPARECELL(tr("Other"), 0, modelPrinter->printSettingsOther(), 0);
321 columns.appendTableEnd();
322 str.append(columns.print());
323 return str;
326 QString MultiModelPrinter::printTimers()
328 QString str;
329 MultiColumns columns(modelPrinterMap.size());
330 columns.appendSectionTableStart();
331 columns.appendRowHeader(QStringList() << tr("Timers") << tr("Time") << tr("Switch") << tr("Countdown") << tr("Min.call") << tr("Persist"));
333 for (int i=0; i<firmware->getCapability(Timers); i++) {
334 columns.appendRowStart();
335 columns.appendCellStart(20, true);
336 COMPARE(modelPrinter->printTimerName(i));
337 columns.appendCellEnd(true);
338 COMPARECELLWIDTH(modelPrinter->printTimerTimeValue(model->timers[i].val), 15);
339 COMPARECELLWIDTH(model->timers[i].mode.toString(), 15);
340 COMPARECELLWIDTH(modelPrinter->printTimerCountdownBeep(model->timers[i].countdownBeep), 15);
341 COMPARECELLWIDTH(modelPrinter->printTimerMinuteBeep(model->timers[i].minuteBeep), 15);
342 COMPARECELLWIDTH(modelPrinter->printTimerPersistent(model->timers[i].persistent), 20);
343 columns.appendRowEnd();
345 columns.appendTableEnd();
346 str.append(columns.print());
347 return str;
350 QString MultiModelPrinter::printModules()
352 QString str = printTitle(tr("Modules"));
353 MultiColumns columns(modelPrinterMap.size());
354 columns.appendSectionTableStart();
355 for (int i=0; i<firmware->getCapability(NumModules); i++) {
356 columns.appendRowStart();
357 columns.appendCellStart(20, true);
358 COMPARE(modelPrinter->printModuleType(i));
359 columns.appendCellEnd(true);
360 COMPARECELLWIDTH(modelPrinter->printModule(i), 80);
361 columns.appendRowEnd();
363 if (firmware->getCapability(ModelTrainerEnable))
364 columns.appendRowStart(tr("Trainer port"));
365 COMPARECELL(modelPrinter->printModule(-1));
366 columns.appendRowEnd();
367 columns.appendTableEnd();
368 str.append(columns.print());
369 return str;
372 QString MultiModelPrinter::printHeliSetup()
374 bool heliEnabled = false;
375 for (int k=0; k < modelPrinterMap.size(); k++) {
376 heliEnabled = heliEnabled || modelPrinterMap.value(k).first->swashRingData.type != HELI_SWASH_TYPE_NONE;
379 if (!heliEnabled)
380 return "";
382 QString str = printTitle(tr("Helicopter"));
383 MultiColumns columns(modelPrinterMap.size());
384 columns.appendSectionTableStart();
385 columns.appendRowStart(tr("Swash"), 20);
386 LABELCOMPARECELL(tr("Type"), modelPrinter->printHeliSwashType(), 20);
387 LABELCOMPARECELL(tr("Ring"), model->swashRingData.value, 20);
388 columns.appendRowEnd();
390 columns.appendRowBlank();
391 columns.appendRowHeader(QStringList() << "" << tr("Input") << tr("Weight"));
392 columns.appendRowStart(tr("Long. cyc"));
393 COMPARECELL(model->swashRingData.elevatorSource.toString(model));
394 COMPARECELL(model->swashRingData.elevatorWeight);
395 columns.appendRowEnd();
397 columns.appendRowStart(tr("Lateral cyc"));
398 COMPARECELL(model->swashRingData.aileronSource.toString(model));
399 COMPARECELL(model->swashRingData.aileronWeight)
400 columns.appendRowEnd();
402 columns.appendRowStart(tr("Collective"));
403 COMPARECELL(model->swashRingData.collectiveSource.toString(model));
404 COMPARECELL(model->swashRingData.collectiveWeight)
405 columns.appendRowEnd();
407 columns.appendTableEnd();
408 str.append(columns.print());
409 return str;
412 QString MultiModelPrinter::printFlightModes()
414 QString str = printTitle(tr("Flight modes"));
415 // Trims
417 MultiColumns columns(modelPrinterMap.size());
418 columns.appendSectionTableStart();
419 QStringList hd = QStringList() << tr("Flight mode") << tr("Switch") << tr("F.In") << tr("F.Out");
420 for (int i=0; i < getBoardCapability(getCurrentBoard(), Board::NumTrims); i++) {
421 hd << RawSource(SOURCE_TYPE_TRIM, i).toString();
423 columns.appendRowHeader(hd);
424 int wd = 80/(getBoardCapability(getCurrentBoard(), Board::NumTrims) + 3);
425 for (int i=0; i<firmware->getCapability(FlightModes); i++) {
426 columns.appendRowStart();
427 columns.appendCellStart(20,true);
428 COMPARE(modelPrinter->printFlightModeName(i));
429 columns.appendCellEnd(true);
430 COMPARECELLWIDTH(modelPrinter->printFlightModeSwitch(model->flightModeData[i].swtch), wd);
431 COMPARECELLWIDTH(model->flightModeData[i].fadeIn, wd);
432 COMPARECELLWIDTH(model->flightModeData[i].fadeOut, wd);
433 for (int k=0; k < getBoardCapability(getCurrentBoard(), Board::NumTrims); k++) {
434 COMPARECELLWIDTH(modelPrinter->printTrim(i, k), wd);
436 columns.appendRowEnd();
439 columns.appendTableEnd();
440 str.append(columns.print());
443 // GVars and Rotary Encoders
444 int gvars = firmware->getCapability(Gvars);
445 if ((gvars && firmware->getCapability(GvarsFlightModes)) || firmware->getCapability(RotaryEncoders)) {
446 MultiColumns columns(modelPrinterMap.size());
447 columns.appendSectionTableStart();
448 QStringList hd = QStringList() << tr("Global vars");
449 if (firmware->getCapability(GvarsFlightModes)) {
450 for (int i=0; i<gvars; i++) {
451 hd << tr("GV%1").arg(i+1);
454 for (int i=0; i<firmware->getCapability(RotaryEncoders); i++) {
455 hd << tr("RE%1").arg(i+1);
457 columns.appendRowHeader(hd);
458 int wd = 80/gvars;
459 if (firmware->getCapability(GvarsFlightModes)) {
460 columns.appendRowStart(tr("Name"), 20);
461 for (int i=0; i<gvars; i++) {
462 COMPARECELLWIDTH(model->gvarData[i].name, wd);
464 columns.appendRowEnd();
465 columns.appendRowStart(tr("Unit"));
466 for (int i=0; i<gvars; i++) {
467 COMPARECELL(modelPrinter->printGlobalVarUnit(i));
469 columns.appendRowEnd();
470 columns.appendRowStart(tr("Prec"));
471 for (int i=0; i<gvars; i++) {
472 COMPARECELL(modelPrinter->printGlobalVarPrec(i));
474 columns.appendRowEnd();
475 columns.appendRowStart(tr("Min"));
476 for (int i=0; i<gvars; i++) {
477 COMPARECELL(modelPrinter->printGlobalVarMin(i));
479 columns.appendRowEnd();
480 columns.appendRowStart(tr("Max"));
481 for (int i=0; i<gvars; i++) {
482 COMPARECELL(modelPrinter->printGlobalVarMax(i));
484 columns.appendRowEnd();
485 columns.appendRowStart(tr("Popup"));
486 for (int i=0; i<gvars; i++) {
487 COMPARECELL(modelPrinter->printGlobalVarPopup(i));
489 columns.appendRowEnd();
492 columns.appendRowHeader(QStringList() << tr("Flight mode"));
494 for (int i=0; i<firmware->getCapability(FlightModes); i++) {
495 columns.appendRowStart();
496 columns.appendCellStart(0,true);
497 COMPARE(modelPrinter->printFlightModeName(i));
498 columns.appendCellEnd(true);
499 if (firmware->getCapability(GvarsFlightModes)) {
500 for (int k=0; k<gvars; k++) {
501 COMPARECELL(modelPrinter->printGlobalVar(i, k));
504 for (int k=0; k<firmware->getCapability(RotaryEncoders); k++) {
505 COMPARECELL(modelPrinter->printRotaryEncoder(i, k));
507 columns.appendRowEnd();
509 columns.appendTableEnd();
510 str.append(columns.print());
513 return str;
516 QString MultiModelPrinter::printOutputs()
518 QString str = printTitle(tr("Outputs"));
519 MultiColumns columns(modelPrinterMap.size());
520 columns.appendSectionTableStart();
521 QStringList hd = QStringList() << tr("Channel") << tr("Subtrim") << tr("Min") << tr("Max") << tr("Direct");
522 if (IS_HORUS_OR_TARANIS(firmware->getBoard()))
523 hd << tr("Curve");
524 if (firmware->getCapability(PPMCenter))
525 hd << tr("PPM");
526 if (firmware->getCapability(SYMLimits))
527 hd << tr("Linear");
528 columns.appendRowHeader(hd);
529 int cols = 4;
530 if (IS_HORUS_OR_TARANIS(firmware->getBoard()))
531 cols++;
532 if (firmware->getCapability(PPMCenter))
533 cols++;
534 if (firmware->getCapability(SYMLimits))
535 cols++;
536 int wd = 80/cols;
537 for (int i=0; i<firmware->getCapability(Outputs); i++) {
538 int count = 0;
539 for (int k=0; k < modelPrinterMap.size(); k++)
540 count = std::max(count, modelPrinterMap.value(k).first->mixes(i).size());
541 if (!count)
542 continue;
543 columns.appendRowStart();
544 columns.appendCellStart(20, true);
545 COMPARE(modelPrinter->printChannelName(i));
546 columns.appendCellEnd(true);
547 COMPARECELLWIDTH(modelPrinter->printOutputOffset(i), wd);
548 COMPARECELLWIDTH(modelPrinter->printOutputMin(i), wd);
549 COMPARECELLWIDTH(modelPrinter->printOutputMax(i), wd);
550 COMPARECELLWIDTH(modelPrinter->printOutputRevert(i), wd);
551 if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
552 COMPARECELLWIDTH(modelPrinter->printOutputCurve(i), wd);
554 if (firmware->getCapability(PPMCenter)) {
555 COMPARECELLWIDTH(modelPrinter->printOutputPpmCenter(i), wd);
557 if (firmware->getCapability(SYMLimits)) {
558 COMPARECELLWIDTH(modelPrinter->printOutputSymetrical(i), wd);
560 columns.appendRowEnd();
562 columns.appendTableEnd();
563 str.append(columns.print());
564 return str;
567 QString MultiModelPrinter::printGvars()
569 QString str = printTitle(tr("Global Variables"));
570 int gvars = firmware->getCapability(Gvars);
571 MultiColumns columns(modelPrinterMap.size());
572 columns.appendSectionTableStart();
573 QStringList hd;
574 for (int i=0; i<gvars; i++) {
575 hd << tr("GV%1").arg(i+1);
577 columns.appendRowHeader(hd);
579 for (int i=0; i<gvars; i++) {
580 COMPARECELL(model->flightModeData[0].gvars[i]);
582 columns.appendRowEnd();
583 columns.appendTableEnd();
584 str.append(columns.print());
585 return str;
588 QString MultiModelPrinter::printInputs()
590 QString str = printTitle(tr("Inputs"));
591 MultiColumns columns(modelPrinterMap.size());
592 columns.appendSectionTableStart();
593 for (int i=0; i<std::max(4, firmware->getCapability(VirtualInputs)); i++) {
594 int count = 0;
595 for (int k=0; k < modelPrinterMap.size(); k++) {
596 count = std::max(count, modelPrinterMap.value(k).first->expos(i).size());
598 if (count > 0) {
599 columns.appendRowStart();
600 columns.appendCellStart(20, true);
601 COMPARE(modelPrinter->printInputName(i));
602 columns.appendCellEnd(true);
603 columns.appendCellStart(80);
604 for (int j=0; j<count; j++) {
605 if (j > 0)
606 columns.appendLineBreak();
607 COMPARE(j<model->expos(i).size() ? modelPrinter->printInputLine(*model->expos(i)[j]) : "");
609 columns.appendCellEnd();
610 columns.appendRowEnd();
613 columns.appendTableEnd();
614 str.append(columns.print());
615 return str;
618 QString MultiModelPrinter::printMixers()
620 QString str = printTitle(tr("Mixers"));
621 MultiColumns columns(modelPrinterMap.size());
622 columns.appendSectionTableStart();
623 for (int i=0; i<firmware->getCapability(Outputs); i++) {
624 int count = 0;
625 for (int k=0; k < modelPrinterMap.size(); k++) {
626 count = std::max(count, modelPrinterMap.value(k).first->mixes(i).size());
628 if (count > 0) {
629 columns.appendRowStart();
630 columns.appendCellStart(20, true);
631 COMPARE(modelPrinter->printChannelName(i));
632 columns.appendCellEnd(true);
633 columns.appendCellStart(80);
634 for (int j=0; j<count; j++) {
635 if (j > 0)
636 columns.appendLineBreak();
637 COMPARE((j < model->mixes(i).size()) ? modelPrinter->printMixerLine(*model->mixes(i)[j], (j>0)) : "&nbsp;");
639 columns.appendCellEnd();
640 columns.appendRowEnd();
643 columns.appendTableEnd();
644 str.append(columns.print());
645 return str;
648 QString MultiModelPrinter::printCurves(QTextDocument * document)
650 QString str;
651 MultiColumns columns(modelPrinterMap.size());
652 int count = 0;
653 columns.appendSectionTableStart();
654 for (int i=0; i<firmware->getCapability(NumCurves); i++) {
655 bool curveEmpty = true;
656 for (int k=0; k < modelPrinterMap.size(); k++) {
657 if (!modelPrinterMap.value(k).first->curves[i].isEmpty()) {
658 curveEmpty = false;
659 break;
662 if (!curveEmpty) {
663 count++;
664 columns.appendRowStart();
665 columns.appendCellStart(20, true);
666 COMPARE(modelPrinter->printCurveName(i));
667 columns.appendCellEnd(true);
668 COMPARECELL(modelPrinter->printCurve(i));
669 columns.appendRowEnd();
670 columns.appendRowStart("", 20);
671 columns.appendCellStart();
672 for (int k=0; k < modelPrinterMap.size(); k++)
673 columns.append(k, QString("<br/><img src='%1' border='0' /><br/>").arg(modelPrinterMap.value(k).second->createCurveImage(i, document)));
674 columns.appendCellEnd();
675 columns.appendRowEnd();
678 columns.appendTableEnd();
679 if (count > 0) {
680 str.append(printTitle(tr("Curves")));
681 str.append(columns.print());
683 return str;
686 QString MultiModelPrinter::printLogicalSwitches()
688 QString str;
689 MultiColumns columns(modelPrinterMap.size());
690 columns.appendSectionTableStart();
691 int count = 0;
692 for (int i=0; i<firmware->getCapability(LogicalSwitches); i++) {
693 bool lsEmpty = true;
694 for (int k=0; k < modelPrinterMap.size(); k++) {
695 if (!modelPrinterMap.value(k).first->logicalSw[i].isEmpty()) {
696 lsEmpty = false;
697 break;
700 if (!lsEmpty) {
701 count++;
702 columns.appendRowStart(tr("L%1").arg(i+1), 20);
703 COMPARECELL(modelPrinter->printLogicalSwitchLine(i));
704 columns.appendRowEnd();
707 columns.appendTableEnd();
708 if (count > 0) {
709 str.append(printTitle(tr("Logical Switches")));
710 str.append(columns.print());
712 return str;
715 QString MultiModelPrinter::printSpecialFunctions()
717 QString str;
718 MultiColumns columns(modelPrinterMap.size());
719 int count = 0;
720 columns.appendSectionTableStart();
721 for (int i=0; i < firmware->getCapability(CustomFunctions); i++) {
722 bool sfEmpty = true;
723 for (int k=0; k < modelPrinterMap.size(); k++) {
724 if (!modelPrinterMap.value(k).first->customFn[i].isEmpty()) {
725 sfEmpty = false;
726 break;
729 if (!sfEmpty) {
730 count++;
731 columns.appendRowStart(tr("SF%1").arg(i+1), 20);
732 COMPARECELL(modelPrinter->printCustomFunctionLine(i));
733 columns.appendRowEnd();
736 columns.appendTableEnd();
737 if (count > 0) {
738 str.append(printTitle(tr("Special Functions")));
739 str.append(columns.print());
741 return str;
744 QString MultiModelPrinter::printTelemetry()
746 QString str = printTitle(tr("Telemetry"));
747 MultiColumns columns(modelPrinterMap.size());
748 columns.appendSectionTableStart();
750 // Analogs on non ARM boards
751 if (!IS_ARM(firmware->getBoard())) {
752 columns.appendRowHeader(QStringList() << tr("Analogs") << tr("Unit") << tr("Scale") << tr("Offset"));
753 for (int i=0; i<2; i++) {
754 columns.appendRowStart(QString("A%1").arg(i+1), 20);
755 COMPARECELLWIDTH(FrSkyChannelData::unitString(model->frsky.channels[i].type), 20);
756 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);
757 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);
758 columns.appendRowEnd();
761 else {
762 // Protocol
763 columns.appendRowStart(tr("Protocol"), 20);
764 COMPARECELL(modelPrinter->printTelemetryProtocol(model->telemetryProtocol));
765 columns.appendRowEnd();
768 // RSSI alarms
770 columns.appendRowStart(tr("RSSI Alarms"), 20);
771 columns.appendCellStart(80);
772 COMPARESTRING("", (IS_ARM(getCurrentBoard()) ? tr("Low") : FrSkyAlarmData::alarmLevelName(model->rssiAlarms.level[0])), false);
773 columns.append(": ");
774 COMPARESTRING("", QString("&lt; %1").arg(QString::number(model->rssiAlarms.warning, 10)), true);
775 COMPARESTRING("", (IS_ARM(getCurrentBoard()) ? tr("Critical") : FrSkyAlarmData::alarmLevelName(model->rssiAlarms.level[1])), false);
776 columns.append(": ");
777 COMPARESTRING("", QString("&lt; %1").arg(QString::number(model->rssiAlarms.critical, 10)), true);
778 COMPARESTRING(tr("Telemetry audio"), modelPrinter->printRssiAlarmsDisabled(model->rssiAlarms.disabled), false);
779 columns.appendCellEnd();
780 columns.appendRowEnd();
783 // Altimetry
784 if (firmware->getCapability(HasVario)) {
785 columns.appendRowStart(tr("Altimetry"), 20);
786 if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
787 LABELCOMPARECELL(tr("Vario source"), modelPrinter->printTelemetrySource(model->frsky.varioSource), 80);
789 else {
790 LABELCOMPARECELL(tr("Vario source"), modelPrinter->printVarioSource(model->frsky.varioSource), 80);
792 columns.appendRowEnd();
793 columns.appendRowStart("", 20);
794 columns.appendCellStart(80);
795 columns.appendTitle(tr("Vario limits >"));
796 if (firmware->getCapability(HasVarioSink)) {
797 COMPARESTRING(tr("Sink max"), QString::number(model->frsky.varioMin - 10), true);
798 COMPARESTRING(tr("Sink min"), QString::number((float(model->frsky.varioCenterMin) / 10.0) - 0.5), true);
800 COMPARESTRING(tr("Climb min"), QString::number((float(model->frsky.varioCenterMax) / 10.0) + 0.5), true);
801 COMPARESTRING(tr("Climb max"), QString::number(model->frsky.varioMax + 10), true);
802 COMPARESTRING(tr("Center silent"), modelPrinter->printVarioCenterSilent(model->frsky.varioCenterSilent), false);
803 columns.appendCellEnd();
804 columns.appendRowEnd();
807 // Top Bar
808 if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
809 columns.appendRowStart(tr("Top Bar"), 20);
810 columns.appendCellStart(80);
811 COMPARESTRING(tr("Volts source"), modelPrinter->printTelemetrySource(model->frsky.voltsSource), true);
812 COMPARESTRING(tr("Altitude source"), modelPrinter->printTelemetrySource(model->frsky.altitudeSource), false);
813 columns.appendCellEnd();
814 columns.appendRowEnd();
817 if (IS_ARM(firmware->getBoard())) {
818 ROWLABELCOMPARECELL("Multi sensors", 0, modelPrinter->printIgnoreSensorIds(!model->frsky.ignoreSensorIds), 0);
821 // Various
822 if (!IS_ARM(firmware->getBoard())) {
823 columns.appendRowHeader(QStringList() << tr("Various"));
824 if (!firmware->getCapability(NoTelemetryProtocol)) {
825 columns.appendRowStart("", 20);
826 LABELCOMPARECELL(tr("Serial protocol"), modelPrinter->printTelemetrySource(model->frsky.voltsSource), 80);
827 columns.appendRowEnd();
829 columns.appendRowStart("", 20);
830 columns.appendCellStart(80);
831 QString firmware_id = g.profile[g.id()].fwType();
832 if (firmware->getCapability(HasFasOffset) && firmware_id.contains("fasoffset")) {
833 COMPARESTRING(tr("FAS offset"), QString("%1 A").arg(model->frsky.fasOffset/10.0), true);
835 if (firmware->getCapability(HasMahPersistent)) {
836 COMPARESTRING(tr("mAh count"), QString("%1 mAh").arg(model->frsky.storedMah), true);
837 COMPARESTRING(tr("Persistent mAh"), modelPrinter->printMahPersistent(model->frsky.mAhPersistent), false);
839 columns.appendRowEnd();
840 columns.appendRowStart("", 20);
841 columns.appendCellStart(80);
842 COMPARESTRING(tr("Volts source"), modelPrinter->printVoltsSource(model->frsky.voltsSource), true);
843 COMPARESTRING(tr("Current source"), modelPrinter->printCurrentSource(model->frsky.currentSource), false);
844 columns.appendCellEnd();
845 columns.appendRowEnd();
846 columns.appendRowStart("", 20);
847 LABELCOMPARECELL(tr("Blades"), model->frsky.blades, 80);
848 columns.appendRowEnd();
850 columns.appendTableEnd();
851 str.append(columns.print());
852 return str;
855 QString MultiModelPrinter::printSensors()
857 MultiColumns columns(modelPrinterMap.size());
858 QString str;
859 int count = 0;
860 columns.appendSectionTableStart();
861 columns.appendRowHeader(QStringList() << tr("Name") << tr("Type") << tr("Parameters"));
862 for (int i=0; i<CPN_MAX_SENSORS; ++i) {
863 bool tsEmpty = true;
864 for (int k=0; k < modelPrinterMap.size(); k++) {
865 if (modelPrinterMap.value(k).first->sensorData[i].isAvailable()) {
866 tsEmpty = false;
867 break;
870 if (!tsEmpty) {
871 count++;
872 columns.appendRowStart();
873 columns.appendCellStart(20, true);
874 COMPARE(model->sensorData[i].nameToString(i));
875 columns.appendCellEnd(true);
876 COMPARECELLWIDTH(modelPrinter->printSensorTypeCond(i), 15);
877 COMPARECELLWIDTH(modelPrinter->printSensorParams(i), 65);
878 columns.appendRowEnd();
881 columns.appendTableEnd();
882 if (count > 0) {
883 str.append(printTitle(tr("Telemetry Sensors")));
884 str.append(columns.print());
886 return str;
889 QString MultiModelPrinter::printTelemetryScreens()
891 MultiColumns columns(modelPrinterMap.size());
892 QString str;
893 int count = 0;
894 columns.appendSectionTableStart();
895 for (int i=0; i<firmware->getCapability(TelemetryCustomScreens); ++i) {
896 bool tsEmpty = true;
897 for (int k=0; k < modelPrinterMap.size(); k++) {
898 if (!(modelPrinterMap.value(k).first->frsky.screens[i].type == TELEMETRY_SCREEN_NONE)) {
899 tsEmpty = false;
900 break;
903 if (!tsEmpty) {
904 count++;
905 columns.appendRowStart();
906 LABELCOMPARECELL(QString("%1").arg(i+1), modelPrinter->printTelemetryScreenType(model->frsky.screens[i].type), 20);
907 columns.appendRowEnd();
908 for (int l=0; l<4; l++) {
909 COMPARE(modelPrinter->printTelemetryScreen(i, l, 80));
913 columns.appendTableEnd();
914 if (count > 0) {
915 str.append(printTitle(tr("Telemetry Screens")));
916 str.append(columns.print());
918 return str;