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.
22 #include "modelprinter.h"
23 #include "multiprotocols.h"
26 #include <QApplication>
30 #include "multiprotocols.h"
32 QString
changeColor(const QString
& input
, const QString
& to
, const QString
& from
)
34 QString result
= input
;
35 return result
.replace("color="+from
, "color="+to
);
38 ModelPrinter::ModelPrinter(Firmware
* firmware
, const GeneralSettings
& generalSettings
, const ModelData
& model
):
40 generalSettings(generalSettings
),
45 ModelPrinter::~ModelPrinter()
49 QString
formatTitle(const QString
& name
)
51 return QString("<b>" + name
+ "</b> ");
54 void debugHtml(const QString
& html
)
56 QFile
file("foo.html");
57 file
.open(QIODevice::Truncate
| QIODevice::WriteOnly
);
58 file
.write(html
.toUtf8());
62 QString
addFont(const QString
& input
, const QString
& color
, const QString
& size
, const QString
& face
)
65 if (!color
.isEmpty()) {
66 colorStr
= "color=" + color
;
69 if (!size
.isEmpty()) {
70 sizeStr
= "size=" + size
;
73 if (!face
.isEmpty()) {
74 faceStr
= "face='" + face
+ "'";
76 return "<font " + sizeStr
+ " " + faceStr
+ " " + colorStr
+ ">" + input
+ "</font>";
79 #define MASK_TIMEVALUE_HRSMINS 1
80 #define MASK_TIMEVALUE_ZEROHRS 2
81 #define MASK_TIMEVALUE_PADSIGN 3
83 QString
ModelPrinter::printTimeValue(const int value
, const unsigned int mask
)
92 result
= (sign
< 0 ? QString("-") : ((mask
&& MASK_TIMEVALUE_PADSIGN
) ? QString(" ") : QString("")));
93 if (mask
&& MASK_TIMEVALUE_HRSMINS
) {
94 int hours
= val
/ 3600;
95 if (hours
> 0 || (mask
&& MASK_TIMEVALUE_ZEROHRS
)) {
97 result
.append(QString("%1:").arg(hours
, 2, 10, QLatin1Char('0')));
100 int minutes
= val
/ 60;
101 int seconds
= val
% 60;
102 result
.append(QString("%1:%2").arg(minutes
, 2, 10, QLatin1Char('0')).arg(seconds
, 2, 10, QLatin1Char('0')));
106 #define BOOLEAN_ENABLEDISABLE 1
107 #define BOOLEAN_TRUEFALSE 2
108 #define BOOLEAN_YESNO 3
110 #define BOOLEAN_ONOFF 5
112 QString
ModelPrinter::printBoolean(const bool val
, const int typ
)
115 case BOOLEAN_ENABLEDISABLE
:
116 return (val
? tr("Enable") : tr("Disable"));
117 case BOOLEAN_TRUEFALSE
:
118 return (val
? tr("True") : tr("False"));
120 return (val
? tr("Yes") : tr("No"));
122 return (val
? tr("Y") : tr("N"));
124 return (val
? tr("ON") : tr("OFF"));
130 QString
ModelPrinter::printEEpromSize()
132 return QString("%1 ").arg(getCurrentEEpromInterface()->getSize(model
)) + tr("bytes");
135 QString
ModelPrinter::printChannelName(int idx
)
137 QString str
= RawSource(SOURCE_TYPE_CH
, idx
).toString(&model
, &generalSettings
);
138 if (firmware
->getCapability(ChannelsName
)) {
139 str
= str
.leftJustified(firmware
->getCapability(ChannelsName
) + 5, ' ', false);
142 return str
.toHtmlEscaped();
145 QString
ModelPrinter::printTrimIncrementMode()
147 switch (model
.trimInc
) {
149 return tr("Exponential");
151 return tr("Extra Fine");
159 return tr("Unknown");
163 QString
ModelPrinter::printModuleProtocol(unsigned int protocol
)
165 static const char * strings
[] = {
168 "Silverlit A", "Silverlit B", "Silverlit C",
170 "LP45", "DSM2", "DSMX",
172 "FrSky XJT (D16)", "FrSky XJT (D8)", "FrSky XJT (LR12)", "FrSky DJT",
174 "DIY Multiprotocol Module",
176 "SBUS output at VBat"
179 return CHECK_IN_ARRAY(strings
, protocol
);
182 QString
ModelPrinter::printMultiRfProtocol(int rfProtocol
, bool custom
)
184 static const char *strings
[] = {
185 "FlySky", "Hubsan", "FrSky", "Hisky", "V2x2", "DSM", "Devo", "YD717", "KN", "SymaX", "SLT", "CX10", "CG023",
186 "Bayang", "ESky", "MT99XX", "MJXQ", "Shenqi", "FY326", "SFHSS", "J6 PRO","FQ777","Assan","Hontai","OLRS",
187 "FlySky AFHDS2A", "Q2x2", "Walkera", "Q303", "GW008", "DM002", "CABELL", "Esky 150", "H8 3D"
190 return "Custom - proto " + QString::number(rfProtocol
);
192 return CHECK_IN_ARRAY(strings
, rfProtocol
);
195 QString
ModelPrinter::printMultiSubType(unsigned rfProtocol
, bool custom
, unsigned int subType
) {
196 /* custom protocols */
199 rfProtocol
= MM_RF_CUSTOM_SELECTED
;
201 Multiprotocols::MultiProtocolDefinition pdef
= multiProtocols
.getProtocol(rfProtocol
);
203 if (subType
< (unsigned int) pdef
.subTypeStrings
.size())
204 return qApp
->translate("Multiprotocols", qPrintable(pdef
.subTypeStrings
[subType
]));
209 QString
ModelPrinter::printR9MPowerValue(unsigned subType
, unsigned val
, bool telem
)
211 static const QStringList strFTC
= QStringList() << tr("10mW") << tr("100mW") << tr("500mW") << tr("1W");
212 static const QStringList strLBT
= QStringList() << tr("25mW") << tr("500mW");
215 if (subType
== 0 && (int)val
< strFTC
.size())
216 return strFTC
.at(val
);
217 else if (subType
== 1)
218 return (telem
? strLBT
.at(0) : strLBT
.at(1));
223 QString
ModelPrinter::printModuleSubType(unsigned protocol
, unsigned subType
, unsigned rfProtocol
, bool custom
)
225 static const char * strings
[] = {
231 case PULSES_MULTIMODULE
:
232 return printMultiSubType(rfProtocol
, custom
, subType
);
235 return CHECK_IN_ARRAY(strings
, subType
);
242 QString
ModelPrinter::printModule(int idx
)
246 ModuleData module
= model
.moduleData
[(idx
<0 ? CPN_MAX_MODULES
: idx
)];
248 str
+= tr("Mode") + QString("(%1)").arg(printTrainerMode());
249 if (IS_HORUS_OR_TARANIS(firmware
->getBoard())) {
250 if (model
.trainerMode
== TRAINER_SLAVE_JACK
) {
251 str
+= tr("Channels") + QString("(%1-%2)").arg(module
.channelsStart
+ 1).arg(module
.channelsStart
+ module
.channelsCount
);
252 str
+= tr("Frame length") + QString("(%1ms)").arg(printPPMFrameLength(module
.ppm
.frameLength
));
253 str
+= tr("PPM delay") + QString("(%1us)").arg(module
.ppm
.delay
);
254 str
+= tr("Polarity") + QString("(%1)").arg(module
.polarityToString());
257 result
= str
.join(", ");
260 str
+= printModuleType(idx
);
261 str
+= tr("Protocol") + QString("(%1)").arg(printModuleProtocol(module
.protocol
));
262 if (module
.protocol
) {
263 str
+= tr("Channels") + QString("(%1-%2)").arg(module
.channelsStart
+ 1).arg(module
.channelsStart
+ module
.channelsCount
);
264 if (module
.protocol
== PULSES_PPM
|| module
.protocol
== PULSES_SBUS
) {
265 str
+= tr("Frame length") + QString("(%1ms)").arg(printPPMFrameLength(module
.ppm
.frameLength
));
266 str
+= tr("Polarity") + QString("(%1)").arg(module
.polarityToString());
267 if (module
.protocol
== PULSES_PPM
)
268 str
+= tr("Delay") + QString("(%1us)").arg(module
.ppm
.delay
);
271 if (!(module
.protocol
== PULSES_PXX_XJT_D8
|| module
.protocol
== PULSES_CROSSFIRE
|| module
.protocol
== PULSES_SBUS
)) {
272 str
+= tr("Receiver") + QString("(%1)").arg(module
.modelId
);
274 if (module
.protocol
== PULSES_MULTIMODULE
) {
275 str
+= tr("Radio protocol") + QString("(%1)").arg(printMultiRfProtocol(module
.multi
.rfProtocol
, module
.multi
.customProto
));
276 str
+= tr("Subtype") + QString("(%1)").arg(printMultiSubType(module
.multi
.rfProtocol
, module
.multi
.customProto
, module
.subType
));
277 str
+= tr("Option value") + QString("(%1)").arg(module
.multi
.optionValue
);
279 if (module
.protocol
== PULSES_PXX_R9M
) {
280 str
+= tr("Sub Type") + QString("(%1)").arg(printModuleSubType(module
.protocol
, module
.subType
));
281 str
+= tr("RF Output Power") + QString("(%1)").arg(printR9MPowerValue(module
.subType
, module
.pxx
.power
, module
.pxx
.sport_out
));
282 str
+= tr("Telemetry") + QString("(%1)").arg(printBoolean(module
.pxx
.sport_out
, BOOLEAN_ENABLEDISABLE
));
286 result
= str
.join(", ");
287 if (((PulsesProtocol
)module
.protocol
== PulsesProtocol::PULSES_PXX_XJT_X16
|| (PulsesProtocol
)module
.protocol
== PulsesProtocol::PULSES_PXX_R9M
)
288 && firmware
->getCapability(HasFailsafe
))
289 result
.append(printFailsafe(idx
));
294 QString
ModelPrinter::printTrainerMode()
297 switch (model
.trainerMode
) {
298 case TRAINER_MASTER_JACK
:
299 result
= tr("Master/Jack");
301 case TRAINER_SLAVE_JACK
:
302 result
= tr("Slave/Jack");
304 case TRAINER_MASTER_SBUS_MODULE
:
305 result
= tr("Master/SBUS Module");
307 case TRAINER_MASTER_CPPM_MODULE
:
308 result
= tr("Master/CPPM Module");
310 case TRAINER_MASTER_SBUS_BATT_COMPARTMENT
:
311 result
= tr("Master/SBUS in battery compartment");
319 QString
ModelPrinter::printHeliSwashType ()
321 switch (model
.swashRingData
.type
) {
322 case HELI_SWASH_TYPE_90
:
324 case HELI_SWASH_TYPE_120
:
326 case HELI_SWASH_TYPE_120X
:
328 case HELI_SWASH_TYPE_140
:
330 case HELI_SWASH_TYPE_NONE
:
337 QString
ModelPrinter::printCenterBeep()
340 if (model
.beepANACenter
& 0x01)
341 strl
<< tr("Rudder");
342 if (model
.beepANACenter
& 0x02)
343 strl
<< tr("Elevator");
344 if (model
.beepANACenter
& 0x04)
345 strl
<< tr("Throttle");
346 if (model
.beepANACenter
& 0x08)
347 strl
<< tr("Aileron");
348 if (IS_HORUS(firmware
->getBoard())) {
350 qDebug() << "ModelPrinter::printCenterBeep() TODO";
352 else if (IS_TARANIS(firmware
->getBoard())) {
353 if (model
.beepANACenter
& 0x10)
355 if (model
.beepANACenter
& 0x20)
357 if (model
.beepANACenter
& 0x40)
359 if (model
.beepANACenter
& 0x80)
361 if (model
.beepANACenter
& 0x100)
365 if (model
.beepANACenter
& 0x10)
367 if (model
.beepANACenter
& 0x20)
369 if (model
.beepANACenter
& 0x40)
372 return (strl
.isEmpty() ? tr("None") : strl
.join(", "));
375 QString
ModelPrinter::printTimer(int idx
)
377 return printTimer(model
.timers
[idx
]);
380 QString
ModelPrinter::printTimer(const TimerData
& timer
)
383 if (firmware
->getCapability(TimersName
) && timer
.name
[0])
384 result
+= tr("Name") + QString("(%1)").arg(timer
.name
);
385 result
+= printTimeValue(timer
.val
, MASK_TIMEVALUE_HRSMINS
| MASK_TIMEVALUE_ZEROHRS
);
386 result
+= timer
.mode
.toString();
387 if (timer
.countdownBeep
)
388 result
+= tr("Countdown") + QString("(%1)").arg(printTimerCountdownBeep(timer
.countdownBeep
));
389 if (timer
.minuteBeep
)
390 result
+= tr("Minute call");
391 if (timer
.persistent
)
392 result
+= tr("Persistent") + QString("(%1)").arg(printTimerPersistent(timer
.persistent
));
393 return result
.join(", ");
396 QString
ModelPrinter::printTrim(int flightModeIndex
, int stickIndex
)
398 const FlightModeData
& fm
= model
.flightModeData
[flightModeIndex
];
400 if (fm
.trimMode
[stickIndex
] == -1) {
404 if (fm
.trimRef
[stickIndex
] == flightModeIndex
) {
405 return QString("%1").arg(fm
.trim
[stickIndex
]);
408 if (fm
.trimMode
[stickIndex
] == 0) {
409 return tr("FM%1").arg(fm
.trimRef
[stickIndex
]);
412 if (fm
.trim
[stickIndex
] < 0)
413 return tr("FM%1%2").arg(fm
.trimRef
[stickIndex
]).arg(fm
.trim
[stickIndex
]);
415 return tr("FM%1+%2").arg(fm
.trimRef
[stickIndex
]).arg(fm
.trim
[stickIndex
]);
421 QString
ModelPrinter::printGlobalVar(int flightModeIndex
, int gvarIndex
)
423 const FlightModeData
& fm
= model
.flightModeData
[flightModeIndex
];
425 if (fm
.gvars
[gvarIndex
] <= 1024) {
426 return QString("%1").arg(fm
.gvars
[gvarIndex
] * model
.gvarData
[gvarIndex
].multiplierGet());
429 int num
= fm
.gvars
[gvarIndex
] - 1025;
430 if (num
>= flightModeIndex
) num
++;
431 return tr("FM%1").arg(num
);
435 QString
ModelPrinter::printRotaryEncoder(int flightModeIndex
, int reIndex
)
437 const FlightModeData
& fm
= model
.flightModeData
[flightModeIndex
];
439 if (fm
.rotaryEncoders
[reIndex
] <= 1024) {
440 return QString("%1").arg(fm
.rotaryEncoders
[reIndex
]);
443 int num
= fm
.rotaryEncoders
[reIndex
] - 1025;
444 if (num
>= flightModeIndex
) num
++;
445 return tr("FM%1").arg(num
);
449 QString
ModelPrinter::printInputName(int idx
)
451 RawSourceType srcType
= (firmware
->getCapability(VirtualInputs
) ? SOURCE_TYPE_VIRTUAL_INPUT
: SOURCE_TYPE_STICK
);
452 return RawSource(srcType
, idx
).toString(&model
, &generalSettings
).toHtmlEscaped();
455 QString
ModelPrinter::printInputLine(int idx
)
457 return printInputLine(model
.expoData
[idx
]);
460 QString
ModelPrinter::printInputLine(const ExpoData
& input
)
462 QString str
= " ";
464 switch (input
.mode
) {
465 case (1): str
+= "<- "; break;
466 case (2): str
+= "-> "; break;
467 default: str
+= " "; break;
470 if (firmware
->getCapability(VirtualInputs
)) {
471 str
+= input
.srcRaw
.toString(&model
, &generalSettings
).toHtmlEscaped();
474 str
+= " " + tr("Weight").toHtmlEscaped() + QString("(%1)").arg(Helpers::getAdjustmentString(input
.weight
, &model
, true).toHtmlEscaped());
475 if (input
.curve
.value
)
476 str
+= " " + input
.curve
.toString(&model
).toHtmlEscaped();
478 QString flightModesStr
= printFlightModes(input
.flightModes
);
479 if (!flightModesStr
.isEmpty())
480 str
+= " " + flightModesStr
.toHtmlEscaped();
482 if (input
.swtch
.type
!= SWITCH_TYPE_NONE
)
483 str
+= " " + tr("Switch").toHtmlEscaped() + QString("(%1)").arg(input
.swtch
.toString(getCurrentBoard(), &generalSettings
)).toHtmlEscaped();
486 if (firmware
->getCapability(VirtualInputs
)) {
487 if (input
.carryTrim
>0)
488 str
+= " " + tr("NoTrim").toHtmlEscaped();
489 else if (input
.carryTrim
<0)
490 str
+= " " + RawSource(SOURCE_TYPE_TRIM
, (-(input
.carryTrim
)-1)).toString(&model
, &generalSettings
).toHtmlEscaped();
494 str
+= " " + tr("Offset(%1)").arg(Helpers::getAdjustmentString(input
.offset
, &model
)).toHtmlEscaped();
496 if (firmware
->getCapability(HasExpoNames
) && input
.name
[0])
497 str
+= QString(" [%1]").arg(input
.name
).toHtmlEscaped();
502 QString
ModelPrinter::printMixerLine(const MixData
& mix
, bool showMultiplex
, int highlightedSource
)
504 QString str
= " ";
508 case (1): str
+= "*="; break;
509 case (2): str
+= ":="; break;
510 default: str
+= "+="; break;
514 str
+= " ";
516 // highlight source if needed
517 QString source
= mix
.srcRaw
.toString(&model
, &generalSettings
).toHtmlEscaped();
518 if ( (mix
.srcRaw
.type
== SOURCE_TYPE_CH
) && (mix
.srcRaw
.index
+1 == (int)highlightedSource
) ) {
519 source
= "<b>" + source
+ "</b>";
521 str
+= " " + source
;
523 if (mix
.mltpx
== MLTPX_MUL
&& !showMultiplex
)
524 str
+= " " + tr("MULT!").toHtmlEscaped();
526 str
+= " " + tr("Weight") + QString("(%1)").arg(Helpers::getAdjustmentString(mix
.weight
, &model
, true)).toHtmlEscaped();
528 QString flightModesStr
= printFlightModes(mix
.flightModes
);
529 if (!flightModesStr
.isEmpty())
530 str
+= " " + flightModesStr
.toHtmlEscaped();
532 if (mix
.swtch
.type
!= SWITCH_TYPE_NONE
)
533 str
+= " " + tr("Switch") + QString("(%1)").arg(mix
.swtch
.toString(getCurrentBoard(), &generalSettings
)).toHtmlEscaped();
535 if (mix
.carryTrim
> 0)
536 str
+= " " + tr("NoTrim").toHtmlEscaped();
537 else if (mix
.carryTrim
< 0)
538 str
+= " " + RawSource(SOURCE_TYPE_TRIM
, (-(mix
.carryTrim
)-1)).toString(&model
, &generalSettings
);
540 if (firmware
->getCapability(HasNoExpo
) && mix
.noExpo
)
541 str
+= " " + tr("No DR/Expo").toHtmlEscaped();
543 str
+= " " + tr("Offset") + QString("(%1)").arg(Helpers::getAdjustmentString(mix
.sOffset
, &model
)).toHtmlEscaped();
545 str
+= " " + mix
.curve
.toString(&model
).toHtmlEscaped();
546 int scale
= firmware
->getCapability(SlowScale
);
549 if (mix
.delayDown
|| mix
.delayUp
)
550 str
+= " " + tr("Delay") + QString("(u%1:d%2)").arg((double)mix
.delayUp
/scale
).arg((double)mix
.delayDown
/scale
).toHtmlEscaped();
551 if (mix
.speedDown
|| mix
.speedUp
)
552 str
+= " " + tr("Slow") + QString("(u%1:d%2)").arg((double)mix
.speedUp
/scale
).arg((double)mix
.speedDown
/scale
).toHtmlEscaped();
554 str
+= " " + tr("Warn") + QString("(%1)").arg(mix
.mixWarn
).toHtmlEscaped();
555 if (firmware
->getCapability(HasMixerNames
) && mix
.name
[0])
556 str
+= QString(" [%1]").arg(mix
.name
).toHtmlEscaped();
560 QString
ModelPrinter::printFlightModeSwitch(const RawSwitch
& swtch
)
562 return swtch
.toString(getCurrentBoard(), &generalSettings
);
565 QString
ModelPrinter::printFlightModeName(int index
)
567 return model
.flightModeData
[index
].nameToString(index
);
570 QString
ModelPrinter::printFlightModes(unsigned int flightModes
)
572 int numFlightModes
= firmware
->getCapability(FlightModes
);
573 if (numFlightModes
&& flightModes
) {
574 if (flightModes
== (unsigned int)(1<<numFlightModes
) - 1) {
575 return tr("Disabled in all flight modes");
579 for (int i
=0; i
<numFlightModes
; i
++) {
580 if (!(flightModes
& (1<<i
))) {
581 list
<< printFlightModeName(i
);
584 return (list
.size() > 1 ? tr("Flight modes") : tr("Flight mode")) + QString("(%1)").arg(list
.join(", "));
591 QString
ModelPrinter::printLogicalSwitchLine(int idx
)
594 const LogicalSwitchData
& ls
= model
.logicalSw
[idx
];
595 const QString sw1Name
= RawSwitch(ls
.val1
).toString(getCurrentBoard(), &generalSettings
);
596 const QString sw2Name
= RawSwitch(ls
.val2
).toString(getCurrentBoard(), &generalSettings
);
604 switch (ls
.getFunctionFamily()) {
606 result
+= tr("Edge") + QString("(%1, [%2:%3])").arg(sw1Name
).arg(ValToTim(ls
.val2
)).arg(ls
.val3
<0 ? tr("instant") : QString("%1").arg(ValToTim(ls
.val2
+ls
.val3
)));
608 case LS_FAMILY_STICKY
:
609 result
+= tr("Sticky") + QString("(%1, %2)").arg(sw1Name
).arg(sw2Name
);
611 case LS_FAMILY_TIMER
:
612 result
+= tr("Timer") + QString("(%1, %2)").arg(ValToTim(ls
.val1
)).arg(ValToTim(ls
.val2
));
614 case LS_FAMILY_VOFS
: {
615 RawSource source
= RawSource(ls
.val1
);
616 RawSourceRange range
= source
.getRange(&model
, generalSettings
);
619 res
+= source
.toString(&model
, &generalSettings
);
623 if (ls
.func
== LS_FN_APOS
|| ls
.func
== LS_FN_ANEG
)
624 res
= "|" + res
+ "|";
625 else if (ls
.func
== LS_FN_DAPOS
)
626 res
= "|d(" + res
+ ")|";
627 else if (ls
.func
== LS_FN_DPOS
)
628 result
= "d(" + res
+ ")";
630 if (ls
.func
== LS_FN_VEQUAL
)
632 else if (ls
.func
== LS_FN_APOS
|| ls
.func
== LS_FN_VPOS
|| ls
.func
== LS_FN_DPOS
|| ls
.func
== LS_FN_DAPOS
)
634 else if (ls
.func
== LS_FN_ANEG
|| ls
.func
== LS_FN_VNEG
)
636 else if (ls
.func
== LS_FN_VALMOSTEQUAL
)
639 result
+= tr(" missing");
640 result
+= QString::number(range
.step
* (ls
.val2
/*TODO+ source.getRawOffset(model)*/) + range
.offset
);
643 case LS_FAMILY_VBOOL
:
662 case LS_FAMILY_VCOMP
:
664 result
+= RawSource(ls
.val1
).toString(&model
, &generalSettings
);
692 result
+= RawSource(ls
.val2
).toString(&model
, &generalSettings
);
700 result
+= RawSwitch(ls
.andsw
).toString(getCurrentBoard(), &generalSettings
);
703 if (firmware
->getCapability(LogicalSwitchesExt
)) {
705 result
+= " " + tr("Duration") + QString("(%1s)").arg(ls
.duration
/10.0);
707 result
+= " " + tr("Delay") + QString("(%1s)").arg(ls
.delay
/10.0);
713 QString
ModelPrinter::printCustomFunctionLine(int idx
)
716 const CustomFunctionData
& cf
= model
.customFn
[idx
];
717 if (cf
.swtch
.type
== SWITCH_TYPE_NONE
)
720 result
+= cf
.swtch
.toString(getCurrentBoard(), &generalSettings
) + " - ";
721 result
+= cf
.funcToString(&model
) + " (";
722 result
+= cf
.paramToString(&model
) + ")";
723 if (!cf
.repeatToString().isEmpty())
724 result
+= " " + cf
.repeatToString();
725 if (!cf
.enabledToString().isEmpty())
726 result
+= " " + cf
.enabledToString();
730 QString
ModelPrinter::printCurveName(int idx
)
732 return model
.curves
[idx
].nameToString(idx
).toHtmlEscaped();
735 QString
ModelPrinter::printCurve(int idx
)
738 const CurveData
& curve
= model
.curves
[idx
];
739 result
+= (curve
.type
== CurveData::CURVE_TYPE_CUSTOM
) ? tr("Custom") : tr("Standard");
741 if (curve
.type
== CurveData::CURVE_TYPE_CUSTOM
) {
742 for (int j
=0; j
<curve
.count
; j
++) {
745 result
+= QString("(%1, %2)").arg(curve
.points
[j
].x
).arg(curve
.points
[j
].y
);
749 for (int j
=0; j
<curve
.count
; j
++) {
752 result
+= QString("%1").arg(curve
.points
[j
].y
);
759 CurveImage::CurveImage():
761 image(size
+1, size
+1, QImage::Format_RGB32
),
764 painter
.setBrush(QBrush("#FFFFFF"));
765 painter
.setPen(QColor(0, 0, 0));
766 painter
.drawRect(0, 0, size
, size
);
768 painter
.setPen(QColor(0, 0, 0));
769 painter
.drawLine(0, size
/2, size
, size
/2);
770 painter
.drawLine(size
/2, 0, size
/2, size
);
771 for (int i
=0; i
<21; i
++) {
772 painter
.drawLine(size
/2-5, (size
*i
)/(20), size
/2+5, (size
*i
)/(20));
773 painter
.drawLine((size
*i
)/(20), size
/2-5, (size
*i
)/(20), size
/2+5);
777 void CurveImage::drawCurve(const CurveData
& curve
, QColor color
)
779 painter
.setPen(QPen(color
, 2, Qt::SolidLine
));
780 for (int j
=1; j
<curve
.count
; j
++) {
781 if (curve
.type
== CurveData::CURVE_TYPE_CUSTOM
)
782 painter
.drawLine(size
/2+(size
*curve
.points
[j
-1].x
)/200, size
/2-(size
*curve
.points
[j
-1].y
)/200, size
/2+(size
*curve
.points
[j
].x
)/200, size
/2-(size
*curve
.points
[j
].y
)/200);
784 painter
.drawLine(size
*(j
-1)/(curve
.count
-1), size
/2-(size
*curve
.points
[j
-1].y
)/200, size
*(j
)/(curve
.count
-1), size
/2-(size
*curve
.points
[j
].y
)/200);
788 QString
ModelPrinter::createCurveImage(int idx
, QTextDocument
* document
)
791 image
.drawCurve(model
.curves
[idx
], colors
[idx
]);
792 QString filename
= QString("mydata://curve-%1-%2.png").arg((uint64_t)this).arg(idx
);
794 document
->addResource(QTextDocument::ImageResource
, QUrl(filename
), image
.get());
795 // qDebug() << "ModelPrinter::createCurveImage()" << idx << filename;
799 QString
ModelPrinter::printGlobalVarUnit(int idx
)
801 return model
.gvarData
[idx
].unitToString().toHtmlEscaped();
804 QString
ModelPrinter::printGlobalVarPrec(int idx
)
806 return model
.gvarData
[idx
].precToString().toHtmlEscaped();
809 QString
ModelPrinter::printGlobalVarMin(int idx
)
811 return QString::number(model
.gvarData
[idx
].getMinPrec());
814 QString
ModelPrinter::printGlobalVarMax(int idx
)
816 return QString::number(model
.gvarData
[idx
].getMaxPrec());
819 QString
ModelPrinter::printGlobalVarPopup(int idx
)
821 return printBoolean(model
.gvarData
[idx
].popup
, BOOLEAN_YN
);
824 QString
ModelPrinter::printOutputValueGVar(int val
)
827 if (abs(val
) > 10000) {
830 result
.append(RawSource(SOURCE_TYPE_GVAR
, abs(val
)-10001).toString(&model
));
835 result
.append(QString::number((qreal
)val
/10, 'f', 1) + "%");
840 QString
ModelPrinter::printOutputOffset(int idx
)
842 return printOutputValueGVar(model
.limitData
[idx
].offset
);
845 QString
ModelPrinter::printOutputMin(int idx
)
847 return printOutputValueGVar(model
.limitData
[idx
].min
);
850 QString
ModelPrinter::printOutputMax(int idx
)
852 return printOutputValueGVar(model
.limitData
[idx
].max
);
855 QString
ModelPrinter::printOutputRevert(int idx
)
857 return model
.limitData
[idx
].revertToString();
860 QString
ModelPrinter::printOutputPpmCenter(int idx
)
862 return QString::number(model
.limitData
[idx
].ppmCenter
+ 1500);
865 QString
ModelPrinter::printOutputCurve(int idx
)
867 return CurveReference(CurveReference::CURVE_REF_CUSTOM
, model
.limitData
[idx
].curve
.value
).toString(&model
, false);
870 QString
ModelPrinter::printOutputSymetrical(int idx
)
872 return printBoolean(model
.limitData
[idx
].symetrical
, BOOLEAN_YN
);
875 QString
ModelPrinter::printSettingsOther()
878 if (model
.extendedLimits
)
879 str
+= tr("Extended Limits");
880 if (firmware
->getCapability(HasDisplayText
) && model
.displayChecklist
)
881 str
+= tr("Display Checklist");
882 if (firmware
->getCapability(GlobalFunctions
) && !model
.noGlobalFunctions
)
883 str
+= tr("Global Functions");
884 return str
.join(", ");
887 QString
ModelPrinter::printSwitchWarnings()
890 Boards board
= firmware
->getBoard();
891 uint64_t switchStates
= model
.switchWarningStates
;
894 for (int idx
=0; idx
<board
.getCapability(Board::Switches
); idx
++) {
895 Board::SwitchInfo switchInfo
= Boards::getSwitchInfo(board
.getBoardType(), idx
);
896 switchInfo
.config
= Board::SwitchType(generalSettings
.switchConfig
[idx
]);
897 if (switchInfo
.config
== Board::SWITCH_NOT_AVAILABLE
|| switchInfo
.config
== Board::SWITCH_TOGGLE
) {
900 if (!(model
.switchWarningEnable
& (1 << idx
))) {
901 if (IS_HORUS_OR_TARANIS(board
.getBoardType())) {
902 value
= (switchStates
>> (2*idx
)) & 0x03;
905 value
= (idx
==0 ? switchStates
& 0x3 : switchStates
& 0x1);
906 switchStates
>>= (idx
==0 ? 2 : 1);
908 str
+= RawSwitch(SWITCH_TYPE_SWITCH
, 1+idx
*3+value
).toString(board
.getBoardType(), &generalSettings
, &model
);
911 return (str
.isEmpty() ? tr("None") : str
.join(", ")) ;
914 QString
ModelPrinter::printPotWarnings()
918 Boards board
= firmware
->getBoard();
919 str
+= (model
.potsWarningMode
? tr("Mode") + QString("(%1)").arg(printPotsWarningMode()) : tr("None"));
920 if (model
.potsWarningMode
) {
921 for (int i
=0; i
<board
.getCapability(Board::Pots
)+board
.getCapability(Board::Sliders
); i
++) {
922 RawSource
src(SOURCE_TYPE_STICK
, CPN_MAX_STICKS
+ i
);
923 if ((src
.isPot(&genAryIdx
) && generalSettings
.isPotAvailable(genAryIdx
)) || (src
.isSlider(&genAryIdx
) && generalSettings
.isSliderAvailable(genAryIdx
))) {
924 if (!model
.potsWarningEnabled
[i
])
925 str
+= src
.toString(&model
, &generalSettings
);
929 return str
.join(", ");
932 QString
ModelPrinter::printPotsWarningMode()
934 switch (model
.potsWarningMode
) {
946 QString
ModelPrinter::printFailsafe(int idx
)
949 ModuleData module
= model
.moduleData
[idx
];
950 strl
+= "<br>" + tr("Failsafe Mode") + QString("(%1)").arg(printFailsafeMode(module
.failsafeMode
));
951 if (module
.failsafeMode
== FAILSAFE_CUSTOM
) {
952 for (int i
=0; i
<module
.channelsCount
; i
++) {
953 strl
+= QString("%1(%2)").arg(printChannelName(module
.channelsStart
+ i
).trimmed()).arg(printFailsafeValue(module
.failsafeChannels
[i
]));
956 return strl
.join(", ");
959 QString
ModelPrinter::printFailsafeValue(int val
)
965 return tr("No Pulse");
967 return QString("%1%").arg(QString::number(divRoundClosest(val
* 1000, 1024) / 10.0));
971 QString
ModelPrinter::printFailsafeMode(unsigned int fsmode
)
974 case FAILSAFE_NOT_SET
:
975 return tr("Not set");
978 case FAILSAFE_CUSTOM
:
980 case FAILSAFE_NOPULSES
:
981 return tr("No pulses");
982 case FAILSAFE_RECEIVER
:
983 return tr("Receiver");
989 QString
ModelPrinter::printTimerCountdownBeep(unsigned int countdownBeep
)
991 switch (countdownBeep
) {
992 case TimerData::COUNTDOWN_SILENT
:
994 case TimerData::COUNTDOWN_BEEPS
:
996 case TimerData::COUNTDOWN_VOICE
:
998 case TimerData::COUNTDOWN_HAPTIC
:
1005 QString
ModelPrinter::printTimerPersistent(unsigned int persistent
)
1007 switch (persistent
) {
1011 return tr("Flight");
1013 return tr("Manual reset");
1019 QString
ModelPrinter::printSettingsTrim()
1022 str
+= tr("Step") + QString("(%1)").arg(printTrimIncrementMode());
1023 if (IS_ARM(firmware
->getBoard()) && model
.trimsDisplay
)
1024 str
+= tr("Display") + QString("(%1)").arg(printTrimsDisplayMode());
1025 if (model
.extendedTrims
)
1026 str
+= tr("Extended");
1027 return str
.join(", ");
1030 QString
ModelPrinter::printThrottleSource(int idx
)
1032 Boards board
= firmware
->getBoard();
1033 int chnstart
= board
.getCapability(Board::Pots
)+board
.getCapability(Board::Sliders
);
1036 else if (idx
< (chnstart
+1))
1037 return firmware
->getAnalogInputName(idx
+board
.getCapability(Board::Sticks
)-1);
1039 return RawSource(SOURCE_TYPE_CH
, idx
-chnstart
-1).toString(&model
, &generalSettings
);
1042 QString
ModelPrinter::printTrimsDisplayMode()
1044 switch (model
.trimsDisplay
) {
1048 return tr("On Change");
1050 return tr("Always");
1052 return tr("Unknown");
1056 QString
ModelPrinter::printModuleType(int idx
)
1059 return tr("Trainer Port");
1060 else if (firmware
->getCapability(NumModules
) > 1)
1061 if (IS_HORUS_OR_TARANIS(firmware
->getBoard()))
1063 return tr("Internal Radio System");
1065 return tr("External Radio Module");
1067 return tr("Radio System");
1069 return tr("Extra Radio System");
1071 return tr("Radio System");
1074 QString
ModelPrinter::printPxxPower(int power
)
1076 static const char *strings
[] = {
1077 "10mW", "100mW", "500mW", "3W"
1079 return CHECK_IN_ARRAY(strings
, power
);
1082 QString
ModelPrinter::printThrottle()
1085 result
+= tr("Source") + QString("(%1)").arg(printThrottleSource(model
.thrTraceSrc
));
1087 result
+= tr("Trim idle only");
1088 if (!model
.disableThrottleWarning
)
1089 result
+= tr("Warning");
1090 if (model
.throttleReversed
)
1091 result
+= tr("Reversed");
1092 return result
.join(", ");
1095 QString
ModelPrinter::printPPMFrameLength(int ppmFL
)
1097 double result
= (((double)ppmFL
* 5) + 225) / 10;
1098 return QString::number(result
);
1101 QString
ModelPrinter::printTimerName(int idx
)
1104 result
= tr("Tmr") + QString("%1").arg(idx
+1);
1105 if (firmware
->getCapability(TimersName
) && model
.timers
[idx
].name
[0])
1106 result
.append(":" + QString(model
.timers
[idx
].name
));
1111 QString
ModelPrinter::printTimerTimeValue(unsigned int val
)
1113 return printTimeValue(val
, MASK_TIMEVALUE_HRSMINS
| MASK_TIMEVALUE_ZEROHRS
);
1116 QString
ModelPrinter::printTimerMinuteBeep(bool mb
)
1118 return printBoolean(mb
, BOOLEAN_YESNO
);