GCC Code Coverage Report


Directory: /home/runner/work/Flight-Computer-Firmware/Flight-Computer-Firmware/app/rev2/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 129 / 0 / 129
Functions: 100.0% 3 / 0 / 3
Branches: 94.7% 71 / 0 / 75

prelaunch.c
Line Branch Exec Source
1 /*******************************************************************************
2 * *
3 * FILE: *
4 * prelaunch.c *
5 * *
6 * DESCRIPTION: *
7 * Non-flight-qualified partition of APPA. Contains application loop for *
8 * idle state. *
9 * *
10 * CRITICALITY: *
11 * NFQ - Non-Flight Qualified *
12 * *
13 * COPYRIGHT: *
14 * Copyright (c) 2025 Sun Devil Rocketry. *
15 * All rights reserved. *
16 * *
17 * This software is licensed under terms that can be found in the LICENSE *
18 * file in the root directory of this software component. *
19 * If no LICENSE file comes with this software, it is covered under the *
20 * BSD-3-Clause. *
21 * *
22 * https://opensource.org/license/bsd-3-clause *
23 * *
24 *******************************************************************************/
25
26 /*------------------------------------------------------------------------------
27 Includes
28 ------------------------------------------------------------------------------*/
29 #include <string.h>
30 #include "main.h"
31 #include "led.h"
32 #include "usb.h"
33 #include "math.h"
34 #include "sensor.h"
35 #include "lora.h"
36 #include "error_sdr.h"
37 #include "math_sdr.h"
38 #include "commands.h"
39 #include "ignition.h"
40 #include "buzzer.h"
41
42
43 /*------------------------------------------------------------------------------
44 Global Variables
45 ------------------------------------------------------------------------------*/
46 extern PRESET_DATA preset_data;
47 extern SENSOR_DATA sensor_data;
48
49 /*------------------------------------------------------------------------------
50 Functions
51 ------------------------------------------------------------------------------*/
52
53
54 /*******************************************************************************
55 * *
56 * PROCEDURE: *
57 * prelaunch_terminal *
58 * *
59 * DESCRIPTION: *
60 * Poll for USB input and execute terminal commands. *
61 * *
62 *******************************************************************************/
63 31 USB_STATUS prelaunch_terminal
64 (
65 uint8_t firmware_code,
66 FLASH_STATUS* flash_status,
67 HFLASH_BUFFER* flash_handle,
68 uint32_t* flash_address,
69 uint8_t* gps_mesg_byte,
70 SENSOR_STATUS* sensor_status
71 )
72 {
73 /*------------------------------------------------------------------------------
74 Local Variables
75 ------------------------------------------------------------------------------*/
76 31 USB_STATUS usb_status = USB_OK; /* USB Status*/
77 31 uint8_t usb_rx_data = 0; /* USB Incoming Data Buffer */
78 31 uint8_t subcommand_code = 0; /* USB Subcommand Buffer */
79
80 /*------------------------------------------------------------------------------
81 Terminal Command Handler
82 ------------------------------------------------------------------------------*/
83 31 led_set_color( LED_GREEN );
84
85
2/2
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 6 times.
31 if ( usb_detect() )
86 {
87 /* Poll usb port */
88 25 usb_status = usb_receive( &usb_rx_data,
89 sizeof( usb_rx_data ),
90 HAL_DEFAULT_TIMEOUT );
91
92 /* Parse input code */
93
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1 time.
25 if ( usb_status == USB_OK )
94 {
95
11/11
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 4 times.
✓ Branch 10 taken 1 time.
24 switch ( usb_rx_data )
96 {
97 /*-------------------------------------------------------------
98 PING_OP
99 -------------------------------------------------------------*/
100 1 case PING_OP:
101 {
102 /* Send board identifying code */
103 1 ping();
104
105 1 break;
106 } /* PING_OP */
107 /*-------------------------------------------------------------
108 CONNECT_OP
109 -------------------------------------------------------------*/
110 1 case CONNECT_OP:
111 {
112 /* Send board identifying code */
113 1 ping();
114
115 /* Send firmware identifying code */
116 1 usb_transmit( &firmware_code ,
117 sizeof( uint8_t ),
118 HAL_DEFAULT_TIMEOUT );
119 1 break;
120 } /* CONNECT_OP */
121
122 /*--------------------------------------------------------------
123 SENSOR Command
124 --------------------------------------------------------------*/
125 2 case SENSOR_OP:
126 {
127 2 USB_STATUS command_status; /* Status of USB HAL */
128 /* Receive sensor subcommand */
129 2 command_status = usb_receive( &subcommand_code ,
130 sizeof( subcommand_code ),
131 HAL_SENSOR_TIMEOUT );
132
133
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if ( command_status == USB_OK )
134 {
135 /* Execute sensor subcommand */
136 1 sensor_cmd_execute( subcommand_code );
137 }
138
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 else if ( command_status == USB_TIMEOUT )
139 {
140 break;
141 }
142 else
143 {
144 1 error_fail_fast( ERROR_SENSOR_CMD_ERROR );
145 }
146 break;
147 } /* SENSOR_OP */
148
149 /*-------------------------------------------------------------
150 FIN_OP
151 -------------------------------------------------------------*/
152 2 case FIN_OP:
153 {
154 2 usb_status = finCalibration( &usb_rx_data );
155
156
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if ( usb_status != USB_OK )
157 {
158 1 error_fail_fast( ERROR_SERVO_CMD_ERROR );
159 }
160
161
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 if ( write_preset( flash_handle, flash_address) != FLASH_OK )
162 {
163 1 error_fail_fast( ERROR_FLASH_CMD_ERROR );
164 }
165
166 break;
167 }
168
169 /*-------------------------------------------------------------
170 FLASH_OP
171 -------------------------------------------------------------*/
172 3 case FLASH_OP:
173 {
174 /* Recieve flash subcommand over USB */
175 3 usb_status = usb_receive( &subcommand_code ,
176 sizeof( subcommand_code ),
177 HAL_DEFAULT_TIMEOUT );
178
179 /* Execute subcommand */
180
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
3 if ( usb_status == USB_OK )
181 {
182
183 /* Execute the subcommand */
184 1 *flash_status = flash_cmd_execute( subcommand_code,
185 flash_handle );
186 }
187 else
188 {
189 /* Subcommand code not recieved */
190 2 error_fail_fast( ERROR_FLASH_CMD_ERROR );
191 }
192
193 /* Transmit status code to PC */
194 3 usb_status = usb_transmit( flash_status ,
195 sizeof( flash_status ),
196 HAL_DEFAULT_TIMEOUT );
197
198
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
3 if ( usb_status != USB_OK )
199 {
200 /* Status not transmitted properly */
201 1 error_fail_fast( ERROR_FLASH_CMD_ERROR );
202 }
203
204 break;
205 } /* FLASH_OP */
206
207 /*-------------------------------------------------------------
208 IGNITE_OP
209 -------------------------------------------------------------*/
210 2 case IGNITE_OP:
211 {
212 /* Recieve ignition subcommand over USB */
213 2 usb_status = usb_receive( &subcommand_code ,
214 sizeof( subcommand_code ),
215 HAL_DEFAULT_TIMEOUT );
216
217 /* Execute subcommand */
218
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if ( usb_status == USB_OK )
219 {
220 1 IGN_STATUS ign_status;
221 /* Execute subcommand*/
222 1 ign_status = ign_cmd_execute( subcommand_code );
223
224 /* Return response code to terminal */
225 1 usb_transmit( &ign_status,
226 sizeof( ign_status ),
227 HAL_DEFAULT_TIMEOUT );
228 }
229 else
230 {
231 /* Error: no subcommand recieved */
232 1 error_fail_fast( ERROR_IGN_CMD_ERROR );
233 }
234
235 break;
236 }
237 /*-------------------------------------------------------------
238 PRESET_OP
239 -------------------------------------------------------------*/
240 3 case PRESET_OP:
241 {
242 /* Recieve preset subcommand over USB */
243 3 usb_status = usb_receive( &subcommand_code ,
244 sizeof( subcommand_code ),
245 HAL_DEFAULT_TIMEOUT );
246
247 /* Execute subcommand */
248
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
3 if ( usb_status == USB_OK )
249 {
250 /* Execute the subcommand */
251 1 *flash_status = preset_cmd_execute( &subcommand_code,
252 flash_handle,
253 flash_address );
254 }
255 else
256 {
257 /* Subcommand code not recieved */
258 2 error_fail_fast( ERROR_FLASH_CMD_ERROR );
259 }
260
261 /* Transmit status code to PC */
262 3 usb_status = usb_transmit( flash_status ,
263 sizeof( flash_status ),
264 HAL_DEFAULT_TIMEOUT );
265
266
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
3 if ( usb_status != USB_OK )
267 {
268 /* Status not transmitted properly */
269 1 error_fail_fast( ERROR_FLASH_CMD_ERROR );
270 }
271
272 break;
273 } /* PRESET_OP */
274 /*--------------------------------------------------------------
275 SERVO Command
276 --------------------------------------------------------------*/
277 3 case SERVO_OP:
278 {
279 3 SERVO_STATUS servo_status = SERVO_FAIL;
280 /* Recieve servo subcommand over USB */
281 3 usb_status = usb_receive( &subcommand_code ,
282 sizeof( subcommand_code ),
283 HAL_DEFAULT_TIMEOUT );
284
285 /* Execute subcommand */
286
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 if ( usb_status == USB_OK )
287 {
288 2 servo_status = servo_cmd_execute( subcommand_code );
289 }
290
291
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if ( servo_status != SERVO_OK )
292 {
293 2 led_set_color( LED_RED );
294 2 HAL_Delay( 5000 );
295 }
296 break;
297 }
298 /*--------------------------------------------------------------
299 DASHBOARD Command
300 --------------------------------------------------------------*/
301 2 case DASHBOARD_OP:
302 {
303 2 usb_status = dashboard_dump();
304
305
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if ( usb_status == USB_FAIL )
306 {
307 1 error_fail_fast( ERROR_SENSOR_CMD_ERROR );
308 }
309 }
310 break;
311 /*-------------------------------------------------------------
312 LORA_OP
313 -------------------------------------------------------------*/
314 4 case LORA_OP:
315 {
316 4 uint8_t subcommand_code;
317 4 LORA_STATUS command_status;
318 /* Recieve telem subcommand over USB */
319 4 usb_status = usb_receive( &subcommand_code ,
320 sizeof( subcommand_code ),
321 HAL_DEFAULT_TIMEOUT );
322
323 /* Execute subcommand to mutate or transmit buffer */
324 4 command_status = lora_cmd_execute(subcommand_code, &(preset_data.lora_preset));
325
326
3/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 time.
4 if ( command_status == LORA_OK && subcommand_code == LORA_PRESET_UPLOAD )
327 {
328
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
3 if(write_preset(flash_handle, flash_address)) /* writes all presets */
329 {
330 1 error_fail_fast(ERROR_FLASH_CMD_ERROR);
331 }
332
333 /* Finally, re-configure the modem */
334
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
3 if ( lora_configure( &(preset_data.lora_preset) ) != LORA_OK ) /* also errors out if configs are invalid! */
335 {
336 1 error_fail_fast( ERROR_LORA_CMD_ERROR );
337 }
338 }
339
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 else if ( command_status != LORA_OK || subcommand_code != LORA_PRESET_DOWNLOAD )
340 {
341 /* unknown subcommand or usb fail */
342 1 error_fail_fast( ERROR_LORA_CMD_ERROR );
343 }
344 4 break;
345 }
346 /*-------------------------------------------------------------
347 Unrecognized command code
348 -------------------------------------------------------------*/
349 default:
350 {
351 // TODO: Give warning ( via error_fail_safe() )
352 //error_fail_fast();
353 break;
354 }
355
356 } /* switch( usb_rx_data ) */
357 } /* if ( usb_status != USB_OK ) */
358 } /* if ( usb_detect() )*/
359
360 /*------------------------------------------------------------------------------
361 Arm Flight Computer
362 ------------------------------------------------------------------------------*/
363
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 26 times.
31 if ( ign_switch_armed() ) /* Enter flight mode */
364 {
365
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 time.
5 if ( !check_config_validity( &preset_data ) )
366 {
367 4 error_fail_fast( ERROR_CONFIG_VALIDITY_ERROR );
368 }
369
370 /* check chute continuity */
371
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 time.
5 if( preset_data.config_settings.enabled_features & DUAL_DEPLOY_ENABLED )
372 {
373
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if ( !ign_drogue_cont()
374
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 || !ign_main_cont() )
375 {
376 3 buzzer_beep(3000);
377 3 error_fail_fast( ERROR_IGNITION_CONTINUITY_ERROR );
378 }
379 }
380 5 fc_state_update( FC_STATE_CALIB );
381 } /* if ( ign_switch_cont() )*/
382
383 31 return usb_status;
384
385 } /* prelaunch_terminal */
386
387
388 /*******************************************************************************
389 * *
390 * PROCEDURE: *
391 * preset_cmd_execute *
392 * *
393 * DESCRIPTION: *
394 * Execute a preset command. *
395 * *
396 *******************************************************************************/
397 8 FLASH_STATUS preset_cmd_execute
398 (
399 uint8_t* subcommand_code,
400 HFLASH_BUFFER* flash_handle,
401 uint32_t* flash_address
402 )
403 {
404 8 enum SUBCMD_CODES {
405 PRESET_UPLOAD = 0x01,
406 PRESET_DOWNLOAD = 0x02,
407 PRESET_VERIFY = 0x03
408 };
409 8 USB_STATUS usb_status = USB_OK;
410
411
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
8 switch (*subcommand_code)
412 {
413
414 /*-------------------------------------------------------------
415 Upload Preset (to FC)
416 -------------------------------------------------------------*/
417 2 case PRESET_UPLOAD:
418 {
419 /* Recieve preset subcommand over USB */
420 2 uint8_t data_receive_buffer[sizeof( CONFIG_SETTINGS_TYPE ) + 4];
421 2 usb_status = usb_receive( data_receive_buffer,
422 sizeof( CONFIG_SETTINGS_TYPE ) + 4,
423 HAL_DEFAULT_TIMEOUT );
424
425
426 /* Compute checksum */
427 2 uint32_t checksum = crc32( &data_receive_buffer[4], sizeof( CONFIG_SETTINGS_TYPE ) );
428 2 uint32_t received_checksum = 0;
429
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 memcpy(&received_checksum, data_receive_buffer, 4);
430
431 /* Copy received data into preset data */
432 2 memcpy(&(preset_data.config_settings),&(data_receive_buffer[4]), sizeof( CONFIG_SETTINGS_TYPE ) );
433
434 /* Verify checksum */
435
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if( received_checksum == checksum )
436 {
437 1 preset_data.checksum = checksum;
438 }
439 else
440 {
441 1 preset_data.checksum = 0;
442 1 led_set_color( LED_RED );
443 1 buzzer_beep(2000);
444 }
445
446 2 return write_preset( flash_handle, flash_address );
447 }
448
449 /*-------------------------------------------------------------
450 Download Preset (from FC)
451 -------------------------------------------------------------*/
452 2 case PRESET_DOWNLOAD:
453 {
454 2 FLASH_STATUS flash_status = FLASH_OK;
455 2 uint8_t buffer[ sizeof(PRESET_DATA) ];
456 // flash_status = write_preset( flash_handle, &preset_data, flash_address );
457 2 memcpy(buffer, &preset_data, sizeof(PRESET_DATA));
458 2 usb_status = usb_transmit( buffer, sizeof(PRESET_DATA), HAL_DEFAULT_TIMEOUT );
459
460
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if ( usb_status != USB_OK )
461 {
462 1 return FLASH_FAIL;
463 }
464
465 return flash_status;
466 }
467
468 /*-------------------------------------------------------------
469 Verify Preset
470 -------------------------------------------------------------*/
471 2 case PRESET_VERIFY:
472 {
473 2 uint32_t checksum = crc32
474 (
475 (uint8_t*) &preset_data.config_settings, /* pointer arithmetic; modify carefully */
476 sizeof( CONFIG_SETTINGS_TYPE )
477 );
478 2 uint8_t result = (checksum == preset_data.checksum);
479 2 usb_status = usb_transmit( &result, 1, HAL_DEFAULT_TIMEOUT );
480
481
482
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if (usb_status != USB_OK)
483 {
484 1 error_fail_fast( ERROR_USB_UART_ERROR );
485 }
486
487
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(!result)
488 {
489 2 led_set_color( LED_RED );
490 2 buzzer_multi_beeps(500, 500, 3);
491 }
492
493 2 return FLASH_OK;
494 }
495 /*-------------------------------------------------------------
496 Unrecognized command code
497 -------------------------------------------------------------*/
498 2 default:
499 {
500 2 error_fail_fast( ERROR_USB_UART_ERROR );
501 2 return FLASH_FAIL;
502 }
503 }
504
505 }
506
507
508 /*******************************************************************************
509 * *
510 * PROCEDURE: *
511 * check_config_validity *
512 * *
513 * DESCRIPTION: *
514 * Ensure no incompatibilities exist in configs. *
515 * *
516 *******************************************************************************/
517 7 bool check_config_validity
518 (
519 PRESET_DATA* preset_data_ptr
520 )
521 {
522 /*-------------------------------------------------------------
523 Local Variables
524 -------------------------------------------------------------*/
525 7 bool valid = true;
526
527 /*-------------------------------------------------------------
528 Postponed or deprecated feature check
529 -------------------------------------------------------------*/
530
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 if ( preset_data_ptr->config_settings.enabled_features &
531 ( DUAL_DEPLOY_ENABLED
532 | ACTIVE_PITCH_YAW_CONTROL_ENABLED
533 | ACTIVE_ROLL_CONTROL_ENABLED /* temporarily deprecated */
534 ) ) /* list invalid feature flags here*/
535 {
536 5 valid = false;
537 }
538
539 /*-------------------------------------------------------------
540 TODO: Validate checksum before proceeding
541 -------------------------------------------------------------*/
542
543 /*-------------------------------------------------------------
544 TODO: Validate servo ranges before proceeding
545 -------------------------------------------------------------*/
546
547 7 return valid;
548
549 } /* check_config_validity */
550