diff --git a/.github/workflows/release_artifacts.yml b/.github/workflows/release_artifacts.yml new file mode 100644 index 00000000..10d9875e --- /dev/null +++ b/.github/workflows/release_artifacts.yml @@ -0,0 +1,40 @@ +name: Include Submodules in Release + +on: + release: + types: [published] + +jobs: + flatten-release: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + submodules: recursive + fetch-depth: 0 + + - name: Remove submodule metadata + run: | + git submodule foreach --quiet ' + echo "Flattening $name at $path..." + git rm --cached -r "$path" || true + rm -rf ".git/modules/$path" + ' + rm -f .gitmodules + + - name: Create release zip + run: | + REPO_NAME=${{ github.event.repository.name }} + TAG_NAME=${{ github.event.release.tag_name }} + ZIP_NAME="${REPO_NAME}-${TAG_NAME}.zip" + echo "Creating zip: $ZIP_NAME" + zip -r "$ZIP_NAME" . -x ".git/*" -x ".github/*" + echo "ZIP created: $ZIP_NAME" + + - name: Upload zip to release + uses: softprops/action-gh-release@v2 + with: + files: "${{ github.event.repository.name }}-${{ github.event.release.tag_name }}.zip" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 2ba986f6..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "chrome", - "request": "launch", - "name": "Launch Chrome against localhost", - "url": "http://localhost:8080", - "webRoot": "${workspaceFolder}" - } - ] -} \ No newline at end of file diff --git a/Firmware/Drivers/Inc/ADC_Sense.h b/Firmware/Drivers/Inc/ADC_Sense.h index 3c2010b4..3598cffc 100644 --- a/Firmware/Drivers/Inc/ADC_Sense.h +++ b/Firmware/Drivers/Inc/ADC_Sense.h @@ -1,24 +1,23 @@ #pragma once #include "inits.h" -#include "queue.h" -#include "UART.h" #include "ADC.h" #include "ADC_Battery_LUT.h" #include "ADC_Motor_LUT.h" #include "FaultBits.h" +#include "UART.h" +#include "queue.h" // ADC Channel 11 (Motor Voltage) and 12 (Battery Voltage) are GPIOB 12 and 2 -#define ADC1_CHANNEL ADC_CHANNEL_11 -#define ADC2_CHANNEL ADC_CHANNEL_12 -#define ADC_QUEUE_LENGTH 4 +#define ADC1_CHANNEL ADC_CHANNEL_11 +#define ADC2_CHANNEL ADC_CHANNEL_12 +#define ADC_QUEUE_LENGTH 4 #define ADC_QUEUE_ITEM_SIZE sizeof(uint16_t) -#define ADC_SAMPLING_TIME ADC_SAMPLETIME_2CYCLES_5 +#define ADC_SAMPLING_TIME ADC_SAMPLETIME_2CYCLES_5 /** * @brief ADC Initialization Function * @param adcHandle Pointer to ADC handle struct - * @retval None */ void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle); @@ -27,40 +26,36 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle); * * Contains scaled motor and battery voltages in millivolts. */ -typedef struct -{ - uint32_t Motor_Voltage; - uint32_t Battery_Voltage; +typedef struct { + uint32_t Motor_Voltage; + uint32_t Battery_Voltage; } ADC_Sense_Result; /** * @brief ADC sense function return status */ -typedef enum -{ - ADC_SENSE_OK = 0, // Operation successful - ADC_QUEUE_ERR, // Queue creation failed - ADC_1_INIT_ERR, // ADC1 initialization failed - ADC_2_INIT_ERR, // ADC2 initialization failed - ADC_1_READ_ERR, // ADC1 read failed - ADC_2_READ_ERR, // ADC2 read failed - ADC_SENSE_INIT_ERR, // Initialization not called or failed - READ_ADC_BAD_PARAM_ERR, // Bad result parameter - MOTOR_QUEUE_RECEIVE_ERR, // ADC values not received from motor ADC queue - BATTERY_QUEUE_RECEIVE_ERR // ADC values not received from battery ADC queue +typedef enum { + ADC_SENSE_OK = 0, // Operation successful + ADC_QUEUE_ERR, // Queue creation failed + ADC_1_INIT_ERR, // ADC1 initialization failed + ADC_2_INIT_ERR, // ADC2 initialization failed + ADC_1_READ_ERR, // ADC1 read failed + ADC_2_READ_ERR, // ADC2 read failed + ADC_SENSE_INIT_ERR, // Initialization not called or failed + READ_ADC_BAD_PARAM_ERR, // Bad result parameter + MOTOR_QUEUE_RECEIVE_ERR, // ADC values not received from motor ADC queue + BATTERY_QUEUE_RECEIVE_ERR // ADC values not received from battery ADC queue } ADC_Sense_Status_t; /** - * @brief Initialize ADC1 struct and calls the wrapper adc_init function to initialize ADC1 peripheral - * @param None - * @retval None + * @brief Initialize ADC1 struct and calls the wrapper adc_init function to initialize ADC1 + * peripheral */ ADC_Sense_Status_t ADC_1_Init(void); /** - * @brief Initialize ADC2 struct and calls the wrapper adc_init function to initialize ADC2 peripheral - * @param None - * @retval None + * @brief Initialize ADC2 struct and calls the wrapper adc_init function to initialize ADC2 + * peripheral */ ADC_Sense_Status_t ADC_2_Init(void); @@ -89,13 +84,11 @@ ADC_Sense_Status_t Read_ADC(uint32_t Timeout_MS, ADC_Sense_Result *Result); /** * @brief ADC1 Initialization Function * @param None - * @retval None */ void MX_ADC1_Init(void); /** * @brief ADC2 Initialization Function * @param None - * @retval None */ void MX_ADC2_Init(void); diff --git a/Firmware/Drivers/Inc/CANbus.h b/Firmware/Drivers/Inc/CANbus.h index 3a3a7b9b..52e6b796 100644 --- a/Firmware/Drivers/Inc/CANbus.h +++ b/Firmware/Drivers/Inc/CANbus.h @@ -1,34 +1,46 @@ #pragma once -#include "stm32xx_hal.h" #include "CAN_FD.h" - -extern FDCAN_HandleTypeDef *hfdcan1; -extern FDCAN_HandleTypeDef *hfdcan3; +#include "stm32xx_hal.h" +#include "MotorCAN_can_msgs.h" +#include "BPSCAN_can_msgs.h" +#include "CarCAN_can_msgs.h" +#include "SteeringCAN_can_msgs.h" extern FDCAN_HandleTypeDef *motorfdcan; extern FDCAN_HandleTypeDef *carfdcan; -can_status_t CAN_Init(void); - -can_status_t Motor_CANBus_Send(FDCAN_TxHeaderTypeDef *header, - uint8_t data[], - TickType_t delay_ticks); +can_status_t MotorCAN_Init(void); +can_status_t MotorCAN_Send(FDCAN_TxHeaderTypeDef *header, uint8_t data[], TickType_t delay_ticks); +can_status_t MotorCAN_Recv(uint32_t id, FDCAN_RxHeaderTypeDef *header, uint8_t data[], + TickType_t delay_ticks); -can_status_t Motor_CANBus_Receive(uint16_t id, - FDCAN_RxHeaderTypeDef *header, - uint8_t data[], - TickType_t delay_ticks); +can_status_t MotorCAN_Recv_Status(mc_status_t *out, TickType_t delay); +can_status_t MotorCAN_Recv_Velocity(mc_velocitymeasurement_t *out, TickType_t delay); +can_status_t MotorCAN_Recv_Control_Src(set_motor_cmd_src_t *out, TickType_t delay); -can_status_t Car_CANBus_Send(FDCAN_TxHeaderTypeDef *header, - uint8_t data[], - TickType_t delay_ticks); +can_status_t MotorCAN_Send_Drive_Cmd(float velocity, float current, TickType_t delay); +can_status_t MotorCAN_Send_Power_Cmd(float current, TickType_t delay); -can_status_t Car_CANBus_Receive(uint16_t id, - FDCAN_RxHeaderTypeDef *header, - uint8_t data[], +can_status_t CarCAN_Init(void); +can_status_t CarCAN_Send(FDCAN_TxHeaderTypeDef *header, uint8_t data[], TickType_t delay_ticks); +can_status_t CarCAN_Recv(uint32_t id, FDCAN_RxHeaderTypeDef *header, uint8_t data[], TickType_t delay_ticks); +can_status_t CarCAN_Recv_BPS_Status(bps_status_t *out, TickType_t delay); +can_status_t CarCAN_Recv_LWS(lws_standard_t *out, TickType_t delay); +can_status_t CarCAN_Recv_Driver_Input(driver_input_status_t *out, TickType_t delay); +can_status_t CarCAN_Recv_Pedals_Position(pedal_status_t *out, TickType_t delay); +can_status_t CarCAN_Recv_Brake_Pressure1(brake_pressure_1_t *out, TickType_t delay); +can_status_t CarCAN_Recv_Brake_Pressure2(brake_pressure_2_t *out, TickType_t delay); +can_status_t CarCAN_Recv_Controls_Status(controls_status_t *out, TickType_t delay); +can_status_t CarCAN_Send_Precharge_Voltages(uint32_t motor_mv, uint32_t battery_mv, + TickType_t delay); +can_status_t CarCAN_Send_Drive_Cmd(float velocity, float current, TickType_t delay); + +can_status_t CAN_Send_Drive_Cmd(float velocity, float current, TickType_t delay); + + /* HAL MSP hooks implemented in CANbus.c */ void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef *fdcanHandle); -void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef *fdcanHandle); +void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef *fdcanHandle); \ No newline at end of file diff --git a/Firmware/Drivers/Inc/Contactors.h b/Firmware/Drivers/Inc/Contactors.h index 015d3b7e..c41db371 100644 --- a/Firmware/Drivers/Inc/Contactors.h +++ b/Firmware/Drivers/Inc/Contactors.h @@ -1,18 +1,17 @@ -#pragma once + #pragma once #include "inits.h" /* Timing Definitions */ /** Time to wait for the physical contactor to settle before reading feedback */ -#define CONTACTOR_SENSE_DELAY pdMS_TO_TICKS(250) +#define CONTACTOR_SENSE_DELAY pdMS_TO_TICKS(250) /** Maximum time allowed for callback execution to prevent task starvation */ #define CALLBACK_BLOCKING_TIME pdMS_TO_TICKS(20) /** * @brief Represents the logical and physical state of a contactor. */ -typedef enum -{ +typedef enum { OPEN = 0, /**< Circuit is disconnected */ CLOSED = 1 /**< Circuit is connected */ } contactor_state_t; @@ -20,8 +19,7 @@ typedef enum /** * @brief Identification for specific contactors within the HV system. */ -typedef enum -{ +typedef enum { MOTOR_PRE_CONTACTOR, /**< Battery to Motor Contactor */ MOTOR_CONTACTOR, /**< Post-Precharge Bypass Contactor */ NUM_CONTACTORS /**< Total count helper */ @@ -30,36 +28,41 @@ typedef enum /** * @brief Contactor hardware abstraction object. */ -typedef struct -{ - contactor_state_t state; /**< Current state */ - GpioPin_t sense_pin; /**< Digital input for auxiliary feedback loop */ - GpioPin_t control_pin; /**< Digital output to coil driver/relay */ +typedef struct { + contactor_state_t state; /* Current state */ + GpioPin_t sense_pin; /* Digital input for auxiliary feedback loop */ + GpioPin_t control_pin; /* Digital output to coil driver/relay */ /* RTOS Resources */ - TimerHandle_t senseTimer; /**< Handle for non-blocking state verification */ - StaticTimer_t senseTimerBuffer; /**< Memory buffer for static timer allocation */ + TimerHandle_t senseTimer; /* Handle for non-blocking state verification */ + StaticTimer_t senseTimerBuffer; /* Memory buffer for static timer allocation */ } contactor_t; -/** @brief Hardware/RTOS init for all contactors, timers, and mutexes. */ +/** + * @brief Hardware/RTOS init for all contactors, timers, and mutexes. + */ void contactor_init(void); -/** * @brief Reads the physical sense pin for a specific contactor. +/** + * @brief Reads the physical sense pin for a specific contactor. * @return 1 if CLOSED, 0 if OPEN. */ contactor_state_t contactor_get_sense(contactor_num_t contactor_num); -/** * @brief Reads the current logical state for a specific contactor. +/** + * @brief Reads the current logical state for a specific contactor. * @return 1 if CLOSED, 0 if OPEN. */ contactor_state_t contactor_get_commanded_state(contactor_num_t contactor_num); -/** * @brief Commands a contactor state change with safety verification via callback function. +/** + * @brief Commands a contactor state change with safety verification via callback function. * @param wait_ms Wait time for sense delay before returning. * @param emergency Immediate execution; bypasses safety callbacks. * @return SUCCESS or hardware ERROR code. */ -ErrorStatus contactor_set(contactor_num_t contactor_num, contactor_state_t state, uint32_t wait_ms, fault_state_t emergency); +ErrorStatus contactor_set(contactor_num_t contactor_num, contactor_state_t state, uint32_t wait_ms, + fault_state_t emergency); /** @brief When fault is detected, opens all contactors. */ void contactor_emergency_open_all(); \ No newline at end of file diff --git a/Firmware/Drivers/Inc/FaultBits.h b/Firmware/Drivers/Inc/FaultBits.h index e76797c3..44b2208c 100644 --- a/Firmware/Drivers/Inc/FaultBits.h +++ b/Firmware/Drivers/Inc/FaultBits.h @@ -1,101 +1,213 @@ #pragma once -#include "inits.h" -#include +#include "FreeRTOS.h" +#include "event_groups.h" #include +#include + +#define FAULT_ID_LIST(X) \ + /* ============= MOTOR CONTROLLER ============ */ \ + X(MOTOR_HARDWARE_OVERCURRENT) \ + X(MOTOR_SOFTWARE_OVERCURRENT) \ + X(MOTOR_DC_BUS_OVERVOLTAGE) \ + X(MOTOR_BAD_HALL_SEQUENCE) \ + X(MOTOR_WD_RESET) \ + X(MOTOR_CONFIG_READ) \ + X(MOTOR_15V_UNDERVOLTAGE) \ + X(MOTOR_DESATURATION) \ + X(MOTOR_OVERSPEED) \ + \ + /* ================ PRECHARGE ================ */ \ + X(PRECHARGE_TIMEOUT) /* Prech sequence took too long */ \ + X(PRECHARGE_SENSE_TIMEOUT) /* Prech contactor didn't close within expected time */ \ + X(PRECHARGE_SENSE_MISMATCH) /* Prech contactor sense reading doesnt match contactor state */ \ + X(MOTOR_SENSE_TIMEOUT) /* Motor contactor didn't close within expected time */ \ + X(MOTOR_SENSE_MISMATCH) /* Motor contactor sense reading doesnt match contactor state */ \ + X(BATTERY_OVERVOLTAGE) /* Battery voltage is greater than OVERVOLTAGE_THRESHOLD_MV */ \ + X(BATTERY_UNDERVOLTAGE) /* Battery voltage is less than UNDERVOLTAGE_THRESHOLD_MV */ \ + X(MOTOR_GT_BATTERY) /* Motor voltage is greater than battery voltage */ \ + X(CONTACTOR_CALLBACK) /* Contactor state didnt match expected state after being set */ \ + X(MOTOR_LT_BATTERY) /* Motor voltage dropped below 80% of battery voltage */ \ + \ + /* ============== OTHER BOARDS =============== */ \ + X(STEERING_SENSOR_FAULT) /* Sensor not OK or data invalid */ \ + X(PEDAL_BOARD_FAULT) /* Pedal board fault or data invalid */ \ + X(CONTROLS_FAULT) /* Fault in controls status */ \ + X(BPS_FAULT) /* Fault in BPS status */ \ + X(GENERIC_WATCHDOG_FAULT) /* A generic fault triggereed by all dogs */ + +typedef enum { +#define X(name) FAULT_ID_##name, + FAULT_ID_LIST(X) +#undef X + FAULT_ID_COUNT +} FaultID_e; -#define ALL_FAULT_BITS ((1UL << NUM_FAULTS) - 1UL) - -// The max number of fault bits is dependent on the configUSE_16_BIT_TICKS defined in FreeRTOS.h #if (configUSE_16_BIT_TICKS == 0) #define MAX_FAULT_BITS 24U #else #define MAX_FAULT_BITS 8U #endif -typedef enum -{ - MOTOR_GREATER_THAN_BATTERY_FAULT, // Motor voltage is greater than battery voltage - BATTERY_OVERVOLTAGE_FAULT, // Battery voltage is greater than OVERVOLTAGE_THRESHOLD_MV - BATTERY_UNDERVOLTAGE_FAULT, // Battery voltage is less than UNDERVOLTAGE_THRESHOLD_MV - MOTOR_SENSE_TIMEOUT_FAULT, // Motor contactor didn't close within expected time - PRECHARGE_SENSE_TIMEOUT_FAULT, // Precharge contactor didn't close within expected time - PRECHARGE_TIMEOUT_FAULT, // Precharge sequence took too long - CALLBACK_FAULT, // Contactor state did not match expected state after being set - MOTOR_SENSE_MISMATCH_FAULT, // Motor contactor sense pin reading does not match contactor state - PRECHARGE_SENSE_MISMATCH_FAULT, // Precharge contactor sense pin reading does not match contactor state - BPS_FAULT, // Fault bit for any fault reported by BPS - NUM_FAULTS -} fault_bit_t; - -typedef enum -{ - PRECHARGE_WAITING_STATE, - PRECHARGE_INITIAL_STATE, // Indiciates we are in the inital state when set - PRECHARGE_PRECHARGING_STATE, // Indicates we are in the precharging state when set - PRECHARGE_RUN_STATE, // Indicates we are in the run state when set - NUM_STATES -} state_bit_t; - -#define FAULT_NUM 10 - -/* Convert enum to bitmask */ -#define FAULT_BIT(fault) (1UL << (fault)) -#define FAULT_BITMASK ((EventBits_t)((1UL << NUM_FAULTS) - 1UL)) - -#define STATE_BIT(state) (1UL << (state)) -#define STATE_BITMASK ((EventBits_t)((1UL << NUM_STATES) - 1UL)) - -_Static_assert(NUM_FAULTS <= MAX_FAULT_BITS, "Too many fault bits for EventGroup"); +_Static_assert(FAULT_ID_COUNT <= MAX_FAULT_BITS, + "Too many fault bits for EventGroup"); + +// Names for faults for printing/debugging purposes. Indexed by FaultID_e values +extern const char *fault_names[]; + +#define FAULT_BIT(id) (1UL << (id)) +#define FAULT_MASK_ALL ((1UL << FAULT_ID_COUNT) - 1) + +#define FAULT_MASK_MOTOR_ALL ( \ + FAULT_BIT(FAULT_ID_MOTOR_HARDWARE_OVERCURRENT) | \ + FAULT_BIT(FAULT_ID_MOTOR_SOFTWARE_OVERCURRENT) | \ + FAULT_BIT(FAULT_ID_MOTOR_DC_BUS_OVERVOLTAGE) | \ + FAULT_BIT(FAULT_ID_MOTOR_BAD_HALL_SEQUENCE) | \ + FAULT_BIT(FAULT_ID_MOTOR_WD_RESET) | \ + FAULT_BIT(FAULT_ID_MOTOR_CONFIG_READ) | \ + FAULT_BIT(FAULT_ID_MOTOR_15V_UNDERVOLTAGE) | \ + FAULT_BIT(FAULT_ID_MOTOR_DESATURATION) | \ + FAULT_BIT(FAULT_ID_MOTOR_OVERSPEED) \ +) + +#define FAULT_MASK_PRECHARGE_ALL ( \ + FAULT_BIT(FAULT_ID_PRECHARGE_TIMEOUT) | \ + FAULT_BIT(FAULT_ID_PRECHARGE_SENSE_TIMEOUT) | \ + FAULT_BIT(FAULT_ID_PRECHARGE_SENSE_MISMATCH) | \ + FAULT_BIT(FAULT_ID_MOTOR_SENSE_TIMEOUT) | \ + FAULT_BIT(FAULT_ID_MOTOR_SENSE_MISMATCH) | \ + FAULT_BIT(FAULT_ID_BATTERY_OVERVOLTAGE) | \ + FAULT_BIT(FAULT_ID_BATTERY_UNDERVOLTAGE) | \ + FAULT_BIT(FAULT_ID_MOTOR_GT_BATTERY) | \ + FAULT_BIT(FAULT_ID_CONTACTOR_CALLBACK) | \ + FAULT_BIT(FAULT_ID_MOTOR_LT_BATTERY) \ +) + +#define WARNING_ID_LIST(X) \ + X(MOTOR_DIRECTION_CHANGE_LOCKOUT) \ + X(TIPPING_LIMIT_ACTIVE) \ + X(REGEN_NOT_ALLOWED) \ + X(REGEN_NOT_ENABLED) + +typedef enum { +#define X(name) WARNING_ID_##name, + WARNING_ID_LIST(X) +#undef X + WARNING_ID_COUNT +} WarningID_e; + +#if (configUSE_16_BIT_TICKS == 0) +#define MAX_WARNING_BITS 24U +#else +#define MAX_WARNING_BITS 8U +#endif + +_Static_assert(WARNING_ID_COUNT <= MAX_WARNING_BITS, + "Too many warning bits for EventGroup"); + +// Names for warnings for printing/debugging purposes. Indexed by WarningID_e values +extern const char *warning_names[]; + +#define WARNING_MASK_ALL ((1UL << WARNING_ID_COUNT) - 1) + +/** + * @brief Initializes fault bitmap and associated data structures. Must be + * called before using any other functions in this module. + * + * @return true if initialization succeeded, false if it failed + */ +bool faults_init(void); + +/** + * @brief Sets a fault bit. + * + * @param id The fault ID to set. + */ +void faults_set(FaultID_e id); + +/** + * @brief Sets a fault bit from an ISR context. + * + * This is a separate function from the non-ISR version because it needs to use + * FromISR FreeRTOS APIs and handle the pxHigherPriorityTaskWoken parameter. + * + * @param id The fault ID to set. + */ +void faults_set_from_isr(FaultID_e id); + +/** + * @brief Sets multiple fault bits at once using a mask. This is useful for + * cases where multiple faults need to be set simultaneously. + * + * @param mask A bitmask of fault bits to set. Only bits corresponding to valid + * fault IDs will be set; other bits will be ignored. + */ +void faults_set_mask(EventBits_t mask); + +/** + * @brief Clears a fault bit. + * + * @param id The fault ID to clear. + */ +void faults_clear(FaultID_e id); /** - * @brief Initializes fault bitmap - * - * @param none - * @return 0 on failure, 1 on success + * @brief Checks if a specific fault bit is active. + * + * @param id The fault ID to check. + * @return true if the specified fault bit is active, false otherwise. */ -uint8_t faultBits_init(void); +bool faults_is_active(FaultID_e id); /** - * @brief Set a fault in the fault bitmap - * - * @param bit which fault is being set - * @return none + * @brief Checks if any fault bits are active. + * + * @return true if any fault bits are active, false if no fault bits are active. */ -void set_faultBit(fault_bit_t bit); +bool faults_any_active(void); /** - * @brief Wait for a fault to be set - * - * @param bit which fault to wait for, pass NUM_FAULTS if waiting for any fault - * @param xTicksToWait delay when waiting - * @return the event bit that was set + * @brief Gets the current active fault bits as a bitmask. + * + * @return A bitmask where each bit corresponds to an active fault. Only bits + * corresponding to valid fault IDs will be set; other bits will be 0. */ -EventBits_t faultBit_wait(fault_bit_t bit, TickType_t xTicksToWait); +EventBits_t faults_get(void); /** - * @brief Initializes state bitmap - * - * @param none - * @return 0 on failure, 1 on success + * @brief Waits for specific fault bits to become active. + * + * @param id The fault ID to wait for, or NUM_FAULTS to wait for any fault. + * @param ticks The maximum time to wait in ticks. Use portMAX_DELAY to wait + * indefinitely + * @return A bitmask of the fault bits that are currently active. If waiting for + * a specific fault ID, the returned bitmask will have that bit set if it became + * active. If waiting for any fault, the returned bitmask will have all active + * fault bits set. */ -uint8_t stateBits_init(void); +EventBits_t faults_wait(FaultID_e id, TickType_t ticks); /** - * @brief Set a state in the state bitmap - * - * @param bit which state is being set - * @return none + * @brief Set a warning. Non critical and just informational for driver. + * + * @param id The warning to set. */ -void set_stateBit(state_bit_t bit); +void warning_set(WarningID_e id); /** - * @brief Set a fault in the fault bitmap from an ISR - * - * @param bit which fault is being set - * @return none + * @brief Get the state of all warnings. + * @return A bitmask of fault bits that are currently active. */ -void set_faultBitFromISR(fault_bit_t bit); +EventBits_t warning_get(void); -extern EventGroupHandle_t faultStateBits; -extern EventGroupHandle_t stateBits; \ No newline at end of file +/** + * @brief Checks if a specific warning bit is active. + * @return true if the specified warning bit is active, false otherwise. + */ +bool warning_is_active(WarningID_e id); + +/** + * @brief Clear a specific warning bit. + * @param id The warning to clear. + */ +void warning_clear(WarningID_e id); \ No newline at end of file diff --git a/Firmware/Drivers/Inc/MotorSafeBits.h b/Firmware/Drivers/Inc/MotorSafeBits.h index 41d571cb..d8b00b8b 100644 --- a/Firmware/Drivers/Inc/MotorSafeBits.h +++ b/Firmware/Drivers/Inc/MotorSafeBits.h @@ -1,35 +1,36 @@ #pragma once #include "FreeRTOS.h" -#include "stm32xx_hal.h" #include "inits.h" +#include "stm32xx_hal.h" #include #include +#include // The max number of fault bits is dependent on the configUSE_16_BIT_TICKS defined in FreeRTOS.h -#if ( configUSE_16_BIT_TICKS == 0 ) - #define MAX_MOTOR_SAFE_BITS 24U +#if (configUSE_16_BIT_TICKS == 0) +#define MAX_MOTOR_SAFE_BITS 24U #else - #define MAX_MOTOR_SAFE_BITS 8U +#define MAX_MOTOR_SAFE_BITS 8U #endif -typedef enum -{ - BPS_SAFE = 0, // BPS is clear and high voltage is on - PEDALS_READING_ACCELERATOR = 1, // We're getting correct accelerator pedal messages - PEDALS_READING_BRAKE = 2, // We're getting correct brake pedal messages - MOTOR_CONTACTOR_ENABLED = 3, // The Motor contactor is enabled - MOTOR_PRECHARGE_CONTACTOR_ENABLED = 4, // The Motor precharge Contactor is enabled - DASHBOARD_IGNITION_MOTOR = 5, // Ignition switch is set to motor - NUM_MOTOR_STATUS_BITS = 6 +typedef enum { + BPS_SAFE = 0, // BPS is clear and high voltage is on + PEDALS_READING_ACCELERATOR = 1, // We're getting correct accelerator pedal messages + PEDALS_READING_BRAKE = 2, // We're getting correct brake pedal messages + MOTOR_CONTACTOR_ENABLED = 3, // The Motor contactor is enabled + MOTOR_PRECHARGE_CONTACTOR_ENABLED = 4, // The Motor precharge Contactor is enabled + DASHBOARD_IGNITION_MOTOR = 5, // Ignition switch is set to motor + NUM_MOTOR_STATUS_BITS } motor_status_bit_t; -_Static_assert(NUM_MOTOR_STATUS_BITS <= MAX_MOTOR_SAFE_BITS, "Too many motor safe bits for EventGroup"); +_Static_assert(NUM_MOTOR_STATUS_BITS <= MAX_MOTOR_SAFE_BITS, + "Too many motor safe bits for EventGroup"); /* Convert enum to bitmask */ -#define MOTOR_STATUS_BIT(motorBit) (1UL << (motorBit)) +#define MOTOR_STATUS_BIT(motorBit) (1UL << (motorBit)) -BaseType_t MotorSafeBits_Init(); +bool MotorSafeBits_Init(); EventBits_t MotorSafeBits_WaitMask(EventBits_t bitsToWait, TickType_t delay_ticks); diff --git a/Firmware/Drivers/Inc/StatusLEDs.h b/Firmware/Drivers/Inc/StatusLEDs.h index 56b04e07..c438e782 100644 --- a/Firmware/Drivers/Inc/StatusLEDs.h +++ b/Firmware/Drivers/Inc/StatusLEDs.h @@ -1,22 +1,19 @@ #pragma once -#include #include "inits.h" +#include -#define num_LEDs 15 - -/** * @brief LED States */ -typedef enum -{ +/** @brief LED States */ +typedef enum { LED_OFF = GPIO_PIN_SET, // Negative logic - LED_ON = GPIO_PIN_RESET + LED_ON = GPIO_PIN_RESET } LED_state_t; -/** * @brief Logic-to-Hardware mapping for diagnostic LEDs. +/** + * @brief Logic-to-Hardware mapping for diagnostic LEDs. * @note Values correspond to specific shift register positions. */ -typedef enum -{ +typedef enum { PRECHARGE_COMPLETE, // precharge voltage threshold reached PRECHARGE_TIMEOUT, // precharge voltage did not meet threshold in time PRECHARGE_SENSE_TIMEOUT, // precharge contactor sense did not return in time @@ -31,17 +28,18 @@ typedef enum WATCHDOG, // moco watchdog fault SWOC, // moco swoc fault MOTOR_FAULT, // moco generic fault - HB // hb led + HB, // hb led + NUM_LEDS, } Status_Mapping_t; /** @brief Sets a specific LED to on (true) or off (false). */ void LED_set(Status_Mapping_t LED, LED_state_t state); /** @brief Turns off all LEDs. */ -void LEDs_clear(void); +void LED_clear(void); /** @brief Configures GPIO pins for all diagnostic LEDs. */ -void LEDs_init(void); +void LED_init(void); /** @brief Toggle the LED */ -void Toggle_LED(Status_Mapping_t LED); +void LED_toggle(Status_Mapping_t LED); diff --git a/Firmware/Drivers/Inc/Watchdogs.h b/Firmware/Drivers/Inc/Watchdogs.h new file mode 100644 index 00000000..99304e95 --- /dev/null +++ b/Firmware/Drivers/Inc/Watchdogs.h @@ -0,0 +1,109 @@ +/** + * @file Watchdogs.h + * @brief CAN message watchdog monitoring + * @copyright Copyright (c) 2026 UT Longhorn Racing Solar + */ + +#pragma once + +#include "FreeRTOS.h" +#include "timers.h" +#include "FaultBits.h" +#include +#include + +#define MAX_WD_TIMERS 10 + +#define NODAWG 1 + +/** + * @brief List of watchdogs to create, along with their timeouts and fault IDs + * Format: X(name, string_name, timeout_ms, fault_id) + * - name: enum name for the watchdog index (e.g. WD_IDX_DRIVER_INPUT) + * - string_name: name to show in printf when the dog times out (e.g. "wd_driver_input") + * - timeout_ms: how long the watchdog should wait before timing out in milliseconds (e.g. 150) + * - fault_id: which fault to throw when the watchdog times out + * + * Currently all watchdogs throw the same generic fault, but you can specify different + * faults for each one if you want to get more specific information about which signal + * caused the fault. Just make sure to add the new fault IDs to FaultBits.h as well. + */ +#define WATCHDOG_LIST(X) \ + X(DRIVER_INPUT, "wd_driver_input", 1000U, FAULT_ID_GENERIC_WATCHDOG_FAULT) \ + X(ACCEL_BRAKE, "wd_accel_brake", 1000U, FAULT_ID_GENERIC_WATCHDOG_FAULT) \ + X(BRAKE_PRESSURE_1, "wd_brake_pressure_1", 1000U, FAULT_ID_GENERIC_WATCHDOG_FAULT) \ + X(BRAKE_PRESSURE_2, "wd_brake_pressure_2", 1000U, FAULT_ID_GENERIC_WATCHDOG_FAULT) \ + X(STEERING_ANGLE, "wd_steering_angle", 1000U, FAULT_ID_GENERIC_WATCHDOG_FAULT) \ + X(CONTROLS_STATUS, "wd_controls_status", 1000U, FAULT_ID_GENERIC_WATCHDOG_FAULT) \ + X(BPS_STATUS, "wd_bps_status", 2000U, FAULT_ID_GENERIC_WATCHDOG_FAULT) \ + X(MOCO_STATUS, "wd_moco_status", 1000U, FAULT_ID_GENERIC_WATCHDOG_FAULT) \ + X(MOCO_VELOCITY, "wd_moco_velocity", 1000U, FAULT_ID_GENERIC_WATCHDOG_FAULT) + +typedef enum { +#define X(name, str, timeout, fault) WD_IDX_##name, + WATCHDOG_LIST(X) +#undef X + WD_IDX_COUNT +} WatchdogIndex_e; + +_Static_assert(WD_IDX_COUNT <= MAX_WD_TIMERS, "Too many watchdogs; keep under the max"); + +#define X(name, str, timeout, fault) enum { WD_TIMEOUT_##name##_MS = timeout }; +WATCHDOG_LIST(X) +#undef X + + +/** + * @brief Initialize all watchdogs. This must be called before using + * any watchdog timers. + */ +void watchdog_init(void); + +/** + * @brief Create a watchdog timer for a given index. The timer will be created + * in a stopped state, so you need to call watchdog_start_all to start it after + * creating all the timers. + */ +void watchdog_create(const char *name, uint8_t idx, uint32_t timeout_ms, FaultID_e fault_id); + +/** + * @brief Start all watchdog timers. Should be called after creating all timers + * with watchdog_create, and also after handling a fault to restart the timers + * once the fault condition has been resolved. + * + * Note that if you call this function while a timer is already running, it will + * reset the timer back to its full timeout. + */ +void watchdog_start_all(void); + +/** + * @brief Stop all watchdog timers. Should be called when entering a fault state + * to prevent any watchdog timeouts from triggering additional faults while + * we're already handling a fault. + */ +void watchdog_stop_all(void); + +/** + * @brief Pet the watchdog for a given index. Should be called from the task + * context when a CAN message is received. + */ +void watchdog_received_can_message(uint8_t idx); + +/** + * @brief Pet the watchdog from an ISR context. This is a separate function from + * the non-ISR version because it needs to use FromISR FreeRTOS APIs and handle + * the pxHigherPriorityTaskWoken parameter. + */ +void watchdog_received_can_message_ISR(uint8_t idx, BaseType_t *pxHigherPriorityTaskWoken); + +/** + * @brief Check if the watchdog for a given index is alive (i.e. has been petted + * recently enough that it hasn't timed out). + */ +bool watchdog_is_alive(int idx); + +/** + * @brief Get the number of watchdog timers that have been created. Useful for + * iterating over all timers or for debugging. + */ +uint8_t watchdog_count(void); diff --git a/Firmware/Drivers/Src/ADC_Sense.c b/Firmware/Drivers/Src/ADC_Sense.c index b18ccabe..7a93d122 100644 --- a/Firmware/Drivers/Src/ADC_Sense.c +++ b/Firmware/Drivers/Src/ADC_Sense.c @@ -19,7 +19,8 @@ static ADC_ChannelConfTypeDef sConfig1 = { .SamplingTime = ADC_SAMPLING_TIME, .SingleDiff = ADC_SINGLE_ENDED, .OffsetNumber = ADC_OFFSET_NONE, - .Offset = 0}; + .Offset = 0 +}; static ADC_ChannelConfTypeDef sConfig2 = { .Channel = ADC2_CHANNEL, @@ -27,7 +28,8 @@ static ADC_ChannelConfTypeDef sConfig2 = { .SamplingTime = ADC_SAMPLING_TIME, .SingleDiff = ADC_SINGLE_ENDED, .OffsetNumber = ADC_OFFSET_NONE, - .Offset = 0}; + .Offset = 0 +}; static uint32_t HAL_RCC_ADC12_CLK_ENABLED = 0; @@ -118,7 +120,7 @@ ADC_Sense_Status_t ADC_1_Init() if (adc_init(&adc_init_1, hadc1) != ADC_OK) { // ADC1 initialization failed - set_faultBit(ADC_1_INIT_ERR); + faults_set(ADC_1_INIT_ERR); return ADC_1_INIT_ERR; } @@ -157,7 +159,7 @@ ADC_Sense_Status_t ADC_2_Init() if (adc_init(&adc_init_2, hadc2) != ADC_OK) { // ADC2 initialization failed - set_faultBit(ADC_2_INIT_ERR); + faults_set(ADC_2_INIT_ERR); return ADC_2_INIT_ERR; } @@ -179,14 +181,14 @@ ADC_Sense_Status_t ADC_Sense_Init(void) // Initialize ADCs and queues if (Motor_ADC_Queue == NULL || Battery_ADC_Queue == NULL) { // Queue creation failed - set_faultBit(ADC_QUEUE_ERR); + faults_set(ADC_QUEUE_ERR); return ADC_QUEUE_ERR; } if (ADC_1_Init() != ADC_SENSE_OK || ADC_2_Init() != ADC_SENSE_OK) { // One or both ADC initializations failed - set_faultBit(ADC_SENSE_INIT_ERR); + faults_set(ADC_SENSE_INIT_ERR); return ADC_SENSE_INIT_ERR; } @@ -199,14 +201,14 @@ ADC_Sense_Status_t Read_ADC(uint32_t Timeout_MS, ADC_Sense_Result *Result) // Re if (!Is_Initialized) { // ADC_Sense_Init has not been called or failed - set_faultBit(ADC_SENSE_INIT_ERR); + faults_set(ADC_SENSE_INIT_ERR); return ADC_SENSE_INIT_ERR; } if (Result == NULL) { // Invalid result pointer - set_faultBit(READ_ADC_BAD_PARAM_ERR); + faults_set(READ_ADC_BAD_PARAM_ERR); return READ_ADC_BAD_PARAM_ERR; } @@ -220,13 +222,13 @@ ADC_Sense_Status_t Read_ADC(uint32_t Timeout_MS, ADC_Sense_Result *Result) // Re if (adc_read(hadc1, &sConfig1, Motor_ADC_Queue) != ADC_OK) { // Motor ADC read failed - set_faultBit(ADC_1_READ_ERR); + faults_set(ADC_1_READ_ERR); return ADC_1_READ_ERR; } if (adc_read(hadc2, &sConfig2, Battery_ADC_Queue) != ADC_OK) { // Battery ADC read failed - set_faultBit(ADC_2_READ_ERR); + faults_set(ADC_2_READ_ERR); return ADC_2_READ_ERR; } @@ -237,7 +239,7 @@ ADC_Sense_Status_t Read_ADC(uint32_t Timeout_MS, ADC_Sense_Result *Result) // Re else { // Queue receive failed for motor ADC - set_faultBit(MOTOR_QUEUE_RECEIVE_ERR); + faults_set(MOTOR_QUEUE_RECEIVE_ERR); return MOTOR_QUEUE_RECEIVE_ERR; } @@ -248,7 +250,7 @@ ADC_Sense_Status_t Read_ADC(uint32_t Timeout_MS, ADC_Sense_Result *Result) // Re else { // Queue receive failed for battery ADC - set_faultBit(BATTERY_QUEUE_RECEIVE_ERR); + faults_set(BATTERY_QUEUE_RECEIVE_ERR); return BATTERY_QUEUE_RECEIVE_ERR; } diff --git a/Firmware/Drivers/Src/CANbus.c b/Firmware/Drivers/Src/CANbus.c index 587b0b85..c550c832 100644 --- a/Firmware/Drivers/Src/CANbus.c +++ b/Firmware/Drivers/Src/CANbus.c @@ -1,251 +1,598 @@ #include "CANbus.h" +#include "BPSCAN_can_msgs.h" +#include "CarCAN_can_msgs.h" +#include "MotorCAN_can_msgs.h" +#include "UpdateVCUInputsTask.h" +#include "Watchdogs.h" +#include +#include + #define FDCAN_NVIC_PRIO configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 5 -FDCAN_HandleTypeDef* motorfdcan; -FDCAN_HandleTypeDef* carfdcan; - -static can_status_t Motor_CANBus_Init(void) -{ - - motorfdcan = hfdcan1; - motorfdcan->Instance = FDCAN1; - - motorfdcan->Init.ClockDivider = FDCAN_CLOCK_DIV1; - motorfdcan->Init.FrameFormat = FDCAN_FRAME_CLASSIC; - motorfdcan->Init.Mode = FDCAN_MODE_NORMAL; - motorfdcan->Init.AutoRetransmission = ENABLE; - motorfdcan->Init.TransmitPause = DISABLE; - motorfdcan->Init.ProtocolException = DISABLE; - motorfdcan->Init.NominalPrescaler = 20; - motorfdcan->Init.NominalSyncJumpWidth = 1; - motorfdcan->Init.NominalTimeSeg1 = 13; - motorfdcan->Init.NominalTimeSeg2 = 2; - motorfdcan->Init.DataPrescaler = 1; - motorfdcan->Init.DataSyncJumpWidth = 1; - motorfdcan->Init.DataTimeSeg1 = 1; - motorfdcan->Init.DataTimeSeg2 = 1; - motorfdcan->Init.StdFiltersNbr = 1; - motorfdcan->Init.ExtFiltersNbr = 0; - motorfdcan->Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; - - // accepts all CAN IDs from - // FDCAN1 Filter Config - FDCAN_FilterTypeDef sFilterConfig1; - sFilterConfig1.IdType = FDCAN_STANDARD_ID; - sFilterConfig1.FilterIndex = 0; - sFilterConfig1.FilterType = FDCAN_FILTER_MASK; - sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; // directs frames to FIFO0 - sFilterConfig1.FilterID1 = 0x000; - sFilterConfig1.FilterID2 = 0x000; - - if (can_fd_init(motorfdcan, &sFilterConfig1) != CAN_OK) - { - return CAN_ERR; - } - - if (can_fd_start(motorfdcan) != CAN_OK) - { - return CAN_ERR; - } - - return CAN_OK; +FDCAN_HandleTypeDef *motorfdcan; +FDCAN_HandleTypeDef *carfdcan; + +can_status_t MotorCAN_Init(void) { + motorfdcan = hfdcan1; + motorfdcan->Instance = FDCAN1; + + motorfdcan->Init.ClockDivider = FDCAN_CLOCK_DIV1; + motorfdcan->Init.FrameFormat = FDCAN_FRAME_CLASSIC; + motorfdcan->Init.Mode = FDCAN_MODE_NORMAL; + motorfdcan->Init.AutoRetransmission = ENABLE; + motorfdcan->Init.TransmitPause = DISABLE; + motorfdcan->Init.ProtocolException = DISABLE; + motorfdcan->Init.NominalPrescaler = 20; + motorfdcan->Init.NominalSyncJumpWidth = 1; + motorfdcan->Init.NominalTimeSeg1 = 13; + motorfdcan->Init.NominalTimeSeg2 = 2; + motorfdcan->Init.DataPrescaler = 1; + motorfdcan->Init.DataSyncJumpWidth = 1; + motorfdcan->Init.DataTimeSeg1 = 1; + motorfdcan->Init.DataTimeSeg2 = 1; + motorfdcan->Init.StdFiltersNbr = 1; + motorfdcan->Init.ExtFiltersNbr = 0; + motorfdcan->Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; + + // accepts all CAN IDs + FDCAN_FilterTypeDef sFilterConfig1; + sFilterConfig1.IdType = FDCAN_STANDARD_ID; + sFilterConfig1.FilterIndex = 0; + sFilterConfig1.FilterType = FDCAN_FILTER_MASK; + sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; // directs frames to FIFO0 + + if (can_fd_init(motorfdcan, &sFilterConfig1) != CAN_OK) { + return CAN_ERR; + } + + if (can_fd_start(motorfdcan) != CAN_OK) { + return CAN_ERR; + } + + return CAN_OK; +} + +can_status_t MotorCAN_Send(FDCAN_TxHeaderTypeDef *header, uint8_t data[], TickType_t delay_ticks) { + return can_fd_send(motorfdcan, header, data, delay_ticks); } -static can_status_t Car_CANBus_Init(void) -{ - - carfdcan = hfdcan3; - carfdcan->Instance = FDCAN3; - - carfdcan->Init.ClockDivider = FDCAN_CLOCK_DIV1; - carfdcan->Init.FrameFormat = FDCAN_FRAME_CLASSIC; - carfdcan->Init.Mode = FDCAN_MODE_NORMAL; - carfdcan->Init.AutoRetransmission = ENABLE; - carfdcan->Init.TransmitPause = DISABLE; - carfdcan->Init.ProtocolException = DISABLE; - carfdcan->Init.NominalPrescaler = 20; - carfdcan->Init.NominalSyncJumpWidth = 1; - carfdcan->Init.NominalTimeSeg1 = 13; - carfdcan->Init.NominalTimeSeg2 = 2; - carfdcan->Init.DataPrescaler = 1; - carfdcan->Init.DataSyncJumpWidth = 1; - carfdcan->Init.DataTimeSeg1 = 1; - carfdcan->Init.DataTimeSeg2 = 1; - carfdcan->Init.StdFiltersNbr = 1; - carfdcan->Init.ExtFiltersNbr = 0; - carfdcan->Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; - - // accepts all CAN IDs from - // FDCAN1 Filter Config - FDCAN_FilterTypeDef sFilterConfig1; - sFilterConfig1.IdType = FDCAN_STANDARD_ID; - sFilterConfig1.FilterIndex = 0; - sFilterConfig1.FilterType = FDCAN_FILTER_MASK; - sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; // directs frames to FIFO0 - sFilterConfig1.FilterID1 = 0x000; - sFilterConfig1.FilterID2 = 0x000; - - if (can_fd_init(carfdcan, &sFilterConfig1) != CAN_OK) - { - return CAN_ERR; - } - - if (can_fd_start(carfdcan) != CAN_OK) - { - return CAN_ERR; - } - - return CAN_OK; +can_status_t MotorCAN_Recv(uint32_t id, FDCAN_RxHeaderTypeDef *header, uint8_t data[], + TickType_t delay_ticks) { + return can_fd_recv(motorfdcan, id, header, data, delay_ticks); } -static bool is_initialized = false; +can_status_t MotorCAN_Recv_Velocity(mc_velocitymeasurement_t *out, TickType_t delay) { + if (out == NULL) return CAN_EMPTY; -can_status_t Motor_CANBus_Send(FDCAN_TxHeaderTypeDef *header, uint8_t data[], TickType_t delay_ticks) -{ - return can_fd_send(motorfdcan, header, data, delay_ticks); + FDCAN_RxHeaderTypeDef header = {0}; + uint8_t motor_vel_rx_data[CAN_DLC_MC_VELOCITYMEASUREMENT] = {0}; + + can_status_t result = + can_fd_recv(motorfdcan, CAN_ID_MC_VELOCITYMEASUREMENT, &header, motor_vel_rx_data, delay); + + if (result == CAN_OK) { + out->MC_MotorVelocity = *((float *)&motor_vel_rx_data[0]); + out->MC_VehicleVelocity = *((float *)&motor_vel_rx_data[4]); + watchdog_received_can_message(WD_IDX_MOCO_VELOCITY); + } + return result; } -can_status_t Motor_CANBus_Receive(uint16_t id, FDCAN_RxHeaderTypeDef *header, uint8_t data[], TickType_t delay_ticks) -{ - return can_fd_recv(motorfdcan, id, header, data, delay_ticks); +can_status_t MotorCAN_Recv_Status(mc_status_t *out, TickType_t delay) { + if (out == NULL) return CAN_EMPTY; + + FDCAN_RxHeaderTypeDef header = {0}; + uint8_t moco_status_rx_data[CAN_DLC_MC_STATUS] = {0}; + + can_status_t result = + can_fd_recv(motorfdcan, CAN_ID_MC_STATUS, &header, moco_status_rx_data, delay); + + if (result == CAN_OK) { + out->MC_LIMIT_OutputVoltagePWM = (moco_status_rx_data[0] >> 0) & 0x1; + out->MC_LIMIT_MotorCurrent = (moco_status_rx_data[0] >> 1) & 0x1; + out->MC_LIMIT_Velocity = (moco_status_rx_data[0] >> 2) & 0x1; + out->MC_LIMIT_BusCurrent = (moco_status_rx_data[0] >> 3) & 0x1; + out->MC_LIMIT_BusVoltageUpper = (moco_status_rx_data[0] >> 4) & 0x1; + out->MC_LIMIT_BusVoltageLower = (moco_status_rx_data[0] >> 5) & 0x1; + out->MC_LIMIT_MotorTemp = (moco_status_rx_data[0] >> 6) & 0x1; + out->MC_LIMIT_Reserved = ((uint16_t)(moco_status_rx_data[0] >> 7) & 0x1) | + ((uint16_t)moco_status_rx_data[1] << 1); + + out->MC_FAULT_HardwareOverCurrent = (moco_status_rx_data[2] >> 0) & 0x1; + out->MC_FAULT_SoftwareOverCurrent = (moco_status_rx_data[2] >> 1) & 0x1; + out->MC_FAULT_DcBusOverVoltage = (moco_status_rx_data[2] >> 2) & 0x1; + out->MC_FAULT_BadMotorPositionHallSeq = (moco_status_rx_data[2] >> 3) & 0x1; + out->MC_FAULT_WatchdogCausedLastReset = (moco_status_rx_data[2] >> 4) & 0x1; + out->MC_FAULT_ConfigRead = (moco_status_rx_data[2] >> 5) & 0x1; + out->MC_FAULT_15vRailUnderVoltage = (moco_status_rx_data[2] >> 6) & 0x1; + out->MC_FAULT_DesaturationFault = (moco_status_rx_data[2] >> 7) & 0x1; + out->MC_FAULT_MotorOverSpeed = (moco_status_rx_data[3] >> 0) & 0x1; + out->MC_FAULT_Reserved = (moco_status_rx_data[3] >> 1) & 0x7F; + + out->MC_ActiveMotor = + (uint16_t)moco_status_rx_data[4] | ((uint16_t)moco_status_rx_data[5] << 8); + out->MC_TxErrorCount = moco_status_rx_data[6]; + out->MC_RxErrorCount = moco_status_rx_data[7]; + + watchdog_received_can_message(WD_IDX_MOCO_STATUS); + } + + return result; } -can_status_t Car_CANBus_Send(FDCAN_TxHeaderTypeDef *header, uint8_t data[], TickType_t delay_ticks) -{ - return can_fd_send(carfdcan, header, data, delay_ticks); +can_status_t MotorCAN_Recv_Control_Src(set_motor_cmd_src_t *out, TickType_t delay) { + if (out == NULL) return CAN_EMPTY; + + FDCAN_RxHeaderTypeDef header = {0}; + uint8_t moco_control_src_rx_data[CAN_DLC_SET_MOTOR_CMD_SRC] = {0}; + + can_status_t result = + can_fd_recv(motorfdcan, CAN_ID_SET_MOTOR_CMD_SRC, &header, moco_control_src_rx_data, delay); + + if (result == CAN_OK) { + out->Motor_Command_Source = moco_control_src_rx_data[0]; + } + + return result; +} + +static void Pack_Drive_Cmd(FDCAN_TxHeaderTypeDef *header, uint8_t data[], float velocity, float current){ + + header->Identifier = CAN_ID_MC_DRIVECOMMAND; + header->IdType = FDCAN_STANDARD_ID, + header->TxFrameType = FDCAN_DATA_FRAME, + header->DataLength = FDCAN_DLC_BYTES(CAN_DLC_MC_DRIVECOMMAND), + header->ErrorStateIndicator = FDCAN_ESI_ACTIVE, + header->BitRateSwitch = FDCAN_BRS_OFF, + header->FDFormat = FDCAN_CLASSIC_CAN, + header->TxEventFifoControl = FDCAN_NO_TX_EVENTS, + header->MessageMarker = 0, + + memcpy(&data[0], &velocity, sizeof(float)); + memcpy(&data[4], ¤t, sizeof(float)); } -can_status_t Car_CANBus_Receive(uint16_t id, FDCAN_RxHeaderTypeDef *header, uint8_t data[], TickType_t delay_ticks) -{ - return can_fd_recv(carfdcan, id, header, data, delay_ticks); + +can_status_t MotorCAN_Send_Drive_Cmd(float velocity, float current, TickType_t delay) { + // printf("Motor CAN send drive cmd: %f vel, %f curr", velocity, current); + if (!isfinite(velocity) || !isfinite(current)) return CAN_EMPTY; + if (g_data_read->motor_controls_src.Motor_Command_Source) return CAN_OK; + + uint8_t moco_drive_tx_data[CAN_DLC_MC_DRIVECOMMAND] = {0}; + FDCAN_TxHeaderTypeDef header; + + Pack_Drive_Cmd(&header, moco_drive_tx_data, velocity, current); + + can_status_t result = can_fd_send(motorfdcan, &header, moco_drive_tx_data, delay); + + return result; } -can_status_t CAN_Init() -{ - if (Motor_CANBus_Init() != CAN_OK) - { - return CAN_ERR; - } - if (Car_CANBus_Init() != CAN_OK) - { - return CAN_ERR; - } - - is_initialized = true; - return CAN_OK; +can_status_t CarCAN_Send_Drive_Cmd(float velocity, float current, TickType_t delay) { + if (!isfinite(velocity) || !isfinite(current)) return CAN_EMPTY; + if (g_data_read->motor_controls_src.Motor_Command_Source) return CAN_OK; + + uint8_t moco_drive_tx_data[CAN_DLC_MC_DRIVECOMMAND] = {0}; + FDCAN_TxHeaderTypeDef header; + + Pack_Drive_Cmd(&header, moco_drive_tx_data, velocity, current); + + can_status_t result = can_fd_send(carfdcan, &header, moco_drive_tx_data, delay); + + + return result; } -static uint32_t HAL_RCC_FDCAN_CLK_ENABLED = 0; +can_status_t CAN_Send_Drive_Cmd(float velocity, float current, TickType_t delay) { + // printf("Motor CAN send drive cmd: %f vel, %f curr", velocity, current); + if (!isfinite(velocity) || !isfinite(current)) return CAN_EMPTY; + if (g_data_read->motor_controls_src.Motor_Command_Source) return CAN_OK; -void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef *fdcanHandle) -{ + uint8_t moco_drive_tx_data[CAN_DLC_MC_DRIVECOMMAND] = {0}; + FDCAN_TxHeaderTypeDef header; + + Pack_Drive_Cmd(&header, moco_drive_tx_data, velocity, current); - GPIO_InitTypeDef GPIO_InitStruct = {0}; - RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; + can_status_t result = can_fd_send(carfdcan, &header, moco_drive_tx_data, delay); - if (fdcanHandle->Instance == FDCAN1) - { - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_FDCAN; - PeriphClkInit.FdcanClockSelection = RCC_FDCANCLKSOURCE_PCLK1; - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) - { - Error_Handler(); + result = can_fd_send(motorfdcan, &header, moco_drive_tx_data, delay); + + return result; +} + +can_status_t MotorCAN_Send_Power_Cmd(float current, TickType_t delay){ + // printf("Motor CAN send drive cmd: %f vel, %f curr", velocity, current); + if (!isfinite(current)) return CAN_EMPTY; + if (g_data_read->motor_controls_src.Motor_Command_Source) return CAN_OK; + + FDCAN_TxHeaderTypeDef header = { + .Identifier = CAN_ID_MC_POWERCOMMAND, + .IdType = FDCAN_STANDARD_ID, + .TxFrameType = FDCAN_DATA_FRAME, + .DataLength = FDCAN_DLC_BYTES(CAN_DLC_MC_POWERCOMMAND), + .ErrorStateIndicator = FDCAN_ESI_ACTIVE, + .BitRateSwitch = FDCAN_BRS_OFF, + .FDFormat = FDCAN_CLASSIC_CAN, + .TxEventFifoControl = FDCAN_NO_TX_EVENTS, + .MessageMarker = 0, + }; + + uint8_t moco_power_tx_data[CAN_DLC_MC_POWERCOMMAND] = {0}; + + //first 4 bytes reserved + memcpy(&moco_power_tx_data[4], ¤t, sizeof(float)); + + can_status_t result = + can_fd_send(motorfdcan, &header, moco_power_tx_data, delay); + + return result; +} + + +///////// Carcan + +can_status_t CarCAN_Init(void) { + carfdcan = hfdcan3; + carfdcan->Instance = FDCAN3; + + carfdcan->Init.ClockDivider = FDCAN_CLOCK_DIV1; + carfdcan->Init.FrameFormat = FDCAN_FRAME_CLASSIC; + carfdcan->Init.Mode = FDCAN_MODE_NORMAL; + carfdcan->Init.AutoRetransmission = DISABLE; + carfdcan->Init.TransmitPause = DISABLE; + carfdcan->Init.ProtocolException = DISABLE; + carfdcan->Init.NominalPrescaler = 20; + carfdcan->Init.NominalSyncJumpWidth = 1; + carfdcan->Init.NominalTimeSeg1 = 13; + carfdcan->Init.NominalTimeSeg2 = 2; + carfdcan->Init.DataPrescaler = 1; + carfdcan->Init.DataSyncJumpWidth = 1; + carfdcan->Init.DataTimeSeg1 = 1; + carfdcan->Init.DataTimeSeg2 = 1; + carfdcan->Init.StdFiltersNbr = 1; + carfdcan->Init.ExtFiltersNbr = 0; + carfdcan->Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; + + // accepts all CAN IDs from + // FDCAN1 Filter Config + FDCAN_FilterTypeDef CarCANFilterConfig; + CarCANFilterConfig.IdType = FDCAN_STANDARD_ID; + CarCANFilterConfig.FilterIndex = 0; + CarCANFilterConfig.FilterType = FDCAN_FILTER_MASK; + CarCANFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; // directs frames to FIFO0 + CarCANFilterConfig.FilterID1 = 0x000; + CarCANFilterConfig.FilterID2 = 0x000; + + if (can_fd_init(carfdcan, &CarCANFilterConfig) != CAN_OK) { + return CAN_ERR; } - /* FDCAN1 clock enable */ - HAL_RCC_FDCAN_CLK_ENABLED++; - if (HAL_RCC_FDCAN_CLK_ENABLED == 1) - { - __HAL_RCC_FDCAN_CLK_ENABLE(); + if (can_fd_start(carfdcan) != CAN_OK) { + return CAN_ERR; } - __HAL_RCC_GPIOA_CLK_ENABLE(); - /**FDCAN1 GPIO Configuration - PA11 ------> FDCAN1_RX - PA12 ------> FDCAN1_TX - */ - GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - - /* FDCAN1 interrupt Init */ - HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, FDCAN_NVIC_PRIO, 0); - HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn); - HAL_NVIC_SetPriority(FDCAN1_IT1_IRQn, FDCAN_NVIC_PRIO, 0); - HAL_NVIC_EnableIRQ(FDCAN1_IT1_IRQn); - } - - else if (fdcanHandle->Instance == FDCAN3) - { - /** Initializes the peripherals clocks - */ - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_FDCAN; - PeriphClkInit.FdcanClockSelection = RCC_FDCANCLKSOURCE_PCLK1; - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) - { - Error_Handler(); + return CAN_OK; +} + +can_status_t CarCAN_Send(FDCAN_TxHeaderTypeDef *header, uint8_t data[], TickType_t delay_ticks) { + return can_fd_send(carfdcan, header, data, delay_ticks); +} + +can_status_t CarCAN_Recv(uint32_t id, FDCAN_RxHeaderTypeDef *header, uint8_t data[], + TickType_t delay_ticks) { + return can_fd_recv(carfdcan, id, header, data, delay_ticks); +} + +can_status_t CarCAN_Recv_BPS_Status(bps_status_t *out, TickType_t delay) { + if (out == NULL) return CAN_EMPTY; + + FDCAN_RxHeaderTypeDef header = {0}; + uint8_t bps_status_rx_data[CAN_DLC_BPS_STATUS] = {0}; + + can_status_t result = + can_fd_recv(carfdcan, CAN_ID_BPS_STATUS, &header, bps_status_rx_data, delay); + + if (result == CAN_OK) { + out->BPS_Fault = bps_status_rx_data[0]; + out->BPS_Regen_OK = (bps_status_rx_data[1] >> 0) & 1; + out->BPS_Charge_OK = (bps_status_rx_data[1] >> 1) & 1; + out->HV_Plus_Contactor_State = (bps_status_rx_data[1] >> 2) & 1; + out->HV_Minus_Contactor_State = (bps_status_rx_data[1] >> 3) & 1; + out->Array_Contactor_State = (bps_status_rx_data[1] >> 4) & 1; + out->Array_Precharge_Contactor_State = (bps_status_rx_data[1] >> 5) & 1; + out->Main_Battery_Voltage = (uint32_t)(bps_status_rx_data[4] | + ((uint32_t)bps_status_rx_data[5] << 8) | + ((uint32_t)bps_status_rx_data[6] << 16) | + ((uint32_t)bps_status_rx_data[7] << 24)); + out->Main_Battery_Avg_Temperature = (int16_t)((uint16_t)bps_status_rx_data[2] | ((uint16_t)bps_status_rx_data[3] << 8)); + + watchdog_received_can_message(WD_IDX_BPS_STATUS); } + return result; +} + +can_status_t CarCAN_Recv_Controls_Status(controls_status_t *out, TickType_t delay) { + if (out == NULL) return CAN_EMPTY; + + FDCAN_RxHeaderTypeDef header = {0}; + uint8_t controls_status_rx_data[CAN_DLC_CONTROLS_STATUS] = {0}; - /* FDCAN3 clock enable */ - HAL_RCC_FDCAN_CLK_ENABLED++; - if (HAL_RCC_FDCAN_CLK_ENABLED == 1) - { - __HAL_RCC_FDCAN_CLK_ENABLE(); + can_status_t result = + can_fd_recv(carfdcan, CAN_ID_CONTROLS_STATUS, &header, controls_status_rx_data, delay); + + if (result == CAN_OK) { + out->Controls_Leader_Fault = controls_status_rx_data[0]; + // out->Controls_Lighting_Fault = (uint16_t) (controls_status_rx_data[1]); + watchdog_received_can_message(WD_IDX_CONTROLS_STATUS); } - __HAL_RCC_GPIOA_CLK_ENABLE(); - /**FDCAN3 GPIO Configuration - PA8 ------> FDCAN3_RX - PA15 ------> FDCAN3_TX - */ - GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_15; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF11_FDCAN3; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - - /* FDCAN3 interrupt Init */ - HAL_NVIC_SetPriority(FDCAN3_IT0_IRQn, FDCAN_NVIC_PRIO, 0); - HAL_NVIC_EnableIRQ(FDCAN3_IT0_IRQn); - HAL_NVIC_SetPriority(FDCAN3_IT1_IRQn, FDCAN_NVIC_PRIO, 0); - HAL_NVIC_EnableIRQ(FDCAN3_IT1_IRQn); - } + return result; } -void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef *fdcanHandle) -{ - if (fdcanHandle->Instance == FDCAN1) - { - /* Peripheral clock disable */ - HAL_RCC_FDCAN_CLK_ENABLED--; - if (HAL_RCC_FDCAN_CLK_ENABLED == 0) - { - __HAL_RCC_FDCAN_CLK_DISABLE(); +can_status_t CarCAN_Recv_LWS(lws_standard_t *out, TickType_t delay) { + if (out == NULL) return CAN_EMPTY; + + FDCAN_RxHeaderTypeDef header = {0}; + uint8_t steering_angle_rx_data[CAN_DLC_LWS_STANDARD] = {0}; + + can_status_t result = + can_fd_recv(carfdcan, CAN_ID_LWS_STANDARD, &header, steering_angle_rx_data, delay); + + if (result == CAN_OK) { + // Angle: Byte0 (LSB), Byte1 (MSB) + out->LWS_Angle = (int16_t)( + (steering_angle_rx_data[1] << 8) | + steering_angle_rx_data[0]); + + // Speed: Byte2 + out->LWS_Speed = steering_angle_rx_data[2]; + + // Status bits: Byte3 + out->LWS_Fault = (steering_angle_rx_data[3] >> 0) & 0x01; + out->LWS_CalibrationStaus = (steering_angle_rx_data[3] >> 1) & 0x01; + out->LWS_Trimming_Status = (steering_angle_rx_data[3] >> 2) & 0x01; + + watchdog_received_can_message(WD_IDX_STEERING_ANGLE); } - /**FDCAN1 GPIO Configuration - PA11 ------> FDCAN1_RX - PA12 ------> FDCAN1_TX - */ - HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11 | GPIO_PIN_12); - - /* FDCAN1 interrupt Deinit */ - HAL_NVIC_DisableIRQ(FDCAN1_IT0_IRQn); - HAL_NVIC_DisableIRQ(FDCAN1_IT1_IRQn); - } - - else if (fdcanHandle->Instance == FDCAN3) - { - /* Peripheral clock disable */ - HAL_RCC_FDCAN_CLK_ENABLED--; - if (HAL_RCC_FDCAN_CLK_ENABLED == 0) - { - __HAL_RCC_FDCAN_CLK_DISABLE(); + return result; +} + +can_status_t CarCAN_Recv_Driver_Input(driver_input_status_t *out, TickType_t delay) { + if (out == NULL) return CAN_EMPTY; + + FDCAN_RxHeaderTypeDef header = {0}; + uint8_t driver_input_rx_data[CAN_DLC_DRIVER_INPUT_STATUS] = {0}; + + can_status_t result = + can_fd_recv(carfdcan, CAN_ID_DRIVER_INPUT_STATUS, &header, driver_input_rx_data, delay); + + if (result == CAN_OK) { + out->Ignition_Array = !!(driver_input_rx_data[0] & (1U << 0)); + out->Ignition_Motor = !!(driver_input_rx_data[0] & (1U << 1)); + out->Ignition_Off = !!(driver_input_rx_data[0] & (1U << 2)); + out->Cruise_Enable = !!(driver_input_rx_data[0] & (1U << 3)); + out->Cruise_Set = !!(driver_input_rx_data[0] & (1U << 4)); + out->Gear_Forward = !!(driver_input_rx_data[0] & (1U << 5)); + out->Gear_Neutral = !!(driver_input_rx_data[0] & (1U << 6)); + out->Gear_Reverse = !!(driver_input_rx_data[0] & (1U << 7)); + + out->Hazard_Pressed = !!(driver_input_rx_data[1] & (1U << 0)); + out->Horn_Pressed = !!(driver_input_rx_data[1] & (1U << 1)); + out->Blinker_Left = !!(driver_input_rx_data[1] & (1U << 2)); + out->Blinker_Right = !!(driver_input_rx_data[1] & (1U << 3)); + out->PushToTalk_Pressed = !!(driver_input_rx_data[1] & (1U << 4)); + out->Regen_Activate = !!(driver_input_rx_data[1] & (1U << 5)); + out->Regen_Enable = !!(driver_input_rx_data[1] & (1U << 6)); + + watchdog_received_can_message(WD_IDX_DRIVER_INPUT); + } + + return result; +} + +can_status_t CarCAN_Recv_Pedals_Position(pedal_status_t *out, TickType_t delay) { + if (out == NULL) return CAN_EMPTY; + + FDCAN_RxHeaderTypeDef header = {0}; + uint8_t pedals_pos_rx_data[CAN_DLC_PEDAL_STATUS] = {0}; + + can_status_t result = + can_fd_recv(carfdcan, CAN_ID_PEDAL_STATUS, &header, pedals_pos_rx_data, delay); + + if (result == CAN_OK) { + out->AccelPedal_Main_Pos = pedals_pos_rx_data[0]; + out->AccelPedal_Redundant_Pos = pedals_pos_rx_data[1]; + out->BrakePedal_Main_Pos = pedals_pos_rx_data[2]; + out->BrakePedal_Redundant_Pos = pedals_pos_rx_data[3]; + + out->AccelPedal_Main_Fault = !!(pedals_pos_rx_data[4] & (1U << 0)); + out->AccelPedal_Redundant_Fault = !!(pedals_pos_rx_data[4] & (1U << 1)); + out->BrakePedal_Main_Fault = !!(pedals_pos_rx_data[4] & (1U << 2)); + out->BrakePedal_Redundant_Fault = !!(pedals_pos_rx_data[4] & (1U << 3)); + + watchdog_received_can_message(WD_IDX_ACCEL_BRAKE); + } + + return result; +} + +can_status_t CarCAN_Recv_Brake_Pressure1(brake_pressure_1_t *out, TickType_t delay) { + if (out == NULL) return CAN_EMPTY; + + FDCAN_RxHeaderTypeDef header = {0}; + uint8_t brake_pressure1_rx_data[CAN_DLC_BRAKE_PRESSURE_1] = {0}; + + can_status_t result = + can_fd_recv(carfdcan, CAN_ID_BRAKE_PRESSURE_1, &header, brake_pressure1_rx_data, delay); + + if (result == CAN_OK) { + out->Brake_Pressure = (uint16_t)(brake_pressure1_rx_data[0] | ((uint16_t)brake_pressure1_rx_data[1] << 8)); + out->Brake_Pressure_ADC = (uint16_t)(brake_pressure1_rx_data[2] | ((uint16_t)brake_pressure1_rx_data[3] << 8)); + out->FrameID_Pedals = brake_pressure1_rx_data[4]; + + watchdog_received_can_message(WD_IDX_BRAKE_PRESSURE_1); + } + + return result; +} + +can_status_t CarCAN_Recv_Brake_Pressure2(brake_pressure_2_t *out, TickType_t delay) { + if (out == NULL) return CAN_EMPTY; + + FDCAN_RxHeaderTypeDef header = {0}; + uint8_t brake_pressure2_rx_data[CAN_DLC_BRAKE_PRESSURE_2] = {0}; + + can_status_t result = + can_fd_recv(carfdcan, CAN_ID_BRAKE_PRESSURE_2, &header, brake_pressure2_rx_data, delay); + + if (result == CAN_OK) { + out->Brake_Pressure = (uint16_t)(brake_pressure2_rx_data[0] | ((uint16_t)brake_pressure2_rx_data[1] << 8)); + out->Brake_Pressure_ADC = (uint16_t)(brake_pressure2_rx_data[2] | ((uint16_t)brake_pressure2_rx_data[3] << 8)); + out->FrameID_Pedals = brake_pressure2_rx_data[4]; + + watchdog_received_can_message(WD_IDX_BRAKE_PRESSURE_2); + } + + return result; +} + +can_status_t CarCAN_Send_Precharge_Voltages(uint32_t motor_mv, uint32_t battery_mv, + TickType_t delay) { + + // printf("Car CAN send prech voltages: %lu motor_mv, %lu batt_mv\n\r", motor_mv, battery_mv); + + FDCAN_TxHeaderTypeDef header = { + .Identifier = CAN_ID_VCU_PRECHARGE_VOLTAGES, + .IdType = FDCAN_STANDARD_ID, + .TxFrameType = FDCAN_DATA_FRAME, + .DataLength = FDCAN_DLC_BYTES(CAN_DLC_VCU_PRECHARGE_VOLTAGES), + .ErrorStateIndicator = FDCAN_ESI_ACTIVE, + .BitRateSwitch = FDCAN_BRS_OFF, + .FDFormat = FDCAN_CLASSIC_CAN, + .TxEventFifoControl = FDCAN_NO_TX_EVENTS, + .MessageMarker = 0, + }; + + uint8_t vcu_prech_tx_data[CAN_DLC_VCU_PRECHARGE_VOLTAGES] = {0}; + + memcpy(&vcu_prech_tx_data[0], &motor_mv, 3); + memcpy(&vcu_prech_tx_data[3], &battery_mv, 3); + + can_status_t result = + can_fd_send(carfdcan, &header, vcu_prech_tx_data, delay); + + return result; +} + +//////// HAL bs + +static uint32_t HAL_RCC_FDCAN_CLK_ENABLED = 0; + +void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef *fdcanHandle) { + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; + + if (fdcanHandle->Instance == FDCAN1) { + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_FDCAN; + PeriphClkInit.FdcanClockSelection = RCC_FDCANCLKSOURCE_PCLK1; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { + Error_Handler(); + } + + /* FDCAN1 clock enable */ + HAL_RCC_FDCAN_CLK_ENABLED++; + if (HAL_RCC_FDCAN_CLK_ENABLED == 1) { + __HAL_RCC_FDCAN_CLK_ENABLE(); + } + + __HAL_RCC_GPIOA_CLK_ENABLE(); + /**FDCAN1 GPIO Configuration + PA11 ------> FDCAN1_RX + PA12 ------> FDCAN1_TX + */ + GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /* FDCAN1 interrupt Init */ + HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, FDCAN_NVIC_PRIO, 0); + HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn); + HAL_NVIC_SetPriority(FDCAN1_IT1_IRQn, FDCAN_NVIC_PRIO, 0); + HAL_NVIC_EnableIRQ(FDCAN1_IT1_IRQn); + } else if (fdcanHandle->Instance == FDCAN3) { + /** Initializes the peripherals clocks + */ + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_FDCAN; + PeriphClkInit.FdcanClockSelection = RCC_FDCANCLKSOURCE_PCLK1; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { + Error_Handler(); + } + + /* FDCAN3 clock enable */ + HAL_RCC_FDCAN_CLK_ENABLED++; + if (HAL_RCC_FDCAN_CLK_ENABLED == 1) { + __HAL_RCC_FDCAN_CLK_ENABLE(); + } + + __HAL_RCC_GPIOA_CLK_ENABLE(); + /**FDCAN3 GPIO Configuration + PA8 ------> FDCAN3_RX + PA15 ------> FDCAN3_TX + */ + GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_15; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF11_FDCAN3; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /* FDCAN3 interrupt Init */ + HAL_NVIC_SetPriority(FDCAN3_IT0_IRQn, FDCAN_NVIC_PRIO, 0); + HAL_NVIC_EnableIRQ(FDCAN3_IT0_IRQn); + HAL_NVIC_SetPriority(FDCAN3_IT1_IRQn, FDCAN_NVIC_PRIO, 0); + HAL_NVIC_EnableIRQ(FDCAN3_IT1_IRQn); + } +} + +void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef *fdcanHandle) { + if (fdcanHandle->Instance == FDCAN1) { + /* Peripheral clock disable */ + HAL_RCC_FDCAN_CLK_ENABLED--; + if (HAL_RCC_FDCAN_CLK_ENABLED == 0) { + __HAL_RCC_FDCAN_CLK_DISABLE(); + } + + /**FDCAN1 GPIO Configuration + PA11 ------> FDCAN1_RX + PA12 ------> FDCAN1_TX + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11 | GPIO_PIN_12); + + /* FDCAN1 interrupt Deinit */ + HAL_NVIC_DisableIRQ(FDCAN1_IT0_IRQn); + HAL_NVIC_DisableIRQ(FDCAN1_IT1_IRQn); + } else if (fdcanHandle->Instance == FDCAN3) { + /* Peripheral clock disable */ + HAL_RCC_FDCAN_CLK_ENABLED--; + if (HAL_RCC_FDCAN_CLK_ENABLED == 0) { + __HAL_RCC_FDCAN_CLK_DISABLE(); + } + + /**FDCAN3 GPIO Configuration + PA8 ------> FDCAN3_RX + PA15 ------> FDCAN3_TX + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_8 | GPIO_PIN_15); + + /* FDCAN3 interrupt Deinit */ + HAL_NVIC_DisableIRQ(FDCAN3_IT0_IRQn); + HAL_NVIC_DisableIRQ(FDCAN3_IT1_IRQn); } /**FDCAN3 GPIO Configuration @@ -257,5 +604,4 @@ void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef *fdcanHandle) /* FDCAN3 interrupt Deinit */ HAL_NVIC_DisableIRQ(FDCAN3_IT0_IRQn); HAL_NVIC_DisableIRQ(FDCAN3_IT1_IRQn); - } } diff --git a/Firmware/Drivers/Src/Contactors.c b/Firmware/Drivers/Src/Contactors.c index 5b4db6dd..b720b40d 100644 --- a/Firmware/Drivers/Src/Contactors.c +++ b/Firmware/Drivers/Src/Contactors.c @@ -4,20 +4,14 @@ static SemaphoreHandle_t contactorsMutex = NULL; static StaticSemaphore_t contactorsMutexBuffer; -static const char *CONTACTOR_NAMES[NUM_CONTACTORS] = { - "Motor Contactor", - "Motor Pre Contactor"}; +static const char *CONTACTOR_NAMES[NUM_CONTACTORS] = {"Motor Contactor", "Motor Pre Contactor"}; // array to hold the contactor structs static contactor_t contactors[NUM_CONTACTORS]; -// get -contactor_state_t contactor_get_sense(contactor_num_t contactor_num) -{ - +contactor_state_t contactor_get_sense(contactor_num_t contactor_num) { // check that contactor exists - if ((contactor_num < 0) || (contactor_num >= NUM_CONTACTORS)) - { + if ((contactor_num < 0) || (contactor_num >= NUM_CONTACTORS)) { Error_Handler(); } @@ -25,56 +19,48 @@ contactor_state_t contactor_get_sense(contactor_num_t contactor_num) return HAL_GPIO_ReadPin(contactor->sense_pin.port, contactor->sense_pin.pin); } -contactor_state_t contactor_get_commanded_state(contactor_num_t contactor_num) -{ +contactor_state_t contactor_get_commanded_state(contactor_num_t contactor_num) { // check that contactor exists - if ((contactor_num < 0) || (contactor_num >= NUM_CONTACTORS)) - { + if ((contactor_num < 0) || (contactor_num >= NUM_CONTACTORS)) { Error_Handler(); } return contactors[contactor_num].state; } -static void vContactorCallback(TimerHandle_t senseTimer) -{ - +static void vContactorCallback(TimerHandle_t senseTimer) { contactor_num_t contactor_num = (contactor_num_t)pvTimerGetTimerID(senseTimer); contactor_t *contactor = &contactors[contactor_num]; - if (contactor->state != contactor_get_sense(contactor_num)) - { - set_faultBit(CALLBACK_FAULT); + if (contactor->state != contactor_get_sense(contactor_num)) { + faults_set(FAULT_ID_CONTACTOR_CALLBACK); } } -/* sets contactor, updates state value, then starts timer to check expected state matches actual state. -An error means semaphore was busy, or that I set a contactor that didn't exist. */ -ErrorStatus contactor_set(contactor_num_t contactor_num, contactor_state_t state, uint32_t wait_ms, fault_state_t emergency) -{ - +/* sets contactor, updates state value, then starts timer to check expected state matches actual +state. An error means semaphore was busy, or that I set a contactor that didn't exist. */ +ErrorStatus contactor_set(contactor_num_t contactor_num, contactor_state_t state, uint32_t wait_ms, + fault_state_t emergency) { // check that contactor exists - if ((contactor_num < 0) || (contactor_num >= NUM_CONTACTORS)) - { + if ((contactor_num < 0) || (contactor_num >= NUM_CONTACTORS)) { return ERROR; } contactor_t *contactor = &contactors[contactor_num]; // if its emergency, dont bother with semaphore - if (!emergency && xSemaphoreTake(contactorsMutex, wait_ms) == pdFALSE) - { + if (!emergency && xSemaphoreTake(contactorsMutex, wait_ms) == pdFALSE) { return ERROR; - }; + } // critical section: HAL_GPIO_WritePin(contactor->control_pin.port, contactor->control_pin.pin, state); contactor->state = state; - /* start timer to check if the state of the contactor makes expected state, the exit critical section. Timer resets - when the contactor is set to another value, so no possible error with expected value changing from when timer is called*/ - if (!emergency) - { + /* start timer to check if the state of the contactor makes expected state, the exit critical + section. Timer resets when the contactor is set to another value, so no possible error with + expected value changing from when timer is called*/ + if (!emergency) { xTimerStart(contactor->senseTimer, 0); xSemaphoreGive(contactorsMutex); } @@ -82,9 +68,7 @@ ErrorStatus contactor_set(contactor_num_t contactor_num, contactor_state_t state return SUCCESS; } -void contactor_init() -{ - +void contactor_init() { // Enable clock for GPIO A/B/C __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); @@ -106,11 +90,8 @@ void contactor_init() contactors[MOTOR_PRE_CONTACTOR].control_pin = Precharge_Contactor_Enable; GPIO_InitTypeDef GPIO_InitStruct = {0}; - // loop to intialize contactor GPIO and timers - for (uint32_t contactor_num = 0; contactor_num < NUM_CONTACTORS; contactor_num++) - { - + for (uint32_t contactor_num = 0; contactor_num < NUM_CONTACTORS; contactor_num++) { contactor_t *contactor = &contactors[contactor_num]; // init contactor control pins @@ -141,10 +122,8 @@ void contactor_init() } } -void contactor_emergency_open_all() -{ - for (uint32_t contactor_num = 0; contactor_num < NUM_CONTACTORS; contactor_num++) - { +void contactor_emergency_open_all() { + for (uint32_t contactor_num = 0; contactor_num < NUM_CONTACTORS; contactor_num++) { contactor_set(contactor_num, OPEN, portMAX_DELAY, EMERGENCY); } } \ No newline at end of file diff --git a/Firmware/Drivers/Src/FaultBits.c b/Firmware/Drivers/Src/FaultBits.c index 72287651..d111aaba 100644 --- a/Firmware/Drivers/Src/FaultBits.c +++ b/Firmware/Drivers/Src/FaultBits.c @@ -1,87 +1,101 @@ #include "FaultBits.h" - -// Event group handle to store fault state bits -EventGroupHandle_t faultStateBits; -EventGroupHandle_t stateBits; - -// Static buffer to store the event handle -StaticEventGroup_t faultStateBitsBuffer; -StaticEventGroup_t stateBitsBuffer; - -uint8_t faultBits_init(void){ - faultStateBits = xEventGroupCreateStatic( &faultStateBitsBuffer ); - if(faultStateBits == NULL){ - return 0; +#include + +static StaticEventGroup_t faultBuffer; +static EventGroupHandle_t faultGroup; + +static StaticEventGroup_t warningBuffer; +static EventGroupHandle_t warningGroup; + +const char *fault_names[FAULT_ID_COUNT] = { +#define X(name) [FAULT_ID_##name] = #name, + FAULT_ID_LIST(X) +#undef X +}; + +const char *warning_names[WARNING_ID_COUNT] = { +#define X(name) [WARNING_ID_##name] = #name, + WARNING_ID_LIST(X) +#undef X +}; + +bool faults_init(void) { + faultGroup = xEventGroupCreateStatic(&faultBuffer); + if (faultGroup == NULL) { + return false; } - return 1; -} + xEventGroupClearBits(faultGroup, FAULT_MASK_ALL); -void set_faultBit(fault_bit_t bit){ - // not a valid fault - if(bit >= NUM_FAULTS){ - return; + warningGroup = xEventGroupCreateStatic(&warningBuffer); + if (warningGroup == NULL) { + return false; } + xEventGroupClearBits(warningGroup, WARNING_MASK_ALL); - // chat we're cooked - xEventGroupSetBits(faultStateBits, FAULT_BIT(bit)); - // should never return from here - taskYIELD(); + return true; } -void set_faultBitFromISR(fault_bit_t bit){ - BaseType_t xHigherPriorityTaskWoken = pdFALSE; +void faults_set(FaultID_e id) { + configASSERT(id < FAULT_ID_COUNT); + xEventGroupSetBits(faultGroup, FAULT_BIT(id)); +} - if(bit >= NUM_FAULTS){ - return; - } +void faults_set_from_isr(FaultID_e id) { + BaseType_t hpw = pdFALSE; + configASSERT(id < FAULT_ID_COUNT); + xEventGroupSetBitsFromISR(faultGroup, FAULT_BIT(id), &hpw); + portYIELD_FROM_ISR(hpw); +} - xEventGroupSetBitsFromISR( - faultStateBits, - FAULT_BIT(bit), - &xHigherPriorityTaskWoken - ); +void faults_set_mask(EventBits_t mask) { + xEventGroupSetBits(faultGroup, mask & FAULT_MASK_ALL); +} - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +void faults_clear(FaultID_e id) { + configASSERT(id < FAULT_ID_COUNT); + xEventGroupClearBits(faultGroup, FAULT_BIT(id)); } -uint8_t stateBits_init(void){ - stateBits = xEventGroupCreateStatic( &stateBitsBuffer ); - if(stateBits == NULL){ - return 0; - } - return 1; +bool faults_any_active(void) { + return (xEventGroupGetBits(faultGroup) & FAULT_MASK_ALL) != 0; } -void set_stateBit(state_bit_t bit){ - // not a valid state - if(bit >= NUM_STATES){ - return; - } +bool faults_is_active(FaultID_e id) { + configASSERT(id < FAULT_ID_COUNT); + return (xEventGroupGetBits(faultGroup) & FAULT_BIT(id)) != 0; +} - // Clear all state bits first - xEventGroupClearBits(stateBits, STATE_BITMASK); +EventBits_t faults_get(void) { + return xEventGroupGetBits(faultGroup) & FAULT_MASK_ALL; +} - // Set only the requested bit - xEventGroupSetBits(stateBits, STATE_BIT(bit)); +EventBits_t faults_wait(FaultID_e id, TickType_t ticks) { + EventBits_t mask = (id == FAULT_ID_COUNT) ? FAULT_MASK_ALL : FAULT_BIT(id); - taskYIELD(); + return xEventGroupWaitBits( + faultGroup, + mask, + pdFALSE, // don't clear + pdFALSE, // wait for any + ticks + ); } -EventBits_t faultBit_wait(fault_bit_t bit, TickType_t xTicksToWait){ +void warning_set(WarningID_e id) { + configASSERT(id < WARNING_ID_COUNT); + xEventGroupSetBits(warningGroup, 1 << id); +} - // NUM_FAULTS indiciates you want to wait for all bits - if(bit > NUM_FAULTS){ - return 0; - } +void warning_clear(WarningID_e id) { + configASSERT(id < WARNING_ID_COUNT); + xEventGroupClearBits(warningGroup, 1 << id); +} - EventBits_t uxBitsToWaitFor = bit == NUM_FAULTS ? FAULT_BITMASK : (FAULT_BIT(bit)); +EventBits_t warning_get(void) { + return xEventGroupGetBits(warningGroup) & WARNING_MASK_ALL; +} - EventBits_t pending = xEventGroupWaitBits( - faultStateBits, - uxBitsToWaitFor, // wait for any defined fault - pdFALSE, // fault bits are not reset - pdFALSE, // wait for ANY bit to be set - xTicksToWait - ); - return pending; +bool warning_is_active(WarningID_e id) { + configASSERT(id < WARNING_ID_COUNT); + return (xEventGroupGetBits(warningGroup) & (1 << id)) != 0; } \ No newline at end of file diff --git a/Firmware/Drivers/Src/MotorSafeBits.c b/Firmware/Drivers/Src/MotorSafeBits.c index 1e1cbf0c..8d6bb2a9 100644 --- a/Firmware/Drivers/Src/MotorSafeBits.c +++ b/Firmware/Drivers/Src/MotorSafeBits.c @@ -1,78 +1,59 @@ #include "MotorSafeBits.h" -// Event group handle to store fault state bits EventGroupHandle_t motorSafeBits; - -// Static buffer to store the event handle StaticEventGroup_t motorSafeBitsBuffer; - -BaseType_t MotorSafeBits_Init(){ - - motorSafeBits = xEventGroupCreateStatic( &motorSafeBitsBuffer ); - if(motorSafeBits == NULL){ - return pdFALSE; +bool MotorSafeBits_Init() { + motorSafeBits = xEventGroupCreateStatic(&motorSafeBitsBuffer); + if (motorSafeBits == NULL) { + return false; } - return pdTRUE; + return true; } -void set_MotorSafeBit(motor_status_bit_t bit){ +void set_MotorSafeBit(motor_status_bit_t bit) { // not a valid fault - if(bit >= NUM_MOTOR_STATUS_BITS){ - return; - } - if(motorSafeBits == NULL){ + if (bit >= NUM_MOTOR_STATUS_BITS || motorSafeBits == NULL) { return; } - + // set the bit xEventGroupSetBits(motorSafeBits, MOTOR_STATUS_BIT(bit)); } -void clear_MotorSafeBit(motor_status_bit_t bit){ - +void clear_MotorSafeBit(motor_status_bit_t bit) { // not a valid fault - if(bit >= NUM_MOTOR_STATUS_BITS){ - return; - } - if(motorSafeBits == NULL){ + if (bit >= NUM_MOTOR_STATUS_BITS || motorSafeBits == NULL) { return; } - + // set the bit xEventGroupClearBits(motorSafeBits, MOTOR_STATUS_BIT(bit)); } -EventBits_t MotorSafeBits_WaitMask(EventBits_t bitsToWait, TickType_t delay_ticks){ - - if(motorSafeBits == NULL){ +EventBits_t MotorSafeBits_WaitMask(EventBits_t bitsToWait, TickType_t delay_ticks) { + if (motorSafeBits == NULL) { return 0; } - EventBits_t pending = xEventGroupWaitBits( - motorSafeBits, - bitsToWait, // wait for the given bits to be set - pdFALSE, // fault bits are not reset - pdTRUE, // wait for all bits to be set - delay_ticks - ); - + EventBits_t pending = xEventGroupWaitBits(motorSafeBits, + bitsToWait, // wait for the given bits to be set + pdFALSE, // fault bits are not reset + pdTRUE, // wait for all bits to be set + delay_ticks); + return pending; } -EventBits_t MotorSafeBits_Wait(motor_status_bit_t motor_status_bit, TickType_t delay_ticks){ - - EventBits_t bitsToWaitFor = MOTOR_STATUS_BIT(motor_status_bit); - - if(motorSafeBits == NULL){ +EventBits_t MotorSafeBits_Wait(motor_status_bit_t motor_status_bit, TickType_t delay_ticks) { + if (motorSafeBits == NULL) { return 0; } - EventBits_t pending = xEventGroupWaitBits( - motorSafeBits, - bitsToWaitFor, // wait for the given bits to be set - pdFALSE, // fault bits are not reset - pdTRUE, // wait for all bits to be set - delay_ticks - ); - + EventBits_t bitsToWaitFor = MOTOR_STATUS_BIT(motor_status_bit); + EventBits_t pending = xEventGroupWaitBits(motorSafeBits, + bitsToWaitFor, // wait for the given bits to be set + pdFALSE, // fault bits are not reset + pdTRUE, // wait for all bits to be set + delay_ticks); + return pending; } \ No newline at end of file diff --git a/Firmware/Drivers/Src/StatusLEDs.c b/Firmware/Drivers/Src/StatusLEDs.c index 3f1c39b1..42c7ebb5 100644 --- a/Firmware/Drivers/Src/StatusLEDs.c +++ b/Firmware/Drivers/Src/StatusLEDs.c @@ -1,72 +1,62 @@ -// NOTE: LEDs are negative logic, however ON and OFF are defined such that they reflect the actual state of the LED +// NOTE: LEDs are negative logic, however ON and OFF are defined such that they reflect the actual +// state of the LED #include "StatusLEDs.h" -static uint16_t LEDbitmap; +static const GpioPin_t DebugLEDs[NUM_LEDS] = { + {PRECHARGE_COMPLETE_LED_PORT, PRECHARGE_COMPLETE_LED_PIN}, + {PRECHARGE_TO_LED_PORT, PRECHARGE_TO_LED_PIN}, + {PRECHARGE_SENSE_TO_LED_PORT, PRECHARGE_SENSE_TO_LED_PIN}, + {MOTOR_SENSE_TO_LED_PORT, MOTOR_SENSE_TO_LED_PIN}, + {DRIVABLE_LED_PORT, DRIVABLE_LED_PIN}, + {DRIVING_LED_PORT, DRIVING_LED_PIN}, + {CRUISE_LED_PORT, CRUISE_LED_PIN}, + {REGEN_LED_PORT, REGEN_LED_PIN}, + {BPS_FAULT_LED_PORT, BPS_FAULT_LED_PIN}, + {CAR_HB_LED_PORT, CAR_HB_LED_PIN}, + {HALL_EFFECT_LED_PORT, HALL_EFFECT_LED_PIN}, + {DAWG_LED_PORT, DAWG_LED_PIN}, + {SWOC_LED_PORT, SWOC_LED_PIN}, + {FAULT_LED_PORT, FAULT_LED_PIN}, + {HB_LED_PORT, HB_LED_PIN} +}; -static const GpioPin_t DebugLEDs[num_LEDs] = {{PRECHARGE_COMPLETE_LED_PORT, PRECHARGE_COMPLETE_LED_PIN}, - {PRECHARGE_TO_LED_PORT, PRECHARGE_TO_LED_PIN}, - {PRECHARGE_SENSE_TO_LED_PORT, PRECHARGE_SENSE_TO_LED_PIN}, - {MOTOR_SENSE_TO_LED_PORT, MOTOR_SENSE_TO_LED_PIN}, - {DRIVABLE_LED_PORT, DRIVABLE_LED_PIN}, - {DRIVING_LED_PORT, DRIVING_LED_PIN}, - {CRUISE_LED_PORT, CRUISE_LED_PIN}, - {REGEN_LED_PORT, REGEN_LED_PIN}, - {BPS_FAULT_LED_PORT, BPS_FAULT_LED_PIN}, - {CAR_HB_LED_PORT, CAR_HB_LED_PIN}, - {HALL_EFFECT_LED_PORT, HALL_EFFECT_LED_PIN}, - {DAWG_LED_PORT, DAWG_LED_PIN}, - {SWOC_LED_PORT, SWOC_LED_PIN}, - {FAULT_LED_PORT, FAULT_LED_PIN}, - {HB_LED_PORT, HB_LED_PIN}}; - -void Toggle_LED(Status_Mapping_t LED) -{ - if (LED < 0 || LED >= num_LEDs) { +void LED_toggle(Status_Mapping_t LED) { + if (LED < 0 || LED >= NUM_LEDS) { return; } HAL_GPIO_TogglePin(DebugLEDs[LED].port, DebugLEDs[LED].pin); } -void LED_set(Status_Mapping_t LED, LED_state_t state) -{ - // make sure LED is within bound - if(LED > num_LEDs || LED < 0){ +void LED_set(Status_Mapping_t LED, LED_state_t state) { + if (LED < 0 || LED >= NUM_LEDS) { return; } - if(LED == HB){ + if (LED == HB) { // the heartbeat LED is the only positive logic LED HAL_GPIO_WritePin(DebugLEDs[LED].port, DebugLEDs[LED].pin, !state); - } - else{ + } else { HAL_GPIO_WritePin(DebugLEDs[LED].port, DebugLEDs[LED].pin, state); } } -void LEDs_clear() -{ - LEDbitmap = 0; - for (int i = 0; i < num_LEDs; i++) - { +void LED_clear() { + for (uint8_t i = 0; i < NUM_LEDS; i++) { LED_set(i, LED_OFF); } } - -void LEDs_init() -{ - +void LED_init() { __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); - for (size_t i = 0; i < num_LEDs; ++i) - { - + for (uint8_t i = 0; i < NUM_LEDS; ++i) { GPIO_InitTypeDef led_config = { - .Mode = GPIO_MODE_OUTPUT_PP, - .Pull = GPIO_NOPULL, - .Pin = DebugLEDs[i].pin}; + .Mode = GPIO_MODE_OUTPUT_PP, + .Pull = GPIO_NOPULL, + .Pin = DebugLEDs[i].pin + }; HAL_GPIO_Init(DebugLEDs[i].port, &led_config); LED_set(i, LED_OFF); diff --git a/Firmware/Drivers/Src/UART_Init.c b/Firmware/Drivers/Src/UART_Init.c index f09bf7bf..78b7abf9 100644 --- a/Firmware/Drivers/Src/UART_Init.c +++ b/Firmware/Drivers/Src/UART_Init.c @@ -1,7 +1,38 @@ #include "UART_Init.h" -void Init_UART_Printf() +// Initializes the UART specified +void MX_UART_INIT(UART_HandleTypeDef *uartHandle) { + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; + + if (uartHandle->Instance == USART3) + { + /** Initializes the peripherals clocks + */ + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART3; + PeriphClkInit.Usart3ClockSelection = RCC_USART3CLKSOURCE_PCLK1; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) + { + Error_Handler(); + } + + /* USART3 clock enable */ + __HAL_RCC_USART3_CLK_ENABLE(); + + __HAL_RCC_GPIOC_CLK_ENABLE(); + /**USART3 GPIO Configuration + PC10 ------> USART3_TX + PC11 ------> USART3_RX + */ + GPIO_InitStruct.Pin = USART3_TX_PIN | USART3_RX_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF7_USART3; + HAL_GPIO_Init(USART3_PORT, &GPIO_InitStruct); + husart3->Instance = USART3; husart3->Init.BaudRate = 115200; husart3->Init.WordLength = UART_WORDLENGTH_8B; @@ -14,46 +45,34 @@ void Init_UART_Printf() husart3->Init.ClockPrescaler = UART_PRESCALER_DIV1; husart3->AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; - printf_init(husart3); -} - -void HAL_UART_MspGPIOInit(UART_HandleTypeDef* huart){ - - GPIO_InitTypeDef GPIO_InitStruct = {0}; - - // for the ESP32 - if(huart->Instance == LPUART1){ - __HAL_RCC_GPIOB_CLK_ENABLE(); - /**LPUART1 GPIO Configuration - PB10 ------> LPUART1_RX - PB11 ------> LPUART1_TX - */ - GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF8_LPUART1; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + if (HAL_UART_Init(husart3) != HAL_OK) + { + Error_Handler(); } - - // for printf - if(huart->Instance == USART3){ - - __HAL_RCC_GPIOC_CLK_ENABLE(); - /**USART3 GPIO Configuration - PC10 ------> USART3_TX - PC11 ------> USART3_RX - */ - GPIO_InitStruct.Pin = USART3_TX_PIN | USART3_RX_PIN; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF7_USART3; - HAL_GPIO_Init(USART3_PORT, &GPIO_InitStruct); - + if (HAL_UARTEx_SetTxFifoThreshold(husart3, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK) + { + Error_Handler(); + } + if (HAL_UARTEx_SetRxFifoThreshold(husart3, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK) + { + Error_Handler(); + } + if (HAL_UARTEx_DisableFifoMode(husart3) != HAL_OK) + { + Error_Handler(); } + } +} - setvbuf(stdout, NULL, _IONBF, 0); +void Init_UART_Printf() +{ + husart3->Init.BaudRate = 115200; + husart3->Init.WordLength = UART_WORDLENGTH_8B; + husart3->Init.StopBits = UART_STOPBITS_1; + husart3->Init.Parity = UART_PARITY_NONE; + husart3->Init.Mode = UART_MODE_TX_RX; + husart3->Init.HwFlowCtl = UART_HWCONTROL_NONE; + husart3->Init.OverSampling = UART_OVERSAMPLING_16; printf_init(husart3); } \ No newline at end of file diff --git a/Firmware/Drivers/Src/Watchdogs.c b/Firmware/Drivers/Src/Watchdogs.c new file mode 100644 index 00000000..d578388b --- /dev/null +++ b/Firmware/Drivers/Src/Watchdogs.c @@ -0,0 +1,112 @@ +/** + * @file Watchdogs.c + * @brief CAN message watchdog implementation + * @copyright Copyright (c) 2018-2026 UT Longhorn Racing Solar + */ + +#include "Watchdogs.h" +#include "FaultBits.h" +#include +#include + + +#ifndef NODAWG +static StaticEventGroup_t dogBuffer; +static EventGroupHandle_t dogGroup; // 1 = alive, 0 = dead +static StaticTimer_t wd_buffers[MAX_WD_TIMERS] = {0}; +static TimerHandle_t wd_timers[MAX_WD_TIMERS] = {0}; +static FaultID_e wd_fault_ids[MAX_WD_TIMERS] = {0}; +#endif + +static uint8_t wd_count = 0; + +#define WDOG_MASK_ALL ((1UL << WD_IDX_COUNT) - 1) +#define WDOG_BIT(idx) (1UL << idx) + +#ifndef NODAWG +// Callback function for when a watchdog timer expires +static void wd_callback(TimerHandle_t xTimer) { + uint8_t idx = (uint8_t)(uintptr_t)pvTimerGetTimerID(xTimer); + xEventGroupClearBits(dogGroup, WDOG_BIT(idx)); + printf("WD timeout: signal %d\r\n", idx); + faults_set(wd_fault_ids[idx]); +} +#endif + +void watchdog_init(void) { +#ifndef NODAWG +#define X(name, str, timeout, fault) \ + watchdog_create(str, WD_IDX_##name, timeout, fault); + WATCHDOG_LIST(X) +#undef X + dogGroup = xEventGroupCreateStatic(&dogBuffer); + if (dogGroup == NULL) { + return; + } + xEventGroupSetBits(dogGroup, WDOG_MASK_ALL); +#endif +} + +void watchdog_create(const char *name, uint8_t idx, uint32_t timeout_ms, FaultID_e fault_id) { +#ifndef NODAWG + + configASSERT(wd_count < MAX_WD_TIMERS); + configASSERT(idx < MAX_WD_TIMERS); + + TimerHandle_t t = xTimerCreateStatic( + name, + pdMS_TO_TICKS(timeout_ms), + pdFALSE, // one-shot + (void *)(uintptr_t)idx, + wd_callback, + &wd_buffers[wd_count] + ); + configASSERT(t != NULL); + wd_timers[idx] = t; + wd_fault_ids[idx] = fault_id; + wd_count++; +#endif +} + +void watchdog_start_all(void) { +#ifndef NODAWG + for (uint8_t i = 0; i < wd_count; i++) { + configASSERT(xTimerStart(wd_timers[i], portMAX_DELAY) == pdPASS); + } +#endif +} + +void watchdog_stop_all(void) { +#ifndef NODAWG + for (uint8_t i = 0; i < wd_count; i++) { + xTimerStop(wd_timers[i], portMAX_DELAY); + } +#endif +} + +void watchdog_received_can_message(uint8_t idx) { +#ifndef NODAWG + configASSERT(idx < MAX_WD_TIMERS && wd_timers[idx] != NULL); + xEventGroupSetBits(dogGroup, (0x1 << idx)); + xTimerReset(wd_timers[idx], 0); +#endif +} + +void watchdog_received_can_message_ISR(uint8_t idx, BaseType_t *pxHigherPriorityTaskWoken) { +#ifndef NODAWG + configASSERT(idx < MAX_WD_TIMERS && wd_timers[idx] != NULL); + xEventGroupClearBitsFromISR(dogGroup, WDOG_BIT(idx)); + xTimerResetFromISR(wd_timers[idx], pxHigherPriorityTaskWoken); +#endif +} + +bool watchdog_is_alive(int idx) { +#ifndef NODAWG + if (idx < 0 || idx >= MAX_WD_TIMERS) return false; + return ((xEventGroupGetBits(dogGroup) >> idx) & 0x1); +#else + return true; +#endif +} + +uint8_t watchdog_count(void) { return wd_count; } diff --git a/Firmware/Embedded-Sharepoint b/Firmware/Embedded-Sharepoint index bc3401c2..489ea138 160000 --- a/Firmware/Embedded-Sharepoint +++ b/Firmware/Embedded-Sharepoint @@ -1 +1 @@ -Subproject commit bc3401c230f732038f254a83186b5123960e9a4a +Subproject commit 489ea138be7f6689cb8dc33dc3b8d95abdf291e5 diff --git a/Firmware/Makefile b/Firmware/Makefile index a3781177..b3524a16 100644 --- a/Firmware/Makefile +++ b/Firmware/Makefile @@ -52,6 +52,10 @@ PROJECT_BUILD_DIR := $(addprefix $(MAKEFILE_DIR)/, $(PROJECT_BUILD_DIR)) # Additional defines PROJECT_MACROS = USART3_RX_QUEUE_SIZE=100 +ifeq ($(NODAWG),1) +PROJECT_MACROS += NODAWG +endif + # export variables export PROJECT_TARGET export PROJECT_C_SOURCES diff --git a/Firmware/Tasks/Inc/CanTxTelemetryTask.h b/Firmware/Tasks/Inc/CanTxTelemetryTask.h deleted file mode 100644 index f189c465..00000000 --- a/Firmware/Tasks/Inc/CanTxTelemetryTask.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "MotorCAN_can_msgs.h" -#include "stm32xx_hal.h" -#include -#include "CANbus.h" -#include "inits.h" -#include "StatusLEDs.h" -#include "pinDefs.h" -#include "InitTask.h" -#include "slcanFormat.h" - - -void CanTxTelemetryTask_Init(void); - -void Task_CanTxTelemetry(); diff --git a/Firmware/Tasks/Inc/DriverInputTask.h b/Firmware/Tasks/Inc/DriverInputTask.h deleted file mode 100644 index dcd37ac0..00000000 --- a/Firmware/Tasks/Inc/DriverInputTask.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "FaultBits.h" -#include "Contactors.h" -#include "StatusLEDs.h" -#include "ADC_Sense.h" -#include "InitTask.h" -#include "MotorSafeBits.h" -#include "CANbus.h" -#include "CarCAN_can_msgs.h" -#include - -void Init_DriverInputTestTask(); -void Task_DriverInputTest(); diff --git a/Firmware/Tasks/Inc/FSMTask.h b/Firmware/Tasks/Inc/FSMTask.h new file mode 100644 index 00000000..99317c16 --- /dev/null +++ b/Firmware/Tasks/Inc/FSMTask.h @@ -0,0 +1,102 @@ +/** + * @file FSM.h + * @brief Prohelion wavesculptor 22 motor controller FSM types and public API + * @copyright Copyright (c) 2026 UT Longhorn Racing Solar + * + * WARNING: BITFIELD_INPUT_LIST order must match BITS dict in + * scripts/fsm_generator.py. If you add/reorder entries, + * update that script and regenerate fsm_table.h. Same + * with FSMState_e + */ + +#pragma once + +#include "inits.h" +#include "CANbus.h" +#include "event_groups.h" + +/** + * @brief A list of inputs; uses X macro pattern + * @note Make sure if you change this to also change it in scripts/fsm_generator.py + */ +#define BITFIELD_INPUT_LIST(X) \ + X(NEUTRAL) \ + X(FORWARD) \ + X(REVERSE) \ + X(CRUISE_CONTROL_BUTTON) \ + X(REGEN_BUTTON) \ + X(READY_TO_REGEN) \ + X(REGEN_ENABLED) \ + X(BRAKE) \ + X(PRECHARGE_COMPLETE) + +/** + * @brief An enum of all FSM inputs + */ +typedef enum { +#define X(name) BIT_IDX_##name, + BITFIELD_INPUT_LIST(X) +#undef X + BITFIELD_INPUT_COUNT +} InputBitsIdx_e; + +#define FSM_INPUT_BIT(x) (1U << x) + +typedef enum { +#define X(name) name##_BIT = (1U << BIT_IDX_##name), + BITFIELD_INPUT_LIST(X) +#undef X +} InputBits_t; + +#define NEXT_STATES_LENGTH (1U << BITFIELD_INPUT_COUNT) +#define FSM_INPUTS_MASK_ALL ((1U << BITFIELD_INPUT_COUNT) - 1U) + +// must match in the generator script +typedef enum { + STATE_INIT = 0, + FORWARD_DRIVE, + NEUTRAL_DRIVE, + REVERSE_DRIVE, + REGEN, + CRUISE_CONTROL, + DISABLED, + CAR_NOT_READY, + NUM_STATES +} FSMState_e; + +typedef struct { + FSMState_e stateName; + void (*stateHandler)(void); + uint8_t NextStates[NEXT_STATES_LENGTH]; +} MocoState_t; + +extern MocoState_t FSM[NUM_STATES]; +extern MocoState_t current_state; + +/** + * @brief Used for stepping current down at higher speeds. An array of these will + * represent a bin for min speed and associated max current. + */ +typedef struct { + float speed_mph; + float max_current; // 0.0 to 1.0 +} swoc_threshold_t; + + +void fsm_init(void); +void fsm_step(void); +void fsm_disable(void); +void fsm_recover(void); + +void fsm_set_all_inputs(EventBits_t mask); +void fsm_set_input(EventBits_t mask); +uint16_t fsm_get_inputs(void); + +bool fsm_is_over_rollover_speed(void); + +void Task_FSM(void *args); + +float map_to_percent(uint8_t input, uint8_t in_min, uint8_t in_max, uint8_t out_min, + uint8_t out_max); + +bool fsm_is_input_set(InputBits_t bit); diff --git a/Firmware/Tasks/Inc/FaultHandlerTask.h b/Firmware/Tasks/Inc/FaultHandlerTask.h index 8dcceec2..33902381 100644 --- a/Firmware/Tasks/Inc/FaultHandlerTask.h +++ b/Firmware/Tasks/Inc/FaultHandlerTask.h @@ -9,27 +9,6 @@ #include "CarCAN_can_msgs.h" #include "MotorSafeBits.h" -#define MAX_FAULT_STRING_CHARS 20 -#define PRINTF_DELAY_MS 250 - -typedef struct{ - const char fault_string[MAX_FAULT_STRING_CHARS]; - uint8_t faultStringSize; -}fault_string_t; - - -/** @brief Initialize the fault handler task. */ -void Init_FaultHandlerTask(); /** @brief Run the fault handler task. */ void Task_FaultHandler(); - -/** @brief Kill the precharge task. */ -void Kill_Precharge_Task(); - -void Fault_Loop(); - -void Set_Fault_LED(); - -extern EventBits_t fault_bits; -extern EventBits_t state_bits; \ No newline at end of file diff --git a/Firmware/Tasks/Inc/InitTask.h b/Firmware/Tasks/Inc/InitTask.h index 12da8e69..ba40bf56 100644 --- a/Firmware/Tasks/Inc/InitTask.h +++ b/Firmware/Tasks/Inc/InitTask.h @@ -2,24 +2,21 @@ #include "FaultHandlerTask.h" #include "PrechargeTask.h" -#include "VCUReceiveCANTask.h" -#include "DriverInputTask.h" -#include "MotorSafeBits.h" -#include "MotorControlTask.h" -#include "MotorTelemetryTask.h" -#include "CanTxTelemetryTask.h" +#include "FSMTask.h" +#include "UpdateVCUInputsTask.h" +#include "VCUStatusTask.h" #include "CANbus.h" #define INIT_TASK_STACK_SIZE configMINIMAL_STACK_SIZE -#define FAULT_HANDLER_TASK_STACK_SIZE configMINIMAL_STACK_SIZE -#define PRECHARGE_TASK_STACK_SIZE configMINIMAL_STACK_SIZE -#define MOTOR_CONTROL_TASK_STACK_SIZE configMINIMAL_STACK_SIZE -#define MOTOR_TELEMETRY_TASK_STACK_SIZE configMINIMAL_STACK_SIZE -#define CAN_TX_TELEMETRY_STACK_SIZE configMINIMAL_STACK_SIZE +#define FAULT_HANDLER_TASK_STACK_SIZE configMINIMAL_STACK_SIZE * 2 +#define PRECHARGE_TASK_STACK_SIZE configMINIMAL_STACK_SIZE * 2 +#define FSM_TASK_STACK_SIZE configMINIMAL_STACK_SIZE * 2 +#define VCU_STATUS_TASK_STACK_SIZE configMINIMAL_STACK_SIZE * 2 +#define UPDATE_VCU_INPUTS_STACK_SIZE configMINIMAL_STACK_SIZE * 2 -extern StaticTask_t FaultHandlerTask_Buffer; -extern StackType_t FaultHandlerTask_Stack[FAULT_HANDLER_TASK_STACK_SIZE]; +extern StaticTask_t FaultHandler_Task_Buffer; +extern StackType_t FaultHandler_Task_Stack[FAULT_HANDLER_TASK_STACK_SIZE]; extern StaticTask_t Precharge_Task_Buffer; extern StackType_t Precharge_Task_Stack[PRECHARGE_TASK_STACK_SIZE]; @@ -27,21 +24,25 @@ extern StackType_t Precharge_Task_Stack[PRECHARGE_TASK_STACK_SIZE]; extern StaticTask_t Init_Task_Buffer; extern StackType_t Init_Task_Stack[INIT_TASK_STACK_SIZE]; -extern StaticTask_t Motor_Control_Task_Buffer; -extern StackType_t Motor_Control_Task_Stack[MOTOR_CONTROL_TASK_STACK_SIZE]; +extern StaticTask_t FSM_Task_Buffer; +extern StackType_t FSM_Task_Stack[FSM_TASK_STACK_SIZE]; -extern StaticTask_t Motor_Telemetry_Task_Buffer; -extern StackType_t Motor_Telemetry_Task_Stack[MOTOR_TELEMETRY_TASK_STACK_SIZE]; +extern StaticTask_t VCUStatus_Task_Buffer; +extern StackType_t VCUStatus_Task_Stack[VCU_STATUS_TASK_STACK_SIZE]; -extern StaticTask_t Can_Tx_Telemetry_Task_Buffer; -extern StackType_t Can_Tx_Telemetry_Task_Stack[CAN_TX_TELEMETRY_STACK_SIZE]; +extern StaticTask_t UpdateVCUInputs_Task_Buffer; +extern StackType_t UpdateVCUInputs_Task_Stack[FSM_TASK_STACK_SIZE]; + + + +#define FAULT_HANDLER_THREAD_PRIO (tskIDLE_PRIORITY + 4) +#define PRECHARGE_THREAD_PRIO (tskIDLE_PRIORITY + 3) +#define UPDATE_VCU_INPUTS_THREAD_PRIO (tskIDLE_PRIORITY + 2) +#define FSM_THREAD_PRIO (tskIDLE_PRIORITY + 2) +#define UPDATE_CONTROL_STATUS_THREAD_PRIO (tskIDLE_PRIORITY + 2) +#define VCU_STATUS_THREAD_PRIO (tskIDLE_PRIORITY + 1) +#define SDCARD_WORKER_THREAD_PRIO (tskIDLE_PRIORITY + 1) -#define FAULT_HANDLER_THREAD_PRIO (tskIDLE_PRIORITY + 4) -#define PRECHARGE_THREAD_PRIO (tskIDLE_PRIORITY + 3) -#define MOTOR_CONTROL_THREAD_PRIO (tskIDLE_PRIORITY + 2) -#define MOTOR_TELEMETRY_THREAD_PRIO (tskIDLE_PRIORITY + 1) -#define CAN_TX_TELEMETRY_THREAD_PRIO (tskIDLE_PRIORITY + 1) -#define SDCARD_WORKER_THREAD_PRIO (tskIDLE_PRIORITY + 1) // Period the fault thread runs at (once a fault is active) #define FAULT_LOOP_PERIOD_MS 500 @@ -52,8 +53,8 @@ extern StackType_t Can_Tx_Telemetry_Task_Stack[CAN_TX_TELEMETRY_STACK_SIZE]; // Period the precharge thread runs at #define PRECHARGE_TASK_DELAY_MS 100 +extern TaskHandle_t precharge_task_handle; + -extern StaticTask_t VCUReceiveCAN_Task_Buffer; -extern StackType_t VCUReceiveCAN_Task_Stack[configMINIMAL_STACK_SIZE]; -void Task_Init(); \ No newline at end of file +void Task_Init(); diff --git a/Firmware/Tasks/Inc/MotorControlTask.h b/Firmware/Tasks/Inc/MotorControlTask.h deleted file mode 100644 index e4d0321f..00000000 --- a/Firmware/Tasks/Inc/MotorControlTask.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "MotorCAN_can_msgs.h" -#include "stm32xx_hal.h" -#include -#include "CANbus.h" -#include "inits.h" -#include "MotorSafeBits.h" -#include "InitTask.h" -#include "StatusLEDs.h" - -// this one is just used for testing. TODO: swap out once controls integration starts -static const EventBits_t motorDrivableBits = MOTOR_STATUS_BIT(MOTOR_CONTACTOR_ENABLED) - | MOTOR_STATUS_BIT(MOTOR_PRECHARGE_CONTACTOR_ENABLED); -// Real motor bits -// static const EventBits_t motorDrivableBits = MOTOR_STATUS_BIT(MOTOR_CONTACTOR_ENABLED) -// | MOTOR_STATUS_BIT(MOTOR_PRECHARGE_CONTACTOR_ENABLED) -// | MOTOR_STATUS_BIT(PEDALS_READING_ACCELERATOR) -// | MOTOR_STATUS_BIT(PEDALS_READING_BRAKE) -// | MOTOR_STATUS_BIT(DASHBOARD_IGNITION_MOTOR) -// | MOTOR_STATUS_BIT(BPS_SAFE); - - -void MotorControlTask_Init(void); - -void Task_MotorControl(); diff --git a/Firmware/Tasks/Inc/PrechargeTask.h b/Firmware/Tasks/Inc/PrechargeTask.h index d9083833..66695dd3 100644 --- a/Firmware/Tasks/Inc/PrechargeTask.h +++ b/Firmware/Tasks/Inc/PrechargeTask.h @@ -1,53 +1,61 @@ #pragma once -#include "FaultBits.h" -#include "Contactors.h" -#include "StatusLEDs.h" #include "ADC_Sense.h" +#include "CANbus.h" +#include "Contactors.h" +#include "FaultBits.h" #include "InitTask.h" #include "MotorSafeBits.h" -#include "CANbus.h" -#include "CarCAN_can_msgs.h" +#include "StatusLEDs.h" #include -#include "VCUReceiveCANTask.h" // Precharge thresholds -#define OVERVOLTAGE_THRESHOLD_MV 140000 // 140 V -#define UNDERVOLTAGE_THRESHOLD_MV 80000 // 80.0 V +#define OVERVOLTAGE_THRESHOLD_MV 180000 // 140 V +#define UNDERVOLTAGE_THRESHOLD_MV 80000 // 80.0 V // Fixed-point scaling for ratio comparisons -#define RATIO_SCALE 1000 +#define RATIO_SCALE 1000 // 900/1000 = 0.900, 800/1000 = 0.800 // TODO: Test and increase hysterisis threshold closer to 90% -#define PRECHARGE_THRESHOLD_90 900 -#define PRECHARGE_THRESHOLD_80 800 // NOTE: The second threshold exists to account for hysteresis, so that we don't drop out of the run state after successfully precharging just because of a small ADC reading change +#define PRECHARGE_THRESHOLD_90 900 +#define PRECHARGE_THRESHOLD_80 800 +// NOTE: The second threshold exists to account for hysteresis, so that we don't drop out of +// the run state after successfully precharging just because of a small ADC reading change // Allowed difference between motor and battery voltage -#define VOLTAGE_TOLERANCE_NUMERATOR 22 -#define VOLTAGE_TOLERANCE_DENOMINATOR 20 // Motor voltage can at most 10% higher than battery voltage +#define VOLTAGE_TOLERANCE_NUMERATOR 22 +// Motor voltage can at most 10% higher than battery voltage +#define VOLTAGE_TOLERANCE_DENOMINATOR 20 -#define PRECHARGE_TIMEOUT_MS 400 // Precharge time to 90% -> 0.9 = 1 - e^(-t/RC), so t = -RC * ln(1-0.9) = 2.3*RC. For our case, R = 110 Ohms and C = 1 mF -> t = 253 ms. -#define ADC_TIMEOUT_MS 20 +// Precharge time to 90% -> 0.9 = 1 - e^(-t/RC), so t = -RC * ln(1-0.9) = 2.3*RC. +// For our case, R = 110 Ohms and C = 1 mF -> t = 253 ms. +#define PRECHARGE_TIMEOUT_MS 400 +#define ADC_TIMEOUT_MS 20 -typedef enum -{ - PRECHARGE_STATE_WAITING, // Waiting for ignition state - PRECHARGE_STATE_INITIAL, // Precharge sequence hasn't started, start by closing main contactor and starting a timer to check for precharge timeout - PRECHARGE_STATE_PRECHARGING, // Precharge sequence started successfully, close contactor and check hysterisis - PRECHARGE_STATE_RUN, // Precharge got through hysterisis, now continuously polling ADC - PRECHARGE_STATE_NUM -} Precharge_State_t; +#define PRECHARGE_STATE_LIST(X) \ + X(WAITING) /* Waiting for ignition state */ \ + X(INITIAL) /* Precharge hasn't started; closing main contactor and starting timer */ \ + X(PRECHARGING) /* Precharge started successfully, close contactor and check hysterisis */ \ + X(COMPLETE) /* Precharge got through hysterisis, now continuously polling ADC */ + +typedef enum { +#define X(name) PRECHARGE_STATE_##name, + PRECHARGE_STATE_LIST(X) +#undef X + PRECHARGE_STATE_COUNT +} PrechargeState_e; + +// Names for faults for printing/debugging purposes. Indexed by FaultID_e values +extern const char *precharge_state_names[]; + +#define PRECHARGE_STATE_BIT(state) (1UL << (state)) +#define PRECHARGE_STATE_MASK ((EventBits_t)((1UL << NUM_PRECHARGE_STATES) - 1UL)) -/** - * @brief Precharge task initialization function, initializes ADC, printf, and contactors - * @param None - * @retval None - */ -void Init_PrechargeTask(); /** - * @brief Checks the repeated fault conditions for precharge sequence, if any fault condition is met, will call fault handler and not return + * @brief Checks the repeated fault conditions for precharge sequence, if any fault condition is + * met, will call fault handler and not return * @param Motor_Voltage most recent motor voltage reading in mV * @param Battery_Voltage most recent battery voltage reading in mV * @retval None @@ -55,17 +63,12 @@ void Init_PrechargeTask(); void Fault_Checker(uint32_t Motor_Voltage, uint32_t Battery_Voltage); /** - * @brief Precharge task main execution function, implements precharge pseudo state machine and fault handling + * @brief Precharge task main execution function, implements precharge pseudo state machine and + * fault handling * @param None * @retval None */ void Task_Precharge(); -void Ignition_Off(); - -/* handle for the Precharge task, defined in PrechargeTask.c */ -extern TaskHandle_t hprecharge_task; - -extern uint32_t Battery_Voltage; -extern uint32_t Motor_Voltage; -extern uint8_t Ignition_State; \ No newline at end of file +extern uint32_t battery_voltage; +extern uint32_t motor_voltage; \ No newline at end of file diff --git a/Firmware/Tasks/Inc/ReadMotorCAN.h b/Firmware/Tasks/Inc/ReadMotorCAN.h deleted file mode 100644 index 93c44155..00000000 --- a/Firmware/Tasks/Inc/ReadMotorCAN.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "stm32xx_hal.h" -#include "CANbus.h" -#include "CAN_FD.h" -#include "MotorCAN_can_msgs.h" - -void Init_ReadMotorCAN(); - -void Task_ReadMotorCAN(); diff --git a/Firmware/Tasks/Inc/UpdateVCUInputsTask.h b/Firmware/Tasks/Inc/UpdateVCUInputsTask.h new file mode 100644 index 00000000..f70ab4f6 --- /dev/null +++ b/Firmware/Tasks/Inc/UpdateVCUInputsTask.h @@ -0,0 +1,28 @@ +#pragma once + +#include "inits.h" +#include "CANbus.h" +#include "FSMTask.h" + +#define BRAKE_THRESH 0.0f // psi +#define BRAKE_THRESH_HYST 0.0f // psi + +#define ACCEPTABLE_PEDAL_DEVIATION 3 // percent + +typedef struct { + driver_input_status_t driver_input; + pedal_status_t accel_brake; + brake_pressure_1_t brake_pressure1; + brake_pressure_2_t brake_pressure2; + lws_standard_t lws; + controls_status_t controls_status; + mc_status_t motor_status; + bps_status_t bps_status; + mc_velocitymeasurement_t motor_velocity; + set_motor_cmd_src_t motor_controls_src; +} VCUDataIn_t; + +extern VCUDataIn_t * volatile g_data_read; +extern VCUDataIn_t * volatile g_data_write; + +void Task_UpdateVCUInputs(void *args __attribute__((unused))); diff --git a/Firmware/Tasks/Inc/VCUReceiveCANTask.h b/Firmware/Tasks/Inc/VCUReceiveCANTask.h deleted file mode 100644 index a84fd3dc..00000000 --- a/Firmware/Tasks/Inc/VCUReceiveCANTask.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "StatusLEDs.h" -#include "InitTask.h" -#include "MotorSafeBits.h" -#include "CANbus.h" -#include "CarCAN_can_msgs.h" -#include -#include "PrechargeTask.h" - -// enables the fdcan3 recieve hook, calls can_fd_rx_callback_hook everytime a can rx interrupt happens -#define FDCAN3_RECV_HOOK_EN -#define DRIVER_INPUT_QUEUE_SIZE 32 -#define BPS_QUEUE_SIZE 32 -#define IGNITION_MOTOR_INDEX 1 // index of motor ignition in driver input status message -#define CAN_BLOCKING_TIME_MS 100 - -extern uint8_t Start_Precharge; -extern uint8_t End_Precharge; - -void Task_VCUReceiveCAN(); \ No newline at end of file diff --git a/Firmware/Tasks/Inc/VCUStatusTask.h b/Firmware/Tasks/Inc/VCUStatusTask.h new file mode 100644 index 00000000..f04a6f2e --- /dev/null +++ b/Firmware/Tasks/Inc/VCUStatusTask.h @@ -0,0 +1,6 @@ +#pragma once + +#include "inits.h" + + +void Task_BroadcastVCUStatus(void *args __attribute__((unused))); \ No newline at end of file diff --git a/Firmware/Tasks/Inc/fsm_table.h b/Firmware/Tasks/Inc/fsm_table.h new file mode 100644 index 00000000..166018ee --- /dev/null +++ b/Firmware/Tasks/Inc/fsm_table.h @@ -0,0 +1,544 @@ +/** + * @file fsm_table.h + * @brief Auto-generated FSM table (FULL); do not edit + * Regenerate: python3 generate_fsm.py --full + */ + +#pragma once +#include "FSMTask.h" + +extern MocoState_t FSM[NUM_STATES]; + +#ifdef DEFINE_FSM_TABLE +MocoState_t FSM[NUM_STATES] = { + + [STATE_INIT] = { STATE_INIT, NULL, { + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY + }}, + [FORWARD_DRIVE] = { FORWARD_DRIVE, NULL, { + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + CRUISE_CONTROL, NEUTRAL_DRIVE, CRUISE_CONTROL, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + CRUISE_CONTROL, NEUTRAL_DRIVE, CRUISE_CONTROL, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + CRUISE_CONTROL, NEUTRAL_DRIVE, CRUISE_CONTROL, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + REGEN, NEUTRAL_DRIVE, REGEN, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + REGEN, NEUTRAL_DRIVE, REGEN, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + CRUISE_CONTROL, NEUTRAL_DRIVE, CRUISE_CONTROL, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + CRUISE_CONTROL, NEUTRAL_DRIVE, CRUISE_CONTROL, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + CRUISE_CONTROL, NEUTRAL_DRIVE, CRUISE_CONTROL, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + REGEN, NEUTRAL_DRIVE, REGEN, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + REGEN, NEUTRAL_DRIVE, REGEN, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE + }}, + [NEUTRAL_DRIVE] = { NEUTRAL_DRIVE, NULL, { + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE + }}, + [REVERSE_DRIVE] = { REVERSE_DRIVE, NULL, { + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE + }}, + [REGEN] = { REGEN, NULL, { + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN, FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN, + FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN, FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN, FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN, + FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN, FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN, FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN, + FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN, FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN, FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN, + FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN, FORWARD_DRIVE, FORWARD_DRIVE, REGEN, REGEN + }}, + [CRUISE_CONTROL] = { CRUISE_CONTROL, NULL, { + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, + FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, + CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL, CRUISE_CONTROL + }}, + [DISABLED] = { DISABLED, NULL, { + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED + }}, + [CAR_NOT_READY] = { CAR_NOT_READY, NULL, { + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE + }}, +}; +#endif diff --git a/Firmware/Tasks/Inc/fsm_table_dnr.h b/Firmware/Tasks/Inc/fsm_table_dnr.h new file mode 100644 index 00000000..a8b384a2 --- /dev/null +++ b/Firmware/Tasks/Inc/fsm_table_dnr.h @@ -0,0 +1,544 @@ +/** + * @file fsm_table_dnr.h + * @brief Auto-generated FSM table (DNR); do not edit + * Regenerate: python3 generate_fsm.py --dnr + */ + +#pragma once +#include "FSMTask.h" + +extern MocoState_t FSM[NUM_STATES]; + +#ifdef DEFINE_FSM_TABLE +MocoState_t FSM[NUM_STATES] = { + + [STATE_INIT] = { STATE_INIT, NULL, { + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY + }}, + [FORWARD_DRIVE] = { FORWARD_DRIVE, NULL, { + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE + }}, + [NEUTRAL_DRIVE] = { NEUTRAL_DRIVE, NULL, { + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, FORWARD_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE + }}, + [REVERSE_DRIVE] = { REVERSE_DRIVE, NULL, { + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, REVERSE_DRIVE, REVERSE_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE + }}, + [REGEN] = { REGEN, NULL, { + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE + }}, + [CRUISE_CONTROL] = { CRUISE_CONTROL, NULL, { + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + FORWARD_DRIVE, NEUTRAL_DRIVE, FORWARD_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE + }}, + [DISABLED] = { DISABLED, NULL, { + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, + DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED, DISABLED + }}, + [CAR_NOT_READY] = { CAR_NOT_READY, NULL, { + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, CAR_NOT_READY, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, + NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE, NEUTRAL_DRIVE + }}, +}; +#endif diff --git a/Firmware/Tasks/Inc/rollover_speed_table.h b/Firmware/Tasks/Inc/rollover_speed_table.h new file mode 100644 index 00000000..2a7264de --- /dev/null +++ b/Firmware/Tasks/Inc/rollover_speed_table.h @@ -0,0 +1,111 @@ +/** + * @file rollover_speed_table.h + * @brief Auto-generated rollover speed limit lookup table — do not edit + * Regenerate: python3 scripts/generate_rollover_table.py + * + * Index : abs(LWS_Angle / 10) [integer degrees, 0-720] + * Value : max allowable speed in cm/s | 0xFFFF = no limit (straight) + */ + +#pragma once + +#include + +#define ROLLOVER_TABLE_NO_LIMIT 0xFFFFU +#define ROLLOVER_TABLE_MAX_DEG 720U + +// Index: abs(LWS_Angle / 10) in integer degrees (0-720) +// Value: max allowable speed in cm/s | 0xFFFF = no limit +static const uint16_t rollover_speed_table[721] = { + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // 0-7 deg + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // 8-15 deg + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // 16-23 deg + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x09D8, 0x09AF, // 24-31 deg + 0x0988, 0x0963, 0x093F, 0x091D, 0x08FD, 0x08DD, 0x08BF, 0x08A2, // 32-39 deg + 0x0886, 0x086B, 0x0852, 0x0839, 0x0821, 0x0809, 0x07F3, 0x07DD, // 40-47 deg + 0x07C8, 0x07B3, 0x079F, 0x078C, 0x0779, 0x0767, 0x0756, 0x0744, // 48-55 deg + 0x0734, 0x0723, 0x0714, 0x0704, 0x06F5, 0x06E6, 0x06D8, 0x06CA, // 56-63 deg + 0x06BC, 0x06AF, 0x06A2, 0x0695, 0x0688, 0x067C, 0x0670, 0x0665, // 64-71 deg + 0x0659, 0x064E, 0x0643, 0x0638, 0x062E, 0x0623, 0x0619, 0x060F, // 72-79 deg + 0x0605, 0x05FC, 0x05F2, 0x05E9, 0x05E0, 0x05D7, 0x05CE, 0x05C6, // 80-87 deg + 0x05BD, 0x05B5, 0x05AD, 0x05A5, 0x059D, 0x0595, 0x058D, 0x0586, // 88-95 deg + 0x057E, 0x0577, 0x0570, 0x0568, 0x0561, 0x055B, 0x0554, 0x054D, // 96-103 deg + 0x0546, 0x0540, 0x0539, 0x0533, 0x052D, 0x0527, 0x0521, 0x051B, // 104-111 deg + 0x0515, 0x050F, 0x0509, 0x0503, 0x04FE, 0x04F8, 0x04F3, 0x04ED, // 112-119 deg + 0x04E8, 0x04E3, 0x04DE, 0x04D8, 0x04D3, 0x04CE, 0x04C9, 0x04C4, // 120-127 deg + 0x04C0, 0x04BB, 0x04B6, 0x04B1, 0x04AD, 0x04A8, 0x04A4, 0x049F, // 128-135 deg + 0x049B, 0x0496, 0x0492, 0x048E, 0x048A, 0x0485, 0x0481, 0x047D, // 136-143 deg + 0x0479, 0x0475, 0x0471, 0x046D, 0x0469, 0x0465, 0x0461, 0x045E, // 144-151 deg + 0x045A, 0x0456, 0x0452, 0x044F, 0x044B, 0x0448, 0x0444, 0x0440, // 152-159 deg + 0x043D, 0x043A, 0x0436, 0x0433, 0x042F, 0x042C, 0x0429, 0x0425, // 160-167 deg + 0x0422, 0x041F, 0x041C, 0x0419, 0x0415, 0x0412, 0x040F, 0x040C, // 168-175 deg + 0x0409, 0x0406, 0x0403, 0x0400, 0x03FD, 0x03FA, 0x03F7, 0x03F5, // 176-183 deg + 0x03F2, 0x03EF, 0x03EC, 0x03E9, 0x03E7, 0x03E4, 0x03E1, 0x03DE, // 184-191 deg + 0x03DC, 0x03D9, 0x03D7, 0x03D4, 0x03D1, 0x03CF, 0x03CC, 0x03CA, // 192-199 deg + 0x03C7, 0x03C5, 0x03C2, 0x03C0, 0x03BD, 0x03BB, 0x03B8, 0x03B6, // 200-207 deg + 0x03B4, 0x03B1, 0x03AF, 0x03AD, 0x03AA, 0x03A8, 0x03A6, 0x03A3, // 208-215 deg + 0x03A1, 0x039F, 0x039D, 0x039B, 0x0398, 0x0396, 0x0394, 0x0392, // 216-223 deg + 0x0390, 0x038E, 0x038B, 0x0389, 0x0387, 0x0385, 0x0383, 0x0381, // 224-231 deg + 0x037F, 0x037D, 0x037B, 0x0379, 0x0377, 0x0375, 0x0373, 0x0371, // 232-239 deg + 0x036F, 0x036D, 0x036B, 0x0369, 0x0368, 0x0366, 0x0364, 0x0362, // 240-247 deg + 0x0360, 0x035E, 0x035C, 0x035B, 0x0359, 0x0357, 0x0355, 0x0353, // 248-255 deg + 0x0352, 0x0350, 0x034E, 0x034C, 0x034B, 0x0349, 0x0347, 0x0346, // 256-263 deg + 0x0344, 0x0342, 0x0341, 0x033F, 0x033D, 0x033C, 0x033A, 0x0338, // 264-271 deg + 0x0337, 0x0335, 0x0333, 0x0332, 0x0330, 0x032F, 0x032D, 0x032C, // 272-279 deg + 0x032A, 0x0328, 0x0327, 0x0325, 0x0324, 0x0322, 0x0321, 0x031F, // 280-287 deg + 0x031E, 0x031C, 0x031B, 0x0319, 0x0318, 0x0316, 0x0315, 0x0313, // 288-295 deg + 0x0312, 0x0311, 0x030F, 0x030E, 0x030C, 0x030B, 0x030A, 0x0308, // 296-303 deg + 0x0307, 0x0305, 0x0304, 0x0303, 0x0301, 0x0300, 0x02FF, 0x02FD, // 304-311 deg + 0x02FC, 0x02FA, 0x02F9, 0x02F8, 0x02F7, 0x02F5, 0x02F4, 0x02F3, // 312-319 deg + 0x02F1, 0x02F0, 0x02EF, 0x02ED, 0x02EC, 0x02EB, 0x02EA, 0x02E8, // 320-327 deg + 0x02E7, 0x02E6, 0x02E5, 0x02E3, 0x02E2, 0x02E1, 0x02E0, 0x02DE, // 328-335 deg + 0x02DD, 0x02DC, 0x02DB, 0x02DA, 0x02D8, 0x02D7, 0x02D6, 0x02D5, // 336-343 deg + 0x02D4, 0x02D3, 0x02D1, 0x02D0, 0x02CF, 0x02CE, 0x02CD, 0x02CC, // 344-351 deg + 0x02CA, 0x02C9, 0x02C8, 0x02C7, 0x02C6, 0x02C5, 0x02C4, 0x02C3, // 352-359 deg + 0x02C2, 0x02C0, 0x02BF, 0x02BE, 0x02BD, 0x02BC, 0x02BB, 0x02BA, // 360-367 deg + 0x02B9, 0x02B8, 0x02B7, 0x02B6, 0x02B5, 0x02B3, 0x02B2, 0x02B1, // 368-375 deg + 0x02B0, 0x02AF, 0x02AE, 0x02AD, 0x02AC, 0x02AB, 0x02AA, 0x02A9, // 376-383 deg + 0x02A8, 0x02A7, 0x02A6, 0x02A5, 0x02A4, 0x02A3, 0x02A2, 0x02A1, // 384-391 deg + 0x02A0, 0x029F, 0x029E, 0x029D, 0x029C, 0x029B, 0x029A, 0x0299, // 392-399 deg + 0x0298, 0x0297, 0x0296, 0x0295, 0x0294, 0x0293, 0x0293, 0x0292, // 400-407 deg + 0x0291, 0x0290, 0x028F, 0x028E, 0x028D, 0x028C, 0x028B, 0x028A, // 408-415 deg + 0x0289, 0x0288, 0x0287, 0x0286, 0x0286, 0x0285, 0x0284, 0x0283, // 416-423 deg + 0x0282, 0x0281, 0x0280, 0x027F, 0x027E, 0x027D, 0x027D, 0x027C, // 424-431 deg + 0x027B, 0x027A, 0x0279, 0x0278, 0x0277, 0x0277, 0x0276, 0x0275, // 432-439 deg + 0x0274, 0x0273, 0x0272, 0x0271, 0x0271, 0x0270, 0x026F, 0x026E, // 440-447 deg + 0x026D, 0x026C, 0x026B, 0x026B, 0x026A, 0x0269, 0x0268, 0x0267, // 448-455 deg + 0x0267, 0x0266, 0x0265, 0x0264, 0x0263, 0x0262, 0x0262, 0x0261, // 456-463 deg + 0x0260, 0x025F, 0x025E, 0x025E, 0x025D, 0x025C, 0x025B, 0x025A, // 464-471 deg + 0x025A, 0x0259, 0x0258, 0x0257, 0x0257, 0x0256, 0x0255, 0x0254, // 472-479 deg + 0x0253, 0x0253, 0x0252, 0x0251, 0x0250, 0x0250, 0x024F, 0x024E, // 480-487 deg + 0x024D, 0x024D, 0x024C, 0x024B, 0x024A, 0x024A, 0x0249, 0x0248, // 488-495 deg + 0x0247, 0x0247, 0x0246, 0x0245, 0x0244, 0x0244, 0x0243, 0x0242, // 496-503 deg + 0x0241, 0x0241, 0x0240, 0x023F, 0x023F, 0x023E, 0x023D, 0x023C, // 504-511 deg + 0x023C, 0x023B, 0x023A, 0x023A, 0x0239, 0x0238, 0x0237, 0x0237, // 512-519 deg + 0x0236, 0x0235, 0x0235, 0x0234, 0x0233, 0x0232, 0x0232, 0x0231, // 520-527 deg + 0x0230, 0x0230, 0x022F, 0x022E, 0x022E, 0x022D, 0x022C, 0x022C, // 528-535 deg + 0x022B, 0x022A, 0x022A, 0x0229, 0x0228, 0x0227, 0x0227, 0x0226, // 536-543 deg + 0x0225, 0x0225, 0x0224, 0x0223, 0x0223, 0x0222, 0x0221, 0x0221, // 544-551 deg + 0x0220, 0x021F, 0x021F, 0x021E, 0x021E, 0x021D, 0x021C, 0x021C, // 552-559 deg + 0x021B, 0x021A, 0x021A, 0x0219, 0x0218, 0x0218, 0x0217, 0x0216, // 560-567 deg + 0x0216, 0x0215, 0x0214, 0x0214, 0x0213, 0x0213, 0x0212, 0x0211, // 568-575 deg + 0x0211, 0x0210, 0x020F, 0x020F, 0x020E, 0x020D, 0x020D, 0x020C, // 576-583 deg + 0x020C, 0x020B, 0x020A, 0x020A, 0x0209, 0x0209, 0x0208, 0x0207, // 584-591 deg + 0x0207, 0x0206, 0x0205, 0x0205, 0x0204, 0x0204, 0x0203, 0x0202, // 592-599 deg + 0x0202, 0x0201, 0x0201, 0x0200, 0x01FF, 0x01FF, 0x01FE, 0x01FE, // 600-607 deg + 0x01FD, 0x01FC, 0x01FC, 0x01FB, 0x01FB, 0x01FA, 0x01F9, 0x01F9, // 608-615 deg + 0x01F8, 0x01F8, 0x01F7, 0x01F6, 0x01F6, 0x01F5, 0x01F5, 0x01F4, // 616-623 deg + 0x01F3, 0x01F3, 0x01F2, 0x01F2, 0x01F1, 0x01F1, 0x01F0, 0x01EF, // 624-631 deg + 0x01EF, 0x01EE, 0x01EE, 0x01ED, 0x01EC, 0x01EC, 0x01EB, 0x01EB, // 632-639 deg + 0x01EA, 0x01EA, 0x01E9, 0x01E8, 0x01E8, 0x01E7, 0x01E7, 0x01E6, // 640-647 deg + 0x01E6, 0x01E5, 0x01E4, 0x01E4, 0x01E3, 0x01E3, 0x01E2, 0x01E2, // 648-655 deg + 0x01E1, 0x01E1, 0x01E0, 0x01DF, 0x01DF, 0x01DE, 0x01DE, 0x01DD, // 656-663 deg + 0x01DD, 0x01DC, 0x01DC, 0x01DB, 0x01DA, 0x01DA, 0x01D9, 0x01D9, // 664-671 deg + 0x01D8, 0x01D8, 0x01D7, 0x01D7, 0x01D6, 0x01D5, 0x01D5, 0x01D4, // 672-679 deg + 0x01D4, 0x01D3, 0x01D3, 0x01D2, 0x01D2, 0x01D1, 0x01D1, 0x01D0, // 680-687 deg + 0x01D0, 0x01CF, 0x01CE, 0x01CE, 0x01CD, 0x01CD, 0x01CC, 0x01CC, // 688-695 deg + 0x01CB, 0x01CB, 0x01CA, 0x01CA, 0x01C9, 0x01C9, 0x01C8, 0x01C7, // 696-703 deg + 0x01C7, 0x01C6, 0x01C6, 0x01C5, 0x01C5, 0x01C4, 0x01C4, 0x01C3, // 704-711 deg + 0x01C3, 0x01C2, 0x01C2, 0x01C1, 0x01C1, 0x01C0, 0x01C0, 0x01BF, // 712-719 deg + 0x01BF, // 720-720 deg +}; diff --git a/Firmware/Tasks/Src/CanTxTelemetryTask.c b/Firmware/Tasks/Src/CanTxTelemetryTask.c deleted file mode 100644 index 0e8fc41f..00000000 --- a/Firmware/Tasks/Src/CanTxTelemetryTask.c +++ /dev/null @@ -1,85 +0,0 @@ -#include "CanTxTelemetryTask.h" - -#define CAN_TX_TELEMETRY_QUEUE_SIZE 10 - -static StaticQueue_t canTxTelemetryQueueBuffer; -static uint8_t canTxTelemetryQueueStorage[CAN_TX_TELEMETRY_QUEUE_SIZE * sizeof(can_tx_payload_t)]; -static QueueHandle_t canTxTelemetryQueue; - - -void can_tx_print_slcan(const can_tx_payload_t payload) -{ - - uint32_t id = payload.header.Identifier; - uint8_t len = (payload.header.DataLength); - - /* SLCAN supports max 8 bytes */ - if (len > 8) - len = 8; - - if (payload.header.IdType == FDCAN_STANDARD_ID) - { - /* tIII DLC DATA... */ - printf("t%03lX%1X", id & 0x7FF, len); - } - else - { - /* TIIIIIIII DLC DATA... */ - printf("T%08lX%1X", id & 0x1FFFFFFF, len); - } - - for (uint8_t i = 0; i < len; i++) - { - printf("%02X", payload.data[i]); - } - - printf("\r\n"); -} - -void CanTxTelemetryTask_Init(void){ - canTxTelemetryQueue = xQueueCreateStatic( - CAN_TX_TELEMETRY_QUEUE_SIZE, - sizeof(can_tx_payload_t), - canTxTelemetryQueueStorage, - &canTxTelemetryQueueBuffer - ); - - if(canTxTelemetryQueue == NULL){ - return; - } -} - -void can_fd_tx_callback_hook(FDCAN_HandleTypeDef* hfdcan, const can_tx_payload_t* payload){ - - BaseType_t higherPriorityTaskWoken = pdFALSE; - - if(canTxTelemetryQueue != NULL){ - xQueueSendFromISR( - canTxTelemetryQueue, - payload, - &higherPriorityTaskWoken - ); - - } - // don't yield at the end of this since the rest of the ISR needs to run -} - - -void Task_CanTxTelemetry(){ - - // car canbus MUST be initialized by now - CanTxTelemetryTask_Init(); - - can_tx_payload_t payload; - - while(1){ - // forward all transmitted can messages to USB - if (xQueueReceive(canTxTelemetryQueue, &payload, portMAX_DELAY) == pdTRUE){ - // TODO: use the embedded-sharepoint slcan formatter - can_tx_print_slcan(payload); - // TODO: should also forward data to ESP32 - - taskYIELD(); - } - } -} \ No newline at end of file diff --git a/Firmware/Tasks/Src/DriverInputTask.c b/Firmware/Tasks/Src/DriverInputTask.c deleted file mode 100644 index 3054a22d..00000000 --- a/Firmware/Tasks/Src/DriverInputTask.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "DriverInputTask.h" - -#define DRIVER_INPUT_TEST_TASK_STACK configMINIMAL_STACK_SIZE -#define DRIVER_INPUT_TEST_TASK_PRIO (tskIDLE_PRIORITY + 1) - -static void initDriverInputHeader(FDCAN_TxHeaderTypeDef *tx_header) -{ - tx_header->Identifier = CAN_ID_DRIVER_INPUT_STATUS; - tx_header->IdType = FDCAN_STANDARD_ID; - tx_header->TxFrameType = FDCAN_DATA_FRAME; - tx_header->DataLength = FDCAN_DLC_BYTES_8; - tx_header->ErrorStateIndicator = FDCAN_ESI_ACTIVE; - tx_header->BitRateSwitch = FDCAN_BRS_OFF; - tx_header->FDFormat = FDCAN_CLASSIC_CAN; - tx_header->TxEventFifoControl = FDCAN_NO_TX_EVENTS; - tx_header->MessageMarker = 0; -} - -void Task_DriverInputTest(void *pvParameters) -{ - FDCAN_TxHeaderTypeDef header; - uint8_t tx_data[8] = {0}; - - initDriverInputHeader(&header); - - vTaskDelay(pdMS_TO_TICKS(2000)); // let everything initialize first - - tx_data[IGNITION_MOTOR_INDEX] = 1; - - if (Car_CANBus_Send(&header, tx_data, portMAX_DELAY) == CAN_OK) - { - printf("TEST: Sent ignition ON frame\r\n"); - } - else - { - printf("TEST: Failed to send ignition ON frame\r\n"); - } - - vTaskDelete(NULL); -} \ No newline at end of file diff --git a/Firmware/Tasks/Src/FSMTask.c b/Firmware/Tasks/Src/FSMTask.c new file mode 100644 index 00000000..2c8470e6 --- /dev/null +++ b/Firmware/Tasks/Src/FSMTask.c @@ -0,0 +1,269 @@ +/** + * @file FSM.c + * @brief Motor controller FSM implementation + * @copyright Copyright (c) 2026 UT Longhorn Racing Solar + */ + +#define DEFINE_FSM_TABLE +#include "fsm_table_dnr.h" +#include "rollover_speed_table.h" + +#include "FSMTask.h" +#include "UpdateVCUInputsTask.h" +#include "FaultBits.h" +#include "Watchdogs.h" +#include "StatusLEDs.h" +#include +#include +#include + +#define MAX_VELOCITY 12000 +#define MAX_CURRENT_PERCENT 1.0f + +#define ACCEL_DEADZONE_MIN 5u // Minimum 5% pedal pressed to register accel input, prevents ghost inputs :P +#define METERS_SEC_TO_MPH 2.23694f + +StaticEventGroup_t fsmInputBuffer = {0}; +EventGroupHandle_t fsmInputGroup = {0}; +MocoState_t current_state = {0}; + +static bool rollover_limit_active = false; +static volatile uint16_t fsm_inputs = 0; + +// method stubs so linker doesnt shit itself +static void handle_state_init(void); +static void handle_state_not_ready(void); +static void handle_state_forward(void); +static void handle_state_neutral(void); +static void handle_state_reverse(void); +static void handle_state_regen(void); +static void handle_state_cruise(void); +static void handle_state_disabled(void); + +static void handle_drive_state(bool); + +static float apply_rollover_limit(float requested_current); +static float swoc_max_current(float speed_mph); +static float get_drive_current(float speed_mph, uint8_t accel_percent_0_100); + +void fsm_init(void) { + FSM[STATE_INIT].stateHandler = handle_state_init; + FSM[FORWARD_DRIVE].stateHandler = handle_state_forward; + FSM[NEUTRAL_DRIVE].stateHandler = handle_state_neutral; + FSM[REVERSE_DRIVE].stateHandler = handle_state_reverse; + FSM[REGEN].stateHandler = handle_state_regen; + FSM[CRUISE_CONTROL].stateHandler = handle_state_cruise; + FSM[DISABLED].stateHandler = handle_state_disabled; + FSM[CAR_NOT_READY].stateHandler = handle_state_not_ready; + + current_state = FSM[STATE_INIT]; + current_state.stateHandler(); + + fsmInputGroup = xEventGroupCreateStatic(&fsmInputBuffer); +} + +void fsm_step(void) { + fsm_inputs = xEventGroupGetBits(fsmInputGroup); + current_state = FSM[current_state.NextStates[fsm_inputs]]; + // printf("FSM step: %X inputs, %d curr_state\n\r", fsm_inputs, current_state.stateName); + if (current_state.stateHandler) current_state.stateHandler(); +} + +void fsm_disable(void) { current_state = FSM[DISABLED]; } +void fsm_recover(void) { current_state = FSM[CAR_NOT_READY]; } +uint16_t fsm_get_fsm_inputs(void) { return (uint16_t)fsm_inputs; } +bool fsm_is_over_rollover_speed(void) { return rollover_limit_active; } + +void fsm_set_all_inputs(EventBits_t mask) { + taskENTER_CRITICAL(); + xEventGroupClearBits(fsmInputGroup, FSM_INPUTS_MASK_ALL); + xEventGroupSetBits(fsmInputGroup, mask & FSM_INPUTS_MASK_ALL); + taskEXIT_CRITICAL(); +} + +void fsm_set_input(EventBits_t mask) { + xEventGroupSetBits(fsmInputGroup, mask & FSM_INPUTS_MASK_ALL); +} + +uint16_t fsm_get_inputs(void) { + return (uint16_t)xEventGroupGetBits(fsmInputGroup); +} + +bool fsm_is_input_set(InputBits_t bit) { + return (xEventGroupGetBits(fsmInputGroup) & bit) != 0; +} + + + +// goofy ahh logic, uses lut +static float apply_rollover_limit(float requested_current) { + // printf("Applying rollover limit, requested current: %.2f, vehicle velocity: %.2f, steering angle: %.1f\r\n", + // requested_current, g_data_read->motor_velocity.MC_VehicleVelocity, (float)g_data_read->lws.LWS_Angle / 10.0f); + int deg = abs((int)g_data_read->lws.LWS_Angle) / 10; + if (deg > (int)ROLLOVER_TABLE_MAX_DEG) deg = (int)ROLLOVER_TABLE_MAX_DEG; + + uint16_t v_max_cms = rollover_speed_table[deg]; + uint16_t v_now_cms = (uint16_t)(g_data_read->motor_velocity.MC_VehicleVelocity * 100.0f); + + if (v_max_cms != ROLLOVER_TABLE_NO_LIMIT && v_now_cms > v_max_cms) { + rollover_limit_active = true; + warning_set(WARNING_ID_TIPPING_LIMIT_ACTIVE); + return 0.0f; + } + + warning_clear(WARNING_ID_REGEN_NOT_ALLOWED); + rollover_limit_active = false; + return requested_current; +} + +float map_to_percent(uint8_t input, uint8_t in_min, uint8_t in_max, uint8_t out_min, + uint8_t out_max) { + if (in_min >= in_max || input <= in_min) return (float)out_min / 100.0f; + if (input >= in_max) return (float)out_max / 100.0f; + uint16_t oi = input - in_min; + uint16_t ir = in_max - in_min; + uint16_t or_ = out_max - out_min; + return ((float)(oi * or_) / (float)ir + (float)out_min) / 100.0f; +} + +static float get_drive_current(float speed_mph, uint8_t accel_percent_0_100) { + uint8_t pedal = accel_percent_0_100; + if (pedal <= ACCEL_DEADZONE_MIN) pedal = 0U; + float requested = (float)pedal / 100.0f; + float swoc_cap = swoc_max_current(speed_mph); + float after_rollover = apply_rollover_limit(requested); + return fminf(swoc_cap, after_rollover); +} + +//// state handlers + +static void handle_state_init(void) { current_state = FSM[CAR_NOT_READY]; } +static void handle_state_neutral(void) { CAN_Send_Drive_Cmd(0.0f, 0.0f, 0); } +static void handle_state_disabled(void) { CAN_Send_Drive_Cmd(0.0f, 0.0f, 0); } +static void handle_state_regen(void) { CAN_Send_Drive_Cmd(0.0f, 1.0f, 0); } +static void handle_state_not_ready(void) { CAN_Send_Drive_Cmd(0.0f, 0.0f, 0); } + +// static void handle_state_forward(void) { +// float velocitySetpoint = 0.0f; +// float currentSetpoint = 0.0f; +// if (g_data_read->motor_velocity.MC_VehicleVelocity < -0.5f) { +// // if we're actually going backwards, let off the pedal until we slow down +// velocitySetpoint = 0.0f; +// currentSetpoint = 0.0f; +// warning_set(WARNING_ID_MOTOR_DIRECTION_CHANGE_LOCKOUT); +// } else { +// warning_clear(WARNING_ID_REGEN_NOT_ALLOWED); +// velocitySetpoint = MAX_VELOCITY; +// currentSetpoint = fmin(apply_swoc_speed_limit(g_data_read->motor_velocity.MC_VehicleVelocity * METERS_SEC_TO_MPH), +// apply_rollover_limit(((float)((g_data_read->accel_brake.AccelPedal_Main_Pos > ACCEL_DEADZONE_MIN) ? g_data_read->accel_brake.AccelPedal_Main_Pos : 0))/100.0f)); +// } + +// printf("Forwards Drive cmd: %f vel, %f curr\r\n", velocitySetpoint, currentSetpoint); + +// CAN_Send_Drive_Cmd(velocitySetpoint, currentSetpoint, 0); + +// } + +// static void handle_state_reverse(void) { + +// float velocitySetpoint = 0.0f; +// float currentSetpoint = 0.0f; + +// if (g_data_read->motor_velocity.MC_VehicleVelocity > 0.5f) { +// // if we're actually going forwards, let off the pedal until we slow down +// velocitySetpoint = 0.0f; +// currentSetpoint = 0.0f; +// warning_set(WARNING_ID_MOTOR_DIRECTION_CHANGE_LOCKOUT); +// } else { +// velocitySetpoint = -MAX_VELOCITY; +// currentSetpoint = fmin(apply_swoc_speed_limit(g_data_read->motor_velocity.MC_VehicleVelocity * METERS_SEC_TO_MPH), ((float)apply_rollover_limit(((g_data_read->accel_brake.AccelPedal_Main_Pos > ACCEL_DEADZONE_MIN) ? g_data_read->accel_brake.AccelPedal_Main_Pos : 0)))/100.0f); +// } + +// CAN_Send_Drive_Cmd(velocitySetpoint, currentSetpoint, 0); + +// printf("Backwards Drive cmd: %f vel, %f curr", velocitySetpoint, currentSetpoint); + +// } + +static void handle_state_forward(void) { + handle_drive_state(false); +} + +static void handle_state_reverse(void) { + handle_drive_state(true); +} + +static void handle_drive_state(bool reverse) { + float velocity_setpoint = 0.0f; + float current_setpoint = 0.0f; + + const float vehicle_velocity = + g_data_read->motor_velocity.MC_VehicleVelocity; + + const bool is_wrong_direction = + (!reverse && vehicle_velocity < -0.5f) || + ( reverse && vehicle_velocity > 0.5f); + + if (is_wrong_direction) { + // If we're moving opposite the requested direction, + // force zero torque until vehicle slows down + velocity_setpoint = 0.0f; + current_setpoint = 0.0f; + warning_set(WARNING_ID_MOTOR_DIRECTION_CHANGE_LOCKOUT); + } else { + if (!reverse) warning_clear(WARNING_ID_REGEN_NOT_ALLOWED); + + velocity_setpoint = reverse ? -MAX_VELOCITY : MAX_VELOCITY; + + float speed_mph = fabsf(vehicle_velocity) * METERS_SEC_TO_MPH; + current_setpoint = get_drive_current(speed_mph, g_data_read->accel_brake.AccelPedal_Main_Pos); + } + + CAN_Send_Drive_Cmd(velocity_setpoint, current_setpoint, 0); + + printf("%s Drive cmd: %f vel, %f curr\r\n", + reverse ? "Reverse" : "Forward", + velocity_setpoint, + current_setpoint); +} + +static void handle_state_cruise(void) { + float velocity = rollover_limit_active ? 0.0f : MAX_VELOCITY; + float speed_mph = fabsf(g_data_read->motor_velocity.MC_VehicleVelocity) * METERS_SEC_TO_MPH; + CAN_Send_Drive_Cmd( + velocity, + get_drive_current(speed_mph, g_data_read->accel_brake.AccelPedal_Main_Pos), + 0); +} + +static const swoc_threshold_t SWOC_THRESHOLDS[] = { + {10.0f, 0.80f}, {17.0f, 0.75f}, {20.0f, 0.70f}, + {23.0f, 0.60f}, {25.0f, 0.50f}, {28.5f, 0.45f} +}; +static const size_t NUM_SWOC_THRESHOLDS = (sizeof(SWOC_THRESHOLDS) / sizeof(SWOC_THRESHOLDS[0])); + +static float swoc_max_current(float speed_mph) { + float cap = MAX_CURRENT_PERCENT; + for (size_t i = 0; i < NUM_SWOC_THRESHOLDS; ++i) { + if (speed_mph >= SWOC_THRESHOLDS[i].speed_mph) { + cap = SWOC_THRESHOLDS[i].max_current; + } + } + return cap; +} + + +//////// rtos tasks + + +void Task_FSM(void *args __attribute__((unused))) { + // TickType_t last = xTaskGetTickCount(); + while (1) { + fsm_step(); + // CAN_Send_Drive_Cmd(0.0f, 0.0f, 100); + LED_toggle(HB); + // printf("FSM Task Running\r\n"); + vTaskDelay(pdMS_TO_TICKS(90)); + // vTaskDelayUntil(&last, pdMS_TO_TICKS(10)); + } +} diff --git a/Firmware/Tasks/Src/FaultHandlerTask.c b/Firmware/Tasks/Src/FaultHandlerTask.c index d0bbccbf..11bca983 100644 --- a/Firmware/Tasks/Src/FaultHandlerTask.c +++ b/Firmware/Tasks/Src/FaultHandlerTask.c @@ -1,265 +1,116 @@ #include "FaultHandlerTask.h" -#include "PrechargeTask.h" // for hprecharge_task handle +#include "InitTask.h" // for hprecharge_task handle +#include "Watchdogs.h" #define FAULT_LOOP_PRINTF_DELAY_MS 10000 +#define FAULT_PRINTF_COUNTER (FAULT_LOOP_PRINTF_DELAY_MS / FAULT_LOOP_PERIOD_MS) -#define FAULT_PRINTF_COUNTER (FAULT_LOOP_PRINTF_DELAY_MS/FAULT_LOOP_PERIOD_MS) -EventBits_t fault_bits = 0; -EventBits_t state_bits = 0; - -static FDCAN_TxHeaderTypeDef VCUSendStatusHeader; - -static void initVCUSendStatusHeader(FDCAN_TxHeaderTypeDef *tx_header) -{ - tx_header->Identifier = CAN_ID_VCU_STATUS; - tx_header->IdType = FDCAN_STANDARD_ID; - tx_header->TxFrameType = FDCAN_DATA_FRAME; - tx_header->DataLength = FDCAN_DLC_BYTES_8; - tx_header->ErrorStateIndicator = FDCAN_ESI_ACTIVE; - tx_header->BitRateSwitch = FDCAN_BRS_OFF; - tx_header->FDFormat = FDCAN_CLASSIC_CAN; - tx_header->TxEventFifoControl = FDCAN_STORE_TX_EVENTS; - tx_header->MessageMarker = 0; -} - -void Init_FaultHandlerTask() -{ - if (faultBits_init() != 1) - { - // Fault bit initialization failed - Error_Handler(); +static void FHT_kill_precharge_task(void) { + if (precharge_task_handle != NULL) { + vTaskDelete(precharge_task_handle); + precharge_task_handle = NULL; } - - if (stateBits_init() != 1) - { - // Fault bit initialization failed - Error_Handler(); - } - - initVCUSendStatusHeader(&VCUSendStatusHeader); } -void Kill_Precharge_Task() -{ - if (hprecharge_task != NULL) - { - vTaskDelete(hprecharge_task); - } -} - -static void print_fault(){ - switch (fault_bits) // compare against individual bitmasks - { - case FAULT_BIT(MOTOR_GREATER_THAN_BATTERY_FAULT): - printf("Fault: Motor Voltage Greater Than Battery Voltage\r\n"); - break; - case FAULT_BIT(BATTERY_OVERVOLTAGE_FAULT): - printf("Fault: Battery Overvoltage\r\n"); - break; - case FAULT_BIT(BATTERY_UNDERVOLTAGE_FAULT): - printf("Fault: Battery Undervoltage\r\n"); - break; - case FAULT_BIT(MOTOR_SENSE_TIMEOUT_FAULT): - printf("Fault: Motor Sense Timeout\r\n"); - break; - case FAULT_BIT(PRECHARGE_SENSE_TIMEOUT_FAULT): - printf("Fault: Precharge Sense Timeout\r\n"); - break; - case FAULT_BIT(PRECHARGE_TIMEOUT_FAULT): - printf("Fault: Precharge Sequence Timeout\r\n"); - break; - case FAULT_BIT(CALLBACK_FAULT): - printf("Fault: Contactor Sense Fault\r\n"); - break; - case FAULT_BIT(MOTOR_SENSE_MISMATCH_FAULT): - printf("Fault: Motor Sense Mismatch\r\n"); - break; - case FAULT_BIT(PRECHARGE_SENSE_MISMATCH_FAULT): - printf("Fault: Precharge Sense Mismatch\r\n"); - break; - default: - printf("Fault: Unknown\r\n"); - break; - } -} - -void Fault_Loop() -{ - uint32_t fault_printf_debug_counter = 0; - while (1) - { - switch (fault_bits) // compare against individual bitmasks - { - case FAULT_BIT(MOTOR_GREATER_THAN_BATTERY_FAULT): - printf("Fault: Motor Voltage Greater Than Battery Voltage\r\n"); - vTaskDelay(PRINTF_DELAY_MS); - break; - case FAULT_BIT(BATTERY_OVERVOLTAGE_FAULT): - printf("Fault: Overvoltage\r\n"); - vTaskDelay(PRINTF_DELAY_MS); - break; - case FAULT_BIT(BATTERY_UNDERVOLTAGE_FAULT): - printf("Fault: Undervoltage\r\n"); - vTaskDelay(PRINTF_DELAY_MS); - break; - case FAULT_BIT(MOTOR_SENSE_TIMEOUT_FAULT): - printf("Fault: Motor Sense Timeout\r\n"); - vTaskDelay(PRINTF_DELAY_MS); - break; - case FAULT_BIT(PRECHARGE_SENSE_TIMEOUT_FAULT): - printf("Fault: Precharge Sense Timeout\r\n"); - vTaskDelay(PRINTF_DELAY_MS); - break; - case FAULT_BIT(PRECHARGE_TIMEOUT_FAULT): - printf("Fault: Precharge Sequence Timeout\r\n"); - vTaskDelay(PRINTF_DELAY_MS); - break; - case FAULT_BIT(CALLBACK_FAULT): - printf("Fault: Contactor Sense Fault\r\n"); - vTaskDelay(PRINTF_DELAY_MS); - break; - case FAULT_BIT(MOTOR_SENSE_MISMATCH_FAULT): - printf("Fault: Motor Sense Mismatch\r\n"); - vTaskDelay(PRINTF_DELAY_MS); - break; - case FAULT_BIT(PRECHARGE_SENSE_MISMATCH_FAULT): - printf("Fault: Precharge Sense Mismatch\r\n"); - vTaskDelay(PRINTF_DELAY_MS); - break; - case FAULT_BIT(BPS_FAULT): - printf("Fault: BPS Fault\r\n"); - vTaskDelay(PRINTF_DELAY_MS); - break; - default: - break; - fault_printf_debug_counter++; - - if(fault_printf_debug_counter >= FAULT_PRINTF_COUNTER){ - print_fault(); - fault_printf_debug_counter = 0; +// Sets fault LEDs based on which faults are active. Multiple faults may be +// active at once, so multiple LEDs may be set. +static void FHT_set_fault_leds(EventBits_t bits) { + // TODO add a generic fault LED + //LED_set(FAULT_LED, LED_ON); + for (FaultID_e i = 0; i < FAULT_ID_COUNT; i++) { + if (bits & FAULT_BIT(i)) { + switch (i) { + /* ============= MOTOR CONTROLLER ============ */ + case FAULT_ID_MOTOR_HARDWARE_OVERCURRENT: + case FAULT_ID_MOTOR_DC_BUS_OVERVOLTAGE: + case FAULT_ID_MOTOR_WD_RESET: + case FAULT_ID_MOTOR_CONFIG_READ: + case FAULT_ID_MOTOR_15V_UNDERVOLTAGE: + case FAULT_ID_MOTOR_DESATURATION: + case FAULT_ID_MOTOR_OVERSPEED: + LED_set(MOTOR_FAULT, LED_ON); + break; + case FAULT_ID_MOTOR_SOFTWARE_OVERCURRENT: + LED_set(SWOC, LED_ON); + break; + case FAULT_ID_MOTOR_BAD_HALL_SEQUENCE: + LED_set(HALL_EFFECT, LED_ON); + break; + + /* ================ PRECHARGE ================ */ + case FAULT_ID_PRECHARGE_TIMEOUT: + case FAULT_ID_PRECHARGE_SENSE_TIMEOUT: + case FAULT_ID_PRECHARGE_SENSE_MISMATCH: + case FAULT_ID_MOTOR_SENSE_TIMEOUT: + case FAULT_ID_MOTOR_SENSE_MISMATCH: + case FAULT_ID_BATTERY_OVERVOLTAGE: + case FAULT_ID_BATTERY_UNDERVOLTAGE: + case FAULT_ID_MOTOR_GT_BATTERY: + case FAULT_ID_CONTACTOR_CALLBACK: + // TODO add a precharge fault led + break; + + /* ============== OTHER BOARDS =============== */ + case FAULT_ID_STEERING_SENSOR_FAULT: + case FAULT_ID_PEDAL_BOARD_FAULT: + case FAULT_ID_CONTROLS_FAULT: + // TODO add other leds + break; + case FAULT_ID_BPS_FAULT: + LED_set(CAR_BPSFAULT, LED_ON); + break; + case FAULT_ID_GENERIC_WATCHDOG_FAULT: + LED_set(WATCHDOG, LED_ON); + break; + + default: + // TODO unknown fault, turn on generic fault LED + //LED_set(FAULT_LED, LED_ON); + break; + } } - - Toggle_LED(HB); - vTaskDelay(FAULT_LOOP_PERIOD_MS); - } - } -} - -void Set_Fault_LED() -{ - switch (fault_bits) // compare against individual bitmasks - { - case FAULT_BIT(MOTOR_GREATER_THAN_BATTERY_FAULT): - LED_set(CAR_BPSFAULT, LED_ON); - break; - case FAULT_BIT(BATTERY_OVERVOLTAGE_FAULT): - LED_set(CAR_BPSFAULT, LED_ON); - break; - case FAULT_BIT(BATTERY_UNDERVOLTAGE_FAULT): - LED_set(CAR_BPSFAULT, LED_ON); - break; - case FAULT_BIT(MOTOR_SENSE_TIMEOUT_FAULT): - LED_set(MOTOR_SENSE_TIMEOUT, LED_ON); - break; - case FAULT_BIT(PRECHARGE_SENSE_TIMEOUT_FAULT): - LED_set(PRECHARGE_SENSE_TIMEOUT, LED_ON); - break; - case FAULT_BIT(PRECHARGE_TIMEOUT_FAULT): - LED_set(PRECHARGE_TIMEOUT, LED_ON); - break; - case FAULT_BIT(CALLBACK_FAULT): - LED_set(CAR_BPSFAULT, LED_ON); - break; - case FAULT_BIT(MOTOR_SENSE_MISMATCH_FAULT): - LED_set(CAR_BPSFAULT, LED_ON); - break; - case FAULT_BIT(PRECHARGE_SENSE_MISMATCH_FAULT): - LED_set(CAR_BPSFAULT, LED_ON); - break; - case FAULT_BIT(BPS_FAULT): - LED_set(CAR_BPSFAULT, LED_ON); - break; - default: - break; } } -static uint8_t convertFaultBitsToIndex(uint32_t faults) -{ - for (int i = 0; i < FAULT_NUM; i++) - { - if (faults & (1U << i)) - { - return i + 1; // fault codes start at 1, 0 = no fault - } +void Task_FaultHandler(void *args __attribute__((unused))) { + if (!faults_init()) { + // Fault bit initialization failed, cannot proceed safely + Error_Handler(); } - return 0; // no fault active -} - -// encodes VCU status struct into an array of bytes for can_send -static void packVCUStatus(vcu_status_t status, uint8_t tx_data[8]) -{ - uint32_t faults = fault_bits; - uint8_t fault_code = convertFaultBitsToIndex(faults); - tx_data[0] = fault_code; - - uint8_t motor_contactor_state = (state_bits >> 1) & 0x1; - uint8_t precharge_contactor_state = (state_bits >> 2) & 0x1; - uint8_t ready_to_drive = (state_bits >> 3) & 0x1; - - tx_data[1] = motor_contactor_state; // Motor_Contactor_State - tx_data[2] = precharge_contactor_state; // Motor_Precharge_Contactor_State - tx_data[3] = ready_to_drive; // Motor_Ready_To_Drive - tx_data[4] = 0; // VCU_Driver_Input_OK - tx_data[5] = 0; // VCU_Pedals_OK - tx_data[6] = 0; // VCU_Regen_OK - tx_data[7] = 0; // VCU_Regen_Active / FSM_State -} - -void Task_FaultHandler() -{ - Init_FaultHandlerTask(); - - uint8_t VCU_tx_data[8]; - vcu_status_t VCUStatus = {0}; - - uint8_t can_send_errors = 0; + while (true) { + EventBits_t bits = faults_wait(FAULT_ID_COUNT, portMAX_DELAY); - while (1) - { - packVCUStatus(VCUStatus, VCU_tx_data); - - if (Car_CANBus_Send(&VCUSendStatusHeader, VCU_tx_data, portMAX_DELAY) == CAN_ERR) - { - can_send_errors++; - } - else - { - can_send_errors = 0; - } - - fault_bits = faultBit_wait(NUM_FAULTS, portMAX_DELAY); - - if (fault_bits != 0) - { - Kill_Precharge_Task(); + if (bits != 0) { + FHT_kill_precharge_task(); contactor_emergency_open_all(); - - // prevents the motor from running clear_MotorSafeBit(MOTOR_CONTACTOR_ENABLED); clear_MotorSafeBit(MOTOR_PRECHARGE_CONTACTOR_ENABLED); - - printf("Fault Handler triggered with bitmask: 0x%02lX\r\n", fault_bits); - - Set_Fault_LED(); - Fault_Loop(); + fsm_disable(); + watchdog_stop_all(); + + printf("Fault Handler triggered: 0x%02lX\r\n", bits); + + // Loop to display/handle fault until system reset + uint32_t print_counter = 0; + while (true) { + print_counter++; + if (print_counter >= FAULT_PRINTF_COUNTER) { + for (int i = 0; i < FAULT_ID_COUNT; i++) { + if (bits & FAULT_BIT(i)) { + printf("Fault: %s\r\n", fault_names[i]); + } + } + print_counter = 0; + } + + FHT_set_fault_leds(bits); + vTaskDelay(pdMS_TO_TICKS(FAULT_LOOP_PERIOD_MS)); + } } - - vTaskDelay(1000); - } - vTaskDelay(1000); + vTaskDelay(pdMS_TO_TICKS(1000)); + } } \ No newline at end of file diff --git a/Firmware/Tasks/Src/InitTask.c b/Firmware/Tasks/Src/InitTask.c index 230f3577..1e421b92 100644 --- a/Firmware/Tasks/Src/InitTask.c +++ b/Firmware/Tasks/Src/InitTask.c @@ -1,7 +1,10 @@ #include "InitTask.h" +#include "StatusLEDs.h" +#include "Watchdogs.h" +#include "MotorTelemetryTask.h" -StaticTask_t FaultHandlerTask_Buffer; -StackType_t FaultHandlerTask_Stack[FAULT_HANDLER_TASK_STACK_SIZE]; +StaticTask_t FaultHandler_Task_Buffer; +StackType_t FaultHandler_Task_Stack[FAULT_HANDLER_TASK_STACK_SIZE]; StaticTask_t Precharge_Task_Buffer; StackType_t Precharge_Task_Stack[PRECHARGE_TASK_STACK_SIZE]; @@ -9,70 +12,93 @@ StackType_t Precharge_Task_Stack[PRECHARGE_TASK_STACK_SIZE]; StaticTask_t Init_Task_Buffer; StackType_t Init_Task_Stack[INIT_TASK_STACK_SIZE]; +StaticTask_t FSM_Task_Buffer; +StackType_t FSM_Task_Stack[FSM_TASK_STACK_SIZE]; -StaticTask_t Motor_Control_Task_Buffer; -StackType_t Motor_Control_Task_Stack[MOTOR_CONTROL_TASK_STACK_SIZE]; +StaticTask_t VCUStatus_Task_Buffer; +StackType_t VCUStatus_Task_Stack[VCU_STATUS_TASK_STACK_SIZE]; -StaticTask_t Motor_Telemetry_Task_Buffer; -StackType_t Motor_Telemetry_Task_Stack[MOTOR_TELEMETRY_TASK_STACK_SIZE]; +StaticTask_t UpdateVCUInputs_Task_Buffer; +StackType_t UpdateVCUInputs_Task_Stack[UPDATE_VCU_INPUTS_STACK_SIZE]; -StaticTask_t Can_Tx_Telemetry_Task_Buffer; -StackType_t Can_Tx_Telemetry_Task_Stack[CAN_TX_TELEMETRY_STACK_SIZE]; +TaskHandle_t precharge_task_handle = NULL; -StaticTask_t VCUReceiveCAN_Task_Buffer; -StackType_t VCUReceiveCAN_Task_Stack[configMINIMAL_STACK_SIZE]; - -StaticTask_t Driver_Input_Task_Buffer; -StackType_t Driver_Input_Task_Stack[configMINIMAL_STACK_SIZE]; - -void Task_Init() -{ +void Task_Init() { __HAL_RCC_SYSCFG_CLK_ENABLE(); __HAL_RCC_PWR_CLK_ENABLE(); + Init_UART_Printf(); - CAN_Init(); + // prech + ADC_Sense_Init(); + contactor_init(); MotorSafeBits_Init(); + MotorCAN_Init(); + CarCAN_Init(); + + fsm_init(); + + watchdog_init(); + watchdog_start_all(); + + + // Required for VCU status testing + faults_init(); + + MotorTelemetryTask_Init(); + xTaskCreateStatic( - Task_FaultHandler, // Task function - "FaultHandler", // Name of the task (for debugging) - configMINIMAL_STACK_SIZE, // Stack size in words - NULL, // Task input parameter - FAULT_HANDLER_THREAD_PRIO, // Task priority - FaultHandlerTask_Stack, // Task handle - &FaultHandlerTask_Buffer // Static task buffer (optional) + Task_FaultHandler, + "FaultHandler", + FAULT_HANDLER_TASK_STACK_SIZE, + NULL, + FAULT_HANDLER_THREAD_PRIO, + FaultHandler_Task_Stack, + &FaultHandler_Task_Buffer ); - hprecharge_task = xTaskCreateStatic( - Task_Precharge, // Task function - "Precharge", // Name of the task (for debugging) - configMINIMAL_STACK_SIZE, // Stack size in words - NULL, // Task input parameter - PRECHARGE_THREAD_PRIO, // Task priority - Precharge_Task_Stack, // Task handle - &Precharge_Task_Buffer // Static task buffer (optional) + precharge_task_handle = xTaskCreateStatic( + Task_Precharge, + "Precharge", + PRECHARGE_TASK_STACK_SIZE, + NULL, + PRECHARGE_THREAD_PRIO, + Precharge_Task_Stack, + &Precharge_Task_Buffer + ); + + xTaskCreateStatic( + Task_FSM, + "FSM Thread", + FSM_TASK_STACK_SIZE, + NULL, + FSM_THREAD_PRIO, + FSM_Task_Stack, + &FSM_Task_Buffer ); xTaskCreateStatic( - Task_VCUReceiveCAN, // Task function - "VCUReceiveCAN", // Name of the task (for debugging) - configMINIMAL_STACK_SIZE, // Stack size in words - NULL, // Task input parameter - tskIDLE_PRIORITY + 2, // Task priority - VCUReceiveCAN_Task_Stack, // Task handle - &VCUReceiveCAN_Task_Buffer // Static task buffer (optional) + Task_BroadcastVCUStatus, + "VCU Status Thread", + VCU_STATUS_TASK_STACK_SIZE, + NULL, + VCU_STATUS_THREAD_PRIO, + VCUStatus_Task_Stack, + &VCUStatus_Task_Buffer ); xTaskCreateStatic( - Task_DriverInputTest, - "DriverInputTest", - configMINIMAL_STACK_SIZE, + Task_UpdateVCUInputs, + "Update FSM Inputs Thread", + UPDATE_VCU_INPUTS_STACK_SIZE, NULL, - tskIDLE_PRIORITY + 2, - Driver_Input_Task_Stack, - &Driver_Input_Task_Buffer); + UPDATE_VCU_INPUTS_THREAD_PRIO, + UpdateVCUInputs_Task_Stack, + &UpdateVCUInputs_Task_Buffer + ); + vTaskDelete(NULL); } \ No newline at end of file diff --git a/Firmware/Tasks/Src/MotorControlTask.c b/Firmware/Tasks/Src/MotorControlTask.c deleted file mode 100644 index 097dff84..00000000 --- a/Firmware/Tasks/Src/MotorControlTask.c +++ /dev/null @@ -1,127 +0,0 @@ -#include "MotorControlTask.h" -#include "CAN_FD.h" - -// how often we want print outs from this thread -#define MOTOR_CONTROLLER_PRINT_DEBUG_PERIOD 5000 - -// number of times the thread will run before we print out debug info -#define MOTOR_CONTROLLER_PRINT_DEBUG_COUNT (MOTOR_CONTROLLER_PRINT_DEBUG_PERIOD/MOTOR_CONTROL_TASK_PERIOD_MS) - - -static FDCAN_TxHeaderTypeDef mocoDriveCommandHeader; - -static void initDriveCommandHeader(FDCAN_TxHeaderTypeDef *tx_header); -static void initMotorPowerCommandHeader(FDCAN_TxHeaderTypeDef *tx_header); - -void MotorControlTask_Init(void) -{ - // set necessary motor drive command parameters - initDriveCommandHeader(&mocoDriveCommandHeader); -} - -static void initMotorPowerCommandHeader(FDCAN_TxHeaderTypeDef *tx_header) -{ - - tx_header->Identifier = CAN_ID_MC_POWERCOMMAND; - tx_header->IdType = FDCAN_STANDARD_ID; - tx_header->TxFrameType = FDCAN_DATA_FRAME; - tx_header->DataLength = FDCAN_DLC_BYTES_8; - tx_header->ErrorStateIndicator = FDCAN_ESI_ACTIVE; - tx_header->BitRateSwitch = FDCAN_BRS_OFF; - tx_header->FDFormat = FDCAN_CLASSIC_CAN; - tx_header->TxEventFifoControl = FDCAN_STORE_TX_EVENTS; - tx_header->MessageMarker = 0; -} - -// helper function to inialize motor drive command headers -static void initDriveCommandHeader(FDCAN_TxHeaderTypeDef *tx_header) -{ - - tx_header->Identifier = CAN_ID_MC_DRIVECOMMAND; - tx_header->IdType = FDCAN_STANDARD_ID; - tx_header->TxFrameType = FDCAN_DATA_FRAME; - tx_header->DataLength = FDCAN_DLC_BYTES_8; - tx_header->ErrorStateIndicator = FDCAN_ESI_ACTIVE; - tx_header->BitRateSwitch = FDCAN_BRS_OFF; - tx_header->FDFormat = FDCAN_CLASSIC_CAN; - tx_header->TxEventFifoControl = FDCAN_STORE_TX_EVENTS; - tx_header->MessageMarker = 0; -} - -// encodes a drive command struct into an array of bytes for can_send -static void packDriveCommand(mc_drivecommand_t motorDriveCommand, uint8_t tx_data[8]) -{ - memcpy(&tx_data[4], &(motorDriveCommand.MC_MotorCurrentSetpoint), sizeof(float)); - memcpy(&tx_data[0], &(motorDriveCommand.MC_MotorVelocitySetpoint), sizeof(float)); -} - -static void packPowerCommand(mc_powercommand_t motorPowerCommand, uint8_t tx_data[8]) -{ - memcpy(&tx_data[4], &(motorPowerCommand.MC_MotorPowerSetpoint), sizeof(float)); -} - -static float busCurrentSetPoint = 1.0f; - -void Task_MotorControl(void) -{ - - // motor canbus MUST be initalized by now - // the motor safe bits MUST be initalized by now - MotorControlTask_Init(); - - // current and velocity setpoint control speed of motor - mc_drivecommand_t motorDriveCommand = {0}; - motorDriveCommand.MC_MotorCurrentSetpoint = 0.0f; - motorDriveCommand.MC_MotorVelocitySetpoint = 0.0f; - uint8_t motor_drive_tx_data[8]; - - uint8_t print_debug_counter = 0; - - // sets the max power of the motor - mc_powercommand_t motorPowerCommand = {0}; - motorPowerCommand.MC_MotorPowerSetpoint = busCurrentSetPoint; - FDCAN_TxHeaderTypeDef mocoPowerCommandHeader; - uint8_t motor_power_tx_data[8]; // the message being sent on the CANbus - initMotorPowerCommandHeader(&mocoPowerCommandHeader); // initializes the can tx header - packPowerCommand(motorPowerCommand, motor_power_tx_data); // packs the motorPower struct into an array of bytes - - EventBits_t motorSafeBits; - while(1){ - - // Send power command - Motor_CANBus_Send(&mocoPowerCommandHeader, motor_power_tx_data, portMAX_DELAY); - - // check if the car is in a drivable state - motorSafeBits = MotorSafeBits_WaitMask(motorDrivableBits, pdMS_TO_TICKS(0)); - - // no bits are set, so the motor should not be run - if(motorSafeBits == 0){ - motorDriveCommand.MC_MotorCurrentSetpoint = 0.0f; - motorDriveCommand.MC_MotorVelocitySetpoint = 0.0f; - LED_set(CAR_DRIVABLE, LED_OFF); - } - else{ - motorDriveCommand.MC_MotorCurrentSetpoint = 0.2f; - motorDriveCommand.MC_MotorVelocitySetpoint = 12000.0f; - LED_set(CAR_DRIVABLE, LED_ON); - } - - packDriveCommand(motorDriveCommand, motor_drive_tx_data); - - Motor_CANBus_Send(&mocoDriveCommandHeader, motor_drive_tx_data, portMAX_DELAY); - - print_debug_counter++; - if(print_debug_counter > MOTOR_CONTROLLER_PRINT_DEBUG_COUNT){ - printf("Motor Current Setpoint: "); - printf("%f\r\n", motorDriveCommand.MC_MotorCurrentSetpoint); - printf("Motor Velocity Setpoint: "); - printf("%f\r\n", motorDriveCommand.MC_MotorVelocitySetpoint); - print_debug_counter = 0; - } - - Toggle_LED(CAR_HB); - - // minimum delay for drive command is 250ms, or else the wavesculptor will reset to neutral - vTaskDelay(pdMS_TO_TICKS(MOTOR_CONTROL_TASK_PERIOD_MS)); - } -} diff --git a/Firmware/Tasks/Src/MotorTelemetryTask.c b/Firmware/Tasks/Src/MotorTelemetryTask.c index 6a1cb778..408b6a61 100644 --- a/Firmware/Tasks/Src/MotorTelemetryTask.c +++ b/Firmware/Tasks/Src/MotorTelemetryTask.c @@ -1,70 +1,77 @@ #include "MotorTelemetryTask.h" -#define MOTOR_TELEMETRY_QUEUE_SIZE 32 +#define MOTOR_TELEMETRY_QUEUE_SIZE 32 static StaticQueue_t motorTelemetryQueueBuffer; static uint8_t motorTelemetryQueueStorage[MOTOR_TELEMETRY_QUEUE_SIZE * sizeof(can_rx_payload_t)]; static QueueHandle_t motorTelemetryQueue; - -void print_slcan(const can_rx_payload_t payload) -{ - - uint32_t id = payload.header.Identifier; - uint8_t len = (payload.header.DataLength); +void print_slcan(const can_rx_payload_t payload) { + uint32_t id = payload.header.Identifier; + uint8_t len = (payload.header.DataLength); /* SLCAN supports max 8 bytes */ - if (len > 8) - len = 8; + if (len > 8) len = 8; - if (payload.header.IdType == FDCAN_STANDARD_ID) - { + if (payload.header.IdType == FDCAN_STANDARD_ID) { /* tIII DLC DATA... */ printf("t%03lX%1X", id & 0x7FF, len); - } - else - { + } else { /* TIIIIIIII DLC DATA... */ printf("T%08lX%1X", id & 0x1FFFFFFF, len); } - for (uint8_t i = 0; i < len; i++) - { + for (uint8_t i = 0; i < len; i++) { printf("%02X", payload.data[i]); } printf("\r\n"); } -void MotorTelemetryTask_Init(void){ - motorTelemetryQueue = xQueueCreateStatic( - MOTOR_TELEMETRY_QUEUE_SIZE, - sizeof(can_rx_payload_t), - motorTelemetryQueueStorage, - &motorTelemetryQueueBuffer - ); +void MotorTelemetryTask_Init(void) { + motorTelemetryQueue = + xQueueCreateStatic(MOTOR_TELEMETRY_QUEUE_SIZE, sizeof(can_rx_payload_t), + motorTelemetryQueueStorage, &motorTelemetryQueueBuffer); - if(motorTelemetryQueue == NULL){ + if (motorTelemetryQueue == NULL) { return; } } -// void can_fd_rx_callback_hook(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs, can_rx_payload_t recv_payload ){ + +void can_fd_rx_callback_hook(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs, can_rx_payload_t recv_payload ){ -// // only forward motorCAN messages to CarCAN -// if(motorfdcan != NULL && hfdcan->Instance == motorfdcan->Instance){ + // only forward motorCAN messages to CarCAN + if (motorfdcan != NULL && hfdcan->Instance == motorfdcan->Instance){ -// BaseType_t higherPriorityTaskWoken = pdFALSE; + BaseType_t higherPriorityTaskWoken = pdFALSE; + + if (motorTelemetryQueue != NULL) { + xQueueSendFromISR( + motorTelemetryQueue, + &recv_payload, + &higherPriorityTaskWoken + ); + } + // don't yield at the end of this since the rest of the ISR needs to run + + + FDCAN_TxHeaderTypeDef tx_header = {0}; + tx_header.Identifier = recv_payload.header.Identifier; + tx_header.IdType = recv_payload.header.IdType; + tx_header.TxFrameType = FDCAN_DATA_FRAME; + tx_header.DataLength = recv_payload.header.DataLength; + tx_header.ErrorStateIndicator = recv_payload.header.ErrorStateIndicator; + tx_header.BitRateSwitch = recv_payload.header.BitRateSwitch; + tx_header.FDFormat = recv_payload.header.FDFormat; + tx_header.TxEventFifoControl = FDCAN_NO_TX_EVENTS; + tx_header.MessageMarker = 0; + + can_fd_send_isr(carfdcan, &tx_header, recv_payload.data, &higherPriorityTaskWoken); + } +} -// xQueueSendFromISR( -// motorTelemetryQueue, -// &recv_payload, -// &higherPriorityTaskWoken -// ); -// // don't yield at the end of this since the rest of the ISR needs to run -// } -// } -void Task_MotorTelemetry(){ +void Task_MotorTelemetry() { // motor canbus MUST be initialized by now MotorTelemetryTask_Init(); @@ -82,16 +89,16 @@ void Task_MotorTelemetry(){ carCanTransmitHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS; carCanTransmitHeader.MessageMarker = 0; - while(1){ - if (xQueueReceive(motorTelemetryQueue, &payload, portMAX_DELAY) == pdTRUE){ + while (1) { + if (xQueueReceive(motorTelemetryQueue, &payload, portMAX_DELAY) == pdTRUE) { // copy the incoming message's ID and data length carCanTransmitHeader.Identifier = payload.header.Identifier; carCanTransmitHeader.DataLength = payload.header.DataLength; // forward the motorCAN message to CarCAN - Car_CANBus_Send(&carCanTransmitHeader, payload.data, portMAX_DELAY); + CarCAN_Send(&carCanTransmitHeader, payload.data, portMAX_DELAY); - // print the incoming message over + // print the incoming message over print_slcan(payload); taskYIELD(); } diff --git a/Firmware/Tasks/Src/PrechargeTask.c b/Firmware/Tasks/Src/PrechargeTask.c index 54ed18e3..dd5ee2dd 100644 --- a/Firmware/Tasks/Src/PrechargeTask.c +++ b/Firmware/Tasks/Src/PrechargeTask.c @@ -1,301 +1,234 @@ #include "PrechargeTask.h" +#include "UpdateVCUInputsTask.h" -#define PRECHARGE_PRINTF_DEBUG_PERIOD_MS 10000 +#define PRECHARGE_PRINTF_DEBUG_PERIOD_MS 2000 #define PRECHARGE_PRINTF_DEBUG_COUNTER (PRECHARGE_PRINTF_DEBUG_PERIOD_MS / PRECHARGE_TASK_DELAY_MS) -/* handle for the Precharge task, defined here */ -TaskHandle_t hprecharge_task = NULL; - -StaticEventGroup_t xPrechargeEventGroup; -EventGroupHandle_t xPrechargeEventGroup_handle; - -uint32_t Battery_Voltage = 0; -uint32_t Motor_Voltage = 0; -static Precharge_State_t State; -uint8_t Ignition_State = 0; -// uint8_t Ignition_Off_Initiated = 0; -TickType_t offTick = 0; - -static FDCAN_TxHeaderTypeDef VCUSendVoltageHeader; - -static void initVCUSendVoltageHeader(FDCAN_TxHeaderTypeDef *tx_header) -{ - tx_header->Identifier = CAN_ID_VCU_PRECHARGE_VOLTAGES; - tx_header->IdType = FDCAN_STANDARD_ID; - tx_header->TxFrameType = FDCAN_DATA_FRAME; - tx_header->DataLength = FDCAN_DLC_BYTES_8; - tx_header->ErrorStateIndicator = FDCAN_ESI_ACTIVE; - tx_header->BitRateSwitch = FDCAN_BRS_OFF; - tx_header->FDFormat = FDCAN_CLASSIC_CAN; - tx_header->TxEventFifoControl = FDCAN_STORE_TX_EVENTS; - tx_header->MessageMarker = 0; -} +uint32_t battery_voltage = 0; +uint32_t motor_voltage = 0; +PrechargeState_e g_precharge_state = PRECHARGE_STATE_WAITING; + +const char *precharge_state_names[PRECHARGE_STATE_COUNT] = { +#define X(name) [PRECHARGE_STATE_##name] = #name, + PRECHARGE_STATE_LIST(X) +#undef X +}; -void Ignition_Off() -{ +void PT_ign_off() { printf("Ignition OFF, opening motor precharge contactor\r\n"); - if (contactor_set(MOTOR_PRE_CONTACTOR, OPEN, CALLBACK_BLOCKING_TIME, NORMAL) != SUCCESS) - { - set_faultBit(PRECHARGE_SENSE_TIMEOUT_FAULT); + if (contactor_set(MOTOR_PRE_CONTACTOR, OPEN, CALLBACK_BLOCKING_TIME, NORMAL) != SUCCESS) { + faults_set(FAULT_ID_PRECHARGE_SENSE_TIMEOUT); } printf("Ignition OFF, opening motor contactor\r\n"); - if (contactor_set(MOTOR_CONTACTOR, OPEN, CALLBACK_BLOCKING_TIME, NORMAL) != SUCCESS) - { - set_faultBit(MOTOR_SENSE_TIMEOUT_FAULT); + if (contactor_set(MOTOR_CONTACTOR, OPEN, CALLBACK_BLOCKING_TIME, NORMAL) != SUCCESS) { + faults_set(FAULT_ID_MOTOR_SENSE_TIMEOUT); } - State = PRECHARGE_STATE_WAITING; // Return task to idle/waiting state + taskENTER_CRITICAL(); + g_precharge_state = PRECHARGE_STATE_WAITING; + taskEXIT_CRITICAL(); printf("Ignition OFF, shutdown complete\r\n"); } -void Check_Ignition_State() -{ - // if (Ignition_Off_Initiated && (xTaskGetTickCount() - offTick) > pdMS_TO_TICKS(IGNITION_OFF_DELAY_MS)) +// TODO add message countign to c=transition +void PT_check_ign() { + static bool last_ign; + bool curr_ign = g_data_read->driver_input.Ignition_Motor; - if (Start_Precharge) - { - Start_Precharge = 0; - Ignition_State = 1; - State = PRECHARGE_STATE_INITIAL; + if (curr_ign && !last_ign) { + taskENTER_CRITICAL(); + g_precharge_state = PRECHARGE_STATE_INITIAL; + taskEXIT_CRITICAL(); printf("Ignition ON, starting precharge sequence\r\n"); - } - else if (End_Precharge) - { - End_Precharge = 0; - Ignition_State = 0; + } else if (!curr_ign && last_ign) { printf("Ignition OFF, stopping precharge sequence\r\n"); - Ignition_Off(); + PT_ign_off(); } -} - -void Init_PrechargeTask() -{ - // Event Group init - xPrechargeEventGroup_handle = xEventGroupCreateStatic(&xPrechargeEventGroup); - configASSERT(xPrechargeEventGroup_handle); // check if handle is set - // xEventGroupClearBits(xReadADCEventGroup_handle, /* The event group being updated. */ - // 0xFF ); /* The bits being cleared. */ - - // Inits ADC & contactors - ADC_Sense_Init(); - contactor_init(); - MotorSafeBits_Init(); - initVCUSendVoltageHeader(&VCUSendVoltageHeader); -} -// encodes battery and motor voltage into an array of bytes for can_send -static void packMotorVoltage(vcu_precharge_voltages_t voltages, uint8_t tx_data[8]) -{ - memcpy(&tx_data[0], &(voltages.VCU_Precharge_Battery_Voltage), sizeof(uint32_t)); // TODO: Have Precharge task push adc readings into the can messages struct - memcpy(&tx_data[4], &(voltages.VCU_Precharge_Motor_Voltage), sizeof(uint32_t)); + last_ign = curr_ign; } -void Fault_Checker(uint32_t Motor_Voltage, uint32_t Battery_Voltage) -{ - if (Motor_Voltage > (Battery_Voltage * VOLTAGE_TOLERANCE_NUMERATOR / VOLTAGE_TOLERANCE_DENOMINATOR)) - { - // Fault handler - set_faultBit(MOTOR_GREATER_THAN_BATTERY_FAULT); +void Fault_Checker(uint32_t Motor_Voltage, uint32_t Battery_Voltage) { + if (Motor_Voltage > + (Battery_Voltage * VOLTAGE_TOLERANCE_NUMERATOR / VOLTAGE_TOLERANCE_DENOMINATOR)) { + faults_set(FAULT_ID_MOTOR_GT_BATTERY); } - if (Battery_Voltage > OVERVOLTAGE_THRESHOLD_MV) - { - /* BATTERY ABOUT TO GO BOOM */ - // Fault handler - set_faultBit(BATTERY_OVERVOLTAGE_FAULT); + // is battery booming + if (Battery_Voltage > OVERVOLTAGE_THRESHOLD_MV) { + faults_set(FAULT_ID_BATTERY_OVERVOLTAGE); } - if (Battery_Voltage < UNDERVOLTAGE_THRESHOLD_MV) - { - /* Battery voltage is too low or battery is disconnected, treat as fault */ - // Fault handler - set_faultBit(BATTERY_UNDERVOLTAGE_FAULT); + // Is batt voltage too low or disconnected? + if (Battery_Voltage < UNDERVOLTAGE_THRESHOLD_MV) { + faults_set(FAULT_ID_BATTERY_UNDERVOLTAGE); } - if (contactor_get_sense(MOTOR_CONTACTOR) != contactor_get_commanded_state(MOTOR_CONTACTOR)) - { - // Fault handler - set_faultBit(MOTOR_SENSE_MISMATCH_FAULT); + if (contactor_get_sense(MOTOR_CONTACTOR) != contactor_get_commanded_state(MOTOR_CONTACTOR)) { + faults_set(FAULT_ID_MOTOR_SENSE_MISMATCH); } - if (contactor_get_sense(MOTOR_PRE_CONTACTOR) != contactor_get_commanded_state(MOTOR_PRE_CONTACTOR)) - { - // Fault handler - set_faultBit(PRECHARGE_SENSE_MISMATCH_FAULT); + if (contactor_get_sense(MOTOR_PRE_CONTACTOR) != + contactor_get_commanded_state(MOTOR_PRE_CONTACTOR)) { + faults_set(FAULT_ID_PRECHARGE_SENSE_MISMATCH); } } -static void print_Precharge_State(Precharge_State_t State) -{ - switch (State) - { - case PRECHARGE_STATE_INITIAL: - printf("Precharge State: Initial\r\n"); - break; - case PRECHARGE_STATE_PRECHARGING: - printf("Precharge State: Precharging\r\n"); - break; - case PRECHARGE_STATE_RUN: - printf("Precharge State: Run\r\n"); - break; - default: - printf("Unknown\r\n"); - break; - } +static void PT_print_state(PrechargeState_e state) { + printf("Prech_state: %s\r\n", precharge_state_names[state]); } -void Task_Precharge() -{ - Init_PrechargeTask(); - - State = PRECHARGE_STATE_WAITING; - static TickType_t Start_Tick = 0; - +void Task_Precharge() { + TickType_t timeout_start_tick = 0; ADC_Sense_Result ADC_Result = {0}; - - uint8_t VCU_tx_data[8]; - vcu_precharge_voltages_t precharge_voltages = {0}; uint8_t can_send_errors = 0; uint8_t printDebugCounter = 0; + LED_set(HALL_EFFECT, LED_ON); - while (1) - { - - if (Read_ADC(ADC_TIMEOUT_MS, &ADC_Result) != ADC_SENSE_OK) - { - Error_Handler(); + while (1) { + if (Read_ADC(ADC_TIMEOUT_MS, &ADC_Result) != ADC_SENSE_OK) { + faults_set(FAULT_ID_PRECHARGE_SENSE_TIMEOUT); } - Battery_Voltage = ADC_Result.Battery_Voltage; - Motor_Voltage = ADC_Result.Motor_Voltage; - precharge_voltages.VCU_Precharge_Battery_Voltage = Battery_Voltage; - precharge_voltages.VCU_Precharge_Motor_Voltage = Motor_Voltage; + battery_voltage = ADC_Result.Battery_Voltage; + motor_voltage = ADC_Result.Motor_Voltage; - packMotorVoltage(precharge_voltages, VCU_tx_data); + can_status_t result = + CarCAN_Send_Precharge_Voltages(motor_voltage, battery_voltage, portMAX_DELAY); - if (Car_CANBus_Send(&VCUSendVoltageHeader, VCU_tx_data, portMAX_DELAY) == CAN_ERR) - { + if (result == CAN_ERR) { can_send_errors++; - } - else - { + } else { can_send_errors = 0; } - printf("Motor: %ld mV | Battery: %ld mV\r\n", Motor_Voltage, Battery_Voltage); - - switch (State) - { - case PRECHARGE_STATE_WAITING: - - set_stateBit(PRECHARGE_WAITING_STATE); - Check_Ignition_State(); // Wait for ignition on message from driver input task, then move to initial precharge state - printf("Precharge State: Waiting for Ignition\r\n"); - - break; - case PRECHARGE_STATE_INITIAL: // Startup state: Closes main contactor and moves to precharging state - - Check_Ignition_State(); - - set_stateBit(PRECHARGE_INITIAL_STATE); - - printf("Precharge State: Initial\r\n"); - - if (contactor_set(MOTOR_CONTACTOR, CLOSED, CALLBACK_BLOCKING_TIME, NORMAL) != SUCCESS) - { - set_faultBit(MOTOR_SENSE_TIMEOUT_FAULT); - } - - State = PRECHARGE_STATE_PRECHARGING; - - set_MotorSafeBit(MOTOR_CONTACTOR_ENABLED); - - // Start a timer for precharging - Start_Tick = xTaskGetTickCount(); - - break; - case PRECHARGE_STATE_PRECHARGING: // Precharging state: Waits for battery voltage to reach 90% of motor voltage, then closes precharge contactor and moves to run state - - Check_Ignition_State(); - - set_stateBit(PRECHARGE_PRECHARGING_STATE); - - Fault_Checker(Motor_Voltage, Battery_Voltage); // Check for faults while precharging, if any fault conditions are met, will call fault handler and not proceed with precharge sequence - - const TickType_t Current_Tick = xTaskGetTickCount(); // Check how long we've been precharging for, fault if not precharged after PRECHARGE_TIMEOUT_MS - printf("Precharge State: Precharging\r\n"); - if ((Current_Tick - Start_Tick) > pdMS_TO_TICKS(PRECHARGE_TIMEOUT_MS)) // Faults if precharging takes too long - { - // Check if motor voltage is within 90% of battery voltage (precharge complete) - if (Motor_Voltage * RATIO_SCALE >= Battery_Voltage * PRECHARGE_THRESHOLD_90) - { - set_faultBit(MOTOR_SENSE_TIMEOUT_FAULT); + // printf("Motor: %ld mV | Battery: %ld mV\r\n", motor_voltage, battery_voltage); + + PT_check_ign(); + + PrechargeState_e curr_state; + taskENTER_CRITICAL(); + curr_state = g_precharge_state; + taskEXIT_CRITICAL(); + + switch (curr_state) { + case PRECHARGE_STATE_WAITING: + // Wait for ignition on message from driver input task, + // then move to initial precharge state + // printf("Precharge State: Waiting for Ignition\r\n"); + break; + + // Startup state: Closes main contactor and moves to precharging state + case PRECHARGE_STATE_INITIAL: + // printf("Precharge State: Initial\r\n"); + + // dont attempt to close contactors before bps ready + if (!g_data_read->bps_status.HV_Plus_Contactor_State || + !g_data_read->bps_status.HV_Minus_Contactor_State || + g_data_read->bps_status.BPS_Fault) { + break; } - State = PRECHARGE_STATE_PRECHARGING; - } - - // Start a timer for precharging - set_MotorSafeBit(MOTOR_PRECHARGE_CONTACTOR_ENABLED); - Start_Tick = xTaskGetTickCount(); - break; - case PRECHARGE_STATE_RUN: // Run state: Continuously checks that motor voltage stays within 80% of battery voltage - Check_Ignition_State(); - - set_stateBit(PRECHARGE_RUN_STATE); - - Fault_Checker(Motor_Voltage, Battery_Voltage); // Check for faults while precharging, if any fault conditions are met, will call fault handler and not proceed with precharge sequence + if (contactor_set(MOTOR_CONTACTOR, CLOSED, CALLBACK_BLOCKING_TIME, NORMAL) != + SUCCESS) { + faults_set(FAULT_ID_MOTOR_SENSE_TIMEOUT); + } - // Use 80% threshold for hysteresis - printf("Precharge State: Run\r\n"); - if (Motor_Voltage * RATIO_SCALE < Battery_Voltage * PRECHARGE_THRESHOLD_80) - { - } - break; - default: - break; + taskENTER_CRITICAL(); + g_precharge_state = PRECHARGE_STATE_PRECHARGING; + taskEXIT_CRITICAL(); + + set_MotorSafeBit(MOTOR_CONTACTOR_ENABLED); + + // Start a timer for precharging + timeout_start_tick = xTaskGetTickCount(); + break; + + // Precharging state: Waits for battery voltage to reach 90% of motor voltage, + // then closes precharge contactor and moves to run state + case PRECHARGE_STATE_PRECHARGING: + // Check for faults while precharging, if any fault conditions are met, + // will call fault handler and not proceed with precharge sequence + Fault_Checker(motor_voltage, battery_voltage); + + // Check how long we've been precharging for, fault if not precharged after + // PRECHARGE_TIMEOUT_MS + const TickType_t timeout_curr_tick = xTaskGetTickCount(); + // printf("Precharge State: Precharging\r\n"); + + // Faults if precharging takes too long + if ((timeout_curr_tick - timeout_start_tick) > + pdMS_TO_TICKS(PRECHARGE_TIMEOUT_MS)) { + // Check if motor voltage is within 90% of battery voltage (precharge complete) + if (motor_voltage * RATIO_SCALE >= battery_voltage * PRECHARGE_THRESHOLD_90) { + if (contactor_set(MOTOR_PRE_CONTACTOR, CLOSED, CALLBACK_BLOCKING_TIME, + false) != SUCCESS) { + faults_set(FAULT_ID_MOTOR_SENSE_TIMEOUT); + } + taskENTER_CRITICAL(); + g_precharge_state = PRECHARGE_STATE_COMPLETE; + taskEXIT_CRITICAL(); + } else { + faults_set(FAULT_ID_PRECHARGE_TIMEOUT); + } + } + set_MotorSafeBit(MOTOR_PRECHARGE_CONTACTOR_ENABLED); + break; + + // Run state: Continuously checks that motor voltage stays + // within 80% of battery voltage (Threshold lowered to 80%) + // after precharge is complete + case PRECHARGE_STATE_COMPLETE: + // Check for faults while precharging, if any fault + // conditions are met, will call fault handler and + // not proceed with precharge sequence + Fault_Checker(motor_voltage, battery_voltage); + + // Use 80% threshold for hysteresis + if (motor_voltage * RATIO_SCALE < battery_voltage * PRECHARGE_THRESHOLD_80) { + faults_set(FAULT_ID_MOTOR_LT_BATTERY); + } + break; + default: + break; } - if (printDebugCounter >= PRECHARGE_PRINTF_DEBUG_COUNTER) - { + taskENTER_CRITICAL(); + curr_state = g_precharge_state; + taskEXIT_CRITICAL(); + + printDebugCounter++; + if (printDebugCounter >= PRECHARGE_PRINTF_DEBUG_COUNTER) { // prints battery and motor voltage - printf("Motor: %ld mV | Battery: %ld mV\r\n", - Motor_Voltage, - Battery_Voltage); + printf("Motor: %ld mV | Battery: %ld mV\r\n", motor_voltage, battery_voltage); // prints current precharge state - print_Precharge_State(State); + PT_print_state(curr_state); printDebugCounter = 0; } // set the Precharge Complete LED - LED_set(PRECHARGE_COMPLETE, State == PRECHARGE_STATE_RUN ? LED_ON : LED_OFF); + LED_set(PRECHARGE_COMPLETE, curr_state == PRECHARGE_STATE_COMPLETE ? LED_ON : LED_OFF); // update the motor safe bits with Contactor state - if (contactor_get_sense(MOTOR_PRE_CONTACTOR) == CLOSED) - { + if (contactor_get_sense(MOTOR_PRE_CONTACTOR) == CLOSED) { set_MotorSafeBit(MOTOR_PRECHARGE_CONTACTOR_ENABLED); - } - else - { + } else { clear_MotorSafeBit(MOTOR_PRECHARGE_CONTACTOR_ENABLED); } - if (contactor_get_sense(MOTOR_CONTACTOR) == CLOSED) - { + if (contactor_get_sense(MOTOR_CONTACTOR) == CLOSED) { set_MotorSafeBit(MOTOR_CONTACTOR_ENABLED); - } - else - { + } else { clear_MotorSafeBit(MOTOR_CONTACTOR_ENABLED); } - Toggle_LED(HB); - vTaskDelay(PRECHARGE_TASK_DELAY_MS); + // LED_toggle(HB); + vTaskDelay(pdMS_TO_TICKS(PRECHARGE_TASK_DELAY_MS)); } -} \ No newline at end of file +} diff --git a/Firmware/Tasks/Src/ReadMotorCAN.c b/Firmware/Tasks/Src/ReadMotorCAN.c deleted file mode 100644 index 1b3b99a2..00000000 --- a/Firmware/Tasks/Src/ReadMotorCAN.c +++ /dev/null @@ -1,31 +0,0 @@ -#include "ReadMotorCAN.h" - -void Init_ReadMotorCAN() -{ -} - -void Task_ReadMotorCAN() -{ - - // Motor CANbus must be initialized by now - - Init_ReadMotorCAN(); - - FDCAN_RxHeaderTypeDef motorstatus_rx_header = {0}; - uint8_t motorstatus_rx_data[8] = {0}; - - uint8_t can_recv_errors = 0; - - while (1) - { - - if (Motor_CANBus_Receive(CAN_ID_MC_STATUS, &motorstatus_rx_header, motorstatus_rx_data, portMAX_DELAY) == CAN_OK) - { - can_recv_errors = 0; - } - else - { - can_recv_errors++; - } - } -} diff --git a/Firmware/Tasks/Src/UpdateVCUInputsTask.c b/Firmware/Tasks/Src/UpdateVCUInputsTask.c new file mode 100644 index 00000000..c1218e01 --- /dev/null +++ b/Firmware/Tasks/Src/UpdateVCUInputsTask.c @@ -0,0 +1,138 @@ +#include "UpdateVCUInputsTask.h" +#include "Contactors.h" +#include "FaultBits.h" +#include "StatusLEDs.h" +#include "event_groups.h" +#include +#include + +static float brake_threshold = BRAKE_THRESH; + +static VCUDataIn_t fsm_input_a = {0}; +static VCUDataIn_t fsm_input_b = {0}; + +VCUDataIn_t * volatile g_data_read = &fsm_input_a; +VCUDataIn_t * volatile g_data_write = &fsm_input_b; + +static void rebuild_inputs(void) { + EventBits_t s = 0; + + if (g_data_read->driver_input.Gear_Forward) + s |= FORWARD_BIT; + else if (g_data_read->driver_input.Gear_Reverse) + s |= REVERSE_BIT; + else + s |= NEUTRAL_BIT; + + if (g_data_read->driver_input.Regen_Activate) + s |= REGEN_BUTTON_BIT; + if (g_data_read->driver_input.Regen_Enable) + s |= REGEN_ENABLED_BIT; + if (g_data_read->driver_input.Cruise_Enable) + s |= CRUISE_CONTROL_BUTTON_BIT; + if (g_data_read->bps_status.BPS_Regen_OK) + s |= READY_TO_REGEN_BIT; + if (contactor_get_sense(MOTOR_CONTACTOR) && contactor_get_sense(MOTOR_PRE_CONTACTOR)) + s |= PRECHARGE_COMPLETE_BIT; + + if (g_data_read->brake_pressure1.Brake_Pressure >= brake_threshold) { + s |= BRAKE_BIT; + brake_threshold = BRAKE_THRESH_HYST; + } else { + brake_threshold = BRAKE_THRESH; + } + + fsm_set_all_inputs(s); + + if(fsm_is_input_set(REGEN_BUTTON_BIT) && !fsm_is_input_set(READY_TO_REGEN_BIT)) { + warning_set(WARNING_ID_REGEN_NOT_ALLOWED); + } else { + warning_clear(WARNING_ID_REGEN_NOT_ALLOWED); + } +} + +void UFI_throw_faults() { + EventBits_t mask = 0; + if (g_data_read->bps_status.BPS_Fault) + mask |= FAULT_BIT(FAULT_ID_BPS_FAULT); + if (g_data_read->controls_status.Controls_Leader_Fault) + mask |= FAULT_BIT(FAULT_ID_CONTROLS_FAULT); + + // Moco faults + if (g_data_read->motor_status.MC_FAULT_HardwareOverCurrent) + mask |= FAULT_BIT(FAULT_ID_MOTOR_HARDWARE_OVERCURRENT); + if (g_data_read->motor_status.MC_FAULT_SoftwareOverCurrent) + mask |= FAULT_BIT(FAULT_ID_MOTOR_SOFTWARE_OVERCURRENT); + if (g_data_read->motor_status.MC_FAULT_DcBusOverVoltage) + mask |= FAULT_BIT(FAULT_ID_MOTOR_DC_BUS_OVERVOLTAGE); + if (g_data_read->motor_status.MC_FAULT_BadMotorPositionHallSeq) + mask |= FAULT_BIT(FAULT_ID_MOTOR_BAD_HALL_SEQUENCE); + if (g_data_read->motor_status.MC_FAULT_WatchdogCausedLastReset) + mask |= FAULT_BIT(FAULT_ID_MOTOR_WD_RESET); + if (g_data_read->motor_status.MC_FAULT_ConfigRead) + mask |= FAULT_BIT(FAULT_ID_MOTOR_CONFIG_READ); + if (g_data_read->motor_status.MC_FAULT_15vRailUnderVoltage) + mask |= FAULT_BIT(FAULT_ID_MOTOR_15V_UNDERVOLTAGE); + if (g_data_read->motor_status.MC_FAULT_DesaturationFault) + mask |= FAULT_BIT(FAULT_ID_MOTOR_DESATURATION); + if (g_data_read->motor_status.MC_FAULT_MotorOverSpeed) + mask |= FAULT_BIT(FAULT_ID_MOTOR_OVERSPEED); + + // Pedals faults + if (g_data_read->accel_brake.AccelPedal_Main_Fault || + g_data_read->accel_brake.AccelPedal_Redundant_Fault || + g_data_read->accel_brake.Brake_Pressure_1_Fault || + g_data_read->accel_brake.Brake_Pressure_2_Fault) { + mask |= FAULT_BIT(FAULT_ID_PEDAL_BOARD_FAULT); + } + + if (g_data_read->lws.LWS_Fault) + mask |= FAULT_BIT(FAULT_ID_STEERING_SENSOR_FAULT); + + faults_set_mask(mask); +} + +void Task_UpdateVCUInputs(void *args __attribute__((unused))) { + TickType_t last = xTaskGetTickCount(); + + while (1) { + // printf("Task_UpdateVCUInputs: %ld", last); + // update from can + VCUDataIn_t *volatile update = g_data_write; + if (MotorCAN_Recv_Status(&update->motor_status, 0) == CAN_OK) { + LED_toggle(HB); + } + MotorCAN_Recv_Status(&update->motor_status, 0); + MotorCAN_Recv_Velocity(&update->motor_velocity, 0); + MotorCAN_Recv_Control_Src(&update->motor_controls_src, 0); + + // making these motor can should be CARCAN + + CarCAN_Recv_BPS_Status(&update->bps_status, 0); + CarCAN_Recv_Pedals_Position(&update->accel_brake, 0); + CarCAN_Recv_Brake_Pressure1(&update->brake_pressure1, 0); + CarCAN_Recv_Brake_Pressure2(&update->brake_pressure2, 0); + CarCAN_Recv_Controls_Status(&update->controls_status, 0); + CarCAN_Recv_Driver_Input(&update->driver_input, 0); + CarCAN_Recv_LWS(&update->lws, 0); + + printf("Update VCU inputs: about to switch read and write ptrs\r\n"); + + VCUDataIn_t *volatile tmp; + taskENTER_CRITICAL(); + tmp = g_data_read; + g_data_read = g_data_write; + g_data_write = tmp; + taskEXIT_CRITICAL(); + + printf("Updated from CAN!\r\n"); + + memcpy(g_data_write, g_data_read, sizeof(VCUDataIn_t)); + + // Throw relevant faults + UFI_throw_faults(); + + rebuild_inputs(); + vTaskDelayUntil(&last, pdMS_TO_TICKS(50)); + } +} diff --git a/Firmware/Tasks/Src/VCUReceiveCANTask.c b/Firmware/Tasks/Src/VCUReceiveCANTask.c deleted file mode 100644 index 21145a43..00000000 --- a/Firmware/Tasks/Src/VCUReceiveCANTask.c +++ /dev/null @@ -1,98 +0,0 @@ -#include "VCUReceiveCANTask.h" - -static StaticQueue_t driverInputQueueBuffer; -static uint8_t driverInputQueueStorage[DRIVER_INPUT_QUEUE_SIZE * sizeof(can_rx_payload_t)]; -static QueueHandle_t driverInputQueue; - -static StaticQueue_t BPSQueueBuffer; -static uint8_t BPSQueueStorage[BPS_QUEUE_SIZE * sizeof(can_rx_payload_t)]; -static QueueHandle_t BPSQueue; - -can_rx_payload_t payload; -uint8_t Start_Precharge = 0; -uint8_t End_Precharge = 0; - -static void initDriverInputQueue() -{ - driverInputQueue = xQueueCreateStatic( - DRIVER_INPUT_QUEUE_SIZE, - sizeof(can_rx_payload_t), - driverInputQueueStorage, - &driverInputQueueBuffer); - - if (driverInputQueue == NULL) - { - return; - } -} - -static void initBPSQueue() -{ - BPSQueue = xQueueCreateStatic( - BPS_QUEUE_SIZE, - sizeof(can_rx_payload_t), - BPSQueueStorage, - &BPSQueueBuffer); - - if (BPSQueue == NULL) - { - return; - } -} - -void Init_VCUReceiveCANTask() -{ - initDriverInputQueue(); - initBPSQueue(); -} - -void can_fd_rx_callback_hook(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs, can_rx_payload_t recv_payload) -{ - BaseType_t higherPriorityTaskWoken = pdFALSE; - - if (recv_payload.header.Identifier == CAN_ID_DRIVER_INPUT_STATUS) - { - if (driverInputQueue != NULL) - { - xQueueSendFromISR(driverInputQueue, &recv_payload, &higherPriorityTaskWoken); - } - } - else if (recv_payload.header.Identifier == CAN_ID_BPS_STATUS) - { - if (BPSQueue != NULL) - { - xQueueSendFromISR(BPSQueue, &recv_payload, &higherPriorityTaskWoken); - } - } - - portYIELD_FROM_ISR(higherPriorityTaskWoken); -} - -void Task_VCUReceiveCAN() -{ - Init_VCUReceiveCANTask(); - - while(1) - { - if (xQueueReceive(driverInputQueue, &payload, pdMS_TO_TICKS(CAN_BLOCKING_TIME_MS)) == pdTRUE) - { - if (payload.header.Identifier == CAN_ID_DRIVER_INPUT_STATUS && payload.data[IGNITION_MOTOR_INDEX] == 1 && Ignition_State == 0) - { - Start_Precharge = 1; - } - else if (payload.header.Identifier == CAN_ID_DRIVER_INPUT_STATUS && payload.data[IGNITION_MOTOR_INDEX] == 0 && Ignition_State == 1) - { - // offTick = xTaskGetTickCount(); - End_Precharge = 1; // Turning off ignition - } - } - - if (xQueueReceive(BPSQueue, &payload, pdMS_TO_TICKS(CAN_BLOCKING_TIME_MS)) == pdTRUE) - { - if(payload.header.Identifier == CAN_ID_BPS_STATUS && payload.data[0] != BPS_STATUS_BPS_FAULT_OK) - { - set_faultBit(BPS_FAULT); - } - } - } -} \ No newline at end of file diff --git a/Firmware/Tasks/Src/VCUStatusTask.c b/Firmware/Tasks/Src/VCUStatusTask.c new file mode 100644 index 00000000..787a2d2f --- /dev/null +++ b/Firmware/Tasks/Src/VCUStatusTask.c @@ -0,0 +1,94 @@ +#include "VCUStatusTask.h" +#include "Contactors.h" +#include "FSMTask.h" +#include "FaultBits.h" +#include "StatusLEDs.h" +#include "UpdateVCUInputsTask.h" +#include "Watchdogs.h" +#include "event_groups.h" +#include "math.h" + +void Task_BroadcastVCUStatus(void *args __attribute__((unused))) { + uint8_t buf[CAN_DLC_VCU_STATUS]; + + while (1) { + // Byte 0 + uint8_t state = current_state.stateName & 0x0FU; + bool motor_ready = (current_state.stateName != DISABLED) && + (current_state.stateName != STATE_INIT) && + (current_state.stateName != CAR_NOT_READY); + bool motor_prech_cont_state = contactor_get_sense(MOTOR_PRE_CONTACTOR); + bool motor_cont_state = contactor_get_sense(MOTOR_CONTACTOR); + bool driver_inp_wdog = watchdog_is_alive(WD_IDX_DRIVER_INPUT); + buf[0] = (state) | (motor_ready << 4) | (motor_prech_cont_state << 5) | + (motor_cont_state << 6) | (driver_inp_wdog << 7); + + // Byte 1 + bool pedals_wdog = watchdog_is_alive(WD_IDX_ACCEL_BRAKE); + bool bps_wdog = watchdog_is_alive(WD_IDX_BPS_STATUS); + bool steering_wdog = watchdog_is_alive(WD_IDX_STEERING_ANGLE); + bool bps_fault = faults_is_active(FAULT_ID_BPS_FAULT); + bool controls_fault = faults_is_active(FAULT_ID_CONTROLS_FAULT); + bool motor_fault = !!(faults_get() & FAULT_MASK_MOTOR_ALL); + bool pedals_fault = ((bool)g_data_read->accel_brake.AccelPedal_Main_Fault) || + ((bool)g_data_read->accel_brake.AccelPedal_Redundant_Fault) || + ((bool)g_data_read->accel_brake.BrakePedal_Main_Fault) || + ((bool)g_data_read->accel_brake.BrakePedal_Redundant_Fault); //|| + // (fabs(g_data_read->accel_brake.AccelPedal_Main_Pos - + // g_data_read->accel_brake.AccelPedal_Redundant_Pos) < + // ACCEPTABLE_PEDAL_DEVIATION); + + bool steering_fault = g_data_read->lws.LWS_Fault; + buf[1] = (pedals_wdog) | (bps_wdog << 1) | (steering_wdog << 2) | (bps_fault << 3) | + (controls_fault << 4) | (motor_fault << 5) | (pedals_fault << 6) | + (steering_fault << 7); + + buf[2] = g_data_read->motor_controls_src.Motor_Command_Source | + ((current_state.stateName == REGEN) << 1) | + (g_data_read->bps_status.BPS_Regen_OK << 2) | + (faults_is_active(FAULT_ID_PRECHARGE_TIMEOUT) << 3) | + (faults_is_active(FAULT_ID_PRECHARGE_SENSE_TIMEOUT) << 4) | + (faults_is_active(FAULT_ID_PRECHARGE_SENSE_MISMATCH) << 5) | + (faults_is_active(FAULT_ID_MOTOR_SENSE_MISMATCH) << 6) | + (faults_is_active(FAULT_ID_MOTOR_SENSE_TIMEOUT) << 7); + + buf[3] = (faults_is_active(FAULT_ID_BATTERY_OVERVOLTAGE)) | + (faults_is_active(FAULT_ID_BATTERY_UNDERVOLTAGE) << 1) | + (faults_is_active(FAULT_ID_MOTOR_GT_BATTERY) << 2) | // TODO check if this is right + (faults_is_active(FAULT_ID_MOTOR_LT_BATTERY) << 3) | + //(faults_any_active() << 4) | // TODO: make this "other" but not enough faults bits rn + //The rest of these bits and one of the next one are all warnings + (warning_is_active(WARNING_ID_MOTOR_DIRECTION_CHANGE_LOCKOUT) << 5) | + (warning_is_active(WARNING_ID_TIPPING_LIMIT_ACTIVE) << 6) | + (warning_is_active(WARNING_ID_REGEN_NOT_ALLOWED) << 7); + + buf[4] = (warning_is_active(WARNING_ID_REGEN_NOT_ENABLED) << 0) | + (fsm_is_input_set(BRAKE_BIT) << 1) | + (fsm_is_input_set(PRECHARGE_COMPLETE_BIT) << 2) | + (fsm_is_input_set(CRUISE_CONTROL_BUTTON_BIT) << 3) | + (fsm_is_input_set(REGEN_BUTTON_BIT) << 4) | + (fsm_is_input_set(REGEN_ENABLED_BIT) << 5) | + (fsm_is_input_set(READY_TO_REGEN_BIT) << 6) | + (fsm_is_input_set(FORWARD_BIT) << 7); + + buf[5] = (fsm_is_input_set(NEUTRAL_BIT) << 0) | + (fsm_is_input_set(REVERSE_BIT) << 1); + + + FDCAN_TxHeaderTypeDef tx_header = {0}; + tx_header.Identifier = CAN_ID_VCU_STATUS; + tx_header.IdType = FDCAN_STANDARD_ID; + tx_header.TxFrameType = FDCAN_DATA_FRAME; + tx_header.DataLength = FDCAN_DLC_BYTES(CAN_DLC_VCU_STATUS); + tx_header.ErrorStateIndicator = FDCAN_ESI_ACTIVE; + tx_header.BitRateSwitch = FDCAN_BRS_OFF; + tx_header.FDFormat = FDCAN_CLASSIC_CAN; + tx_header.TxEventFifoControl = FDCAN_NO_TX_EVENTS; + tx_header.MessageMarker = 0; + + CarCAN_Send(&tx_header, buf, sizeof(buf)); + + LED_toggle(HB); + vTaskDelay(pdMS_TO_TICKS(800)); + } +} \ No newline at end of file diff --git a/Firmware/config/Inc/BPSCAN_can_msgs.h b/Firmware/config/Inc/BPSCAN_can_msgs.h new file mode 100644 index 00000000..b9cb13f2 --- /dev/null +++ b/Firmware/config/Inc/BPSCAN_can_msgs.h @@ -0,0 +1,349 @@ +#pragma once + +#include + +/* ================= CAN ID Macros ================= */ + +#define CAN_ID_BPS_VT0_VOLTAGE_ARR 0x2 +#define CAN_ID_BPS_VT1_VOLTAGE_ARR 0x3 +#define CAN_ID_BPS_VT2_VOLTAGE_ARR 0x4 +#define CAN_ID_BPS_VT3_VOLTAGE_ARR 0x5 +#define CAN_ID_BPS_VT4_VOLTAGE_ARR 0x6 +#define CAN_ID_BPS_VT5_VOLTAGE_ARR 0x7 +#define CAN_ID_BPS_VT6_VOLTAGE_ARR 0x8 +#define CAN_ID_BPS_VT7_VOLTAGE_ARR 0x9 +#define CAN_ID_BPS_PACK_CURRENT 0xA +#define CAN_ID_BPS_VT0_TEMPERATURE_ARR 0x10 +#define CAN_ID_BPS_VT1_TEMPERATURE_ARR 0x11 +#define CAN_ID_BPS_VT2_TEMPERATURE_ARR 0x12 +#define CAN_ID_BPS_VT3_TEMPERATURE_ARR 0x13 +#define CAN_ID_BPS_VT4_TEMPERATURE_ARR 0x14 +#define CAN_ID_BPS_VT5_TEMPERATURE_ARR 0x15 +#define CAN_ID_BPS_VT6_TEMPERATURE_ARR 0x16 +#define CAN_ID_BPS_VT7_TEMPERATURE_ARR 0x17 +#define CAN_ID_BPS_PACK_CURRENT_ADC 0x755 +#define CAN_ID_BPS_BALANCE_DISCHARGE 0x7A0 + +/* ================= CAN Length Macros ================= */ + +#define CAN_DLC_BPS_VT0_VOLTAGE_ARR 4 +#define CAN_DLC_BPS_VT1_VOLTAGE_ARR 4 +#define CAN_DLC_BPS_VT2_VOLTAGE_ARR 4 +#define CAN_DLC_BPS_VT3_VOLTAGE_ARR 4 +#define CAN_DLC_BPS_VT4_VOLTAGE_ARR 4 +#define CAN_DLC_BPS_VT5_VOLTAGE_ARR 4 +#define CAN_DLC_BPS_VT6_VOLTAGE_ARR 4 +#define CAN_DLC_BPS_VT7_VOLTAGE_ARR 4 +#define CAN_DLC_BPS_PACK_CURRENT 5 +#define CAN_DLC_BPS_VT0_TEMPERATURE_ARR 7 +#define CAN_DLC_BPS_VT1_TEMPERATURE_ARR 7 +#define CAN_DLC_BPS_VT2_TEMPERATURE_ARR 7 +#define CAN_DLC_BPS_VT3_TEMPERATURE_ARR 7 +#define CAN_DLC_BPS_VT4_TEMPERATURE_ARR 7 +#define CAN_DLC_BPS_VT5_TEMPERATURE_ARR 7 +#define CAN_DLC_BPS_VT6_TEMPERATURE_ARR 7 +#define CAN_DLC_BPS_VT7_TEMPERATURE_ARR 7 +#define CAN_DLC_BPS_PACK_CURRENT_ADC 3 +#define CAN_DLC_BPS_BALANCE_DISCHARGE 1 + + +/* ================= Value Table Enums ================= */ + +typedef enum { + BPS_VT0_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OK = 0, + BPS_VT0_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_BQ_I2C_READ_ERROR = 1, + BPS_VT0_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OUT_OF_BOUNDS = 2, + BPS_VT0_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OVER_VOLTAGE = 3, + BPS_VT0_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_UNDER_VOLTAGE = 4, + BPS_VT0_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_MESSAGE_WATCHDOG = 5, +} bps_vt0_voltage_arr_bps_voltage_tap_fault_e; + +typedef enum { + BPS_VT1_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OK = 0, + BPS_VT1_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_BQ_I2C_READ_ERROR = 1, + BPS_VT1_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OUT_OF_BOUNDS = 2, + BPS_VT1_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OVER_VOLTAGE = 3, + BPS_VT1_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_UNDER_VOLTAGE = 4, + BPS_VT1_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_MESSAGE_WATCHDOG = 5, +} bps_vt1_voltage_arr_bps_voltage_tap_fault_e; + +typedef enum { + BPS_VT2_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OK = 0, + BPS_VT2_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_BQ_I2C_READ_ERROR = 1, + BPS_VT2_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OUT_OF_BOUNDS = 2, + BPS_VT2_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OVER_VOLTAGE = 3, + BPS_VT2_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_UNDER_VOLTAGE = 4, + BPS_VT2_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_MESSAGE_WATCHDOG = 5, +} bps_vt2_voltage_arr_bps_voltage_tap_fault_e; + +typedef enum { + BPS_VT3_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OK = 0, + BPS_VT3_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_BQ_I2C_READ_ERROR = 1, + BPS_VT3_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OUT_OF_BOUNDS = 2, + BPS_VT3_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OVER_VOLTAGE = 3, + BPS_VT3_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_UNDER_VOLTAGE = 4, + BPS_VT3_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_MESSAGE_WATCHDOG = 5, +} bps_vt3_voltage_arr_bps_voltage_tap_fault_e; + +typedef enum { + BPS_VT4_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OK = 0, + BPS_VT4_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_BQ_I2C_READ_ERROR = 1, + BPS_VT4_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OUT_OF_BOUNDS = 2, + BPS_VT4_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OVER_VOLTAGE = 3, + BPS_VT4_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_UNDER_VOLTAGE = 4, + BPS_VT4_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_MESSAGE_WATCHDOG = 5, +} bps_vt4_voltage_arr_bps_voltage_tap_fault_e; + +typedef enum { + BPS_VT5_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OK = 0, + BPS_VT5_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_BQ_I2C_READ_ERROR = 1, + BPS_VT5_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OUT_OF_BOUNDS = 2, + BPS_VT5_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OVER_VOLTAGE = 3, + BPS_VT5_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_UNDER_VOLTAGE = 4, + BPS_VT5_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_MESSAGE_WATCHDOG = 5, +} bps_vt5_voltage_arr_bps_voltage_tap_fault_e; + +typedef enum { + BPS_VT6_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OK = 0, + BPS_VT6_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_BQ_I2C_READ_ERROR = 1, + BPS_VT6_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OUT_OF_BOUNDS = 2, + BPS_VT6_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OVER_VOLTAGE = 3, + BPS_VT6_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_UNDER_VOLTAGE = 4, + BPS_VT6_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_MESSAGE_WATCHDOG = 5, +} bps_vt6_voltage_arr_bps_voltage_tap_fault_e; + +typedef enum { + BPS_VT7_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OK = 0, + BPS_VT7_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_BQ_I2C_READ_ERROR = 1, + BPS_VT7_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OUT_OF_BOUNDS = 2, + BPS_VT7_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_OVER_VOLTAGE = 3, + BPS_VT7_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_UNDER_VOLTAGE = 4, + BPS_VT7_VOLTAGE_ARR_BPS_VOLTAGE_TAP_FAULT_MESSAGE_WATCHDOG = 5, +} bps_vt7_voltage_arr_bps_voltage_tap_fault_e; + +typedef enum { + BPS_PACK_CURRENT_BPS_AMPERES_FAULT_OK = 0, + BPS_PACK_CURRENT_BPS_AMPERES_FAULT_OUT_OF_BOUNDS = 1, + BPS_PACK_CURRENT_BPS_AMPERES_FAULT_OVER_CURRENT_DISCHARGE_ = 2, + BPS_PACK_CURRENT_BPS_AMPERES_FAULT_OVER_CURRENT_CHARGE_ = 3, + BPS_PACK_CURRENT_BPS_AMPERES_FAULT_MESSAGE_WATCHDOG = 4, +} bps_pack_current_bps_amperes_fault_e; + +typedef enum { + BPS_VT0_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OK = 0, + BPS_VT0_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_GND_ = 1, + BPS_VT0_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_VCC_ = 2, + BPS_VT0_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_DISCONNECTED = 3, + BPS_VT0_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OVER_TEMPERATURE = 4, + BPS_VT0_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_OVER_TEMPERATURE = 5, + BPS_VT0_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_UNDER_TEMPERATURE = 6, + BPS_VT0_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_UNDER_TEMPERATURE = 7, + BPS_VT0_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_MESSAGE_WATCHDOG = 8, +} bps_vt0_temperature_arr_bps_temperature_tap_fault_e; + +typedef enum { + BPS_VT1_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OK = 0, + BPS_VT1_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_GND_ = 1, + BPS_VT1_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_VCC_ = 2, + BPS_VT1_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_DISCONNECTED = 3, + BPS_VT1_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OVER_TEMPERATURE = 4, + BPS_VT1_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_OVER_TEMPERATURE = 5, + BPS_VT1_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_UNDER_TEMPERATURE = 6, + BPS_VT1_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_UNDER_TEMPERATURE = 7, + BPS_VT1_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_MESSAGE_WATCHDOG = 8, +} bps_vt1_temperature_arr_bps_temperature_tap_fault_e; + +typedef enum { + BPS_VT2_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OK = 0, + BPS_VT2_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_GND_ = 1, + BPS_VT2_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_VCC_ = 2, + BPS_VT2_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_DISCONNECTED = 3, + BPS_VT2_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OVER_TEMPERATURE = 4, + BPS_VT2_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_OVER_TEMPERATURE = 5, + BPS_VT2_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_UNDER_TEMPERATURE = 6, + BPS_VT2_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_UNDER_TEMPERATURE = 7, + BPS_VT2_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_MESSAGE_WATCHDOG = 8, +} bps_vt2_temperature_arr_bps_temperature_tap_fault_e; + +typedef enum { + BPS_VT3_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OK = 0, + BPS_VT3_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_GND_ = 1, + BPS_VT3_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_VCC_ = 2, + BPS_VT3_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_DISCONNECTED = 3, + BPS_VT3_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OVER_TEMPERATURE = 4, + BPS_VT3_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_OVER_TEMPERATURE = 5, + BPS_VT3_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_UNDER_TEMPERATURE = 6, + BPS_VT3_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_UNDER_TEMPERATURE = 7, + BPS_VT3_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_MESSAGE_WATCHDOG = 8, +} bps_vt3_temperature_arr_bps_temperature_tap_fault_e; + +typedef enum { + BPS_VT4_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OK = 0, + BPS_VT4_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_GND_ = 1, + BPS_VT4_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_VCC_ = 2, + BPS_VT4_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_DISCONNECTED = 3, + BPS_VT4_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OVER_TEMPERATURE = 4, + BPS_VT4_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_OVER_TEMPERATURE = 5, + BPS_VT4_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_UNDER_TEMPERATURE = 6, + BPS_VT4_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_UNDER_TEMPERATURE = 7, + BPS_VT4_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_MESSAGE_WATCHDOG = 8, +} bps_vt4_temperature_arr_bps_temperature_tap_fault_e; + +typedef enum { + BPS_VT5_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OK = 0, + BPS_VT5_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_GND_ = 1, + BPS_VT5_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_VCC_ = 2, + BPS_VT5_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_DISCONNECTED = 3, + BPS_VT5_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OVER_TEMPERATURE = 4, + BPS_VT5_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_OVER_TEMPERATURE = 5, + BPS_VT5_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_UNDER_TEMPERATURE = 6, + BPS_VT5_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_UNDER_TEMPERATURE = 7, + BPS_VT5_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_MESSAGE_WATCHDOG = 8, +} bps_vt5_temperature_arr_bps_temperature_tap_fault_e; + +typedef enum { + BPS_VT6_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OK = 0, + BPS_VT6_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_GND_ = 1, + BPS_VT6_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_VCC_ = 2, + BPS_VT6_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_DISCONNECTED = 3, + BPS_VT6_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OVER_TEMPERATURE = 4, + BPS_VT6_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_OVER_TEMPERATURE = 5, + BPS_VT6_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_UNDER_TEMPERATURE = 6, + BPS_VT6_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_UNDER_TEMPERATURE = 7, + BPS_VT6_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_MESSAGE_WATCHDOG = 8, +} bps_vt6_temperature_arr_bps_temperature_tap_fault_e; + +typedef enum { + BPS_VT7_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OK = 0, + BPS_VT7_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_GND_ = 1, + BPS_VT7_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_VCC_ = 2, + BPS_VT7_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_DISCONNECTED = 3, + BPS_VT7_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_OVER_TEMPERATURE = 4, + BPS_VT7_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_OVER_TEMPERATURE = 5, + BPS_VT7_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_UNDER_TEMPERATURE = 6, + BPS_VT7_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_UNDER_TEMPERATURE = 7, + BPS_VT7_TEMPERATURE_ARR_BPS_TEMPERATURE_TAP_FAULT_MESSAGE_WATCHDOG = 8, +} bps_vt7_temperature_arr_bps_temperature_tap_fault_e; + +/* ================= Message Structs ================= */ + +typedef struct { + uint8_t BPS_Tap_idx; + uint16_t BPS_Voltage_Tap_Data; + uint8_t BPS_Voltage_Tap_Fault; +} bps_vt0_voltage_arr_t; + +typedef struct { + uint8_t BPS_Tap_idx; + uint16_t BPS_Voltage_Tap_Data; + uint8_t BPS_Voltage_Tap_Fault; +} bps_vt1_voltage_arr_t; + +typedef struct { + uint8_t BPS_Tap_idx; + uint16_t BPS_Voltage_Tap_Data; + uint8_t BPS_Voltage_Tap_Fault; +} bps_vt2_voltage_arr_t; + +typedef struct { + uint8_t BPS_Tap_idx; + uint16_t BPS_Voltage_Tap_Data; + uint8_t BPS_Voltage_Tap_Fault; +} bps_vt3_voltage_arr_t; + +typedef struct { + uint8_t BPS_Tap_idx; + uint16_t BPS_Voltage_Tap_Data; + uint8_t BPS_Voltage_Tap_Fault; +} bps_vt4_voltage_arr_t; + +typedef struct { + uint8_t BPS_Tap_idx; + uint16_t BPS_Voltage_Tap_Data; + uint8_t BPS_Voltage_Tap_Fault; +} bps_vt5_voltage_arr_t; + +typedef struct { + uint8_t BPS_Tap_idx; + uint16_t BPS_Voltage_Tap_Data; + uint8_t BPS_Voltage_Tap_Fault; +} bps_vt6_voltage_arr_t; + +typedef struct { + uint8_t BPS_Tap_idx; + uint16_t BPS_Voltage_Tap_Data; + uint8_t BPS_Voltage_Tap_Fault; +} bps_vt7_voltage_arr_t; + +typedef struct { + uint8_t BPS_Amperes_Fault; + int32_t Main_Battery_Current; + uint8_t FrameID_Amperes; +} bps_pack_current_t; + +typedef struct { + uint8_t BPS_Tap_idx; + int32_t BPS_Temperature_Tap_Data; + uint8_t BPS_Temperature_Tap_Fault; + uint16_t BPS_Temperature_Tap_ADC; +} bps_vt0_temperature_arr_t; + +typedef struct { + uint8_t BPS_Tap_idx; + int32_t BPS_Temperature_Tap_Data; + uint8_t BPS_Temperature_Tap_Fault; + uint16_t BPS_Temperature_Tap_ADC; +} bps_vt1_temperature_arr_t; + +typedef struct { + uint8_t BPS_Tap_idx; + int32_t BPS_Temperature_Tap_Data; + uint8_t BPS_Temperature_Tap_Fault; + uint16_t BPS_Temperature_Tap_ADC; +} bps_vt2_temperature_arr_t; + +typedef struct { + uint8_t BPS_Tap_idx; + int32_t BPS_Temperature_Tap_Data; + uint8_t BPS_Temperature_Tap_Fault; + uint16_t BPS_Temperature_Tap_ADC; +} bps_vt3_temperature_arr_t; + +typedef struct { + uint8_t BPS_Tap_idx; + int32_t BPS_Temperature_Tap_Data; + uint8_t BPS_Temperature_Tap_Fault; + uint16_t BPS_Temperature_Tap_ADC; +} bps_vt4_temperature_arr_t; + +typedef struct { + uint8_t BPS_Tap_idx; + int32_t BPS_Temperature_Tap_Data; + uint8_t BPS_Temperature_Tap_Fault; + uint16_t BPS_Temperature_Tap_ADC; +} bps_vt5_temperature_arr_t; + +typedef struct { + uint8_t BPS_Tap_idx; + int32_t BPS_Temperature_Tap_Data; + uint8_t BPS_Temperature_Tap_Fault; + uint16_t BPS_Temperature_Tap_ADC; +} bps_vt6_temperature_arr_t; + +typedef struct { + uint8_t BPS_Tap_idx; + int32_t BPS_Temperature_Tap_Data; + uint8_t BPS_Temperature_Tap_Fault; + uint16_t BPS_Temperature_Tap_ADC; +} bps_vt7_temperature_arr_t; + +typedef struct { + uint16_t Main_Battery_Current_ADC; + uint8_t FrameID_Amperes; +} bps_pack_current_adc_t; + +typedef struct { + uint8_t BPS_Segment_idx; + uint8_t BPS_Tap_idx; +} bps_balance_discharge_t; + diff --git a/Firmware/config/Inc/CarCAN_can_msgs.h b/Firmware/config/Inc/CarCAN_can_msgs.h index 4aa223d4..be074e12 100644 --- a/Firmware/config/Inc/CarCAN_can_msgs.h +++ b/Firmware/config/Inc/CarCAN_can_msgs.h @@ -7,14 +7,12 @@ #define CAN_ID_BPS_STATUS 0x1 #define CAN_ID_BPS_VOLTAGE_AGGREGATE_ARR 0xB #define CAN_ID_BPS_TEMPERATURE_AGGREGATE_ARR 0xC -#define CAN_ID_BPS_TEMP_RAWV_AGGREGATE_ARR 0xD +#define CAN_ID_CHARGERINTERFACE_STATUS 0xE #define CAN_ID_VCU_STATUS 0x18 #define CAN_ID_CONTROLS_STATUS 0x19 #define CAN_ID_BPS_PRECHARGE_VOLTAGES 0x20 #define CAN_ID_VCU_PRECHARGE_VOLTAGES 0x21 #define CAN_ID_PEDAL_STATUS 0x50 -#define CAN_ID_PEDAL_ACCEL_RAWV 0x51 -#define CAN_ID_PEDAL_BRAKE_RAWV 0x52 #define CAN_ID_DRIVER_INPUT_STATUS 0x60 #define CAN_ID_MPPT_A_POWERMEASUREMENTS 0x200 #define CAN_ID_MPPT_A_STATUS 0x201 @@ -38,7 +36,8 @@ #define CAN_ID_MPPT_C_SETOUTPUTVOLTAGELIMIT 0x251 #define CAN_ID_MPPT_C_SETOUTPUTCURRENTLIMIT 0x252 #define CAN_ID_SUPP_BATTERY_STATUS 0x300 -#define CAN_ID_SUPP_BATTERY_CHARGER_STATUS 0x301 +#define CAN_ID_SUPP_CHARGER_STATUS 0x301 +#define CAN_ID_SUPP_VICOR_STATS 0x302 #define CAN_ID_PDU_STATUS_ARR 0x350 #define CAN_ID_PDU_SET_SWITCH_ARR 0x351 #define CAN_ID_PDU_SET_CURRENT_LIMIT_ARR 0x352 @@ -48,22 +47,25 @@ #define CAN_ID_LV_CARRIER_STATUS 0x600 #define CAN_ID_BRAKE_PRESSURE_1 0x650 #define CAN_ID_BRAKE_PRESSURE_2 0x651 -#define CAN_ID_DISPLAY_STATUS 0x700 -#define CAN_ID_TELEMETRY_STATUS 0x750 +#define CAN_ID_DISPLAY_STATUS 0x680 +#define CAN_ID_TELEMETRY_STATUS 0x700 +#define CAN_ID_BPS_TEMP_ADC_AGGREGATE_ARR 0x750 +#define CAN_ID_SUPP_MEASUREMENTS_ADC 0x751 +#define CAN_ID_SUPP_VICOR_MEASUREMENTS_ADC 0x752 +#define CAN_ID_PEDAL_BRAKE_ADC 0x753 +#define CAN_ID_PEDAL_ACCEL_ADC 0x754 /* ================= CAN Length Macros ================= */ #define CAN_DLC_BPS_STATUS 8 #define CAN_DLC_BPS_VOLTAGE_AGGREGATE_ARR 6 #define CAN_DLC_BPS_TEMPERATURE_AGGREGATE_ARR 8 -#define CAN_DLC_BPS_TEMP_RAWV_AGGREGATE_ARR 4 -#define CAN_DLC_VCU_STATUS 4 -#define CAN_DLC_CONTROLS_STATUS 1 +#define CAN_DLC_CHARGERINTERFACE_STATUS 5 +#define CAN_DLC_VCU_STATUS 6 +#define CAN_DLC_CONTROLS_STATUS 6 #define CAN_DLC_BPS_PRECHARGE_VOLTAGES 6 #define CAN_DLC_VCU_PRECHARGE_VOLTAGES 6 #define CAN_DLC_PEDAL_STATUS 6 -#define CAN_DLC_PEDAL_ACCEL_RAWV 5 -#define CAN_DLC_PEDAL_BRAKE_RAWV 5 #define CAN_DLC_DRIVER_INPUT_STATUS 2 #define CAN_DLC_MPPT_A_POWERMEASUREMENTS 8 #define CAN_DLC_MPPT_A_STATUS 5 @@ -86,8 +88,9 @@ #define CAN_DLC_MPPT_C_PERFORMSWEEP 5 #define CAN_DLC_MPPT_C_SETOUTPUTVOLTAGELIMIT 2 #define CAN_DLC_MPPT_C_SETOUTPUTCURRENTLIMIT 2 -#define CAN_DLC_SUPP_BATTERY_STATUS 8 -#define CAN_DLC_SUPP_BATTERY_CHARGER_STATUS 8 +#define CAN_DLC_SUPP_BATTERY_STATUS 6 +#define CAN_DLC_SUPP_CHARGER_STATUS 6 +#define CAN_DLC_SUPP_VICOR_STATS 5 #define CAN_DLC_PDU_STATUS_ARR 5 #define CAN_DLC_PDU_SET_SWITCH_ARR 1 #define CAN_DLC_PDU_SET_CURRENT_LIMIT_ARR 3 @@ -95,593 +98,805 @@ #define CAN_DLC_COOLANT_TEMPERATURE 4 #define CAN_DLC_RADIATOR_FANSPEED 8 #define CAN_DLC_LV_CARRIER_STATUS 1 -#define CAN_DLC_BRAKE_PRESSURE_1 6 -#define CAN_DLC_BRAKE_PRESSURE_2 6 +#define CAN_DLC_BRAKE_PRESSURE_1 5 +#define CAN_DLC_BRAKE_PRESSURE_2 5 #define CAN_DLC_DISPLAY_STATUS 2 #define CAN_DLC_TELEMETRY_STATUS 8 +#define CAN_DLC_BPS_TEMP_ADC_AGGREGATE_ARR 4 +#define CAN_DLC_SUPP_MEASUREMENTS_ADC 5 +#define CAN_DLC_SUPP_VICOR_MEASUREMENTS_ADC 5 +#define CAN_DLC_PEDAL_BRAKE_ADC 5 +#define CAN_DLC_PEDAL_ACCEL_ADC 5 /* ================= Value Table Enums ================= */ typedef enum { - BPS_STATUS_BPS_FAULT_DISCHARGING_OVERCURRENT = 17, - BPS_STATUS_BPS_FAULT_CHARGING_OVERCURRENT = 16, - BPS_STATUS_BPS_FAULT_ESTOP_3 = 15, - BPS_STATUS_BPS_FAULT_ESTOP_2 = 14, - BPS_STATUS_BPS_FAULT_ESTOP_1 = 13, - BPS_STATUS_BPS_FAULT_ARRAY_PCHG_CONTACTOR_SENSE = 12, - BPS_STATUS_BPS_FAULT_ARRAY_CONTACTOR_SENSE = 11, - BPS_STATUS_BPS_FAULT_HV_MINUS_CONTACTOR_SENSE = 10, - BPS_STATUS_BPS_FAULT_HV_PLUS_CONTACTOR_SENSE = 9, - BPS_STATUS_BPS_FAULT_SEGMENT_WATCHDOG = 8, - BPS_STATUS_BPS_FAULT_INTERNAL_WATCHDOG = 7, - BPS_STATUS_BPS_FAULT_ARRAY_PRECHARGE_TIMEOUT = 6, - BPS_STATUS_BPS_FAULT_ELCON = 5, - BPS_STATUS_BPS_FAULT_OVERTEMPERATURE = 4, - BPS_STATUS_BPS_FAULT_REGEN = 3, - BPS_STATUS_BPS_FAULT_UNDERVOLTAGE = 2, - BPS_STATUS_BPS_FAULT_OVERVOLTAGE = 1, BPS_STATUS_BPS_FAULT_OK = 0, + BPS_STATUS_BPS_FAULT_OVERVOLTAGE = 1, + BPS_STATUS_BPS_FAULT_UNDERVOLTAGE = 2, + BPS_STATUS_BPS_FAULT_REGEN = 3, + BPS_STATUS_BPS_FAULT_OVERTEMPERATURE = 4, + BPS_STATUS_BPS_FAULT_ELCON = 5, + BPS_STATUS_BPS_FAULT_ARRAY_PRECHARGE_TIMEOUT = 6, + BPS_STATUS_BPS_FAULT_INTERNAL_WATCHDOG = 7, + BPS_STATUS_BPS_FAULT_SEGMENT_WATCHDOG = 8, + BPS_STATUS_BPS_FAULT_HV_PLUS_CONTACTOR_SENSE = 9, + BPS_STATUS_BPS_FAULT_HV_MINUS_CONTACTOR_SENSE = 10, + BPS_STATUS_BPS_FAULT_ARRAY_CONTACTOR_SENSE = 11, + BPS_STATUS_BPS_FAULT_ARRAY_PCHG_CONTACTOR_SENSE = 12, + BPS_STATUS_BPS_FAULT_ESTOP_1 = 13, + BPS_STATUS_BPS_FAULT_ESTOP_2 = 14, + BPS_STATUS_BPS_FAULT_ESTOP_3 = 15, + BPS_STATUS_BPS_FAULT_CHARGING_OVERCURRENT = 16, + BPS_STATUS_BPS_FAULT_DISCHARGING_OVERCURRENT = 17, BPS_STATUS_BPS_FAULT_AMPERES_WATCHDOG = 18, } bps_status_bps_fault_e; typedef enum { - BPS_STATUS_BPS_CHARGE_OK_OK = 1, BPS_STATUS_BPS_CHARGE_OK_NOT_OK = 0, + BPS_STATUS_BPS_CHARGE_OK_OK = 1, } bps_status_bps_charge_ok_e; typedef enum { - BPS_STATUS_BPS_REGEN_OK_OK = 1, BPS_STATUS_BPS_REGEN_OK_NOT_OK = 0, + BPS_STATUS_BPS_REGEN_OK_OK = 1, } bps_status_bps_regen_ok_e; typedef enum { - BPS_STATUS_HV_PLUS_CONTACTOR_STATE_CLOSED = 1, BPS_STATUS_HV_PLUS_CONTACTOR_STATE_OPEN = 0, + BPS_STATUS_HV_PLUS_CONTACTOR_STATE_CLOSED = 1, } bps_status_hv_plus_contactor_state_e; typedef enum { - BPS_STATUS_HV_MINUS_CONTACTOR_STATE_CLOSED = 1, BPS_STATUS_HV_MINUS_CONTACTOR_STATE_OPEN = 0, + BPS_STATUS_HV_MINUS_CONTACTOR_STATE_CLOSED = 1, } bps_status_hv_minus_contactor_state_e; typedef enum { - BPS_STATUS_ARRAY_CONTACTOR_STATE_CLOSED = 1, BPS_STATUS_ARRAY_CONTACTOR_STATE_OPEN = 0, + BPS_STATUS_ARRAY_CONTACTOR_STATE_CLOSED = 1, } bps_status_array_contactor_state_e; typedef enum { - BPS_STATUS_ARRAY_PRECHARGE_CONTACTOR_STATE_CLOSED = 1, BPS_STATUS_ARRAY_PRECHARGE_CONTACTOR_STATE_OPEN = 0, + BPS_STATUS_ARRAY_PRECHARGE_CONTACTOR_STATE_CLOSED = 1, } bps_status_array_precharge_contactor_state_e; typedef enum { - BPS_STATUS_BPS_SEGMENT0_STATUS_FAULT = 1, BPS_STATUS_BPS_SEGMENT0_STATUS_OK = 0, + BPS_STATUS_BPS_SEGMENT0_STATUS_FAULT = 1, } bps_status_bps_segment0_status_e; typedef enum { - BPS_STATUS_BPS_SEGMENT1_STATUS_FAULT = 1, BPS_STATUS_BPS_SEGMENT1_STATUS_OK = 0, + BPS_STATUS_BPS_SEGMENT1_STATUS_FAULT = 1, } bps_status_bps_segment1_status_e; typedef enum { - BPS_STATUS_BPS_SEGMENT2_STATUS_FAULT = 1, BPS_STATUS_BPS_SEGMENT2_STATUS_OK = 0, + BPS_STATUS_BPS_SEGMENT2_STATUS_FAULT = 1, } bps_status_bps_segment2_status_e; typedef enum { - BPS_STATUS_BPS_SEGMENT3_STATUS_FAULT = 1, BPS_STATUS_BPS_SEGMENT3_STATUS_OK = 0, + BPS_STATUS_BPS_SEGMENT3_STATUS_FAULT = 1, } bps_status_bps_segment3_status_e; typedef enum { - BPS_STATUS_BPS_SEGMENT4_STATUS_FAULT = 1, BPS_STATUS_BPS_SEGMENT4_STATUS_OK = 0, + BPS_STATUS_BPS_SEGMENT4_STATUS_FAULT = 1, } bps_status_bps_segment4_status_e; typedef enum { - BPS_STATUS_BPS_SEGMENT5_STATUS_FAULT = 1, BPS_STATUS_BPS_SEGMENT5_STATUS_OK = 0, + BPS_STATUS_BPS_SEGMENT5_STATUS_FAULT = 1, } bps_status_bps_segment5_status_e; typedef enum { - BPS_STATUS_BPS_SEGMENT6_STATUS_FAULT = 1, BPS_STATUS_BPS_SEGMENT6_STATUS_OK = 0, + BPS_STATUS_BPS_SEGMENT6_STATUS_FAULT = 1, } bps_status_bps_segment6_status_e; typedef enum { - BPS_STATUS_BPS_SEGMENT7_STATUS_FAULT = 1, BPS_STATUS_BPS_SEGMENT7_STATUS_OK = 0, + BPS_STATUS_BPS_SEGMENT7_STATUS_FAULT = 1, } bps_status_bps_segment7_status_e; typedef enum { - BPS_VOLTAGE_AGGREGATE_ARR_BPS_TAP_MSG_WDOG_OK = 1, - BPS_VOLTAGE_AGGREGATE_ARR_BPS_TAP_MSG_WDOG_NOT_OK = 0, -} bps_voltage_aggregate_arr_bps_tap_msg_wdog_e; - -typedef enum { - BPS_VOLTAGE_AGGREGATE_ARR_BPS_VOLTAGE_TAP_FAULT_UNDER_VOLTAGE = 3, - BPS_VOLTAGE_AGGREGATE_ARR_BPS_VOLTAGE_TAP_FAULT_OVER_VOLTAGE = 2, - BPS_VOLTAGE_AGGREGATE_ARR_BPS_VOLTAGE_TAP_FAULT_BQ_I2C_READ_ERROR = 1, BPS_VOLTAGE_AGGREGATE_ARR_BPS_VOLTAGE_TAP_FAULT_OK = 0, + BPS_VOLTAGE_AGGREGATE_ARR_BPS_VOLTAGE_TAP_FAULT_BQ_I2C_READ_ERROR = 1, + BPS_VOLTAGE_AGGREGATE_ARR_BPS_VOLTAGE_TAP_FAULT_OUT_OF_BOUNDS = 2, + BPS_VOLTAGE_AGGREGATE_ARR_BPS_VOLTAGE_TAP_FAULT_OVER_VOLTAGE = 3, + BPS_VOLTAGE_AGGREGATE_ARR_BPS_VOLTAGE_TAP_FAULT_UNDER_VOLTAGE = 4, + BPS_VOLTAGE_AGGREGATE_ARR_BPS_VOLTAGE_TAP_FAULT_MESSAGE_WATCHDOG = 5, } bps_voltage_aggregate_arr_bps_voltage_tap_fault_e; typedef enum { - BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_UNDER_TEMPERATURE = 7, - BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_UNDER_TEMPERATURE = 6, - BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_OVER_TEMPERATURE = 5, - BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_OVER_TEMPERATURE = 4, - BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_DISCONNECTED = 3, - BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_SHORT_TO_VCC = 2, - BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_SHORT_TO_GND = 1, BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_OK = 0, + BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_GND_ = 1, + BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_OUT_OF_BOUNDS_SHORT_TO_VCC_ = 2, + BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_DISCONNECTED = 3, + BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_OVER_TEMPERATURE = 4, + BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_OVER_TEMPERATURE = 5, + BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_UNDER_TEMPERATURE = 6, + BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_CHARGE_UNDER_TEMPERATURE = 7, + BPS_TEMPERATURE_AGGREGATE_ARR_BPS_TEMPERATURE_TAP_FAULT_MESSAGE_WATCHDOG = 8, } bps_temperature_aggregate_arr_bps_temperature_tap_fault_e; typedef enum { - BPS_TEMP_RAWV_AGGREGATE_ARR_BPS_TAP_MSG_WDOG_OK = 1, - BPS_TEMP_RAWV_AGGREGATE_ARR_BPS_TAP_MSG_WDOG_NOT_OK = 0, -} bps_temp_rawv_aggregate_arr_bps_tap_msg_wdog_e; + CHARGERINTERFACE_STATUS_ELCON_WATCHDOG_NOT_OK = 0, + CHARGERINTERFACE_STATUS_ELCON_WATCHDOG_OK = 1, +} chargerinterface_status_elcon_watchdog_e; typedef enum { - VCU_STATUS_VCU_FAULT_MOTOR_HV_UNDERVOLTAGE = 6, - VCU_STATUS_VCU_FAULT_MOTOR_HV_OVERVOLTAGE = 5, - VCU_STATUS_VCU_FAULT_MOTOR_CONTROLLER_FAULT = 4, - VCU_STATUS_VCU_FAULT_MOTOR_PRECHARGE_TIMEOUT = 3, - VCU_STATUS_VCU_FAULT_MOTOR_PCHG_CONTACTOR_SENSE = 2, - VCU_STATUS_VCU_FAULT_MOTOR_CONTACTOR_SENSE = 1, - VCU_STATUS_VCU_FAULT_NO_FAULT = 0, -} vcu_status_vcu_fault_e; + CHARGERINTERFACE_STATUS_ELCON_CMD_TIMEOUT_NOT_OK = 0, + CHARGERINTERFACE_STATUS_ELCON_CMD_TIMEOUT_OK = 1, +} chargerinterface_status_elcon_cmd_timeout_e; typedef enum { - VCU_STATUS_MOTOR_CONTACTOR_STATE_CLOSED = 1, - VCU_STATUS_MOTOR_CONTACTOR_STATE_OPEN = 0, -} vcu_status_motor_contactor_state_e; + CHARGERINTERFACE_STATUS_ELCON_START_STATE_NOT_OK = 0, + CHARGERINTERFACE_STATUS_ELCON_START_STATE_OK = 1, +} chargerinterface_status_elcon_start_state_e; typedef enum { - VCU_STATUS_MOTOR_PRECHARGE_CONTACTOR_STATE_CLOSED = 1, - VCU_STATUS_MOTOR_PRECHARGE_CONTACTOR_STATE_OPEN = 0, -} vcu_status_motor_precharge_contactor_state_e; + CHARGERINTERFACE_STATUS_ELCON_INPUT_VOL_ERROR_OK = 0, + CHARGERINTERFACE_STATUS_ELCON_INPUT_VOL_ERROR_FAULT = 1, +} chargerinterface_status_elcon_input_vol_error_e; + +typedef enum { + CHARGERINTERFACE_STATUS_ELCON_OVER_TEMPERATURE_OK = 0, + CHARGERINTERFACE_STATUS_ELCON_OVER_TEMPERATURE_FAULT = 1, +} chargerinterface_status_elcon_over_temperature_e; + +typedef enum { + CHARGERINTERFACE_STATUS_ELCON_HW_FAULT_OK = 0, + CHARGERINTERFACE_STATUS_ELCON_HW_FAULT_FAULT = 1, +} chargerinterface_status_elcon_hw_fault_e; + +typedef enum { + VCU_STATUS_VCU_FSM_STATE_INIT = 0, + VCU_STATUS_VCU_FSM_STATE_FORWARD_DRIVE = 1, + VCU_STATUS_VCU_FSM_STATE_NEUTRAL_DRIVE = 2, + VCU_STATUS_VCU_FSM_STATE_REVERSE_DRIVE = 3, + VCU_STATUS_VCU_FSM_STATE_REGEN = 4, + VCU_STATUS_VCU_FSM_STATE_CRUISE_CONTROL = 5, + VCU_STATUS_VCU_FSM_STATE_DISABLED = 6, + VCU_STATUS_VCU_FSM_STATE_VEHICLE_NOT_READY = 7, +} vcu_status_vcu_fsm_state_e; typedef enum { - VCU_STATUS_MOTOR_READY_OK = 1, VCU_STATUS_MOTOR_READY_NOT_OK = 0, + VCU_STATUS_MOTOR_READY_OK = 1, } vcu_status_motor_ready_e; typedef enum { - VCU_STATUS_VCU_DRIVER_INPUT_OK_OK = 1, - VCU_STATUS_VCU_DRIVER_INPUT_OK_NOT_OK = 0, -} vcu_status_vcu_driver_input_ok_e; + VCU_STATUS_MOTOR_PRECHARGE_CONTACTOR_STATE_OPEN = 0, + VCU_STATUS_MOTOR_PRECHARGE_CONTACTOR_STATE_CLOSED = 1, +} vcu_status_motor_precharge_contactor_state_e; typedef enum { - VCU_STATUS_VCU_PEDALS_OK_OK = 1, - VCU_STATUS_VCU_PEDALS_OK_NOT_OK = 0, -} vcu_status_vcu_pedals_ok_e; + VCU_STATUS_MOTOR_CONTACTOR_STATE_OPEN = 0, + VCU_STATUS_MOTOR_CONTACTOR_STATE_CLOSED = 1, +} vcu_status_motor_contactor_state_e; typedef enum { - VCU_STATUS_VCU_REGEN_OK_OK = 1, - VCU_STATUS_VCU_REGEN_OK_NOT_OK = 0, -} vcu_status_vcu_regen_ok_e; + VCU_STATUS_VCU_DRIVER_INPUT_WATCHDOG_NOT_OK = 0, + VCU_STATUS_VCU_DRIVER_INPUT_WATCHDOG_OK = 1, +} vcu_status_vcu_driver_input_watchdog_e; + +typedef enum { + VCU_STATUS_VCU_PEDALS_WATCHDOG_NOT_OK = 0, + VCU_STATUS_VCU_PEDALS_WATCHDOG_OK = 1, +} vcu_status_vcu_pedals_watchdog_e; + +typedef enum { + VCU_STATUS_VCU_BPS_WATCHDOG_NOT_OK = 0, + VCU_STATUS_VCU_BPS_WATCHDOG_OK = 1, +} vcu_status_vcu_bps_watchdog_e; + +typedef enum { + VCU_STATUS_VCU_STEERING_ANGLE_WATCHDOG_NOT_OK = 0, + VCU_STATUS_VCU_STEERING_ANGLE_WATCHDOG_OK = 1, +} vcu_status_vcu_steering_angle_watchdog_e; + +typedef enum { + VCU_STATUS_VCU_BPS_FAULT_DETECTED_OK = 0, + VCU_STATUS_VCU_BPS_FAULT_DETECTED_FAULT = 1, +} vcu_status_vcu_bps_fault_detected_e; + +typedef enum { + VCU_STATUS_VCU_CONTROLS_FAULT_DETECTED_OK = 0, + VCU_STATUS_VCU_CONTROLS_FAULT_DETECTED_FAULT = 1, +} vcu_status_vcu_controls_fault_detected_e; + +typedef enum { + VCU_STATUS_VCU_MTR_FAULT_DETECTED_OK = 0, + VCU_STATUS_VCU_MTR_FAULT_DETECTED_FAULT = 1, +} vcu_status_vcu_mtr_fault_detected_e; + +typedef enum { + VCU_STATUS_VCU_PEDALS_FAULT_DETECTED_OK = 0, + VCU_STATUS_VCU_PEDALS_FAULT_DETECTED_FAULT = 1, +} vcu_status_vcu_pedals_fault_detected_e; + +typedef enum { + VCU_STATUS_VCU_STEERING_FAULT_DETECTED_OK = 0, + VCU_STATUS_VCU_STEERING_FAULT_DETECTED_FAULT = 1, +} vcu_status_vcu_steering_fault_detected_e; + +typedef enum { + VCU_STATUS_VCU_MOTORCOMMANDSOURCE_VCU = 0, + VCU_STATUS_VCU_MOTORCOMMANDSOURCE_TRITIUM_EXTERNAL = 1, +} vcu_status_vcu_motorcommandsource_e; typedef enum { - VCU_STATUS_VCU_REGEN_ACTIVE_ACTIVE = 1, VCU_STATUS_VCU_REGEN_ACTIVE_INACTIVE = 0, + VCU_STATUS_VCU_REGEN_ACTIVE_ACTIVE = 1, } vcu_status_vcu_regen_active_e; typedef enum { - VCU_STATUS_VCU_STEERING_ANGLE_OK_OK = 1, - VCU_STATUS_VCU_STEERING_ANGLE_OK_NOT_OK = 0, -} vcu_status_vcu_steering_angle_ok_e; + VCU_STATUS_VCU_REGEN_OK_NOT_OK = 0, + VCU_STATUS_VCU_REGEN_OK_OK = 1, +} vcu_status_vcu_regen_ok_e; typedef enum { - VCU_STATUS_VCU_FSM_STATE_VEHICLE_NOT_READY = 7, - VCU_STATUS_VCU_FSM_STATE_DISABLED = 6, - VCU_STATUS_VCU_FSM_STATE_CRUISE_CONTROL = 5, - VCU_STATUS_VCU_FSM_STATE_REGEN = 4, - VCU_STATUS_VCU_FSM_STATE_REVERSE_DRIVE = 3, - VCU_STATUS_VCU_FSM_STATE_NEUTRAL_DRIVE = 2, - VCU_STATUS_VCU_FSM_STATE_FORWARD_DRIVE = 1, - VCU_STATUS_VCU_FSM_STATE_INIT = 0, -} vcu_status_vcu_fsm_state_e; + VCU_STATUS_VCU_MTR_PCHG_TIMEOUT_OK = 0, + VCU_STATUS_VCU_MTR_PCHG_TIMEOUT_FAULT = 1, +} vcu_status_vcu_mtr_pchg_timeout_e; typedef enum { - VCU_STATUS_VCU_FSM_IN_PCHG_OK_FALSE = 0, - VCU_STATUS_VCU_FSM_IN_PCHG_OK_TRUE = 1, -} vcu_status_vcu_fsm_in_pchg_ok_e; + VCU_STATUS_VCU_MTR_PCHG_CONT_TIMEOUT_OK = 0, + VCU_STATUS_VCU_MTR_PCHG_CONT_TIMEOUT_FAULT = 1, +} vcu_status_vcu_mtr_pchg_cont_timeout_e; typedef enum { - VCU_STATUS_VCU_FSM_IN_BRAKE_FALSE = 0, - VCU_STATUS_VCU_FSM_IN_BRAKE_TRUE = 1, -} vcu_status_vcu_fsm_in_brake_e; + VCU_STATUS_VCU_MTR_PCHG_CONT_MISMATCH_OK = 0, + VCU_STATUS_VCU_MTR_PCHG_CONT_MISMATCH_FAULT = 1, +} vcu_status_vcu_mtr_pchg_cont_mismatch_e; typedef enum { - VCU_STATUS_VCU_FSM_IN_FORWARD_FALSE = 0, - VCU_STATUS_VCU_FSM_IN_FORWARD_TRUE = 1, -} vcu_status_vcu_fsm_in_forward_e; + VCU_STATUS_VCU_MTR_CONT_MISMATCH_OK = 0, + VCU_STATUS_VCU_MTR_CONT_MISMATCH_FAULT = 1, +} vcu_status_vcu_mtr_cont_mismatch_e; typedef enum { - VCU_STATUS_VCU_FSM_IN_NEUTRAL_FALSE = 0, - VCU_STATUS_VCU_FSM_IN_NEUTRAL_TRUE = 1, -} vcu_status_vcu_fsm_in_neutral_e; + VCU_STATUS_VCU_MTR_CONT_TIMEOUT_OK = 0, + VCU_STATUS_VCU_MTR_CONT_TIMEOUT_FAULT = 1, +} vcu_status_vcu_mtr_cont_timeout_e; typedef enum { - VCU_STATUS_VCU_FSM_IN_REVERSE_FALSE = 0, - VCU_STATUS_VCU_FSM_IN_REVERSE_TRUE = 1, -} vcu_status_vcu_fsm_in_reverse_e; + VCU_STATUS_VCU_PCHG_OV_OK = 0, + VCU_STATUS_VCU_PCHG_OV_FAULT = 1, +} vcu_status_vcu_pchg_ov_e; typedef enum { - VCU_STATUS_VCU_FSM_IN_REGEN_RDY_FALSE = 0, - VCU_STATUS_VCU_FSM_IN_REGEN_RDY_TRUE = 1, -} vcu_status_vcu_fsm_in_regen_rdy_e; + VCU_STATUS_VCU_PCHG_UV_OK = 0, + VCU_STATUS_VCU_PCHG_UV_FAULT = 1, +} vcu_status_vcu_pchg_uv_e; typedef enum { - VCU_STATUS_VCU_FSM_IN_REGEN_ENABLE_FALSE = 0, - VCU_STATUS_VCU_FSM_IN_REGEN_ENABLE_TRUE = 1, -} vcu_status_vcu_fsm_in_regen_enable_e; + VCU_STATUS_VCU_MTR_OV_OK = 0, + VCU_STATUS_VCU_MTR_OV_FAULT = 1, +} vcu_status_vcu_mtr_ov_e; typedef enum { - VCU_STATUS_VCU_FSM_IN_CRUISE_REQ_FALSE = 0, - VCU_STATUS_VCU_FSM_IN_CRUISE_REQ_TRUE = 1, -} vcu_status_vcu_fsm_in_cruise_req_e; + VCU_STATUS_VCU_MTR_UV_OK = 0, + VCU_STATUS_VCU_MTR_UV_FAULT = 1, +} vcu_status_vcu_mtr_uv_e; typedef enum { - VCU_STATUS_VCU_FSM_IN_REGEN_REQ_FALSE = 0, - VCU_STATUS_VCU_FSM_IN_REGEN_REQ_TRUE = 1, -} vcu_status_vcu_fsm_in_regen_req_e; + VCU_STATUS_VCU_OTHER_FAULT_OK = 0, + VCU_STATUS_VCU_OTHER_FAULT_FAULT = 1, +} vcu_status_vcu_other_fault_e; + +typedef enum { + VCU_STATUS_VCU_MTR_DIR_CHANGE_LOCKOUT_INACTIVE = 0, + VCU_STATUS_VCU_MTR_DIR_CHANGE_LOCKOUT_ACTIVE = 1, +} vcu_status_vcu_mtr_dir_change_lockout_e; + +typedef enum { + VCU_STATUS_VCU_TIPPING_WARNING_INACTIVE = 0, + VCU_STATUS_VCU_TIPPING_WARNING_ACTIVE = 1, +} vcu_status_vcu_tipping_warning_e; + +typedef enum { + VCU_STATUS_VCU_WARN_REGEN_NOT_ALLOW_INACTIVE = 0, + VCU_STATUS_VCU_WARN_REGEN_NOT_ALLOW_ACTIVE = 1, +} vcu_status_vcu_warn_regen_not_allow_e; + +typedef enum { + VCU_STATUS_VCU_WARN_REGEN_NOT_EN_INACTIVE = 0, + VCU_STATUS_VCU_WARN_REGEN_NOT_EN_ACTIVE = 1, +} vcu_status_vcu_warn_regen_not_en_e; + +typedef enum { + VCU_STATUS_VCU_FSM_INP_BRAKE_FALSE = 0, + VCU_STATUS_VCU_FSM_INP_BRAKE_TRUE = 1, +} vcu_status_vcu_fsm_inp_brake_e; + +typedef enum { + VCU_STATUS_VCU_FSM_INP_PCHG_OK_FALSE = 0, + VCU_STATUS_VCU_FSM_INP_PCHG_OK_TRUE = 1, +} vcu_status_vcu_fsm_inp_pchg_ok_e; + +typedef enum { + VCU_STATUS_VCU_FSM_INP_CRUISE_REQ_FALSE = 0, + VCU_STATUS_VCU_FSM_INP_CRUISE_REQ_TRUE = 1, +} vcu_status_vcu_fsm_inp_cruise_req_e; + +typedef enum { + VCU_STATUS_VCU_FSM_INP_REGEN_REQ_FALSE = 0, + VCU_STATUS_VCU_FSM_INP_REGEN_REQ_TRUE = 1, +} vcu_status_vcu_fsm_inp_regen_req_e; + +typedef enum { + VCU_STATUS_VCU_FSM_INP_REGEN_ENABLE_FALSE = 0, + VCU_STATUS_VCU_FSM_INP_REGEN_ENABLE_TRUE = 1, +} vcu_status_vcu_fsm_inp_regen_enable_e; + +typedef enum { + VCU_STATUS_VCU_FSM_INP_REGEN_RDY_FALSE = 0, + VCU_STATUS_VCU_FSM_INP_REGEN_RDY_TRUE = 1, +} vcu_status_vcu_fsm_inp_regen_rdy_e; + +typedef enum { + VCU_STATUS_VCU_FSM_INP_FORWARD_FALSE = 0, + VCU_STATUS_VCU_FSM_INP_FORWARD_TRUE = 1, +} vcu_status_vcu_fsm_inp_forward_e; + +typedef enum { + VCU_STATUS_VCU_FSM_INP_NEUTRAL_FALSE = 0, + VCU_STATUS_VCU_FSM_INP_NEUTRAL_TRUE = 1, +} vcu_status_vcu_fsm_inp_neutral_e; + +typedef enum { + VCU_STATUS_VCU_FSM_INP_REVERSE_FALSE = 0, + VCU_STATUS_VCU_FSM_INP_REVERSE_TRUE = 1, +} vcu_status_vcu_fsm_inp_reverse_e; typedef enum { - CONTROLS_STATUS_CONTROLS_LEADER_FAULT_LIGHTING_FAULT = 4, - CONTROLS_STATUS_CONTROLS_LEADER_FAULT_INVALID_DRIVER_INPUTS = 3, - CONTROLS_STATUS_CONTROLS_LEADER_FAULT_BPS_WATCHDOG = 2, - CONTROLS_STATUS_CONTROLS_LEADER_FAULT_BOSCH_LWS_WATCHDOG = 1, CONTROLS_STATUS_CONTROLS_LEADER_FAULT_OK = 0, + CONTROLS_STATUS_CONTROLS_LEADER_FAULT_BOSCH_LWS_WATCHDOG = 1, + CONTROLS_STATUS_CONTROLS_LEADER_FAULT_BPS_WATCHDOG = 2, + CONTROLS_STATUS_CONTROLS_LEADER_FAULT_INVALID_DRIVER_INPUTS = 3, + CONTROLS_STATUS_CONTROLS_LEADER_FAULT_LIGHTING_BOARD_FAULT = 4, + CONTROLS_STATUS_CONTROLS_LEADER_FAULT_LIGHTING_BOARD_WATCHDOG = 5, } controls_status_controls_leader_fault_e; typedef enum { - PEDAL_STATUS_ACCELPEDAL_MAIN_FAULT_FAULT = 1, + CONTROLS_STATUS_LIGHTINGBOARD_FRONT_STATUS_OK = 0, + CONTROLS_STATUS_LIGHTINGBOARD_FRONT_STATUS_ADDR_LED_UNDERCURRENT = 1, + CONTROLS_STATUS_LIGHTINGBOARD_FRONT_STATUS_LED0_UNDERCURRENT = 2, + CONTROLS_STATUS_LIGHTINGBOARD_FRONT_STATUS_LED1_UNDERCURRENT = 3, + CONTROLS_STATUS_LIGHTINGBOARD_FRONT_STATUS_ADDR_LED_OVERCURRENT = 4, + CONTROLS_STATUS_LIGHTINGBOARD_FRONT_STATUS_LED0_OVERCURRENT = 5, + CONTROLS_STATUS_LIGHTINGBOARD_FRONT_STATUS_LED1_OVERCURRENT = 6, + CONTROLS_STATUS_LIGHTINGBOARD_FRONT_STATUS_LIGHT_COMMAND_WATCHDOG = 7, + CONTROLS_STATUS_LIGHTINGBOARD_FRONT_STATUS_WATCHDOG = 8, +} controls_status_lightingboard_front_status_e; + +typedef enum { + CONTROLS_STATUS_LIGHTINGBOARD_LEFT_STATUS_OK = 0, + CONTROLS_STATUS_LIGHTINGBOARD_LEFT_STATUS_ADDR_LED_UNDERCURRENT = 1, + CONTROLS_STATUS_LIGHTINGBOARD_LEFT_STATUS_LED0_UNDERCURRENT = 2, + CONTROLS_STATUS_LIGHTINGBOARD_LEFT_STATUS_LED1_UNDERCURRENT = 3, + CONTROLS_STATUS_LIGHTINGBOARD_LEFT_STATUS_ADDR_LED_OVERCURRENT = 4, + CONTROLS_STATUS_LIGHTINGBOARD_LEFT_STATUS_LED0_OVERCURRENT = 5, + CONTROLS_STATUS_LIGHTINGBOARD_LEFT_STATUS_LED1_OVERCURRENT = 6, + CONTROLS_STATUS_LIGHTINGBOARD_LEFT_STATUS_LIGHT_COMMAND_WATCHDOG = 7, + CONTROLS_STATUS_LIGHTINGBOARD_LEFT_STATUS_WATCHDOG = 8, +} controls_status_lightingboard_left_status_e; + +typedef enum { + CONTROLS_STATUS_LIGHTINGBOARD_RIGHT_STATUS_OK = 0, + CONTROLS_STATUS_LIGHTINGBOARD_RIGHT_STATUS_ADDR_LED_UNDERCURRENT = 1, + CONTROLS_STATUS_LIGHTINGBOARD_RIGHT_STATUS_LED0_UNDERCURRENT = 2, + CONTROLS_STATUS_LIGHTINGBOARD_RIGHT_STATUS_LED1_UNDERCURRENT = 3, + CONTROLS_STATUS_LIGHTINGBOARD_RIGHT_STATUS_ADDR_LED_OVERCURRENT = 4, + CONTROLS_STATUS_LIGHTINGBOARD_RIGHT_STATUS_LED0_OVERCURRENT = 5, + CONTROLS_STATUS_LIGHTINGBOARD_RIGHT_STATUS_LED1_OVERCURRENT = 6, + CONTROLS_STATUS_LIGHTINGBOARD_RIGHT_STATUS_LIGHT_COMMAND_WATCHDOG = 7, + CONTROLS_STATUS_LIGHTINGBOARD_RIGHT_STATUS_WATCHDOG = 8, +} controls_status_lightingboard_right_status_e; + +typedef enum { + CONTROLS_STATUS_LIGHTINGBOARD_REAR_STATUS_OK = 0, + CONTROLS_STATUS_LIGHTINGBOARD_REAR_STATUS_ADDR_LED_UNDERCURRENT = 1, + CONTROLS_STATUS_LIGHTINGBOARD_REAR_STATUS_LED0_UNDERCURRENT = 2, + CONTROLS_STATUS_LIGHTINGBOARD_REAR_STATUS_LED1_UNDERCURRENT = 3, + CONTROLS_STATUS_LIGHTINGBOARD_REAR_STATUS_ADDR_LED_OVERCURRENT = 4, + CONTROLS_STATUS_LIGHTINGBOARD_REAR_STATUS_LED0_OVERCURRENT = 5, + CONTROLS_STATUS_LIGHTINGBOARD_REAR_STATUS_LED1_OVERCURRENT = 6, + CONTROLS_STATUS_LIGHTINGBOARD_REAR_STATUS_LIGHT_COMMAND_WATCHDOG = 7, + CONTROLS_STATUS_LIGHTINGBOARD_REAR_STATUS_WATCHDOG = 8, +} controls_status_lightingboard_rear_status_e; + +typedef enum { + CONTROLS_STATUS_LIGHTINGBOARD_CANOPY_STATUS_OK = 0, + CONTROLS_STATUS_LIGHTINGBOARD_CANOPY_STATUS_ADDR_LED_UNDERCURRENT = 1, + CONTROLS_STATUS_LIGHTINGBOARD_CANOPY_STATUS_LED0_UNDERCURRENT = 2, + CONTROLS_STATUS_LIGHTINGBOARD_CANOPY_STATUS_LED1_UNDERCURRENT = 3, + CONTROLS_STATUS_LIGHTINGBOARD_CANOPY_STATUS_ADDR_LED_OVERCURRENT = 4, + CONTROLS_STATUS_LIGHTINGBOARD_CANOPY_STATUS_LED0_OVERCURRENT = 5, + CONTROLS_STATUS_LIGHTINGBOARD_CANOPY_STATUS_LED1_OVERCURRENT = 6, + CONTROLS_STATUS_LIGHTINGBOARD_CANOPY_STATUS_LIGHT_COMMAND_WATCHDOG = 7, + CONTROLS_STATUS_LIGHTINGBOARD_CANOPY_STATUS_WATCHDOG = 8, +} controls_status_lightingboard_canopy_status_e; + +typedef enum { PEDAL_STATUS_ACCELPEDAL_MAIN_FAULT_OK = 0, + PEDAL_STATUS_ACCELPEDAL_MAIN_FAULT_FAULT = 1, } pedal_status_accelpedal_main_fault_e; typedef enum { - PEDAL_STATUS_ACCELPEDAL_REDUNDANT_FAULT_FAULT = 1, PEDAL_STATUS_ACCELPEDAL_REDUNDANT_FAULT_OK = 0, + PEDAL_STATUS_ACCELPEDAL_REDUNDANT_FAULT_FAULT = 1, } pedal_status_accelpedal_redundant_fault_e; typedef enum { - PEDAL_STATUS_BRAKEPEDAL_MAIN_FAULT_FAULT = 1, PEDAL_STATUS_BRAKEPEDAL_MAIN_FAULT_OK = 0, + PEDAL_STATUS_BRAKEPEDAL_MAIN_FAULT_FAULT = 1, } pedal_status_brakepedal_main_fault_e; typedef enum { - PEDAL_STATUS_BRAKEPEDAL_REDUNDANT_FAULT_FAULT = 1, PEDAL_STATUS_BRAKEPEDAL_REDUNDANT_FAULT_OK = 0, + PEDAL_STATUS_BRAKEPEDAL_REDUNDANT_FAULT_FAULT = 1, } pedal_status_brakepedal_redundant_fault_e; typedef enum { - DRIVER_INPUT_STATUS_IGNITION_ARRAY_SELECTED = 1, + PEDAL_STATUS_BRAKE_PRESSURE_1_FAULT_OK = 0, + PEDAL_STATUS_BRAKE_PRESSURE_1_FAULT_FAULT = 1, +} pedal_status_brake_pressure_1_fault_e; + +typedef enum { + PEDAL_STATUS_BRAKE_PRESSURE_2_FAULT_OK = 0, + PEDAL_STATUS_BRAKE_PRESSURE_2_FAULT_FAULT = 1, +} pedal_status_brake_pressure_2_fault_e; + +typedef enum { DRIVER_INPUT_STATUS_IGNITION_ARRAY__ = 0, + DRIVER_INPUT_STATUS_IGNITION_ARRAY_SELECTED = 1, } driver_input_status_ignition_array_e; typedef enum { - DRIVER_INPUT_STATUS_IGNITION_MOTOR_SELECTED = 1, DRIVER_INPUT_STATUS_IGNITION_MOTOR__ = 0, + DRIVER_INPUT_STATUS_IGNITION_MOTOR_SELECTED = 1, } driver_input_status_ignition_motor_e; typedef enum { - DRIVER_INPUT_STATUS_IGNITION_OFF_SELECTED = 1, DRIVER_INPUT_STATUS_IGNITION_OFF__ = 0, + DRIVER_INPUT_STATUS_IGNITION_OFF_SELECTED = 1, } driver_input_status_ignition_off_e; typedef enum { - DRIVER_INPUT_STATUS_CRUISE_ENABLE_ENABLED = 1, DRIVER_INPUT_STATUS_CRUISE_ENABLE_DISABLED = 0, + DRIVER_INPUT_STATUS_CRUISE_ENABLE_ENABLED = 1, } driver_input_status_cruise_enable_e; typedef enum { - DRIVER_INPUT_STATUS_CRUISE_SET_PRESSED = 1, DRIVER_INPUT_STATUS_CRUISE_SET__ = 0, + DRIVER_INPUT_STATUS_CRUISE_SET_PRESSED = 1, } driver_input_status_cruise_set_e; typedef enum { - DRIVER_INPUT_STATUS_GEAR_FORWARD_SELECTED = 1, DRIVER_INPUT_STATUS_GEAR_FORWARD__ = 0, + DRIVER_INPUT_STATUS_GEAR_FORWARD_SELECTED = 1, } driver_input_status_gear_forward_e; typedef enum { - DRIVER_INPUT_STATUS_GEAR_NEUTRAL_SELECTED = 1, DRIVER_INPUT_STATUS_GEAR_NEUTRAL__ = 0, + DRIVER_INPUT_STATUS_GEAR_NEUTRAL_SELECTED = 1, } driver_input_status_gear_neutral_e; typedef enum { - DRIVER_INPUT_STATUS_GEAR_REVERSE_SELECTED = 1, DRIVER_INPUT_STATUS_GEAR_REVERSE__ = 0, + DRIVER_INPUT_STATUS_GEAR_REVERSE_SELECTED = 1, } driver_input_status_gear_reverse_e; typedef enum { - DRIVER_INPUT_STATUS_HAZARD_PRESSED_ON = 1, DRIVER_INPUT_STATUS_HAZARD_PRESSED_OFF = 0, + DRIVER_INPUT_STATUS_HAZARD_PRESSED_ON = 1, } driver_input_status_hazard_pressed_e; typedef enum { - DRIVER_INPUT_STATUS_HORN_PRESSED_ON = 1, DRIVER_INPUT_STATUS_HORN_PRESSED_OFF = 0, + DRIVER_INPUT_STATUS_HORN_PRESSED_ON = 1, } driver_input_status_horn_pressed_e; typedef enum { - DRIVER_INPUT_STATUS_BLINKER_LEFT_SELECTED = 1, DRIVER_INPUT_STATUS_BLINKER_LEFT__ = 0, + DRIVER_INPUT_STATUS_BLINKER_LEFT_SELECTED = 1, } driver_input_status_blinker_left_e; typedef enum { - DRIVER_INPUT_STATUS_BLINKER_RIGHT_SELECTED = 1, DRIVER_INPUT_STATUS_BLINKER_RIGHT__ = 0, + DRIVER_INPUT_STATUS_BLINKER_RIGHT_SELECTED = 1, } driver_input_status_blinker_right_e; typedef enum { - DRIVER_INPUT_STATUS_PUSHTOTALK_PRESSED_PRESSED = 1, DRIVER_INPUT_STATUS_PUSHTOTALK_PRESSED__ = 0, + DRIVER_INPUT_STATUS_PUSHTOTALK_PRESSED_PRESSED = 1, } driver_input_status_pushtotalk_pressed_e; typedef enum { - DRIVER_INPUT_STATUS_REGEN_ACTIVATE_PRESSED = 1, DRIVER_INPUT_STATUS_REGEN_ACTIVATE__ = 0, + DRIVER_INPUT_STATUS_REGEN_ACTIVATE_PRESSED = 1, } driver_input_status_regen_activate_e; typedef enum { - DRIVER_INPUT_STATUS_REGEN_ENABLE_ENABLED = 1, DRIVER_INPUT_STATUS_REGEN_ENABLE_DISABLED = 0, + DRIVER_INPUT_STATUS_REGEN_ENABLE_ENABLED = 1, } driver_input_status_regen_enable_e; typedef enum { - MPPT_A_STATUS_MPPT_MODE_FAULT = 6, - MPPT_A_STATUS_MPPT_MODE_TEMPERATURE_DE_RATING = 5, - MPPT_A_STATUS_MPPT_MODE_CONSTANT_OUTPUT_CURRENT = 4, - MPPT_A_STATUS_MPPT_MODE_CONSTANT_OUTPUT_VOLTAGE = 3, - MPPT_A_STATUS_MPPT_MODE_MINIMUM_INPUT_CURRENT = 2, - MPPT_A_STATUS_MPPT_MODE_CONSTANT_INPUT_CURRENT = 1, MPPT_A_STATUS_MPPT_MODE_CONSTANT_INPUT_VOLTAGE = 0, + MPPT_A_STATUS_MPPT_MODE_CONSTANT_INPUT_CURRENT = 1, + MPPT_A_STATUS_MPPT_MODE_MINIMUM_INPUT_CURRENT = 2, + MPPT_A_STATUS_MPPT_MODE_CONSTANT_OUTPUT_VOLTAGE = 3, + MPPT_A_STATUS_MPPT_MODE_CONSTANT_OUTPUT_CURRENT = 4, + MPPT_A_STATUS_MPPT_MODE_TEMPERATURE_DE_RATING = 5, + MPPT_A_STATUS_MPPT_MODE_FAULT = 6, } mppt_a_status_mppt_mode_e; typedef enum { - MPPT_A_STATUS_MPPT_FAULT_UNKNOWN_FAULT = 8, - MPPT_A_STATUS_MPPT_FAULT_PHASE_OVER_CURRENT = 7, - MPPT_A_STATUS_MPPT_FAULT_INPUT_UNDER_CURRENT = 6, - MPPT_A_STATUS_MPPT_FAULT_INPUT_OVER_CURRENT = 5, - MPPT_A_STATUS_MPPT_FAULT_OUTPUT_OVER_CURRENT = 4, - MPPT_A_STATUS_MPPT_FAULT_OUTPUT_OVER_VOLTAGE = 3, - MPPT_A_STATUS_MPPT_FAULT_INPUT_OVER_VOLTAGE = 2, - MPPT_A_STATUS_MPPT_FAULT_CONFIGURATION_ERROR = 1, MPPT_A_STATUS_MPPT_FAULT_OK = 0, + MPPT_A_STATUS_MPPT_FAULT_CONFIGURATION_ERROR = 1, + MPPT_A_STATUS_MPPT_FAULT_INPUT_OVER_VOLTAGE = 2, + MPPT_A_STATUS_MPPT_FAULT_OUTPUT_OVER_VOLTAGE = 3, + MPPT_A_STATUS_MPPT_FAULT_OUTPUT_OVER_CURRENT = 4, + MPPT_A_STATUS_MPPT_FAULT_INPUT_OVER_CURRENT = 5, + MPPT_A_STATUS_MPPT_FAULT_INPUT_UNDER_CURRENT = 6, + MPPT_A_STATUS_MPPT_FAULT_PHASE_OVER_CURRENT = 7, + MPPT_A_STATUS_MPPT_FAULT_UNKNOWN_FAULT = 8, } mppt_a_status_mppt_fault_e; typedef enum { - MPPT_A_STATUS_MPPT_ENABLED_ENABLED_CONSTANT_VOLTAGE = 2, - MPPT_A_STATUS_MPPT_ENABLED_ENABLED = 1, MPPT_A_STATUS_MPPT_ENABLED_DISABLED = 0, + MPPT_A_STATUS_MPPT_ENABLED_ENABLED = 1, + MPPT_A_STATUS_MPPT_ENABLED_ENABLED_CONSTANT_VOLTAGE = 2, } mppt_a_status_mppt_enabled_e; typedef enum { - MPPT_A_SETMODE_MPPT_SET_ENABLE_ENABLED_CONSTANT_VOLTAGE = 2, - MPPT_A_SETMODE_MPPT_SET_ENABLE_ENABLED = 1, MPPT_A_SETMODE_MPPT_SET_ENABLE_DISABLED = 0, + MPPT_A_SETMODE_MPPT_SET_ENABLE_ENABLED = 1, + MPPT_A_SETMODE_MPPT_SET_ENABLE_ENABLED_CONSTANT_VOLTAGE = 2, } mppt_a_setmode_mppt_set_enable_e; typedef enum { - MPPT_B_STATUS_MPPT_MODE_FAULT = 6, - MPPT_B_STATUS_MPPT_MODE_TEMPERATURE_DE_RATING = 5, - MPPT_B_STATUS_MPPT_MODE_CONSTANT_OUTPUT_CURRENT = 4, - MPPT_B_STATUS_MPPT_MODE_CONSTANT_OUTPUT_VOLTAGE = 3, - MPPT_B_STATUS_MPPT_MODE_MINIMUM_INPUT_CURRENT = 2, - MPPT_B_STATUS_MPPT_MODE_CONSTANT_INPUT_CURRENT = 1, MPPT_B_STATUS_MPPT_MODE_CONSTANT_INPUT_VOLTAGE = 0, + MPPT_B_STATUS_MPPT_MODE_CONSTANT_INPUT_CURRENT = 1, + MPPT_B_STATUS_MPPT_MODE_MINIMUM_INPUT_CURRENT = 2, + MPPT_B_STATUS_MPPT_MODE_CONSTANT_OUTPUT_VOLTAGE = 3, + MPPT_B_STATUS_MPPT_MODE_CONSTANT_OUTPUT_CURRENT = 4, + MPPT_B_STATUS_MPPT_MODE_TEMPERATURE_DE_RATING = 5, + MPPT_B_STATUS_MPPT_MODE_FAULT = 6, } mppt_b_status_mppt_mode_e; typedef enum { - MPPT_B_STATUS_MPPT_FAULT_UNKNOWN_FAULT = 8, - MPPT_B_STATUS_MPPT_FAULT_PHASE_OVER_CURRENT = 7, - MPPT_B_STATUS_MPPT_FAULT_INPUT_UNDER_CURRENT = 6, - MPPT_B_STATUS_MPPT_FAULT_INPUT_OVER_CURRENT = 5, - MPPT_B_STATUS_MPPT_FAULT_OUTPUT_OVER_CURRENT = 4, - MPPT_B_STATUS_MPPT_FAULT_OUTPUT_OVER_VOLTAGE = 3, - MPPT_B_STATUS_MPPT_FAULT_INPUT_OVER_VOLTAGE = 2, - MPPT_B_STATUS_MPPT_FAULT_CONFIGURATION_ERROR = 1, MPPT_B_STATUS_MPPT_FAULT_OK = 0, + MPPT_B_STATUS_MPPT_FAULT_CONFIGURATION_ERROR = 1, + MPPT_B_STATUS_MPPT_FAULT_INPUT_OVER_VOLTAGE = 2, + MPPT_B_STATUS_MPPT_FAULT_OUTPUT_OVER_VOLTAGE = 3, + MPPT_B_STATUS_MPPT_FAULT_OUTPUT_OVER_CURRENT = 4, + MPPT_B_STATUS_MPPT_FAULT_INPUT_OVER_CURRENT = 5, + MPPT_B_STATUS_MPPT_FAULT_INPUT_UNDER_CURRENT = 6, + MPPT_B_STATUS_MPPT_FAULT_PHASE_OVER_CURRENT = 7, + MPPT_B_STATUS_MPPT_FAULT_UNKNOWN_FAULT = 8, } mppt_b_status_mppt_fault_e; typedef enum { - MPPT_B_STATUS_MPPT_ENABLED_ENABLED_CONSTANT_VOLTAGE = 2, - MPPT_B_STATUS_MPPT_ENABLED_ENABLED = 1, MPPT_B_STATUS_MPPT_ENABLED_DISABLED = 0, + MPPT_B_STATUS_MPPT_ENABLED_ENABLED = 1, + MPPT_B_STATUS_MPPT_ENABLED_ENABLED_CONSTANT_VOLTAGE = 2, } mppt_b_status_mppt_enabled_e; typedef enum { - MPPT_B_SETMODE_MPPT_SET_ENABLE_ENABLED_CONSTANT_VOLTAGE = 2, - MPPT_B_SETMODE_MPPT_SET_ENABLE_ENABLED = 1, MPPT_B_SETMODE_MPPT_SET_ENABLE_DISABLED = 0, + MPPT_B_SETMODE_MPPT_SET_ENABLE_ENABLED = 1, + MPPT_B_SETMODE_MPPT_SET_ENABLE_ENABLED_CONSTANT_VOLTAGE = 2, } mppt_b_setmode_mppt_set_enable_e; typedef enum { - MPPT_C_STATUS_MPPT_MODE_FAULT = 6, - MPPT_C_STATUS_MPPT_MODE_TEMPERATURE_DE_RATING = 5, - MPPT_C_STATUS_MPPT_MODE_CONSTANT_OUTPUT_CURRENT = 4, - MPPT_C_STATUS_MPPT_MODE_CONSTANT_OUTPUT_VOLTAGE = 3, - MPPT_C_STATUS_MPPT_MODE_MINIMUM_INPUT_CURRENT = 2, - MPPT_C_STATUS_MPPT_MODE_CONSTANT_INPUT_CURRENT = 1, MPPT_C_STATUS_MPPT_MODE_CONSTANT_INPUT_VOLTAGE = 0, + MPPT_C_STATUS_MPPT_MODE_CONSTANT_INPUT_CURRENT = 1, + MPPT_C_STATUS_MPPT_MODE_MINIMUM_INPUT_CURRENT = 2, + MPPT_C_STATUS_MPPT_MODE_CONSTANT_OUTPUT_VOLTAGE = 3, + MPPT_C_STATUS_MPPT_MODE_CONSTANT_OUTPUT_CURRENT = 4, + MPPT_C_STATUS_MPPT_MODE_TEMPERATURE_DE_RATING = 5, + MPPT_C_STATUS_MPPT_MODE_FAULT = 6, } mppt_c_status_mppt_mode_e; typedef enum { - MPPT_C_STATUS_MPPT_FAULT_UNKNOWN_FAULT = 8, - MPPT_C_STATUS_MPPT_FAULT_PHASE_OVER_CURRENT = 7, - MPPT_C_STATUS_MPPT_FAULT_INPUT_UNDER_CURRENT = 6, - MPPT_C_STATUS_MPPT_FAULT_INPUT_OVER_CURRENT = 5, - MPPT_C_STATUS_MPPT_FAULT_OUTPUT_OVER_CURRENT = 4, - MPPT_C_STATUS_MPPT_FAULT_OUTPUT_OVER_VOLTAGE = 3, - MPPT_C_STATUS_MPPT_FAULT_INPUT_OVER_VOLTAGE = 2, - MPPT_C_STATUS_MPPT_FAULT_CONFIGURATION_ERROR = 1, MPPT_C_STATUS_MPPT_FAULT_OK = 0, + MPPT_C_STATUS_MPPT_FAULT_CONFIGURATION_ERROR = 1, + MPPT_C_STATUS_MPPT_FAULT_INPUT_OVER_VOLTAGE = 2, + MPPT_C_STATUS_MPPT_FAULT_OUTPUT_OVER_VOLTAGE = 3, + MPPT_C_STATUS_MPPT_FAULT_OUTPUT_OVER_CURRENT = 4, + MPPT_C_STATUS_MPPT_FAULT_INPUT_OVER_CURRENT = 5, + MPPT_C_STATUS_MPPT_FAULT_INPUT_UNDER_CURRENT = 6, + MPPT_C_STATUS_MPPT_FAULT_PHASE_OVER_CURRENT = 7, + MPPT_C_STATUS_MPPT_FAULT_UNKNOWN_FAULT = 8, } mppt_c_status_mppt_fault_e; typedef enum { - MPPT_C_STATUS_MPPT_ENABLED_ENABLED_CONSTANT_VOLTAGE = 2, - MPPT_C_STATUS_MPPT_ENABLED_ENABLED = 1, MPPT_C_STATUS_MPPT_ENABLED_DISABLED = 0, + MPPT_C_STATUS_MPPT_ENABLED_ENABLED = 1, + MPPT_C_STATUS_MPPT_ENABLED_ENABLED_CONSTANT_VOLTAGE = 2, } mppt_c_status_mppt_enabled_e; typedef enum { - MPPT_C_SETMODE_MPPT_SET_ENABLE_ENABLED_CONSTANT_VOLTAGE = 2, - MPPT_C_SETMODE_MPPT_SET_ENABLE_ENABLED = 1, MPPT_C_SETMODE_MPPT_SET_ENABLE_DISABLED = 0, + MPPT_C_SETMODE_MPPT_SET_ENABLE_ENABLED = 1, + MPPT_C_SETMODE_MPPT_SET_ENABLE_ENABLED_CONSTANT_VOLTAGE = 2, } mppt_c_setmode_mppt_set_enable_e; typedef enum { - SUPP_BATTERY_CHARGER_STATUS_SUPPCHARGER_STATUS_FAULT = 3, - SUPP_BATTERY_CHARGER_STATUS_SUPPCHARGER_STATUS_CHARGING_ = 2, - SUPP_BATTERY_CHARGER_STATUS_SUPPCHARGER_STATUS_CHARGE_COMPLETE = 1, - SUPP_BATTERY_CHARGER_STATUS_SUPPCHARGER_STATUS_CHARGE_DISABLED = 0, -} supp_battery_charger_status_suppcharger_status_e; + SUPP_BATTERY_STATUS_SUPPLEMENTAL_BATTERY_FAULT_OK = 0, + SUPP_BATTERY_STATUS_SUPPLEMENTAL_BATTERY_FAULT_UNDER_VOLTAGE = 1, + SUPP_BATTERY_STATUS_SUPPLEMENTAL_BATTERY_FAULT_OVER_VOLTAGE = 2, + SUPP_BATTERY_STATUS_SUPPLEMENTAL_BATTERY_FAULT_OVER_CURRENT_DISCHARGE_ = 3, + SUPP_BATTERY_STATUS_SUPPLEMENTAL_BATTERY_FAULT_OVER_CURRENT_CHARGE_ = 4, + SUPP_BATTERY_STATUS_SUPPLEMENTAL_BATTERY_FAULT_UNKNOWN_FAULT = 5, +} supp_battery_status_supplemental_battery_fault_e; + +typedef enum { + SUPP_CHARGER_STATUS_SUPPLEMENTAL_CHARGER_STATUS_CHARGE_DISABLED = 0, + SUPP_CHARGER_STATUS_SUPPLEMENTAL_CHARGER_STATUS_TRICKLE_CHARGING = 1, + SUPP_CHARGER_STATUS_SUPPLEMENTAL_CHARGER_STATUS_PRECHARGE = 2, + SUPP_CHARGER_STATUS_SUPPLEMENTAL_CHARGER_STATUS_FAST_CHARGING = 3, + SUPP_CHARGER_STATUS_SUPPLEMENTAL_CHARGER_STATUS_TAPER = 4, + SUPP_CHARGER_STATUS_SUPPLEMENTAL_CHARGER_STATUS_ERROR = 5, + SUPP_CHARGER_STATUS_SUPPLEMENTAL_CHARGER_STATUS_TOPPING_OFF = 6, + SUPP_CHARGER_STATUS_SUPPLEMENTAL_CHARGER_STATUS_DONE = 7, +} supp_charger_status_supplemental_charger_status_e; + +typedef enum { + SUPP_CHARGER_STATUS_BQ25756E_ERROR_OK = 0, + SUPP_CHARGER_STATUS_BQ25756E_ERROR_I2C_ERROR = 1, + SUPP_CHARGER_STATUS_BQ25756E_ERROR_INPUT_UV = 2, + SUPP_CHARGER_STATUS_BQ25756E_ERROR_INPUT_OV = 3, + SUPP_CHARGER_STATUS_BQ25756E_ERROR_BATTERY_OC = 4, + SUPP_CHARGER_STATUS_BQ25756E_ERROR_BATTERY_OV = 5, + SUPP_CHARGER_STATUS_BQ25756E_ERROR_OVER_TEMPERATURE = 6, +} supp_charger_status_bq25756e_error_e; + +typedef enum { + SUPP_CHARGER_STATUS_BQ25756E_WATCHDOG_NOT_OK = 0, + SUPP_CHARGER_STATUS_BQ25756E_WATCHDOG_OK = 1, +} supp_charger_status_bq25756e_watchdog_e; typedef enum { - PDU_STATUS_ARR_HSS_CHANNEL_IDX_PDE_FANS = 15, - PDU_STATUS_ARR_HSS_CHANNEL_IDX_UNASSIGNED_1 = 14, - PDU_STATUS_ARR_HSS_CHANNEL_IDX_UNASSIGNED_2 = 13, - PDU_STATUS_ARR_HSS_CHANNEL_IDX_PUMP = 12, - PDU_STATUS_ARR_HSS_CHANNEL_IDX_TELEMETRY_DATA_ACQ = 11, - PDU_STATUS_ARR_HSS_CHANNEL_IDX_MOTOR_CONTROLLER = 10, - PDU_STATUS_ARR_HSS_CHANNEL_IDX_MPPTS = 9, - PDU_STATUS_ARR_HSS_CHANNEL_IDX_BATTERY = 8, - PDU_STATUS_ARR_HSS_CHANNEL_IDX_UNASSIGNED_3 = 7, - PDU_STATUS_ARR_HSS_CHANNEL_IDX_CAMERAS = 6, - PDU_STATUS_ARR_HSS_CHANNEL_IDX_PEDALS = 5, - PDU_STATUS_ARR_HSS_CHANNEL_IDX_PI_DISPLAY = 4, - PDU_STATUS_ARR_HSS_CHANNEL_IDX_LIGHTS = 3, - PDU_STATUS_ARR_HSS_CHANNEL_IDX_HORN = 2, - PDU_STATUS_ARR_HSS_CHANNEL_IDX_DASHBOARD = 1, PDU_STATUS_ARR_HSS_CHANNEL_IDX_VCU = 0, + PDU_STATUS_ARR_HSS_CHANNEL_IDX_DASHBOARD = 1, + PDU_STATUS_ARR_HSS_CHANNEL_IDX_HORN = 2, + PDU_STATUS_ARR_HSS_CHANNEL_IDX_LIGHTS = 3, + PDU_STATUS_ARR_HSS_CHANNEL_IDX_PI_DISPLAY = 4, + PDU_STATUS_ARR_HSS_CHANNEL_IDX_PEDALS = 5, + PDU_STATUS_ARR_HSS_CHANNEL_IDX_CAMERAS = 6, + PDU_STATUS_ARR_HSS_CHANNEL_IDX_UNASSIGNED_0 = 7, + PDU_STATUS_ARR_HSS_CHANNEL_IDX_BATTERY = 8, + PDU_STATUS_ARR_HSS_CHANNEL_IDX_MPPTS = 9, + PDU_STATUS_ARR_HSS_CHANNEL_IDX_MOTOR_CONTROLLER = 10, + PDU_STATUS_ARR_HSS_CHANNEL_IDX_TELEMETRY_DATA_ACQ = 11, + PDU_STATUS_ARR_HSS_CHANNEL_IDX_PUMP = 12, + PDU_STATUS_ARR_HSS_CHANNEL_IDX_UNASSIGNED_1 = 13, + PDU_STATUS_ARR_HSS_CHANNEL_IDX_UNASSIGNED_2 = 14, + PDU_STATUS_ARR_HSS_CHANNEL_IDX_PDE_FANS = 15, } pdu_status_arr_hss_channel_idx_e; typedef enum { - PDU_STATUS_ARR_HSS_FAULT_FAULT = 1, PDU_STATUS_ARR_HSS_FAULT_OK = 0, + PDU_STATUS_ARR_HSS_FAULT_FAULT = 1, } pdu_status_arr_hss_fault_e; typedef enum { - PDU_STATUS_ARR_HSS_ENABLED_ENABLED = 1, PDU_STATUS_ARR_HSS_ENABLED_DISABLED = 0, + PDU_STATUS_ARR_HSS_ENABLED_ENABLED = 1, } pdu_status_arr_hss_enabled_e; typedef enum { - PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_PDE_FANS = 15, - PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_UNASSIGNED_1 = 14, - PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_UNASSIGNED_2 = 13, - PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_PUMP = 12, - PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_TELEMETRY_DATA_ACQ = 11, - PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_MOTOR_CONTROLLER = 10, - PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_MPPTS = 9, - PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_BATTERY = 8, - PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_UNASSIGNED_3 = 7, - PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_CAMERAS = 6, - PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_PEDALS = 5, - PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_PI_DISPLAY = 4, - PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_LIGHTS = 3, - PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_HORN = 2, - PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_DASHBOARD = 1, PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_VCU = 0, + PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_DASHBOARD = 1, + PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_HORN = 2, + PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_LIGHTS = 3, + PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_PI_DISPLAY = 4, + PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_PEDALS = 5, + PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_CAMERAS = 6, + PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_UNASSIGNED_0 = 7, + PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_BATTERY = 8, + PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_MPPTS = 9, + PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_MOTOR_CONTROLLER = 10, + PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_TELEMETRY_DATA_ACQ = 11, + PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_PUMP = 12, + PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_UNASSIGNED_1 = 13, + PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_UNASSIGNED_2 = 14, + PDU_SET_SWITCH_ARR_HSS_CHANNEL_IDX_PDE_FANS = 15, } pdu_set_switch_arr_hss_channel_idx_e; typedef enum { - PDU_SET_SWITCH_ARR_HSS_SETSWITCH_TOGGLE_OFF = 2, - PDU_SET_SWITCH_ARR_HSS_SETSWITCH_TOGGLE_ON = 1, PDU_SET_SWITCH_ARR_HSS_SETSWITCH_DO_NOTHING = 0, + PDU_SET_SWITCH_ARR_HSS_SETSWITCH_TOGGLE_ON = 1, + PDU_SET_SWITCH_ARR_HSS_SETSWITCH_TOGGLE_OFF = 2, } pdu_set_switch_arr_hss_setswitch_e; typedef enum { - PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_PDE_FANS = 15, - PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_UNASSIGNED_1 = 14, - PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_UNASSIGNED_2 = 13, - PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_PUMP = 12, - PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_TELEMETRY_DATA_ACQ = 11, - PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_MOTOR_CONTROLLER = 10, - PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_MPPTS = 9, - PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_BATTERY = 8, - PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_UNASSIGNED_3 = 7, - PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_CAMERAS = 6, - PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_PEDALS = 5, - PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_PI_DISPLAY = 4, - PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_LIGHTS = 3, - PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_HORN = 2, - PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_DASHBOARD = 1, PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_VCU = 0, + PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_DASHBOARD = 1, + PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_HORN = 2, + PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_LIGHTS = 3, + PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_PI_DISPLAY = 4, + PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_PEDALS = 5, + PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_CAMERAS = 6, + PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_UNASSIGNED_0 = 7, + PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_BATTERY = 8, + PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_MPPTS = 9, + PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_MOTOR_CONTROLLER = 10, + PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_TELEMETRY_DATA_ACQ = 11, + PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_PUMP = 12, + PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_UNASSIGNED_1 = 13, + PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_UNASSIGNED_2 = 14, + PDU_SET_CURRENT_LIMIT_ARR_HSS_CHANNEL_IDX_PDE_FANS = 15, } pdu_set_current_limit_arr_hss_channel_idx_e; typedef enum { - PUMP_STATUS_PUMP_FAULT_FAULT = 1, PUMP_STATUS_PUMP_FAULT_OK = 0, + PUMP_STATUS_PUMP_FAULT_FAULT = 1, } pump_status_pump_fault_e; typedef enum { - LV_CARRIER_STATUS_LTC4421_HVDCDC_SELECTED_SELECTED = 1, LV_CARRIER_STATUS_LTC4421_HVDCDC_SELECTED__ = 0, + LV_CARRIER_STATUS_LTC4421_HVDCDC_SELECTED_SELECTED = 1, } lv_carrier_status_ltc4421_hvdcdc_selected_e; typedef enum { - LV_CARRIER_STATUS_LTC4421_HVDCDC_FAULT_FAULT = 1, LV_CARRIER_STATUS_LTC4421_HVDCDC_FAULT_OK = 0, + LV_CARRIER_STATUS_LTC4421_HVDCDC_FAULT_FAULT = 1, } lv_carrier_status_ltc4421_hvdcdc_fault_e; typedef enum { - LV_CARRIER_STATUS_LTC4421_HVDCDC_VALID_OK = 1, LV_CARRIER_STATUS_LTC4421_HVDCDC_VALID_NOT_OK = 0, + LV_CARRIER_STATUS_LTC4421_HVDCDC_VALID_OK = 1, } lv_carrier_status_ltc4421_hvdcdc_valid_e; typedef enum { - LV_CARRIER_STATUS_LTC4421_SUPPBATT_SELECTED_SELECTED = 1, LV_CARRIER_STATUS_LTC4421_SUPPBATT_SELECTED__ = 0, + LV_CARRIER_STATUS_LTC4421_SUPPBATT_SELECTED_SELECTED = 1, } lv_carrier_status_ltc4421_suppbatt_selected_e; typedef enum { - LV_CARRIER_STATUS_LTC4421_SUPPBATT_FAULT_FAULT = 1, LV_CARRIER_STATUS_LTC4421_SUPPBATT_FAULT_OK = 0, + LV_CARRIER_STATUS_LTC4421_SUPPBATT_FAULT_FAULT = 1, } lv_carrier_status_ltc4421_suppbatt_fault_e; typedef enum { - LV_CARRIER_STATUS_LTC4421_SUPPBATT_VALID_OK = 1, LV_CARRIER_STATUS_LTC4421_SUPPBATT_VALID_NOT_OK = 0, + LV_CARRIER_STATUS_LTC4421_SUPPBATT_VALID_OK = 1, } lv_carrier_status_ltc4421_suppbatt_valid_e; typedef enum { - LV_CARRIER_STATUS_LV_EN_SUPPLEMENTALBATTERY_ENABLED = 1, LV_CARRIER_STATUS_LV_EN_SUPPLEMENTALBATTERY_DISABLED = 0, + LV_CARRIER_STATUS_LV_EN_SUPPLEMENTALBATTERY_ENABLED = 1, } lv_carrier_status_lv_en_supplementalbattery_e; typedef enum { - LV_CARRIER_STATUS_LV_EN_POWERSUPPLY_ENABLED = 1, LV_CARRIER_STATUS_LV_EN_POWERSUPPLY_DISABLED = 0, + LV_CARRIER_STATUS_LV_EN_POWERSUPPLY_ENABLED = 1, } lv_carrier_status_lv_en_powersupply_e; typedef enum { - BRAKE_PRESSURE_1_BRAKE_PRESSURE_FAULT_FAULT = 1, - BRAKE_PRESSURE_1_BRAKE_PRESSURE_FAULT_OK = 0, -} brake_pressure_1_brake_pressure_fault_e; - -typedef enum { - BRAKE_PRESSURE_2_BRAKE_PRESSURE_FAULT_FAULT = 1, - BRAKE_PRESSURE_2_BRAKE_PRESSURE_FAULT_OK = 0, -} brake_pressure_2_brake_pressure_fault_e; - -typedef enum { - DISPLAY_STATUS_CAMERA_STATUS_BACKUP_OK = 1, DISPLAY_STATUS_CAMERA_STATUS_BACKUP_NOT_OK = 0, + DISPLAY_STATUS_CAMERA_STATUS_BACKUP_OK = 1, } display_status_camera_status_backup_e; typedef enum { - DISPLAY_STATUS_CAMERA_STATUS_LEFT_OK = 1, DISPLAY_STATUS_CAMERA_STATUS_LEFT_NOT_OK = 0, + DISPLAY_STATUS_CAMERA_STATUS_LEFT_OK = 1, } display_status_camera_status_left_e; typedef enum { - DISPLAY_STATUS_CAMERA_STATUS_RIGHT_OK = 1, DISPLAY_STATUS_CAMERA_STATUS_RIGHT_NOT_OK = 0, + DISPLAY_STATUS_CAMERA_STATUS_RIGHT_OK = 1, } display_status_camera_status_right_e; /* ================= Message Structs ================= */ @@ -697,7 +912,7 @@ typedef struct { uint32_t Main_Battery_Voltage; int16_t Main_Battery_Avg_Temperature; uint8_t BPS_Segment0_Status; - int8_t BPS_Segment1_Status; + uint8_t BPS_Segment1_Status; uint8_t BPS_Segment2_Status; uint8_t BPS_Segment3_Status; uint8_t BPS_Segment4_Status; @@ -708,7 +923,6 @@ typedef struct { typedef struct { uint8_t BPS_Tap_idx; - uint8_t BPS_Tap_Msg_WDog; uint16_t BPS_Voltage_Tap_Data; uint8_t BPS_Voltage_Tap_Fault; uint16_t BPS_Voltage_Tap_Age; @@ -716,43 +930,72 @@ typedef struct { typedef struct { uint8_t BPS_Tap_idx; - uint8_t BPS_Temperature_Tap_Fault; int32_t BPS_Temperature_Tap_Data; + uint8_t BPS_Temperature_Tap_Fault; uint16_t BPS_Temperature_Tap_Age; - uint8_t BPS_Temperature_FrameID; + uint8_t FrameID_BPS_Temperature; } bps_temperature_aggregate_arr_t; typedef struct { - uint8_t BPS_Tap_idx; - uint8_t BPS_Tap_Msg_WDog; - uint16_t BPS_Temperature_Tap_RawV; - uint8_t BPS_Temperature_FrameID; -} bps_temp_rawv_aggregate_arr_t; + uint16_t Elcon_VOL_OUT; + uint16_t Elcon_CUR_OUT; + uint8_t Elcon_Watchdog; + uint8_t Elcon_CMD_TIMEOUT; + uint8_t Elcon_START_STATE; + uint8_t Elcon_INPUT_VOL_ERROR; + uint8_t Elcon_OVER_TEMPERATURE; + uint8_t Elcon_HW_FAULT; +} chargerinterface_status_t; typedef struct { - uint8_t VCU_Fault; - uint8_t Motor_Contactor_State; - uint8_t Motor_Precharge_Contactor_State; + uint8_t VCU_FSM_State; uint8_t Motor_Ready; - uint8_t VCU_Driver_Input_OK; - uint8_t VCU_Pedals_OK; - uint8_t VCU_Regen_OK; + uint8_t Motor_Precharge_Contactor_State; + uint8_t Motor_Contactor_State; + uint8_t VCU_Driver_Input_Watchdog; + uint8_t VCU_Pedals_Watchdog; + uint8_t VCU_BPS_Watchdog; + uint8_t VCU_Steering_Angle_Watchdog; + uint8_t VCU_BPS_FAULT_DETECTED; + uint8_t VCU_CONTROLS_FAULT_DETECTED; + uint8_t VCU_MTR_FAULT_DETECTED; + uint8_t VCU_PEDALS_FAULT_DETECTED; + uint8_t VCU_STEERING_FAULT_DETECTED; + uint8_t VCU_MotorCommandSource; uint8_t VCU_Regen_Active; - uint8_t VCU_Steering_Angle_OK; - uint8_t VCU_FSM_State; - uint8_t VCU_FSM_IN_PCHG_OK; - uint8_t VCU_FSM_IN_BRAKE; - uint8_t VCU_FSM_IN_FORWARD; - uint8_t VCU_FSM_IN_NEUTRAL; - uint8_t VCU_FSM_IN_REVERSE; - uint8_t VCU_FSM_IN_REGEN_RDY; - uint8_t VCU_FSM_IN_REGEN_ENABLE; - uint8_t VCU_FSM_IN_CRUISE_REQ; - uint8_t VCU_FSM_IN_REGEN_REQ; + uint8_t VCU_Regen_OK; + uint8_t VCU_MTR_PCHG_TIMEOUT; + uint8_t VCU_MTR_PCHG_CONT_TIMEOUT; + uint8_t VCU_MTR_PCHG_CONT_MISMATCH; + uint8_t VCU_MTR_CONT_MISMATCH; + uint8_t VCU_MTR_CONT_TIMEOUT; + uint8_t VCU_PCHG_OV; + uint8_t VCU_PCHG_UV; + uint8_t VCU_MTR_OV; + uint8_t VCU_MTR_UV; + uint8_t VCU_OTHER_FAULT; + uint8_t VCU_MTR_DIR_CHANGE_LOCKOUT; + uint8_t VCU_TIPPING_WARNING; + uint8_t VCU_WARN_REGEN_NOT_ALLOW; + uint8_t VCU_WARN_REGEN_NOT_EN; + uint8_t VCU_FSM_INP_BRAKE; + uint8_t VCU_FSM_INP_PCHG_OK; + uint8_t VCU_FSM_INP_CRUISE_REQ; + uint8_t VCU_FSM_INP_REGEN_REQ; + uint8_t VCU_FSM_INP_REGEN_ENABLE; + uint8_t VCU_FSM_INP_REGEN_RDY; + uint8_t VCU_FSM_INP_FORWARD; + uint8_t VCU_FSM_INP_NEUTRAL; + uint8_t VCU_FSM_INP_REVERSE; } vcu_status_t; typedef struct { uint8_t Controls_Leader_Fault; + uint8_t LightingBoard_Front_Status; + uint8_t LightingBoard_Left_Status; + uint8_t LightingBoard_Right_Status; + uint8_t LightingBoard_Rear_Status; + uint8_t LightingBoard_Canopy_Status; } controls_status_t; typedef struct { @@ -774,21 +1017,11 @@ typedef struct { uint8_t AccelPedal_Redundant_Fault; uint8_t BrakePedal_Main_Fault; uint8_t BrakePedal_Redundant_Fault; - uint8_t Pedals_FrameID; + uint8_t Brake_Pressure_1_Fault; + uint8_t Brake_Pressure_2_Fault; + uint8_t FrameID_Pedals; } pedal_status_t; -typedef struct { - uint16_t AccelPedal_Main_RawV; - uint16_t AccelPedal_Redundant_RawV; - uint8_t Pedals_FrameID; -} pedal_accel_rawv_t; - -typedef struct { - uint16_t BrakePedal_Main_RawV; - uint16_t BrakePedal_Redundant_RawV; - uint8_t Pedals_FrameID; -} pedal_brake_rawv_t; - typedef struct { uint8_t Ignition_Array; uint8_t Ignition_Motor; @@ -925,15 +1158,26 @@ typedef struct { } mppt_c_setoutputcurrentlimit_t; typedef struct { + uint8_t Supplemental_Battery_Fault; uint16_t Supplemental_Battery_Voltage; + int16_t Supplemental_Battery_Current; + uint8_t FrameID_Supp; } supp_battery_status_t; typedef struct { - uint8_t SuppCharger_Status; - int16_t Supplemental_Battery_Current; - uint16_t Supplemental_DCDC_Voltage; - int16_t Supplemental_DCDC_Current; -} supp_battery_charger_status_t; + uint8_t Supplemental_Charger_Status; + uint8_t BQ25756E_Error; + uint8_t BQ25756E_Watchdog; + int16_t Supplemental_Charge_Current; + uint16_t Supp_Charge_Current_Limit; + uint8_t FrameID_Supp_Charger; +} supp_charger_status_t; + +typedef struct { + uint16_t Supplemental_Vicor_Voltage; + int16_t Supplemental_Vicor_Current; + uint8_t FrameID_Supp_Charger; +} supp_vicor_stats_t; typedef struct { uint8_t HSS_Channel_idx; @@ -985,16 +1229,14 @@ typedef struct { typedef struct { uint16_t Brake_Pressure; - uint16_t Brake_Pressure_RawV; - uint8_t Brake_Pressure_Fault; - uint8_t Pedals_FrameID; + uint16_t Brake_Pressure_ADC; + uint8_t FrameID_Pedals; } brake_pressure_1_t; typedef struct { uint16_t Brake_Pressure; - uint16_t Brake_Pressure_RawV; - uint8_t Brake_Pressure_Fault; - uint8_t Pedals_FrameID; + uint16_t Brake_Pressure_ADC; + uint8_t FrameID_Pedals; } brake_pressure_2_t; typedef struct { @@ -1005,4 +1247,35 @@ typedef struct { } display_status_t; typedef struct { -} telemetry_status_t; \ No newline at end of file +} telemetry_status_t; + +typedef struct { + uint8_t BPS_Tap_idx; + uint16_t BPS_Temperature_Tap_ADC; + uint8_t FrameID_BPS_Temperature; +} bps_temp_adc_aggregate_arr_t; + +typedef struct { + uint16_t Supp_Battery_Voltage_ADC; + int16_t Supp_Battery_Current_ADC; + uint8_t FrameID_Supp; +} supp_measurements_adc_t; + +typedef struct { + uint16_t Supp_Vicor_Voltage_ADC; + uint16_t Supp_Vicor_Current_ADC; + uint8_t FrameID_Supp_Charger; +} supp_vicor_measurements_adc_t; + +typedef struct { + uint16_t BrakePedal_Main_ADC; + uint16_t BrakePedal_Redundant_ADC; + uint8_t FrameID_Pedals; +} pedal_brake_adc_t; + +typedef struct { + uint16_t AccelPedal_Main_ADC; + uint16_t AccelPedal_Redundant_ADC; + uint8_t FrameID_Pedals; +} pedal_accel_adc_t; + diff --git a/Firmware/config/Inc/MotorCAN_can_msgs.h b/Firmware/config/Inc/MotorCAN_can_msgs.h index 86cd5e73..f58ee493 100644 --- a/Firmware/config/Inc/MotorCAN_can_msgs.h +++ b/Firmware/config/Inc/MotorCAN_can_msgs.h @@ -15,13 +15,132 @@ #define CAN_ID_MC_MOTORVOLTAGEVECTORMEASUREMENT 0x425 #define CAN_ID_MC_MOTORCURRENTVECTORMEASUREMENT 0x426 #define CAN_ID_MC_BACKEMFMEASUREMENTPREDICTION 0x427 -#define CAN_ID_MC_15VRAILMEASUREMENT 0x428 -#define CAN_ID_MC_3V319VRAILMEASUREMENT 0x429 +#define CAN_ID_MC_15V_RAILMEASUREMENT 0x428 +#define CAN_ID_MC_3V3_19V_RAILMEASUREMENT 0x429 #define CAN_ID_MC_MOTOR_TEMPMEASUREMENT 0x42B #define CAN_ID_MC_DSPBOARDTEMPMEASUREMENT 0x42C #define CAN_ID_MC_ODOMETERBUSAHMEASUREMENT 0x42E #define CAN_ID_MC_SLIPSPEEDMEASUREMENT 0x437 - +#define CAN_ID_SET_MOTOR_CMD_SRC 0x7A1 + +/* ================= CAN Length Macros ================= */ + +#define CAN_DLC_MC_DRIVECOMMAND 8 +#define CAN_DLC_MC_POWERCOMMAND 4 +#define CAN_DLC_MC_RESETCOMMAND 1 +#define CAN_DLC_MC_INFO 8 +#define CAN_DLC_MC_STATUS 8 +#define CAN_DLC_MC_BUSMEASUREMENT 8 +#define CAN_DLC_MC_VELOCITYMEASUREMENT 8 +#define CAN_DLC_MC_PHASECURRENTMEASUREMENT 8 +#define CAN_DLC_MC_MOTORVOLTAGEVECTORMEASUREMENT 8 +#define CAN_DLC_MC_MOTORCURRENTVECTORMEASUREMENT 8 +#define CAN_DLC_MC_BACKEMFMEASUREMENTPREDICTION 8 +#define CAN_DLC_MC_15V_RAILMEASUREMENT 8 +#define CAN_DLC_MC_3V3_19V_RAILMEASUREMENT 8 +#define CAN_DLC_MC_MOTOR_TEMPMEASUREMENT 8 +#define CAN_DLC_MC_DSPBOARDTEMPMEASUREMENT 8 +#define CAN_DLC_MC_ODOMETERBUSAHMEASUREMENT 8 +#define CAN_DLC_MC_SLIPSPEEDMEASUREMENT 8 +#define CAN_DLC_SET_MOTOR_CMD_SRC 1 + + +/* ================= Value Table Enums ================= */ + +typedef enum { + MC_STATUS_MC_LIMIT_OUTPUTVOLTAGEPWM_OK = 0, + MC_STATUS_MC_LIMIT_OUTPUTVOLTAGEPWM_LIMIT = 1, +} mc_status_mc_limit_outputvoltagepwm_e; + +typedef enum { + MC_STATUS_MC_LIMIT_MOTORCURRENT_OK = 0, + MC_STATUS_MC_LIMIT_MOTORCURRENT_LIMIT = 1, +} mc_status_mc_limit_motorcurrent_e; + +typedef enum { + MC_STATUS_MC_LIMIT_VELOCITY_OK = 0, + MC_STATUS_MC_LIMIT_VELOCITY_LIMIT = 1, +} mc_status_mc_limit_velocity_e; + +typedef enum { + MC_STATUS_MC_LIMIT_BUSCURRENT_OK = 0, + MC_STATUS_MC_LIMIT_BUSCURRENT_LIMIT = 1, +} mc_status_mc_limit_buscurrent_e; + +typedef enum { + MC_STATUS_MC_LIMIT_BUSVOLTAGEUPPER_OK = 0, + MC_STATUS_MC_LIMIT_BUSVOLTAGEUPPER_LIMIT = 1, +} mc_status_mc_limit_busvoltageupper_e; + +typedef enum { + MC_STATUS_MC_LIMIT_BUSVOLTAGELOWER_OK = 0, + MC_STATUS_MC_LIMIT_BUSVOLTAGELOWER_LIMIT = 1, +} mc_status_mc_limit_busvoltagelower_e; + +typedef enum { + MC_STATUS_MC_LIMIT_MOTORTEMP_OK = 0, + MC_STATUS_MC_LIMIT_MOTORTEMP_LIMIT = 1, +} mc_status_mc_limit_motortemp_e; + +typedef enum { + MC_STATUS_MC_LIMIT_RESERVED_OK = 0, + MC_STATUS_MC_LIMIT_RESERVED_LIMIT = 1, +} mc_status_mc_limit_reserved_e; + +typedef enum { + MC_STATUS_MC_FAULT_HARDWAREOVERCURRENT_OK = 0, + MC_STATUS_MC_FAULT_HARDWAREOVERCURRENT_FAULT = 1, +} mc_status_mc_fault_hardwareovercurrent_e; + +typedef enum { + MC_STATUS_MC_FAULT_SOFTWAREOVERCURRENT_OK = 0, + MC_STATUS_MC_FAULT_SOFTWAREOVERCURRENT_FAULT = 1, +} mc_status_mc_fault_softwareovercurrent_e; + +typedef enum { + MC_STATUS_MC_FAULT_DCBUSOVERVOLTAGE_OK = 0, + MC_STATUS_MC_FAULT_DCBUSOVERVOLTAGE_FAULT = 1, +} mc_status_mc_fault_dcbusovervoltage_e; + +typedef enum { + MC_STATUS_MC_FAULT_BADMOTORPOSITIONHALLSEQ_OK = 0, + MC_STATUS_MC_FAULT_BADMOTORPOSITIONHALLSEQ_FAULT = 1, +} mc_status_mc_fault_badmotorpositionhallseq_e; + +typedef enum { + MC_STATUS_MC_FAULT_WATCHDOGCAUSEDLASTRESET_OK = 0, + MC_STATUS_MC_FAULT_WATCHDOGCAUSEDLASTRESET_FAULT = 1, +} mc_status_mc_fault_watchdogcausedlastreset_e; + +typedef enum { + MC_STATUS_MC_FAULT_CONFIGREAD_OK = 0, + MC_STATUS_MC_FAULT_CONFIGREAD_FAULT = 1, +} mc_status_mc_fault_configread_e; + +typedef enum { + MC_STATUS_MC_FAULT_15VRAILUNDERVOLTAGE_OK = 0, + MC_STATUS_MC_FAULT_15VRAILUNDERVOLTAGE_FAULT = 1, +} mc_status_mc_fault_15vrailundervoltage_e; + +typedef enum { + MC_STATUS_MC_FAULT_DESATURATIONFAULT_OK = 0, + MC_STATUS_MC_FAULT_DESATURATIONFAULT_FAULT = 1, +} mc_status_mc_fault_desaturationfault_e; + +typedef enum { + MC_STATUS_MC_FAULT_MOTOROVERSPEED_OK = 0, + MC_STATUS_MC_FAULT_MOTOROVERSPEED_FAULT = 1, +} mc_status_mc_fault_motoroverspeed_e; + +typedef enum { + MC_STATUS_MC_FAULT_RESERVED_OK = 0, + MC_STATUS_MC_FAULT_RESERVED_FAULT = 1, +} mc_status_mc_fault_reserved_e; + +typedef enum { + SET_MOTOR_CMD_SRC_MOTOR_COMMAND_SOURCE_VCU = 0, + SET_MOTOR_CMD_SRC_MOTOR_COMMAND_SOURCE_TRITIUM_EXTERNAL = 1, +} set_motor_cmd_src_motor_command_source_e; /* ================= Message Structs ================= */ @@ -99,12 +218,12 @@ typedef struct { typedef struct { float MC_Supply15V; -} mc_15vrailmeasurement_t; +} mc_15v_railmeasurement_t; typedef struct { float MC_Supply1V9; float MC_Supply3V3; -} mc_3v319vrailmeasurement_t; +} mc_3v3_19v_railmeasurement_t; typedef struct { float MC_MotorTemp; @@ -124,3 +243,7 @@ typedef struct { float MC_SlipSpeed; } mc_slipspeedmeasurement_t; +typedef struct { + uint8_t Motor_Command_Source; +} set_motor_cmd_src_t; + diff --git a/Firmware/config/Inc/SteeringCAN_can_msgs.h b/Firmware/config/Inc/SteeringCAN_can_msgs.h new file mode 100644 index 00000000..ab754e78 --- /dev/null +++ b/Firmware/config/Inc/SteeringCAN_can_msgs.h @@ -0,0 +1,55 @@ +#pragma once + +#include + +/* ================= CAN ID Macros ================= */ + +#define CAN_ID_LWS_STANDARD 0x2B0 +#define CAN_ID_LWS_CONFIG 0x7C0 + +/* ================= CAN Length Macros ================= */ + +#define CAN_DLC_LWS_STANDARD 5 +#define CAN_DLC_LWS_CONFIG 2 + + +/* ================= Value Table Enums ================= */ + +typedef enum { + LWS_STANDARD_LWS_FAULT_OK = 0, + LWS_STANDARD_LWS_FAULT_INTERNAL_FAULT = 1, +} lws_standard_lws_fault_e; + +typedef enum { + LWS_STANDARD_LWS_CALIBRATIONSTAUS_SENSOR_NOT_CALIBRATED = 0, + LWS_STANDARD_LWS_CALIBRATIONSTAUS_SENSOR_CALIBRATED = 1, +} lws_standard_lws_calibrationstaus_e; + +typedef enum { + LWS_STANDARD_LWS_TRIMMING_STATUS_FAULT_SENSOR_NOT_TRIMMED = 0, + LWS_STANDARD_LWS_TRIMMING_STATUS_SENSOR_TRIMMED = 1, +} lws_standard_lws_trimming_status_e; + +typedef enum { + LWS_CONFIG_LWS_CCW_SETS_THE_SIGNAL_LWS_ANGLE_TO_0Ã_Â_ = 3, + LWS_CONFIG_LWS_CCW_RESETS_CALIBRATION_STATUS = 5, +} lws_config_lws_ccw_e; + +/* ================= Message Structs ================= */ + +typedef struct { + int16_t LWS_Angle; + uint8_t LWS_Speed; + uint8_t LWS_Fault; + uint8_t LWS_CalibrationStaus; + uint8_t LWS_Trimming_Status; + uint8_t LWS_SF1_5; + uint8_t LWS_MSG_CNT; + uint8_t LWS_CHK_SUM; +} lws_standard_t; + +typedef struct { + uint8_t LWS_CCW; + uint16_t LWS_RES; +} lws_config_t; + diff --git a/Firmware/config/Inc/can1_recv_entries.h b/Firmware/config/Inc/can1_recv_entries.h index 4e930cd6..2aa2ecfd 100644 --- a/Firmware/config/Inc/can1_recv_entries.h +++ b/Firmware/config/Inc/can1_recv_entries.h @@ -1,6 +1,12 @@ #include "CarCAN_can_msgs.h" // CAN_RECV_ENTRY(ID, SIZE, CIRCULAR) +// motorcan +#include "MotorCAN_can_msgs.h" + +CAN_RECV_ENTRY(0x123, 8, true) // testing only comment later +CAN_RECV_ENTRY(CAN_ID_MC_INFO, 2, true) +CAN_RECV_ENTRY(CAN_ID_MC_STATUS, 2, true) +CAN_RECV_ENTRY(CAN_ID_MC_BUSMEASUREMENT, 2, true) +CAN_RECV_ENTRY(CAN_ID_MC_VELOCITYMEASUREMENT, 2, true) +CAN_RECV_ENTRY(CAN_ID_SET_MOTOR_CMD_SRC, 2, true) -CAN_RECV_ENTRY(0x421, 5, true) -CAN_RECV_ENTRY(CAN_ID_VCU_PRECHARGE_VOLTAGES, 6, true) -CAN_RECV_ENTRY(0x321, 8, false) \ No newline at end of file diff --git a/Firmware/config/Inc/can3_recv_entries.h b/Firmware/config/Inc/can3_recv_entries.h index 888eb76d..3cfdf523 100644 --- a/Firmware/config/Inc/can3_recv_entries.h +++ b/Firmware/config/Inc/can3_recv_entries.h @@ -1,10 +1,16 @@ #include "CarCAN_can_msgs.h" // CAN_RECV_ENTRY(ID, SIZE, CIRCULAR) +// carcan -CAN_RECV_ENTRY(0x001, 5, false) -CAN_RECV_ENTRY(0x002, 8, false) -CAN_RECV_ENTRY(0x003, 3, false) -CAN_RECV_ENTRY(CAN_ID_VCU_STATUS, 6, true) -CAN_RECV_ENTRY(CAN_ID_DRIVER_INPUT_STATUS, 2, true) -CAN_RECV_ENTRY(CAN_ID_VCU_PRECHARGE_VOLTAGES, 6, true) -CAN_RECV_ENTRY(0x321, 8, false) \ No newline at end of file +#include "CarCAN_can_msgs.h" +#include "SteeringCAN_can_msgs.h" +#include "BPSCAN_can_msgs.h" + +CAN_RECV_ENTRY(0x123, 8, true) // testing only, comment later +CAN_RECV_ENTRY(CAN_ID_BPS_STATUS, 8, true) +CAN_RECV_ENTRY(CAN_ID_PEDAL_STATUS, 8, true) +CAN_RECV_ENTRY(CAN_ID_LV_CARRIER_STATUS, 8, true) +CAN_RECV_ENTRY(CAN_ID_LWS_STANDARD, 8, true) +CAN_RECV_ENTRY(CAN_ID_DRIVER_INPUT_STATUS, 8, true) +CAN_RECV_ENTRY(CAN_ID_BPS_PRECHARGE_VOLTAGES, 8, true) +CAN_RECV_ENTRY(CAN_ID_CONTROLS_STATUS, 8, true) diff --git a/Firmware/config/Inc/pinDefs.h b/Firmware/config/Inc/pinDefs.h index 03b1376f..1fe9808d 100644 --- a/Firmware/config/Inc/pinDefs.h +++ b/Firmware/config/Inc/pinDefs.h @@ -2,66 +2,66 @@ #include "stm32xx_hal.h" -#define HB_LED_PORT GPIOC -#define HB_LED_PIN GPIO_PIN_3 +#define HB_LED_PORT GPIOC +#define HB_LED_PIN GPIO_PIN_3 // Car State LEDs -#define DRIVABLE_LED_PORT GPIOC -#define DRIVABLE_LED_PIN GPIO_PIN_6 +#define DRIVABLE_LED_PORT GPIOC +#define DRIVABLE_LED_PIN GPIO_PIN_6 -#define DRIVING_LED_PORT GPIOC -#define DRIVING_LED_PIN GPIO_PIN_9 +#define DRIVING_LED_PORT GPIOC +#define DRIVING_LED_PIN GPIO_PIN_9 -#define CRUISE_LED_PORT GPIOB -#define CRUISE_LED_PIN GPIO_PIN_13 +#define CRUISE_LED_PORT GPIOB +#define CRUISE_LED_PIN GPIO_PIN_13 -#define REGEN_LED_PORT GPIOB -#define REGEN_LED_PIN GPIO_PIN_15 +#define REGEN_LED_PORT GPIOB +#define REGEN_LED_PIN GPIO_PIN_15 -#define BPS_FAULT_LED_PORT GPIOB -#define BPS_FAULT_LED_PIN GPIO_PIN_9 +#define BPS_FAULT_LED_PORT GPIOB +#define BPS_FAULT_LED_PIN GPIO_PIN_9 -#define CAR_HB_LED_PORT GPIOB -#define CAR_HB_LED_PIN GPIO_PIN_14 +#define CAR_HB_LED_PORT GPIOB +#define CAR_HB_LED_PIN GPIO_PIN_14 // Motor Contactor -#define MOTOR_SENSE_TO_LED_PORT GPIOC -#define MOTOR_SENSE_TO_LED_PIN GPIO_PIN_7 +#define MOTOR_SENSE_TO_LED_PORT GPIOC +#define MOTOR_SENSE_TO_LED_PIN GPIO_PIN_7 -#define MOTOR_ENABLE_LED_PORT GPIOC -#define MOTOR_ENABLE_LED_PIN GPIO_PIN_0 +#define MOTOR_ENABLE_LED_PORT GPIOC +#define MOTOR_ENABLE_LED_PIN GPIO_PIN_0 -#define MOTOR_SENSE_LED_PORT GPIOC -#define MOTOR_SENSE_LED_PIN GPIO_PIN_2 +#define MOTOR_SENSE_LED_PORT GPIOC +#define MOTOR_SENSE_LED_PIN GPIO_PIN_2 // Precharge Contactor #define PRECHARGE_COMPLETE_LED_PORT GPIOC -#define PRECHARGE_COMPLETE_LED_PIN GPIO_PIN_8 +#define PRECHARGE_COMPLETE_LED_PIN GPIO_PIN_8 -#define PRECHARGE_TO_LED_PORT GPIOD -#define PRECHARGE_TO_LED_PIN GPIO_PIN_2 +#define PRECHARGE_TO_LED_PORT GPIOD +#define PRECHARGE_TO_LED_PIN GPIO_PIN_2 #define PRECHARGE_SENSE_TO_LED_PORT GPIOC -#define PRECHARGE_SENSE_TO_LED_PIN GPIO_PIN_12 +#define PRECHARGE_SENSE_TO_LED_PIN GPIO_PIN_12 -#define PRECHARGE_ENABLE_LED_PORT GPIOC -#define PRECHARGE_ENABLE_LED_PIN GPIO_PIN_4 +#define PRECHARGE_ENABLE_LED_PORT GPIOC +#define PRECHARGE_ENABLE_LED_PIN GPIO_PIN_4 -#define PRECHARGE_SENSE_LED_PORT GPIOC -#define PRECHARGE_SENSE_LED_PIN GPIO_PIN_5 +#define PRECHARGE_SENSE_LED_PORT GPIOC +#define PRECHARGE_SENSE_LED_PIN GPIO_PIN_5 // Motor Faults -#define HALL_EFFECT_LED_PORT GPIOB -#define HALL_EFFECT_LED_PIN GPIO_PIN_3 +#define HALL_EFFECT_LED_PORT GPIOB +#define HALL_EFFECT_LED_PIN GPIO_PIN_3 -#define DAWG_LED_PORT GPIOB -#define DAWG_LED_PIN GPIO_PIN_5 +#define DAWG_LED_PORT GPIOB +#define DAWG_LED_PIN GPIO_PIN_5 -#define SWOC_LED_PORT GPIOA -#define SWOC_LED_PIN GPIO_PIN_10 +#define SWOC_LED_PORT GPIOA +#define SWOC_LED_PIN GPIO_PIN_10 -#define FAULT_LED_PORT GPIOB -#define FAULT_LED_PIN GPIO_PIN_4 +#define FAULT_LED_PORT GPIOB +#define FAULT_LED_PIN GPIO_PIN_4 // SDCard Pins #define SDCARD_CS_PORT GPIOA @@ -77,28 +77,28 @@ #define SDCARD_MOSI_PIN GPIO_PIN_7 // Other pins -#define USART3_PORT GPIOC -#define USART3_TX_PIN GPIO_PIN_10 -#define USART3_RX_PIN GPIO_PIN_11 +#define USART3_PORT GPIOC +#define USART3_TX_PIN GPIO_PIN_10 +#define USART3_RX_PIN GPIO_PIN_11 -#define GPIO_INIT_PORT GPIOC -#define GPIO_ONE_PIN GPIO_PIN_8 -#define GPIO_TWO_PIN GPIO_PIN_12 +#define GPIO_INIT_PORT GPIOC +#define GPIO_ONE_PIN GPIO_PIN_8 +#define GPIO_TWO_PIN GPIO_PIN_12 -#define ADC_PORT GPIOB -#define ADC1_PIN GPIO_PIN_12 -#define ADC2_PIN GPIO_PIN_2 +#define ADC_PORT GPIOB +#define ADC1_PIN GPIO_PIN_12 +#define ADC2_PIN GPIO_PIN_2 /** * @brief object that holds pin num and port of a GPIO pin */ typedef struct { - GPIO_TypeDef* port; // e.g., GPIOA - uint16_t pin; // e.g., GPIO_PIN_3 + GPIO_TypeDef *port; // e.g., GPIOA + uint16_t pin; // e.g., GPIO_PIN_3 } GpioPin_t; typedef enum { NORMAL = 0, // We good - EMERGENCY = 1 // We bad + EMERGENCY = 1 // We bad } fault_state_t; \ No newline at end of file diff --git a/Firmware/core/Src/main.c b/Firmware/core/Src/main.c index 7836d321..dbc3520d 100644 --- a/Firmware/core/Src/main.c +++ b/Firmware/core/Src/main.c @@ -7,9 +7,9 @@ int main(void) { HAL_Init(); SystemClock_Config(); - LEDs_init(); + LED_init(); - xTaskCreateStatic( + xTaskCreateStatic( Task_Init, // Task function "Init", // Name of the task (for debugging) configMINIMAL_STACK_SIZE, // Stack size in words @@ -19,9 +19,9 @@ int main(void) &Init_Task_Buffer // Static task buffer (optional) ); + vTaskStartScheduler(); - Error_Handler(); /* Infinite loop */ while (1) diff --git a/Firmware/scripts/fsm_generator.py b/Firmware/scripts/fsm_generator.py new file mode 100644 index 00000000..77315ded --- /dev/null +++ b/Firmware/scripts/fsm_generator.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python3 +import argparse +from pathlib import Path + +OUT_DIR = Path(__file__).resolve().parent.parent / "Tasks/Inc" + +BITS = { + "NEUTRAL_BIT": 1 << 0, + "FORWARD_BIT": 1 << 1, + "REVERSE_BIT": 1 << 2, + "CRUISE_CONTROL_BUTTON_BIT": 1 << 3, + "REGEN_BUTTON_BIT": 1 << 4, + "READY_TO_REGEN_BIT": 1 << 5, + "REGEN_ENABLED_BIT": 1 << 6, + "BRAKE_BIT": 1 << 7, + "PRECHARGE_BIT": 1 << 8, +} + +STATES = [ + "STATE_INIT", + "FORWARD_DRIVE", + "NEUTRAL_DRIVE", + "REVERSE_DRIVE", + "REGEN", + "CRUISE_CONTROL", + "DISABLED", + "CAR_NOT_READY", +] + +STATE_IDX = {s: i for i, s in enumerate(STATES)} +NSL = 1 << len(BITS) + +# preresolve some constants so its easier to write +NEU = BITS["NEUTRAL_BIT"] +FWD = BITS["FORWARD_BIT"] +REV = BITS["REVERSE_BIT"] +CC = BITS["CRUISE_CONTROL_BUTTON_BIT"] +RB = BITS["REGEN_BUTTON_BIT"] +RTR = BITS["READY_TO_REGEN_BIT"] +REN = BITS["REGEN_ENABLED_BIT"] +BRK = BITS["BRAKE_BIT"] +PC = BITS["PRECHARGE_BIT"] + +INIT = STATE_IDX["STATE_INIT"] +FWD_DRIVE = STATE_IDX["FORWARD_DRIVE"] +NEUTRAL = STATE_IDX["NEUTRAL_DRIVE"] +REV_DRIVE = STATE_IDX["REVERSE_DRIVE"] +REGEN = STATE_IDX["REGEN"] +CRUISE = STATE_IDX["CRUISE_CONTROL"] +DISABLED = STATE_IDX["DISABLED"] +NOT_READY = STATE_IDX["CAR_NOT_READY"] + + +def transition_full(cur, bits): + if cur == INIT: + return NOT_READY + + if cur == NOT_READY: + return NEUTRAL if (bits & PC) else NOT_READY + + if cur == DISABLED: + return DISABLED + + if cur == NEUTRAL: + if (bits & FWD) and not (bits & REV) and not (bits & BRK): + return FWD_DRIVE + if (bits & REV) and not (bits & FWD) and not (bits & BRK): + return REV_DRIVE + return NEUTRAL + + if cur == FWD_DRIVE: + if (bits & REV) or (bits & NEU) or (bits & BRK): + return NEUTRAL + if (bits & REN) and (bits & RTR) and (bits & RB): + return REGEN + if (bits & CC) and (bits & REN): + return CRUISE + return FWD_DRIVE + + if cur == REV_DRIVE: + if (bits & REV) and not (bits & FWD) and not (bits & BRK): + return REV_DRIVE + return NEUTRAL + + if cur == REGEN: + if (bits & RB) and (bits & RTR) and (bits & REN) and (bits & FWD): + return REGEN + return FWD_DRIVE + + if cur == CRUISE: + return CRUISE if (bits & CC) else FWD_DRIVE + + return NEUTRAL + + +def transition_dnr(cur, bits): + if cur == DISABLED: + return DISABLED + + if cur == INIT: + return NOT_READY + + if cur != DISABLED and not (bits & PC): + return NOT_READY + + if cur == NOT_READY: + return NEUTRAL if (bits & PC) else NOT_READY + + if cur == NEUTRAL: + if (bits & FWD) and not (bits & REV): + return FWD_DRIVE + if (bits & REV) and not (bits & FWD): + return REV_DRIVE + return NEUTRAL + + if cur == FWD_DRIVE: + if (bits & REV) or (bits & NEU) or (bits & BRK): + return NEUTRAL + return FWD_DRIVE + + + if cur in (REGEN, CRUISE): + if (bits & REV) or (bits & NEU) or (bits & BRK): + return NEUTRAL + return FWD_DRIVE + + if cur == REV_DRIVE: + if (bits & REV) and not (bits & FWD) and not (bits & BRK): + return REV_DRIVE + return NEUTRAL + + return NEUTRAL + + +def write_table(path, fn, label): + rows = [] + states = STATES + nsl = NSL + + for i, name in enumerate(states): + ns = [states[fn(i, j)] for j in range(nsl)] + chunks = [ + ", ".join(ns[x:x+8]) + for x in range(0, nsl, 8) + ] + + body = ",\n".join(f" {c}" for c in chunks) + + rows.append( + f" [{name}] = {{ {name}, NULL, {{\n{body}\n }}}},\n" + ) + + path.write_text( + f"/**\n" + f" * @file {path.name}\n" + f" * @brief Auto-generated FSM table ({label}); do not edit\n" + f" * Regenerate: python3 generate_fsm.py --{label.lower()}\n" + f" */\n\n" + f"#pragma once\n" + f'#include "FSMTask.h"\n\n' + f"extern MocoState_t FSM[NUM_STATES];\n\n" + f"#ifdef DEFINE_FSM_TABLE\n" + f"MocoState_t FSM[NUM_STATES] = {{\n\n" + + "".join(rows) + + "};\n" + f"#endif\n" + ) + + print(f"[{label:4}] {path.name} ({len(states)} states x {nsl} inputs)") + + + +def main(): + parser = argparse.ArgumentParser() + g = parser.add_mutually_exclusive_group(required=True) + g.add_argument("--full", action="store_true") + g.add_argument("--dnr", action="store_true") + g.add_argument("--all", action="store_true") + args = parser.parse_args() + + OUT_DIR.mkdir(parents=True, exist_ok=True) + + if args.full or args.all: + write_table(OUT_DIR / "fsm_table.h", transition_full, "FULL") + if args.dnr or args.all: + write_table(OUT_DIR / "fsm_table_dnr.h", transition_dnr, "DNR") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Firmware/scripts/steering_angle_lut_generator.py b/Firmware/scripts/steering_angle_lut_generator.py new file mode 100644 index 00000000..af012157 --- /dev/null +++ b/Firmware/scripts/steering_angle_lut_generator.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +""" +generate_rollover_table.py +Generates rollover_speed_table.h — the max allowable speed lookup table. +LWS_Angle is int16_t in 0.1 degree units; table indexed by abs(LWS_Angle / 10). +""" + +import math +from pathlib import Path + +OUT = Path(__file__).resolve().parent.parent / "Tasks/Inc/rollover_speed_table.h" + +G, HALF_TRACK, CG_LATERAL = 9.81, 1.35, 1.612 +CG_HEIGHT, WHEELBASE, STEERING_RATIO, MIN_DEG = 0.481, 2.25, 15.0, 2.0 +NO_LIMIT = 0xFFFF + +def v_max_cms(deg): + wheel_deg = deg / STEERING_RATIO + if abs(wheel_deg) < MIN_DEG: + return NO_LIMIT + R = WHEELBASE / math.tan(math.radians(abs(wheel_deg))) + v_ms = math.sqrt(G * R * HALF_TRACK * CG_LATERAL / (2.0 * CG_HEIGHT * WHEELBASE)) + return min(int(v_ms * 100), NO_LIMIT - 1) + +table = [v_max_cms(i) for i in range(721)] + +rows = [f" " + ", ".join(f"0x{v:04X}" for v in table[i:i+8]) + f", // {i}-{min(i+7, len(table)-1)} deg" + for i in range(0, len(table), 8)] + +OUT.write_text( + "/**\n" + " * @file rollover_speed_table.h\n" + " * @brief Auto-generated rollover speed limit lookup table — do not edit\n" + " * Regenerate: python3 scripts/generate_rollover_table.py\n" + " *\n" + " * Index : abs(LWS_Angle / 10) [integer degrees, 0-720]\n" + " * Value : max allowable speed in cm/s | 0xFFFF = no limit (straight)\n" + " */\n\n" + "#pragma once\n\n" + "#include \n\n" + "#define ROLLOVER_TABLE_NO_LIMIT 0xFFFFU\n" + "#define ROLLOVER_TABLE_MAX_DEG 720U\n\n" + "// Index: abs(LWS_Angle / 10) in integer degrees (0-720)\n" + "// Value: max allowable speed in cm/s | 0xFFFF = no limit\n" + "static const uint16_t rollover_speed_table[721] = {\n" + + "\n".join(rows) + "\n" + "};\n" +) +print(f"Generated {OUT} ({len(table)} entries, {len(table)*2} bytes)") diff --git a/Firmware/scripts/voltage_lut_generator.py b/Firmware/scripts/voltage_lut_generator.py new file mode 100644 index 00000000..c32e3d48 --- /dev/null +++ b/Firmware/scripts/voltage_lut_generator.py @@ -0,0 +1,63 @@ +import numpy as np +import os + +def generate_voltage_lut(csv_path, output_path): + # Get the directory where the script itself is located + script_dir = os.path.dirname(os.path.abspath(__file__)) + + adc_max = 4095 # 12-bit ADC + + # Constants + VREF_MV = 3300 + GAIN_NUM = 5 + GAIN_DEN = 2 + R_NUM = 102490 + R_DEN = 2490 + + adc_range = np.arange(4096, dtype=np.uint64) + + # Integer math for voltage calculation + numerator = adc_range * VREF_MV * GAIN_NUM * R_NUM + denominator = adc_max * GAIN_DEN * R_DEN + voltage_milli_v = (numerator + denominator // 2) // denominator # rounded division + + # Prepare C header file content + header_content = [ + "#pragma once", + "", + "#include ", + "", + "/**", + " * @brief Look-up table for voltage ADC counts to voltage.", + " * Index: 12-bit ADC Count (0 - 4095)", + " * Value: Voltage in millivolts (mV)", + " */", + "static const uint32_t voltage_lut[4096] = {" + ] + + # Add array entries formatted for readability (10 per line) + for i in range(0, len(voltage_milli_v), 10): + row = voltage_milli_v[i:i+10] + row_str = " " + ", ".join(f"{val:7d}" for val in row) + if i + 10 < len(voltage_milli_v): + row_str += "," + header_content.append(row_str) + + header_content.append("};") + + # Get the directory where the script itself is located + script_dir = os.path.dirname(os.path.abspath(__file__)) + # Join that directory with your filename + output = os.path.join(script_dir, output_path) + + # Ensure directory exists and write file + os.makedirs(os.path.dirname(output), exist_ok=True) + with open(output, 'w') as f: + f.write("\n".join(header_content)) + + print(f"Successfully generated {output}") + +if __name__ == "__main__": + csv_filename = 'ERTJ1VR.csv' + output_filename = '../voltage_lut.h' + generate_voltage_lut(csv_filename, output_filename) \ No newline at end of file diff --git a/Firmware/tests/CANBus_test.c b/Firmware/tests/CANBus_test.c deleted file mode 100644 index e67fb0d0..00000000 --- a/Firmware/tests/CANBus_test.c +++ /dev/null @@ -1,82 +0,0 @@ -#include "CANbus.h" -#include "stm32xx_hal.h" -#include "inits.h" -#include "StatusLEDs.h" -#include "pinDefs.h" - -StaticTask_t task_buffer; -StackType_t task_stack[512]; - -static void task(void *pvParameters){ - - int test_id = 0x321; - FDCAN_TxHeaderTypeDef tx_header = {0}; - tx_header.Identifier = test_id; - tx_header.IdType = FDCAN_STANDARD_ID; - tx_header.TxFrameType = FDCAN_DATA_FRAME; - tx_header.DataLength = FDCAN_DLC_BYTES_8; - tx_header.ErrorStateIndicator = FDCAN_ESI_ACTIVE; - tx_header.BitRateSwitch = FDCAN_BRS_OFF; - tx_header.FDFormat = FDCAN_CLASSIC_CAN; - tx_header.TxEventFifoControl = FDCAN_STORE_TX_EVENTS; - tx_header.MessageMarker = 0; - - // send x1234 to 0x11 - uint8_t tx_data[8] = {0}; - tx_data[0] = 0x12; - tx_data[1] = 0x34; - tx_data[2] = 0x56; - tx_data[3] = 0x78; - tx_data[4] = 0x9A; - tx_data[5] = 0xBC; - tx_data[6] = 0xDE; - tx_data[7] = 0xFF; - - while(1){ - - if (can_fd_send(hfdcan3, &tx_header, tx_data, portMAX_DELAY) == CAN_ERR){ - Error_Handler(); - } - - // TODO: add status LED - HAL_GPIO_TogglePin(HB_LED_PORT, HB_LED_PIN); - vTaskDelay(pdMS_TO_TICKS(1000)); - } -} - -void can_error_handler(){ - while(1){ - LED_set(MOTOR_FAULT, LED_ON); - } -} - -int main(){ - HAL_Init(); - - SystemClock_Config(); - __HAL_RCC_SYSCFG_CLK_ENABLE(); - __HAL_RCC_PWR_CLK_ENABLE(); - - LEDs_init(); - - - if(CAN_Init() != CAN_OK){ - can_error_handler(); - } - - xTaskCreateStatic( - task, - "task", - 512, - NULL, - tskIDLE_PRIORITY + 2, - task_stack, - &task_buffer); - - - vTaskStartScheduler(); - - while(1){ - - } -} \ No newline at end of file diff --git a/Firmware/tests/CanTxTelemetry_test.c b/Firmware/tests/CanTxTelemetry_test.c deleted file mode 100644 index e444666a..00000000 --- a/Firmware/tests/CanTxTelemetry_test.c +++ /dev/null @@ -1,89 +0,0 @@ -#include "CANbus.h" -#include "stm32xx_hal.h" -#include "inits.h" -#include "StatusLEDs.h" -#include "pinDefs.h" -#include "CanTxTelemetryTask.h" - -StaticTask_t task_buffer; -StackType_t task_stack[512]; - -static void task(void *pvParameters){ - - int test_id = 0x321; - FDCAN_TxHeaderTypeDef tx_header = {0}; - tx_header.Identifier = test_id; - tx_header.IdType = FDCAN_STANDARD_ID; - tx_header.TxFrameType = FDCAN_DATA_FRAME; - tx_header.DataLength = FDCAN_DLC_BYTES_8; - tx_header.ErrorStateIndicator = FDCAN_ESI_ACTIVE; - tx_header.BitRateSwitch = FDCAN_BRS_OFF; - tx_header.FDFormat = FDCAN_CLASSIC_CAN; - tx_header.TxEventFifoControl = FDCAN_STORE_TX_EVENTS; - tx_header.MessageMarker = 0; - - // send x1234 to 0x11 - uint8_t tx_data[8] = {0}; - tx_data[0] = 0x12; - tx_data[1] = 0x34; - tx_data[2] = 0x56; - tx_data[3] = 0x78; - tx_data[4] = 0x9A; - tx_data[5] = 0xBC; - tx_data[6] = 0xDE; - tx_data[7] = 0xFF; - - while(1){ - - if (Motor_CANBus_Send( &tx_header, tx_data, portMAX_DELAY) == CAN_ERR){} - - Toggle_LED(HB); - vTaskDelay(pdMS_TO_TICKS(1000)); - } -} - -int main(){ - - HAL_Init(); - - SystemClock_Config(); - __HAL_RCC_SYSCFG_CLK_ENABLE(); - __HAL_RCC_PWR_CLK_ENABLE(); - - LEDs_init(); - - - CAN_Init(); - - Init_UART_Printf(); - - - xTaskCreateStatic( - Task_CanTxTelemetry, // Task function - "Can TX Telemetry Thread", // Name of the task (for debugging) - configMINIMAL_STACK_SIZE, // Stack size in words - NULL, // Task input parameter - CAN_TX_TELEMETRY_THREAD_PRIO, // Task priority - Can_Tx_Telemetry_Task_Stack, // Task handle - &Can_Tx_Telemetry_Task_Buffer // Static task buffer (optional) - ); - - xTaskCreateStatic( - task, - "task", - 512, - NULL, - tskIDLE_PRIORITY + 2, - task_stack, - &task_buffer); - - - - vTaskStartScheduler(); - - - while(1){ - - } - return 0; -} \ No newline at end of file diff --git a/Firmware/tests/Contactors_test.c b/Firmware/tests/Contactors_test.c index 477494cf..e9c4056d 100644 --- a/Firmware/tests/Contactors_test.c +++ b/Firmware/tests/Contactors_test.c @@ -45,7 +45,7 @@ int main() { SystemClock_Config(); - LEDs_init(); + LED_init(); contactor_init(); diff --git a/Firmware/tests/FaultHandler_test.c b/Firmware/tests/FaultHandler_test.c deleted file mode 100644 index e7b9e7f5..00000000 --- a/Firmware/tests/FaultHandler_test.c +++ /dev/null @@ -1,41 +0,0 @@ -#include "FaultHandlerTask.h" -#include "PrechargeTask.h" -#include "StatusLEDs.h" -#include "inits.h" - -int main() -{ - if (HAL_Init() != HAL_OK) - Error_Handler(); - SystemClock_Config(); - __HAL_RCC_SYSCFG_CLK_ENABLE(); - __HAL_RCC_PWR_CLK_ENABLE(); - - Init_UART_Printf(); - LEDs_init(); - - // Task - xTaskCreateStatic( - Task_FaultHandler, // Task function - "FaultHandler", // Name of the task (for debugging) - configMINIMAL_STACK_SIZE, // Stack size in words - NULL, // Task input parameter - tskIDLE_PRIORITY + 2, // Task priority - FaultHandlerTask_Stack, // Task handle - &FaultHandlerTask_Buffer // Static task buffer (optional) - ); - - hprecharge_task = xTaskCreateStatic( - Task_Precharge, // Task function - "Precharge", // Name of the task (for debugging) - configMINIMAL_STACK_SIZE, // Stack size in words - NULL, // Task input parameter - tskIDLE_PRIORITY + 1, // Task priority - Precharge_Task_Stack, // Task handle - &Precharge_Task_Buffer // Static task buffer (optional) - ); - - vTaskStartScheduler(); - - return 0; -} \ No newline at end of file diff --git a/Firmware/tests/MotorController_test.c b/Firmware/tests/MotorController_test.c deleted file mode 100644 index 122e111c..00000000 --- a/Firmware/tests/MotorController_test.c +++ /dev/null @@ -1,67 +0,0 @@ -#include "CANbus.h" -#include "stm32xx_hal.h" -#include "inits.h" -#include "StatusLEDs.h" -#include "pinDefs.h" -#include "MotorTelemetryTask.h" -#include "MotorControlTask.h" - -#define PRINTF_DEBUG - - -void can_error_handler(){ - - while(1){ - HAL_GPIO_TogglePin(HB_LED_PORT, HB_LED_PIN); - HAL_Delay(500); - } -} - - -int main(){ - HAL_Init(); - - SystemClock_Config(); - __HAL_RCC_SYSCFG_CLK_ENABLE(); - __HAL_RCC_PWR_CLK_ENABLE(); - - LEDs_init(); - - - if(CAN_Init() != CAN_OK){ - can_error_handler(); - } - - MotorTelemetryTask_Init(); - MotorControlTask_Init(); - - MotorSafeBits_Init(); - - - Init_UART_Printf(); - - xTaskCreateStatic( - Task_MotorTelemetry, - "Motor Telemetry Task", - 512, - NULL, - tskIDLE_PRIORITY + 2, - Motor_Telemetry_Task_Stack, - &Motor_Telemetry_Task_Buffer); - - xTaskCreateStatic( - Task_MotorControl, - "Motor Control Task", - 512, - NULL, - tskIDLE_PRIORITY + 4, - Motor_Control_Task_Stack, - &Motor_Control_Task_Buffer); - - - vTaskStartScheduler(); - - while(1){ - - } -} diff --git a/Firmware/tests/MotorSafe_test.c b/Firmware/tests/MotorSafe_test.c index a8ad654f..eb945bfe 100644 --- a/Firmware/tests/MotorSafe_test.c +++ b/Firmware/tests/MotorSafe_test.c @@ -15,7 +15,7 @@ void waitTask(void *pvParameters){ while(1){ MotorSafeBits_WaitMask((motorDrivableBits), portMAX_DELAY); - Toggle_LED(CAR_DRIVABLE); + LED_toggle(CAR_DRIVABLE); vTaskDelay(pdMS_TO_TICKS(500)); } } @@ -48,7 +48,7 @@ int main(){ __HAL_RCC_SYSCFG_CLK_ENABLE(); __HAL_RCC_PWR_CLK_ENABLE(); - LEDs_init(); + LED_init(); Init_UART_Printf(); diff --git a/Firmware/tests/MotorTelemetryTask_test.c b/Firmware/tests/MotorTelemetryTask_test.c index df8b3fd7..9b3b5bc1 100644 --- a/Firmware/tests/MotorTelemetryTask_test.c +++ b/Firmware/tests/MotorTelemetryTask_test.c @@ -25,10 +25,10 @@ int main() __HAL_RCC_SYSCFG_CLK_ENABLE(); __HAL_RCC_PWR_CLK_ENABLE(); - LEDs_init(); + LED_init(); - if (CAN_Init() != CAN_OK) - { + + if(MotorCAN_Init() != CAN_OK){ can_error_handler(); } diff --git a/Firmware/tests/Precharge_test.c b/Firmware/tests/Precharge_test.c index 8ec5583f..643654ed 100644 --- a/Firmware/tests/Precharge_test.c +++ b/Firmware/tests/Precharge_test.c @@ -14,7 +14,7 @@ int main() __HAL_RCC_PWR_CLK_ENABLE(); // Initialize all LED GPIOs - LEDs_init(); + LED_init(); Init_UART_Printf(); diff --git a/Firmware/tests/blinky_test.c b/Firmware/tests/blinky_test.c index 3a848136..f49372e9 100644 --- a/Firmware/tests/blinky_test.c +++ b/Firmware/tests/blinky_test.c @@ -41,13 +41,13 @@ int main(){ */ // Initialize all LED GPIOs - LEDs_init(); + LED_init(); while (1) { // Turn LEDs on one-by-one - for (size_t i = 0; i < num_LEDs; ++i) + for (size_t i = 0; i < NUM_LEDS; ++i) { - Toggle_LED(i); + LED_toggle(i); HAL_Delay(200); } @@ -55,9 +55,9 @@ int main(){ HAL_Delay(500); // Turn LEDs off one-by-one - for (size_t i = 0; i < num_LEDs; ++i) + for (size_t i = 0; i < NUM_LEDS; ++i) { - Toggle_LED(i); + LED_toggle(i); HAL_Delay(200); } diff --git a/Firmware/tests/carcan_test.c b/Firmware/tests/carcan_test.c new file mode 100644 index 00000000..74981502 --- /dev/null +++ b/Firmware/tests/carcan_test.c @@ -0,0 +1,110 @@ +/** + * canbus test!! + * + * Sends and receives as 2 different tasks. + * For rx: send data from candapter at ID 0x123 to see an led blink + * For tx: use candapter to see if 123456789ABCDEFF is being received at 0x321 + * + */ + +#include "CANbus.h" +#include "StatusLEDs.h" +#include "inits.h" +#include "pinDefs.h" +#include "stm32xx_hal.h" + +#define TESTING_STACK_SIZE (configMINIMAL_STACK_SIZE * 8) + +StaticTask_t rx_task_buffer; +StackType_t rx_task_stack[TESTING_STACK_SIZE]; + +StaticTask_t tx_task_buffer; +StackType_t tx_task_stack[TESTING_STACK_SIZE]; + +#define TEST_CAN_ID_RX 0x123 +#define TEST_CAN_ID_TX 0x321 +#define TEST_CAN_DATA_TX {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF} +#define TEST_CAN_DATA_LENGTH 8 + +void can_error_handler() { + while (1) { + LED_set(MOTOR_FAULT, LED_ON); + } +} + +static void rx_task(void *pvParameters) { + FDCAN_RxHeaderTypeDef rx_header = {0}; + uint8_t rx_data[TEST_CAN_DATA_LENGTH] = {0}; + while (1) { + if (CarCAN_Recv(TEST_CAN_ID_RX, &rx_header, rx_data, portMAX_DELAY) == CAN_ERR) { + can_error_handler(); + } + + LED_toggle(PRECHARGE_COMPLETE); + + // Optional delay if the can recv isnt blocking + // vTaskDelay(pdMS_TO_TICKS(1000)); + } +} + +static void tx_task(void *pvParameters) { + FDCAN_TxHeaderTypeDef tx_header = {0}; + tx_header.Identifier = TEST_CAN_ID_TX; + tx_header.IdType = FDCAN_STANDARD_ID; + tx_header.TxFrameType = FDCAN_DATA_FRAME; + tx_header.DataLength = FDCAN_DLC_BYTES_8; + tx_header.ErrorStateIndicator = FDCAN_ESI_ACTIVE; + tx_header.BitRateSwitch = FDCAN_BRS_OFF; + tx_header.FDFormat = FDCAN_CLASSIC_CAN; + tx_header.TxEventFifoControl = FDCAN_NO_TX_EVENTS; + tx_header.MessageMarker = 0; + + uint8_t tx_data[TEST_CAN_DATA_LENGTH] = TEST_CAN_DATA_TX; + while (1) { + if (CarCAN_Send(&tx_header, tx_data, portMAX_DELAY) == CAN_ERR) { + can_error_handler(); + } + + LED_toggle(HB); + vTaskDelay(pdMS_TO_TICKS(1000)); + } +} + +int main() { + HAL_Init(); + + SystemClock_Config(); + __HAL_RCC_SYSCFG_CLK_ENABLE(); + __HAL_RCC_PWR_CLK_ENABLE(); + + LED_init(); + + if (CarCAN_Init() != CAN_OK) { + can_error_handler(); + } + + xTaskCreateStatic( + tx_task, + "tx_task", + TESTING_STACK_SIZE, + NULL, + tskIDLE_PRIORITY + 2, + tx_task_stack, + &tx_task_buffer + ); + + xTaskCreateStatic( + rx_task, + "rx_task", + TESTING_STACK_SIZE, + NULL, + tskIDLE_PRIORITY + 1, + rx_task_stack, + &rx_task_buffer + ); + + vTaskStartScheduler(); + + while (1) { + } +} \ No newline at end of file diff --git a/Firmware/tests/faulthandler_test.c b/Firmware/tests/faulthandler_test.c new file mode 100644 index 00000000..28eb0de3 --- /dev/null +++ b/Firmware/tests/faulthandler_test.c @@ -0,0 +1,45 @@ +#include "FaultHandlerTask.h" +#include "PrechargeTask.h" +#include "StatusLEDs.h" +#include "InitTask.h" +#include "inits.h" + +int main() +{ + if (HAL_Init() != HAL_OK) + Error_Handler(); + SystemClock_Config(); + __HAL_RCC_SYSCFG_CLK_ENABLE(); + __HAL_RCC_PWR_CLK_ENABLE(); + + Init_UART_Printf(); + LED_init(); + + faults_init(); + + + // Task + xTaskCreateStatic( + Task_FaultHandler, + "FaultHandler", + FAULT_HANDLER_TASK_STACK_SIZE, + NULL, + FAULT_HANDLER_THREAD_PRIO, + FaultHandler_Task_Stack, + &FaultHandler_Task_Buffer + ); + + precharge_task_handle = xTaskCreateStatic( + Task_Precharge, + "Precharge", + PRECHARGE_TASK_STACK_SIZE, + NULL, + PRECHARGE_THREAD_PRIO, + Precharge_Task_Stack, + &Precharge_Task_Buffer + ); + + vTaskStartScheduler(); + + return 0; +} \ No newline at end of file diff --git a/Firmware/tests/fsm_transition_test.c b/Firmware/tests/fsm_transition_test.c new file mode 100644 index 00000000..21010ed2 --- /dev/null +++ b/Firmware/tests/fsm_transition_test.c @@ -0,0 +1,80 @@ +/** + * VCU status test. + * + * Only enables vcu status task. This basically tests if the msg works (not + * really its interaction with other stuff). + * + * + */ + +#include "VCUStatusTask.h" +#include "UpdateVCUInputsTask.h" +#include "inits.h" +#include "InitTask.h" +#include "FSMTask.h" +// #include "" + +#define PRINTF_DEBUG + +void can_error_handler() { + while (1) { + HAL_GPIO_TogglePin(HB_LED_PORT, HB_LED_PIN); + HAL_Delay(500); + } +} + +int main() { + HAL_Init(); + + SystemClock_Config(); + __HAL_RCC_SYSCFG_CLK_ENABLE(); + __HAL_RCC_PWR_CLK_ENABLE(); + + LED_init(); + + if (CarCAN_Init() != CAN_OK) { + can_error_handler(); + } + + Init_UART_Printf(); + + faults_init(); + contactor_init(); + FSM_TaskInit(); + fsm_init(); + + xTaskCreateStatic( + Task_BroadcastVCUStatus, + "VCU status tx", + VCU_STATUS_TASK_STACK_SIZE, + NULL, + VCU_STATUS_THREAD_PRIO, + VCUStatus_Task_Stack, + &VCUStatus_Task_Buffer + ); + + xTaskCreateStatic( + Task_UpdateVCUInputs, + "Update FSM Inputs Thread", + UPDATE_VCU_INPUTS_STACK_SIZE, + NULL, + UPDATE_VCU_INPUTS_THREAD_PRIO, + UpdateVCUInputs_Task_Stack, + &UpdateVCUInputs_Task_Buffer + ); + + xTaskCreateStatic( + Task_FSM, + "FSM Thread", + FSM_TASK_STACK_SIZE, + NULL, + FSM_THREAD_PRIO, + FSM_Task_Stack, + &FSM_Task_Buffer + ); + + vTaskStartScheduler(); + + while (1) { + } +} diff --git a/Firmware/tests/fsminputs_test.c b/Firmware/tests/fsminputs_test.c new file mode 100644 index 00000000..8154cea1 --- /dev/null +++ b/Firmware/tests/fsminputs_test.c @@ -0,0 +1,70 @@ +/** + * VCU status test. + * + * Only enables vcu status task. This basically tests if the msg works (not + * really its interaction with other stuff). + * + * + */ + +#include "VCUStatusTask.h" +#include "UpdateVCUInputsTask.h" +#include "inits.h" +#include "InitTask.h" +#include "FSMTask.h" +// #include "" + +#define PRINTF_DEBUG + +void can_error_handler() { + while (1) { + HAL_GPIO_TogglePin(HB_LED_PORT, HB_LED_PIN); + HAL_Delay(500); + } +} + +int main() { + HAL_Init(); + + SystemClock_Config(); + __HAL_RCC_SYSCFG_CLK_ENABLE(); + __HAL_RCC_PWR_CLK_ENABLE(); + + LED_init(); + + if (CarCAN_Init() != CAN_OK) { + can_error_handler(); + } + + Init_UART_Printf(); + + faults_init(); + contactor_init(); + FSM_TaskInit(); + fsm_init(); + + xTaskCreateStatic( + Task_BroadcastVCUStatus, + "VCU status tx", + VCU_STATUS_TASK_STACK_SIZE, + NULL, + VCU_STATUS_THREAD_PRIO, + VCUStatus_Task_Stack, + &VCUStatus_Task_Buffer + ); + + xTaskCreateStatic( + Task_UpdateFSMInputs, + "Update FSM Inputs Thread", + UPDATE_FSM_INPUTS_STACK_SIZE, + NULL, + UPDATE_FSM_INPUTS_THREAD_PRIO, + UpdateFSMInputs_Task_Stack, + &UpdateFSMInputs_Task_Buffer + ); + + vTaskStartScheduler(); + + while (1) { + } +} diff --git a/Firmware/tests/motorControlTask_test.c b/Firmware/tests/motorControlTask_test.c deleted file mode 100644 index b2b902d8..00000000 --- a/Firmware/tests/motorControlTask_test.c +++ /dev/null @@ -1,54 +0,0 @@ -#include "CANbus.h" -#include "stm32xx_hal.h" -#include "inits.h" -#include "StatusLEDs.h" -#include "pinDefs.h" -#include "MotorControlTask.h" - -#define PRINTF_DEBUG - -StaticTask_t task_buffer; -StackType_t task_stack[512]; - -void can_error_handler(){ - - while(1){ - LED_set(MOTOR_FAULT, LED_ON); - } -} - - -int main(){ - HAL_Init(); - - SystemClock_Config(); - __HAL_RCC_SYSCFG_CLK_ENABLE(); - __HAL_RCC_PWR_CLK_ENABLE(); - - LEDs_init(); - - - if(CAN_Init() != CAN_OK){ - can_error_handler(); - } - - MotorControlTask_Init(); - - Init_UART_Printf(); - - xTaskCreateStatic( - Task_MotorControl, - "Motor Controller Task", - 512, - NULL, - tskIDLE_PRIORITY + 2, - task_stack, - &task_buffer); - - - vTaskStartScheduler(); - - while(1){ - - } -} \ No newline at end of file diff --git a/Firmware/tests/motorcan_test.c b/Firmware/tests/motorcan_test.c new file mode 100644 index 00000000..b5b6fb51 --- /dev/null +++ b/Firmware/tests/motorcan_test.c @@ -0,0 +1,110 @@ +/** + * canbus test!! + * + * Sends and receives as 2 different tasks. + * For rx: send data from candapter at ID 0x123 to see an led blink + * For tx: use candapter to see if 123456789ABCDEFF is being received at 0x321 + * + */ + +#include "CANbus.h" +#include "StatusLEDs.h" +#include "inits.h" +#include "pinDefs.h" +#include "stm32xx_hal.h" + +#define TESTING_STACK_SIZE (configMINIMAL_STACK_SIZE * 8) + +StaticTask_t rx_task_buffer; +StackType_t rx_task_stack[TESTING_STACK_SIZE]; + +StaticTask_t tx_task_buffer; +StackType_t tx_task_stack[TESTING_STACK_SIZE]; + +#define TEST_CAN_ID_RX 0x123 +#define TEST_CAN_ID_TX 0x321 +#define TEST_CAN_DATA_TX {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF} +#define TEST_CAN_DATA_LENGTH 8 + +void can_error_handler() { + while (1) { + LED_set(MOTOR_FAULT, LED_ON); + } +} + +static void rx_task(void *pvParameters) { + FDCAN_RxHeaderTypeDef rx_header = {0}; + uint8_t rx_data[TEST_CAN_DATA_LENGTH] = {0}; + while (1) { + if (MotorCAN_Recv(TEST_CAN_ID_RX, &rx_header, rx_data, portMAX_DELAY) == CAN_ERR) { + can_error_handler(); + } + + LED_toggle(PRECHARGE_COMPLETE); + + // Optional delay if the can recv isnt blocking + // vTaskDelay(pdMS_TO_TICKS(1000)); + } +} + +static void tx_task(void *pvParameters) { + FDCAN_TxHeaderTypeDef tx_header = {0}; + tx_header.Identifier = TEST_CAN_ID_TX; + tx_header.IdType = FDCAN_STANDARD_ID; + tx_header.TxFrameType = FDCAN_DATA_FRAME; + tx_header.DataLength = FDCAN_DLC_BYTES_8; + tx_header.ErrorStateIndicator = FDCAN_ESI_ACTIVE; + tx_header.BitRateSwitch = FDCAN_BRS_OFF; + tx_header.FDFormat = FDCAN_CLASSIC_CAN; + tx_header.TxEventFifoControl = FDCAN_NO_TX_EVENTS; + tx_header.MessageMarker = 0; + + uint8_t tx_data[TEST_CAN_DATA_LENGTH] = TEST_CAN_DATA_TX; + while (1) { + if (MotorCAN_Send(&tx_header, tx_data, portMAX_DELAY) == CAN_ERR) { + can_error_handler(); + } + + LED_toggle(HB); + vTaskDelay(pdMS_TO_TICKS(1000)); + } +} + +int main() { + HAL_Init(); + + SystemClock_Config(); + __HAL_RCC_SYSCFG_CLK_ENABLE(); + __HAL_RCC_PWR_CLK_ENABLE(); + + LED_init(); + + if (MotorCAN_Init() != CAN_OK) { + can_error_handler(); + } + + xTaskCreateStatic( + tx_task, + "tx_task", + TESTING_STACK_SIZE, + NULL, + tskIDLE_PRIORITY + 2, + tx_task_stack, + &tx_task_buffer + ); + + xTaskCreateStatic( + rx_task, + "rx_task", + TESTING_STACK_SIZE, + NULL, + tskIDLE_PRIORITY + 1, + rx_task_stack, + &rx_task_buffer + ); + + vTaskStartScheduler(); + + while (1) { + } +} \ No newline at end of file diff --git a/Firmware/tests/Printf_Init_test.c b/Firmware/tests/printf_test.c similarity index 53% rename from Firmware/tests/Printf_Init_test.c rename to Firmware/tests/printf_test.c index d6f7b2e5..d6536c1d 100644 --- a/Firmware/tests/Printf_Init_test.c +++ b/Firmware/tests/printf_test.c @@ -1,37 +1,36 @@ +#include "FreeRTOS.h" +#include "stm32xx_hal.h" #include "StatusLEDs.h" -#include "pinDefs.h" -#include "inits.h" #include "UART.h" -#include "projdefs.h" -#include "stm32xx_hal.h" -#include "printf.h" #include "UART_Init.h" +#include + StaticTask_t txTaskBuffer; StackType_t txTaskStack[configMINIMAL_STACK_SIZE]; -void TxTask(void *argument){ - - while(1){ +void TxTask(void *argument) { + while (true) { printf("Hello World! %s %d %f\n\r", "Test String", 5, 4.4); vTaskDelay(pdMS_TO_TICKS(1000)); } } int main(void) { - HAL_Init(); SystemClock_Config(); Init_UART_Printf(); - xTaskCreateStatic(TxTask, - "TX", - configMINIMAL_STACK_SIZE, - NULL, - tskIDLE_PRIORITY + 2, - txTaskStack, - &txTaskBuffer); + xTaskCreateStatic( + TxTask, + "TX", + configMINIMAL_STACK_SIZE, + NULL, + tskIDLE_PRIORITY + 2, + txTaskStack, + &txTaskBuffer + ); vTaskStartScheduler(); diff --git a/Firmware/tests/vcustatus_test.c b/Firmware/tests/vcustatus_test.c new file mode 100644 index 00000000..a36e8f8a --- /dev/null +++ b/Firmware/tests/vcustatus_test.c @@ -0,0 +1,59 @@ +/** + * VCU status test. + * + * Only enables vcu status task. This basically tests if the msg works (not + * really its interaction with other stuff). + * + * + */ + +#include "VCUStatusTask.h" +#include "inits.h" +#include "InitTask.h" +#include "FSM.h" +// #include "" + +#define PRINTF_DEBUG + +void can_error_handler() { + while (1) { + HAL_GPIO_TogglePin(HB_LED_PORT, HB_LED_PIN); + HAL_Delay(500); + } +} + +int main() { + HAL_Init(); + + SystemClock_Config(); + __HAL_RCC_SYSCFG_CLK_ENABLE(); + __HAL_RCC_PWR_CLK_ENABLE(); + + LED_init(); + + if (CarCAN_Init() != CAN_OK) { + can_error_handler(); + } + + Init_UART_Printf(); + + faults_init(); + contactor_init(); + FSM_TaskInit(); + fsm_init(); + + xTaskCreateStatic( + Task_BroadcastVCUStatus, + "VCU status tx", + VCU_STATUS_TASK_STACK_SIZE, + NULL, + VCU_STATUS_THREAD_PRIO, + VCUStatus_Task_Stack, + &VCUStatus_Task_Buffer + ); + + vTaskStartScheduler(); + + while (1) { + } +} diff --git a/KiCAD-Bild b/KiCAD-Bild new file mode 160000 index 00000000..c4713377 --- /dev/null +++ b/KiCAD-Bild @@ -0,0 +1 @@ +Subproject commit c471337769c733b3db7bfcbf68b52eb2a727f807 diff --git a/VehicleControlUnitLib/UTSVT-KiCadLibraries b/VehicleControlUnitLib/UTSVT-KiCadLibraries new file mode 160000 index 00000000..6eca31ff --- /dev/null +++ b/VehicleControlUnitLib/UTSVT-KiCadLibraries @@ -0,0 +1 @@ +Subproject commit 6eca31ff4859b771102042364b7d2128e8f0f684