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/>.
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"
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"
60 #include "io/ledstrip.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"
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"
86 void taskBstMasterProcess(timeUs_t currentTimeUs
);
89 #define TASK_PERIOD_HZ(hz) (1000000 / (hz))
90 #define TASK_PERIOD_MS(ms) ((ms) * 1000)
91 #define TASK_PERIOD_US(us) (us)
94 static void taskUpdateAccelerometer(timeUs_t currentTimeUs
)
96 UNUSED(currentTimeUs
);
98 accUpdate(&accelerometerConfigMutable()->accelerometerTrims
);
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
);
113 // in cli mode, all serial stuff goes to here. enter cli mode by sending #
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
);
141 #if !defined(BARO) && !defined(SONAR)
142 // updateRcCommands sets rcCommand, which is needed by updateAltHoldState and updateSonarAltHoldState
148 if (sensors(SENSOR_BARO
)) {
149 updateAltHoldState();
154 if (sensors(SENSOR_SONAR
)) {
155 updateSonarAltHoldState();
162 static void taskUpdateCompass(timeUs_t currentTimeUs
)
164 if (sensors(SENSOR_MAG
)) {
165 compassUpdate(currentTimeUs
, &compassConfigMutable()->magZero
);
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
);
184 #if defined(BARO) || defined(SONAR)
185 static void taskCalculateAltitude(timeUs_t currentTimeUs
)
189 || (sensors(SENSOR_BARO
) && isBaroReady())
192 || sensors(SENSOR_SONAR
)
195 calculateEstimatedAltitude(currentTimeUs
);
200 static void taskTelemetry(timeUs_t currentTimeUs
)
202 telemetryCheckState();
204 if (!cliMode
&& feature(FEATURE_TELEMETRY
)) {
205 telemetryProcess(currentTimeUs
);
211 // Everything that listens to VTX devices
212 void taskVtxControl(uint32_t currentTime
)
214 if (ARMING_FLAG(ARMED
))
218 vtxCommonProcess(currentTime
);
224 void osdSlaveTasksInit(void)
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
);
238 setTaskEnabled(TASK_TRANSPONDER
, feature(FEATURE_TRANSPONDER
));
241 setTaskEnabled(TASK_OSD_SLAVE
, true);
244 setTaskEnabled(TASK_STACK_CHECK
, true);
249 #ifndef USE_OSD_SLAVE
250 void fcTasksInit(void)
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());
278 setTaskEnabled(TASK_BEEPER
, true);
281 setTaskEnabled(TASK_GPS
, feature(FEATURE_GPS
));
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));
291 setTaskEnabled(TASK_BARO
, sensors(SENSOR_BARO
));
294 setTaskEnabled(TASK_SONAR
, sensors(SENSOR_SONAR
));
296 #if defined(BARO) || defined(SONAR)
297 setTaskEnabled(TASK_ALTITUDE
, sensors(SENSOR_BARO
) || sensors(SENSOR_SONAR
));
300 setTaskEnabled(TASK_DASHBOARD
, feature(FEATURE_DASHBOARD
));
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));
315 setTaskEnabled(TASK_LEDSTRIP
, feature(FEATURE_LED_STRIP
));
318 setTaskEnabled(TASK_TRANSPONDER
, feature(FEATURE_TRANSPONDER
));
321 setTaskEnabled(TASK_OSD
, feature(FEATURE_OSD
));
324 setTaskEnabled(TASK_OSD_SLAVE
, true);
327 setTaskEnabled(TASK_BST_MASTER_PROCESS
, true);
329 #ifdef USE_ESC_SENSOR
330 setTaskEnabled(TASK_ESC_SENSOR
, feature(FEATURE_ESC_SENSOR
));
333 #ifdef USE_MSP_DISPLAYPORT
334 setTaskEnabled(TASK_CMS
, true);
336 setTaskEnabled(TASK_CMS
, feature(FEATURE_OSD
) || feature(FEATURE_DASHBOARD
));
340 setTaskEnabled(TASK_STACK_CHECK
, true);
343 #if defined(VTX_SMARTAUDIO) || defined(VTX_TRAMP)
344 setTaskEnabled(TASK_VTXCTRL
, true);
347 #ifdef USE_GYRO_DATA_ANALYSE
348 setTaskEnabled(TASK_GYRO_DATA_ANALYSE
, true);
353 cfTask_t cfTasks
[TASK_COUNT
] = {
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
364 .subTaskName
= "GYRO",
365 .taskFunc
= taskMainPidLoop
,
366 .desiredPeriod
= TASK_GYROPID_DESIRED_PERIOD
,
367 .staticPriority
= TASK_PRIORITY_REALTIME
,
372 .taskFunc
= taskUpdateAccelerometer
,
373 .desiredPeriod
= TASK_PERIOD_HZ(1000), // 1000Hz, every 1ms
374 .staticPriority
= TASK_PRIORITY_MEDIUM
,
378 .taskName
= "ATTITUDE",
379 .taskFunc
= imuUpdateAttitude
,
380 .desiredPeriod
= TASK_PERIOD_HZ(100),
381 .staticPriority
= TASK_PRIORITY_MEDIUM
,
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
,
394 .taskName
= "SERIAL",
395 .taskFunc
= taskHandleSerial
,
397 .checkFunc
= taskSerialCheck
,
398 .desiredPeriod
= TASK_PERIOD_HZ(100),
399 .staticPriority
= TASK_PRIORITY_REALTIME
,
401 .desiredPeriod
= TASK_PERIOD_HZ(100), // 100 Hz should be enough to flush up to 115 bytes @ 115200 baud
402 .staticPriority
= TASK_PRIORITY_LOW
,
406 #ifndef USE_OSD_SLAVE
408 .taskName
= "DISPATCH",
409 .taskFunc
= dispatchProcess
,
410 .desiredPeriod
= TASK_PERIOD_HZ(1000),
411 .staticPriority
= TASK_PRIORITY_HIGH
,
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
438 .taskName
= "BEEPER",
439 .taskFunc
= beeperUpdate
,
440 .desiredPeriod
= TASK_PERIOD_HZ(100), // 100 Hz
441 .staticPriority
= TASK_PRIORITY_LOW
,
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
,
456 .taskName
= "COMPASS",
457 .taskFunc
= taskUpdateCompass
,
458 .desiredPeriod
= TASK_PERIOD_HZ(10), // Compass is updated at 10 Hz
459 .staticPriority
= TASK_PRIORITY_LOW
,
466 .taskFunc
= taskUpdateBaro
,
467 .desiredPeriod
= TASK_PERIOD_HZ(20),
468 .staticPriority
= TASK_PRIORITY_LOW
,
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
,
481 #if defined(BARO) || defined(SONAR)
483 .taskName
= "ALTITUDE",
484 .taskFunc
= taskCalculateAltitude
,
485 .desiredPeriod
= TASK_PERIOD_HZ(40),
486 .staticPriority
= TASK_PRIORITY_LOW
,
492 [TASK_TRANSPONDER
] = {
493 .taskName
= "TRANSPONDER",
494 .taskFunc
= transponderUpdate
,
495 .desiredPeriod
= TASK_PERIOD_HZ(250), // 250 Hz, 4ms
496 .staticPriority
= TASK_PRIORITY_LOW
,
500 #ifndef USE_OSD_SLAVE
503 .taskName
= "DASHBOARD",
504 .taskFunc
= dashboardUpdate
,
505 .desiredPeriod
= TASK_PERIOD_HZ(10),
506 .staticPriority
= TASK_PRIORITY_LOW
,
512 .taskFunc
= osdUpdate
,
513 .desiredPeriod
= TASK_PERIOD_HZ(60), // 60 Hz
514 .staticPriority
= TASK_PRIORITY_LOW
,
521 .taskName
= "OSD_SLAVE",
522 .checkFunc
= osdSlaveCheck
,
523 .taskFunc
= osdSlaveUpdate
,
524 .desiredPeriod
= TASK_PERIOD_HZ(60), // 60 Hz
525 .staticPriority
= TASK_PRIORITY_HIGH
,
529 #ifndef USE_OSD_SLAVE
532 .taskName
= "TELEMETRY",
533 .taskFunc
= taskTelemetry
,
534 .desiredPeriod
= TASK_PERIOD_HZ(250), // 250 Hz, 4ms
535 .staticPriority
= TASK_PRIORITY_LOW
,
541 .taskName
= "LEDSTRIP",
542 .taskFunc
= ledStripUpdate
,
543 .desiredPeriod
= TASK_PERIOD_HZ(100), // 100 Hz, 10ms
544 .staticPriority
= TASK_PRIORITY_LOW
,
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
,
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
,
569 .taskFunc
= cmsHandler
,
570 .desiredPeriod
= TASK_PERIOD_HZ(60), // 60 Hz
571 .staticPriority
= TASK_PRIORITY_LOW
,
576 [TASK_STACK_CHECK
] = {
577 .taskName
= "STACKCHECK",
578 .taskFunc
= taskStackCheck
,
579 .desiredPeriod
= TASK_PERIOD_HZ(10), // 10 Hz
580 .staticPriority
= TASK_PRIORITY_IDLE
,
586 .taskName
= "VTXCTRL",
587 .taskFunc
= taskVtxControl
,
588 .desiredPeriod
= TASK_PERIOD_HZ(5), // 5 Hz, 200ms
589 .staticPriority
= TASK_PRIORITY_IDLE
,
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
,