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>
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 void oplinkSettingsUpdatedCb(UAVObjEvent
*ev
);
137 extern uintptr_t pios_uavo_settings_fs_id
;
138 extern uintptr_t pios_user_fs_id
;
141 * Create the module task.
142 * \returns 0 on success or -1 if initialization failed
144 int32_t SystemModStart(void)
147 stackOverflow
= STACKOVERFLOW_NONE
;
148 mallocFailed
= false;
149 // Create system task
150 xTaskCreate(systemTask
, "System", STACK_SIZE_BYTES
/ 4, NULL
, TASK_PRIORITY
, &systemTaskHandle
);
156 * Initialize the module, called on startup.
157 * \returns 0 on success or -1 if initialization failed
159 int32_t SystemModInitialize(void)
161 // Must registers objects here for system thread because ObjectManager started in OpenPilotInit
162 SystemSettingsInitialize();
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
);
246 TaskInfoData taskInfoData
;
247 memset(&taskInfoData
, 0, sizeof(TaskInfoData
));
248 CallbackInfoData callbackInfoData
;
249 memset(&callbackInfoData
, 0, sizeof(CallbackInfoData
));
253 NotificationUpdateStatus();
254 // Update the system statistics
260 // Update the system alarms
261 updateSystemAlarms();
262 #ifdef DIAG_I2C_WDG_STATS
266 #ifdef PIOS_INCLUDE_INSTRUMENTATION
267 InstrumentationPublishAllCounters();
271 // Update the task status object
272 PIOS_TASK_MONITOR_ForEachTask(taskMonitorForEachCallback
, &taskInfoData
);
273 TaskInfoSet(&taskInfoData
);
274 // Update the callback status object
275 PIOS_CALLBACKSCHEDULER_ForEachCallback(callbackSchedulerForEachCallback
, &callbackInfoData
);
276 CallbackInfoSet(&callbackInfoData
);
280 int delayTime
= SYSTEM_UPDATE_PERIOD_MS
;
282 #if defined(PIOS_INCLUDE_RFM22B)
284 // Update the OPLinkStatus UAVO
285 OPLinkStatusData oplinkStatus
;
286 OPLinkStatusGet(&oplinkStatus
);
287 oplinkStatus
.HeapRemaining
= xPortGetFreeHeapSize();
289 if (pios_rfm22b_id
) {
290 // Get the other device stats.
291 PIOS_RFM22B_GetPairStats(pios_rfm22b_id
, oplinkStatus
.PairIDs
, oplinkStatus
.PairSignalStrengths
, OPLINKSTATUS_PAIRIDS_NUMELEM
);
293 // Get the stats from the radio device
294 struct rfm22b_stats radio_stats
;
295 PIOS_RFM22B_GetStats(pios_rfm22b_id
, &radio_stats
);
297 // Update the OPLInk status
298 static bool first_time
= true;
299 static uint16_t prev_tx_count
= 0;
300 static uint16_t prev_rx_count
= 0;
301 static uint16_t prev_tx_seq
= 0;
302 static uint16_t prev_rx_seq
= 0;
304 oplinkStatus
.DeviceID
= PIOS_RFM22B_DeviceID(pios_rfm22b_id
);
305 oplinkStatus
.RxGood
= radio_stats
.rx_good
;
306 oplinkStatus
.RxCorrected
= radio_stats
.rx_corrected
;
307 oplinkStatus
.RxErrors
= radio_stats
.rx_error
;
308 oplinkStatus
.RxMissed
= radio_stats
.rx_missed
;
309 oplinkStatus
.RxFailure
= radio_stats
.rx_failure
;
310 oplinkStatus
.TxDropped
= radio_stats
.tx_dropped
;
311 oplinkStatus
.TxFailure
= radio_stats
.tx_failure
;
312 oplinkStatus
.Resets
= radio_stats
.resets
;
313 oplinkStatus
.Timeouts
= radio_stats
.timeouts
;
314 oplinkStatus
.RSSI
= radio_stats
.rssi
;
315 oplinkStatus
.LinkQuality
= radio_stats
.link_quality
;
316 oplinkStatus
.AFCCorrection
= radio_stats
.afc_correction
;
320 uint16_t tx_count
= radio_stats
.tx_byte_count
;
321 uint16_t rx_count
= radio_stats
.rx_byte_count
;
322 uint16_t tx_packets
= radio_stats
.tx_seq
- prev_tx_seq
;
323 uint16_t rx_packets
= radio_stats
.rx_seq
- prev_rx_seq
;
324 uint16_t tx_bytes
= (tx_count
< prev_tx_count
) ? (0xffff - prev_tx_count
+ tx_count
) : (tx_count
- prev_tx_count
);
325 uint16_t rx_bytes
= (rx_count
< prev_rx_count
) ? (0xffff - prev_rx_count
+ rx_count
) : (rx_count
- prev_rx_count
);
326 oplinkStatus
.TXRate
= (uint16_t)((float)(tx_bytes
* 1000) / SYSTEM_UPDATE_PERIOD_MS
);
327 oplinkStatus
.RXRate
= (uint16_t)((float)(rx_bytes
* 1000) / SYSTEM_UPDATE_PERIOD_MS
);
328 oplinkStatus
.TXPacketRate
= (uint16_t)((float)(tx_packets
* 1000) / SYSTEM_UPDATE_PERIOD_MS
);
329 oplinkStatus
.RXPacketRate
= (uint16_t)((float)(rx_packets
* 1000) / SYSTEM_UPDATE_PERIOD_MS
);
330 prev_tx_count
= tx_count
;
331 prev_rx_count
= rx_count
;
332 prev_tx_seq
= radio_stats
.tx_seq
;
333 prev_rx_seq
= radio_stats
.rx_seq
;
335 oplinkStatus
.TXSeq
= radio_stats
.tx_seq
;
336 oplinkStatus
.RXSeq
= radio_stats
.rx_seq
;
338 oplinkStatus
.LinkState
= radio_stats
.link_state
;
340 oplinkStatus
.LinkState
= OPLINKSTATUS_LINKSTATE_DISABLED
;
342 OPLinkStatusSet(&oplinkStatus
);
344 #endif /* if defined(PIOS_INCLUDE_RFM22B) */
346 if (xQueueReceive(objectPersistenceQueue
, &ev
, delayTime
) == pdTRUE
) {
347 // If object persistence is updated call the callback
348 objectUpdatedCb(&ev
);
354 * Function called in response to object updates
356 static void objectUpdatedCb(UAVObjEvent
*ev
)
358 ObjectPersistenceData objper
;
361 // If the object updated was the ObjectPersistence execute requested action
362 if (ev
->obj
== ObjectPersistenceHandle()) {
364 ObjectPersistenceGet(&objper
);
367 FlightStatusData flightStatus
;
368 FlightStatusGet(&flightStatus
);
370 // When this is called because of this method don't do anything
371 if (objper
.Operation
== OBJECTPERSISTENCE_OPERATION_ERROR
|| objper
.Operation
== OBJECTPERSISTENCE_OPERATION_COMPLETED
) {
375 // Execute action if disarmed
376 if (flightStatus
.Armed
!= FLIGHTSTATUS_ARMED_DISARMED
) {
378 } else if (objper
.Operation
== OBJECTPERSISTENCE_OPERATION_LOAD
) {
379 if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_SINGLEOBJECT
) {
380 // Get selected object
381 obj
= UAVObjGetByID(objper
.ObjectID
);
385 // Load selected instance
386 retval
= UAVObjLoad(obj
, objper
.InstanceID
);
387 } else if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLSETTINGS
|| objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLOBJECTS
) {
388 retval
= UAVObjLoadSettings();
389 } else if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLMETAOBJECTS
|| objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLOBJECTS
) {
390 retval
= UAVObjLoadMetaobjects();
392 } else if (objper
.Operation
== OBJECTPERSISTENCE_OPERATION_SAVE
) {
393 if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_SINGLEOBJECT
) {
394 // Get selected object
395 obj
= UAVObjGetByID(objper
.ObjectID
);
399 // Save selected instance
400 retval
= UAVObjSave(obj
, objper
.InstanceID
);
402 // Not sure why this is needed
405 // Verify saving worked
407 retval
= UAVObjLoad(obj
, objper
.InstanceID
);
409 } else if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLSETTINGS
|| objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLOBJECTS
) {
410 retval
= UAVObjSaveSettings();
411 } else if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLMETAOBJECTS
|| objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLOBJECTS
) {
412 retval
= UAVObjSaveMetaobjects();
414 } else if (objper
.Operation
== OBJECTPERSISTENCE_OPERATION_DELETE
) {
415 if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_SINGLEOBJECT
) {
416 // Get selected object
417 obj
= UAVObjGetByID(objper
.ObjectID
);
421 // Delete selected instance
422 retval
= UAVObjDelete(obj
, objper
.InstanceID
);
423 } else if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLSETTINGS
|| objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLOBJECTS
) {
424 retval
= UAVObjDeleteSettings();
425 } else if (objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLMETAOBJECTS
|| objper
.Selection
== OBJECTPERSISTENCE_SELECTION_ALLOBJECTS
) {
426 retval
= UAVObjDeleteMetaobjects();
428 } else if (objper
.Operation
== OBJECTPERSISTENCE_OPERATION_FULLERASE
) {
429 #if defined(PIOS_INCLUDE_FLASH_LOGFS_SETTINGS)
430 retval
= PIOS_FLASHFS_Format(0);
437 objper
.Operation
= OBJECTPERSISTENCE_OPERATION_COMPLETED
;
438 ObjectPersistenceSet(&objper
);
441 objper
.Operation
= OBJECTPERSISTENCE_OPERATION_ERROR
;
442 ObjectPersistenceSet(&objper
);
451 * Called whenever hardware settings changed
453 static void checkSettingsUpdatedCb(__attribute__((unused
)) UAVObjEvent
*ev
)
455 HwSettingsData currentHwSettings
;
457 HwSettingsGet(¤tHwSettings
);
458 FrameType_t currentFrameType
= GetCurrentFrameType();
459 // check whether the Hw Configuration has changed from the one used at boot time
460 if ((memcmp(&bootHwSettings
, ¤tHwSettings
, sizeof(HwSettingsData
)) != 0) ||
461 (currentFrameType
!= bootFrameType
)) {
462 ExtendedAlarmsSet(SYSTEMALARMS_ALARM_BOOTFAULT
, SYSTEMALARMS_ALARM_CRITICAL
, SYSTEMALARMS_EXTENDEDALARMSTATUS_REBOOTREQUIRED
, 0);
466 #ifdef PIOS_INCLUDE_RFM22B
468 * Called whenever OPLink settings changed
470 static void oplinkSettingsUpdatedCb(__attribute__((unused
)) UAVObjEvent
*ev
)
472 uint8_t currentRFXtalCap
;
474 OPLinkSettingsRFXtalCapGet(¤tRFXtalCap
);
476 // Check if RFXtalCap value changed
477 if (currentRFXtalCap
!= previousRFXtalCap
) {
478 PIOS_RFM22B_SetXtalCap(pios_rfm22b_id
, currentRFXtalCap
);
479 PIOS_RFM22B_Reinit(pios_rfm22b_id
);
480 previousRFXtalCap
= currentRFXtalCap
;
483 #endif /* ifdef PIOS_INCLUDE_RFM22B */
486 static void taskMonitorForEachCallback(uint16_t task_id
, const struct pios_task_info
*task_info
, void *context
)
488 TaskInfoData
*taskData
= (TaskInfoData
*)context
;
490 // By convention, there is a direct mapping between task monitor task_id's and members
491 // of the TaskInfoXXXXElem enums
492 PIOS_DEBUG_Assert(task_id
< TASKINFO_RUNNING_NUMELEM
);
493 TaskInfoRunningToArray(taskData
->Running
)[task_id
] = task_info
->is_running
? TASKINFO_RUNNING_TRUE
: TASKINFO_RUNNING_FALSE
;
494 ((uint16_t *)&taskData
->StackRemaining
)[task_id
] = task_info
->stack_remaining
;
495 ((uint8_t *)&taskData
->RunningTime
)[task_id
] = task_info
->running_time_percentage
;
498 static void callbackSchedulerForEachCallback(int16_t callback_id
, const struct pios_callback_info
*callback_info
, void *context
)
500 CallbackInfoData
*callbackData
= (CallbackInfoData
*)context
;
502 if (callback_id
< 0) {
505 // delayed callback scheduler reports callback stack overflows as remaininng: -1
506 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32)
507 if (callback_info
->stack_remaining
< 0 && stackOverflow
== STACKOVERFLOW_NONE
) {
508 stackOverflow
= STACKOVERFLOW_WARNING
;
511 // By convention, there is a direct mapping between (not negative) callback scheduler callback_id's and members
512 // of the CallbackInfoXXXXElem enums
513 PIOS_DEBUG_Assert(callback_id
< CALLBACKINFO_RUNNING_NUMELEM
);
514 ((uint8_t *)&callbackData
->Running
)[callback_id
] = callback_info
->is_running
;
515 ((uint32_t *)&callbackData
->RunningTime
)[callback_id
] = callback_info
->running_time_count
;
516 ((int16_t *)&callbackData
->StackRemaining
)[callback_id
] = callback_info
->stack_remaining
;
518 #endif /* ifdef DIAG_TASKS */
521 * Called periodically (every SYSTEM_UPDATE_PERIOD_MS milliseconds) to update the I2C statistics
523 static void updateI2Cstats()
525 #if defined(PIOS_INCLUDE_I2C)
526 static uint8_t previous_error_counts
[PIOS_I2C_ERROR_COUNT_NUMELEM
];
528 struct pios_i2c_fault_history history
;
529 uint8_t error_counts
[PIOS_I2C_ERROR_COUNT_NUMELEM
];
531 PIOS_I2C_GetDiagnostics(&history
, error_counts
);
533 // every time a counter changes, set activity timeout counter to ( I2C_ERROR_ACTIVITY_TIMEOUT ).
534 // every time a counter does not change, decrease activity counter.
536 for (uint8_t i
= 0; i
< PIOS_I2C_ERROR_COUNT_NUMELEM
; i
++) {
537 if (error_counts
[i
] != previous_error_counts
[i
]) {
538 i2c_error_activity
[i
] = I2C_ERROR_ACTIVITY_TIMEOUT
;
539 } else if (i2c_error_activity
[i
] > 0) {
540 i2c_error_activity
[i
]--;
543 previous_error_counts
[i
] = error_counts
[i
];
546 #ifdef DIAG_I2C_WDG_STATS
547 I2CStatsData i2cStats
;
548 I2CStatsGet(&i2cStats
);
550 memcpy(&i2cStats
.event_errors
, &error_counts
, sizeof(error_counts
));
552 for (uint8_t i
= 0; (i
< I2C_LOG_DEPTH
) && (i
< I2CSTATS_EVENT_LOG_NUMELEM
); i
++) {
553 i2cStats
.evirq_log
[i
] = history
.evirq
[i
];
554 i2cStats
.erirq_log
[i
] = history
.erirq
[i
];
555 i2cStats
.event_log
[i
] = history
.event
[i
];
556 i2cStats
.state_log
[i
] = history
.state
[i
];
558 i2cStats
.last_error_type
= history
.type
;
559 I2CStatsSet(&i2cStats
);
560 #endif /* DIAG_I2C_WDG_STATS */
561 #endif /* PIOS_INCLUDE_I2C */
564 #ifdef DIAG_I2C_WDG_STATS
565 static void updateWDGstats()
567 WatchdogStatusData watchdogStatus
;
569 watchdogStatus
.BootupFlags
= PIOS_WDG_GetBootupFlags();
570 watchdogStatus
.ActiveFlags
= PIOS_WDG_GetActiveFlags();
571 WatchdogStatusSet(&watchdogStatus
);
573 #endif /* ifdef DIAG_I2C_WDG_STATS */
576 * Called periodically to update the system stats
578 static uint16_t GetFreeIrqStackSize(void)
582 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK)
583 extern uint32_t _irq_stack_top
;
584 extern uint32_t _irq_stack_end
;
585 uint32_t pattern
= 0x0000A5A5;
586 uint32_t *ptr
= &_irq_stack_end
;
588 #if 1 /* the ugly way accurate but takes more time, useful for debugging */
589 uint32_t stack_size
= (((uint32_t)&_irq_stack_top
- (uint32_t)&_irq_stack_end
) & ~3) / 4;
591 for (i
= 0; i
< stack_size
; i
++) {
592 if (ptr
[i
] != pattern
) {
597 #else /* faster way but not accurate */
598 if (*(volatile uint32_t *)((uint32_t)ptr
+ IRQSTACK_LIMIT_CRITICAL
) != pattern
) {
599 i
= IRQSTACK_LIMIT_CRITICAL
- 1;
600 } else if (*(volatile uint32_t *)((uint32_t)ptr
+ IRQSTACK_LIMIT_WARNING
) != pattern
) {
601 i
= IRQSTACK_LIMIT_WARNING
- 1;
603 i
= IRQSTACK_LIMIT_WARNING
;
606 #endif /* if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK) */
611 * Called periodically to update the system stats
613 static void updateStats()
615 SystemStatsData stats
;
617 // Get stats and update
618 SystemStatsGet(&stats
);
619 stats
.FlightTime
= xTaskGetTickCount() * portTICK_RATE_MS
;
620 #if defined(ARCH_POSIX) || defined(ARCH_WIN32)
621 // POSIX port of FreeRTOS doesn't have xPortGetFreeHeapSize()
622 stats
.SystemModStackRemaining
= 128;
623 stats
.HeapRemaining
= 10240;
625 stats
.HeapRemaining
= xPortGetFreeHeapSize();
626 stats
.SystemModStackRemaining
= uxTaskGetStackHighWaterMark(NULL
) * 4;
629 // Get Irq stack status
630 stats
.IRQStackRemaining
= GetFreeIrqStackSize();
632 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(PIOS_INCLUDE_FLASH_LOGFS_SETTINGS)
633 static struct PIOS_FLASHFS_Stats fsStats
;
635 if (pios_uavo_settings_fs_id
) {
636 PIOS_FLASHFS_GetStats(pios_uavo_settings_fs_id
, &fsStats
);
637 stats
.SysSlotsFree
= fsStats
.num_free_slots
;
638 stats
.SysSlotsActive
= fsStats
.num_active_slots
;
640 if (pios_user_fs_id
) {
641 PIOS_FLASHFS_GetStats(pios_user_fs_id
, &fsStats
);
642 stats
.UsrSlotsFree
= fsStats
.num_free_slots
;
643 stats
.UsrSlotsActive
= fsStats
.num_active_slots
;
646 stats
.CPUIdleTicks
= PIOS_TASK_MONITOR_GetIdleTicksCount();
647 stats
.CPUZeroLoadTicks
= PIOS_TASK_MONITOR_GetZeroLoadTicksCount();
648 stats
.CPULoad
= 100 - (uint8_t)((100 * stats
.CPUIdleTicks
) / stats
.CPUZeroLoadTicks
);
650 #if defined(PIOS_INCLUDE_ADC) && defined(PIOS_ADC_USE_TEMP_SENSOR)
651 float temp_voltage
= PIOS_ADC_PinGetVolt(PIOS_ADC_TEMPERATURE_PIN
);
652 stats
.CPUTemp
= PIOS_CONVERT_VOLT_TO_CPU_TEMP(temp_voltage
);;
654 SystemStatsSet(&stats
);
658 * Update system alarms
660 static void updateSystemAlarms()
662 SystemStatsData stats
;
663 UAVObjStats objStats
;
666 SystemStatsGet(&stats
);
668 // Check heap, IRQ stack and malloc failures
669 if (mallocFailed
|| (stats
.HeapRemaining
< HEAP_LIMIT_CRITICAL
)
670 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK)
671 || (stats
.IRQStackRemaining
< IRQSTACK_LIMIT_CRITICAL
)
674 AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY
, SYSTEMALARMS_ALARM_CRITICAL
);
675 } else if ((stats
.HeapRemaining
< HEAP_LIMIT_WARNING
)
676 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK)
677 || (stats
.IRQStackRemaining
< IRQSTACK_LIMIT_WARNING
)
680 AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY
, SYSTEMALARMS_ALARM_WARNING
);
682 AlarmsClear(SYSTEMALARMS_ALARM_OUTOFMEMORY
);
686 if (stats
.CPULoad
> CPULOAD_LIMIT_CRITICAL
) {
687 AlarmsSet(SYSTEMALARMS_ALARM_CPUOVERLOAD
, SYSTEMALARMS_ALARM_CRITICAL
);
688 } else if (stats
.CPULoad
> CPULOAD_LIMIT_WARNING
) {
689 AlarmsSet(SYSTEMALARMS_ALARM_CPUOVERLOAD
, SYSTEMALARMS_ALARM_WARNING
);
691 AlarmsClear(SYSTEMALARMS_ALARM_CPUOVERLOAD
);
694 // Check for stack overflow
695 switch (stackOverflow
) {
696 case STACKOVERFLOW_NONE
:
697 AlarmsClear(SYSTEMALARMS_ALARM_STACKOVERFLOW
);
699 case STACKOVERFLOW_WARNING
:
700 AlarmsSet(SYSTEMALARMS_ALARM_STACKOVERFLOW
, SYSTEMALARMS_ALARM_WARNING
);
703 AlarmsSet(SYSTEMALARMS_ALARM_STACKOVERFLOW
, SYSTEMALARMS_ALARM_CRITICAL
);
706 // Check for event errors
707 UAVObjGetStats(&objStats
);
708 EventGetStats(&evStats
);
711 if (objStats
.eventCallbackErrors
> 0 || objStats
.eventQueueErrors
> 0 || evStats
.eventErrors
> 0) {
712 AlarmsSet(SYSTEMALARMS_ALARM_EVENTSYSTEM
, SYSTEMALARMS_ALARM_WARNING
);
714 AlarmsClear(SYSTEMALARMS_ALARM_EVENTSYSTEM
);
717 if (objStats
.lastCallbackErrorID
|| objStats
.lastQueueErrorID
|| evStats
.lastErrorID
) {
718 SystemStatsData sysStats
;
719 SystemStatsGet(&sysStats
);
720 sysStats
.EventSystemWarningID
= evStats
.lastErrorID
;
721 sysStats
.ObjectManagerCallbackID
= objStats
.lastCallbackErrorID
;
722 sysStats
.ObjectManagerQueueID
= objStats
.lastQueueErrorID
;
723 SystemStatsSet(&sysStats
);
726 #ifdef PIOS_INCLUDE_I2C
727 if (AlarmsGet(SYSTEMALARMS_ALARM_I2C
) != SYSTEMALARMS_ALARM_UNINITIALISED
) {
728 static const SystemAlarmsAlarmOptions i2c_alarm_by_error
[] = {
729 [PIOS_I2C_BAD_EVENT_COUNTER
] = SYSTEMALARMS_ALARM_ERROR
,
730 [PIOS_I2C_FSM_FAULT_COUNT
] = SYSTEMALARMS_ALARM_ERROR
,
731 [PIOS_I2C_ERROR_INTERRUPT_COUNTER
] = SYSTEMALARMS_ALARM_ERROR
,
732 [PIOS_I2C_NACK_COUNTER
] = SYSTEMALARMS_ALARM_CRITICAL
,
733 [PIOS_I2C_TIMEOUT_COUNTER
] = SYSTEMALARMS_ALARM_ERROR
,
736 SystemAlarmsAlarmOptions i2c_alarm
= SYSTEMALARMS_ALARM_OK
;
738 for (uint8_t i
= 0; i
< PIOS_I2C_ERROR_COUNT_NUMELEM
; i
++) {
739 if ((i2c_error_activity
[i
] > 0) && (i2c_alarm
< i2c_alarm_by_error
[i
])) {
740 i2c_alarm
= i2c_alarm_by_error
[i
];
744 AlarmsSet(SYSTEMALARMS_ALARM_I2C
, i2c_alarm
);
746 #endif /* PIOS_INCLUDE_I2C */
750 * Called by the RTOS when the CPU is idle,
752 void vApplicationIdleHook(void)
754 PIOS_TASK_MONITOR_IdleHook();
755 NotificationOnboardLedsRun();
756 #ifdef PIOS_INCLUDE_WS2811
757 LedNotificationExtLedsRun();
761 * Called by the RTOS when a stack overflow is detected.
763 #define DEBUG_STACK_OVERFLOW 0
764 void vApplicationStackOverflowHook(__attribute__((unused
)) xTaskHandle
*pxTask
,
765 __attribute__((unused
)) signed portCHAR
*pcTaskName
)
767 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32)
768 stackOverflow
= STACKOVERFLOW_CRITICAL
;
769 #if DEBUG_STACK_OVERFLOW
770 static volatile bool wait_here
= true;
780 * Called by the RTOS when a malloc call fails.
782 #define DEBUG_MALLOC_FAILURES 0
783 void vApplicationMallocFailedHook(void)
786 #if DEBUG_MALLOC_FAILURES
787 static volatile bool wait_here
= true;