Companion: Russian UI (#7180)
[opentx.git] / radio / src / pulses / pulses.cpp
blob21c4d7eee02897286fec04d2aa080f7ac702a4c0
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 "opentx.h"
22 #include "io/frsky_pxx2.h"
23 #include "pulses/pxx2.h"
25 uint8_t s_pulses_paused = 0;
26 ModuleState moduleState[NUM_MODULES];
27 InternalModulePulsesData intmodulePulsesData __DMA;
28 ExternalModulePulsesData extmodulePulsesData __DMA;
29 TrainerPulsesData trainerPulsesData __DMA;
31 void ModuleState::startBind(BindInformation * destination, ModuleCallback bindCallback)
33 bindInformation = destination;
34 callback = bindCallback;
35 mode = MODULE_MODE_BIND;
36 #if defined(SIMU)
37 bindInformation->candidateReceiversCount = 2;
38 strcpy(bindInformation->candidateReceiversNames[0], "SimuRX1");
39 strcpy(bindInformation->candidateReceiversNames[1], "SimuRX2");
40 #endif
43 uint8_t getModuleType(uint8_t module)
45 uint8_t type = g_model.moduleData[module].type;
47 #if defined(HARDWARE_INTERNAL_MODULE)
48 if (module == INTERNAL_MODULE && isInternalModuleAvailable(type)) {
49 return type;
51 #endif
53 if (module == EXTERNAL_MODULE && isExternalModuleAvailable(type)) {
54 return type;
57 return MODULE_TYPE_NONE;
60 uint8_t getRequiredProtocol(uint8_t module)
62 uint8_t protocol;
64 switch (getModuleType(module)) {
65 case MODULE_TYPE_PPM:
66 protocol = PROTOCOL_CHANNELS_PPM;
67 break;
69 case MODULE_TYPE_XJT_PXX1:
70 #if defined(INTMODULE_USART)
71 if (module == INTERNAL_MODULE) {
72 protocol = PROTOCOL_CHANNELS_PXX1_SERIAL;
73 break;
75 #endif
76 protocol = PROTOCOL_CHANNELS_PXX1_PULSES;
77 break;
79 case MODULE_TYPE_R9M_PXX1:
80 protocol = PROTOCOL_CHANNELS_PXX1_PULSES;
81 break;
83 #if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
84 case MODULE_TYPE_R9M_LITE_PXX1:
85 case MODULE_TYPE_R9M_LITE_PRO_PXX1:
86 protocol = PROTOCOL_CHANNELS_PXX1_SERIAL;
87 break;
89 case MODULE_TYPE_R9M_LITE_PXX2:
90 protocol = PROTOCOL_CHANNELS_PXX2_LOWSPEED;
91 break;
92 #endif
94 case MODULE_TYPE_ISRM_PXX2:
95 case MODULE_TYPE_R9M_PXX2:
96 #if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
97 case MODULE_TYPE_XJT_LITE_PXX2:
98 case MODULE_TYPE_R9M_LITE_PRO_PXX2:
99 #endif
100 protocol = PROTOCOL_CHANNELS_PXX2_HIGHSPEED;
101 break;
103 case MODULE_TYPE_SBUS:
104 protocol = PROTOCOL_CHANNELS_SBUS;
105 break;
107 #if defined(MULTIMODULE)
108 case MODULE_TYPE_MULTIMODULE:
109 protocol = PROTOCOL_CHANNELS_MULTIMODULE;
110 break;
111 #endif
113 #if defined(DSM2)
114 case MODULE_TYPE_DSM2:
115 protocol = limit<uint8_t>(PROTOCOL_CHANNELS_DSM2_LP45, PROTOCOL_CHANNELS_DSM2_LP45+g_model.moduleData[module].rfProtocol, PROTOCOL_CHANNELS_DSM2_DSMX);
116 // The module is set to OFF during one second before BIND start
118 static tmr10ms_t bindStartTime = 0;
119 if (moduleState[module].mode == MODULE_MODE_BIND) {
120 if (bindStartTime == 0) bindStartTime = get_tmr10ms();
121 if ((tmr10ms_t)(get_tmr10ms() - bindStartTime) < 100) {
122 protocol = PROTOCOL_CHANNELS_NONE;
123 break;
126 else {
127 bindStartTime = 0;
130 break;
131 #endif
133 #if defined(CROSSFIRE)
134 case MODULE_TYPE_CROSSFIRE:
135 protocol = PROTOCOL_CHANNELS_CROSSFIRE;
136 break;
137 #endif
139 default:
140 protocol = PROTOCOL_CHANNELS_NONE;
141 break;
144 if (s_pulses_paused) {
145 protocol = PROTOCOL_CHANNELS_NONE;
148 #if 0
149 // will need an EEPROM conversion
150 if (moduleState[module].mode == MODULE_OFF) {
151 protocol = PROTOCOL_CHANNELS_NONE;
153 #endif
155 return protocol;
158 void enablePulsesExternalModule(uint8_t protocol)
160 // start new protocol hardware here
162 switch (protocol) {
163 #if defined(PXX1)
164 case PROTOCOL_CHANNELS_PXX1_PULSES:
165 extmodulePxx1PulsesStart();
166 break;
167 #endif
169 #if defined(PXX1) && defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
170 case PROTOCOL_CHANNELS_PXX1_SERIAL:
171 extmodulePxx1SerialStart();
172 break;
173 #endif
175 #if defined(DSM2)
176 case PROTOCOL_CHANNELS_DSM2_LP45:
177 case PROTOCOL_CHANNELS_DSM2_DSM2:
178 case PROTOCOL_CHANNELS_DSM2_DSMX:
179 extmoduleSerialStart(DSM2_BAUDRATE, DSM2_PERIOD * 2000, false);
180 break;
181 #endif
183 #if defined(CROSSFIRE)
184 case PROTOCOL_CHANNELS_CROSSFIRE:
185 EXTERNAL_MODULE_ON();
186 break;
187 #endif
189 #if defined(PXX2) && defined(EXTMODULE_USART)
190 case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
191 extmoduleInvertedSerialStart(PXX2_HIGHSPEED_BAUDRATE);
192 break;
194 case PROTOCOL_CHANNELS_PXX2_LOWSPEED:
195 extmoduleInvertedSerialStart(PXX2_LOWSPEED_BAUDRATE);
196 break;
197 #endif
199 #if defined(MULTIMODULE)
200 case PROTOCOL_CHANNELS_MULTIMODULE:
201 extmoduleSerialStart(MULTIMODULE_BAUDRATE, MULTIMODULE_PERIOD * 2000, true);
202 break;
203 #endif
205 #if defined(SBUS)
206 case PROTOCOL_CHANNELS_SBUS:
207 extmoduleSerialStart(SBUS_BAUDRATE, SBUS_PERIOD_HALF_US, false);
208 break;
209 #endif
211 #if defined(PPM)
212 case PROTOCOL_CHANNELS_PPM:
213 extmodulePpmStart();
214 break;
215 #endif
217 default:
218 break;
222 void setupPulsesExternalModule(uint8_t protocol)
224 switch (protocol) {
225 #if defined(PXX1)
226 case PROTOCOL_CHANNELS_PXX1_PULSES:
227 extmodulePulsesData.pxx.setupFrame(EXTERNAL_MODULE);
228 scheduleNextMixerCalculation(EXTERNAL_MODULE, PXX_PULSES_PERIOD);
229 break;
230 #endif
232 #if defined(PXX1) && defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
233 case PROTOCOL_CHANNELS_PXX1_SERIAL:
234 extmodulePulsesData.pxx_uart.setupFrame(EXTERNAL_MODULE);
235 scheduleNextMixerCalculation(EXTERNAL_MODULE, EXTMODULE_PXX1_SERIAL_PERIOD);
236 break;
237 #endif
239 #if defined(PXX2)
240 case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
241 case PROTOCOL_CHANNELS_PXX2_LOWSPEED:
242 extmodulePulsesData.pxx2.setupFrame(EXTERNAL_MODULE);
243 scheduleNextMixerCalculation(EXTERNAL_MODULE, PXX2_PERIOD);
244 break;
245 #endif
247 #if defined(SBUS)
248 case PROTOCOL_CHANNELS_SBUS:
249 setupPulsesSbus();
250 scheduleNextMixerCalculation(EXTERNAL_MODULE, SBUS_PERIOD);
251 break;
252 #endif
254 #if defined(DSM2)
255 case PROTOCOL_CHANNELS_DSM2_LP45:
256 case PROTOCOL_CHANNELS_DSM2_DSM2:
257 case PROTOCOL_CHANNELS_DSM2_DSMX:
258 setupPulsesDSM2();
259 scheduleNextMixerCalculation(EXTERNAL_MODULE, DSM2_PERIOD);
260 break;
261 #endif
263 #if defined(CROSSFIRE)
264 case PROTOCOL_CHANNELS_CROSSFIRE:
265 setupPulsesCrossfire();
266 scheduleNextMixerCalculation(EXTERNAL_MODULE, CROSSFIRE_PERIOD);
267 break;
268 #endif
270 #if defined(MULTIMODULE)
271 case PROTOCOL_CHANNELS_MULTIMODULE:
272 setupPulsesMultiExternalModule();
273 scheduleNextMixerCalculation(EXTERNAL_MODULE, MULTIMODULE_PERIOD);
274 break;
275 #endif
277 #if defined(PPM)
278 case PROTOCOL_CHANNELS_PPM:
279 setupPulsesPPMExternalModule();
280 scheduleNextMixerCalculation(EXTERNAL_MODULE, PPM_PERIOD(EXTERNAL_MODULE));
281 break;
282 #endif
284 default:
285 break;
289 #if defined(HARDWARE_INTERNAL_MODULE)
290 static void enablePulsesInternalModule(uint8_t protocol)
292 // start new protocol hardware here
294 switch (protocol) {
295 #if defined(PXX1) && !defined(INTMODULE_USART)
296 case PROTOCOL_CHANNELS_PXX1_PULSES:
297 intmodulePxx1PulsesStart();
298 break;
299 #endif
301 #if defined(PXX1) && defined(INTMODULE_USART)
302 case PROTOCOL_CHANNELS_PXX1_SERIAL:
303 intmodulePxx1SerialStart();
304 break;
305 #endif
307 #if defined(PXX2)
308 case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
309 intmoduleSerialStart(PXX2_HIGHSPEED_BAUDRATE, true, USART_Parity_No, USART_StopBits_1, USART_WordLength_8b);
310 #if defined(HARDWARE_INTERNAL_MODULE) && defined(INTERNAL_MODULE_PXX2) && defined(ACCESS_LIB)
311 globalData.authenticationCount = 0;
312 #endif
313 break;
314 #endif
316 #if defined(INTERNAL_MODULE_MULTI)
317 case PROTOCOL_CHANNELS_MULTIMODULE:
318 intmodulePulsesData.multi.initFrame();
319 intmoduleSerialStart(MULTIMODULE_BAUDRATE, true, USART_Parity_Even, USART_StopBits_2, USART_WordLength_9b);
320 intmoduleTimerStart(MULTIMODULE_PERIOD);
321 break;
322 #endif
323 default:
324 break;
328 bool setupPulsesInternalModule(uint8_t protocol)
330 switch (protocol) {
331 #if defined(HARDWARE_INTERNAL_MODULE) && defined(PXX1) && !defined(INTMODULE_USART)
332 case PROTOCOL_CHANNELS_PXX1_PULSES:
333 intmodulePulsesData.pxx.setupFrame(INTERNAL_MODULE);
334 scheduleNextMixerCalculation(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
335 return true;
336 #endif
338 #if defined(PXX1) && defined(INTMODULE_USART)
339 case PROTOCOL_CHANNELS_PXX1_SERIAL:
340 intmodulePulsesData.pxx_uart.setupFrame(INTERNAL_MODULE);
341 #if !defined(INTMODULE_HEARTBEAT)
342 scheduleNextMixerCalculation(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
343 #endif
344 return true;
345 #endif
347 #if defined(PXX2)
348 case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
350 bool result = intmodulePulsesData.pxx2.setupFrame(INTERNAL_MODULE);
351 if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_SPECTRUM_ANALYSER || moduleState[INTERNAL_MODULE].mode == MODULE_MODE_POWER_METER) {
352 scheduleNextMixerCalculation(INTERNAL_MODULE, PXX2_TOOLS_PERIOD);
354 #if !defined(INTMODULE_HEARTBEAT)
355 else {
356 scheduleNextMixerCalculation(INTERNAL_MODULE, PXX2_PERIOD);
358 #endif
359 return result;
361 #endif
363 #if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM)
364 case PROTOCOL_CHANNELS_PPM:
365 setupPulsesPPMInternalModule();
366 scheduleNextMixerCalculation(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE));
367 return true;
368 #endif
370 #if defined(INTERNAL_MODULE_MULTI)
371 case PROTOCOL_CHANNELS_MULTIMODULE:
372 setupPulsesMultiInternalModule();
373 scheduleNextMixerCalculation(INTERNAL_MODULE, MULTIMODULE_PERIOD);
374 return true;
375 #endif
377 default:
378 return true;
382 bool setupPulsesInternalModule()
384 uint8_t protocol = getRequiredProtocol(INTERNAL_MODULE);
386 heartbeat |= (HEART_TIMER_PULSES << INTERNAL_MODULE);
388 if (moduleState[INTERNAL_MODULE].protocol != protocol) {
389 intmoduleStop();
390 moduleState[INTERNAL_MODULE].protocol = protocol;
391 enablePulsesInternalModule(protocol);
392 return false;
394 else {
395 return setupPulsesInternalModule(protocol);
398 #endif
400 bool setupPulsesExternalModule()
402 uint8_t protocol = getRequiredProtocol(EXTERNAL_MODULE);
404 heartbeat |= (HEART_TIMER_PULSES << EXTERNAL_MODULE);
406 if (moduleState[EXTERNAL_MODULE].protocol != protocol) {
407 extmoduleStop();
408 moduleState[EXTERNAL_MODULE].protocol = protocol;
409 enablePulsesExternalModule(protocol);
410 return false;
412 else {
413 setupPulsesExternalModule(protocol);
414 return true;
418 void setCustomFailsafe(uint8_t moduleIndex)
420 if (moduleIndex < NUM_MODULES) {
421 for (int ch=0; ch<MAX_OUTPUT_CHANNELS; ch++) {
422 if (ch < g_model.moduleData[moduleIndex].channelsStart || ch >= sentModuleChannels(moduleIndex) + g_model.moduleData[moduleIndex].channelsStart) {
423 g_model.failsafeChannels[ch] = 0;
425 else if (g_model.failsafeChannels[ch] < FAILSAFE_CHANNEL_HOLD) {
426 g_model.failsafeChannels[ch] = channelOutputs[ch];