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.
23 uint8_t s_pulses_paused
= 0;
24 uint8_t s_current_protocol
[NUM_MODULES
] = { MODULES_INIT(255) };
25 uint16_t failsafeCounter
[NUM_MODULES
] = { MODULES_INIT(100) };
26 uint8_t moduleFlag
[NUM_MODULES
] = { 0 };
28 ModulePulsesData modulePulsesData
[NUM_MODULES
] __DMA
;
29 TrainerPulsesData trainerPulsesData __DMA
;
31 #if defined(CROSSFIRE)
32 uint8_t createCrossfireChannelsFrame(uint8_t * frame
, int16_t * pulses
);
35 uint8_t getRequiredProtocol(uint8_t port
)
37 uint8_t required_protocol
;
40 #if defined(PCBTARANIS) || defined(PCBHORUS)
42 switch (g_model
.moduleData
[INTERNAL_MODULE
].type
) {
43 #if defined(TARANIS_INTERNAL_PPM)
45 required_protocol
= PROTO_PPM
;
49 required_protocol
= PROTO_PXX
;
52 required_protocol
= PROTO_NONE
;
59 port
= EXTERNAL_MODULE
; // ensure it's external module only
60 switch (g_model
.moduleData
[EXTERNAL_MODULE
].type
) {
62 required_protocol
= PROTO_PPM
;
66 required_protocol
= PROTO_PXX
;
68 case MODULE_TYPE_SBUS
:
69 required_protocol
= PROTO_SBUS
;
71 #if defined(MULTIMODULE)
72 case MODULE_TYPE_MULTIMODULE
:
73 required_protocol
= PROTO_MULTIMODULE
;
77 case MODULE_TYPE_DSM2
:
78 required_protocol
= limit
<uint8_t>(PROTO_DSM2_LP45
, PROTO_DSM2_LP45
+g_model
.moduleData
[EXTERNAL_MODULE
].rfProtocol
, PROTO_DSM2_DSMX
);
79 // The module is set to OFF during one second before BIND start
81 static tmr10ms_t bindStartTime
= 0;
82 if (moduleFlag
[EXTERNAL_MODULE
] == MODULE_BIND
) {
83 if (bindStartTime
== 0) bindStartTime
= get_tmr10ms();
84 if ((tmr10ms_t
)(get_tmr10ms() - bindStartTime
) < 100) {
85 required_protocol
= PROTO_NONE
;
95 #if defined(CROSSFIRE)
96 case MODULE_TYPE_CROSSFIRE
:
97 required_protocol
= PROTO_CROSSFIRE
;
101 required_protocol
= PROTO_NONE
;
107 if (s_pulses_paused
) {
108 required_protocol
= PROTO_NONE
;
112 // will need an EEPROM conversion
113 if (moduleFlag
[port
] == MODULE_OFF
) {
114 required_protocol
= PROTO_NONE
;
118 return required_protocol
;
121 void setupPulses(uint8_t port
)
123 bool init_needed
= false;
124 uint8_t required_protocol
= getRequiredProtocol(port
);
126 heartbeat
|= (HEART_TIMER_PULSES
<< port
);
128 if (s_current_protocol
[port
] != required_protocol
) {
130 switch (s_current_protocol
[port
]) { // stop existing protocol hardware
136 case PROTO_DSM2_LP45
:
137 case PROTO_DSM2_DSM2
:
138 case PROTO_DSM2_DSMX
:
139 disable_serial(port
);
143 #if defined(CROSSFIRE)
144 case PROTO_CROSSFIRE
:
145 disable_crossfire(port
);
149 #if defined(MULTIMODULE)
150 case PROTO_MULTIMODULE
:
153 disable_serial(port
);
161 disable_no_pulses(port
);
164 s_current_protocol
[port
] = required_protocol
;
167 // Set up output data here
168 switch (required_protocol
) {
170 setupPulsesPXX(port
);
171 scheduleNextMixerCalculation(port
, PXX_PERIOD
);
175 setupPulsesSbus(port
);
176 scheduleNextMixerCalculation(port
, SBUS_PERIOD
);
180 case PROTO_DSM2_LP45
:
181 case PROTO_DSM2_DSM2
:
182 case PROTO_DSM2_DSMX
:
183 setupPulsesDSM2(port
);
184 scheduleNextMixerCalculation(port
, DSM2_PERIOD
);
188 #if defined(CROSSFIRE)
189 case PROTO_CROSSFIRE
:
190 if (telemetryProtocol
== PROTOCOL_PULSES_CROSSFIRE
&& !init_needed
) {
191 uint8_t * crossfire
= modulePulsesData
[port
].crossfire
.pulses
;
194 if (outputTelemetryBufferTrigger
!= 0x00 && outputTelemetryBufferSize
> 0) {
195 memcpy(crossfire
, outputTelemetryBuffer
, outputTelemetryBufferSize
);
196 len
= outputTelemetryBufferSize
;
197 outputTelemetryBufferTrigger
= 0x00;
198 outputTelemetryBufferSize
= 0;
203 len
= createCrossfireChannelsFrame(crossfire
, &channelOutputs
[g_model
.moduleData
[port
].channelsStart
]);
205 sportSendBuffer(crossfire
, len
);
207 scheduleNextMixerCalculation(port
, CROSSFIRE_PERIOD
);
211 #if defined(MULTIMODULE)
212 case PROTO_MULTIMODULE
:
213 setupPulsesMultimodule(port
);
214 scheduleNextMixerCalculation(port
, MULTIMODULE_PERIOD
);
219 #if defined(PCBSKY9X)
222 setupPulsesPPMModule(port
);
223 scheduleNextMixerCalculation(port
, PPM_PERIOD(port
));
231 switch (required_protocol
) { // Start new protocol hardware here
237 case PROTO_DSM2_LP45
:
238 case PROTO_DSM2_DSM2
:
239 case PROTO_DSM2_DSMX
:
240 init_serial(port
, DSM2_BAUDRATE
, DSM2_PERIOD
* 2000);
244 #if defined(CROSSFIRE)
245 case PROTO_CROSSFIRE
:
246 init_crossfire(port
);
250 #if defined(MULTIMODULE)
251 case PROTO_MULTIMODULE
:
252 init_serial(port
, MULTIMODULE_BAUDRATE
, MULTIMODULE_PERIOD
* 2000);
257 init_serial(port
, SBUS_BAUDRATE
, SBUS_PERIOD_HALF_US
);
265 init_no_pulses(port
);
271 void setCustomFailsafe(uint8_t moduleIndex
)
273 if (moduleIndex
< NUM_MODULES
) {
274 for (int ch
=0; ch
<MAX_OUTPUT_CHANNELS
; ch
++) {
275 if (ch
< g_model
.moduleData
[moduleIndex
].channelsStart
|| ch
>= NUM_CHANNELS(moduleIndex
) + g_model
.moduleData
[moduleIndex
].channelsStart
) {
276 g_model
.moduleData
[moduleIndex
].failsafeChannels
[ch
] = 0;
278 else if (g_model
.moduleData
[moduleIndex
].failsafeChannels
[ch
] < FAILSAFE_CHANNEL_HOLD
) {
279 g_model
.moduleData
[moduleIndex
].failsafeChannels
[ch
] = channelOutputs
[ch
];