diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 249b9bda..1e2408de 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -10,15 +10,15 @@ # supported CodeQL languages. # name: "CodeQL Advanced" - + on: push: - branches: [ "main" ] + branches: [ "main", "integration/**" ] pull_request: - branches: [ "main" ] + branches: [ "main", "integration/**" ] schedule: - cron: '41 0 * * 1' - + jobs: analyze: name: Analyze (${{ matrix.language }}) @@ -27,18 +27,18 @@ jobs: # - https://gh.io/supported-runners-and-hardware-resources # - https://gh.io/using-larger-runners (GitHub.com only) # Consider using larger runners or machines with greater resources for possible analysis time improvements. - runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + runs-on: ubuntu-latest permissions: # required for all workflows security-events: write - + # required to fetch internal or private CodeQL packs packages: read - + # only required for workflows in private repositories actions: read contents: read - + strategy: fail-fast: false matrix: @@ -60,15 +60,26 @@ jobs: uses: actions/checkout@v6 with: submodules: 'recursive' - + # Add any setup steps before running the `github/codeql-action/init` action. # This includes steps like installing compilers or runtimes (`actions/setup-node` # or others). This is typically only required for manual builds. - # - name: Setup runtime (example) - # uses: actions/setup-example@v1 - - # Initializes the CodeQL tools for scanning. + - name: Check out firmware compiler + if: matrix.language == 'c-cpp' + uses: carlosperate/arm-none-eabi-gcc-action@v1 + with: + release: '13.3.Rel1' # <-- The compiler release to use + - name: Check out X11 tools for emulator build + if: matrix.language == 'c-cpp' + run: | + sudo apt-get update + sudo apt-get install -y libx11-dev libxcursor-dev libxrandr-dev libxinerama-dev libxcb-xinput-dev libxi-dev + + # ------------------------------------------------------------------ + # Non-c-cpp languages (e.g. 'actions'): single init / build / analyze + # ------------------------------------------------------------------ - name: Initialize CodeQL + if: matrix.language != 'c-cpp' uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} @@ -79,33 +90,91 @@ jobs: # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. - + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality - - name: Check out firmware compiler - uses: carlosperate/arm-none-eabi-gcc-action@v1 + + - name: Perform CodeQL Analysis + if: matrix.language != 'c-cpp' + uses: github/codeql-action/analyze@v4 with: - release: '13.3.Rel1' # <-- The compiler release to use - - # If the analyze step fails for one of the languages you are analyzing with - # "We were unable to automatically build your code", modify the matrix above - # to set the build mode to "manual" for that language. Then modify this step - # to build your code. - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - name: Run manual build steps - if: matrix.build-mode == 'manual' + category: "/language:${{matrix.language}}" + + # ------------------------------------------------------------------ + # c-cpp: split into three databases/categories so rev2, rev3, and the + # emulator build show up as separate results in code scanning instead + # of being merged into a single combined database. + # ------------------------------------------------------------------ + + # --- rev2 release build --- + - name: Initialize CodeQL (rev2 release) + if: matrix.language == 'c-cpp' + uses: github/codeql-action/init@v4 + with: + languages: c-cpp + build-mode: manual + config: | + paths-ignore: + - auto + + - name: Build rev2 release + if: matrix.language == 'c-cpp' shell: bash run: | - # Release Build cd app/rev2 make DEBUG=0 - - # Rev 3 Test App (drivers) - cd ../rev3 + + - name: Analyze rev2 release + if: matrix.language == 'c-cpp' + uses: github/codeql-action/analyze@v4 + with: + category: "/language:c-cpp/rev2" + + # --- rev3 test app (drivers) --- + - name: Initialize CodeQL (rev3) + if: matrix.language == 'c-cpp' + uses: github/codeql-action/init@v4 + with: + languages: c-cpp + build-mode: manual + config: | + paths-ignore: + - auto + + - name: Build rev3 test app + if: matrix.language == 'c-cpp' + shell: bash + run: | + cd app/rev3 make - - - name: Perform CodeQL Analysis + + - name: Analyze rev3 + if: matrix.language == 'c-cpp' uses: github/codeql-action/analyze@v4 with: - category: "/language:${{matrix.language}}" + category: "/language:c-cpp/rev3" + + # --- emulator build --- + - name: Initialize CodeQL (emulator) + if: matrix.language == 'c-cpp' + uses: github/codeql-action/init@v4 + with: + languages: c-cpp + build-mode: manual + config: | + paths-ignore: + - auto + + - name: Build emulator + if: matrix.language == 'c-cpp' + shell: bash + run: | + cd app/rev2 + make clean + make emulator + + - name: Analyze emulator + if: matrix.language == 'c-cpp' + uses: github/codeql-action/analyze@v4 + with: + category: "/language:c-cpp/emulator" diff --git a/.github/workflows/test-runner.yml b/.github/workflows/test-runner.yml index 04636bdd..dfed4626 100644 --- a/.github/workflows/test-runner.yml +++ b/.github/workflows/test-runner.yml @@ -18,7 +18,7 @@ on: permissions: contents: read jobs: - unit-tests: + app-unit-tests: runs-on: ubuntu-latest strategy: matrix: @@ -63,6 +63,51 @@ jobs: run: echo 'Artifact ID is ${{ steps.promote-results.outputs.artifact-id }}' - run: echo "🍏 This job's status is ${{ job.status }}." + driver-unit-tests: + runs-on: ubuntu-latest + strategy: + matrix: + tests: [gps, servo] + steps: + - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." + - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" + - run: echo "🔎 The name of your branch is ${{ github.ref }}." + - name: Install test environment + run: | + python -m pip install --upgrade pip + pip install gcovr + - name: Check out FCF repository code + uses: actions/checkout@v6 + with: + ref: ${{ github.event.inputs.fw-branch || github.ref }} + submodules: 'recursive' + - run: echo "💡 The repository has been cloned to the runner." + - run: echo "đŸ–Ĩī¸ The workflow is now ready to test your code on the runner." + - name: List files in the repository + run: | + ls ${{ github.workspace }} + + - name: Build and run the appa/${{ matrix.tests }} tests + run: | + cd ${{ github.workspace }}/driver/_test/driver/${{ matrix.tests }} + make test + - name: Check for fails. + run: | + cd ${{ github.workspace }}/driver/_test/driver/${{ matrix.tests }} + tail -3 results.txt | grep "Result: PASS" + - name: Consolidate ${{ matrix.tests }} artifacts + run: mv ${{ github.workspace }}/driver/_test/driver/${{ matrix.tests }}/results.txt ${{ github.workspace }}/driver/_test/driver/${{ matrix.tests }}/coverage/results.txt + - name: "Promote Artifacts" + uses: actions/upload-artifact@v6 + id: promote-results + with: + name: ${{ matrix.tests }}-artifacts + path: ${{ github.workspace }}/driver/_test/driver/${{ matrix.tests }}/coverage/ + include-hidden-files: true + - name: Output artifact ID + run: echo 'Artifact ID is ${{ steps.promote-results.outputs.artifact-id }}' + - run: echo "🍏 This job's status is ${{ job.status }}." + emulator-tests: runs-on: ubuntu-latest timeout-minutes: 7 @@ -162,7 +207,7 @@ jobs: # Take coverage reports and merge them consolidate-coverage: runs-on: ubuntu-latest - needs: [unit-tests, emulator-tests] + needs: [app-unit-tests, driver-unit-tests, emulator-tests] steps: - name: Install gcovr run: | diff --git a/app/rev2/Makefile b/app/rev2/Makefile index fc105fea..d74f0d04 100644 --- a/app/rev2/Makefile +++ b/app/rev2/Makefile @@ -88,6 +88,7 @@ $(DRIVER_DIR)/ignition/ignition.c \ $(DRIVER_DIR)/imu/imu.c \ $(DRIVER_DIR)/led/led.c \ $(DRIVER_DIR)/lora/lora.c \ +$(DRIVER_DIR)/lora/lora_async.c \ $(MOD_DIR)/sensor/sensor.c \ $(DRIVER_DIR)/usb/usb.c \ $(DRIVER_DIR)/gps/gps.c \ @@ -131,8 +132,11 @@ $(BASE_DIR)/emulator/src/emulator_timer.c \ $(BASE_DIR)/emulator/src/emulator_error.c \ $(BASE_DIR)/emulator/src/emulator_init.c \ $(BASE_DIR)/emulator/src/emulator_gpio.c \ +$(BASE_DIR)/emulator/src/emulator_ground_station.c \ $(BASE_DIR)/emulator/src/emulator_uart.c \ $(BASE_DIR)/emulator/src/emulator_spi.c \ +$(BASE_DIR)/emulator/src/emulator_lora.c \ +$(BASE_DIR)/emulator/src/emulator_serial.c \ $(BASE_DIR)/emulator/src/emulator_i2c.c \ $(BASE_DIR)/emulator/src/emulator_gui.c \ $(BASE_DIR)/emulator/src/shaders/shaders.c \ diff --git a/app/rev2/flash_appa.c b/app/rev2/flash_appa.c index 6b829d9a..5b33d39c 100644 --- a/app/rev2/flash_appa.c +++ b/app/rev2/flash_appa.c @@ -309,7 +309,7 @@ idx = 6; if ( preset_data.config_settings.enabled_data & STORE_CONV ) { memcpy( &buffer[idx], - &sensor_data.imu_data.imu_converted, + &sensor_data.imu_converted, sizeof( IMU_CONVERTED )); idx += sizeof( IMU_CONVERTED ); memcpy( &buffer[idx], &sensor_data.baro_pressure, sizeof(float)); @@ -321,13 +321,11 @@ if ( preset_data.config_settings.enabled_data & STORE_CONV ) if ( preset_data.config_settings.enabled_data & STORE_STATE_ESTIM ) { memcpy( &buffer[idx], - &sensor_data.imu_data.state_estimate, + &sensor_data.state_estimate, sizeof( STATE_ESTIMATION )); idx += sizeof( STATE_ESTIMATION ); memcpy( &buffer[idx], &sensor_data.baro_alt, sizeof(float)); idx += 4; - memcpy( &buffer[idx], &sensor_data.baro_velo, sizeof(float)); - idx += 4; } if ( preset_data.config_settings.enabled_data & STORE_GPS ) @@ -400,7 +398,7 @@ if ( preset_data.config_settings.enabled_data & STORE_CONV ) if ( preset_data.config_settings.enabled_data & STORE_STATE_ESTIM ) { size += sizeof( STATE_ESTIMATION ); - size += 2 * sizeof( float ); /* baro alt/velo */ + size += sizeof( float ); /* baro alt */ } if ( preset_data.config_settings.enabled_data & STORE_GPS ) diff --git a/app/rev2/flight.c b/app/rev2/flight.c index 096ac12e..e291263c 100644 --- a/app/rev2/flight.c +++ b/app/rev2/flight.c @@ -30,10 +30,12 @@ Includes #include #include "main.h" #include "led.h" +#include "lora.h" #include "usb.h" #include "math.h" #include "sensor.h" #include "buzzer.h" +#include "debug_sdr.h" #include "error_sdr.h" #include "ignition.h" #include "telemetry.h" @@ -137,6 +139,8 @@ void flight_calib uint32_t* flash_address ) { +LORA_STATUS lora_status = LORA_OK; + led_set_color( LED_YELLOW ); buzzer_multi_beeps(50, 50, 4); @@ -150,6 +154,28 @@ sensorCalibrationSWCON(); write_preset( flash_handle, flash_address ); flash_erase_preserve_preset( flash_handle, flash_address ); +if ( preset_data.config_settings.enabled_features & WIRELESS_TRANSMISSION_ENABLED ) + { + if( !lora_is_lora_initialized() ) + { + lora_status = lora_configure( &preset_data.lora_preset ); + debug_assert( lora_status == LORA_OK, ERROR_LORA_INIT_ERROR ); + } + + /* If the modem fails to configure, disable TX in RAM (but do not write back to flash) */ + if( lora_status != LORA_OK ) + { + preset_data.config_settings.enabled_features &= ~WIRELESS_TRANSMISSION_ENABLED; + + /* Give an indication */ + led_set_color(LED_RED); + buzzer_multi_beeps(400, 200, 3); + led_set_color(LED_YELLOW); + } + + lora_fsm_set_mode( LORA_ASYNC_TX ); + } + fc_state_update( FC_STATE_LAUNCH_DETECT ); } /* flight_calib */ @@ -202,11 +228,11 @@ if ( ( fc_state == FC_STATE_ASCENT ) update_state(); /*------------------------------------------------------------------------------ - Update Telemetry FSM + Update LoRa FSM ------------------------------------------------------------------------------*/ if ( preset_data.config_settings.enabled_features & WIRELESS_TRANSMISSION_ENABLED ) { - telemetry_update( TELEMETRY_EVENT_SYNCHRONOUS_UPDATE ); + lora_fsm_update( LORA_FSM_EVENT_SYNCHRONOUS_UPDATE ); } /*------------------------------------------------------------------------------ @@ -357,8 +383,8 @@ uint8_t max_range_4 = preset_data.servo_preset.rp_servo4 + preset_data.config_se uint8_t min_range_4 = preset_data.servo_preset.rp_servo4 - preset_data.config_settings.control_max_deflection_angle; /* Read velocity and body state from sensor */ -float velocity = sensor_data.imu_data.state_estimate.velocity; -float roll_rate = sensor_data.imu_data.imu_converted.gyro_x; +float velocity = sensor_data.state_estimate.velocity; +float roll_rate = sensor_data.imu_converted.gyro_x; /* Get timing */ pid_delta = HAL_GetTick() - pid_previous; diff --git a/app/rev2/main.c b/app/rev2/main.c index c879c93a..b73f940d 100644 --- a/app/rev2/main.c +++ b/app/rev2/main.c @@ -297,29 +297,16 @@ if ( read_status == FLASH_FAIL ) { error_fail_fast( ERROR_FLASH_CMD_ERROR ); } - -/*------------------------------------------------------------------------------ - LoRA Initialization -------------------------------------------------------------------------------*/ -if ( preset_data.config_settings.enabled_features & WIRELESS_TRANSMISSION_ENABLED ) - { - LORA_STATUS lora_init_status = lora_configure( &(preset_data.lora_preset) ); - if( lora_init_status == LORA_USING_DEFAULTS ) - { - /* give an indicator of default configs*/ - for( int i = 0; i < 4; i++ ) - { - led_set_color( LED_YELLOW ); - buzzer_beep( 400 ); - led_set_color( LED_CYAN ); - delay_ms( 400 ); - } - } - else if( lora_init_status != LORA_OK ) - { - error_fail_fast( ERROR_LORA_INIT_ERROR ); - } - } + +/* Set orientation based on saved data */ +if ( preset_data.imu_offset.accel_x < 0.0f ) + { + set_mount_orientation( MOUNT_ORIENTATION_IMU_NORMAL ); + } +else + { + set_mount_orientation( MOUNT_ORIENTATION_IMU_INVERTED ); + } /*------------------------------------------------------------------------------ End of init // Begin program diff --git a/app/rev2/main.h b/app/rev2/main.h index 6fe33068..ae16acea 100644 --- a/app/rev2/main.h +++ b/app/rev2/main.h @@ -80,8 +80,8 @@ extern "C" { #define VERSION_PRERELEASE_NUMBER (uint8_t)0 /* Tunable (but not configurable) constants */ -#define COAST_DETECT_SAMPLES 3 /* does not need to be tuned per vehicle, our system should work for all */ -#define COAST_DETECT_THRESHOLD 1.25 +#define COAST_DETECT_SAMPLES 5 /* does not need to be tuned per vehicle, our system should work for all */ +#define COAST_DETECT_THRESHOLD 0.75 /*------------------------------------------------------------------------------ Typedefs diff --git a/app/rev2/sensor_calibrate.c b/app/rev2/sensor_calibrate.c index 1e197934..991b1111 100644 --- a/app/rev2/sensor_calibrate.c +++ b/app/rev2/sensor_calibrate.c @@ -42,17 +42,6 @@ extern IMU_OFFSET imu_offset; extern BARO_PRESET baro_preset; extern float velo_x_prev, velo_y_prev, velo_z_prev; -float acc_x_nonzero[1000]; -float acc_y_nonzero[1000]; -float acc_z_nonzero[1000]; - -float gyro_x_nonzero[1000]; -float gyro_y_nonzero[1000]; -float gyro_z_nonzero[1000]; - -float baro_pres_nonzero[1000]; -float baro_temp_nonzero[1000]; - /******************************************************************************* * * * PROCEDURE: * @@ -71,6 +60,9 @@ void sensorCalibrationSWCON(){ SENSOR_STATUS sensor_status = SENSOR_OK; (void)sensor_status; + /* Make sure this is consistent at calib, then flip after if we need to */ + set_mount_orientation( MOUNT_ORIENTATION_IMU_INVERTED ); + preset_data.imu_offset.accel_x = 0.00; preset_data.imu_offset.accel_y = 0.00; preset_data.imu_offset.accel_z = 0.00; @@ -101,12 +93,12 @@ void sensorCalibrationSWCON(){ for (int i = 0; i < samples; i++){ sensor_status = sensor_dump( &sensor_data ); debug_assert( sensor_status == SENSOR_OK, ERROR_SENSOR_CMD_ERROR ); - calc_acc_x = calc_acc_x + sensor_data.imu_data.imu_converted.accel_x; - calc_acc_y = calc_acc_y + sensor_data.imu_data.imu_converted.accel_y; - calc_acc_z = calc_acc_z + sensor_data.imu_data.imu_converted.accel_z; - calc_gyro_x = calc_gyro_x + sensor_data.imu_data.imu_converted.gyro_x; - calc_gyro_y = calc_gyro_y + sensor_data.imu_data.imu_converted.gyro_y; - calc_gyro_z = calc_gyro_z + sensor_data.imu_data.imu_converted.gyro_z; + calc_acc_x = calc_acc_x + sensor_data.imu_converted.accel_x; + calc_acc_y = calc_acc_y + sensor_data.imu_converted.accel_y; + calc_acc_z = calc_acc_z + sensor_data.imu_converted.accel_z; + calc_gyro_x = calc_gyro_x + sensor_data.imu_converted.gyro_x; + calc_gyro_y = calc_gyro_y + sensor_data.imu_converted.gyro_y; + calc_gyro_z = calc_gyro_z + sensor_data.imu_converted.gyro_z; calc_baro_pres = calc_baro_pres + sensor_data.baro_pressure; calc_baro_temp = calc_baro_temp + sensor_data.baro_temp; } @@ -119,6 +111,8 @@ void sensorCalibrationSWCON(){ calc_gyro_y = calc_gyro_y / ( samples ); calc_gyro_z = calc_gyro_z / ( samples ); + debug_assert( calc_acc_x != 0.0f, ERROR_SENSOR_CMD_ERROR ); + calc_baro_pres = calc_baro_pres / ( samples ); calc_baro_temp = calc_baro_temp / ( samples ); @@ -132,14 +126,16 @@ void sensorCalibrationSWCON(){ preset_data.baro_preset.baro_pres = calc_baro_pres; preset_data.baro_preset.baro_temp = calc_baro_temp; + + /* Sensor dump readings already factor in the orientation, which is assumed at startup to be inverted. + If we read a negative value for gravity, flip the orientation */ + if ( calc_acc_x < 0.0f ) + { + set_mount_orientation( MOUNT_ORIENTATION_IMU_NORMAL ); + } - // Reset velocity for accurate data - velo_x_prev = 0.00; - velo_y_prev = 0.00; - velo_z_prev = 0.00; - - // set sensor tick to current time - sensor_initialize_tick(); + /* Initialize sensor */ + sensor_init( &preset_data ); #ifdef DEBUG char sensor_dbg_msg[128]; @@ -149,10 +145,12 @@ void sensorCalibrationSWCON(){ tdelta, (float)tdelta / samples ); debug_ignore_emulator_warnings_stop(); debug_log(sensor_dbg_msg, msg_len, LOG_LVL_INFO); - msg_len = snprintf(sensor_dbg_msg, 128, "IMU Offsets: %.04f %.04f %.04f %.04f %.04f %.04f. Baro Offsets: %.04f %.04f.", - calc_acc_x, calc_acc_y, calc_acc_z, calc_gyro_x, calc_gyro_y, calc_gyro_z, calc_baro_pres, calc_baro_temp); + MOUNT_ORIENTATION orientation = get_mount_orientation(); + msg_len = snprintf(sensor_dbg_msg, 128, "IMU Offsets: %.04f %.04f %.04f %.04f %.04f %.04f. Baro Offsets: %.04f %.04f. Orientation: %d", + calc_acc_x, calc_acc_y, calc_acc_z, calc_gyro_x, calc_gyro_y, calc_gyro_z, calc_baro_pres, calc_baro_temp, orientation ); debug_log(sensor_dbg_msg, msg_len, LOG_LVL_INFO); #endif + } diff --git a/app/rev2/state_transition.c b/app/rev2/state_transition.c index f356a230..fddd3ea5 100644 --- a/app/rev2/state_transition.c +++ b/app/rev2/state_transition.c @@ -39,6 +39,8 @@ /* Error Handling */ #include "error_sdr.h" +#include "math_sdr.h" + /*------------------------------------------------------------------------------ Global Variables ------------------------------------------------------------------------------*/ @@ -71,9 +73,9 @@ bool launch_detection { static uint8_t acc_detect_cnts = 0; static uint8_t baro_detect_cnts = 0; -float accX = sensor_data.imu_data.imu_converted.accel_x; +float accZ = sensor_data.imu_converted.accel_z; float pressure = sensor_data.baro_pressure; -float acc_scalar = sqrtf(accX*accX); +float acc_scalar = fabsf(accZ); if ( preset_data.config_settings.enabled_features & LAUNCH_DETECT_ACCEL_ENABLED ) { @@ -183,32 +185,9 @@ bool coast_detect { /* local variables */ static uint8_t positive_readings = 0; -bool gravity_is_negative_x; - -/* determine thrust vs gravity axis */ -if( preset_data.imu_offset.accel_x < 0 ) - { - gravity_is_negative_x = true; - } -else if( preset_data.imu_offset.accel_x > 0 ) - { - gravity_is_negative_x = false; - } -else - { - // TODO: log warning -- we will not compute coast state for - // this flight without knowing what our axis of gravity is. - return false; - } /* check if accel is sufficiently low */ -if( gravity_is_negative_x - && ( sensor_data.imu_data.imu_converted.accel_x < (-1) * COAST_DETECT_THRESHOLD * 9.8f ) ) - { - positive_readings++; - } -else if( !gravity_is_negative_x - && ( sensor_data.imu_data.imu_converted.accel_x > COAST_DETECT_THRESHOLD * 9.8f ) ) +if ( sensor_data.imu_converted.accel_x < COAST_DETECT_THRESHOLD * GRAVITY ) { positive_readings++; } diff --git a/driver b/driver index 42a63d0f..8091bc52 160000 --- a/driver +++ b/driver @@ -1 +1 @@ -Subproject commit 42a63d0fda862aa673b210b20bf40402efcf655b +Subproject commit 8091bc52b8477477ff8f05439f4f3c0e90582816 diff --git a/emulator b/emulator index b94dc304..3f9f5549 160000 --- a/emulator +++ b/emulator @@ -1 +1 @@ -Subproject commit b94dc304a5eab64c5f3f4b917ef860850b4fe652 +Subproject commit 3f9f5549e9f94160d8da3be27405ece3718888c6 diff --git a/init/rev2/config/Src/stm32h7xx_it.c b/init/rev2/config/Src/stm32h7xx_it.c index 7234faf8..b2fcce76 100644 --- a/init/rev2/config/Src/stm32h7xx_it.c +++ b/init/rev2/config/Src/stm32h7xx_it.c @@ -38,7 +38,7 @@ Standard Includes #include "imu.h" #include "baro.h" #include "timer.h" -#include "telemetry.h" +#include "lora.h" #include "error_sdr.h" #include @@ -326,7 +326,7 @@ void HAL_SPI_TxRxCpltCallback( SPI_HandleTypeDef *hspi ) { /* Driver contract: pull NSS high */ HAL_GPIO_WritePin( LORA_NSS_GPIO_PORT, LORA_NSS_PIN, GPIO_PIN_SET ); /* Update telemetry FSM */ - telemetry_update( TELEMETRY_EVENT_REG_READ_CPLT ); + lora_fsm_update( LORA_FSM_EVENT_REG_READ_CPLT ); } } @@ -336,7 +336,7 @@ void HAL_SPI_TxCpltCallback( SPI_HandleTypeDef *hspi ) { /* Driver contract: pull NSS high */ HAL_GPIO_WritePin( LORA_NSS_GPIO_PORT, LORA_NSS_PIN, GPIO_PIN_SET ); /* Update telemetry FSM */ - telemetry_update( TELEMETRY_EVENT_WRITE_CPLT ); + lora_fsm_update( LORA_FSM_EVENT_WRITE_CPLT ); } } diff --git a/mod b/mod index 690f370d..2c2e9c8c 160000 --- a/mod +++ b/mod @@ -1 +1 @@ -Subproject commit 690f370d123ae97ce51bcff911b79703235791b8 +Subproject commit 2c2e9c8ce8f84ce7fc340b30ff8f5463447a47c8 diff --git a/test/SDECv2 b/test/SDECv2 index 8388be49..262c2a03 160000 --- a/test/SDECv2 +++ b/test/SDECv2 @@ -1 +1 @@ -Subproject commit 8388be4913e38c39a22721f990ad76418dd9e992 +Subproject commit 262c2a030843cb31fdf5aba1bfbf014d03a46106 diff --git a/test/app/rev2/error_int/test_error_int.c b/test/app/rev2/error_int/test_error_int.c index 46432fd1..a56286f0 100644 --- a/test/app/rev2/error_int/test_error_int.c +++ b/test/app/rev2/error_int/test_error_int.c @@ -216,7 +216,7 @@ void test_log_messages /*------------------------------------------------------------------------------ Set up test ------------------------------------------------------------------------------*/ -char test_msg[TEXT_MESSAGE_LENGTH] = "This message tests the log message system."; +char test_msg[TEXT_MESSAGE_LENGTH] = "This msg tsts the log msg system."; TEXT_MESSAGE return_buffer; memset( &return_buffer, 0, sizeof( TEXT_MESSAGE ) ); TEST_ASSERT_FALSE( "Precondition: Verify that there's no pending messages.", error_is_pending_info() ); @@ -224,7 +224,7 @@ TEST_ASSERT_FALSE( "Precondition: Verify that there's no pending messages.", err /*------------------------------------------------------------------------------ Adding to buffer: Call FUT ------------------------------------------------------------------------------*/ -error_log_info( test_msg ); +error_log_info( "This msg tsts the log msg system." ); /*------------------------------------------------------------------------------ Adding to buffer: Verify Result @@ -264,7 +264,7 @@ void test_warning_messages /*------------------------------------------------------------------------------ Set up test ------------------------------------------------------------------------------*/ -char test_msg[TEXT_MESSAGE_LENGTH] = "This message tests the warning message system."; +char test_msg[TEXT_MESSAGE_LENGTH] = "This msg tsts the log msg system."; TEXT_MESSAGE return_buffer; memset( &return_buffer, 0, sizeof( TEXT_MESSAGE ) ); TEST_ASSERT_FALSE( "Precondition: Verify that there's no pending messages.", error_is_pending_info() ); @@ -272,7 +272,7 @@ TEST_ASSERT_FALSE( "Precondition: Verify that there's no pending messages.", err /*------------------------------------------------------------------------------ Adding to buffer: Call FUT ------------------------------------------------------------------------------*/ -error_log_warning( test_msg ); +error_log_warning( "This msg tsts the log msg system." ); /*------------------------------------------------------------------------------ Adding to buffer: Verify Result diff --git a/test/app/rev2/flight/mock/test_flight_stubs.c b/test/app/rev2/flight/mock/test_flight_stubs.c index 54b1ee8a..3ceaf29e 100644 --- a/test/app/rev2/flight/mock/test_flight_stubs.c +++ b/test/app/rev2/flight/mock/test_flight_stubs.c @@ -35,7 +35,8 @@ uint16_t flash_busy_counts = 0; uint16_t sensor_dump_calls = 0; bool store_frame_called = false; bool is_apogee_detected = false; -TELEMETRY_EVENT last_event = TELEMETRY_EVENT_CANCEL; +LORA_FSM_EVENT last_event = LORA_FSM_EVENT_CANCEL; +LORA_ASYNC_OP_MODE last_op_mode = LORA_ASYNC_OFF; /* internal use */ @@ -63,7 +64,7 @@ sensor_dump_calls = 0; store_frame_called = false; is_apogee_detected = false; preset_data.config_settings.flash_rate_limit = 0; -last_event = TELEMETRY_EVENT_CANCEL; +last_event = LORA_FSM_EVENT_CANCEL; } void set_return_ign_deploy_main @@ -388,13 +389,6 @@ FLASH_STATUS get_sensor_frame return FLASH_OK; } -void sensor_frame_size_init - ( - void - ) -{ - -} /* launch_detect.c */ bool launch_detection @@ -447,7 +441,7 @@ FLIGHT_COMP_STATE_TYPE get_fc_state() return flight_computer_state; } -void telemetry_update(TELEMETRY_EVENT event) { +void lora_fsm_update(LORA_FSM_EVENT event) { last_event = event; } @@ -462,4 +456,26 @@ DEBUG_STATUS debug_log { /* Do nothing. Ideally, our tests should run in release mode though. */ return DEBUG_OK; +} + +LORA_STATUS lora_fsm_set_mode + ( + LORA_ASYNC_OP_MODE new_mode + ) +{ +last_op_mode = new_mode; +return LORA_OK; + +} + +LORA_STATUS lora_configure(LORA_PRESET* preset_ptr) +{ +return LORA_OK; + +} + +bool lora_is_lora_initialized(void) +{ +return false; + } \ No newline at end of file diff --git a/test/app/rev2/flight/test_flight.c b/test/app/rev2/flight/test_flight.c index e70ead97..a772d263 100644 --- a/test/app/rev2/flight/test_flight.c +++ b/test/app/rev2/flight/test_flight.c @@ -52,7 +52,8 @@ extern uint16_t preset_preserving_flash_erase_calls; extern uint16_t flash_busy_calls; extern uint16_t flash_busy_counts; extern bool store_frame_called; -extern TELEMETRY_EVENT last_event; +extern LORA_FSM_EVENT last_event; +extern LORA_ASYNC_OP_MODE last_op_mode; /* hijacked globals */ extern uint32_t pid_previous; @@ -141,12 +142,11 @@ flight_calib /*------------------------------------------------------------------------------ Verify results ------------------------------------------------------------------------------*/ -/* The only critical parts of this are GPS enablement based on feature flags. All - others can be proven by analysis. */ TEST_ASSERT_EQ_UINT("Test that GPS was enabled.", was_gps_enabled, true); +TEST_ASSERT_EQ_UINT("Test that TX mode was enabled.", last_op_mode, LORA_ASYNC_TX); /*------------------------------------------------------------------------------ -Case 1: GPS Disabled +Case 2: GPS Disabled ------------------------------------------------------------------------------*/ stubs_reset(); preset_data.config_settings.enabled_features = 0u; @@ -371,8 +371,8 @@ for( uint8_t test_num = 0; test_num < sizeof(cases) / sizeof(struct test_case); /* active roll setup. values are not important, we just need to check control flow. */ pid_previous = 0; launch_detect_time = 0; - sensor_data.imu_data.state_estimate.velocity = 0.0f; /* not important yet */ - sensor_data.imu_data.imu_converted.gyro_x = 100.0f; /* crazy val to check NE assert */ + sensor_data.state_estimate.velocity = 0.0f; /* not important yet */ + sensor_data.imu_converted.gyro_x = 100.0f; /* crazy val to check NE assert */ preset_data.config_settings.control_delay_after_launch = 0; preset_data.config_settings.control_max_deflection_angle = 25; preset_data.config_settings.roll_control_constant_p = 2.0f; @@ -704,7 +704,7 @@ flight_loop /*------------------------------------------------------------------------------ Verify results ------------------------------------------------------------------------------*/ -TEST_ASSERT_EQ_UINT("Test that the last telemetry state update was not caused by this function", last_event, TELEMETRY_EVENT_CANCEL); +TEST_ASSERT_EQ_UINT("Test that the last telemetry state update was not caused by this function", last_event, LORA_FSM_EVENT_CANCEL); TEST_end_nested_case(); @@ -748,7 +748,7 @@ flight_loop /*------------------------------------------------------------------------------ Verify results ------------------------------------------------------------------------------*/ -TEST_ASSERT_EQ_UINT("Test that the last telemetry state update was a synchronous update.", last_event, TELEMETRY_EVENT_SYNCHRONOUS_UPDATE); +TEST_ASSERT_EQ_UINT("Test that the last telemetry state update was a synchronous update.", last_event, LORA_FSM_EVENT_SYNCHRONOUS_UPDATE); TEST_end_nested_case(); @@ -809,8 +809,8 @@ for( uint8_t test_num = 0; test_num < sizeof(cases) / sizeof(struct test_case); stubs_reset(); pid_previous = 0; launch_detect_time = 0; - sensor_data.imu_data.state_estimate.velocity = 0.0f; /* not important yet */ - sensor_data.imu_data.imu_converted.gyro_x = cases[test_num].roll_rate; + sensor_data.state_estimate.velocity = 0.0f; /* not important yet */ + sensor_data.imu_converted.gyro_x = cases[test_num].roll_rate; set_return_HAL_GetTick( cases[test_num].time_since_launch ); preset_data.config_settings.control_delay_after_launch = cases[test_num].delay_after_launch_configuration; preset_data.config_settings.control_max_deflection_angle = cases[test_num].max_deflection_angle; diff --git a/test/app/rev2/flight_int/flight_int_test.py b/test/app/rev2/flight_int/flight_int_test.py index d2ab671d..fa5f2aba 100644 --- a/test/app/rev2/flight_int/flight_int_test.py +++ b/test/app/rev2/flight_int/flight_int_test.py @@ -5,10 +5,11 @@ import json import csv import shutil +import threading from SDECv2.BaseController import Firmware, BaseController from SDECv2.BaseController import create_controllers -from SDECv2.Parser import Parser, PresetConfig, DataBitmask, FeatureBitmask, create_configs +from SDECv2.Parser import Parser, PresetConfig, DataBitmask, FeatureBitmask, Telemetry, create_configs from SDECv2.SerialController import SerialSentry, SerialObj, Comport from sdr_emulator_utils import Emulator, Tester @@ -27,6 +28,32 @@ tmp_dir = Path("tmp") tmp_dir.mkdir(exist_ok=True) +# Set up threading/sync objects +stop_event = threading.Event() +telemetry_obj = Telemetry() + +POLL_INTERVAL = 1/60 + +# Inspired by the API dashboard thread +def dashboard_update_thread(serial_connection: SerialObj): + next_time = time.perf_counter() + while not stop_event.is_set(): + next_time += POLL_INTERVAL + + try: + serial_connection.reset_input_buffer() + telemetry_obj.dashboard_dump(serial_connection) + except ValueError as e: # Serial returned bad values + print("Warning: The telemetry thread received an error. Attempting to recover, but this may not work.") + serial_connection.reset_input_buffer() + tester.assert_eq(False, True, "The dashboard thread received an error: {e}.") + + sleep_time = next_time - time.perf_counter() + if sleep_time > 0: + time.sleep(sleep_time) + else: + next_time = time.perf_counter() + # connect try: ######################################################## @@ -52,6 +79,9 @@ print("[setup] Uploading presets") parser = Parser.upload_preset(serial_connection, path="support/test_presets.json") tester.assert_eq(type(parser), Parser, "The parser object was created successfully.") + + print("[setup] Uploading LoRa presets") + parser.upload_lora_preset(serial_connection, "support/test_presets.json") # give enough time to complete the serial transaction print("[setup] Waiting for completion") @@ -65,19 +95,48 @@ ###################### EXECUTE ######################### ######################################################## print("[execute] Starting emulator") - emulator.start(fast_arm=True) + emulator.start(fast_arm=True, connect_gs=True) time.sleep(5) - print("[execute] Waiting 10 seconds for calibration") - time.sleep(10) # Allow enough time for calib to complete + print("[execute] Set up dashboard drain") + dashboard_dump_thread = threading.Thread( + target=dashboard_update_thread, + args=[serial_connection], + daemon=True + ) + + print("[execute] Connecting") + serial_connection.reset_input_buffer() + serial_connection.connect() + + # assert proper connection + print("[execute] Verifying connection") + tester.assert_eq(serial_connection.target.controller.id, b'\x10', "Check that connect completed successfully (GS HW Opcode).") + tester.assert_eq(serial_connection.target.firmware.id, b'\x11', "Check that connect completed successfully (GS FW Opcode).") + + print("[execute] Start dashboard drain") + dashboard_dump_thread.start() + + print("[execute] Waiting 20 seconds for calibration & sufficient LoRa messages") + time.sleep(20) # Allow enough time for calib to complete print("[execute] Tearing down execute phase") + stop_event.set() + dashboard_dump_thread.join() emulator.stop() time.sleep(5) ######################################################## ###################### VERIFY ########################## ######################################################## + print("[verify] Check that a dashboard_dump message was received.") + dump_msg = telemetry_obj.get_latest_dashboard_dump() + tester.assert_eq(dump_msg is not None, True, "Dashboard Dump message is not None.") + + print("[verify] Check that a vehicle_id message was received.") + id_msg = telemetry_obj.get_latest_wireless_stats() + tester.assert_eq(id_msg["target"] != "Connecting...", True, "Vehicle ID message received.") + print("[verify] Starting emulator") emulator.start() time.sleep(5) diff --git a/test/app/rev2/flight_int/support/test_presets.json b/test/app/rev2/flight_int/support/test_presets.json index e3c9ffda..f993ccbd 100644 --- a/test/app/rev2/flight_int/support/test_presets.json +++ b/test/app/rev2/flight_int/support/test_presets.json @@ -4,7 +4,7 @@ "Dual Deploy": false, "Active Roll Control": false, "Active Pitch Yaw Control": false, - "Wireless Transmission": false, + "Wireless Transmission": true, "Launch Detect Baro": true, "Launch Detect Accel": true, "GPS": true diff --git a/test/app/rev2/launch_detect/test_launch_detect.c b/test/app/rev2/launch_detect/test_launch_detect.c index 46798fc7..c62f380e 100644 --- a/test/app/rev2/launch_detect/test_launch_detect.c +++ b/test/app/rev2/launch_detect/test_launch_detect.c @@ -114,9 +114,9 @@ for ( int test_num = 0; test_num < NUM_CASES_LAUNCH_DETECT; test_num++ ) for ( int i = 0; i < NUM_EXPECTED_SAMPLES; i++ ) { - sensor_data.imu_data.imu_converted.accel_x = inputsAcc[test_num][i]; - sensor_data.imu_data.imu_converted.accel_y = inputsAcc[test_num][i]; - sensor_data.imu_data.imu_converted.accel_z = inputsAcc[test_num][i]; + sensor_data.imu_converted.accel_x = inputsAcc[test_num][i]; + sensor_data.imu_converted.accel_y = inputsAcc[test_num][i]; + sensor_data.imu_converted.accel_z = inputsAcc[test_num][i]; sensor_data.baro_pressure = inputsBaro[test_num][i]; fut_return = launch_detection(&sample_ld_time); @@ -130,9 +130,9 @@ for ( int test_num = 0; test_num < NUM_CASES_LAUNCH_DETECT; test_num++ ) } } /* reset test */ - sensor_data.imu_data.imu_converted.accel_x = 0; - sensor_data.imu_data.imu_converted.accel_y = 0; - sensor_data.imu_data.imu_converted.accel_z = 0; + sensor_data.imu_converted.accel_x = 0; + sensor_data.imu_converted.accel_y = 0; + sensor_data.imu_converted.accel_z = 0; sensor_data.baro_pressure = 0; launch_detection(&sample_ld_time); sample_ld_time = 0; diff --git a/test/app/rev2/main/mock/mocks.c b/test/app/rev2/main/mock/mocks.c index a4cef76d..ea353217 100644 --- a/test/app/rev2/main/mock/mocks.c +++ b/test/app/rev2/main/mock/mocks.c @@ -139,6 +139,14 @@ IMU_STATUS imu_init return imu_init_return; } +void set_mount_orientation + ( + MOUNT_ORIENTATION orientation + ) +{ +// stub +} + SERVO_STATUS servo_init ( void diff --git a/test/app/rev2/main/test_main.c b/test/app/rev2/main/test_main.c index 5e4e2b55..98a62f35 100644 --- a/test/app/rev2/main/test_main.c +++ b/test/app/rev2/main/test_main.c @@ -108,15 +108,15 @@ struct test_case struct test_case cases[] = { { "Normal Case: Initialization Correct", false, FLASH_OK, BARO_OK, IMU_OK, SERVO_OK, FLASH_OK, LORA_OK, false, ERROR_NO_ERROR }, - { "Normal Case: Initialization w/ Valid LoRa", true, FLASH_OK, BARO_OK, IMU_OK, SERVO_OK, FLASH_OK, LORA_OK, false, ERROR_NO_ERROR }, - { "Normal Case: Initialization w/ Invalid Lora", true, FLASH_OK, BARO_OK, IMU_OK, SERVO_OK, FLASH_OK, LORA_USING_DEFAULTS, false, ERROR_NO_ERROR}, +// { "Normal Case: Initialization w/ Valid LoRa", true, FLASH_OK, BARO_OK, IMU_OK, SERVO_OK, FLASH_OK, LORA_OK, false, ERROR_NO_ERROR }, /* MOVED TO FLIGHT */ +// { "Normal Case: Initialization w/ Invalid Lora", true, FLASH_OK, BARO_OK, IMU_OK, SERVO_OK, FLASH_OK, LORA_USING_DEFAULTS, false, ERROR_NO_ERROR}, /* MOVED TO FLIGHT */ { "Robust Case: Flash Init Fail", false, FLASH_INIT_FAIL, BARO_OK, IMU_OK, SERVO_OK, FLASH_OK, LORA_OK, false, ERROR_FLASH_INIT_ERROR }, // { "Robust Case: Baro Init Fail", false, FLASH_OK, BARO_FAIL, IMU_OK, SERVO_OK, FLASH_OK, LORA_OK, false, ERROR_BARO_INIT_ERROR }, // { "Robust Case: IMU Init Fail", false, FLASH_OK, BARO_OK, IMU_FAIL, SERVO_OK, FLASH_OK, LORA_OK, false, ERROR_IMU_INIT_ERROR }, { "Robust Case: Servo Init Fail", false, FLASH_OK, BARO_OK, IMU_OK, SERVO_FAIL, FLASH_OK, LORA_OK, false, ERROR_SERVO_INIT_ERROR }, { "Robust Case: Read Preset Fail", false, FLASH_OK, BARO_OK, IMU_OK, SERVO_OK, FLASH_FAIL, LORA_OK, false, ERROR_FLASH_CMD_ERROR }, { "Robust Case: Switch Terminal Toggled", false, FLASH_OK, BARO_OK, IMU_OK, SERVO_OK, FLASH_OK, LORA_OK, true, ERROR_DATA_HAZARD_ERROR }, - { "Robust Case: LoRa init fail", true, FLASH_OK, BARO_OK, IMU_OK, SERVO_OK, FLASH_OK, LORA_FAIL, false, ERROR_LORA_INIT_ERROR } +// { "Robust Case: LoRa init fail", true, FLASH_OK, BARO_OK, IMU_OK, SERVO_OK, FLASH_OK, LORA_FAIL, false, ERROR_LORA_INIT_ERROR } }; for( uint8_t test_num = 0; test_num < sizeof(cases) / sizeof(struct test_case); test_num++ ) diff --git a/test/app/rev2/sensor_calibrate/mock/MOCK_hal.c b/test/app/rev2/sensor_calibrate/mock/MOCK_hal.c index 49ec1c8c..8aa93548 100644 --- a/test/app/rev2/sensor_calibrate/mock/MOCK_hal.c +++ b/test/app/rev2/sensor_calibrate/mock/MOCK_hal.c @@ -68,7 +68,7 @@ sensor_dump_calls++; return SENSOR_OK; } -void sensor_initialize_tick(void) {} +void sensor_init( PRESET_DATA* preset_data ) {} DEBUG_STATUS debug_log ( @@ -83,3 +83,9 @@ return DEBUG_OK; } void error_fail_fast(ERROR_CODE error_code) {} + +void set_mount_orientation + ( + MOUNT_ORIENTATION orientation + ) +{} diff --git a/test/app/rev2/sensor_calibrate/test_sensor_calibrate.c b/test/app/rev2/sensor_calibrate/test_sensor_calibrate.c index dc6c5d8d..f3122ff0 100644 --- a/test/app/rev2/sensor_calibrate/test_sensor_calibrate.c +++ b/test/app/rev2/sensor_calibrate/test_sensor_calibrate.c @@ -70,13 +70,13 @@ memset( sensor_dump_mock, 0, sizeof( SENSOR_DATA ) * 100 ); preset_data.config_settings.sensor_calibration_samples = 100; for( int i = 0; i < 50; i++ ) { - sensor_dump_mock[i].imu_data.imu_converted.accel_x = 100; - sensor_dump_mock[i].imu_data.imu_converted.accel_y = 100; - sensor_dump_mock[i].imu_data.imu_converted.accel_z = 100; - sensor_dump_mock[i].imu_data.imu_converted.gyro_x = 100; - sensor_dump_mock[i].imu_data.imu_converted.gyro_y = 100; - sensor_dump_mock[i].imu_data.imu_converted.gyro_z = 100; - sensor_dump_mock[i].imu_data.imu_converted.gyro_y = 100; + sensor_dump_mock[i].imu_converted.accel_x = 100; + sensor_dump_mock[i].imu_converted.accel_y = 100; + sensor_dump_mock[i].imu_converted.accel_z = 100; + sensor_dump_mock[i].imu_converted.gyro_x = 100; + sensor_dump_mock[i].imu_converted.gyro_y = 100; + sensor_dump_mock[i].imu_converted.gyro_z = 100; + sensor_dump_mock[i].imu_converted.gyro_y = 100; sensor_dump_mock[i].baro_pressure = 100; sensor_dump_mock[i].baro_temp = 100; } diff --git a/test/app/rev2/terminal_int/terminal_int_test.py b/test/app/rev2/terminal_int/terminal_int_test.py index 4236f154..ca90c6d3 100644 --- a/test/app/rev2/terminal_int/terminal_int_test.py +++ b/test/app/rev2/terminal_int/terminal_int_test.py @@ -16,18 +16,15 @@ # Helper functions def check_sensor(tester, sensor_name, readout): - # These sensors will not trigger a fail if the readout is invalid - postponed_list = ["pos", "altg", "speedg", "utc_time", "long", "lat", "ns", "ew", "gll_s", "rmc_s"] - if readout: min = float('-inf') max = float('inf') match sensor_name: # RAW VALUES - case "accXconv" | "accYconv" | "accZconv": + case "accXconv" | "accYconv" | "accZconv" | "acc_x" | "acc_y" | "acc_z": min = -12 max = 12 - case "gyroXconv" | "gyroYconv" | "gyroZconv": + case "gyroXconv" | "gyroYconv" | "gyroZconv" | "roll_rate": min = -25 max = 25 case "magXconv" | "magYconv": @@ -36,6 +33,9 @@ def check_sensor(tester, sensor_name, readout): case "magZconv": min = -125 max = 125 + case "quat_w" | "quat_x" | "quat_y" | "quat_z": + min = -1 + max = 1 case "pres": min = 90000 max = 101300 @@ -52,18 +52,6 @@ def check_sensor(tester, sensor_name, readout): # This is true since the else branch's assert wasn't reached tester.assert_float_in_range(readout, min, max, f"Check that {sensor_name} is in the expected range.") - else: - # GPS is expected to fail if there are no valid readings, and GPS is only enabled after arming. - # This is known behavior that you may want to consider a bug. If you would like this fixed, - # please open a ticket. - # - # Position is known to be defective as of v2.6.0. The issue was noticed during mod#102 - # and we chose not to address it. The reading will instead be removed at a later date - # when space is needed in the sensor data struct. - # - # Follow mod#101 for updates on this. - if sensor_name not in postponed_list: - tester.assert_neq(0, 0, f"{sensor_name} has no available reading, so autofail.") sdec_comport = os.environ.get("SDEC_COMPORT") emulator_comport = os.environ.get("EMULATOR_COMPORT") diff --git a/test/utilities/sdr_emulator_utils/emulator_runner.py b/test/utilities/sdr_emulator_utils/emulator_runner.py index 45be5925..ec67cf32 100644 --- a/test/utilities/sdr_emulator_utils/emulator_runner.py +++ b/test/utilities/sdr_emulator_utils/emulator_runner.py @@ -61,7 +61,7 @@ def generate_coverage(self) -> bool: os.chdir(cwd) return result.returncode == 0 - def start(self, fast_arm = False) -> subprocess.Popen: + def start(self, fast_arm = False, connect_gs = False) -> subprocess.Popen: args = [] if os.name == "nt": args.append("build/appa.exe") @@ -83,7 +83,14 @@ def start(self, fast_arm = False) -> subprocess.Popen: **kwargs ) assert proc.stdin is not None - proc.stdin.write(os.environ["EMULATOR_COMPORT"] + "\n") + + # Startup Interactions + # 1: FC SDEC Comport + # 2: GS SDEC Comport + if not connect_gs: + proc.stdin.write(os.environ["EMULATOR_COMPORT"] + "\n" + "\n") + else: + proc.stdin.write("\n" + os.environ["EMULATOR_COMPORT"] + "\n") proc.stdin.flush() proc.stdin.close() os.chdir(cwd)