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
, bool clearName
)
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
162 if (clearName
&& !expos(chn
).size())
163 inputNames
[chn
][0] = 0;
166 void ModelData::clearInputs()
168 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++)
171 //clear all input names
172 if (getCurrentFirmware()->getCapability(VirtualInputs
)) {
173 for (int i
=0; i
<CPN_MAX_INPUTS
; i
++) {
174 inputNames
[i
][0] = 0;
179 void ModelData::clearMixes()
181 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++)
185 void ModelData::clear()
187 memset(this, 0, sizeof(ModelData
));
188 modelIndex
= -1; // an invalid index, this is managed by the TreeView data model
189 moduleData
[0].channelsCount
= 8;
190 moduleData
[1].channelsStart
= 0;
191 moduleData
[1].channelsCount
= 8;
192 moduleData
[0].ppm
.delay
= 300;
193 moduleData
[1].ppm
.delay
= 300;
194 moduleData
[2].ppm
.delay
= 300;
195 int board
= getCurrentBoard();
196 if (IS_HORUS_OR_TARANIS(board
)) {
197 moduleData
[0].protocol
= PULSES_PXX_XJT_X16
;
198 moduleData
[1].protocol
= PULSES_OFF
;
200 else if (IS_SKY9X(board
)) {
201 moduleData
[0].protocol
= PULSES_PPM
;
202 moduleData
[1].protocol
= PULSES_PPM
;
205 moduleData
[0].protocol
= PULSES_PPM
;
206 moduleData
[1].protocol
= PULSES_OFF
;
208 for (int i
=0; i
<CPN_MAX_FLIGHT_MODES
; i
++) {
209 flightModeData
[i
].clear(i
);
211 for (int i
=0; i
<CPN_MAX_GVARS
; i
++) {
216 for (int i
=0; i
<CPN_MAX_CHNOUT
; i
++)
217 limitData
[i
].clear();
218 for (int i
=0; i
<CPN_MAX_STICKS
; i
++)
220 for (int i
=0; i
<CPN_MAX_LOGICAL_SWITCHES
; i
++)
221 logicalSw
[i
].clear();
222 for (int i
=0; i
<CPN_MAX_SPECIAL_FUNCTIONS
; i
++)
224 for (int i
=0; i
<CPN_MAX_CURVES
; i
++)
226 for (int i
=0; i
<CPN_MAX_TIMERS
; i
++)
228 swashRingData
.clear();
231 for (int i
=0; i
<CPN_MAX_SENSORS
; i
++)
232 sensorData
[i
].clear();
234 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 };
235 memcpy(customScreenData
[0], blob
, sizeof(blob
));
238 bool ModelData::isEmpty() const
243 void ModelData::setDefaultInputs(const GeneralSettings
& settings
)
245 Board::Type board
= getCurrentBoard();
247 for (int i
=0; i
<CPN_MAX_STICKS
; i
++) {
248 ExpoData
* expo
= &expoData
[i
];
250 expo
->mode
= INPUT_MODE_BOTH
;
251 expo
->srcRaw
= settings
.getDefaultSource(i
);
253 strncpy(inputNames
[i
], removeAccents(expo
->srcRaw
.toString(this)).toLatin1().constData(), sizeof(inputNames
[i
])-1);
258 void ModelData::setDefaultMixes(const GeneralSettings
& settings
)
260 Board::Type board
= getCurrentBoard();
262 setDefaultInputs(settings
);
265 for (int i
=0; i
<CPN_MAX_STICKS
; i
++) {
266 MixData
* mix
= &mixData
[i
];
270 mix
->srcRaw
= RawSource(SOURCE_TYPE_VIRTUAL_INPUT
, i
);
273 mix
->srcRaw
= RawSource(SOURCE_TYPE_STICK
, i
);
278 void ModelData::setDefaultValues(unsigned int id
, const GeneralSettings
& settings
)
282 sprintf(name
, "MODEL%02d", id
+1);
283 for (int i
=0; i
<CPN_MAX_MODULES
; i
++) {
284 moduleData
[i
].modelId
= id
+1;
286 setDefaultMixes(settings
);
289 int ModelData::getTrimValue(int phaseIdx
, int trimIdx
)
292 for (int i
=0; i
<CPN_MAX_FLIGHT_MODES
; i
++) {
293 FlightModeData
& phase
= flightModeData
[phaseIdx
];
294 if (phase
.trimMode
[trimIdx
] < 0) {
298 if (phase
.trimRef
[trimIdx
] == phaseIdx
|| phaseIdx
== 0) {
299 return result
+ phase
.trim
[trimIdx
];
302 phaseIdx
= phase
.trimRef
[trimIdx
];
303 if (phase
.trimMode
[trimIdx
] != 0)
304 result
+= phase
.trim
[trimIdx
];
311 bool ModelData::isGVarLinked(int phaseIdx
, int gvarIdx
)
313 return flightModeData
[phaseIdx
].gvars
[gvarIdx
] > 1024;
316 int ModelData::getGVarFieldValue(int phaseIdx
, int gvarIdx
)
318 int idx
= flightModeData
[phaseIdx
].gvars
[gvarIdx
];
319 for (int i
=0; idx
>GVAR_MAX_VALUE
&& i
<CPN_MAX_FLIGHT_MODES
; i
++) {
320 int nextPhase
= idx
- GVAR_MAX_VALUE
- 1;
321 if (nextPhase
>= phaseIdx
) nextPhase
+= 1;
322 phaseIdx
= nextPhase
;
323 idx
= flightModeData
[phaseIdx
].gvars
[gvarIdx
];
328 void ModelData::setTrimValue(int phaseIdx
, int trimIdx
, int value
)
330 for (uint8_t i
=0; i
<CPN_MAX_FLIGHT_MODES
; i
++) {
331 FlightModeData
& phase
= flightModeData
[phaseIdx
];
332 int mode
= phase
.trimMode
[trimIdx
];
333 int p
= phase
.trimRef
[trimIdx
];
334 int & trim
= phase
.trim
[trimIdx
];
337 if (p
== phaseIdx
|| phaseIdx
== 0) {
341 else if (mode
== 0) {
345 trim
= value
- getTrimValue(p
, trimIdx
);
355 void ModelData::removeGlobalVar(int & var
)
357 if (var
>= 126 && var
<= 130)
358 var
= flightModeData
[0].gvars
[var
-126];
359 else if (var
<= -126 && var
>= -130)
360 var
= - flightModeData
[0].gvars
[-126-var
];
363 ModelData
ModelData::removeGlobalVars()
365 ModelData result
= *this;
367 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++) {
368 removeGlobalVar(mixData
[i
].weight
);
369 removeGlobalVar(mixData
[i
].curve
.value
);
370 removeGlobalVar(mixData
[i
].sOffset
);
373 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
374 removeGlobalVar(expoData
[i
].weight
);
375 removeGlobalVar(expoData
[i
].curve
.value
);
381 int ModelData::getChannelsMax(bool forceExtendedLimits
) const
383 if (forceExtendedLimits
|| extendedLimits
)
384 return IS_HORUS_OR_TARANIS(getCurrentBoard()) ? 150 : 125;
389 bool ModelData::isAvailable(const RawSwitch
& swtch
) const
391 unsigned index
= abs(swtch
.index
) - 1;
393 if (swtch
.type
== SWITCH_TYPE_VIRTUAL
) {
394 return logicalSw
[index
].func
!= LS_FN_OFF
;
396 else if (swtch
.type
== SWITCH_TYPE_FLIGHT_MODE
) {
397 return index
== 0 || flightModeData
[index
].swtch
.type
!= SWITCH_TYPE_NONE
;
399 else if (swtch
.type
== SWITCH_TYPE_SENSOR
) {
400 return strlen(sensorData
[index
].label
) > 0;
407 float ModelData::getGVarFieldValuePrec(int phaseIdx
, int gvarIdx
)
409 return getGVarFieldValue(phaseIdx
, gvarIdx
) * gvarData
[gvarIdx
].multiplierGet();
412 void ModelData::convert(RadioDataConversionState
& cstate
)
414 // Here we can add explicit conversions when moving from one board to another
416 QString origin
= QString(name
);
417 if (origin
.isEmpty())
418 origin
= QString::number(cstate
.modelIdx
+1);
419 cstate
.setOrigin(tr("Model: ") % origin
);
421 cstate
.setComponent("SET", 0);
422 if (thrTraceSrc
&& (int)thrTraceSrc
< cstate
.fromBoard
.getCapability(Board::Pots
) + cstate
.fromBoard
.getCapability(Board::Sliders
)) {
423 cstate
.setSubComp(tr("Throttle Source"));
424 thrTraceSrc
= RawSource(SOURCE_TYPE_STICK
, (int)thrTraceSrc
+ 3).convert(cstate
).index
- 3;
427 for (int i
=0; i
<CPN_MAX_TIMERS
; i
++) {
428 timers
[i
].convert(cstate
.withComponentIndex(i
));
431 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++) {
432 mixData
[i
].convert(cstate
.withComponentIndex(i
));
435 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
436 expoData
[i
].convert(cstate
.withComponentIndex(i
));
439 for (int i
=0; i
<CPN_MAX_LOGICAL_SWITCHES
; i
++) {
440 logicalSw
[i
].convert(cstate
.withComponentIndex(i
));
443 for (int i
=0; i
<CPN_MAX_SPECIAL_FUNCTIONS
; i
++) {
444 customFn
[i
].convert(cstate
.withComponentIndex(i
));
447 for (int i
=0; i
<CPN_MAX_FLIGHT_MODES
; i
++) {
448 flightModeData
[i
].convert(cstate
.withComponentIndex(i
));
451 for (int i
=0; i
<CPN_MAX_MODULES
; i
++) {
452 moduleData
[i
].convert(cstate
.withComponentIndex(i
));