Fix doc path
[opentx.git] / radio / src / pulses / pulses_arm.cpp
blobf2135ed0b07b166ef35377b768a5198636c1f2b7
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"
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);
33 #endif
35 uint8_t getRequiredProtocol(uint8_t port)
37 uint8_t required_protocol;
39 switch (port) {
40 #if defined(PCBTARANIS) || defined(PCBHORUS)
41 case INTERNAL_MODULE:
42 switch (g_model.moduleData[INTERNAL_MODULE].type) {
43 #if defined(TARANIS_INTERNAL_PPM)
44 case MODULE_TYPE_PPM:
45 required_protocol = PROTO_PPM;
46 break;
47 #endif
48 case MODULE_TYPE_XJT:
49 required_protocol = PROTO_PXX;
50 break;
51 default:
52 required_protocol = PROTO_NONE;
53 break;
55 break;
56 #endif
58 default:
59 port = EXTERNAL_MODULE; // ensure it's external module only
60 switch (g_model.moduleData[EXTERNAL_MODULE].type) {
61 case MODULE_TYPE_PPM:
62 required_protocol = PROTO_PPM;
63 break;
64 case MODULE_TYPE_XJT:
65 case MODULE_TYPE_R9M:
66 required_protocol = PROTO_PXX;
67 break;
68 case MODULE_TYPE_SBUS:
69 required_protocol = PROTO_SBUS;
70 break;
71 #if defined(MULTIMODULE)
72 case MODULE_TYPE_MULTIMODULE:
73 required_protocol = PROTO_MULTIMODULE;
74 break;
75 #endif
76 #if defined(DSM2)
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;
86 break;
89 else {
90 bindStartTime = 0;
93 break;
94 #endif
95 #if defined(CROSSFIRE)
96 case MODULE_TYPE_CROSSFIRE:
97 required_protocol = PROTO_CROSSFIRE;
98 break;
99 #endif
100 default:
101 required_protocol = PROTO_NONE;
102 break;
104 break;
107 if (s_pulses_paused) {
108 required_protocol = PROTO_NONE;
111 #if 0
112 // will need an EEPROM conversion
113 if (moduleFlag[port] == MODULE_OFF) {
114 required_protocol = PROTO_NONE;
116 #endif
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) {
129 init_needed = true;
130 switch (s_current_protocol[port]) { // stop existing protocol hardware
131 case PROTO_PXX:
132 disable_pxx(port);
133 break;
135 #if defined(DSM2)
136 case PROTO_DSM2_LP45:
137 case PROTO_DSM2_DSM2:
138 case PROTO_DSM2_DSMX:
139 disable_serial(port);
140 break;
141 #endif
143 #if defined(CROSSFIRE)
144 case PROTO_CROSSFIRE:
145 disable_crossfire(port);
146 break;
147 #endif
149 #if defined(MULTIMODULE)
150 case PROTO_MULTIMODULE:
151 #endif
152 case PROTO_SBUS:
153 disable_serial(port);
154 break;
156 case PROTO_PPM:
157 disable_ppm(port);
158 break;
160 default:
161 disable_no_pulses(port);
162 break;
164 s_current_protocol[port] = required_protocol;
167 // Set up output data here
168 switch (required_protocol) {
169 case PROTO_PXX:
170 setupPulsesPXX(port);
171 scheduleNextMixerCalculation(port, PXX_PERIOD);
172 break;
174 case PROTO_SBUS:
175 setupPulsesSbus(port);
176 scheduleNextMixerCalculation(port, SBUS_PERIOD);
177 break;
179 #if defined(DSM2)
180 case PROTO_DSM2_LP45:
181 case PROTO_DSM2_DSM2:
182 case PROTO_DSM2_DSMX:
183 setupPulsesDSM2(port);
184 scheduleNextMixerCalculation(port, DSM2_PERIOD);
185 break;
186 #endif
188 #if defined(CROSSFIRE)
189 case PROTO_CROSSFIRE:
190 if (telemetryProtocol == PROTOCOL_PULSES_CROSSFIRE && !init_needed) {
191 uint8_t * crossfire = modulePulsesData[port].crossfire.pulses;
192 uint8_t len;
193 #if defined(LUA)
194 if (outputTelemetryBufferTrigger != 0x00 && outputTelemetryBufferSize > 0) {
195 memcpy(crossfire, outputTelemetryBuffer, outputTelemetryBufferSize);
196 len = outputTelemetryBufferSize;
197 outputTelemetryBufferTrigger = 0x00;
198 outputTelemetryBufferSize = 0;
200 else
201 #endif
203 len = createCrossfireChannelsFrame(crossfire, &channelOutputs[g_model.moduleData[port].channelsStart]);
205 sportSendBuffer(crossfire, len);
207 scheduleNextMixerCalculation(port, CROSSFIRE_PERIOD);
208 break;
209 #endif
211 #if defined(MULTIMODULE)
212 case PROTO_MULTIMODULE:
213 setupPulsesMultimodule(port);
214 scheduleNextMixerCalculation(port, MULTIMODULE_PERIOD);
215 break;
216 #endif
218 case PROTO_PPM:
219 #if defined(PCBSKY9X)
220 case PROTO_NONE:
221 #endif
222 setupPulsesPPMModule(port);
223 scheduleNextMixerCalculation(port, PPM_PERIOD(port));
224 break;
226 default:
227 break;
230 if (init_needed) {
231 switch (required_protocol) { // Start new protocol hardware here
232 case PROTO_PXX:
233 init_pxx(port);
234 break;
236 #if defined(DSM2)
237 case PROTO_DSM2_LP45:
238 case PROTO_DSM2_DSM2:
239 case PROTO_DSM2_DSMX:
240 init_serial(port, DSM2_BAUDRATE, DSM2_PERIOD * 2000);
241 break;
242 #endif
244 #if defined(CROSSFIRE)
245 case PROTO_CROSSFIRE:
246 init_crossfire(port);
247 break;
248 #endif
250 #if defined(MULTIMODULE)
251 case PROTO_MULTIMODULE:
252 init_serial(port, MULTIMODULE_BAUDRATE, MULTIMODULE_PERIOD * 2000);
253 break;
254 #endif
256 case PROTO_SBUS:
257 init_serial(port, SBUS_BAUDRATE, SBUS_PERIOD_HALF_US);
258 break;
260 case PROTO_PPM:
261 init_ppm(port);
262 break;
264 default:
265 init_no_pulses(port);
266 break;
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];