2 ******************************************************************************
3 * @addtogroup OpenPilotSystem OpenPilot System
5 * @addtogroup OpenPilotLibraries OpenPilot System Libraries
6 * @brief OpenPilot System libraries are available to all OP modules.
9 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016.
10 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
11 * @brief Library for setting and clearing system alarms
12 * @see The GNU Public License (GPL) Version 3
14 *****************************************************************************/
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 3 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include <openpilot.h>
32 #include "inc/alarms.h"
35 #ifndef PIOS_ALARM_GRACETIME
36 // alarm cannot be turned off for at least 1000 milliseconds
37 // to prevent event system overload through flapping alarms
38 #define PIOS_ALARM_GRACETIME 1000
39 #endif // PIOS_ALARM_GRACETIME
44 static xSemaphoreHandle lock
;
45 static volatile uint16_t lastAlarmChange
[SYSTEMALARMS_ALARM_NUMELEM
] = { 0 }; // this deliberately overflows every 2^16 milliseconds to save memory
48 static int32_t hasSeverity(SystemAlarmsAlarmOptions severity
);
51 * Initialize the alarms library
53 int32_t AlarmsInitialize(void)
55 SystemAlarmsInitialize();
57 lock
= xSemaphoreCreateRecursiveMutex();
58 // do not change the default states of the alarms, let the init code generated by the uavobjectgenerator handle that
60 // AlarmsDefaultAll();
66 * @param alarm The system alarm to be modified
67 * @param severity The alarm severity
68 * @return 0 if success, -1 if an error
70 int32_t AlarmsSet(SystemAlarmsAlarmElem alarm
, SystemAlarmsAlarmOptions severity
)
72 SystemAlarmsAlarmData alarms
;
74 // Check that this is a valid alarm
75 if (alarm
>= SYSTEMALARMS_ALARM_NUMELEM
) {
80 xSemaphoreTakeRecursive(lock
, portMAX_DELAY
);
82 // Read alarm and update its severity only if it was changed
83 SystemAlarmsAlarmGet(&alarms
);
84 uint16_t flightTime
= (uint16_t)xTaskGetTickCount() * (uint16_t)portTICK_RATE_MS
; // this deliberately overflows every 2^16 milliseconds to save memory
85 if (((uint16_t)(flightTime
- lastAlarmChange
[alarm
]) > PIOS_ALARM_GRACETIME
&&
86 SystemAlarmsAlarmToArray(alarms
)[alarm
] != severity
)
87 || SystemAlarmsAlarmToArray(alarms
)[alarm
] < severity
) {
88 SystemAlarmsAlarmToArray(alarms
)[alarm
] = severity
;
89 lastAlarmChange
[alarm
] = flightTime
;
90 SystemAlarmsAlarmSet(&alarms
);
94 xSemaphoreGiveRecursive(lock
);
99 * Set an Extended Alarm
100 * @param alarm The system alarm to be modified
101 * @param severity The alarm severity
102 * @param status The Extended alarm status field
103 * @param subStatus The Extended alarm substatus field
104 * @return 0 if success, -1 if an error
106 int32_t ExtendedAlarmsSet(SystemAlarmsAlarmElem alarm
,
107 SystemAlarmsAlarmOptions severity
,
108 SystemAlarmsExtendedAlarmStatusOptions status
,
111 SystemAlarmsData alarms
;
113 // Check that this is a valid alarm
114 if (alarm
>= SYSTEMALARMS_EXTENDEDALARMSTATUS_NUMELEM
) {
119 xSemaphoreTakeRecursive(lock
, portMAX_DELAY
);
121 // Read alarm and update its severity only if it was changed
122 SystemAlarmsGet(&alarms
);
123 uint16_t flightTime
= (uint16_t)xTaskGetTickCount() * (uint16_t)portTICK_RATE_MS
; // this deliberately overflows every 2^16 milliseconds to save memory
124 if (((uint16_t)(flightTime
- lastAlarmChange
[alarm
]) > PIOS_ALARM_GRACETIME
&&
125 SystemAlarmsAlarmToArray(alarms
.Alarm
)[alarm
] != severity
)
126 || SystemAlarmsAlarmToArray(alarms
.Alarm
)[alarm
] < severity
) {
127 SystemAlarmsExtendedAlarmStatusToArray(alarms
.ExtendedAlarmStatus
)[alarm
] = status
;
128 SystemAlarmsExtendedAlarmSubStatusToArray(alarms
.ExtendedAlarmSubStatus
)[alarm
] = subStatus
;
129 SystemAlarmsAlarmToArray(alarms
.Alarm
)[alarm
] = severity
;
130 lastAlarmChange
[alarm
] = flightTime
;
131 SystemAlarmsSet(&alarms
);
135 xSemaphoreGiveRecursive(lock
);
141 * @param alarm The system alarm to be read
142 * @return Alarm severity
144 SystemAlarmsAlarmOptions
AlarmsGet(SystemAlarmsAlarmElem alarm
)
146 SystemAlarmsAlarmData alarms
;
148 // Check that this is a valid alarm
149 if (alarm
>= SYSTEMALARMS_ALARM_NUMELEM
) {
154 SystemAlarmsAlarmGet(&alarms
);
155 return SystemAlarmsAlarmToArray(alarms
)[alarm
];
159 * Set an alarm to it's default value
160 * @param alarm The system alarm to be modified
161 * @return 0 if success, -1 if an error
163 int32_t AlarmsDefault(SystemAlarmsAlarmElem alarm
)
165 return AlarmsSet(alarm
, SYSTEMALARMS_ALARM_DEFAULT
);
171 void AlarmsDefaultAll()
173 for (uint32_t n
= 0; n
< SYSTEMALARMS_ALARM_NUMELEM
; ++n
) {
180 * @param alarm The system alarm to be modified
181 * @return 0 if success, -1 if an error
183 int32_t AlarmsClear(SystemAlarmsAlarmElem alarm
)
185 if (alarm
< SYSTEMALARMS_EXTENDEDALARMSTATUS_NUMELEM
) {
186 return ExtendedAlarmsSet(alarm
, SYSTEMALARMS_ALARM_OK
, SYSTEMALARMS_EXTENDEDALARMSTATUS_NONE
, 0);
188 return AlarmsSet(alarm
, SYSTEMALARMS_ALARM_OK
);
195 void AlarmsClearAll()
197 for (uint32_t n
= 0; n
< SYSTEMALARMS_ALARM_NUMELEM
; ++n
) {
203 * Check if there are any alarms with the given or higher severity
204 * @return 0 if no alarms are found, 1 if at least one alarm is found
206 int32_t AlarmsHasWarnings()
208 return hasSeverity(SYSTEMALARMS_ALARM_WARNING
);
212 * Check if there are any alarms with error or higher severity
213 * @return 0 if no alarms are found, 1 if at least one alarm is found
215 int32_t AlarmsHasErrors()
217 return hasSeverity(SYSTEMALARMS_ALARM_ERROR
);
222 * Check if there are any alarms with critical or higher severity
223 * @return 0 if no alarms are found, 1 if at least one alarm is found
225 int32_t AlarmsHasCritical()
227 return hasSeverity(SYSTEMALARMS_ALARM_CRITICAL
);
232 * Check if there are any alarms with the given or higher severity
233 * @return 0 if no alarms are found, 1 if at least one alarm is found
235 static int32_t hasSeverity(SystemAlarmsAlarmOptions severity
)
237 SystemAlarmsAlarmData alarms
;
240 xSemaphoreTakeRecursive(lock
, portMAX_DELAY
);
243 SystemAlarmsAlarmGet(&alarms
);
245 // Go through alarms and check if any are of the given severity or higher
246 for (uint32_t n
= 0; n
< SYSTEMALARMS_ALARM_NUMELEM
; ++n
) {
247 if (SystemAlarmsAlarmToArray(alarms
)[n
] >= severity
) {
248 xSemaphoreGiveRecursive(lock
);
253 // If this point is reached then no alarms found
254 xSemaphoreGiveRecursive(lock
);
258 * Get the highest alarm severity
261 SystemAlarmsAlarmOptions
AlarmsGetHighestSeverity()
263 SystemAlarmsAlarmData alarmsData
;
264 SystemAlarmsAlarmOptions highest
= SYSTEMALARMS_ALARM_UNINITIALISED
;
267 xSemaphoreTakeRecursive(lock
, portMAX_DELAY
);
270 SystemAlarmsAlarmGet(&alarmsData
);
272 // Go through alarms and find the highest severity
274 while (n
< SYSTEMALARMS_ALARM_NUMELEM
&& highest
!= SYSTEMALARMS_ALARM_CRITICAL
) {
275 if (SystemAlarmsAlarmToArray(alarmsData
)[n
] > highest
) {
276 highest
= SystemAlarmsAlarmToArray(alarmsData
)[n
];
281 xSemaphoreGiveRecursive(lock
);
286 static const char *const systemalarms_severity_names
[] = {
287 [SYSTEMALARMS_ALARM_UNINITIALISED
] = "UNINITIALISED",
288 [SYSTEMALARMS_ALARM_OK
] = "OK",
289 [SYSTEMALARMS_ALARM_WARNING
] = "WARNING",
290 [SYSTEMALARMS_ALARM_CRITICAL
] = "CRITICAL",
291 [SYSTEMALARMS_ALARM_ERROR
] = "ERROR"
294 static const char *const systemalarms_alarm_names
[] = {
295 [SYSTEMALARMS_ALARM_SYSTEMCONFIGURATION
] = "CONFIG",
296 [SYSTEMALARMS_ALARM_BOOTFAULT
] = "BOOT",
297 [SYSTEMALARMS_ALARM_OUTOFMEMORY
] = "MEM",
298 [SYSTEMALARMS_ALARM_STACKOVERFLOW
] = "STACK",
299 [SYSTEMALARMS_ALARM_CPUOVERLOAD
] = "CPU",
300 [SYSTEMALARMS_ALARM_EVENTSYSTEM
] = "EVENT",
301 [SYSTEMALARMS_ALARM_TELEMETRY
] = "TELEMETRY",
302 [SYSTEMALARMS_ALARM_RECEIVER
] = "INPUT",
303 [SYSTEMALARMS_ALARM_MANUALCONTROL
] = "MANUAL",
304 [SYSTEMALARMS_ALARM_ACTUATOR
] = "ACTUATOR",
305 [SYSTEMALARMS_ALARM_ATTITUDE
] = "ATTI",
306 [SYSTEMALARMS_ALARM_SENSORS
] = "SENSOR",
307 [SYSTEMALARMS_ALARM_MAGNETOMETER
] = "MAG",
308 [SYSTEMALARMS_ALARM_AIRSPEED
] = "AIRSPD",
309 [SYSTEMALARMS_ALARM_STABILIZATION
] = "STAB",
310 [SYSTEMALARMS_ALARM_NAV
] = "NAV",
311 [SYSTEMALARMS_ALARM_GUIDANCE
] = "GUIDANCE",
312 [SYSTEMALARMS_ALARM_PATHPLAN
] = "PLAN",
313 [SYSTEMALARMS_ALARM_BATTERY
] = "BATT",
314 [SYSTEMALARMS_ALARM_FLIGHTTIME
] = "TIME",
315 [SYSTEMALARMS_ALARM_I2C
] = "I2C",
316 [SYSTEMALARMS_ALARM_GPS
] = "GPS",
319 static const char *const systemalarms_extendedalarmstatus_names
[] = {
320 [SYSTEMALARMS_EXTENDEDALARMSTATUS_REBOOTREQUIRED
] = "CFG:REBOOT",
321 [SYSTEMALARMS_EXTENDEDALARMSTATUS_FLIGHTMODE
] = "CFG:FLIGHTMODE",
322 [SYSTEMALARMS_EXTENDEDALARMSTATUS_UNSUPPORTEDCONFIG_ONESHOT
] = "CFG:ONESHOT",
323 [SYSTEMALARMS_EXTENDEDALARMSTATUS_BADTHROTTLEORCOLLECTIVEINPUTRANGE
] = "CFG:THR-COL",
326 size_t AlarmString(SystemAlarmsData
*alarm
, char *buffer
, size_t buffer_size
, SystemAlarmsAlarmOptions level
, SystemAlarmsAlarmOptions
*highestSeverity
)
330 PIOS_STATIC_ASSERT(NELEMENTS(systemalarms_alarm_names
) == SYSTEMALARMS_ALARM_NUMELEM
);
332 for (unsigned severity
= SYSTEMALARMS_ALARM_ERROR
; severity
>= level
; --severity
) {
333 // should we prepend severity level here? No, not for now.
335 for (unsigned i
= 0; i
< SYSTEMALARMS_ALARM_NUMELEM
; ++i
) {
336 if ((SystemAlarmsAlarmToArray(alarm
->Alarm
)[i
] == severity
)
337 && (systemalarms_alarm_names
[i
])) {
338 if (highestSeverity
) { // they are already sorted by severity as we are processing in specific order
339 *highestSeverity
= severity
;
343 // in which case should we dig into extended alarm status?
344 // looks like SYSTEMALARMS_ALARM_SYSTEMCONFIGURATION sets most of the extended alarms
345 // except SYSTEMALARMS_ALARM_BOOTFAULT which also sets SYSTEMALARMS_EXTENDEDALARMSTATUS_REBOOTREQUIRED
347 const char *current_msg
= systemalarms_alarm_names
[i
];
350 case SYSTEMALARMS_ALARM_SYSTEMCONFIGURATION
:
351 if (alarm
->ExtendedAlarmStatus
.SystemConfiguration
< NELEMENTS(systemalarms_extendedalarmstatus_names
)) {
352 current_msg
= systemalarms_extendedalarmstatus_names
[alarm
->ExtendedAlarmStatus
.SystemConfiguration
];
356 case SYSTEMALARMS_ALARM_BOOTFAULT
:
357 if (alarm
->ExtendedAlarmStatus
.BootFault
< NELEMENTS(systemalarms_extendedalarmstatus_names
)) {
358 current_msg
= systemalarms_extendedalarmstatus_names
[alarm
->ExtendedAlarmStatus
.BootFault
];
363 int current_len
= strlen(current_msg
);
365 if ((pos
+ current_len
+ 1) > buffer_size
) {
369 memcpy(buffer
+ pos
, current_msg
, current_len
);
379 --pos
; // get rid of that trailing separator.
384 return pos
; // return length of the string in buffer. Actual bytes written is +1