OP-1900 added deceleration check to autotakeoff failsafe
[librepilot.git] / flight / modules / System / systemmod.c
blob9c6324e03477bc6fc1398bc8bd60dea4c28e259f
1 /**
2 ******************************************************************************
3 * @addtogroup OpenPilotModules OpenPilot Modules
4 * @brief The OpenPilot Modules do the majority of the control in OpenPilot. The
5 * @ref SystemModule "System Module" starts all the other modules that then take care
6 * of all the telemetry and control algorithms and such. This is done through the @ref PIOS
7 * "PIOS Hardware abstraction layer" which then contains hardware specific implementations
8 * (currently only STM32 supported)
10 * @{
11 * @addtogroup SystemModule System Module
12 * @brief Initializes PIOS and other modules runs monitoring
13 * After initializing all the modules (currently selected by Makefile but in
14 * future controlled by configuration on SD card) runs basic monitoring and
15 * alarms.
16 * @{
18 * @file systemmod.c
19 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
20 * @brief System module
22 * @see The GNU Public License (GPL) Version 3
24 *****************************************************************************/
26 * This program is free software; you can redistribute it and/or modify
27 * it under the terms of the GNU General Public License as published by
28 * the Free Software Foundation; either version 3 of the License, or
29 * (at your option) any later version.
31 * This program is distributed in the hope that it will be useful, but
32 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
33 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
34 * for more details.
36 * You should have received a copy of the GNU General Public License along
37 * with this program; if not, write to the Free Software Foundation, Inc.,
38 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
41 #include <openpilot.h>
42 // private includes
43 #include "inc/systemmod.h"
45 #include <notification.h>
46 #ifdef PIOS_INCLUDE_WS2811
47 #include <lednotification.h>
48 #endif
50 // UAVOs
51 #include <objectpersistence.h>
52 #include <flightstatus.h>
53 #include <systemstats.h>
54 #include <systemsettings.h>
55 #include <i2cstats.h>
56 #include <taskinfo.h>
57 #include <watchdogstatus.h>
58 #include <callbackinfo.h>
59 #include <hwsettings.h>
60 #include <pios_flashfs.h>
61 #include <pios_notify.h>
63 #ifdef PIOS_INCLUDE_INSTRUMENTATION
64 #include <instrumentation.h>
65 #include <pios_instrumentation.h>
66 #endif
68 #if defined(PIOS_INCLUDE_RFM22B)
69 #include <oplinkstatus.h>
70 #endif
72 // Flight Libraries
73 #include <sanitycheck.h>
76 // #define DEBUG_THIS_FILE
78 #if defined(PIOS_INCLUDE_DEBUG_CONSOLE) && defined(DEBUG_THIS_FILE)
79 #define DEBUG_MSG(format, ...) PIOS_COM_SendFormattedString(PIOS_COM_DEBUG, format,##__VA_ARGS__)
80 #else
81 #define DEBUG_MSG(format, ...)
82 #endif
84 // Private constants
85 #define SYSTEM_UPDATE_PERIOD_MS 250
87 #if defined(PIOS_SYSTEM_STACK_SIZE)
88 #define STACK_SIZE_BYTES PIOS_SYSTEM_STACK_SIZE
89 #else
90 #define STACK_SIZE_BYTES 1024
91 #endif
93 #define TASK_PRIORITY (tskIDLE_PRIORITY + 1)
95 // Private types
97 // Private variables
98 static xTaskHandle systemTaskHandle;
99 static xQueueHandle objectPersistenceQueue;
100 static enum { STACKOVERFLOW_NONE = 0, STACKOVERFLOW_WARNING = 1, STACKOVERFLOW_CRITICAL = 3 } stackOverflow;
101 static bool mallocFailed;
102 static HwSettingsData bootHwSettings;
103 static FrameType_t bootFrameType;
105 volatile int initTaskDone = 0;
107 // Private functions
108 static void objectUpdatedCb(UAVObjEvent *ev);
109 static void checkSettingsUpdatedCb(UAVObjEvent *ev);
110 #ifdef DIAG_TASKS
111 static void taskMonitorForEachCallback(uint16_t task_id, const struct pios_task_info *task_info, void *context);
112 static void callbackSchedulerForEachCallback(int16_t callback_id, const struct pios_callback_info *callback_info, void *context);
113 #endif
114 static void updateStats();
115 static void updateSystemAlarms();
116 static void systemTask(void *parameters);
117 #ifdef DIAG_I2C_WDG_STATS
118 static void updateI2Cstats();
119 static void updateWDGstats();
120 #endif
122 extern uintptr_t pios_uavo_settings_fs_id;
123 extern uintptr_t pios_user_fs_id;
126 * Create the module task.
127 * \returns 0 on success or -1 if initialization failed
129 int32_t SystemModStart(void)
131 // Initialize vars
132 stackOverflow = STACKOVERFLOW_NONE;
133 mallocFailed = false;
134 // Create system task
135 xTaskCreate(systemTask, "System", STACK_SIZE_BYTES / 4, NULL, TASK_PRIORITY, &systemTaskHandle);
136 // Register task
137 PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_SYSTEM, systemTaskHandle);
139 return 0;
143 * Initialize the module, called on startup.
144 * \returns 0 on success or -1 if initialization failed
146 int32_t SystemModInitialize(void)
148 // Must registers objects here for system thread because ObjectManager started in OpenPilotInit
149 SystemSettingsInitialize();
150 SystemStatsInitialize();
151 FlightStatusInitialize();
152 ObjectPersistenceInitialize();
153 #ifdef DIAG_TASKS
154 TaskInfoInitialize();
155 CallbackInfoInitialize();
156 #endif
157 #ifdef DIAG_I2C_WDG_STATS
158 I2CStatsInitialize();
159 WatchdogStatusInitialize();
160 #endif
162 #ifdef PIOS_INCLUDE_INSTRUMENTATION
163 InstrumentationInit();
164 #endif
166 objectPersistenceQueue = xQueueCreate(1, sizeof(UAVObjEvent));
167 if (objectPersistenceQueue == NULL) {
168 return -1;
171 SystemModStart();
173 return 0;
176 MODULE_INITCALL(SystemModInitialize, 0);
178 * System task, periodically executes every SYSTEM_UPDATE_PERIOD_MS
180 static void systemTask(__attribute__((unused)) void *parameters)
182 while (!initTaskDone) {
183 vTaskDelay(10);
186 /* create all modules thread */
187 MODULE_TASKCREATE_ALL;
189 /* start the delayed callback scheduler */
190 PIOS_CALLBACKSCHEDULER_Start();
192 if (mallocFailed) {
193 /* We failed to malloc during task creation,
194 * system behaviour is undefined. Reset and let
195 * the BootFault code recover for us.
197 PIOS_SYS_Reset();
199 #if defined(PIOS_INCLUDE_IAP)
200 /* Record a successful boot */
201 PIOS_IAP_WriteBootCount(0);
202 #endif
203 // Listen for SettingPersistance object updates, connect a callback function
204 ObjectPersistenceConnectQueue(objectPersistenceQueue);
206 // Load a copy of HwSetting active at boot time
207 HwSettingsGet(&bootHwSettings);
208 bootFrameType = GetCurrentFrameType();
209 // Whenever the configuration changes, make sure it is safe to fly
210 HwSettingsConnectCallback(checkSettingsUpdatedCb);
211 SystemSettingsConnectCallback(checkSettingsUpdatedCb);
213 #ifdef DIAG_TASKS
214 TaskInfoData taskInfoData;
215 CallbackInfoData callbackInfoData;
216 #endif
217 // Main system loop
218 while (1) {
219 NotificationUpdateStatus();
220 // Update the system statistics
221 updateStats();
222 // Update the system alarms
223 updateSystemAlarms();
224 #ifdef DIAG_I2C_WDG_STATS
225 updateI2Cstats();
226 updateWDGstats();
227 #endif
229 #ifdef PIOS_INCLUDE_INSTRUMENTATION
230 InstrumentationPublishAllCounters();
231 #endif
233 #ifdef DIAG_TASKS
234 // Update the task status object
235 PIOS_TASK_MONITOR_ForEachTask(taskMonitorForEachCallback, &taskInfoData);
236 TaskInfoSet(&taskInfoData);
237 // Update the callback status object
238 // if(FALSE){
239 PIOS_CALLBACKSCHEDULER_ForEachCallback(callbackSchedulerForEachCallback, &callbackInfoData);
240 CallbackInfoSet(&callbackInfoData);
241 // }
242 #endif
243 // }
246 UAVObjEvent ev;
247 int delayTime = SYSTEM_UPDATE_PERIOD_MS;
249 #if defined(PIOS_INCLUDE_RFM22B)
251 // Update the OPLinkStatus UAVO
252 OPLinkStatusData oplinkStatus;
253 OPLinkStatusGet(&oplinkStatus);
255 if (pios_rfm22b_id) {
256 // Get the other device stats.
257 PIOS_RFM2B_GetPairStats(pios_rfm22b_id, oplinkStatus.PairIDs, oplinkStatus.PairSignalStrengths, OPLINKSTATUS_PAIRIDS_NUMELEM);
259 // Get the stats from the radio device
260 struct rfm22b_stats radio_stats;
261 PIOS_RFM22B_GetStats(pios_rfm22b_id, &radio_stats);
263 // Update the OPLInk status
264 static bool first_time = true;
265 static uint16_t prev_tx_count = 0;
266 static uint16_t prev_rx_count = 0;
267 oplinkStatus.HeapRemaining = xPortGetFreeHeapSize();
268 oplinkStatus.DeviceID = PIOS_RFM22B_DeviceID(pios_rfm22b_id);
269 oplinkStatus.RxGood = radio_stats.rx_good;
270 oplinkStatus.RxCorrected = radio_stats.rx_corrected;
271 oplinkStatus.RxErrors = radio_stats.rx_error;
272 oplinkStatus.RxMissed = radio_stats.rx_missed;
273 oplinkStatus.RxFailure = radio_stats.rx_failure;
274 oplinkStatus.TxDropped = radio_stats.tx_dropped;
275 oplinkStatus.TxFailure = radio_stats.tx_failure;
276 oplinkStatus.Resets = radio_stats.resets;
277 oplinkStatus.Timeouts = radio_stats.timeouts;
278 oplinkStatus.RSSI = radio_stats.rssi;
279 oplinkStatus.LinkQuality = radio_stats.link_quality;
280 if (first_time) {
281 first_time = false;
282 } else {
283 uint16_t tx_count = radio_stats.tx_byte_count;
284 uint16_t rx_count = radio_stats.rx_byte_count;
285 uint16_t tx_bytes = (tx_count < prev_tx_count) ? (0xffff - prev_tx_count + tx_count) : (tx_count - prev_tx_count);
286 uint16_t rx_bytes = (rx_count < prev_rx_count) ? (0xffff - prev_rx_count + rx_count) : (rx_count - prev_rx_count);
287 oplinkStatus.TXRate = (uint16_t)((float)(tx_bytes * 1000) / SYSTEM_UPDATE_PERIOD_MS);
288 oplinkStatus.RXRate = (uint16_t)((float)(rx_bytes * 1000) / SYSTEM_UPDATE_PERIOD_MS);
289 prev_tx_count = tx_count;
290 prev_rx_count = rx_count;
292 oplinkStatus.TXSeq = radio_stats.tx_seq;
293 oplinkStatus.RXSeq = radio_stats.rx_seq;
295 oplinkStatus.LinkState = radio_stats.link_state;
296 } else {
297 oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED;
299 OPLinkStatusSet(&oplinkStatus);
301 #endif /* if defined(PIOS_INCLUDE_RFM22B) */
303 if (xQueueReceive(objectPersistenceQueue, &ev, delayTime) == pdTRUE) {
304 // If object persistence is updated call the callback
305 objectUpdatedCb(&ev);
311 * Function called in response to object updates
313 static void objectUpdatedCb(UAVObjEvent *ev)
315 ObjectPersistenceData objper;
316 UAVObjHandle obj;
318 // If the object updated was the ObjectPersistence execute requested action
319 if (ev->obj == ObjectPersistenceHandle()) {
320 // Get object data
321 ObjectPersistenceGet(&objper);
323 int retval = 1;
324 FlightStatusData flightStatus;
325 FlightStatusGet(&flightStatus);
327 // When this is called because of this method don't do anything
328 if (objper.Operation == OBJECTPERSISTENCE_OPERATION_ERROR || objper.Operation == OBJECTPERSISTENCE_OPERATION_COMPLETED) {
329 return;
332 // Execute action if disarmed
333 if (flightStatus.Armed != FLIGHTSTATUS_ARMED_DISARMED) {
334 retval = -1;
335 } else if (objper.Operation == OBJECTPERSISTENCE_OPERATION_LOAD) {
336 if (objper.Selection == OBJECTPERSISTENCE_SELECTION_SINGLEOBJECT) {
337 // Get selected object
338 obj = UAVObjGetByID(objper.ObjectID);
339 if (obj == 0) {
340 return;
342 // Load selected instance
343 retval = UAVObjLoad(obj, objper.InstanceID);
344 } else if (objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLSETTINGS || objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLOBJECTS) {
345 retval = UAVObjLoadSettings();
346 } else if (objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLMETAOBJECTS || objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLOBJECTS) {
347 retval = UAVObjLoadMetaobjects();
349 } else if (objper.Operation == OBJECTPERSISTENCE_OPERATION_SAVE) {
350 if (objper.Selection == OBJECTPERSISTENCE_SELECTION_SINGLEOBJECT) {
351 // Get selected object
352 obj = UAVObjGetByID(objper.ObjectID);
353 if (obj == 0) {
354 return;
356 // Save selected instance
357 retval = UAVObjSave(obj, objper.InstanceID);
359 // Not sure why this is needed
360 vTaskDelay(10);
362 // Verify saving worked
363 if (retval == 0) {
364 retval = UAVObjLoad(obj, objper.InstanceID);
366 } else if (objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLSETTINGS || objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLOBJECTS) {
367 retval = UAVObjSaveSettings();
368 } else if (objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLMETAOBJECTS || objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLOBJECTS) {
369 retval = UAVObjSaveMetaobjects();
371 } else if (objper.Operation == OBJECTPERSISTENCE_OPERATION_DELETE) {
372 if (objper.Selection == OBJECTPERSISTENCE_SELECTION_SINGLEOBJECT) {
373 // Get selected object
374 obj = UAVObjGetByID(objper.ObjectID);
375 if (obj == 0) {
376 return;
378 // Delete selected instance
379 retval = UAVObjDelete(obj, objper.InstanceID);
380 } else if (objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLSETTINGS || objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLOBJECTS) {
381 retval = UAVObjDeleteSettings();
382 } else if (objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLMETAOBJECTS || objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLOBJECTS) {
383 retval = UAVObjDeleteMetaobjects();
385 } else if (objper.Operation == OBJECTPERSISTENCE_OPERATION_FULLERASE) {
386 #if defined(PIOS_INCLUDE_FLASH_LOGFS_SETTINGS)
387 retval = PIOS_FLASHFS_Format(0);
388 #else
389 retval = -1;
390 #endif
392 switch (retval) {
393 case 0:
394 objper.Operation = OBJECTPERSISTENCE_OPERATION_COMPLETED;
395 ObjectPersistenceSet(&objper);
396 break;
397 case -1:
398 objper.Operation = OBJECTPERSISTENCE_OPERATION_ERROR;
399 ObjectPersistenceSet(&objper);
400 break;
401 default:
402 break;
408 * Called whenever hardware settings changed
410 static void checkSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev)
412 HwSettingsData currentHwSettings;
414 HwSettingsGet(&currentHwSettings);
415 FrameType_t currentFrameType = GetCurrentFrameType();
416 // check whether the Hw Configuration has changed from the one used at boot time
417 if ((memcmp(&bootHwSettings, &currentHwSettings, sizeof(HwSettingsData)) != 0) ||
418 (currentFrameType != bootFrameType)) {
419 ExtendedAlarmsSet(SYSTEMALARMS_ALARM_BOOTFAULT, SYSTEMALARMS_ALARM_CRITICAL, SYSTEMALARMS_EXTENDEDALARMSTATUS_REBOOTREQUIRED, 0);
423 #ifdef DIAG_TASKS
424 static void taskMonitorForEachCallback(uint16_t task_id, const struct pios_task_info *task_info, void *context)
426 TaskInfoData *taskData = (TaskInfoData *)context;
428 // By convention, there is a direct mapping between task monitor task_id's and members
429 // of the TaskInfoXXXXElem enums
430 PIOS_DEBUG_Assert(task_id < TASKINFO_RUNNING_NUMELEM);
431 TaskInfoRunningToArray(taskData->Running)[task_id] = task_info->is_running ? TASKINFO_RUNNING_TRUE : TASKINFO_RUNNING_FALSE;
432 ((uint16_t *)&taskData->StackRemaining)[task_id] = task_info->stack_remaining;
433 ((uint8_t *)&taskData->RunningTime)[task_id] = task_info->running_time_percentage;
436 static void callbackSchedulerForEachCallback(int16_t callback_id, const struct pios_callback_info *callback_info, void *context)
438 CallbackInfoData *callbackData = (CallbackInfoData *)context;
440 if (callback_id < 0) {
441 return;
443 // delayed callback scheduler reports callback stack overflows as remaininng: -1
444 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32)
445 if (callback_info->stack_remaining < 0 && stackOverflow == STACKOVERFLOW_NONE) {
446 stackOverflow = STACKOVERFLOW_WARNING;
448 #endif
449 // By convention, there is a direct mapping between (not negative) callback scheduler callback_id's and members
450 // of the CallbackInfoXXXXElem enums
451 PIOS_DEBUG_Assert(callback_id < CALLBACKINFO_RUNNING_NUMELEM);
452 ((uint8_t *)&callbackData->Running)[callback_id] = callback_info->is_running;
453 ((uint32_t *)&callbackData->RunningTime)[callback_id] = callback_info->running_time_count;
454 ((int16_t *)&callbackData->StackRemaining)[callback_id] = callback_info->stack_remaining;
456 #endif /* ifdef DIAG_TASKS */
459 * Called periodically to update the I2C statistics
461 #ifdef DIAG_I2C_WDG_STATS
462 static void updateI2Cstats()
464 #if defined(PIOS_INCLUDE_I2C)
465 I2CStatsData i2cStats;
466 I2CStatsGet(&i2cStats);
468 struct pios_i2c_fault_history history;
469 PIOS_I2C_GetDiagnostics(&history, &i2cStats.event_errors);
471 for (uint8_t i = 0; (i < I2C_LOG_DEPTH) && (i < I2CSTATS_EVENT_LOG_NUMELEM); i++) {
472 i2cStats.evirq_log[i] = history.evirq[i];
473 i2cStats.erirq_log[i] = history.erirq[i];
474 i2cStats.event_log[i] = history.event[i];
475 i2cStats.state_log[i] = history.state[i];
477 i2cStats.last_error_type = history.type;
478 I2CStatsSet(&i2cStats);
479 #endif
482 static void updateWDGstats()
484 WatchdogStatusData watchdogStatus;
486 watchdogStatus.BootupFlags = PIOS_WDG_GetBootupFlags();
487 watchdogStatus.ActiveFlags = PIOS_WDG_GetActiveFlags();
488 WatchdogStatusSet(&watchdogStatus);
490 #endif /* ifdef DIAG_I2C_WDG_STATS */
493 * Called periodically to update the system stats
495 static uint16_t GetFreeIrqStackSize(void)
497 uint32_t i = 0x200;
499 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK)
500 extern uint32_t _irq_stack_top;
501 extern uint32_t _irq_stack_end;
502 uint32_t pattern = 0x0000A5A5;
503 uint32_t *ptr = &_irq_stack_end;
505 #if 1 /* the ugly way accurate but takes more time, useful for debugging */
506 uint32_t stack_size = (((uint32_t)&_irq_stack_top - (uint32_t)&_irq_stack_end) & ~3) / 4;
508 for (i = 0; i < stack_size; i++) {
509 if (ptr[i] != pattern) {
510 i = i * 4;
511 break;
514 #else /* faster way but not accurate */
515 if (*(volatile uint32_t *)((uint32_t)ptr + IRQSTACK_LIMIT_CRITICAL) != pattern) {
516 i = IRQSTACK_LIMIT_CRITICAL - 1;
517 } else if (*(volatile uint32_t *)((uint32_t)ptr + IRQSTACK_LIMIT_WARNING) != pattern) {
518 i = IRQSTACK_LIMIT_WARNING - 1;
519 } else {
520 i = IRQSTACK_LIMIT_WARNING;
522 #endif
523 #endif /* if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK) */
524 return i;
528 * Called periodically to update the system stats
530 static void updateStats()
532 SystemStatsData stats;
534 // Get stats and update
535 SystemStatsGet(&stats);
536 stats.FlightTime = xTaskGetTickCount() * portTICK_RATE_MS;
537 #if defined(ARCH_POSIX) || defined(ARCH_WIN32)
538 // POSIX port of FreeRTOS doesn't have xPortGetFreeHeapSize()
539 stats.SystemModStackRemaining = 128;
540 stats.HeapRemaining = 10240;
541 #else
542 stats.HeapRemaining = xPortGetFreeHeapSize();
543 stats.SystemModStackRemaining = uxTaskGetStackHighWaterMark(NULL) * 4;
544 #endif
546 // Get Irq stack status
547 stats.IRQStackRemaining = GetFreeIrqStackSize();
549 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(PIOS_INCLUDE_FLASH_LOGFS_SETTINGS)
550 static struct PIOS_FLASHFS_Stats fsStats;
552 if (pios_uavo_settings_fs_id) {
553 PIOS_FLASHFS_GetStats(pios_uavo_settings_fs_id, &fsStats);
554 stats.SysSlotsFree = fsStats.num_free_slots;
555 stats.SysSlotsActive = fsStats.num_active_slots;
557 if (pios_user_fs_id) {
558 PIOS_FLASHFS_GetStats(pios_user_fs_id, &fsStats);
559 stats.UsrSlotsFree = fsStats.num_free_slots;
560 stats.UsrSlotsActive = fsStats.num_active_slots;
562 #endif
563 stats.CPULoad = 100 - PIOS_TASK_MONITOR_GetIdlePercentage();
565 #if defined(PIOS_INCLUDE_ADC) && defined(PIOS_ADC_USE_TEMP_SENSOR)
566 float temp_voltage = PIOS_ADC_PinGetVolt(PIOS_ADC_TEMPERATURE_PIN);
567 stats.CPUTemp = PIOS_CONVERT_VOLT_TO_CPU_TEMP(temp_voltage);;
568 #endif
569 SystemStatsSet(&stats);
573 * Update system alarms
575 static void updateSystemAlarms()
577 SystemStatsData stats;
578 UAVObjStats objStats;
579 EventStats evStats;
581 SystemStatsGet(&stats);
583 // Check heap, IRQ stack and malloc failures
584 if (mallocFailed || (stats.HeapRemaining < HEAP_LIMIT_CRITICAL)
585 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK)
586 || (stats.IRQStackRemaining < IRQSTACK_LIMIT_CRITICAL)
587 #endif
589 AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY, SYSTEMALARMS_ALARM_CRITICAL);
590 } else if ((stats.HeapRemaining < HEAP_LIMIT_WARNING)
591 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK)
592 || (stats.IRQStackRemaining < IRQSTACK_LIMIT_WARNING)
593 #endif
595 AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY, SYSTEMALARMS_ALARM_WARNING);
596 } else {
597 AlarmsClear(SYSTEMALARMS_ALARM_OUTOFMEMORY);
600 // Check CPU load
601 if (stats.CPULoad > CPULOAD_LIMIT_CRITICAL) {
602 AlarmsSet(SYSTEMALARMS_ALARM_CPUOVERLOAD, SYSTEMALARMS_ALARM_CRITICAL);
603 } else if (stats.CPULoad > CPULOAD_LIMIT_WARNING) {
604 AlarmsSet(SYSTEMALARMS_ALARM_CPUOVERLOAD, SYSTEMALARMS_ALARM_WARNING);
605 } else {
606 AlarmsClear(SYSTEMALARMS_ALARM_CPUOVERLOAD);
609 // Check for stack overflow
610 switch (stackOverflow) {
611 case STACKOVERFLOW_NONE:
612 AlarmsClear(SYSTEMALARMS_ALARM_STACKOVERFLOW);
613 break;
614 case STACKOVERFLOW_WARNING:
615 AlarmsSet(SYSTEMALARMS_ALARM_STACKOVERFLOW, SYSTEMALARMS_ALARM_WARNING);
616 break;
617 default:
618 AlarmsSet(SYSTEMALARMS_ALARM_STACKOVERFLOW, SYSTEMALARMS_ALARM_CRITICAL);
621 // Check for event errors
622 UAVObjGetStats(&objStats);
623 EventGetStats(&evStats);
624 UAVObjClearStats();
625 EventClearStats();
626 if (objStats.eventCallbackErrors > 0 || objStats.eventQueueErrors > 0 || evStats.eventErrors > 0) {
627 AlarmsSet(SYSTEMALARMS_ALARM_EVENTSYSTEM, SYSTEMALARMS_ALARM_WARNING);
628 } else {
629 AlarmsClear(SYSTEMALARMS_ALARM_EVENTSYSTEM);
632 if (objStats.lastCallbackErrorID || objStats.lastQueueErrorID || evStats.lastErrorID) {
633 SystemStatsData sysStats;
634 SystemStatsGet(&sysStats);
635 sysStats.EventSystemWarningID = evStats.lastErrorID;
636 sysStats.ObjectManagerCallbackID = objStats.lastCallbackErrorID;
637 sysStats.ObjectManagerQueueID = objStats.lastQueueErrorID;
638 SystemStatsSet(&sysStats);
643 * Called by the RTOS when the CPU is idle,
645 void vApplicationIdleHook(void)
647 NotificationOnboardLedsRun();
648 #ifdef PIOS_INCLUDE_WS2811
649 LedNotificationExtLedsRun();
650 #endif
653 * Called by the RTOS when a stack overflow is detected.
655 #define DEBUG_STACK_OVERFLOW 0
656 void vApplicationStackOverflowHook(__attribute__((unused)) xTaskHandle *pxTask,
657 __attribute__((unused)) signed portCHAR *pcTaskName)
659 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32)
660 stackOverflow = STACKOVERFLOW_CRITICAL;
661 #if DEBUG_STACK_OVERFLOW
662 static volatile bool wait_here = true;
663 while (wait_here) {
666 wait_here = true;
667 #endif
668 #endif
672 * Called by the RTOS when a malloc call fails.
674 #define DEBUG_MALLOC_FAILURES 0
675 void vApplicationMallocFailedHook(void)
677 mallocFailed = true;
678 #if DEBUG_MALLOC_FAILURES
679 static volatile bool wait_here = true;
680 while (wait_here) {
683 wait_here = true;
684 #endif
688 * @}
689 * @}