Conversation
Summary of ChangesHello @adiv06, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request lays the groundwork for the vehicle's motor control system by introducing a comprehensive Finite State Machine (FSM) architecture. It establishes the necessary CAN communication interfaces for both receiving driver inputs and sending commands to the motor controller. A critical aspect of this work is the integration of a robust fault handling system and a CAN watchdog, designed to ensure system stability and provide mechanisms for recovery or safe shutdown. The changes also include the setup of FreeRTOS tasks to orchestrate these components, forming a foundational embedded software structure. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a significant architectural change by implementing a motor control finite state machine (FSM) using FreeRTOS. The new architecture includes dedicated tasks for the FSM, fault handling, and a CAN watchdog. While this is a good direction, the code in its current state is not ready for merging. It contains several critical issues that prevent compilation, such as multiple CAN signals sharing the same ID, incorrect definitions of global variables in header files leading to linker errors, and numerous undefined variables and functions. My review focuses on these fundamental blocking issues that need to be addressed before a proper logic review can be conducted.
| } | ||
|
|
||
| void init() { | ||
| assert(FSM_SIGNAL_COUNT != SEND_TRITIUM_IDS); //ensuring signal for every ID |
There was a problem hiding this comment.
This assertion assert(FSM_SIGNAL_COUNT != SEND_TRITIUM_IDS) will always fail and halt the program because both FSM_SIGNAL_COUNT and SEND_TRITIUM_IDS are defined as 8. Based on the comment "ensuring signal for every ID", it seems you intend to check for equality.
assert(FSM_SIGNAL_COUNT == SEND_TRITIUM_IDS); //ensuring signal for every ID|
@gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a significant amount of new infrastructure for the motor controller's finite state machine, including CAN message definitions, fault handling, watchdog timers, and the core FSM logic. The overall architecture is well-structured. My review focuses on improving code quality, maintainability, and correctness. I've identified several instances of code duplication that can be refactored, some unprofessional naming conventions, and a few critical logic errors that need to be addressed. Additionally, there are some configurations set for testing (like CAN loopback mode) that will need to be changed for production, and some uses of printf in time-sensitive contexts that should be replaced with a more robust logging solution.
Note: Security Review did not run due to the size of the PR.
| if (status->LWS_OK) { | ||
| faults_throw_fault(FAULT_ID_STEERING_SENSOR_BAD_DATA); | ||
| } |
There was a problem hiding this comment.
This logic appears to be inverted. A fault is thrown if status->LWS_OK is true. The name LWS_OK suggests the sensor is functioning correctly, so a fault should likely be thrown when !status->LWS_OK. Please verify this logic.
| if (status->LWS_OK) { | |
| faults_throw_fault(FAULT_ID_STEERING_SENSOR_BAD_DATA); | |
| } | |
| if (!status->LWS_OK) { | |
| faults_throw_fault(FAULT_ID_STEERING_SENSOR_BAD_DATA); | |
| } |
| &wd_buffers[wd_count] | ||
| ); | ||
| configASSERT(t != NULL); | ||
| wd_timers[wd_count] = t; |
There was a problem hiding this comment.
The timer handle is being stored at wd_timers[wd_count], but it is accessed elsewhere using wd_timers[idx]. This implementation is fragile and will fail if watchdog indices are not created in a strictly sequential order starting from 0. To make this more robust, you should use idx to index the wd_timers array here as well.
| wd_timers[wd_count] = t; | |
| wd_timers[idx] = t; |
| if (bps_status.BPS_Regen_OK) s |= READY_TO_REGEN_BIT; | ||
| if (precharge_complete) s |= PRECHARGE_COMPLETE_BIT; | ||
|
|
||
| accel_pedal_pct = accel_brake.Accel_Pos_Main; |
There was a problem hiding this comment.
The raw uint8_t value from accel_brake.Accel_Pos_Main is being directly cast to a float and used as the motor current setpoint. This value should be scaled to a percentage (e.g., 0.0 to 1.0) before being used. The provided map_to_percent function appears to be designed for this purpose and should be used here.
accel_pedal_pct = map_to_percent(accel_brake.Accel_Pos_Main, 0, 255, 0, 100); // TODO: Use calibrated min/max pedal values| } vcu_status_vcu_fault_e; | ||
|
|
||
| typedef enum { | ||
| BBPDU_SET_SWITCHES_HSS_CONTROL_13_DO_NOTHING_YOU_RE_STUPID = 3, |
There was a problem hiding this comment.
The enum member name BBPDU_SET_SWITCHES_HSS_CONTROL_13_DO_NOTHING_YOU_RE_STUPID is unprofessional. Please use professional and descriptive names for all enum members, variables, and functions. This applies to several other similar enum definitions in this file. A more appropriate name could be BBPDU_SET_SWITCHES_HSS_CONTROL_13_INVALID or BBPDU_SET_SWITCHES_HSS_CONTROL_13_RESERVED.
| #define CAN_ID_MC_DRIVECOMMAND 0x401 | ||
| #define CAN_ID_MC_POWERCOMMAND 0x402 | ||
| #define CAN_ID_MC_RESETCOMMAND 0x403 | ||
| #define CAN_ID_MC_INFO 0x420 | ||
| #define CAN_ID_MC_STATUS 0x421 | ||
| #define CAN_ID_MC_BUSMEASUREMENT 0x422 | ||
| #define CAN_ID_MC_VELOCITYMEASUREMENT 0x423 | ||
| #define CAN_ID_MC_PHASECURRENTMEASUREMENT 0x424 | ||
| #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_MOTOR_TEMPMEASUREMENT 0x42B | ||
| #define CAN_ID_MC_DSPBOARDTEMPMEASUREMENT 0x42C | ||
| #define CAN_ID_MC_ODOMETERBUSAHMEASUREMENT 0x42E | ||
| #define CAN_ID_MC_SLIPSPEEDMEASUREMENT 0x437 |
There was a problem hiding this comment.
These CAN ID macros are already defined in MotorCAN_can_msgs.h. Redefining them here creates code duplication and increases the risk of inconsistencies if one file is updated and the other is not. Please remove these definitions and include MotorCAN_can_msgs.h instead.
| #define CAN_ID_MC_DRIVECOMMAND 0x401 | |
| #define CAN_ID_MC_POWERCOMMAND 0x402 | |
| #define CAN_ID_MC_RESETCOMMAND 0x403 | |
| #define CAN_ID_MC_INFO 0x420 | |
| #define CAN_ID_MC_STATUS 0x421 | |
| #define CAN_ID_MC_BUSMEASUREMENT 0x422 | |
| #define CAN_ID_MC_VELOCITYMEASUREMENT 0x423 | |
| #define CAN_ID_MC_PHASECURRENTMEASUREMENT 0x424 | |
| #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_MOTOR_TEMPMEASUREMENT 0x42B | |
| #define CAN_ID_MC_DSPBOARDTEMPMEASUREMENT 0x42C | |
| #define CAN_ID_MC_ODOMETERBUSAHMEASUREMENT 0x42E | |
| #define CAN_ID_MC_SLIPSPEEDMEASUREMENT 0x437 | |
| #include "MotorCAN_can_msgs.h" |
| { | ||
| "name": "Linux", | ||
| "includePath": [ | ||
| "${workspaceFolder}/**", |
There was a problem hiding this comment.
| static void wd_callback(TimerHandle_t xTimer) { | ||
| uint8_t idx = (uint8_t)(uintptr_t)pvTimerGetTimerID(xTimer); | ||
| wd_alive[idx] = false; | ||
| printf("WD timeout: signal %d\n", idx); |
There was a problem hiding this comment.
|
|
||
| for (int i = 0; i < FAULT_ID_COUNT; i++) { | ||
| if (active & (1U << i)) { | ||
| printf("[FAULT] %s (bit %d) \n", fault_names[i], i); |
There was a problem hiding this comment.
| typedef struct { | ||
| uint8_t BPS_Tap_ID; | ||
| uint8_t BPS_VoltTemp_BQ_Fault; | ||
| uint8_t BPS_Temperature_Tap_Fault; | ||
| uint16_t BPS_Voltage_Tap_Data; | ||
| int16_t BPS_Temperature_Tap_Data; | ||
| uint16_t BPS_Temperature_Tap_RawV; | ||
| } bps_voltage_temperature_0_t; | ||
|
|
||
| typedef struct { | ||
| uint8_t BPS_Tap_ID; | ||
| uint8_t BPS_VoltTemp_BQ_Fault; | ||
| uint8_t BPS_Temperature_Tap_Fault; | ||
| uint16_t BPS_Voltage_Tap_Data; | ||
| int16_t BPS_Temperature_Tap_Data; | ||
| uint16_t BPS_Temperature_Tap_RawV; | ||
| } bps_voltage_temperature_1_t; | ||
|
|
||
| typedef struct { | ||
| uint8_t BPS_Tap_ID; | ||
| uint8_t BPS_VoltTemp_BQ_Fault; | ||
| uint8_t BPS_Temperature_Tap_Fault; | ||
| uint16_t BPS_Voltage_Tap_Data; | ||
| int16_t BPS_Temperature_Tap_Data; | ||
| uint16_t BPS_Temperature_Tap_RawV; | ||
| } bps_voltage_temperature_2_t; | ||
|
|
||
| typedef struct { | ||
| uint8_t BPS_Tap_ID; | ||
| uint8_t BPS_VoltTemp_BQ_Fault; | ||
| uint8_t BPS_Temperature_Tap_Fault; | ||
| uint16_t BPS_Voltage_Tap_Data; | ||
| int16_t BPS_Temperature_Tap_Data; | ||
| uint16_t BPS_Temperature_Tap_RawV; | ||
| } bps_voltage_temperature_3_t; | ||
|
|
||
| typedef struct { | ||
| uint8_t BPS_Tap_ID; | ||
| uint8_t BPS_VoltTemp_BQ_Fault; | ||
| uint8_t BPS_Temperature_Tap_Fault; | ||
| uint16_t BPS_Voltage_Tap_Data; | ||
| int16_t BPS_Temperature_Tap_Data; | ||
| uint16_t BPS_Temperature_Tap_RawV; | ||
| } bps_voltage_temperature_4_t; | ||
|
|
||
| typedef struct { | ||
| uint8_t BPS_Tap_ID; | ||
| uint8_t BPS_VoltTemp_BQ_Fault; | ||
| uint8_t BPS_Temperature_Tap_Fault; | ||
| uint16_t BPS_Voltage_Tap_Data; | ||
| int16_t BPS_Temperature_Tap_Data; | ||
| uint16_t BPS_Temperature_Tap_RawV; | ||
| } bps_voltage_temperature_5_t; | ||
|
|
||
| typedef struct { | ||
| uint8_t BPS_Tap_ID; | ||
| uint8_t BPS_VoltTemp_BQ_Fault; | ||
| uint8_t BPS_Temperature_Tap_Fault; | ||
| uint16_t BPS_Voltage_Tap_Data; | ||
| int16_t BPS_Temperature_Tap_Data; | ||
| uint16_t BPS_Temperature_Tap_RawV; | ||
| } bps_voltage_temperature_6_t; | ||
|
|
||
| typedef struct { | ||
| uint8_t BPS_Tap_ID; | ||
| uint8_t BPS_VoltTemp_BQ_Fault; | ||
| uint8_t BPS_Temperature_Tap_Fault; | ||
| uint16_t BPS_Voltage_Tap_Data; | ||
| int16_t BPS_Temperature_Tap_Data; | ||
| uint16_t BPS_Temperature_Tap_RawV; | ||
| } bps_voltage_temperature_7_t; |
There was a problem hiding this comment.
| ((uint8_t)precharge_complete << 0) | // Motor_Contactor_State | ||
| ((uint8_t)precharge_complete << 1) | // Motor_Precharge_Contactor_State | ||
| ((uint8_t)precharge_complete << 2) | // Motor_Ready_To_Drive |
There was a problem hiding this comment.
The motor contactor state and ready-to-drive status are all derived from the precharge_complete flag. This is likely a placeholder, but it's important to note that for the final implementation, these status bits should reflect the actual hardware state. For example, contactor state should be based on feedback from the BPS or other relevant sensors, not just the VCU's internal precharge status.
DO NOT MERGE YET.
Implementation for motor FSM. I made the architecture so more things can be added later, but just wanted to make sure it looked right.
TODO: