2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
27 #include "build/debug.h"
33 #include "common/color.h"
34 #include "common/utils.h"
36 #include "config/feature.h"
38 #include "drivers/accgyro/accgyro.h"
39 #include "drivers/camera_control.h"
40 #include "drivers/compass/compass.h"
41 #include "drivers/sensor.h"
42 #include "drivers/serial.h"
43 #include "drivers/serial_usb_vcp.h"
44 #include "drivers/stack_check.h"
45 #include "drivers/transponder_ir.h"
46 #include "drivers/usb_io.h"
47 #include "drivers/vtx_common.h"
49 #include "config/config.h"
52 #include "fc/dispatch.h"
53 #include "fc/rc_controls.h"
54 #include "fc/runtime_config.h"
56 #include "flight/position.h"
57 #include "flight/imu.h"
58 #include "flight/mixer.h"
59 #include "flight/pid.h"
61 #include "io/asyncfatfs/asyncfatfs.h"
62 #include "io/beeper.h"
63 #include "io/dashboard.h"
65 #include "io/ledstrip.h"
66 #include "io/piniobox.h"
67 #include "io/serial.h"
68 #include "io/transponder_ir.h"
69 #include "io/vtx_tramp.h" // Will be gone
70 #include "io/rcdevice_cam.h"
71 #include "io/usb_cdc_hid.h"
75 #include "msp/msp_serial.h"
84 #include "scheduler/scheduler.h"
86 #include "sensors/acceleration.h"
87 #include "sensors/adcinternal.h"
88 #include "sensors/barometer.h"
89 #include "sensors/battery.h"
90 #include "sensors/compass.h"
91 #include "sensors/esc_sensor.h"
92 #include "sensors/gyro.h"
93 #include "sensors/sensors.h"
94 #include "sensors/rangefinder.h"
96 #include "telemetry/telemetry.h"
97 #include "telemetry/crsf.h"
103 #ifdef USE_USB_CDC_HID
104 //TODO: Make it platform independent in the future
106 #include "vcpf4/usbd_cdc_vcp.h"
107 #include "usbd_hid_core.h"
108 #elif defined(STM32F7)
109 #include "usbd_cdc_interface.h"
110 #include "usbd_hid.h"
116 // taskUpdateRxMain() has occasional peaks in execution time so normal moving average duration estimation doesn't work
117 // Decay the estimated max task duration by 1/(1 << RX_TASK_DECAY_SHIFT) on every invocation
118 #define RX_TASK_DECAY_SHIFT 6
119 // Add a margin to the task duration estimation
120 #define RX_TASK_MARGIN 1
122 static void taskMain(timeUs_t currentTimeUs
)
124 UNUSED(currentTimeUs
);
131 static void taskHandleSerial(timeUs_t currentTimeUs
)
133 UNUSED(currentTimeUs
);
136 DEBUG_SET(DEBUG_USB
, 0, usbCableIsInserted());
137 DEBUG_SET(DEBUG_USB
, 1, usbVcpIsConnected());
141 // in cli mode, all serial stuff goes to here. enter cli mode by sending #
147 bool evaluateMspData
= ARMING_FLAG(ARMED
) ? MSP_SKIP_NON_MSP_DATA
: MSP_EVALUATE_NON_MSP_DATA
;
148 mspSerialProcess(evaluateMspData
, mspFcProcessCommand
, mspFcProcessReply
);
151 static void taskBatteryAlerts(timeUs_t currentTimeUs
)
153 if (!ARMING_FLAG(ARMED
)) {
154 // the battery *might* fall out in flight, but if that happens the FC will likely be off too unless the user has battery backup.
155 batteryUpdatePresence();
157 batteryUpdateStates(currentTimeUs
);
158 batteryUpdateAlarms();
162 static void taskUpdateAccelerometer(timeUs_t currentTimeUs
)
164 accUpdate(currentTimeUs
, &accelerometerConfigMutable()->accelerometerTrims
);
175 static rxState_e rxState
= RX_STATE_CHECK
;
177 bool taskUpdateRxMainInProgress()
179 return (rxState
!= RX_STATE_CHECK
);
182 static void taskUpdateRxMain(timeUs_t currentTimeUs
)
184 static timeDelta_t rxStateDurationFractionUs
[RX_STATE_COUNT
];
185 timeDelta_t executeTimeUs
;
186 rxState_e oldRxState
= rxState
;
187 timeDelta_t anticipatedExecutionTime
;
189 // Where we are using a state machine call schedulerIgnoreTaskExecRate() for all states bar one
190 if (rxState
!= RX_STATE_UPDATE
) {
191 schedulerIgnoreTaskExecRate();
197 if (!processRx(currentTimeUs
)) {
198 rxState
= RX_STATE_CHECK
;
201 rxState
= RX_STATE_MODES
;
205 processRxModes(currentTimeUs
);
206 rxState
= RX_STATE_UPDATE
;
209 case RX_STATE_UPDATE
:
210 // updateRcCommands sets rcCommand, which is needed by updateAltHoldState and updateSonarAltHoldState
212 updateArmingStatus();
214 #ifdef USE_USB_CDC_HID
215 if (!ARMING_FLAG(ARMED
)) {
219 rxState
= RX_STATE_CHECK
;
223 if (!schedulerGetIgnoreTaskExecTime()) {
224 executeTimeUs
= micros() - currentTimeUs
+ RX_TASK_MARGIN
;
226 // If the scheduler has reduced the anticipatedExecutionTime due to task aging, pick that up
227 anticipatedExecutionTime
= schedulerGetNextStateTime();
228 if (anticipatedExecutionTime
!= (rxStateDurationFractionUs
[oldRxState
] >> RX_TASK_DECAY_SHIFT
)) {
229 rxStateDurationFractionUs
[oldRxState
] = anticipatedExecutionTime
<< RX_TASK_DECAY_SHIFT
;
232 if (executeTimeUs
> (rxStateDurationFractionUs
[oldRxState
] >> RX_TASK_DECAY_SHIFT
)) {
233 rxStateDurationFractionUs
[oldRxState
] = executeTimeUs
<< RX_TASK_DECAY_SHIFT
;
235 // Slowly decay the max time
236 rxStateDurationFractionUs
[oldRxState
]--;
240 if (debugMode
== DEBUG_RX_STATE_TIME
) {
241 debug
[oldRxState
] = rxStateDurationFractionUs
[oldRxState
] >> RX_TASK_DECAY_SHIFT
;
244 schedulerSetNextStateTime(rxStateDurationFractionUs
[rxState
] >> RX_TASK_DECAY_SHIFT
);
249 static void taskUpdateBaro(timeUs_t currentTimeUs
)
251 UNUSED(currentTimeUs
);
253 if (sensors(SENSOR_BARO
)) {
254 const uint32_t newDeadline
= baroUpdate(currentTimeUs
);
255 if (newDeadline
!= 0) {
256 rescheduleTask(TASK_SELF
, newDeadline
);
263 static void taskUpdateMag(timeUs_t currentTimeUs
)
265 UNUSED(currentTimeUs
);
267 if (sensors(SENSOR_MAG
)) {
268 const uint32_t newDeadline
= compassUpdate(currentTimeUs
);
269 if (newDeadline
!= 0) {
270 rescheduleTask(TASK_SELF
, newDeadline
);
276 #if defined(USE_RANGEFINDER)
277 void taskUpdateRangefinder(timeUs_t currentTimeUs
)
279 UNUSED(currentTimeUs
);
281 if (!sensors(SENSOR_RANGEFINDER
)) {
287 rangefinderProcess(getCosTiltAngle());
291 #if defined(USE_BARO) || defined(USE_GPS)
292 static void taskCalculateAltitude(timeUs_t currentTimeUs
)
294 calculateEstimatedAltitude(currentTimeUs
);
296 #endif // USE_BARO || USE_GPS
299 static void taskTelemetry(timeUs_t currentTimeUs
)
301 if (!cliMode
&& featureIsEnabled(FEATURE_TELEMETRY
)) {
302 subTaskTelemetryPollSensors(currentTimeUs
);
304 telemetryProcess(currentTimeUs
);
309 #ifdef USE_CAMERA_CONTROL
310 static void taskCameraControl(uint32_t currentTime
)
312 if (ARMING_FLAG(ARMED
)) {
316 cameraControlProcess(currentTime
);
320 #define DEFINE_TASK(taskNameParam, subTaskNameParam, checkFuncParam, taskFuncParam, desiredPeriodParam, staticPriorityParam) { \
321 .taskName = taskNameParam, \
322 .subTaskName = subTaskNameParam, \
323 .checkFunc = checkFuncParam, \
324 .taskFunc = taskFuncParam, \
325 .desiredPeriodUs = desiredPeriodParam, \
326 .staticPriority = staticPriorityParam \
329 // Task info in .bss (unitialised data)
330 task_t tasks
[TASK_COUNT
];
332 // Task ID data in .data (initialised data)
333 task_attribute_t task_attributes
[TASK_COUNT
] = {
334 [TASK_SYSTEM
] = DEFINE_TASK("SYSTEM", "LOAD", NULL
, taskSystemLoad
, TASK_PERIOD_HZ(10), TASK_PRIORITY_MEDIUM_HIGH
),
335 [TASK_MAIN
] = DEFINE_TASK("SYSTEM", "UPDATE", NULL
, taskMain
, TASK_PERIOD_HZ(1000), TASK_PRIORITY_MEDIUM_HIGH
),
336 [TASK_SERIAL
] = DEFINE_TASK("SERIAL", NULL
, NULL
, taskHandleSerial
, TASK_PERIOD_HZ(100), TASK_PRIORITY_LOW
), // 100 Hz should be enough to flush up to 115 bytes @ 115200 baud
337 [TASK_BATTERY_ALERTS
] = DEFINE_TASK("BATTERY_ALERTS", NULL
, NULL
, taskBatteryAlerts
, TASK_PERIOD_HZ(5), TASK_PRIORITY_MEDIUM
),
338 [TASK_BATTERY_VOLTAGE
] = DEFINE_TASK("BATTERY_VOLTAGE", NULL
, NULL
, batteryUpdateVoltage
, TASK_PERIOD_HZ(SLOW_VOLTAGE_TASK_FREQ_HZ
), TASK_PRIORITY_MEDIUM
), // Freq may be updated in tasksInit
339 [TASK_BATTERY_CURRENT
] = DEFINE_TASK("BATTERY_CURRENT", NULL
, NULL
, batteryUpdateCurrentMeter
, TASK_PERIOD_HZ(50), TASK_PRIORITY_MEDIUM
),
341 #ifdef USE_TRANSPONDER
342 [TASK_TRANSPONDER
] = DEFINE_TASK("TRANSPONDER", NULL
, NULL
, transponderUpdate
, TASK_PERIOD_HZ(250), TASK_PRIORITY_LOW
),
345 #ifdef USE_STACK_CHECK
346 [TASK_STACK_CHECK
] = DEFINE_TASK("STACKCHECK", NULL
, NULL
, taskStackCheck
, TASK_PERIOD_HZ(10), TASK_PRIORITY_LOWEST
),
349 [TASK_GYRO
] = DEFINE_TASK("GYRO", NULL
, NULL
, taskGyroSample
, TASK_GYROPID_DESIRED_PERIOD
, TASK_PRIORITY_REALTIME
),
350 [TASK_FILTER
] = DEFINE_TASK("FILTER", NULL
, NULL
, taskFiltering
, TASK_GYROPID_DESIRED_PERIOD
, TASK_PRIORITY_REALTIME
),
351 [TASK_PID
] = DEFINE_TASK("PID", NULL
, NULL
, taskMainPidLoop
, TASK_GYROPID_DESIRED_PERIOD
, TASK_PRIORITY_REALTIME
),
353 [TASK_ACCEL
] = DEFINE_TASK("ACC", NULL
, NULL
, taskUpdateAccelerometer
, TASK_PERIOD_HZ(1000), TASK_PRIORITY_MEDIUM
),
354 [TASK_ATTITUDE
] = DEFINE_TASK("ATTITUDE", NULL
, NULL
, imuUpdateAttitude
, TASK_PERIOD_HZ(100), TASK_PRIORITY_MEDIUM
),
356 [TASK_RX
] = DEFINE_TASK("RX", NULL
, rxUpdateCheck
, taskUpdateRxMain
, TASK_PERIOD_HZ(33), TASK_PRIORITY_HIGH
), // If event-based scheduling doesn't work, fallback to periodic scheduling
357 [TASK_DISPATCH
] = DEFINE_TASK("DISPATCH", NULL
, NULL
, dispatchProcess
, TASK_PERIOD_HZ(1000), TASK_PRIORITY_HIGH
),
360 [TASK_BEEPER
] = DEFINE_TASK("BEEPER", NULL
, NULL
, beeperUpdate
, TASK_PERIOD_HZ(100), TASK_PRIORITY_LOW
),
364 [TASK_GPS
] = DEFINE_TASK("GPS", NULL
, NULL
, gpsUpdate
, TASK_PERIOD_HZ(TASK_GPS_RATE
), TASK_PRIORITY_MEDIUM
), // Required to prevent buffer overruns if running at 115200 baud (115 bytes / period < 256 bytes buffer)
368 [TASK_COMPASS
] = DEFINE_TASK("COMPASS", NULL
, NULL
, taskUpdateMag
, TASK_PERIOD_HZ(10), TASK_PRIORITY_LOW
),
372 [TASK_BARO
] = DEFINE_TASK("BARO", NULL
, NULL
, taskUpdateBaro
, TASK_PERIOD_HZ(20), TASK_PRIORITY_LOW
),
375 #if defined(USE_BARO) || defined(USE_GPS)
376 [TASK_ALTITUDE
] = DEFINE_TASK("ALTITUDE", NULL
, NULL
, taskCalculateAltitude
, TASK_PERIOD_HZ(40), TASK_PRIORITY_LOW
),
380 [TASK_DASHBOARD
] = DEFINE_TASK("DASHBOARD", NULL
, NULL
, dashboardUpdate
, TASK_PERIOD_HZ(10), TASK_PRIORITY_LOW
),
384 [TASK_OSD
] = DEFINE_TASK("OSD", NULL
, osdUpdateCheck
, osdUpdate
, TASK_PERIOD_HZ(OSD_FRAMERATE_DEFAULT_HZ
), TASK_PRIORITY_LOW
),
388 [TASK_TELEMETRY
] = DEFINE_TASK("TELEMETRY", NULL
, NULL
, taskTelemetry
, TASK_PERIOD_HZ(250), TASK_PRIORITY_LOW
),
392 [TASK_LEDSTRIP
] = DEFINE_TASK("LEDSTRIP", NULL
, NULL
, ledStripUpdate
, TASK_PERIOD_HZ(100), TASK_PRIORITY_LOW
),
396 [TASK_BST_MASTER_PROCESS
] = DEFINE_TASK("BST_MASTER_PROCESS", NULL
, NULL
, taskBstMasterProcess
, TASK_PERIOD_HZ(50), TASK_PRIORITY_LOWEST
),
399 #ifdef USE_ESC_SENSOR
400 [TASK_ESC_SENSOR
] = DEFINE_TASK("ESC_SENSOR", NULL
, NULL
, escSensorProcess
, TASK_PERIOD_HZ(100), TASK_PRIORITY_LOW
),
404 [TASK_CMS
] = DEFINE_TASK("CMS", NULL
, NULL
, cmsHandler
, TASK_PERIOD_HZ(20), TASK_PRIORITY_LOW
),
407 #ifdef USE_VTX_CONTROL
408 [TASK_VTXCTRL
] = DEFINE_TASK("VTXCTRL", NULL
, NULL
, vtxUpdate
, TASK_PERIOD_HZ(5), TASK_PRIORITY_LOWEST
),
412 [TASK_RCDEVICE
] = DEFINE_TASK("RCDEVICE", NULL
, NULL
, rcdeviceUpdate
, TASK_PERIOD_HZ(20), TASK_PRIORITY_MEDIUM
),
415 #ifdef USE_CAMERA_CONTROL
416 [TASK_CAMCTRL
] = DEFINE_TASK("CAMCTRL", NULL
, NULL
, taskCameraControl
, TASK_PERIOD_HZ(5), TASK_PRIORITY_LOW
),
419 #ifdef USE_ADC_INTERNAL
420 [TASK_ADC_INTERNAL
] = DEFINE_TASK("ADCINTERNAL", NULL
, NULL
, adcInternalProcess
, TASK_PERIOD_HZ(1), TASK_PRIORITY_LOWEST
),
424 [TASK_PINIOBOX
] = DEFINE_TASK("PINIOBOX", NULL
, NULL
, pinioBoxUpdate
, TASK_PERIOD_HZ(20), TASK_PRIORITY_LOWEST
),
427 #ifdef USE_RANGEFINDER
428 [TASK_RANGEFINDER
] = DEFINE_TASK("RANGEFINDER", NULL
, NULL
, taskUpdateRangefinder
, TASK_PERIOD_HZ(10), TASK_PRIORITY_LOWEST
),
432 [TASK_SPEED_NEGOTIATION
] = DEFINE_TASK("SPEED_NEGOTIATION", NULL
, NULL
, speedNegotiationProcess
, TASK_PERIOD_HZ(100), TASK_PRIORITY_LOW
),
436 task_t
*getTask(unsigned taskId
)
438 return &tasks
[taskId
];
441 // Has to be done before tasksInit() in order to initialize any task data which may be uninitialized at boot
442 void tasksInitData(void)
444 for (int i
= 0; i
< TASK_COUNT
; i
++) {
445 tasks
[i
].attribute
= &task_attributes
[i
];
453 setTaskEnabled(TASK_MAIN
, true);
455 setTaskEnabled(TASK_SERIAL
, true);
456 rescheduleTask(TASK_SERIAL
, TASK_PERIOD_HZ(serialConfig()->serial_update_rate_hz
));
458 const bool useBatteryVoltage
= batteryConfig()->voltageMeterSource
!= VOLTAGE_METER_NONE
;
459 setTaskEnabled(TASK_BATTERY_VOLTAGE
, useBatteryVoltage
);
461 #if defined(USE_BATTERY_VOLTAGE_SAG_COMPENSATION)
462 // If vbat motor output compensation is used, use fast vbat samplingTime
463 if (isSagCompensationConfigured()) {
464 rescheduleTask(TASK_BATTERY_VOLTAGE
, TASK_PERIOD_HZ(FAST_VOLTAGE_TASK_FREQ_HZ
));
468 const bool useBatteryCurrent
= batteryConfig()->currentMeterSource
!= CURRENT_METER_NONE
;
469 setTaskEnabled(TASK_BATTERY_CURRENT
, useBatteryCurrent
);
470 const bool useBatteryAlerts
= batteryConfig()->useVBatAlerts
|| batteryConfig()->useConsumptionAlerts
|| featureIsEnabled(FEATURE_OSD
);
471 setTaskEnabled(TASK_BATTERY_ALERTS
, (useBatteryVoltage
|| useBatteryCurrent
) && useBatteryAlerts
);
473 #ifdef USE_STACK_CHECK
474 setTaskEnabled(TASK_STACK_CHECK
, true);
477 if (sensors(SENSOR_GYRO
)) {
478 rescheduleTask(TASK_GYRO
, gyro
.sampleLooptime
);
479 rescheduleTask(TASK_FILTER
, gyro
.targetLooptime
);
480 rescheduleTask(TASK_PID
, gyro
.targetLooptime
);
481 setTaskEnabled(TASK_GYRO
, true);
482 setTaskEnabled(TASK_FILTER
, true);
483 setTaskEnabled(TASK_PID
, true);
484 schedulerEnableGyro();
488 if (sensors(SENSOR_ACC
) && acc
.sampleRateHz
) {
489 setTaskEnabled(TASK_ACCEL
, true);
490 rescheduleTask(TASK_ACCEL
, TASK_PERIOD_HZ(acc
.sampleRateHz
));
491 setTaskEnabled(TASK_ATTITUDE
, true);
495 #ifdef USE_RANGEFINDER
496 if (sensors(SENSOR_RANGEFINDER
)) {
497 setTaskEnabled(TASK_RANGEFINDER
, featureIsEnabled(FEATURE_RANGEFINDER
));
501 setTaskEnabled(TASK_RX
, true);
503 setTaskEnabled(TASK_DISPATCH
, dispatchIsEnabled());
506 setTaskEnabled(TASK_BEEPER
, true);
510 setTaskEnabled(TASK_GPS
, featureIsEnabled(FEATURE_GPS
));
514 setTaskEnabled(TASK_COMPASS
, sensors(SENSOR_MAG
));
518 setTaskEnabled(TASK_BARO
, sensors(SENSOR_BARO
));
521 #if defined(USE_BARO) || defined(USE_GPS)
522 setTaskEnabled(TASK_ALTITUDE
, sensors(SENSOR_BARO
) || featureIsEnabled(FEATURE_GPS
));
526 setTaskEnabled(TASK_DASHBOARD
, featureIsEnabled(FEATURE_DASHBOARD
));
530 if (featureIsEnabled(FEATURE_TELEMETRY
)) {
531 setTaskEnabled(TASK_TELEMETRY
, true);
532 if (rxRuntimeState
.serialrxProvider
== SERIALRX_JETIEXBUS
) {
533 // Reschedule telemetry to 500hz for Jeti Exbus
534 rescheduleTask(TASK_TELEMETRY
, TASK_PERIOD_HZ(500));
535 } else if (rxRuntimeState
.serialrxProvider
== SERIALRX_CRSF
) {
536 // Reschedule telemetry to 500hz, 2ms for CRSF
537 rescheduleTask(TASK_TELEMETRY
, TASK_PERIOD_HZ(500));
543 setTaskEnabled(TASK_LEDSTRIP
, featureIsEnabled(FEATURE_LED_STRIP
));
546 #ifdef USE_TRANSPONDER
547 setTaskEnabled(TASK_TRANSPONDER
, featureIsEnabled(FEATURE_TRANSPONDER
));
551 rescheduleTask(TASK_OSD
, TASK_PERIOD_HZ(osdConfig()->framerate_hz
));
552 setTaskEnabled(TASK_OSD
, featureIsEnabled(FEATURE_OSD
) && osdGetDisplayPort(NULL
));
556 setTaskEnabled(TASK_BST_MASTER_PROCESS
, true);
559 #ifdef USE_ESC_SENSOR
560 setTaskEnabled(TASK_ESC_SENSOR
, featureIsEnabled(FEATURE_ESC_SENSOR
));
563 #ifdef USE_ADC_INTERNAL
564 setTaskEnabled(TASK_ADC_INTERNAL
, true);
568 pinioBoxTaskControl();
572 #ifdef USE_MSP_DISPLAYPORT
573 setTaskEnabled(TASK_CMS
, true);
575 setTaskEnabled(TASK_CMS
, featureIsEnabled(FEATURE_OSD
) || featureIsEnabled(FEATURE_DASHBOARD
));
579 #ifdef USE_VTX_CONTROL
580 #if defined(USE_VTX_RTC6705) || defined(USE_VTX_SMARTAUDIO) || defined(USE_VTX_TRAMP)
581 setTaskEnabled(TASK_VTXCTRL
, true);
585 #ifdef USE_CAMERA_CONTROL
586 setTaskEnabled(TASK_CAMCTRL
, true);
590 setTaskEnabled(TASK_RCDEVICE
, rcdeviceIsEnabled());
594 const bool useCRSF
= rxRuntimeState
.serialrxProvider
== SERIALRX_CRSF
;
595 setTaskEnabled(TASK_SPEED_NEGOTIATION
, useCRSF
);