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.
24 #include "definitions.h"
25 #include "dataconstants.h"
26 #include "pulses_common.h"
30 #include "modules_helpers.h"
33 #if defined(PCBSKY9X) && defined(DSM2)
34 #define DSM2_BIND_TIMEOUT 255 // 255*11ms
35 extern uint8_t dsm2BindTimer
;
39 #define IS_DSM2_PROTOCOL(protocol) (protocol>=PROTOCOL_CHANNELS_DSM2_LP45 && protocol<=PROTOCOL_CHANNELS_DSM2_DSMX)
41 #define IS_DSM2_PROTOCOL(protocol) (0)
44 #if defined(DSM2_SERIAL)
45 #define IS_DSM2_SERIAL_PROTOCOL(protocol) (IS_DSM2_PROTOCOL(protocol))
47 #define IS_DSM2_SERIAL_PROTOCOL(protocol) (0)
50 #if defined(MULTIMODULE)
51 #define IS_MULTIMODULE_PROTOCOL(protocol) (protocol==PROTOCOL_CHANNELS_MULTIMODULE)
53 #error You need to enable DSM2 = PPM for MULTIMODULE support
56 #define IS_MULTIMODULE_PROTOCOL(protocol) (0)
59 #define IS_SBUS_PROTOCOL(protocol) (protocol == PROTOCOL_CHANNELS_SBUS)
61 extern uint8_t s_pulses_paused
;
63 enum ModuleSettingsMode
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
,
75 MODULE_MODE_RANGECHECK
,
77 MODULE_MODE_AUTHENTICATION
,
78 MODULE_MODE_OTA_UPDATE
,
82 PACK(struct PXX2Version
{
88 PACK(struct PXX2HardwareInformation
{
90 PXX2Version hwVersion
;
91 PXX2Version swVersion
;
93 uint32_t capabilities
; // variable length
94 uint8_t capabilityNotSupported
;
97 PACK(struct ModuleInformation
{
101 PXX2HardwareInformation information
;
103 PXX2HardwareInformation information
;
105 } receivers
[PXX2_MAX_RECEIVERS_PER_MODULE
];
108 class ModuleSettings
{
110 uint8_t state
; // 0x00 = READ 0x40 = WRITE
112 uint8_t externalAntenna
;
117 class ReceiverSettings
{
119 uint8_t state
; // 0x00 = READ 0x40 = WRITE
123 uint8_t telemetryDisabled
;
126 uint8_t outputsCount
;
127 uint8_t outputsMapping
[24];
130 class BindInformation
{
134 char candidateReceiversNames
[PXX2_MAX_RECEIVERS_PER_MODULE
][PXX2_LEN_RX_NAME
+ 1];
135 uint8_t candidateReceiversCount
;
136 uint8_t selectedReceiverIndex
;
140 PXX2HardwareInformation receiverInformation
;
143 class OtaUpdateInformation
: public BindInformation
{
145 char filename
[_MAX_LFN
+ 1];
149 typedef void (* ModuleCallback
)();
151 PACK(struct ModuleState
{
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
{
215 #if defined(PPM_PIN_SERIAL)
216 PACK(struct Dsm2SerialPulsesData
{
220 uint8_t serialBitCount
;
223 typedef Dsm2SerialPulsesData Dsm2PulsesData
;
225 #define MAX_PULSES_TRANSITIONS 300
226 PACK(struct Dsm2TimerPulsesData
{
227 pulse_duration_t pulses
[MAX_PULSES_TRANSITIONS
];
228 pulse_duration_t
* ptr
;
232 typedef Dsm2TimerPulsesData Dsm2PulsesData
;
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
];
251 union InternalModulePulsesData
{
253 #if defined(INTMODULE_USART)
254 UartPxx1Pulses pxx_uart
;
264 #if defined(MULTIMODULE) //&& defined(INTMODULE_USART)
265 UartMultiPulses multi
;
268 #if defined(INTERNAL_MODULE_PPM)
269 PpmPulsesData
<pulse_duration_t
> ppm
;
273 union ExternalModulePulsesData
{
275 #if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
276 UartPxx1Pulses pxx_uart
;
278 #if defined(PPM_PIN_SERIAL)
279 SerialPxx1Pulses pxx
;
289 #if defined(DSM2) || defined(MULTIMODULE) || defined(SBUS)
293 PpmPulsesData
<pulse_duration_t
> ppm
;
295 CrossfirePulsesData crossfire
;
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();
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
);
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();
346 setupPulsesExternalModule();
348 #if defined(HARDWARE_EXTRA_MODULE)
349 extramodulePpmStart();
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
)
412 if (moduleState
[1].mode
== MODULE_MODE_RANGECHECK
)
419 inline bool isModuleInBeepMode()
421 if (moduleState
[0].mode
>= MODULE_MODE_BEEP_FIRST
)
425 if (moduleState
[1].mode
>= MODULE_MODE_BEEP_FIRST
)