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 // menus stack must be aligned to 8 bytes otherwise printf for %f does not work!
25 TaskStack
<MENUS_STACK_SIZE
> _ALIGNED(8) menusStack
;
28 TaskStack
<MIXER_STACK_SIZE
> mixerStack
;
31 TaskStack
<AUDIO_STACK_SIZE
> audioStack
;
33 OS_MutexID audioMutex
;
34 OS_MutexID mixerMutex
;
47 void TaskStack
<SIZE
>::paint()
49 for (uint32_t i
=0; i
<SIZE
; i
++) {
50 stack
[i
] = 0x55555555;
54 uint16_t getStackAvailable(void * address
, uint16_t size
)
56 uint32_t * array
= (uint32_t *)address
;
58 while (i
< size
&& array
[i
] == 0x55555555) {
77 #if defined(STM32) && !defined(SIMU)
80 return ((unsigned char *)&_estack
- (unsigned char *)&_main_stack_start
) / 4;
83 uint16_t stackAvailable()
85 return getStackAvailable(&_main_stack_start
, stackSize());
89 volatile uint16_t timeForcePowerOffPressed
= 0;
91 bool isForcePowerOffRequested()
93 if (pwrOffPressed()) {
94 if (timeForcePowerOffPressed
== 0) {
95 timeForcePowerOffPressed
= get_tmr10ms();
98 uint16_t delay
= (uint16_t)get_tmr10ms() - timeForcePowerOffPressed
;
99 if (delay
> 1000/*10s*/) {
105 resetForcePowerOffRequest();
110 uint32_t nextMixerTime
[NUM_MODULES
];
112 void mixerTask(void * pdata
)
114 static uint32_t lastRunTime
;
115 s_pulses_paused
= true;
120 if (main_thread_running
== 0)
130 if (isForcePowerOffRequested()) {
134 uint32_t now
= CoGetOSTime();
136 #if !defined(SIMU) && defined(STM32)
137 if ((now
- lastRunTime
) >= (usbStarted() ? 5 : 10)) { // run at least every 20ms (every 10ms if USB is active)
139 if ((now
- lastRunTime
) >= 10) { // run at least every 20ms
143 else if (now
== nextMixerTime
[0]) {
147 else if (now
== nextMixerTime
[1]) {
152 continue; // go back to sleep
157 if (!s_pulses_paused
) {
158 uint16_t t0
= getTmr2MHz();
160 DEBUG_TIMER_START(debugTimerMixer
);
161 CoEnterMutexSection(mixerMutex
);
162 doMixerCalculations();
163 DEBUG_TIMER_START(debugTimerMixerCalcToUsage
);
164 DEBUG_TIMER_SAMPLE(debugTimerMixerIterval
);
165 CoLeaveMutexSection(mixerMutex
);
166 DEBUG_TIMER_STOP(debugTimerMixer
);
168 #if defined(STM32) && !defined(SIMU)
169 if (getSelectedUsbMode() == USB_JOYSTICK_MODE
) {
174 #if defined(TELEMETRY_FRSKY) || defined(TELEMETRY_MAVLINK)
175 DEBUG_TIMER_START(debugTimerTelemetryWakeup
);
177 DEBUG_TIMER_STOP(debugTimerTelemetryWakeup
);
180 #if defined(BLUETOOTH)
184 if (heartbeat
== HEART_WDT_CHECK
) {
189 t0
= getTmr2MHz() - t0
;
190 if (t0
> maxMixerDuration
) maxMixerDuration
= t0
;
195 void scheduleNextMixerCalculation(uint8_t module
, uint16_t period_ms
)
197 // Schedule next mixer calculation time,
198 // for now assume mixer calculation takes 2 ms.
199 nextMixerTime
[module
] = (uint32_t)CoGetOSTime() + period_ms
/ 2 - 1/*2ms*/;
200 DEBUG_TIMER_STOP(debugTimerMixerCalcToUsage
);
203 #define MENU_TASK_PERIOD_TICKS 25 // 50ms
205 #if defined(COLORLCD) && defined(CLI)
206 bool perMainEnabled
= true;
209 void menusTask(void * pdata
)
213 #if defined(PWR_BUTTON_PRESS)
215 uint32_t pwr_check
= pwrCheck();
216 if (pwr_check
== e_power_off
) {
219 else if (pwr_check
== e_power_press
) {
220 CoTickDelay(MENU_TASK_PERIOD_TICKS
);
224 while (pwrCheck() != e_power_off
) {
226 uint32_t start
= (uint32_t)CoGetOSTime();
227 DEBUG_TIMER_START(debugTimerPerMain
);
228 #if defined(COLORLCD) && defined(CLI)
229 if (perMainEnabled
) {
235 DEBUG_TIMER_STOP(debugTimerPerMain
);
236 // TODO remove completely massstorage from sky9x firmware
237 uint32_t runtime
= ((uint32_t)CoGetOSTime() - start
);
238 // deduct the thread run-time from the wait, if run-time was more than
239 // desired period, then skip the wait all together
240 if (runtime
< MENU_TASK_PERIOD_TICKS
) {
241 CoTickDelay(MENU_TASK_PERIOD_TICKS
- runtime
);
244 resetForcePowerOffRequest();
247 if (main_thread_running
== 0)
256 #if defined(PCBHORUS)
262 boardOff(); // Only turn power off if necessary
273 mixerTaskId
= CoCreateTask(mixerTask
, NULL
, 5, &mixerStack
.stack
[MIXER_STACK_SIZE
-1], MIXER_STACK_SIZE
);
274 menusTaskId
= CoCreateTask(menusTask
, NULL
, 10, &menusStack
.stack
[MENUS_STACK_SIZE
-1], MENUS_STACK_SIZE
);
277 // TODO move the SIMU audio in this task
278 audioTaskId
= CoCreateTask(audioTask
, NULL
, 7, &audioStack
.stack
[AUDIO_STACK_SIZE
-1], AUDIO_STACK_SIZE
);
281 audioMutex
= CoCreateMutex();
282 mixerMutex
= CoCreateMutex();