Companion: Russian UI (#7180)
[opentx.git] / radio / src / pulses / pulses.h
blob7d859c0752a10c1361f68fda5a741a86c1090c44
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 #ifndef _PULSES_H_
22 #define _PULSES_H_
24 #include "definitions.h"
25 #include "dataconstants.h"
26 #include "pulses_common.h"
27 #include "pxx1.h"
28 #include "pxx2.h"
29 #include "multi.h"
30 #include "modules_helpers.h"
31 #include "ff.h"
33 #if defined(PCBSKY9X) && defined(DSM2)
34 #define DSM2_BIND_TIMEOUT 255 // 255*11ms
35 extern uint8_t dsm2BindTimer;
36 #endif
38 #if defined(DSM2)
39 #define IS_DSM2_PROTOCOL(protocol) (protocol>=PROTOCOL_CHANNELS_DSM2_LP45 && protocol<=PROTOCOL_CHANNELS_DSM2_DSMX)
40 #else
41 #define IS_DSM2_PROTOCOL(protocol) (0)
42 #endif
44 #if defined(DSM2_SERIAL)
45 #define IS_DSM2_SERIAL_PROTOCOL(protocol) (IS_DSM2_PROTOCOL(protocol))
46 #else
47 #define IS_DSM2_SERIAL_PROTOCOL(protocol) (0)
48 #endif
50 #if defined(MULTIMODULE)
51 #define IS_MULTIMODULE_PROTOCOL(protocol) (protocol==PROTOCOL_CHANNELS_MULTIMODULE)
52 #if !defined(DSM2)
53 #error You need to enable DSM2 = PPM for MULTIMODULE support
54 #endif
55 #else
56 #define IS_MULTIMODULE_PROTOCOL(protocol) (0)
57 #endif
59 #define IS_SBUS_PROTOCOL(protocol) (protocol == PROTOCOL_CHANNELS_SBUS)
61 extern uint8_t s_pulses_paused;
63 enum ModuleSettingsMode
65 MODULE_MODE_NORMAL,
66 MODULE_MODE_SPECTRUM_ANALYSER,
67 MODULE_MODE_POWER_METER,
68 MODULE_MODE_GET_HARDWARE_INFO,
69 MODULE_MODE_MODULE_SETTINGS,
70 MODULE_MODE_RECEIVER_SETTINGS,
71 MODULE_MODE_BEEP_FIRST,
72 MODULE_MODE_REGISTER = MODULE_MODE_BEEP_FIRST,
73 MODULE_MODE_BIND,
74 MODULE_MODE_SHARE,
75 MODULE_MODE_RANGECHECK,
76 MODULE_MODE_RESET,
77 MODULE_MODE_AUTHENTICATION,
78 MODULE_MODE_OTA_UPDATE,
82 PACK(struct PXX2Version {
83 uint8_t major;
84 uint8_t revision:4;
85 uint8_t minor:4;
86 });
88 PACK(struct PXX2HardwareInformation {
89 uint8_t modelID;
90 PXX2Version hwVersion;
91 PXX2Version swVersion;
92 uint8_t variant;
93 uint32_t capabilities; // variable length
94 uint8_t capabilityNotSupported;
95 });
97 PACK(struct ModuleInformation {
98 int8_t current;
99 int8_t maximum;
100 uint8_t timeout;
101 PXX2HardwareInformation information;
102 struct {
103 PXX2HardwareInformation information;
104 tmr10ms_t timestamp;
105 } receivers[PXX2_MAX_RECEIVERS_PER_MODULE];
108 class ModuleSettings {
109 public:
110 uint8_t state; // 0x00 = READ 0x40 = WRITE
111 tmr10ms_t timeout;
112 uint8_t externalAntenna;
113 int8_t txPower;
114 uint8_t dirty;
117 class ReceiverSettings {
118 public:
119 uint8_t state; // 0x00 = READ 0x40 = WRITE
120 tmr10ms_t timeout;
121 uint8_t receiverId;
122 uint8_t dirty;
123 uint8_t telemetryDisabled;
124 uint8_t pwmRate;
125 uint8_t fport;
126 uint8_t outputsCount;
127 uint8_t outputsMapping[24];
130 class BindInformation {
131 public:
132 int8_t step;
133 uint32_t timeout;
134 char candidateReceiversNames[PXX2_MAX_RECEIVERS_PER_MODULE][PXX2_LEN_RX_NAME + 1];
135 uint8_t candidateReceiversCount;
136 uint8_t selectedReceiverIndex;
137 uint8_t rxUid;
138 uint8_t lbtMode;
139 uint8_t flexMode;
140 PXX2HardwareInformation receiverInformation;
143 class OtaUpdateInformation: public BindInformation {
144 public:
145 char filename[_MAX_LFN + 1];
146 uint32_t address;
149 typedef void (* ModuleCallback)();
151 PACK(struct ModuleState {
152 uint8_t protocol:4;
153 uint8_t mode:4;
154 uint8_t paused:1;
155 uint8_t spare:7;
156 uint16_t counter;
157 union
159 ModuleInformation * moduleInformation;
160 ModuleSettings * moduleSettings;
161 ReceiverSettings * receiverSettings;
162 BindInformation * bindInformation;
163 OtaUpdateInformation * otaUpdateInformation;
165 ModuleCallback callback;
167 void startBind(BindInformation * destination, ModuleCallback bindCallback = nullptr);
169 void readModuleInformation(ModuleInformation * destination, int8_t first, int8_t last)
171 moduleInformation = destination;
172 moduleInformation->current = first;
173 moduleInformation->maximum = last;
174 mode = MODULE_MODE_GET_HARDWARE_INFO;
177 void readModuleSettings(ModuleSettings * destination)
179 moduleSettings = destination;
180 moduleSettings->state = PXX2_SETTINGS_READ;
181 mode = MODULE_MODE_MODULE_SETTINGS;
184 void writeModuleSettings(ModuleSettings * source)
186 moduleSettings = source;
187 moduleSettings->state = PXX2_SETTINGS_WRITE;
188 moduleSettings->timeout = 0;
189 mode = MODULE_MODE_MODULE_SETTINGS;
192 void readReceiverSettings(ReceiverSettings * destination)
194 receiverSettings = destination;
195 receiverSettings->state = PXX2_SETTINGS_READ;
196 mode = MODULE_MODE_RECEIVER_SETTINGS;
199 void writeReceiverSettings(ReceiverSettings * source)
201 receiverSettings = source;
202 receiverSettings->state = PXX2_SETTINGS_WRITE;
203 receiverSettings->timeout = 0;
204 mode = MODULE_MODE_RECEIVER_SETTINGS;
208 extern ModuleState moduleState[NUM_MODULES];
210 template<class T> struct PpmPulsesData {
211 T pulses[20];
212 T * ptr;
215 #if defined(PPM_PIN_SERIAL)
216 PACK(struct Dsm2SerialPulsesData {
217 uint8_t pulses[64];
218 uint8_t * ptr;
219 uint8_t serialByte ;
220 uint8_t serialBitCount;
221 uint16_t _alignment;
223 typedef Dsm2SerialPulsesData Dsm2PulsesData;
224 #else
225 #define MAX_PULSES_TRANSITIONS 300
226 PACK(struct Dsm2TimerPulsesData {
227 pulse_duration_t pulses[MAX_PULSES_TRANSITIONS];
228 pulse_duration_t * ptr;
229 uint16_t rest;
230 uint8_t index;
232 typedef Dsm2TimerPulsesData Dsm2PulsesData;
233 #endif
235 #define PPM_PERIOD_HALF_US(module) ((g_model.moduleData[module].ppm.frameLength * 5 + 225) * 200) /*half us*/
236 #define PPM_PERIOD(module) (PPM_PERIOD_HALF_US(module) / 2000) /*ms*/
237 #define DSM2_BAUDRATE 125000
238 #define DSM2_PERIOD 22 /*ms*/
239 #define SBUS_BAUDRATE 100000
240 #define SBUS_PERIOD_HALF_US ((g_model.moduleData[EXTERNAL_MODULE].sbus.refreshRate * 5 + 225) * 200) /*half us*/
241 #define SBUS_PERIOD (SBUS_PERIOD_HALF_US / 2000) /*ms*/
242 #define MULTIMODULE_BAUDRATE 100000
243 #define MULTIMODULE_PERIOD 7 /*ms*/
245 #define CROSSFIRE_FRAME_MAXLEN 64
246 PACK(struct CrossfirePulsesData {
247 uint8_t pulses[CROSSFIRE_FRAME_MAXLEN];
248 uint8_t length;
251 union InternalModulePulsesData {
252 #if defined(PXX1)
253 #if defined(INTMODULE_USART)
254 UartPxx1Pulses pxx_uart;
255 #else
256 PwmPxx1Pulses pxx;
257 #endif
258 #endif
260 #if defined(PXX2)
261 Pxx2Pulses pxx2;
262 #endif
264 #if defined(MULTIMODULE) //&& defined(INTMODULE_USART)
265 UartMultiPulses multi;
266 #endif
268 #if defined(INTERNAL_MODULE_PPM)
269 PpmPulsesData<pulse_duration_t> ppm;
270 #endif
271 } __ALIGNED(4);
273 union ExternalModulePulsesData {
274 #if defined(PXX1)
275 #if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
276 UartPxx1Pulses pxx_uart;
277 #endif
278 #if defined(PPM_PIN_SERIAL)
279 SerialPxx1Pulses pxx;
280 #else
281 PwmPxx1Pulses pxx;
282 #endif
283 #endif
285 #if defined(PXX2)
286 Pxx2Pulses pxx2;
287 #endif
289 #if defined(DSM2) || defined(MULTIMODULE) || defined(SBUS)
290 Dsm2PulsesData dsm2;
291 #endif
293 PpmPulsesData<pulse_duration_t> ppm;
295 CrossfirePulsesData crossfire;
296 } __ALIGNED(4);
298 /* The __ALIGNED keyword is required to align the struct inside the modulePulsesData below,
299 * which is also defined to be __DMA (which includes __ALIGNED) aligned.
300 * Arrays in C/C++ are always defined to be *contiguously*. The first byte of the second element is therefore always
301 * sizeof(ModulePulsesData). __ALIGNED is required for sizeof(ModulePulsesData) to be a multiple of the alignment.
305 extern InternalModulePulsesData intmodulePulsesData;
306 extern ExternalModulePulsesData extmodulePulsesData;
308 union TrainerPulsesData {
309 PpmPulsesData<trainer_pulse_duration_t> ppm;
312 extern TrainerPulsesData trainerPulsesData;
314 #if defined(HARDWARE_INTERNAL_MODULE)
315 bool setupPulsesInternalModule();
316 #endif
317 bool setupPulsesExternalModule();
318 void setupPulsesDSM2();
319 void setupPulsesCrossfire();
320 void setupPulsesMultiExternalModule();
321 void setupPulsesMultiInternalModule();
322 void setupPulsesSbus();
323 void setupPulsesPPMInternalModule();
324 void setupPulsesPPMExternalModule();
325 void setupPulsesPPMTrainer();
326 void sendByteDsm2(uint8_t b);
327 void putDsm2Flush();
328 void putDsm2SerialBit(uint8_t bit);
329 void sendByteSbus(uint8_t b);
330 void intmodulePxx1PulsesStart();
331 void intmodulePxx1SerialStart();
332 void extmodulePxx1PulsesStart();
333 void extmodulePxx1SerialStart();
334 void extmodulePpmStart();
335 void intmoduleStop();
336 void extmoduleStop();
338 inline void startPulses()
340 s_pulses_paused = false;
342 #if defined(HARDWARE_INTERNAL_MODULE)
343 setupPulsesInternalModule();
344 #endif
346 setupPulsesExternalModule();
348 #if defined(HARDWARE_EXTRA_MODULE)
349 extramodulePpmStart();
350 #endif
353 enum ChannelsProtocols {
354 PROTOCOL_CHANNELS_UNINITIALIZED,
355 PROTOCOL_CHANNELS_NONE,
356 PROTOCOL_CHANNELS_PPM,
357 PROTOCOL_CHANNELS_PXX1_PULSES,
358 PROTOCOL_CHANNELS_PXX1_SERIAL,
359 PROTOCOL_CHANNELS_DSM2_LP45,
360 PROTOCOL_CHANNELS_DSM2_DSM2,
361 PROTOCOL_CHANNELS_DSM2_DSMX,
362 PROTOCOL_CHANNELS_CROSSFIRE,
363 PROTOCOL_CHANNELS_MULTIMODULE,
364 PROTOCOL_CHANNELS_SBUS,
365 PROTOCOL_CHANNELS_PXX2_LOWSPEED,
366 PROTOCOL_CHANNELS_PXX2_HIGHSPEED,
369 inline void stopPulses()
371 s_pulses_paused = true;
372 moduleState[0].protocol = PROTOCOL_CHANNELS_UNINITIALIZED;
375 inline bool pulsesStarted()
377 return moduleState[0].protocol != PROTOCOL_CHANNELS_UNINITIALIZED;
380 inline void pausePulses()
382 s_pulses_paused = true;
385 inline void resumePulses()
387 s_pulses_paused = false;
390 inline void SEND_FAILSAFE_NOW(uint8_t idx)
392 moduleState[idx].counter = 1;
395 inline void SEND_FAILSAFE_1S()
397 for (uint8_t i=0; i<NUM_MODULES; i++) {
398 moduleState[i].counter = 100;
402 // Assign failsafe values using the current channel outputs
403 // for channels not set previously to HOLD or NOPULSE
404 void setCustomFailsafe(uint8_t moduleIndex);
406 inline bool isModuleInRangeCheckMode()
408 if (moduleState[0].mode == MODULE_MODE_RANGECHECK)
409 return true;
411 #if NUM_MODULES > 1
412 if (moduleState[1].mode == MODULE_MODE_RANGECHECK)
413 return true;
414 #endif
416 return false;
419 inline bool isModuleInBeepMode()
421 if (moduleState[0].mode >= MODULE_MODE_BEEP_FIRST)
422 return true;
424 #if NUM_MODULES > 1
425 if (moduleState[1].mode >= MODULE_MODE_BEEP_FIRST)
426 return true;
427 #endif
429 return false;
432 #endif // _PULSES_H_