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"
33 void TimerData::convert(RadioDataConversionState
& cstate
)
35 cstate
.setComponent(tr("TMR"), 1);
36 cstate
.setSubComp(tr("Timer %1").arg(cstate
.subCompIdx
+ 1));
45 ModelData::ModelData()
50 ModelData::ModelData(const ModelData
& src
)
55 ModelData
& ModelData::operator = (const ModelData
& src
)
57 memcpy(reinterpret_cast<void *>(this), &src
, sizeof(ModelData
));
61 ExpoData
* ModelData::insertInput(const int idx
)
63 memmove(&expoData
[idx
+1], &expoData
[idx
], (CPN_MAX_EXPOS
-(idx
+1))*sizeof(ExpoData
));
64 expoData
[idx
].clear();
65 return &expoData
[idx
];
68 bool ModelData::isInputValid(const unsigned int idx
) const
70 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
71 const ExpoData
* expo
= &expoData
[i
];
72 if (expo
->mode
== 0) break;
79 bool ModelData::hasExpos(uint8_t inputIdx
) const
81 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
82 const ExpoData
& expo
= expoData
[i
];
83 if (expo
.chn
==inputIdx
&& expo
.mode
!=0) {
90 bool ModelData::hasMixes(uint8_t channelIdx
) const
93 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++) {
94 if (mixData
[i
].destCh
== channelIdx
) {
101 QVector
<const ExpoData
*> ModelData::expos(int input
) const
103 QVector
<const ExpoData
*> result
;
104 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
105 const ExpoData
* ed
= &expoData
[i
];
106 if ((int)ed
->chn
==input
&& ed
->mode
!=0) {
113 QVector
<const MixData
*> ModelData::mixes(int channel
) const
115 QVector
<const MixData
*> result
;
116 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++) {
117 const MixData
* md
= &mixData
[i
];
118 if ((int)md
->destCh
== channel
+1) {
125 void ModelData::removeInput(const int idx
, bool clearName
)
127 unsigned int chn
= expoData
[idx
].chn
;
129 memmove(&expoData
[idx
], &expoData
[idx
+1], (CPN_MAX_EXPOS
-(idx
+1))*sizeof(ExpoData
));
130 expoData
[CPN_MAX_EXPOS
-1].clear();
132 //also remove input name if removing last line for this input
133 if (clearName
&& !expos(chn
).size())
134 inputNames
[chn
][0] = 0;
137 void ModelData::clearInputs()
139 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++)
142 //clear all input names
143 if (getCurrentFirmware()->getCapability(VirtualInputs
)) {
144 for (int i
=0; i
<CPN_MAX_INPUTS
; i
++) {
145 inputNames
[i
][0] = 0;
150 void ModelData::clearMixes()
152 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++)
156 void ModelData::clear()
158 memset(reinterpret_cast<void *>(this), 0, sizeof(ModelData
));
159 modelIndex
= -1; // an invalid index, this is managed by the TreeView data model
160 moduleData
[0].protocol
= PULSES_OFF
;
161 moduleData
[1].protocol
= PULSES_OFF
;
162 moduleData
[0].channelsCount
= 8;
163 moduleData
[1].channelsStart
= 0;
164 moduleData
[1].channelsCount
= 8;
165 moduleData
[0].ppm
.delay
= 300;
166 moduleData
[1].ppm
.delay
= 300;
167 moduleData
[2].ppm
.delay
= 300; //Trainer PPM
168 for (int i
=0; i
<CPN_MAX_FLIGHT_MODES
; i
++) {
169 flightModeData
[i
].clear(i
);
171 for (int i
=0; i
<CPN_MAX_GVARS
; i
++) {
176 for (int i
=0; i
<CPN_MAX_CHNOUT
; i
++)
177 limitData
[i
].clear();
178 for (int i
=0; i
<CPN_MAX_STICKS
; i
++)
180 for (int i
=0; i
<CPN_MAX_LOGICAL_SWITCHES
; i
++)
181 logicalSw
[i
].clear();
182 for (int i
=0; i
<CPN_MAX_SPECIAL_FUNCTIONS
; i
++)
184 for (int i
=0; i
<CPN_MAX_CURVES
; i
++)
186 for (int i
=0; i
<CPN_MAX_TIMERS
; i
++)
188 swashRingData
.clear();
191 for (unsigned i
=0; i
<CPN_MAX_SENSORS
; i
++)
192 sensorData
[i
].clear();
194 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 };
195 memcpy(customScreenData
[0], blob
, sizeof(blob
));
198 bool ModelData::isEmpty() const
203 void ModelData::setDefaultInputs(const GeneralSettings
& settings
)
205 Board::Type board
= getCurrentBoard();
207 for (int i
=0; i
<CPN_MAX_STICKS
; i
++) {
208 ExpoData
* expo
= &expoData
[i
];
210 expo
->mode
= INPUT_MODE_BOTH
;
211 expo
->srcRaw
= settings
.getDefaultSource(i
);
213 strncpy(inputNames
[i
], Helpers::removeAccents(expo
->srcRaw
.toString(this)).toLatin1().constData(), sizeof(inputNames
[i
])-1);
218 void ModelData::setDefaultMixes(const GeneralSettings
& settings
)
220 Board::Type board
= getCurrentBoard();
222 setDefaultInputs(settings
);
225 for (int i
=0; i
<CPN_MAX_STICKS
; i
++) {
226 MixData
* mix
= &mixData
[i
];
230 mix
->srcRaw
= RawSource(SOURCE_TYPE_VIRTUAL_INPUT
, i
);
233 mix
->srcRaw
= RawSource(SOURCE_TYPE_STICK
, i
);
238 void ModelData::setDefaultValues(unsigned int id
, const GeneralSettings
& settings
)
242 sprintf(name
, "MODEL%02d", id
+1);
243 for (int i
=0; i
<CPN_MAX_MODULES
; i
++) {
244 moduleData
[i
].modelId
= id
+1;
246 setDefaultMixes(settings
);
249 int ModelData::getTrimValue(int phaseIdx
, int trimIdx
)
252 for (int i
=0; i
<CPN_MAX_FLIGHT_MODES
; i
++) {
253 FlightModeData
& phase
= flightModeData
[phaseIdx
];
254 if (phase
.trimMode
[trimIdx
] < 0) {
258 if (phase
.trimRef
[trimIdx
] == phaseIdx
|| phaseIdx
== 0) {
259 return result
+ phase
.trim
[trimIdx
];
262 phaseIdx
= phase
.trimRef
[trimIdx
];
263 if (phase
.trimMode
[trimIdx
] != 0)
264 result
+= phase
.trim
[trimIdx
];
271 bool ModelData::isGVarLinked(int phaseIdx
, int gvarIdx
)
273 return flightModeData
[phaseIdx
].gvars
[gvarIdx
] > 1024;
276 int ModelData::getGVarFieldValue(int phaseIdx
, int gvarIdx
)
278 int idx
= flightModeData
[phaseIdx
].gvars
[gvarIdx
];
279 for (int i
=0; idx
>GVAR_MAX_VALUE
&& i
<CPN_MAX_FLIGHT_MODES
; i
++) {
280 int nextPhase
= idx
- GVAR_MAX_VALUE
- 1;
281 if (nextPhase
>= phaseIdx
) nextPhase
+= 1;
282 phaseIdx
= nextPhase
;
283 idx
= flightModeData
[phaseIdx
].gvars
[gvarIdx
];
288 void ModelData::setTrimValue(int phaseIdx
, int trimIdx
, int value
)
290 for (uint8_t i
=0; i
<CPN_MAX_FLIGHT_MODES
; i
++) {
291 FlightModeData
& phase
= flightModeData
[phaseIdx
];
292 int mode
= phase
.trimMode
[trimIdx
];
293 int p
= phase
.trimRef
[trimIdx
];
294 int & trim
= phase
.trim
[trimIdx
];
297 if (p
== phaseIdx
|| phaseIdx
== 0) {
301 else if (mode
== 0) {
305 trim
= value
- getTrimValue(p
, trimIdx
);
315 void ModelData::removeGlobalVar(int & var
)
317 if (var
>= 126 && var
<= 130)
318 var
= flightModeData
[0].gvars
[var
-126];
319 else if (var
<= -126 && var
>= -130)
320 var
= - flightModeData
[0].gvars
[-126-var
];
323 ModelData
ModelData::removeGlobalVars()
325 ModelData result
= *this;
327 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++) {
328 removeGlobalVar(mixData
[i
].weight
);
329 removeGlobalVar(mixData
[i
].curve
.value
);
330 removeGlobalVar(mixData
[i
].sOffset
);
333 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
334 removeGlobalVar(expoData
[i
].weight
);
335 removeGlobalVar(expoData
[i
].curve
.value
);
341 int ModelData::getChannelsMax(bool forceExtendedLimits
) const
343 if (forceExtendedLimits
|| extendedLimits
)
344 return IS_HORUS_OR_TARANIS(getCurrentBoard()) ? 150 : 125;
349 bool ModelData::isAvailable(const RawSwitch
& swtch
) const
351 unsigned index
= abs(swtch
.index
) - 1;
353 if (swtch
.type
== SWITCH_TYPE_VIRTUAL
) {
354 return logicalSw
[index
].func
!= LS_FN_OFF
;
356 else if (swtch
.type
== SWITCH_TYPE_FLIGHT_MODE
) {
357 return index
== 0 || flightModeData
[index
].swtch
.type
!= SWITCH_TYPE_NONE
;
359 else if (swtch
.type
== SWITCH_TYPE_SENSOR
) {
360 return strlen(sensorData
[index
].label
) > 0;
367 float ModelData::getGVarFieldValuePrec(int phaseIdx
, int gvarIdx
)
369 return getGVarFieldValue(phaseIdx
, gvarIdx
) * gvarData
[gvarIdx
].multiplierGet();
372 void ModelData::convert(RadioDataConversionState
& cstate
)
374 // Here we can add explicit conversions when moving from one board to another
376 QString origin
= QString(name
);
377 if (origin
.isEmpty())
378 origin
= QString::number(cstate
.modelIdx
+1);
379 cstate
.setOrigin(tr("Model: ") % origin
);
381 cstate
.setComponent("SET", 0);
382 if (thrTraceSrc
&& (int)thrTraceSrc
< cstate
.fromBoard
.getCapability(Board::Pots
) + cstate
.fromBoard
.getCapability(Board::Sliders
)) {
383 cstate
.setSubComp(tr("Throttle Source"));
384 thrTraceSrc
= RawSource(SOURCE_TYPE_STICK
, (int)thrTraceSrc
+ 3).convert(cstate
).index
- 3;
387 for (int i
=0; i
<CPN_MAX_TIMERS
; i
++) {
388 timers
[i
].convert(cstate
.withComponentIndex(i
));
391 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++) {
392 mixData
[i
].convert(cstate
.withComponentIndex(i
));
395 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
396 expoData
[i
].convert(cstate
.withComponentIndex(i
));
399 for (int i
=0; i
<CPN_MAX_LOGICAL_SWITCHES
; i
++) {
400 logicalSw
[i
].convert(cstate
.withComponentIndex(i
));
403 for (int i
=0; i
<CPN_MAX_SPECIAL_FUNCTIONS
; i
++) {
404 customFn
[i
].convert(cstate
.withComponentIndex(i
));
407 for (int i
=0; i
<CPN_MAX_FLIGHT_MODES
; i
++) {
408 flightModeData
[i
].convert(cstate
.withComponentIndex(i
));
411 for (int i
=0; i
<CPN_MAX_MODULES
; i
++) {
412 moduleData
[i
].convert(cstate
.withComponentIndex(i
));