Various fixes around Companion trainer mode (#7116)
[opentx.git] / radio / src / tasks.cpp
blob9cbe9e2bd6ba3e1e93081f78952d340e4723273c
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 RTOS_TASK_HANDLE menusTaskId;
24 RTOS_DEFINE_STACK(menusStack, MENUS_STACK_SIZE);
26 RTOS_TASK_HANDLE mixerTaskId;
27 RTOS_DEFINE_STACK(mixerStack, MIXER_STACK_SIZE);
29 RTOS_TASK_HANDLE audioTaskId;
30 RTOS_DEFINE_STACK(audioStack, AUDIO_STACK_SIZE);
32 RTOS_MUTEX_HANDLE audioMutex;
33 RTOS_MUTEX_HANDLE mixerMutex;
35 enum TaskIndex {
36 MENU_TASK_INDEX,
37 MIXER_TASK_INDEX,
38 AUDIO_TASK_INDEX,
39 CLI_TASK_INDEX,
40 BLUETOOTH_TASK_INDEX,
41 TASK_INDEX_COUNT,
42 MAIN_TASK_INDEX = 255
45 void stackPaint()
47 menusStack.paint();
48 mixerStack.paint();
49 audioStack.paint();
50 #if defined(CLI)
51 cliStack.paint();
52 #endif
55 volatile uint16_t timeForcePowerOffPressed = 0;
57 bool isForcePowerOffRequested()
59 if (pwrOffPressed()) {
60 if (timeForcePowerOffPressed == 0) {
61 timeForcePowerOffPressed = get_tmr10ms();
63 else {
64 uint16_t delay = (uint16_t)get_tmr10ms() - timeForcePowerOffPressed;
65 if (delay > 1000/*10s*/) {
66 return true;
70 else {
71 resetForcePowerOffRequest();
73 return false;
76 bool isModuleSynchronous(uint8_t module)
78 uint8_t protocol = moduleState[module].protocol;
79 if (protocol == PROTOCOL_CHANNELS_PXX2_HIGHSPEED || protocol == PROTOCOL_CHANNELS_PXX2_LOWSPEED || protocol == PROTOCOL_CHANNELS_CROSSFIRE || protocol == PROTOCOL_CHANNELS_NONE)
80 return true;
81 #if defined(INTMODULE_USART) || defined(EXTMODULE_USART)
82 if (protocol == PROTOCOL_CHANNELS_PXX1_SERIAL)
83 return true;
84 #endif
85 return false;
88 void sendSynchronousPulses()
90 #if defined(HARDWARE_INTERNAL_MODULE)
91 if (isModuleSynchronous(INTERNAL_MODULE)) {
92 if (setupPulsesInternalModule())
93 intmoduleSendNextFrame();
95 #endif
97 if (isModuleSynchronous(EXTERNAL_MODULE)) {
98 if (setupPulsesExternalModule())
99 extmoduleSendNextFrame();
103 uint32_t nextMixerTime[NUM_MODULES];
105 TASK_FUNCTION(mixerTask)
107 static uint32_t lastRunTime;
108 s_pulses_paused = true;
110 while (true) {
111 #if defined(PCBTARANIS) && defined(SBUS)
112 // SBUS trainer
113 processSbusInput();
114 #endif
116 #if defined(GYRO)
117 gyro.wakeup();
118 #endif
120 #if defined(BLUETOOTH)
121 bluetooth.wakeup();
122 #endif
124 RTOS_WAIT_TICKS(1);
126 #if defined(SIMU)
127 if (pwrCheck() == e_power_off) {
128 TASK_RETURN();
130 #else
131 if (isForcePowerOffRequested()) {
132 boardOff();
134 #endif
136 uint32_t now = RTOS_GET_MS();
137 bool run = false;
139 if (now - lastRunTime >= 10) {
140 // run at least every 10ms
141 run = true;
144 #if defined(INTMODULE_USART) && defined(INTMODULE_HEARTBEAT)
145 if ((moduleState[INTERNAL_MODULE].protocol == PROTOCOL_CHANNELS_PXX2_HIGHSPEED || moduleState[INTERNAL_MODULE].protocol == PROTOCOL_CHANNELS_PXX1_SERIAL) && heartbeatCapture.valid && heartbeatCapture.timestamp > lastRunTime) {
146 run = true;
148 #endif
150 if (now == nextMixerTime[0]) {
151 run = true;
154 #if NUM_MODULES >= 2
155 if (now == nextMixerTime[1]) {
156 run = true;
158 #endif
160 if (!run) {
161 continue; // go back to sleep
164 lastRunTime = now;
166 if (!s_pulses_paused) {
167 uint16_t t0 = getTmr2MHz();
169 DEBUG_TIMER_START(debugTimerMixer);
170 RTOS_LOCK_MUTEX(mixerMutex);
171 doMixerCalculations();
172 DEBUG_TIMER_START(debugTimerMixerCalcToUsage);
173 DEBUG_TIMER_SAMPLE(debugTimerMixerIterval);
174 RTOS_UNLOCK_MUTEX(mixerMutex);
175 DEBUG_TIMER_STOP(debugTimerMixer);
177 #if defined(STM32) && !defined(SIMU)
178 if (getSelectedUsbMode() == USB_JOYSTICK_MODE) {
179 usbJoystickUpdate();
181 #endif
183 #if defined(PCBSKY9X) && !defined(SIMU)
184 usbJoystickUpdate();
185 #endif
187 DEBUG_TIMER_START(debugTimerTelemetryWakeup);
188 telemetryWakeup();
189 DEBUG_TIMER_STOP(debugTimerTelemetryWakeup);
191 if (heartbeat == HEART_WDT_CHECK) {
192 WDG_RESET();
193 heartbeat = 0;
196 t0 = getTmr2MHz() - t0;
197 if (t0 > maxMixerDuration)
198 maxMixerDuration = t0;
200 sendSynchronousPulses();
205 void scheduleNextMixerCalculation(uint8_t module, uint16_t period_ms)
207 // Schedule next mixer calculation time,
209 if (isModuleSynchronous(module)) {
210 nextMixerTime[module] += period_ms / RTOS_MS_PER_TICK;
211 if (nextMixerTime[module] < RTOS_GET_TIME()) {
212 // we are late ... let's add some small delay
213 nextMixerTime[module] = (uint32_t) RTOS_GET_TIME() + (period_ms / RTOS_MS_PER_TICK);
216 else {
217 // for now assume mixer calculation takes 2 ms.
218 nextMixerTime[module] = (uint32_t) RTOS_GET_TIME() + (period_ms / RTOS_MS_PER_TICK);
221 DEBUG_TIMER_STOP(debugTimerMixerCalcToUsage);
224 #define MENU_TASK_PERIOD_TICKS (50 / RTOS_MS_PER_TICK) // 50ms
226 #if defined(COLORLCD) && defined(CLI)
227 bool perMainEnabled = true;
228 #endif
230 TASK_FUNCTION(menusTask)
232 opentxInit();
234 #if defined(PWR_BUTTON_PRESS)
235 while (true) {
236 uint32_t pwr_check = pwrCheck();
237 if (pwr_check == e_power_off) {
238 break;
240 else if (pwr_check == e_power_press) {
241 RTOS_WAIT_TICKS(MENU_TASK_PERIOD_TICKS);
242 continue;
244 #else
245 while (pwrCheck() != e_power_off) {
246 #endif
247 uint32_t start = (uint32_t)RTOS_GET_TIME();
248 DEBUG_TIMER_START(debugTimerPerMain);
249 #if defined(COLORLCD) && defined(CLI)
250 if (perMainEnabled) {
251 perMain();
253 #else
254 perMain();
255 #endif
256 DEBUG_TIMER_STOP(debugTimerPerMain);
257 // TODO remove completely massstorage from sky9x firmware
258 uint32_t runtime = ((uint32_t)RTOS_GET_TIME() - start);
259 // deduct the thread run-time from the wait, if run-time was more than
260 // desired period, then skip the wait all together
261 if (runtime < MENU_TASK_PERIOD_TICKS) {
262 RTOS_WAIT_TICKS(MENU_TASK_PERIOD_TICKS - runtime);
265 resetForcePowerOffRequest();
268 #if defined(PCBX9E)
269 toplcdOff();
270 #endif
272 #if defined(PCBHORUS)
273 ledOff();
274 #endif
276 drawSleepBitmap();
277 opentxClose();
278 boardOff(); // Only turn power off if necessary
280 TASK_RETURN();
283 void tasksStart()
285 RTOS_INIT();
287 #if defined(CLI)
288 cliStart();
289 #endif
291 RTOS_CREATE_TASK(mixerTaskId, mixerTask, "mixer", mixerStack, MIXER_STACK_SIZE, MIXER_TASK_PRIO);
292 RTOS_CREATE_TASK(menusTaskId, menusTask, "menus", menusStack, MENUS_STACK_SIZE, MENUS_TASK_PRIO);
294 #if !defined(SIMU)
295 RTOS_CREATE_TASK(audioTaskId, audioTask, "audio", audioStack, AUDIO_STACK_SIZE, AUDIO_TASK_PRIO);
296 #endif
298 RTOS_CREATE_MUTEX(audioMutex);
299 RTOS_CREATE_MUTEX(mixerMutex);
301 RTOS_START();