2 ******************************************************************************
3 * @addtogroup LibrePilotModules LibrePilot Modules
4 * @brief The LibrePilot Modules do the majority of the control in LibrePilot. 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)
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
19 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015-2016.
20 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2015.
21 * @brief System module
23 * @see The GNU Public License (GPL) Version 3
25 *****************************************************************************/
27 * This program is free software; you can redistribute it and/or modify
28 * it under the terms of the GNU General Public License as published by
29 * the Free Software Foundation; either version 3 of the License, or
30 * (at your option) any later version.
32 * This program is distributed in the hope that it will be useful, but
33 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
34 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
37 * You should have received a copy of the GNU General Public License along
38 * with this program; if not, write to the Free Software Foundation, Inc.,
39 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
42 #include <openpilot.h>
44 #include "inc/systemmod.h"
46 #include <notification.h>
47 #ifdef PIOS_INCLUDE_WS2811
48 #include <lednotification.h>
52 #include <objectpersistence.h>
53 #include <flightstatus.h>
54 #include <systemstats.h>
55 #include <systemsettings.h>
58 #include <watchdogstatus.h>
59 #include <callbackinfo.h>
60 #include <hwsettings.h>
61 #include <pios_flashfs.h>
62 #include <pios_notify.h>
63 #include <pios_task_monitor.h>
64 #include <pios_board_init.h>
65 #include <pios_board_io.h>
67 #ifdef PIOS_INCLUDE_INSTRUMENTATION
68 #include <instrumentation.h>
69 #include <pios_instrumentation.h>
72 #if defined(PIOS_INCLUDE_RFM22B)
73 #include <oplinkstatus.h>
77 #include <sanitycheck.h>
80 // #define DEBUG_THIS_FILE
82 #if defined(PIOS_INCLUDE_DEBUG_CONSOLE) && defined(DEBUG_THIS_FILE)
83 #define DEBUG_MSG(format, ...) PIOS_COM_SendFormattedString(PIOS_COM_DEBUG, format,##__VA_ARGS__)
85 #define DEBUG_MSG(format, ...)
89 #define SYSTEM_UPDATE_PERIOD_MS 250
91 #if defined(PIOS_SYSTEM_STACK_SIZE)
92 #define STACK_SIZE_BYTES PIOS_SYSTEM_STACK_SIZE
94 #define STACK_SIZE_BYTES 1024
97 #define TASK_PRIORITY (tskIDLE_PRIORITY + 1)
102 static xTaskHandle systemTaskHandle
;
103 static xQueueHandle objectPersistenceQueue
;
104 static enum { STACKOVERFLOW_NONE
= 0, STACKOVERFLOW_WARNING
= 1, STACKOVERFLOW_CRITICAL
= 3 } stackOverflow
;
105 static bool mallocFailed
;
106 static HwSettingsData bootHwSettings
;
107 static FrameType_t bootFrameType
;
109 volatile int initTaskDone
= 0;
112 static void objectUpdatedCb(UAVObjEvent
*ev
);
113 static void checkSettingsUpdatedCb(UAVObjEvent
*ev
);
115 static void taskMonitorForEachCallback(uint16_t task_id
, const struct pios_task_info
*task_info
, void *context
);
116 static void callbackSchedulerForEachCallback(int16_t callback_id
, const struct pios_callback_info
*callback_info
, void *context
);
118 static void updateStats();
119 static void updateSystemAlarms();
120 static void systemTask(void *parameters
);
121 static void updateI2Cstats();
122 #ifdef DIAG_I2C_WDG_STATS
123 static void updateWDGstats();
126 #ifdef PIOS_INCLUDE_I2C
127 #define I2C_ERROR_ACTIVITY_TIMEOUT_SECONDS 2
128 #define I2C_ERROR_ACTIVITY_TIMEOUT (I2C_ERROR_ACTIVITY_TIMEOUT_SECONDS * 1000 / SYSTEM_UPDATE_PERIOD_MS)
129 static uint8_t i2c_error_activity
[PIOS_I2C_ERROR_COUNT_NUMELEM
];
132 #ifdef PIOS_INCLUDE_RFM22B
133 static uint8_t previousRFXtalCap
;
134 static uint8_t protocol
;
135 static void oplinkSettingsUpdatedCb(UAVObjEvent
*ev
);
138 extern uintptr_t pios_uavo_settings_fs_id
;
139 extern uintptr_t pios_user_fs_id
;
142 * Create the module task.
143 * \returns 0 on success or -1 if initialization failed
145 int32_t SystemModStart(void)
148 stackOverflow
= STACKOVERFLOW_NONE
;
149 mallocFailed
= false;
150 // Create system task
151 xTaskCreate(systemTask
, "System", STACK_SIZE_BYTES
/ 4, NULL
, TASK_PRIORITY
, &systemTaskHandle
);
157 * Initialize the module, called on startup.
158 * \returns 0 on success or -1 if initialization failed
160 int32_t SystemModInitialize(void)
162 // Must registers objects here for system thread because ObjectManager started in OpenPilotInit
163 SystemStatsInitialize();
164 FlightStatusInitialize();
165 ObjectPersistenceInitialize();
167 TaskInfoInitialize();
168 CallbackInfoInitialize();
170 #ifdef DIAG_I2C_WDG_STATS
171 I2CStatsInitialize();
172 WatchdogStatusInitialize();
175 #ifdef PIOS_INCLUDE_INSTRUMENTATION
176 InstrumentationInit();
179 objectPersistenceQueue
= xQueueCreate(1, sizeof(UAVObjEvent
));
180 if (objectPersistenceQueue
== NULL
) {
187 MODULE_INITCALL(SystemModInitialize
, 0);
189 * System task, periodically executes every SYSTEM_UPDATE_PERIOD_MS
191 static void systemTask(__attribute__((unused
)) void *parameters
)
193 /* calibrate the cpu usage monitor */
194 PIOS_TASK_MONITOR_CalibrateIdleCounter();
195 /* board driver init */
198 /* Initialize all modules */
199 MODULE_INITIALISE_ALL
;
201 while (!initTaskDone
) {
205 #ifndef PIOS_INCLUDE_WDG
206 // if no watchdog is enabled, don't reset watchdog in MODULE_TASKCREATE_ALL loop
207 #define PIOS_WDG_Clear()
209 /* create all modules thread */
210 MODULE_TASKCREATE_ALL
;
212 /* start the delayed callback scheduler */
213 PIOS_CALLBACKSCHEDULER_Start();
216 PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_SYSTEM
, systemTaskHandle
);
219 /* We failed to malloc during task creation,
220 * system behaviour is undefined. Reset and let
221 * the BootFault code recover for us.
225 #if defined(PIOS_INCLUDE_IAP)
226 /* Record a successful boot */
227 PIOS_IAP_WriteBootCount(0);
229 // Listen for SettingPersistance object updates, connect a callback function
230 ObjectPersistenceConnectQueue(objectPersistenceQueue
);
232 // Load a copy of HwSetting active at boot time
233 HwSettingsGet(&bootHwSettings
);
234 bootFrameType
= GetCurrentFrameType();
235 // Whenever the configuration changes, make sure it is safe to fly
236 HwSettingsConnectCallback(checkSettingsUpdatedCb
);
237 SystemSettingsConnectCallback(checkSettingsUpdatedCb
);
239 #ifdef PIOS_INCLUDE_RFM22B
240 // Initialize previousRFXtalCap used by callback
241 OPLinkSettingsRFXtalCapGet(&previousRFXtalCap
);
242 OPLinkSettingsConnectCallback(oplinkSettingsUpdatedCb
);
244 OPLinkSettingsProtocolGet(&protocol
);
248 TaskInfoData taskInfoData
;
249 memset(&taskInfoData
, 0, sizeof(TaskInfoData
));
250 CallbackInfoData callbackInfoData
;
251 memset(&callbackInfoData
, 0, sizeof(CallbackInfoData
));
255 NotificationUpdateStatus();
256 // Update the system statistics
262 // Update the system alarms
263 updateSystemAlarms();
264 #ifdef DIAG_I2C_WDG_STATS
268 #ifdef PIOS_INCLUDE_INSTRUMENTATION
269 InstrumentationPublishAllCounters();
273 // Update the task status object
274 PIOS_TASK_MONITOR_ForEachTask(taskMonitorForEachCallback
, &taskInfoData
);
275 TaskInfoSet(&taskInfoData
);
276 // Update the callback status object
277 PIOS_CALLBACKSCHEDULER_ForEachCallback(callbackSchedulerForEachCallback
, &callbackInfoData
);
278 CallbackInfoSet(&callbackInfoData
);
282 int delayTime
= SYSTEM_UPDATE_PERIOD_MS
;
284 #if defined(PIOS_INCLUDE_RFM22B)
286 // Update the OPLinkStatus UAVO
287 OPLinkStatusData oplinkStatus
;
288 OPLinkStatusGet(&oplinkStatus
);
289 oplinkStatus
.HeapRemaining
= xPortGetFreeHeapSize();
291 if (pios_rfm22b_id
) {
292 // Get the stats from the radio device
293 struct rfm22b_stats radio_stats
;
294 PIOS_RFM22B_GetStats(pios_rfm22b_id
, &radio_stats
);
296 // Update the OPLInk status
297 static bool first_time
= true;
298 static uint16_t prev_tx_count
= 0;
299 static uint16_t prev_rx_count
= 0;
300 static uint16_t prev_tx_seq
= 0;
301 static uint16_t prev_rx_seq
= 0;
303 oplinkStatus
.DeviceID
= PIOS_RFM22B_DeviceID(pios_rfm22b_id
);
304 oplinkStatus
.RxGood
= radio_stats
.rx_good
;
305 oplinkStatus
.RxCorrected
= radio_stats
.rx_corrected
;
306 oplinkStatus
.RxErrors
= radio_stats
.rx_error
;
307 oplinkStatus
.RxMissed
= radio_stats
.rx_missed
;
308 oplinkStatus
.RxFailure
= radio_stats
.rx_failure
;
309 oplinkStatus
.TxDropped
= radio_stats
.tx_dropped
;
310 oplinkStatus
.TxFailure
= radio_stats
.tx_failure
;
311 oplinkStatus
.Resets
= radio_stats
.resets
;
312 oplinkStatus
.Timeouts
= radio_stats
.timeouts
;
313 oplinkStatus
.RSSI
= radio_stats
.rssi
;
314 oplinkStatus
.LinkQuality
= radio_stats
.link_quality
;
315 oplinkStatus
.AFCCorrection
= radio_stats
.afc_correction
;
319 uint16_t tx_count
= radio_stats
.tx_byte_count
;
320 uint16_t rx_count
= radio_stats
.rx_byte_count
;
321 uint16_t tx_packets
= radio_stats
.tx_seq
- prev_tx_seq
;
322 uint16_t rx_packets
= radio_stats
.rx_seq
- prev_rx_seq
;
323 uint16_t tx_bytes
= (tx_count
< prev_tx_count
) ? (0xffff - prev_tx_count
+ tx_count
) : (tx_count
- prev_tx_count
);
324 uint16_t rx_bytes
= (rx_count
< prev_rx_count
) ? (0xffff - prev_rx_count
+ rx_count
) : (rx_count
- prev_rx_count
);
325 oplinkStatus
.TXRate
= (uint16_t)((float)(tx_bytes
* 1000) / SYSTEM_UPDATE_PERIOD_MS
);
326 oplinkStatus
.RXRate
= (uint16_t)((float)(rx_bytes
* 1000) / SYSTEM_UPDATE_PERIOD_MS
);
327 oplinkStatus
.TXPacketRate
= (uint16_t)((float)(tx_packets
* 1000) / SYSTEM_UPDATE_PERIOD_MS
);
328 oplinkStatus
.RXPacketRate
= (uint16_t)((float)(rx_packets
* 1000) / SYSTEM_UPDATE_PERIOD_MS
);
329 prev_tx_count
= tx_count
;
330 prev_rx_count
= rx_count
;
331 prev_tx_seq
= radio_stats
.tx_seq
;
332 prev_rx_seq
= radio_stats
.rx_seq
;
334 oplinkStatus
.TXSeq
= radio_stats
.tx_seq
;
335 oplinkStatus
.RXSeq
= radio_stats
.rx_seq
;
337 oplinkStatus
.LinkState
= radio_stats
.link_state
;
338 } else if (protocol
!= OPLINKSETTINGS_PROTOCOL_OPENLRS
) {
339 oplinkStatus
.LinkState
= OPLINKSTATUS_LINKSTATE_DISABLED
;
341 OPLinkStatusSet(&oplinkStatus
);
343 #endif /* if defined(PIOS_INCLUDE_RFM22B) */
345 if (xQueueReceive(objectPersistenceQueue
, &ev
, delayTime
) == pdTRUE
) {
346 // If object persistence is updated call the callback
347 objectUpdatedCb(&ev
);
353 * Function called in response to object updates
355 static void objectUpdatedCb(UAVObjEvent
*ev
)
357 ObjectPersistenceData objper
;
360 // If the object updated was the ObjectPersistence execute requested action
361 if (ev
->obj
== ObjectPersistenceHandle()) {
363 ObjectPersistenceGet(&objper
);
366 FlightStatusData flightStatus
;
367 FlightStatusGet(&flightStatus
);
369 // When this is called because of this method don't do anything
370 if (objper
.Operation
== OBJECTPERSISTENCE_OPERATION_ERROR
|| objper
.Operation
== OBJECTPERSISTENCE_OPERATION_COMPLETED
) {
374 // Execute action if disarmed
375 if (flightStatus
.Armed
!= FLIGHTSTATUS_ARMED_DISARMED
) {
377 } else if (objper
.Operation
== OBJECTPERSISTENCE_OPERATION_LOAD
) {
378 if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_SINGLEOBJECT
) {
379 // Get selected object
380 obj
= UAVObjGetByID(objper
.ObjectID
);
384 // Load selected instance
385 retval
= UAVObjLoad(obj
, objper
.InstanceID
);
386 } else if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLSETTINGS
|| objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLOBJECTS
) {
387 retval
= UAVObjLoadSettings();
388 } else if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLMETAOBJECTS
|| objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLOBJECTS
) {
389 retval
= UAVObjLoadMetaobjects();
391 } else if (objper
.Operation
== OBJECTPERSISTENCE_OPERATION_SAVE
) {
392 if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_SINGLEOBJECT
) {
393 // Get selected object
394 obj
= UAVObjGetByID(objper
.ObjectID
);
398 // Save selected instance
399 retval
= UAVObjSave(obj
, objper
.InstanceID
);
401 // Not sure why this is needed
404 // Verify saving worked
406 retval
= UAVObjLoad(obj
, objper
.InstanceID
);
408 } else if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLSETTINGS
|| objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLOBJECTS
) {
409 retval
= UAVObjSaveSettings();
410 } else if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLMETAOBJECTS
|| objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLOBJECTS
) {
411 retval
= UAVObjSaveMetaobjects();
413 } else if (objper
.Operation
== OBJECTPERSISTENCE_OPERATION_DELETE
) {
414 if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_SINGLEOBJECT
) {
415 // Get selected object
416 obj
= UAVObjGetByID(objper
.ObjectID
);
420 // Delete selected instance
421 retval
= UAVObjDelete(obj
, objper
.InstanceID
);
422 } else if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLSETTINGS
|| objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLOBJECTS
) {
423 retval
= UAVObjDeleteSettings();
424 } else if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLMETAOBJECTS
|| objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLOBJECTS
) {
425 retval
= UAVObjDeleteMetaobjects();
427 } else if (objper
.Operation
== OBJECTPERSISTENCE_OPERATION_FULLERASE
) {
428 #if defined(PIOS_INCLUDE_FLASH_LOGFS_SETTINGS)
429 retval
= PIOS_FLASHFS_Format(0);
436 objper
.Operation
= OBJECTPERSISTENCE_OPERATION_COMPLETED
;
437 ObjectPersistenceSet(&objper
);
440 objper
.Operation
= OBJECTPERSISTENCE_OPERATION_ERROR
;
441 ObjectPersistenceSet(&objper
);
450 * Called whenever hardware settings changed
452 static void checkSettingsUpdatedCb(__attribute__((unused
)) UAVObjEvent
*ev
)
454 HwSettingsData currentHwSettings
;
456 HwSettingsGet(¤tHwSettings
);
457 FrameType_t currentFrameType
= GetCurrentFrameType();
458 // check whether the Hw Configuration has changed from the one used at boot time
459 if ((memcmp(&bootHwSettings
, ¤tHwSettings
, sizeof(HwSettingsData
)) != 0) ||
460 (currentFrameType
!= bootFrameType
)) {
461 ExtendedAlarmsSet(SYSTEMALARMS_ALARM_BOOTFAULT
, SYSTEMALARMS_ALARM_CRITICAL
, SYSTEMALARMS_EXTENDEDALARMSTATUS_REBOOTREQUIRED
, 0);
465 #ifdef PIOS_INCLUDE_RFM22B
467 * Called whenever OPLink settings changed
469 static void oplinkSettingsUpdatedCb(__attribute__((unused
)) UAVObjEvent
*ev
)
471 uint8_t currentRFXtalCap
;
473 OPLinkSettingsRFXtalCapGet(¤tRFXtalCap
);
475 // Check if RFXtalCap value changed
476 if (currentRFXtalCap
!= previousRFXtalCap
) {
477 PIOS_RFM22B_SetXtalCap(pios_rfm22b_id
, currentRFXtalCap
);
478 PIOS_RFM22B_Reinit(pios_rfm22b_id
);
479 previousRFXtalCap
= currentRFXtalCap
;
482 #endif /* ifdef PIOS_INCLUDE_RFM22B */
485 static void taskMonitorForEachCallback(uint16_t task_id
, const struct pios_task_info
*task_info
, void *context
)
487 TaskInfoData
*taskData
= (TaskInfoData
*)context
;
489 // By convention, there is a direct mapping between task monitor task_id's and members
490 // of the TaskInfoXXXXElem enums
491 PIOS_DEBUG_Assert(task_id
< TASKINFO_RUNNING_NUMELEM
);
492 TaskInfoRunningToArray(taskData
->Running
)[task_id
] = task_info
->is_running
? TASKINFO_RUNNING_TRUE
: TASKINFO_RUNNING_FALSE
;
493 ((uint16_t *)&taskData
->StackRemaining
)[task_id
] = task_info
->stack_remaining
;
494 ((uint8_t *)&taskData
->RunningTime
)[task_id
] = task_info
->running_time_percentage
;
497 static void callbackSchedulerForEachCallback(int16_t callback_id
, const struct pios_callback_info
*callback_info
, void *context
)
499 CallbackInfoData
*callbackData
= (CallbackInfoData
*)context
;
501 if (callback_id
< 0) {
504 // delayed callback scheduler reports callback stack overflows as remaininng: -1
505 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32)
506 if (callback_info
->stack_remaining
< 0 && stackOverflow
== STACKOVERFLOW_NONE
) {
507 stackOverflow
= STACKOVERFLOW_WARNING
;
510 // By convention, there is a direct mapping between (not negative) callback scheduler callback_id's and members
511 // of the CallbackInfoXXXXElem enums
512 PIOS_DEBUG_Assert(callback_id
< CALLBACKINFO_RUNNING_NUMELEM
);
513 ((uint8_t *)&callbackData
->Running
)[callback_id
] = callback_info
->is_running
;
514 ((uint32_t *)&callbackData
->RunningTime
)[callback_id
] = callback_info
->running_time_count
;
515 ((int16_t *)&callbackData
->StackRemaining
)[callback_id
] = callback_info
->stack_remaining
;
517 #endif /* ifdef DIAG_TASKS */
520 * Called periodically (every SYSTEM_UPDATE_PERIOD_MS milliseconds) to update the I2C statistics
522 static void updateI2Cstats()
524 #if defined(PIOS_INCLUDE_I2C)
525 static uint8_t previous_error_counts
[PIOS_I2C_ERROR_COUNT_NUMELEM
];
527 struct pios_i2c_fault_history history
;
528 uint8_t error_counts
[PIOS_I2C_ERROR_COUNT_NUMELEM
];
530 PIOS_I2C_GetDiagnostics(&history
, error_counts
);
532 // every time a counter changes, set activity timeout counter to ( I2C_ERROR_ACTIVITY_TIMEOUT ).
533 // every time a counter does not change, decrease activity counter.
535 for (uint8_t i
= 0; i
< PIOS_I2C_ERROR_COUNT_NUMELEM
; i
++) {
536 if (error_counts
[i
] != previous_error_counts
[i
]) {
537 i2c_error_activity
[i
] = I2C_ERROR_ACTIVITY_TIMEOUT
;
538 } else if (i2c_error_activity
[i
] > 0) {
539 i2c_error_activity
[i
]--;
542 previous_error_counts
[i
] = error_counts
[i
];
545 #ifdef DIAG_I2C_WDG_STATS
546 I2CStatsData i2cStats
;
547 I2CStatsGet(&i2cStats
);
549 memcpy(&i2cStats
.event_errors
, &error_counts
, sizeof(error_counts
));
551 for (uint8_t i
= 0; (i
< I2C_LOG_DEPTH
) && (i
< I2CSTATS_EVENT_LOG_NUMELEM
); i
++) {
552 i2cStats
.evirq_log
[i
] = history
.evirq
[i
];
553 i2cStats
.erirq_log
[i
] = history
.erirq
[i
];
554 i2cStats
.event_log
[i
] = history
.event
[i
];
555 i2cStats
.state_log
[i
] = history
.state
[i
];
557 i2cStats
.last_error_type
= history
.type
;
558 I2CStatsSet(&i2cStats
);
559 #endif /* DIAG_I2C_WDG_STATS */
560 #endif /* PIOS_INCLUDE_I2C */
563 #ifdef DIAG_I2C_WDG_STATS
564 static void updateWDGstats()
566 WatchdogStatusData watchdogStatus
;
568 watchdogStatus
.BootupFlags
= PIOS_WDG_GetBootupFlags();
569 watchdogStatus
.ActiveFlags
= PIOS_WDG_GetActiveFlags();
570 WatchdogStatusSet(&watchdogStatus
);
572 #endif /* ifdef DIAG_I2C_WDG_STATS */
575 * Called periodically to update the system stats
577 static uint16_t GetFreeIrqStackSize(void)
581 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK)
582 extern uint32_t _irq_stack_top
;
583 extern uint32_t _irq_stack_end
;
585 uint32_t pattern
= 0xA5A5A5A5;
587 uint32_t pattern
= 0xA5A5;
589 uint32_t *ptr
= &_irq_stack_end
;
591 #if 1 /* the ugly way accurate but takes more time, useful for debugging */
592 uint32_t stack_size
= (((uint32_t)&_irq_stack_top
- (uint32_t)&_irq_stack_end
) & ~3) / 4;
594 for (i
= 0; i
< stack_size
; i
++) {
595 if (ptr
[i
] != pattern
) {
600 #else /* faster way but not accurate */
601 if (*(volatile uint32_t *)((uint32_t)ptr
+ IRQSTACK_LIMIT_CRITICAL
) != pattern
) {
602 i
= IRQSTACK_LIMIT_CRITICAL
- 1;
603 } else if (*(volatile uint32_t *)((uint32_t)ptr
+ IRQSTACK_LIMIT_WARNING
) != pattern
) {
604 i
= IRQSTACK_LIMIT_WARNING
- 1;
606 i
= IRQSTACK_LIMIT_WARNING
;
609 #endif /* if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK) */
614 * Called periodically to update the system stats
616 static void updateStats()
618 SystemStatsData stats
;
620 // Get stats and update
621 SystemStatsGet(&stats
);
622 stats
.FlightTime
= xTaskGetTickCount() * portTICK_RATE_MS
;
623 #if defined(ARCH_POSIX) || defined(ARCH_WIN32)
624 // POSIX port of FreeRTOS doesn't have xPortGetFreeHeapSize()
625 stats
.SystemModStackRemaining
= 128;
626 stats
.HeapRemaining
= 10240;
628 stats
.HeapRemaining
= xPortGetFreeHeapSize();
629 stats
.SystemModStackRemaining
= uxTaskGetStackHighWaterMark(NULL
) * 4;
632 // Get Irq stack status
633 stats
.IRQStackRemaining
= GetFreeIrqStackSize();
635 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(PIOS_INCLUDE_FLASH_LOGFS_SETTINGS)
636 static struct PIOS_FLASHFS_Stats fsStats
;
638 if (pios_uavo_settings_fs_id
) {
639 PIOS_FLASHFS_GetStats(pios_uavo_settings_fs_id
, &fsStats
);
640 stats
.SysSlotsFree
= fsStats
.num_free_slots
;
641 stats
.SysSlotsActive
= fsStats
.num_active_slots
;
643 if (pios_user_fs_id
) {
644 PIOS_FLASHFS_GetStats(pios_user_fs_id
, &fsStats
);
645 stats
.UsrSlotsFree
= fsStats
.num_free_slots
;
646 stats
.UsrSlotsActive
= fsStats
.num_active_slots
;
649 stats
.CPUIdleTicks
= PIOS_TASK_MONITOR_GetIdleTicksCount();
650 stats
.CPUZeroLoadTicks
= PIOS_TASK_MONITOR_GetZeroLoadTicksCount();
651 stats
.CPULoad
= 100 - (uint8_t)((100 * stats
.CPUIdleTicks
) / stats
.CPUZeroLoadTicks
);
653 #if defined(PIOS_INCLUDE_ADC) && defined(PIOS_ADC_USE_TEMP_SENSOR)
654 float temp_voltage
= PIOS_ADC_PinGetVolt(PIOS_ADC_TEMPERATURE_PIN
);
655 stats
.CPUTemp
= PIOS_CONVERT_VOLT_TO_CPU_TEMP(temp_voltage
);;
657 SystemStatsSet(&stats
);
661 * Update system alarms
663 static void updateSystemAlarms()
665 SystemStatsData stats
;
666 UAVObjStats objStats
;
669 SystemStatsGet(&stats
);
671 // Check heap, IRQ stack and malloc failures
672 if (mallocFailed
|| (stats
.HeapRemaining
< HEAP_LIMIT_CRITICAL
)
673 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK)
674 || (stats
.IRQStackRemaining
< IRQSTACK_LIMIT_CRITICAL
)
677 AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY
, SYSTEMALARMS_ALARM_CRITICAL
);
678 } else if ((stats
.HeapRemaining
< HEAP_LIMIT_WARNING
)
679 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK)
680 || (stats
.IRQStackRemaining
< IRQSTACK_LIMIT_WARNING
)
683 AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY
, SYSTEMALARMS_ALARM_WARNING
);
685 AlarmsClear(SYSTEMALARMS_ALARM_OUTOFMEMORY
);
689 if (stats
.CPULoad
> CPULOAD_LIMIT_CRITICAL
) {
690 AlarmsSet(SYSTEMALARMS_ALARM_CPUOVERLOAD
, SYSTEMALARMS_ALARM_CRITICAL
);
691 } else if (stats
.CPULoad
> CPULOAD_LIMIT_WARNING
) {
692 AlarmsSet(SYSTEMALARMS_ALARM_CPUOVERLOAD
, SYSTEMALARMS_ALARM_WARNING
);
694 AlarmsClear(SYSTEMALARMS_ALARM_CPUOVERLOAD
);
697 // Check for stack overflow
698 switch (stackOverflow
) {
699 case STACKOVERFLOW_NONE
:
700 AlarmsClear(SYSTEMALARMS_ALARM_STACKOVERFLOW
);
702 case STACKOVERFLOW_WARNING
:
703 AlarmsSet(SYSTEMALARMS_ALARM_STACKOVERFLOW
, SYSTEMALARMS_ALARM_WARNING
);
706 AlarmsSet(SYSTEMALARMS_ALARM_STACKOVERFLOW
, SYSTEMALARMS_ALARM_CRITICAL
);
709 // Check for event errors
710 UAVObjGetStats(&objStats
);
711 EventGetStats(&evStats
);
714 if (objStats
.eventCallbackErrors
> 0 || objStats
.eventQueueErrors
> 0 || evStats
.eventErrors
> 0) {
715 AlarmsSet(SYSTEMALARMS_ALARM_EVENTSYSTEM
, SYSTEMALARMS_ALARM_WARNING
);
717 AlarmsClear(SYSTEMALARMS_ALARM_EVENTSYSTEM
);
720 if (objStats
.lastCallbackErrorID
|| objStats
.lastQueueErrorID
|| evStats
.lastErrorID
) {
721 SystemStatsData sysStats
;
722 SystemStatsGet(&sysStats
);
723 sysStats
.EventSystemWarningID
= evStats
.lastErrorID
;
724 sysStats
.ObjectManagerCallbackID
= objStats
.lastCallbackErrorID
;
725 sysStats
.ObjectManagerQueueID
= objStats
.lastQueueErrorID
;
726 SystemStatsSet(&sysStats
);
729 #ifdef PIOS_INCLUDE_I2C
730 if (AlarmsGet(SYSTEMALARMS_ALARM_I2C
) != SYSTEMALARMS_ALARM_UNINITIALISED
) {
731 static const SystemAlarmsAlarmOptions i2c_alarm_by_error
[] = {
732 [PIOS_I2C_BAD_EVENT_COUNTER
] = SYSTEMALARMS_ALARM_ERROR
,
733 [PIOS_I2C_FSM_FAULT_COUNT
] = SYSTEMALARMS_ALARM_ERROR
,
734 [PIOS_I2C_ERROR_INTERRUPT_COUNTER
] = SYSTEMALARMS_ALARM_ERROR
,
735 [PIOS_I2C_NACK_COUNTER
] = SYSTEMALARMS_ALARM_CRITICAL
,
736 [PIOS_I2C_TIMEOUT_COUNTER
] = SYSTEMALARMS_ALARM_ERROR
,
739 SystemAlarmsAlarmOptions i2c_alarm
= SYSTEMALARMS_ALARM_OK
;
741 for (uint8_t i
= 0; i
< PIOS_I2C_ERROR_COUNT_NUMELEM
; i
++) {
742 if ((i2c_error_activity
[i
] > 0) && (i2c_alarm
< i2c_alarm_by_error
[i
])) {
743 i2c_alarm
= i2c_alarm_by_error
[i
];
747 AlarmsSet(SYSTEMALARMS_ALARM_I2C
, i2c_alarm
);
749 #endif /* PIOS_INCLUDE_I2C */
753 * Called by the RTOS when the CPU is idle,
755 void vApplicationIdleHook(void)
757 PIOS_TASK_MONITOR_IdleHook();
758 NotificationOnboardLedsRun();
759 #ifdef PIOS_INCLUDE_WS2811
760 LedNotificationExtLedsRun();
764 * Called by the RTOS when a stack overflow is detected.
766 #define DEBUG_STACK_OVERFLOW 0
767 void vApplicationStackOverflowHook(__attribute__((unused
)) xTaskHandle
*pxTask
,
768 __attribute__((unused
)) signed portCHAR
*pcTaskName
)
770 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32)
771 stackOverflow
= STACKOVERFLOW_CRITICAL
;
772 #if DEBUG_STACK_OVERFLOW
773 static volatile bool wait_here
= true;
783 * Called by the RTOS when a malloc call fails.
785 #define DEBUG_MALLOC_FAILURES 0
786 void vApplicationMallocFailedHook(void)
789 #if DEBUG_MALLOC_FAILURES
790 static volatile bool wait_here
= true;