Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
preflight_checks.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2022 Freek van Tienen <freek.v.tienen@gmail.com>
3  *
4  * This file is part of paparazzi
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
27 #include "preflight_checks.h"
29 #include <stdio.h>
30 
32 #ifndef PREFLIGHT_CHECK_MAX_MSGBUF
33 #define PREFLIGHT_CHECK_MAX_MSGBUF 1024
34 #endif
35 
37 #ifndef PREFLIGHT_CHECK_SEPERATOR
38 #define PREFLIGHT_CHECK_SEPERATOR ';'
39 #endif
40 
42 #ifndef PREFLIGHT_CHECK_INFO_TIMEOUT
43 #define PREFLIGHT_CHECK_INFO_TIMEOUT 5
44 #endif
45 
47 #ifndef PREFLIGHT_CHECK_GROUND
48 #define PREFLIGHT_CHECK_GROUND TRUE
49 #endif
50 
52 #ifndef PREFLIGHT_CHECK_BYPASS
53 #define PREFLIGHT_CHECK_BYPASS FALSE
54 #endif
55 
57 bool preflight_ground_done = false;
58 
59 static struct preflight_check_t *preflight_head = NULL;
60 
68 {
69  // Prepend the preflight check
71  preflight_head = check;
72  check->func = func;
73  check->next = next;
74 }
75 
82 bool preflight_check(void)
83 {
84  static float last_info_time = 0;
85  char error_msg[PREFLIGHT_CHECK_MAX_MSGBUF];
86  struct preflight_result_t result = {
87  .message = error_msg,
88  .max_len = PREFLIGHT_CHECK_MAX_MSGBUF,
89  .fail_cnt = 0,
90  .warning_cnt = 0,
91  .success_cnt = 0
92  };
93 
94  // Go through all the checks
95  struct preflight_check_t *check = preflight_head;
96  while (check != NULL) {
97  // Peform the check and register errors
98  check->func(&result);
99  check = check->next;
100  }
101 
102  // Add the ground check
103 #if PREFLIGHT_CHECK_GROUND
104  if (!preflight_ground_done) {
105  preflight_error(&result, "Ground checks not done");
106  } else {
107  preflight_success(&result, "Ground checks done");
108  }
109 #endif
110 
111  // We failed a check or have a warning
112  if (result.fail_cnt > 0 || result.warning_cnt > 0) {
113  // Only send every xx amount of seconds
114  if ((get_sys_time_float() - last_info_time) > PREFLIGHT_CHECK_INFO_TIMEOUT) {
115  // Record the total
116  int rc = 0;
117  if (result.fail_cnt > 0) {
118  rc = snprintf(result.message, result.max_len, "*Preflight fail [fail:%d warn:%d tot:%d]*", result.fail_cnt,
119  result.warning_cnt, (result.fail_cnt + result.warning_cnt + result.success_cnt));
120  } else {
121  rc = snprintf(result.message, result.max_len, "*Preflight success with warnings [%d/%d]*", result.warning_cnt,
122  (result.fail_cnt + result.warning_cnt + result.success_cnt));
123  }
124  if (rc > 0) {
125  result.max_len -= rc;
126  }
127 
128  // Send the errors seperatly
129  uint16_t last_sendi = 0;
130  for (uint16_t i = 0; i <= PREFLIGHT_CHECK_MAX_MSGBUF - result.max_len; i++) {
131  if (error_msg[i] == PREFLIGHT_CHECK_SEPERATOR || i == (PREFLIGHT_CHECK_MAX_MSGBUF - result.max_len)) {
132  DOWNLINK_SEND_INFO_MSG(DefaultChannel, DefaultDevice, i - last_sendi, &error_msg[last_sendi]);
133  last_sendi = i + 1;
134  }
135  }
136 
137  // Update the time
138  last_info_time = get_sys_time_float();
139  }
140 
141  // Only if we fail a check
142  if (result.fail_cnt > 0) {
143  return false;
144  } else {
145  return true;
146  }
147  }
148 
149  // Send success down
150  int rc = snprintf(error_msg, PREFLIGHT_CHECK_MAX_MSGBUF, "Preflight success [%d]", result.success_cnt);
151  if (rc > 0) {
152  DOWNLINK_SEND_INFO_MSG(DefaultChannel, DefaultDevice, rc, error_msg);
153  }
154 
155  // Return success if we didn't fail a preflight check
156  return true;
157 }
158 
166 void preflight_error(struct preflight_result_t *result, const char *fmt, ...)
167 {
168  // Record the error count
169  result->fail_cnt++;
170 
171  // No more space in the message
172  if (result->max_len <= 0) {
173  return;
174  }
175 
176  // Add the error
177  va_list args;
178  va_start(args, fmt);
179  int rc = vsnprintf(result->message, result->max_len, fmt, args);
180  va_end(args);
181 
182  // Remove the length from the buffer if it was successfull
183  if (rc > 0) {
184  result->max_len -= rc;
185  result->message += rc;
186 
187  // Add seperator if it fits
188  if (result->max_len > 0) {
189  result->message[0] = PREFLIGHT_CHECK_SEPERATOR;
190  result->max_len--;
191  result->message++;
192 
193  // Add the '\0' character
194  if (result->max_len > 0) {
195  result->message[0] = 0;
196  }
197  }
198  }
199 }
200 
208 void preflight_warning(struct preflight_result_t *result, const char *fmt, ...)
209 {
210  // Record the warning count
211  result->warning_cnt++;
212 
213  // No more space in the message
214  if (result->max_len <= 0) {
215  return;
216  }
217 
218  // Add the warning to the error string
219  va_list args;
220  va_start(args, fmt);
221  int rc = vsnprintf(result->message, result->max_len, fmt, args);
222  va_end(args);
223 
224  // Remove the length from the buffer if it was successfull
225  if (rc > 0) {
226  result->max_len -= rc;
227  result->message += rc;
228 
229  // Add seperator if it fits
230  if (result->max_len > 0) {
231  result->message[0] = PREFLIGHT_CHECK_SEPERATOR;
232  result->max_len--;
233  result->message++;
234 
235  // Add the '\0' character
236  if (result->max_len > 0) {
237  result->message[0] = 0;
238  }
239  }
240  }
241 }
242 
250 void preflight_success(struct preflight_result_t *result, const char *fmt __attribute__((unused)), ...)
251 {
252  // Record the success count
253  result->success_cnt++;
254 }
#define PREFLIGHT_CHECK_INFO_TIMEOUT
Only send messages down every xx amount of seconds.
#define PREFLIGHT_CHECK_BYPASS
Bypass the preflight checks.
void preflight_error(struct preflight_result_t *result, const char *fmt,...)
Register a preflight error used inside the preflight checking functions.
void preflight_success(struct preflight_result_t *result, const char *fmt,...)
Register a preflight success used inside the preflight checking functions.
bool preflight_bypass
bool preflight_ground_done
static struct preflight_check_t * preflight_head
#define PREFLIGHT_CHECK_SEPERATOR
Seperating character for storing the errors.
void preflight_warning(struct preflight_result_t *result, const char *fmt,...)
Register a preflight warning used inside the preflight checking functions.
bool preflight_check(void)
Perform all the preflight checks.
void preflight_check_register(struct preflight_check_t *check, preflight_check_f func)
Register a preflight check and add it to the linked list.
#define PREFLIGHT_CHECK_MAX_MSGBUF
Maximum combined message size for storing the errors.
preflight_check_f func
void(* preflight_check_f)(struct preflight_result_t *result)
struct preflight_check_t * next
static float get_sys_time_float(void)
Get the time in seconds since startup.
Definition: sys_time.h:138
Periodic telemetry system header (includes downlink utility and generated code).
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
Definition: vl53l1_types.h:88