GCC Code Coverage Report


Directory: ../../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 34.1% 44 / 0 / 129
Functions: 66.7% 2 / 0 / 3
Branches: 20.0% 15 / 0 / 75

app/rev2/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 771 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 771 USB_STATUS usb_status = USB_OK; /* USB Status*/
77 771 uint8_t usb_rx_data = 0; /* USB Incoming Data Buffer */
78 771 uint8_t subcommand_code = 0; /* USB Subcommand Buffer */
79
80 /*------------------------------------------------------------------------------
81 Terminal Command Handler
82 ------------------------------------------------------------------------------*/
83 771 led_set_color( LED_GREEN );
84
85
1/2
✓ Branch 1 taken 771 times.
✗ Branch 2 not taken.
771 if ( usb_detect() )
86 {
87 /* Poll usb port */
88 771 usb_status = usb_receive( &usb_rx_data,
89 sizeof( usb_rx_data ),
90 HAL_DEFAULT_TIMEOUT );
91
92 /* Parse input code */
93
1/2
✓ Branch 0 taken 770 times.
✗ Branch 1 not taken.
770 if ( usb_status == USB_OK )
94 {
95
6/11
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 time.
✗ Branch 9 not taken.
✓ Branch 10 taken 764 times.
770 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 2 case CONNECT_OP:
111 {
112 /* Send board identifying code */
113 2 ping();
114
115 /* Send firmware identifying code */
116 2 usb_transmit( &firmware_code ,
117 sizeof( uint8_t ),
118 HAL_DEFAULT_TIMEOUT );
119 2 break;
120 } /* CONNECT_OP */
121
122 /*--------------------------------------------------------------
123 SENSOR Command
124 --------------------------------------------------------------*/
125 1 case SENSOR_OP:
126 {
127 1 USB_STATUS command_status; /* Status of USB HAL */
128 /* Receive sensor subcommand */
129 1 command_status = usb_receive( &subcommand_code ,
130 sizeof( subcommand_code ),
131 HAL_SENSOR_TIMEOUT );
132
133
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if ( command_status == USB_OK )
134 {
135 /* Execute sensor subcommand */
136 1 sensor_cmd_execute( subcommand_code );
137 }
138 ✗ else if ( command_status == USB_TIMEOUT )
139 {
140 break;
141 }
142 else
143 {
144 ✗ error_fail_fast( ERROR_SENSOR_CMD_ERROR );
145 }
146 break;
147 } /* SENSOR_OP */
148
149 /*-------------------------------------------------------------
150 FIN_OP
151 -------------------------------------------------------------*/
152 ✗ case FIN_OP:
153 {
154 ✗ usb_status = finCalibration( &usb_rx_data );
155
156 ✗ if ( usb_status != USB_OK )
157 {
158 ✗ error_fail_fast( ERROR_SERVO_CMD_ERROR );
159 }
160
161 ✗ if ( write_preset( flash_handle, flash_address) != FLASH_OK )
162 {
163 ✗ error_fail_fast( ERROR_FLASH_CMD_ERROR );
164 }
165
166 break;
167 }
168
169 /*-------------------------------------------------------------
170 FLASH_OP
171 -------------------------------------------------------------*/
172 ✗ case FLASH_OP:
173 {
174 /* Recieve flash subcommand over USB */
175 ✗ usb_status = usb_receive( &subcommand_code ,
176 sizeof( subcommand_code ),
177 HAL_DEFAULT_TIMEOUT );
178
179 /* Execute subcommand */
180 ✗ if ( usb_status == USB_OK )
181 {
182
183 /* Execute the subcommand */
184 ✗ *flash_status = flash_cmd_execute( subcommand_code,
185 flash_handle );
186 }
187 else
188 {
189 /* Subcommand code not recieved */
190 ✗ error_fail_fast( ERROR_FLASH_CMD_ERROR );
191 }
192
193 /* Transmit status code to PC */
194 ✗ usb_status = usb_transmit( flash_status ,
195 sizeof( flash_status ),
196 HAL_DEFAULT_TIMEOUT );
197
198 ✗ if ( usb_status != USB_OK )
199 {
200 /* Status not transmitted properly */
201 ✗ error_fail_fast( ERROR_FLASH_CMD_ERROR );
202 }
203
204 break;
205 } /* FLASH_OP */
206
207 /*-------------------------------------------------------------
208 IGNITE_OP
209 -------------------------------------------------------------*/
210 ✗ case IGNITE_OP:
211 {
212 /* Recieve ignition subcommand over USB */
213 ✗ usb_status = usb_receive( &subcommand_code ,
214 sizeof( subcommand_code ),
215 HAL_DEFAULT_TIMEOUT );
216
217 /* Execute subcommand */
218 ✗ if ( usb_status == USB_OK )
219 {
220 ✗ IGN_STATUS ign_status;
221 /* Execute subcommand*/
222 ✗ ign_status = ign_cmd_execute( subcommand_code );
223
224 /* Return response code to terminal */
225 ✗ usb_transmit( &ign_status,
226 sizeof( ign_status ),
227 HAL_DEFAULT_TIMEOUT );
228 }
229 else
230 {
231 /* Error: no subcommand recieved */
232 ✗ error_fail_fast( ERROR_IGN_CMD_ERROR );
233 }
234
235 break;
236 }
237 /*-------------------------------------------------------------
238 PRESET_OP
239 -------------------------------------------------------------*/
240 1 case PRESET_OP:
241 {
242 /* Recieve preset subcommand over USB */
243 1 usb_status = usb_receive( &subcommand_code ,
244 sizeof( subcommand_code ),
245 HAL_DEFAULT_TIMEOUT );
246
247 /* Execute subcommand */
248
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 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 ✗ error_fail_fast( ERROR_FLASH_CMD_ERROR );
259 }
260
261 /* Transmit status code to PC */
262 ✗ usb_status = usb_transmit( flash_status ,
263 sizeof( flash_status ),
264 HAL_DEFAULT_TIMEOUT );
265
266 ✗ if ( usb_status != USB_OK )
267 {
268 /* Status not transmitted properly */
269 ✗ error_fail_fast( ERROR_FLASH_CMD_ERROR );
270 }
271
272 break;
273 } /* PRESET_OP */
274 /*--------------------------------------------------------------
275 SERVO Command
276 --------------------------------------------------------------*/
277 ✗ case SERVO_OP:
278 {
279 ✗ SERVO_STATUS servo_status = SERVO_FAIL;
280 /* Recieve servo subcommand over USB */
281 ✗ usb_status = usb_receive( &subcommand_code ,
282 sizeof( subcommand_code ),
283 HAL_DEFAULT_TIMEOUT );
284
285 /* Execute subcommand */
286 ✗ if ( usb_status == USB_OK )
287 {
288 ✗ servo_status = servo_cmd_execute( subcommand_code );
289 }
290
291 ✗ if ( servo_status != SERVO_OK )
292 {
293 ✗ led_set_color( LED_RED );
294 ✗ HAL_Delay( 5000 );
295 }
296 break;
297 }
298 /*--------------------------------------------------------------
299 DASHBOARD Command
300 --------------------------------------------------------------*/
301 1 case DASHBOARD_OP:
302 {
303 1 usb_status = dashboard_dump();
304
305
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if ( usb_status == USB_FAIL )
306 {
307 ✗ error_fail_fast( ERROR_SENSOR_CMD_ERROR );
308 }
309 }
310 break;
311 /*-------------------------------------------------------------
312 LORA_OP
313 -------------------------------------------------------------*/
314 ✗ case LORA_OP:
315 {
316 ✗ uint8_t subcommand_code;
317 ✗ LORA_STATUS command_status;
318 /* Recieve telem subcommand over USB */
319 ✗ usb_status = usb_receive( &subcommand_code ,
320 sizeof( subcommand_code ),
321 HAL_DEFAULT_TIMEOUT );
322
323 /* Execute subcommand to mutate or transmit buffer */
324 ✗ command_status = lora_cmd_execute(subcommand_code, &(preset_data.lora_preset));
325
326 ✗ if ( command_status == LORA_OK && subcommand_code == LORA_PRESET_UPLOAD )
327 {
328 ✗ if(write_preset(flash_handle, flash_address)) /* writes all presets */
329 {
330 ✗ error_fail_fast(ERROR_FLASH_CMD_ERROR);
331 }
332
333 /* Finally, re-configure the modem */
334 ✗ if ( lora_configure( &(preset_data.lora_preset) ) != LORA_OK ) /* also errors out if configs are invalid! */
335 {
336 ✗ error_fail_fast( ERROR_LORA_CMD_ERROR );
337 }
338 }
339 ✗ else if ( command_status != LORA_OK || subcommand_code != LORA_PRESET_DOWNLOAD )
340 {
341 /* unknown subcommand or usb fail */
342 ✗ error_fail_fast( ERROR_LORA_CMD_ERROR );
343 }
344 ✗ 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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 769 times.
769 if ( ign_switch_armed() ) /* Enter flight mode */
364 {
365 ✗ if ( !check_config_validity( &preset_data ) )
366 {
367 ✗ error_fail_fast( ERROR_CONFIG_VALIDITY_ERROR );
368 }
369
370 /* check chute continuity */
371 ✗ if( preset_data.config_settings.enabled_features & DUAL_DEPLOY_ENABLED )
372 {
373 ✗ if ( !ign_drogue_cont()
374 ✗ || !ign_main_cont() )
375 {
376 ✗ buzzer_beep(3000);
377 ✗ error_fail_fast( ERROR_IGNITION_CONTINUITY_ERROR );
378 }
379 }
380 ✗ fc_state_update( FC_STATE_CALIB );
381 } /* if ( ign_switch_cont() )*/
382
383 769 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 1 FLASH_STATUS preset_cmd_execute
398 (
399 uint8_t* subcommand_code,
400 HFLASH_BUFFER* flash_handle,
401 uint32_t* flash_address
402 )
403 {
404 1 enum SUBCMD_CODES {
405 PRESET_UPLOAD = 0x01,
406 PRESET_DOWNLOAD = 0x02,
407 PRESET_VERIFY = 0x03
408 };
409 1 USB_STATUS usb_status = USB_OK;
410
411
1/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 switch (*subcommand_code)
412 {
413
414 /*-------------------------------------------------------------
415 Upload Preset (to FC)
416 -------------------------------------------------------------*/
417 1 case PRESET_UPLOAD:
418 {
419 /* Recieve preset subcommand over USB */
420 1 uint8_t data_receive_buffer[sizeof( CONFIG_SETTINGS_TYPE ) + 4];
421 1 usb_status = usb_receive( data_receive_buffer,
422 sizeof( CONFIG_SETTINGS_TYPE ) + 4,
423 HAL_DEFAULT_TIMEOUT );
424
425
426 /* Compute checksum */
427 1 uint32_t checksum = crc32( &data_receive_buffer[4], sizeof( CONFIG_SETTINGS_TYPE ) );
428 1 uint32_t received_checksum = 0;
429
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 memcpy(&received_checksum, data_receive_buffer, 4);
430
431 /* Copy received data into preset data */
432 1 memcpy(&(preset_data.config_settings),&(data_receive_buffer[4]), sizeof( CONFIG_SETTINGS_TYPE ) );
433
434 /* Verify checksum */
435
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if( received_checksum == checksum )
436 {
437 1 preset_data.checksum = checksum;
438 }
439 else
440 {
441 ✗ preset_data.checksum = 0;
442 ✗ led_set_color( LED_RED );
443 ✗ buzzer_beep(2000);
444 }
445
446 1 return write_preset( flash_handle, flash_address );
447 }
448
449 /*-------------------------------------------------------------
450 Download Preset (from FC)
451 -------------------------------------------------------------*/
452 ✗ case PRESET_DOWNLOAD:
453 {
454 ✗ FLASH_STATUS flash_status = FLASH_OK;
455 ✗ uint8_t buffer[ sizeof(PRESET_DATA) ];
456 // flash_status = write_preset( flash_handle, &preset_data, flash_address );
457 ✗ memcpy(buffer, &preset_data, sizeof(PRESET_DATA));
458 ✗ usb_status = usb_transmit( buffer, sizeof(PRESET_DATA), HAL_DEFAULT_TIMEOUT );
459
460 ✗ if ( usb_status != USB_OK )
461 {
462 ✗ return FLASH_FAIL;
463 }
464
465 return flash_status;
466 }
467
468 /*-------------------------------------------------------------
469 Verify Preset
470 -------------------------------------------------------------*/
471 ✗ case PRESET_VERIFY:
472 {
473 ✗ uint32_t checksum = crc32
474 (
475 (uint8_t*) &preset_data.config_settings, /* pointer arithmetic; modify carefully */
476 sizeof( CONFIG_SETTINGS_TYPE )
477 );
478 ✗ uint8_t result = (checksum == preset_data.checksum);
479 ✗ usb_status = usb_transmit( &result, 1, HAL_DEFAULT_TIMEOUT );
480
481
482 ✗ if (usb_status != USB_OK)
483 {
484 ✗ error_fail_fast( ERROR_USB_UART_ERROR );
485 }
486
487 ✗ if(!result)
488 {
489 ✗ led_set_color( LED_RED );
490 ✗ buzzer_multi_beeps(500, 500, 3);
491 }
492
493 ✗ return FLASH_OK;
494 }
495 /*-------------------------------------------------------------
496 Unrecognized command code
497 -------------------------------------------------------------*/
498 ✗ default:
499 {
500 ✗ error_fail_fast( ERROR_USB_UART_ERROR );
501 ✗ 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 ✗ bool check_config_validity
518 (
519 PRESET_DATA* preset_data_ptr
520 )
521 {
522 /*-------------------------------------------------------------
523 Local Variables
524 -------------------------------------------------------------*/
525 ✗ bool valid = true;
526
527 /*-------------------------------------------------------------
528 Postponed or deprecated feature check
529 -------------------------------------------------------------*/
530 ✗ 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 ✗ valid = false;
537 }
538
539 /*-------------------------------------------------------------
540 TODO: Validate checksum before proceeding
541 -------------------------------------------------------------*/
542
543 /*-------------------------------------------------------------
544 TODO: Validate servo ranges before proceeding
545 -------------------------------------------------------------*/
546
547 ✗ return valid;
548
549 } /* check_config_validity */
550