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
);
176 static rxState_e rxState
= RX_STATE_CHECK
;
178 bool taskUpdateRxMainInProgress()
180 return (rxState
!= RX_STATE_CHECK
);
183 static void taskUpdateRxMain(timeUs_t currentTimeUs
)
185 static timeDelta_t rxStateDurationFracUs
[RX_STATE_COUNT
];
186 timeDelta_t executeTimeUs
;
187 rxState_e oldRxState
= rxState
;
188 timeDelta_t anticipatedExecutionTime
;
190 // Where we are using a state machine call schedulerIgnoreTaskExecRate() for all states bar one
191 if (rxState
!= RX_STATE_UPDATE
) {
192 schedulerIgnoreTaskExecRate();
198 rxState
= RX_STATE_PROCESS
;
201 case RX_STATE_PROCESS
:
202 if (!processRx(currentTimeUs
)) {
203 rxState
= RX_STATE_CHECK
;
206 rxState
= RX_STATE_MODES
;
210 processRxModes(currentTimeUs
);
211 rxState
= RX_STATE_UPDATE
;
214 case RX_STATE_UPDATE
:
215 // updateRcCommands sets rcCommand, which is needed by updateAltHoldState and updateSonarAltHoldState
217 updateArmingStatus();
219 #ifdef USE_USB_CDC_HID
220 if (!ARMING_FLAG(ARMED
)) {
224 rxState
= RX_STATE_CHECK
;
228 if (!schedulerGetIgnoreTaskExecTime()) {
229 executeTimeUs
= micros() - currentTimeUs
+ RX_TASK_MARGIN
;
231 // If the scheduler has reduced the anticipatedExecutionTime due to task aging, pick that up
232 anticipatedExecutionTime
= schedulerGetNextStateTime();
233 if (anticipatedExecutionTime
!= (rxStateDurationFracUs
[oldRxState
] >> RX_TASK_DECAY_SHIFT
)) {
234 rxStateDurationFracUs
[oldRxState
] = anticipatedExecutionTime
<< RX_TASK_DECAY_SHIFT
;
237 if (executeTimeUs
> (rxStateDurationFracUs
[oldRxState
] >> RX_TASK_DECAY_SHIFT
)) {
238 rxStateDurationFracUs
[oldRxState
] = executeTimeUs
<< RX_TASK_DECAY_SHIFT
;
240 // Slowly decay the max time
241 rxStateDurationFracUs
[oldRxState
]--;
245 if (debugMode
== DEBUG_RX_STATE_TIME
) {
246 debug
[oldRxState
] = rxStateDurationFracUs
[oldRxState
] >> RX_TASK_DECAY_SHIFT
;
249 schedulerSetNextStateTime(rxStateDurationFracUs
[rxState
] >> RX_TASK_DECAY_SHIFT
);
254 static void taskUpdateBaro(timeUs_t currentTimeUs
)
256 UNUSED(currentTimeUs
);
258 if (sensors(SENSOR_BARO
)) {
259 const uint32_t newDeadline
= baroUpdate(currentTimeUs
);
260 if (newDeadline
!= 0) {
261 rescheduleTask(TASK_SELF
, newDeadline
);
267 #if defined(USE_RANGEFINDER)
268 void taskUpdateRangefinder(timeUs_t currentTimeUs
)
270 UNUSED(currentTimeUs
);
272 if (!sensors(SENSOR_RANGEFINDER
)) {
278 rangefinderProcess(getCosTiltAngle());
282 #if defined(USE_BARO) || defined(USE_GPS)
283 static void taskCalculateAltitude(timeUs_t currentTimeUs
)
285 calculateEstimatedAltitude(currentTimeUs
);
287 #endif // USE_BARO || USE_GPS
290 static void taskTelemetry(timeUs_t currentTimeUs
)
292 if (!cliMode
&& featureIsEnabled(FEATURE_TELEMETRY
)) {
293 subTaskTelemetryPollSensors(currentTimeUs
);
295 telemetryProcess(currentTimeUs
);
300 #ifdef USE_CAMERA_CONTROL
301 static void taskCameraControl(uint32_t currentTime
)
303 if (ARMING_FLAG(ARMED
)) {
307 cameraControlProcess(currentTime
);
311 #define DEFINE_TASK(taskNameParam, subTaskNameParam, checkFuncParam, taskFuncParam, desiredPeriodParam, staticPriorityParam) { \
312 .taskName = taskNameParam, \
313 .subTaskName = subTaskNameParam, \
314 .checkFunc = checkFuncParam, \
315 .taskFunc = taskFuncParam, \
316 .desiredPeriodUs = desiredPeriodParam, \
317 .staticPriority = staticPriorityParam \
320 // Task info in .bss (unitialised data)
321 task_t tasks
[TASK_COUNT
];
323 // Task ID data in .data (initialised data)
324 task_attribute_t task_attributes
[TASK_COUNT
] = {
325 [TASK_SYSTEM
] = DEFINE_TASK("SYSTEM", "LOAD", NULL
, taskSystemLoad
, TASK_PERIOD_HZ(10), TASK_PRIORITY_MEDIUM_HIGH
),
326 [TASK_MAIN
] = DEFINE_TASK("SYSTEM", "UPDATE", NULL
, taskMain
, TASK_PERIOD_HZ(1000), TASK_PRIORITY_MEDIUM_HIGH
),
327 [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
328 [TASK_BATTERY_ALERTS
] = DEFINE_TASK("BATTERY_ALERTS", NULL
, NULL
, taskBatteryAlerts
, TASK_PERIOD_HZ(5), TASK_PRIORITY_MEDIUM
),
329 [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
330 [TASK_BATTERY_CURRENT
] = DEFINE_TASK("BATTERY_CURRENT", NULL
, NULL
, batteryUpdateCurrentMeter
, TASK_PERIOD_HZ(50), TASK_PRIORITY_MEDIUM
),
332 #ifdef USE_TRANSPONDER
333 [TASK_TRANSPONDER
] = DEFINE_TASK("TRANSPONDER", NULL
, NULL
, transponderUpdate
, TASK_PERIOD_HZ(250), TASK_PRIORITY_LOW
),
336 #ifdef USE_STACK_CHECK
337 [TASK_STACK_CHECK
] = DEFINE_TASK("STACKCHECK", NULL
, NULL
, taskStackCheck
, TASK_PERIOD_HZ(10), TASK_PRIORITY_LOWEST
),
340 [TASK_GYRO
] = DEFINE_TASK("GYRO", NULL
, NULL
, taskGyroSample
, TASK_GYROPID_DESIRED_PERIOD
, TASK_PRIORITY_REALTIME
),
341 [TASK_FILTER
] = DEFINE_TASK("FILTER", NULL
, NULL
, taskFiltering
, TASK_GYROPID_DESIRED_PERIOD
, TASK_PRIORITY_REALTIME
),
342 [TASK_PID
] = DEFINE_TASK("PID", NULL
, NULL
, taskMainPidLoop
, TASK_GYROPID_DESIRED_PERIOD
, TASK_PRIORITY_REALTIME
),
344 [TASK_ACCEL
] = DEFINE_TASK("ACC", NULL
, NULL
, taskUpdateAccelerometer
, TASK_PERIOD_HZ(1000), TASK_PRIORITY_MEDIUM
),
345 [TASK_ATTITUDE
] = DEFINE_TASK("ATTITUDE", NULL
, NULL
, imuUpdateAttitude
, TASK_PERIOD_HZ(100), TASK_PRIORITY_MEDIUM
),
347 [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
348 [TASK_DISPATCH
] = DEFINE_TASK("DISPATCH", NULL
, NULL
, dispatchProcess
, TASK_PERIOD_HZ(1000), TASK_PRIORITY_HIGH
),
351 [TASK_BEEPER
] = DEFINE_TASK("BEEPER", NULL
, NULL
, beeperUpdate
, TASK_PERIOD_HZ(100), TASK_PRIORITY_LOW
),
355 [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)
359 [TASK_COMPASS
] = DEFINE_TASK("COMPASS", NULL
, NULL
, compassUpdate
,TASK_PERIOD_HZ(10), TASK_PRIORITY_LOW
),
363 [TASK_BARO
] = DEFINE_TASK("BARO", NULL
, NULL
, taskUpdateBaro
, TASK_PERIOD_HZ(20), TASK_PRIORITY_LOW
),
366 #if defined(USE_BARO) || defined(USE_GPS)
367 [TASK_ALTITUDE
] = DEFINE_TASK("ALTITUDE", NULL
, NULL
, taskCalculateAltitude
, TASK_PERIOD_HZ(40), TASK_PRIORITY_LOW
),
371 [TASK_DASHBOARD
] = DEFINE_TASK("DASHBOARD", NULL
, NULL
, dashboardUpdate
, TASK_PERIOD_HZ(10), TASK_PRIORITY_LOW
),
375 [TASK_OSD
] = DEFINE_TASK("OSD", NULL
, osdUpdateCheck
, osdUpdate
, TASK_PERIOD_HZ(OSD_FRAMERATE_DEFAULT_HZ
), TASK_PRIORITY_LOW
),
379 [TASK_TELEMETRY
] = DEFINE_TASK("TELEMETRY", NULL
, NULL
, taskTelemetry
, TASK_PERIOD_HZ(250), TASK_PRIORITY_LOW
),
383 [TASK_LEDSTRIP
] = DEFINE_TASK("LEDSTRIP", NULL
, NULL
, ledStripUpdate
, TASK_PERIOD_HZ(100), TASK_PRIORITY_LOW
),
387 [TASK_BST_MASTER_PROCESS
] = DEFINE_TASK("BST_MASTER_PROCESS", NULL
, NULL
, taskBstMasterProcess
, TASK_PERIOD_HZ(50), TASK_PRIORITY_LOWEST
),
390 #ifdef USE_ESC_SENSOR
391 [TASK_ESC_SENSOR
] = DEFINE_TASK("ESC_SENSOR", NULL
, NULL
, escSensorProcess
, TASK_PERIOD_HZ(100), TASK_PRIORITY_LOW
),
395 [TASK_CMS
] = DEFINE_TASK("CMS", NULL
, NULL
, cmsHandler
, TASK_PERIOD_HZ(20), TASK_PRIORITY_LOW
),
398 #ifdef USE_VTX_CONTROL
399 [TASK_VTXCTRL
] = DEFINE_TASK("VTXCTRL", NULL
, NULL
, vtxUpdate
, TASK_PERIOD_HZ(5), TASK_PRIORITY_LOWEST
),
403 [TASK_RCDEVICE
] = DEFINE_TASK("RCDEVICE", NULL
, NULL
, rcdeviceUpdate
, TASK_PERIOD_HZ(20), TASK_PRIORITY_MEDIUM
),
406 #ifdef USE_CAMERA_CONTROL
407 [TASK_CAMCTRL
] = DEFINE_TASK("CAMCTRL", NULL
, NULL
, taskCameraControl
, TASK_PERIOD_HZ(5), TASK_PRIORITY_LOW
),
410 #ifdef USE_ADC_INTERNAL
411 [TASK_ADC_INTERNAL
] = DEFINE_TASK("ADCINTERNAL", NULL
, NULL
, adcInternalProcess
, TASK_PERIOD_HZ(1), TASK_PRIORITY_LOWEST
),
415 [TASK_PINIOBOX
] = DEFINE_TASK("PINIOBOX", NULL
, NULL
, pinioBoxUpdate
, TASK_PERIOD_HZ(20), TASK_PRIORITY_LOWEST
),
418 #ifdef USE_RANGEFINDER
419 [TASK_RANGEFINDER
] = DEFINE_TASK("RANGEFINDER", NULL
, NULL
, taskUpdateRangefinder
, TASK_PERIOD_HZ(10), TASK_PRIORITY_LOWEST
),
423 [TASK_SPEED_NEGOTIATION
] = DEFINE_TASK("SPEED_NEGOTIATION", NULL
, NULL
, speedNegotiationProcess
, TASK_PERIOD_HZ(100), TASK_PRIORITY_LOWEST
),
427 task_t
*getTask(unsigned taskId
)
429 return &tasks
[taskId
];
434 for (int i
= 0; i
< TASK_COUNT
; i
++) {
435 tasks
[i
].attribute
= &task_attributes
[i
];
440 setTaskEnabled(TASK_MAIN
, true);
442 setTaskEnabled(TASK_SERIAL
, true);
443 rescheduleTask(TASK_SERIAL
, TASK_PERIOD_HZ(serialConfig()->serial_update_rate_hz
));
445 const bool useBatteryVoltage
= batteryConfig()->voltageMeterSource
!= VOLTAGE_METER_NONE
;
446 setTaskEnabled(TASK_BATTERY_VOLTAGE
, useBatteryVoltage
);
448 #if defined(USE_BATTERY_VOLTAGE_SAG_COMPENSATION)
449 // If vbat motor output compensation is used, use fast vbat samplingTime
450 if (isSagCompensationConfigured()) {
451 rescheduleTask(TASK_BATTERY_VOLTAGE
, TASK_PERIOD_HZ(FAST_VOLTAGE_TASK_FREQ_HZ
));
455 const bool useBatteryCurrent
= batteryConfig()->currentMeterSource
!= CURRENT_METER_NONE
;
456 setTaskEnabled(TASK_BATTERY_CURRENT
, useBatteryCurrent
);
457 const bool useBatteryAlerts
= batteryConfig()->useVBatAlerts
|| batteryConfig()->useConsumptionAlerts
|| featureIsEnabled(FEATURE_OSD
);
458 setTaskEnabled(TASK_BATTERY_ALERTS
, (useBatteryVoltage
|| useBatteryCurrent
) && useBatteryAlerts
);
460 #ifdef USE_STACK_CHECK
461 setTaskEnabled(TASK_STACK_CHECK
, true);
464 if (sensors(SENSOR_GYRO
)) {
465 rescheduleTask(TASK_GYRO
, gyro
.sampleLooptime
);
466 rescheduleTask(TASK_FILTER
, gyro
.targetLooptime
);
467 rescheduleTask(TASK_PID
, gyro
.targetLooptime
);
468 setTaskEnabled(TASK_GYRO
, true);
469 setTaskEnabled(TASK_FILTER
, true);
470 setTaskEnabled(TASK_PID
, true);
471 schedulerEnableGyro();
475 if (sensors(SENSOR_ACC
) && acc
.sampleRateHz
) {
476 setTaskEnabled(TASK_ACCEL
, true);
477 rescheduleTask(TASK_ACCEL
, TASK_PERIOD_HZ(acc
.sampleRateHz
));
478 setTaskEnabled(TASK_ATTITUDE
, true);
482 #ifdef USE_RANGEFINDER
483 if (sensors(SENSOR_RANGEFINDER
)) {
484 setTaskEnabled(TASK_RANGEFINDER
, featureIsEnabled(FEATURE_RANGEFINDER
));
488 setTaskEnabled(TASK_RX
, true);
490 setTaskEnabled(TASK_DISPATCH
, dispatchIsEnabled());
493 setTaskEnabled(TASK_BEEPER
, true);
497 setTaskEnabled(TASK_GPS
, featureIsEnabled(FEATURE_GPS
));
501 setTaskEnabled(TASK_COMPASS
, sensors(SENSOR_MAG
));
505 setTaskEnabled(TASK_BARO
, sensors(SENSOR_BARO
));
508 #if defined(USE_BARO) || defined(USE_GPS)
509 setTaskEnabled(TASK_ALTITUDE
, sensors(SENSOR_BARO
) || featureIsEnabled(FEATURE_GPS
));
513 setTaskEnabled(TASK_DASHBOARD
, featureIsEnabled(FEATURE_DASHBOARD
));
517 if (featureIsEnabled(FEATURE_TELEMETRY
)) {
518 setTaskEnabled(TASK_TELEMETRY
, true);
519 if (rxRuntimeState
.serialrxProvider
== SERIALRX_JETIEXBUS
) {
520 // Reschedule telemetry to 500hz for Jeti Exbus
521 rescheduleTask(TASK_TELEMETRY
, TASK_PERIOD_HZ(500));
522 } else if (rxRuntimeState
.serialrxProvider
== SERIALRX_CRSF
) {
523 // Reschedule telemetry to 500hz, 2ms for CRSF
524 rescheduleTask(TASK_TELEMETRY
, TASK_PERIOD_HZ(500));
530 setTaskEnabled(TASK_LEDSTRIP
, featureIsEnabled(FEATURE_LED_STRIP
));
533 #ifdef USE_TRANSPONDER
534 setTaskEnabled(TASK_TRANSPONDER
, featureIsEnabled(FEATURE_TRANSPONDER
));
538 rescheduleTask(TASK_OSD
, TASK_PERIOD_HZ(osdConfig()->framerate_hz
));
539 setTaskEnabled(TASK_OSD
, featureIsEnabled(FEATURE_OSD
) && osdGetDisplayPort(NULL
));
543 setTaskEnabled(TASK_BST_MASTER_PROCESS
, true);
546 #ifdef USE_ESC_SENSOR
547 setTaskEnabled(TASK_ESC_SENSOR
, featureIsEnabled(FEATURE_ESC_SENSOR
));
550 #ifdef USE_ADC_INTERNAL
551 setTaskEnabled(TASK_ADC_INTERNAL
, true);
555 pinioBoxTaskControl();
559 #ifdef USE_MSP_DISPLAYPORT
560 setTaskEnabled(TASK_CMS
, true);
562 setTaskEnabled(TASK_CMS
, featureIsEnabled(FEATURE_OSD
) || featureIsEnabled(FEATURE_DASHBOARD
));
566 #ifdef USE_VTX_CONTROL
567 #if defined(USE_VTX_RTC6705) || defined(USE_VTX_SMARTAUDIO) || defined(USE_VTX_TRAMP)
568 setTaskEnabled(TASK_VTXCTRL
, true);
572 #ifdef USE_CAMERA_CONTROL
573 setTaskEnabled(TASK_CAMCTRL
, true);
577 setTaskEnabled(TASK_RCDEVICE
, rcdeviceIsEnabled());
581 const bool useCRSF
= rxRuntimeState
.serialrxProvider
== SERIALRX_CRSF
;
582 setTaskEnabled(TASK_SPEED_NEGOTIATION
, useCRSF
);