Merge branch 'master' of ../betaflight into betaflight-master
[betaflight.git] / src / main / fc / fc_tasks.c
blobf566f1262a6d3cc471e1dcb1a8c8a815a23aad47
1 /*
2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
18 #include <stdbool.h>
19 #include <stdlib.h>
20 #include <stdint.h>
22 #include <platform.h>
24 #include "cms/cms.h"
26 #include "common/axis.h"
27 #include "common/color.h"
28 #include "common/utils.h"
29 #include "common/filter.h"
31 #include "config/feature.h"
32 #include "config/parameter_group.h"
33 #include "config/parameter_group_ids.h"
35 #include "drivers/sensor.h"
36 #include "drivers/accgyro.h"
37 #include "drivers/compass.h"
38 #include "drivers/serial.h"
39 #include "drivers/stack_check.h"
40 #include "drivers/vtx_common.h"
41 #include "drivers/transponder_ir.h"
43 #include "fc/config.h"
44 #include "fc/fc_msp.h"
45 #include "fc/fc_tasks.h"
46 #include "fc/fc_core.h"
47 #include "fc/rc_controls.h"
48 #include "fc/runtime_config.h"
49 #include "fc/cli.h"
50 #include "fc/fc_dispatch.h"
52 #include "flight/altitude.h"
53 #include "flight/imu.h"
54 #include "flight/mixer.h"
55 #include "flight/pid.h"
57 #include "io/beeper.h"
58 #include "io/dashboard.h"
59 #include "io/gps.h"
60 #include "io/ledstrip.h"
61 #include "io/osd.h"
62 #include "io/osd_slave.h"
63 #include "io/serial.h"
64 #include "io/transponder_ir.h"
65 #include "io/vtx_tramp.h" // Will be gone
67 #include "msp/msp_serial.h"
69 #include "rx/rx.h"
71 #include "sensors/sensors.h"
72 #include "sensors/acceleration.h"
73 #include "sensors/barometer.h"
74 #include "sensors/battery.h"
75 #include "sensors/compass.h"
76 #include "sensors/gyro.h"
77 #include "sensors/gyroanalyse.h"
78 #include "sensors/sonar.h"
79 #include "sensors/esc_sensor.h"
81 #include "scheduler/scheduler.h"
83 #include "telemetry/telemetry.h"
85 #ifdef USE_BST
86 void taskBstMasterProcess(timeUs_t currentTimeUs);
87 #endif
89 #define TASK_PERIOD_HZ(hz) (1000000 / (hz))
90 #define TASK_PERIOD_MS(ms) ((ms) * 1000)
91 #define TASK_PERIOD_US(us) (us)
93 #ifndef USE_OSD_SLAVE
94 static void taskUpdateAccelerometer(timeUs_t currentTimeUs)
96 UNUSED(currentTimeUs);
98 accUpdate(&accelerometerConfigMutable()->accelerometerTrims);
100 #endif
102 bool taskSerialCheck(timeUs_t currentTimeUs, timeDelta_t currentDeltaTimeUs) {
103 UNUSED(currentTimeUs);
104 UNUSED(currentDeltaTimeUs);
106 return mspSerialWaiting();
109 static void taskHandleSerial(timeUs_t currentTimeUs)
111 UNUSED(currentTimeUs);
112 #ifdef USE_CLI
113 // in cli mode, all serial stuff goes to here. enter cli mode by sending #
114 if (cliMode) {
115 cliProcess();
116 return;
118 #endif
119 mspSerialProcess(ARMING_FLAG(ARMED) ? MSP_SKIP_NON_MSP_DATA : MSP_EVALUATE_NON_MSP_DATA, mspFcProcessCommand, mspFcProcessReply);
122 void taskBatteryAlerts(timeUs_t currentTimeUs)
124 UNUSED(currentTimeUs);
126 if (!ARMING_FLAG(ARMED)) {
127 // the battery *might* fall out in flight, but if that happens the FC will likely be off too unless the user has battery backup.
128 batteryUpdatePresence();
130 batteryUpdateStates();
132 batteryUpdateAlarms();
135 #ifndef USE_OSD_SLAVE
136 static void taskUpdateRxMain(timeUs_t currentTimeUs)
138 processRx(currentTimeUs);
139 isRXDataNew = true;
141 #if !defined(BARO) && !defined(SONAR)
142 // updateRcCommands sets rcCommand, which is needed by updateAltHoldState and updateSonarAltHoldState
143 updateRcCommands();
144 #endif
145 updateLEDs();
147 #ifdef BARO
148 if (sensors(SENSOR_BARO)) {
149 updateAltHoldState();
151 #endif
153 #ifdef SONAR
154 if (sensors(SENSOR_SONAR)) {
155 updateSonarAltHoldState();
157 #endif
159 #endif
161 #ifdef MAG
162 static void taskUpdateCompass(timeUs_t currentTimeUs)
164 if (sensors(SENSOR_MAG)) {
165 compassUpdate(currentTimeUs, &compassConfigMutable()->magZero);
168 #endif
170 #ifdef BARO
171 static void taskUpdateBaro(timeUs_t currentTimeUs)
173 UNUSED(currentTimeUs);
175 if (sensors(SENSOR_BARO)) {
176 const uint32_t newDeadline = baroUpdate();
177 if (newDeadline != 0) {
178 rescheduleTask(TASK_SELF, newDeadline);
182 #endif
184 #if defined(BARO) || defined(SONAR)
185 static void taskCalculateAltitude(timeUs_t currentTimeUs)
187 if (false
188 #if defined(BARO)
189 || (sensors(SENSOR_BARO) && isBaroReady())
190 #endif
191 #if defined(SONAR)
192 || sensors(SENSOR_SONAR)
193 #endif
195 calculateEstimatedAltitude(currentTimeUs);
197 #endif
199 #ifdef TELEMETRY
200 static void taskTelemetry(timeUs_t currentTimeUs)
202 telemetryCheckState();
204 if (!cliMode && feature(FEATURE_TELEMETRY)) {
205 telemetryProcess(currentTimeUs);
208 #endif
210 #ifdef VTX_CONTROL
211 // Everything that listens to VTX devices
212 void taskVtxControl(uint32_t currentTime)
214 if (ARMING_FLAG(ARMED))
215 return;
217 #ifdef VTX_COMMON
218 vtxCommonProcess(currentTime);
219 #endif
221 #endif
223 #ifdef USE_OSD_SLAVE
224 void osdSlaveTasksInit(void)
226 schedulerInit();
227 setTaskEnabled(TASK_SERIAL, true);
229 bool useBatteryVoltage = batteryConfig()->voltageMeterSource != VOLTAGE_METER_NONE;
230 setTaskEnabled(TASK_BATTERY_VOLTAGE, useBatteryVoltage);
231 bool useBatteryCurrent = batteryConfig()->currentMeterSource != CURRENT_METER_NONE;
232 setTaskEnabled(TASK_BATTERY_CURRENT, useBatteryCurrent);
234 bool useBatteryAlerts = (batteryConfig()->useVBatAlerts || batteryConfig()->useConsumptionAlerts);
235 setTaskEnabled(TASK_BATTERY_ALERTS, (useBatteryVoltage || useBatteryCurrent) && useBatteryAlerts);
237 #ifdef TRANSPONDER
238 setTaskEnabled(TASK_TRANSPONDER, feature(FEATURE_TRANSPONDER));
239 #endif
241 setTaskEnabled(TASK_OSD_SLAVE, true);
243 #ifdef STACK_CHECK
244 setTaskEnabled(TASK_STACK_CHECK, true);
245 #endif
247 #endif
249 #ifndef USE_OSD_SLAVE
250 void fcTasksInit(void)
252 schedulerInit();
253 rescheduleTask(TASK_GYROPID, gyro.targetLooptime);
254 setTaskEnabled(TASK_GYROPID, true);
256 if (sensors(SENSOR_ACC)) {
257 setTaskEnabled(TASK_ACCEL, true);
258 rescheduleTask(TASK_ACCEL, acc.accSamplingInterval);
261 setTaskEnabled(TASK_ATTITUDE, sensors(SENSOR_ACC));
262 setTaskEnabled(TASK_SERIAL, true);
263 rescheduleTask(TASK_SERIAL, TASK_PERIOD_HZ(serialConfig()->serial_update_rate_hz));
265 bool useBatteryVoltage = batteryConfig()->voltageMeterSource != VOLTAGE_METER_NONE;
266 setTaskEnabled(TASK_BATTERY_VOLTAGE, useBatteryVoltage);
267 bool useBatteryCurrent = batteryConfig()->currentMeterSource != CURRENT_METER_NONE;
268 setTaskEnabled(TASK_BATTERY_CURRENT, useBatteryCurrent);
270 bool useBatteryAlerts = batteryConfig()->useVBatAlerts || batteryConfig()->useConsumptionAlerts || feature(FEATURE_OSD);
271 setTaskEnabled(TASK_BATTERY_ALERTS, (useBatteryVoltage || useBatteryCurrent) && useBatteryAlerts);
273 setTaskEnabled(TASK_RX, true);
275 setTaskEnabled(TASK_DISPATCH, dispatchIsEnabled());
277 #ifdef BEEPER
278 setTaskEnabled(TASK_BEEPER, true);
279 #endif
280 #ifdef GPS
281 setTaskEnabled(TASK_GPS, feature(FEATURE_GPS));
282 #endif
283 #ifdef MAG
284 setTaskEnabled(TASK_COMPASS, sensors(SENSOR_MAG));
285 #if defined(USE_SPI) && defined(USE_MAG_AK8963)
286 // fixme temporary solution for AK6983 via slave I2C on MPU9250
287 rescheduleTask(TASK_COMPASS, TASK_PERIOD_HZ(40));
288 #endif
289 #endif
290 #ifdef BARO
291 setTaskEnabled(TASK_BARO, sensors(SENSOR_BARO));
292 #endif
293 #ifdef SONAR
294 setTaskEnabled(TASK_SONAR, sensors(SENSOR_SONAR));
295 #endif
296 #if defined(BARO) || defined(SONAR)
297 setTaskEnabled(TASK_ALTITUDE, sensors(SENSOR_BARO) || sensors(SENSOR_SONAR));
298 #endif
299 #ifdef USE_DASHBOARD
300 setTaskEnabled(TASK_DASHBOARD, feature(FEATURE_DASHBOARD));
301 #endif
302 #ifdef TELEMETRY
303 setTaskEnabled(TASK_TELEMETRY, feature(FEATURE_TELEMETRY));
304 if (feature(FEATURE_TELEMETRY)) {
305 if (rxConfig()->serialrx_provider == SERIALRX_JETIEXBUS) {
306 // Reschedule telemetry to 500hz for Jeti Exbus
307 rescheduleTask(TASK_TELEMETRY, TASK_PERIOD_HZ(500));
308 } else if (rxConfig()->serialrx_provider == SERIALRX_CRSF) {
309 // Reschedule telemetry to 500hz, 2ms for CRSF
310 rescheduleTask(TASK_TELEMETRY, TASK_PERIOD_HZ(500));
313 #endif
314 #ifdef LED_STRIP
315 setTaskEnabled(TASK_LEDSTRIP, feature(FEATURE_LED_STRIP));
316 #endif
317 #ifdef TRANSPONDER
318 setTaskEnabled(TASK_TRANSPONDER, feature(FEATURE_TRANSPONDER));
319 #endif
320 #ifdef OSD
321 setTaskEnabled(TASK_OSD, feature(FEATURE_OSD));
322 #endif
323 #ifdef USE_OSD_SLAVE
324 setTaskEnabled(TASK_OSD_SLAVE, true);
325 #endif
326 #ifdef USE_BST
327 setTaskEnabled(TASK_BST_MASTER_PROCESS, true);
328 #endif
329 #ifdef USE_ESC_SENSOR
330 setTaskEnabled(TASK_ESC_SENSOR, feature(FEATURE_ESC_SENSOR));
331 #endif
332 #ifdef CMS
333 #ifdef USE_MSP_DISPLAYPORT
334 setTaskEnabled(TASK_CMS, true);
335 #else
336 setTaskEnabled(TASK_CMS, feature(FEATURE_OSD) || feature(FEATURE_DASHBOARD));
337 #endif
338 #endif
339 #ifdef STACK_CHECK
340 setTaskEnabled(TASK_STACK_CHECK, true);
341 #endif
342 #ifdef VTX_CONTROL
343 #if defined(VTX_SMARTAUDIO) || defined(VTX_TRAMP)
344 setTaskEnabled(TASK_VTXCTRL, true);
345 #endif
346 #endif
347 #ifdef USE_GYRO_DATA_ANALYSE
348 setTaskEnabled(TASK_GYRO_DATA_ANALYSE, true);
349 #endif
351 #endif
353 cfTask_t cfTasks[TASK_COUNT] = {
354 [TASK_SYSTEM] = {
355 .taskName = "SYSTEM",
356 .taskFunc = taskSystem,
357 .desiredPeriod = TASK_PERIOD_HZ(10), // 10Hz, every 100 ms
358 .staticPriority = TASK_PRIORITY_MEDIUM_HIGH,
361 #ifndef USE_OSD_SLAVE
362 [TASK_GYROPID] = {
363 .taskName = "PID",
364 .subTaskName = "GYRO",
365 .taskFunc = taskMainPidLoop,
366 .desiredPeriod = TASK_GYROPID_DESIRED_PERIOD,
367 .staticPriority = TASK_PRIORITY_REALTIME,
370 [TASK_ACCEL] = {
371 .taskName = "ACCEL",
372 .taskFunc = taskUpdateAccelerometer,
373 .desiredPeriod = TASK_PERIOD_HZ(1000), // 1000Hz, every 1ms
374 .staticPriority = TASK_PRIORITY_MEDIUM,
377 [TASK_ATTITUDE] = {
378 .taskName = "ATTITUDE",
379 .taskFunc = imuUpdateAttitude,
380 .desiredPeriod = TASK_PERIOD_HZ(100),
381 .staticPriority = TASK_PRIORITY_MEDIUM,
384 [TASK_RX] = {
385 .taskName = "RX",
386 .checkFunc = rxUpdateCheck,
387 .taskFunc = taskUpdateRxMain,
388 .desiredPeriod = TASK_PERIOD_HZ(50), // If event-based scheduling doesn't work, fallback to periodic scheduling
389 .staticPriority = TASK_PRIORITY_HIGH,
391 #endif
393 [TASK_SERIAL] = {
394 .taskName = "SERIAL",
395 .taskFunc = taskHandleSerial,
396 #ifdef USE_OSD_SLAVE
397 .checkFunc = taskSerialCheck,
398 .desiredPeriod = TASK_PERIOD_HZ(100),
399 .staticPriority = TASK_PRIORITY_REALTIME,
400 #else
401 .desiredPeriod = TASK_PERIOD_HZ(100), // 100 Hz should be enough to flush up to 115 bytes @ 115200 baud
402 .staticPriority = TASK_PRIORITY_LOW,
403 #endif
406 #ifndef USE_OSD_SLAVE
407 [TASK_DISPATCH] = {
408 .taskName = "DISPATCH",
409 .taskFunc = dispatchProcess,
410 .desiredPeriod = TASK_PERIOD_HZ(1000),
411 .staticPriority = TASK_PRIORITY_HIGH,
413 #endif
415 [TASK_BATTERY_ALERTS] = {
416 .taskName = "BATTERY_ALERTS",
417 .taskFunc = taskBatteryAlerts,
418 .desiredPeriod = TASK_PERIOD_HZ(5), // 5 Hz
419 .staticPriority = TASK_PRIORITY_MEDIUM,
422 [TASK_BATTERY_VOLTAGE] = {
423 .taskName = "BATTERY_VOLTAGE",
424 .taskFunc = batteryUpdateVoltage,
425 .desiredPeriod = TASK_PERIOD_HZ(50),
426 .staticPriority = TASK_PRIORITY_MEDIUM,
428 [TASK_BATTERY_CURRENT] = {
429 .taskName = "BATTERY_CURRENT",
430 .taskFunc = batteryUpdateCurrentMeter,
431 .desiredPeriod = TASK_PERIOD_HZ(50),
432 .staticPriority = TASK_PRIORITY_MEDIUM,
434 #ifndef USE_OSD_SLAVE
436 #ifdef BEEPER
437 [TASK_BEEPER] = {
438 .taskName = "BEEPER",
439 .taskFunc = beeperUpdate,
440 .desiredPeriod = TASK_PERIOD_HZ(100), // 100 Hz
441 .staticPriority = TASK_PRIORITY_LOW,
443 #endif
445 #ifdef GPS
446 [TASK_GPS] = {
447 .taskName = "GPS",
448 .taskFunc = gpsUpdate,
449 .desiredPeriod = TASK_PERIOD_HZ(100), // Required to prevent buffer overruns if running at 115200 baud (115 bytes / period < 256 bytes buffer)
450 .staticPriority = TASK_PRIORITY_MEDIUM,
452 #endif
454 #ifdef MAG
455 [TASK_COMPASS] = {
456 .taskName = "COMPASS",
457 .taskFunc = taskUpdateCompass,
458 .desiredPeriod = TASK_PERIOD_HZ(10), // Compass is updated at 10 Hz
459 .staticPriority = TASK_PRIORITY_LOW,
461 #endif
463 #ifdef BARO
464 [TASK_BARO] = {
465 .taskName = "BARO",
466 .taskFunc = taskUpdateBaro,
467 .desiredPeriod = TASK_PERIOD_HZ(20),
468 .staticPriority = TASK_PRIORITY_LOW,
470 #endif
472 #ifdef SONAR
473 [TASK_SONAR] = {
474 .taskName = "SONAR",
475 .taskFunc = sonarUpdate,
476 .desiredPeriod = TASK_PERIOD_MS(70), // 70ms required so that SONAR pulses do not interfere with each other
477 .staticPriority = TASK_PRIORITY_LOW,
479 #endif
481 #if defined(BARO) || defined(SONAR)
482 [TASK_ALTITUDE] = {
483 .taskName = "ALTITUDE",
484 .taskFunc = taskCalculateAltitude,
485 .desiredPeriod = TASK_PERIOD_HZ(40),
486 .staticPriority = TASK_PRIORITY_LOW,
488 #endif
489 #endif
491 #ifdef TRANSPONDER
492 [TASK_TRANSPONDER] = {
493 .taskName = "TRANSPONDER",
494 .taskFunc = transponderUpdate,
495 .desiredPeriod = TASK_PERIOD_HZ(250), // 250 Hz, 4ms
496 .staticPriority = TASK_PRIORITY_LOW,
498 #endif
500 #ifndef USE_OSD_SLAVE
501 #ifdef USE_DASHBOARD
502 [TASK_DASHBOARD] = {
503 .taskName = "DASHBOARD",
504 .taskFunc = dashboardUpdate,
505 .desiredPeriod = TASK_PERIOD_HZ(10),
506 .staticPriority = TASK_PRIORITY_LOW,
508 #endif
509 #ifdef OSD
510 [TASK_OSD] = {
511 .taskName = "OSD",
512 .taskFunc = osdUpdate,
513 .desiredPeriod = TASK_PERIOD_HZ(60), // 60 Hz
514 .staticPriority = TASK_PRIORITY_LOW,
516 #endif
517 #endif
519 #ifdef USE_OSD_SLAVE
520 [TASK_OSD_SLAVE] = {
521 .taskName = "OSD_SLAVE",
522 .checkFunc = osdSlaveCheck,
523 .taskFunc = osdSlaveUpdate,
524 .desiredPeriod = TASK_PERIOD_HZ(60), // 60 Hz
525 .staticPriority = TASK_PRIORITY_HIGH,
527 #endif
529 #ifndef USE_OSD_SLAVE
530 #ifdef TELEMETRY
531 [TASK_TELEMETRY] = {
532 .taskName = "TELEMETRY",
533 .taskFunc = taskTelemetry,
534 .desiredPeriod = TASK_PERIOD_HZ(250), // 250 Hz, 4ms
535 .staticPriority = TASK_PRIORITY_LOW,
537 #endif
539 #ifdef LED_STRIP
540 [TASK_LEDSTRIP] = {
541 .taskName = "LEDSTRIP",
542 .taskFunc = ledStripUpdate,
543 .desiredPeriod = TASK_PERIOD_HZ(100), // 100 Hz, 10ms
544 .staticPriority = TASK_PRIORITY_LOW,
546 #endif
548 #ifdef USE_BST
549 [TASK_BST_MASTER_PROCESS] = {
550 .taskName = "BST_MASTER_PROCESS",
551 .taskFunc = taskBstMasterProcess,
552 .desiredPeriod = TASK_PERIOD_HZ(50), // 50 Hz, 20ms
553 .staticPriority = TASK_PRIORITY_IDLE,
555 #endif
557 #ifdef USE_ESC_SENSOR
558 [TASK_ESC_SENSOR] = {
559 .taskName = "ESC_SENSOR",
560 .taskFunc = escSensorProcess,
561 .desiredPeriod = TASK_PERIOD_HZ(100), // 100 Hz, 10ms
562 .staticPriority = TASK_PRIORITY_LOW,
564 #endif
566 #ifdef CMS
567 [TASK_CMS] = {
568 .taskName = "CMS",
569 .taskFunc = cmsHandler,
570 .desiredPeriod = TASK_PERIOD_HZ(60), // 60 Hz
571 .staticPriority = TASK_PRIORITY_LOW,
573 #endif
575 #ifdef STACK_CHECK
576 [TASK_STACK_CHECK] = {
577 .taskName = "STACKCHECK",
578 .taskFunc = taskStackCheck,
579 .desiredPeriod = TASK_PERIOD_HZ(10), // 10 Hz
580 .staticPriority = TASK_PRIORITY_IDLE,
582 #endif
584 #ifdef VTX_CONTROL
585 [TASK_VTXCTRL] = {
586 .taskName = "VTXCTRL",
587 .taskFunc = taskVtxControl,
588 .desiredPeriod = TASK_PERIOD_HZ(5), // 5 Hz, 200ms
589 .staticPriority = TASK_PRIORITY_IDLE,
591 #endif
593 #ifdef USE_GYRO_DATA_ANALYSE
594 [TASK_GYRO_DATA_ANALYSE] = {
595 .taskName = "GYROFFT",
596 .taskFunc = gyroDataAnalyseUpdate,
597 .desiredPeriod = TASK_PERIOD_HZ(100), // 100 Hz, 10ms
598 .staticPriority = TASK_PRIORITY_MEDIUM,
600 #endif
601 #endif