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 "modeldata.h"
23 #include "eeprominterface.h"
24 #include "generalsettings.h"
26 #include "radiodataconversionstate.h"
29 QString
removeAccents(const QString
& str
)
34 const QString tA
[] = { "á", "â", "ã", "à", "ä" };
35 const QString tE
[] = { "é", "è", "ê", "ě" };
36 const QString tI
[] = { "í" };
37 const QString tO
[] = { "ó", "ô", "õ", "ö" };
38 const QString tU
[] = { "ú", "ü" };
39 const QString tC
[] = { "ç" };
40 const QString tY
[] = { "ý" };
41 const QString tS
[] = { "š" };
42 const QString tR
[] = { "ř" };
44 for (unsigned int i
= 0; i
< DIM(tA
); i
++) result
.replace(tA
[i
], "a");
45 for (unsigned int i
= 0; i
< DIM(tE
); i
++) result
.replace(tE
[i
], "e");
46 for (unsigned int i
= 0; i
< DIM(tI
); i
++) result
.replace(tI
[i
], "i");
47 for (unsigned int i
= 0; i
< DIM(tO
); i
++) result
.replace(tO
[i
], "o");
48 for (unsigned int i
= 0; i
< DIM(tU
); i
++) result
.replace(tU
[i
], "u");
49 for (unsigned int i
= 0; i
< DIM(tC
); i
++) result
.replace(tC
[i
], "c");
50 for (unsigned int i
= 0; i
< DIM(tY
); i
++) result
.replace(tY
[i
], "y");
51 for (unsigned int i
= 0; i
< DIM(tS
); i
++) result
.replace(tS
[i
], "s");
52 for (unsigned int i
= 0; i
< DIM(tR
); i
++) result
.replace(tR
[i
], "r");
62 void TimerData::convert(RadioDataConversionState
& cstate
)
64 cstate
.setComponent(tr("TMR"), 1);
65 cstate
.setSubComp(tr("Timer %1").arg(cstate
.subCompIdx
+ 1));
74 ModelData::ModelData()
79 ModelData::ModelData(const ModelData
& src
)
84 ModelData
& ModelData::operator = (const ModelData
& src
)
86 memcpy(this, &src
, sizeof(ModelData
));
90 ExpoData
* ModelData::insertInput(const int idx
)
92 memmove(&expoData
[idx
+1], &expoData
[idx
], (CPN_MAX_EXPOS
-(idx
+1))*sizeof(ExpoData
));
93 expoData
[idx
].clear();
94 return &expoData
[idx
];
97 bool ModelData::isInputValid(const unsigned int idx
) const
99 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
100 const ExpoData
* expo
= &expoData
[i
];
101 if (expo
->mode
== 0) break;
102 if (expo
->chn
== idx
)
108 bool ModelData::hasExpos(uint8_t inputIdx
) const
110 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
111 const ExpoData
& expo
= expoData
[i
];
112 if (expo
.chn
==inputIdx
&& expo
.mode
!=0) {
119 bool ModelData::hasMixes(uint8_t channelIdx
) const
122 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++) {
123 if (mixData
[i
].destCh
== channelIdx
) {
130 QVector
<const ExpoData
*> ModelData::expos(int input
) const
132 QVector
<const ExpoData
*> result
;
133 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
134 const ExpoData
* ed
= &expoData
[i
];
135 if ((int)ed
->chn
==input
&& ed
->mode
!=0) {
142 QVector
<const MixData
*> ModelData::mixes(int channel
) const
144 QVector
<const MixData
*> result
;
145 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++) {
146 const MixData
* md
= &mixData
[i
];
147 if ((int)md
->destCh
== channel
+1) {
154 void ModelData::removeInput(const int idx
)
156 unsigned int chn
= expoData
[idx
].chn
;
158 memmove(&expoData
[idx
], &expoData
[idx
+1], (CPN_MAX_EXPOS
-(idx
+1))*sizeof(ExpoData
));
159 expoData
[CPN_MAX_EXPOS
-1].clear();
161 //also remove input name if removing last line for this input
163 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
164 if (expoData
[i
].mode
==0) continue;
165 if (expoData
[i
].chn
==chn
) {
170 if (!found
) inputNames
[chn
][0] = 0;
173 void ModelData::clearInputs()
175 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++)
178 //clear all input names
179 if (getCurrentFirmware()->getCapability(VirtualInputs
)) {
180 for (int i
=0; i
<CPN_MAX_INPUTS
; i
++) {
181 inputNames
[i
][0] = 0;
186 void ModelData::clearMixes()
188 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++)
192 void ModelData::clear()
194 memset(this, 0, sizeof(ModelData
));
195 modelIndex
= -1; // an invalid index, this is managed by the TreeView data model
196 moduleData
[0].channelsCount
= 8;
197 moduleData
[1].channelsStart
= 0;
198 moduleData
[1].channelsCount
= 8;
199 moduleData
[0].ppm
.delay
= 300;
200 moduleData
[1].ppm
.delay
= 300;
201 moduleData
[2].ppm
.delay
= 300;
202 int board
= getCurrentBoard();
203 if (IS_HORUS_OR_TARANIS(board
)) {
204 moduleData
[0].protocol
= PULSES_PXX_XJT_X16
;
205 moduleData
[1].protocol
= PULSES_OFF
;
207 else if (IS_SKY9X(board
)) {
208 moduleData
[0].protocol
= PULSES_PPM
;
209 moduleData
[1].protocol
= PULSES_PPM
;
212 moduleData
[0].protocol
= PULSES_PPM
;
213 moduleData
[1].protocol
= PULSES_OFF
;
215 for (int i
=0; i
<CPN_MAX_FLIGHT_MODES
; i
++) {
216 flightModeData
[i
].clear(i
);
218 for (int i
=0; i
<CPN_MAX_GVARS
; i
++) {
223 for (int i
=0; i
<CPN_MAX_CHNOUT
; i
++)
224 limitData
[i
].clear();
225 for (int i
=0; i
<CPN_MAX_STICKS
; i
++)
227 for (int i
=0; i
<CPN_MAX_LOGICAL_SWITCHES
; i
++)
228 logicalSw
[i
].clear();
229 for (int i
=0; i
<CPN_MAX_SPECIAL_FUNCTIONS
; i
++)
231 for (int i
=0; i
<CPN_MAX_CURVES
; i
++)
233 for (int i
=0; i
<CPN_MAX_TIMERS
; i
++)
235 swashRingData
.clear();
238 for (int i
=0; i
<CPN_MAX_SENSORS
; i
++)
239 sensorData
[i
].clear();
241 static const uint8_t blob
[] = { 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x32, 0x50, 0x31, 0x00, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x42, 0x6d, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
242 memcpy(customScreenData
[0], blob
, sizeof(blob
));
245 bool ModelData::isEmpty() const
250 void ModelData::setDefaultInputs(const GeneralSettings
& settings
)
252 Board::Type board
= getCurrentBoard();
254 for (int i
=0; i
<CPN_MAX_STICKS
; i
++) {
255 ExpoData
* expo
= &expoData
[i
];
257 expo
->mode
= INPUT_MODE_BOTH
;
258 expo
->srcRaw
= settings
.getDefaultSource(i
);
260 strncpy(inputNames
[i
], removeAccents(expo
->srcRaw
.toString(this)).toLatin1().constData(), sizeof(inputNames
[i
])-1);
265 void ModelData::setDefaultMixes(const GeneralSettings
& settings
)
267 Board::Type board
= getCurrentBoard();
269 setDefaultInputs(settings
);
272 for (int i
=0; i
<CPN_MAX_STICKS
; i
++) {
273 MixData
* mix
= &mixData
[i
];
277 mix
->srcRaw
= RawSource(SOURCE_TYPE_VIRTUAL_INPUT
, i
);
280 mix
->srcRaw
= RawSource(SOURCE_TYPE_STICK
, i
);
285 void ModelData::setDefaultValues(unsigned int id
, const GeneralSettings
& settings
)
289 sprintf(name
, "MODEL%02d", id
+1);
290 for (int i
=0; i
<CPN_MAX_MODULES
; i
++) {
291 moduleData
[i
].modelId
= id
+1;
293 setDefaultMixes(settings
);
296 int ModelData::getTrimValue(int phaseIdx
, int trimIdx
)
299 for (int i
=0; i
<CPN_MAX_FLIGHT_MODES
; i
++) {
300 FlightModeData
& phase
= flightModeData
[phaseIdx
];
301 if (phase
.trimMode
[trimIdx
] < 0) {
305 if (phase
.trimRef
[trimIdx
] == phaseIdx
|| phaseIdx
== 0) {
306 return result
+ phase
.trim
[trimIdx
];
309 phaseIdx
= phase
.trimRef
[trimIdx
];
310 if (phase
.trimMode
[trimIdx
] != 0)
311 result
+= phase
.trim
[trimIdx
];
318 bool ModelData::isGVarLinked(int phaseIdx
, int gvarIdx
)
320 return flightModeData
[phaseIdx
].gvars
[gvarIdx
] > 1024;
323 int ModelData::getGVarFieldValue(int phaseIdx
, int gvarIdx
)
325 int idx
= flightModeData
[phaseIdx
].gvars
[gvarIdx
];
326 for (int i
=0; idx
>GVAR_MAX_VALUE
&& i
<CPN_MAX_FLIGHT_MODES
; i
++) {
327 int nextPhase
= idx
- GVAR_MAX_VALUE
- 1;
328 if (nextPhase
>= phaseIdx
) nextPhase
+= 1;
329 phaseIdx
= nextPhase
;
330 idx
= flightModeData
[phaseIdx
].gvars
[gvarIdx
];
335 void ModelData::setTrimValue(int phaseIdx
, int trimIdx
, int value
)
337 for (uint8_t i
=0; i
<CPN_MAX_FLIGHT_MODES
; i
++) {
338 FlightModeData
& phase
= flightModeData
[phaseIdx
];
339 int mode
= phase
.trimMode
[trimIdx
];
340 int p
= phase
.trimRef
[trimIdx
];
341 int & trim
= phase
.trim
[trimIdx
];
344 if (p
== phaseIdx
|| phaseIdx
== 0) {
348 else if (mode
== 0) {
352 trim
= value
- getTrimValue(p
, trimIdx
);
362 void ModelData::removeGlobalVar(int & var
)
364 if (var
>= 126 && var
<= 130)
365 var
= flightModeData
[0].gvars
[var
-126];
366 else if (var
<= -126 && var
>= -130)
367 var
= - flightModeData
[0].gvars
[-126-var
];
370 ModelData
ModelData::removeGlobalVars()
372 ModelData result
= *this;
374 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++) {
375 removeGlobalVar(mixData
[i
].weight
);
376 removeGlobalVar(mixData
[i
].curve
.value
);
377 removeGlobalVar(mixData
[i
].sOffset
);
380 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
381 removeGlobalVar(expoData
[i
].weight
);
382 removeGlobalVar(expoData
[i
].curve
.value
);
388 int ModelData::getChannelsMax(bool forceExtendedLimits
) const
390 if (forceExtendedLimits
|| extendedLimits
)
391 return IS_HORUS_OR_TARANIS(getCurrentBoard()) ? 150 : 125;
396 bool ModelData::isAvailable(const RawSwitch
& swtch
) const
398 unsigned index
= abs(swtch
.index
) - 1;
400 if (swtch
.type
== SWITCH_TYPE_VIRTUAL
) {
401 return logicalSw
[index
].func
!= LS_FN_OFF
;
403 else if (swtch
.type
== SWITCH_TYPE_FLIGHT_MODE
) {
404 return index
== 0 || flightModeData
[index
].swtch
.type
!= SWITCH_TYPE_NONE
;
406 else if (swtch
.type
== SWITCH_TYPE_SENSOR
) {
407 return strlen(sensorData
[index
].label
) > 0;
414 float ModelData::getGVarFieldValuePrec(int phaseIdx
, int gvarIdx
)
416 return getGVarFieldValue(phaseIdx
, gvarIdx
) * gvarData
[gvarIdx
].multiplierGet();
419 void ModelData::convert(RadioDataConversionState
& cstate
)
421 // Here we can add explicit conversions when moving from one board to another
423 QString origin
= QString(name
);
424 if (origin
.isEmpty())
425 origin
= QString::number(cstate
.modelIdx
+1);
426 cstate
.setOrigin(tr("Model: ") % origin
);
428 cstate
.setComponent("SET", 0);
429 if (thrTraceSrc
&& (int)thrTraceSrc
< cstate
.fromBoard
.getCapability(Board::Pots
) + cstate
.fromBoard
.getCapability(Board::Sliders
)) {
430 cstate
.setSubComp(tr("Throttle Source"));
431 thrTraceSrc
= RawSource(SOURCE_TYPE_STICK
, (int)thrTraceSrc
+ 3).convert(cstate
).index
- 3;
434 for (int i
=0; i
<CPN_MAX_TIMERS
; i
++) {
435 timers
[i
].convert(cstate
.withComponentIndex(i
));
438 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++) {
439 mixData
[i
].convert(cstate
.withComponentIndex(i
));
442 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
443 expoData
[i
].convert(cstate
.withComponentIndex(i
));
446 for (int i
=0; i
<CPN_MAX_LOGICAL_SWITCHES
; i
++) {
447 logicalSw
[i
].convert(cstate
.withComponentIndex(i
));
450 for (int i
=0; i
<CPN_MAX_SPECIAL_FUNCTIONS
; i
++) {
451 customFn
[i
].convert(cstate
.withComponentIndex(i
));
454 for (int i
=0; i
<CPN_MAX_FLIGHT_MODES
; i
++) {
455 flightModeData
[i
].convert(cstate
.withComponentIndex(i
));