diff --git a/Inverter/Code Overview - Map.png b/Inverter/Code Overview - Map.png new file mode 100644 index 0000000..84a5cb6 Binary files /dev/null and b/Inverter/Code Overview - Map.png differ diff --git a/Inverter/Inverter.ino b/Inverter/Inverter.ino new file mode 100644 index 0000000..0fca4f9 --- /dev/null +++ b/Inverter/Inverter.ino @@ -0,0 +1,129 @@ +// Headers for each sensor type +#include "src/InverterDebug.h" +//... +#include "src/Inverter.h" + +#include "src/Serial_CAN_Module.h" + +#include "Base.h" +#include "Sensor.h" +#include "Actuator.h" +#define NUMSENSORS 1 //Or however many +#define NUMACTUATORS 1 //Or however many +#define BAUDRATE 115200 +#define THISARDUINO ARDUINO_ONE + +#define CANBAUD 9600 +#define CANTX 10 +#define CANRX 11 + +Serial_CAN canbus(); + +// Objects for each sensor +InverterDebug inverterDebug(&canbus, THISARDUINO); +//... +Inverter inverter(&canbus, THISARDUINO); +//... + +Sensor* sensors[NUMSENSORS] = { + &inverterDebug +}; + +Actuator* actuators[NUMACTUATORS] = { + &inverter +}; + +// !#!#!#!--- EVERYTHING AFTER HERE DOES NOT NEED TO BE CHANGED FOR SENSOR IMPLEMENTATION ---!#!#!#! + +void setup(){ + Serial.begin(BAUDRATE); + canbus.begin(CANTX, CANRX, CANBAUD); + + bool success = true; + for(int i = 0; i < NUMSENSORS; i++){ + SensorState* state = sensors[i]->begin(); + // Print/send sensor post-setup state data here. For example: + bool _success = (state->error == ERR_NONE); + if(_success){ + Serial.print("Sensor "); + Serial.print(sensors[i]->sensor); + Serial.println(" initialized."); + } else { + Serial.print("Sensor "); + Serial.print(sensors[i]->sensor); + Serial.println(" failed to initialize!"); + } + success &= _success; + } + for(int i = 0; i < NUMACTUATORS; i++){ + ActuatorState* state = actuators[i]->begin(); + // Print/send sensor post-setup state data here. For example: + bool _success = (state->error == ERR_NONE); + if(_success){ + Serial.print("Actuator "); + Serial.print(actuators[i]->actuator); + Serial.print(" initialized. "); + + state = actuators[i]->update(); // Initial set to default target + _success = (state->error == ERR_NONE); + if(_success){ + Serial.print("Set to "); + Serial.println(state->target); + } else { + Serial.print("\nActuator "); + Serial.print(sensors[i]->sensor); + Serial.println(" failed to set!"); + } + } else { + Serial.print("Actuator "); + Serial.print(sensors[i]->sensor); + Serial.println(" failed to initialize!"); + } + success &= _success; + } + if(!success){ + Serial.println("POST failed on one or more devices, freezing..."); + while(1){delay(1000);} + } +} + +void loop(){ + for(int i = 0; i < NUMSENSORS; i++){ + SensorState* state = sensors[i]->update(); + // Print/send sensor post-setup state data here. For example: + bool _success = (state->error == ERR_NONE); + bool _new = (state->debug == DS_SUCCESS); + if(_success && _new) { + Serial.print("Sensor "); + Serial.print(sensors[i]->sensor); + Serial.print(" read success: "); + for(int x = 0; x < state->numdata; x++) { + Serial.print(state->data[x].data); + Serial.print(' '); + Serial.print(state->data[x].units); + if(x < state->numdata-1){Serial.print(", ");} + } + } else if (!_success) { + Serial.print("Sensor "); + Serial.print(sensors[i]->sensor); + Serial.println(" failed to update!"); + // TODO: Recover failed sensor? + } + } + for(int i = 0; i < NUMACTUATORS; i++){ + ActuatorState* state = actuators[i]->update(); + + bool _success = (state->error == ERR_NONE) && (state->debug == DS_SUCCESS); + if(_success){ + Serial.print("Actuator "); + Serial.print(actuators[i]->actuator); + Serial.print(" set success: "); + Serial.println(state->target); + } else { + Serial.print("Actuator "); + Serial.print(actuators[i]->actuator); + Serial.println(" failed to set!"); + // TODO: Recover failed sensor? + } + } +} \ No newline at end of file diff --git a/Inverter/README.md b/Inverter/README.md new file mode 100644 index 0000000..eab40f8 --- /dev/null +++ b/Inverter/README.md @@ -0,0 +1,68 @@ +# Serial CAN Bus + +> Documentation for the **Serial CAN Bus** can be found [here](https://drive.google.com/drive/folders/1rzmLET68QOWb4At4mAyN4rDsj-VGBLyh?usp=sharing). + + +## Todo + +- [ ] Setup, testing, and expected output documentation (screenshot, pictures, logs/stack traces, etc.); +- [ ] A list of dependencies (and links to those); +- [ ] Everything else that is listed under [the master `README`](../README.md). +
+
+ +# PM100 Inverter/Controller CAN Bus Message Reference + +> Prepared by Adam Pietrewicz, adapted to Markdown by Jayden Lefebvre (@JLefebvre55) +> +> Last Updated - July 14th 2021 + +*** + +## Broadcast Messages + +> CAN ID: `0x0A0-0x0AF`. See doc for example implementation (pgs. 4-5) and per-byte breakdown (pgs. 5-11). + +| Address | Frequency | Content | CAN Active Messages (Low Word) | +|-----------|---------------|---------------------------------------------------------|----------------------------------| +| `0x0A0` | Slow/10Hz | Temperatures #1 | `0x0001` | +| `0x0A1` | Slow/10Hz | Temperatures #2 | `0x0002` | +| `0x0A2` | Slow/10Hz | Temperatures #3 | `0x0004` | +| `0x0A3` | Fast/100Hz | Analog Inputs Voltages | `0x0008` | +| `0x0A4` | Fast/100Hz | Digital Input Status | `0x0010` | +| `0x0A5` | Fast/100Hz | Motor Position Information | `0x0020` | +| `0x0A6` | Fast/100Hz | Current Information | `0x0040` | +| `0x0A7` | Fast/100Hz | Voltage Information | `0x0080` | +| `0x0A8` | Fast/100Hz | Flux Information | `0x0100` | +| `0x0A9` | Slow/10Hz | Internal Voltages | `0x0200` | +| `0x0AA` | Fast/100Hz | Internal States | `0x0400` | +| `0x0AB` | Fast/100Hz | Fault Codes | `0x0800` | +| `0x0AC` | Fast/100Hz | Torque & Timer Information | `0x1000` | +| `0x0AD` | Fast/100Hz | Modulation Index & Flux Weakening
Output Information | `0x2000` | +| `0x0AE` | Slow/10Hz | Firmware Information | `0x4000` | +| `0x0AF` | 100Hz (fixed) | Diagnostic Data | `0x8000` | + +*** +## Command Messages + +> CAN ID: `0x0C0`. See doc for example implementation (pgs. 2-3). + +| Byte(s) | Name | Format | Description | +|----------|------------------------|------------------|------------------------------------------------------------------------------------------------------------------------| +| 0, 1 | Torque Command | Torque | Torque command used when in torque mode. | +| 2, 3 | Speed Command | Angular Velocity | Speed command used when in speed mode. | +| 4 | Direction Command | Boolean | `0` - "Reverse", `1` - "Forward" (See Section 2.3.2.2) | +| 5: Bit 0 | Inverter Enable | Boolean | `0` - Inverter Off, `1` - Inverter On | +| 5: Bit 1 | Inverter Discharge | Boolean | `0` - Disable Discharge, `1` - Enable Discharge | +| 5, 2 | Speed Mode Enable | Boolean | `0` - Do not override mode, `1` - Overrides from torque
mode to speed mode ONLY (See "Using Speed Mode" in manual) | +| 6, 7 | Commanded Torque Limit | Torque | Motor and Regen Torque limits. If set to `0`, default
torque limit from EEPROM is used. | + +*** +## Parameter Messages + +> Sets EEPROM parameters. + +**CAN ID `0x0C1`** - Used to send message *to* controller. + +**CAN ID `0x0C2`** - Response *from* controller. +*** \ No newline at end of file diff --git a/Inverter/old/BROADCAST_FAULTS.cpp b/Inverter/old/BROADCAST_FAULTS.cpp new file mode 100644 index 0000000..ee2e6df --- /dev/null +++ b/Inverter/old/BROADCAST_FAULTS.cpp @@ -0,0 +1,270 @@ +//#include +//#include +//#include +#include +#include +//#include +#include +#include + +using namespace std; + +PM100_FAULT_CODE FAULT_CODE_ARRAY[65] = { + //POST FAULTS + //Byte 0 + Hardware_Gate_Desaturation_Fault, + HW_Over_current_Fault, + Accelerator_Shorted, + Accelerator_Open, + Current_Sensor_Low, + Current_Sensor_High, + Module_Temperature_Low, + Module_Temperature_High, + //Byte 1 + Control_PCB_Temperature_Low, + Control_PCB_Temperature_High, + Gate_Drive_PCB_Temperature_Low, + Gate_Drive_PCB_Temperature_High, + Sense_Voltage_Low_5V, + Sense_Voltage_High_5V, + Sense_Voltage_Low_12V, + Sense_Voltage_High_12V, + //Byte 2 + Sense_Voltage_Low_2_5V, + Sense_Voltage_High_2_5V, + Sense_Voltage_Low_1_5V, + Sense_Voltage_High_1_5V, + DC_Bus_Voltage_High, + DC_Bus_Voltage_Low, + Pre_charge_Timeout, + Pre_charge_Voltage_Failure, + //Byte 3 + EEPROM_Checksum_Invalid, + EEPROM_Data_Out_of_Range, + EEPROM_Update_Required, + RESERVED_1, + RESERVED_2, + RESERVED_3, + Brake_Shorted, + Brake_Open, + //Byte 4 + //RUN FAULTS + Motor_Over_speed_Fault, + Over_current_Fault, + Over_voltage_Fault, + Inverter_Over_temperature_Fault, + Accelerator_Input_Shorted_Fault, + Accelerator_Input_Open_Fault, + Direction_Command_Fault, + Inverter_Response_Time_out_Fault, + //Byte 5 + Hardware_Gate_Desaturation_RUN_Fault, + Hardware_Over_current_Fault, + Under_voltage_Fault, + CAN_Command_Message_Lost_Fault, + Motor_Over_temperature_Fault, + RESERVED_4, + RESERVED_5, + RESERVED_6, + //Byte 6 + Brake_Input_Shorted_Fault, + Brake_Input_Open_Fault, + Module_A_Over_temperature_Fault, + Module_B_Over_temperature_Fault, + Module_C_Over_temperature_Fault, + PCB_Over_temperature_Fault, + Gate_Drive_Board_1_Over_temperature_Fault, + Gate_Drive_Board_2_Over_temperature_Fault, + //Byte 7 + Gate_Drive_Board_3_Over_temperature_Fault, + Current_Sensor_Fault, + RESERVED_7, + Hardware_Over_Voltage_Fault, + RESERVED_8, + RESERVED_9, + Resolver_Not_Connected, + Inverter_Discharge_Active, + + //Finally, error if the CAN mssg is NOT for fault codes + NOT_FAULT_CAN_MSSG + +}; + + +std::ostream& operator<<(std::ostream& lhs, PM100_FAULT_CODE fault) { + + switch(fault) { + + case Hardware_Gate_Desaturation_Fault: lhs << "Hardware_Gate_Desaturation_Fault"; break; + case HW_Over_current_Fault: lhs << "HW_Over_current_Fault"; break; + case Accelerator_Shorted: lhs << "Accelerator_Shorted"; break; + case Accelerator_Open: lhs << "Accelerator_Open"; break; + case Current_Sensor_Low: lhs << "Current_Sensor_Low"; break; + case Current_Sensor_High: lhs << "Current_Sensor_High"; break; + case Module_Temperature_Low: lhs << "Module_Temperature_Low"; break; + case Module_Temperature_High: lhs << "Module_Temperature_High"; break; + case Control_PCB_Temperature_Low: lhs << "Control_PCB_Temperature_Low"; break; + case Control_PCB_Temperature_High: lhs << "Control_PCB_Temperature_High"; break; + case Gate_Drive_PCB_Temperature_Low: lhs << "Gate_Drive_PCB_Temperature_Low"; break; + case Gate_Drive_PCB_Temperature_High: lhs << "Gate_Drive_PCB_Temperature_High"; break; + case Sense_Voltage_Low_5V: lhs << "Sense_Voltage_Low_5V"; break; + case Sense_Voltage_High_5V: lhs << "Sense_Voltage_High_5V"; break; + case Sense_Voltage_Low_12V: lhs << "Sense_Voltage_Low_12V"; break; + case Sense_Voltage_High_12V: lhs << "Sense_Voltage_High_12V"; break; + case Sense_Voltage_Low_2_5V: lhs << "Sense_Voltage_Low_2_5V"; break; + case Sense_Voltage_High_2_5V: lhs << "Sense_Voltage_High_2_5V"; break; + case Sense_Voltage_Low_1_5V: lhs << "Sense_Voltage_Low_1_5V"; break; + case Sense_Voltage_High_1_5V: lhs << "Sense_Voltage_High_1_5V"; break; + case DC_Bus_Voltage_High: lhs << "DC_Bus_Voltage_High"; break; + case DC_Bus_Voltage_Low: lhs << "DC_Bus_Voltage_Low"; break; + case Pre_charge_Timeout: lhs << "Pre_charge_Timeout"; break; + case Pre_charge_Voltage_Failure: lhs << "Pre_charge_Voltage_Failure"; break; + case EEPROM_Checksum_Invalid: lhs << "EEPROM_Checksum_Invalid"; break; + case EEPROM_Data_Out_of_Range: lhs << "EEPROM_Data_Out_of_Range"; break; + case EEPROM_Update_Required: lhs << "EEPROM_Update_Required"; break; + case RESERVED_1: lhs << "RESERVED_1"; break; + case RESERVED_2: lhs << "RESERVED_2"; break; + case RESERVED_3: lhs << "RESERVED_3"; break; + case Brake_Shorted: lhs << "Brake_Shorted"; break; + case Brake_Open: lhs << "Brake_Open"; break; + case Motor_Over_speed_Fault: lhs << "Motor_Over_speed_Fault"; break; + case Over_current_Fault: lhs << "Over_current_Fault"; break; + case Over_voltage_Fault: lhs << "Over_voltage_Fault"; break; + case Inverter_Over_temperature_Fault: lhs << "Inverter_Over_temperature_Fault"; break; + case Accelerator_Input_Shorted_Fault: lhs << "Accelerator_Input_Shorted_Fault"; break; + case Accelerator_Input_Open_Fault: lhs << "Accelerator_Input_Open_Fault"; break; + case Direction_Command_Fault: lhs << "Direction_Command_Fault"; break; + case Inverter_Response_Time_out_Fault: lhs << "Inverter_Response_Time_out_Fault"; break; + case Hardware_Gate_Desaturation_RUN_Fault: lhs << "Hardware_Gate_Desaturation_RUN_Fault"; break; + case Hardware_Over_current_Fault: lhs << "Hardware_Over_current_Fault"; break; + case Under_voltage_Fault: lhs << "Under_voltage_Fault"; break; + case CAN_Command_Message_Lost_Fault: lhs << "CAN_Command_Message_Lost_Fault"; break; + case Motor_Over_temperature_Fault: lhs << "Motor_Over_temperature_Fault"; break; + case RESERVED_4: lhs << "RESERVED_4"; break; + case RESERVED_5: lhs << "RESERVED_5"; break; + case RESERVED_6: lhs << "RESERVED_6"; break; + case Brake_Input_Shorted_Fault: lhs << "Brake_Input_Shorted_Fault"; break; + case Brake_Input_Open_Fault: lhs << "Brake_Input_Open_Fault"; break; + case Module_A_Over_temperature_Fault: lhs << "Module_A_Over_temperature_Fault"; break; + case Module_B_Over_temperature_Fault: lhs << "Module_B_Over_temperature_Fault"; break; + case Module_C_Over_temperature_Fault: lhs << "Module_C_Over_temperature_Fault"; break; + case PCB_Over_temperature_Fault: lhs << "PCB_Over_temperature_Fault"; break; + case Gate_Drive_Board_1_Over_temperature_Fault: lhs << "Gate_Drive_Board_1_Over_temperature_Fault"; break; + case Gate_Drive_Board_2_Over_temperature_Fault: lhs << "Gate_Drive_Board_2_Over_temperature_Fault"; break; + case Gate_Drive_Board_3_Over_temperature_Fault: lhs << "Gate_Drive_Board_3_Over_temperature_Fault"; break; + case Current_Sensor_Fault: lhs << "Current_Sensor_Fault"; break; + case RESERVED_7: lhs << "RESERVED_7"; break; + case Hardware_Over_Voltage_Fault: lhs << "Hardware_Over_Voltage_Fault"; break; + case RESERVED_8: lhs << "RESERVED_8"; break; + case RESERVED_9: lhs << "RESERVED_9"; break; + case Resolver_Not_Connected: lhs << "Resolver_Not_Connected"; break; + case Inverter_Discharge_Active: lhs << "Inverter_Discharge_Active"; break; + case NOT_FAULT_CAN_MSSG: lhs << "ERROR - This CAN Message is NOT for FAULT CODES!"; break; + } + + return lhs; +} + + +int return_fault_index_val( PM100_FAULT_CODE fault ){ + + int index_value = fault; + return index_value; +} + + + +std::vector broadcast_message::read_fault_codes_VER_2( int CAN_mssg[9] ){ + + //extract the CAN ID & define return vector of fault codes + int CAN_ID = CAN_mssg[0]; + vector faults_found; + PM100_FAULT_CODE fault; + + //check if CAN message is FAULT message + if( CAN_ID != 0x0AB ){ + cout << NOT_FAULT_CAN_MSSG; + faults_found.push_back( NOT_FAULT_CAN_MSSG ); + } + else if( CAN_ID == 0x0AB ){ + + int fault_code_index = 0; //var used for indexing fault code array + + //here we'll loop 8 times, analyze each CAN data byte + for( int i = 1; i < 9; i++ ){ + + int byte_i = CAN_mssg[i]; + cout << "Byte " << i << " Faults: " << endl; + + //vars to check each bit of current byte + int current_bit; + int int_to_binary = byte_i; + for( int i = 0; i < 8; i++ ){ + + current_bit = int_to_binary % 2; + int_to_binary = int_to_binary / 2; + + if( current_bit ){ + fault = FAULT_CODE_ARRAY[ fault_code_index + i ]; + cout << " " << fault << " -- Fault #" << return_fault_index_val( fault ) << endl; + faults_found.push_back( fault ); + } + } + + fault_code_index = fault_code_index + 8; + } + + } + + return faults_found; +} + + + + + + +int main(){ + + cout << "----------------------------------------------------------------" << endl; + cout << "- -" << endl; + cout << "- CAN PM100 -" << endl; + cout << "- Fault Code Function Testing -" << endl; + cout << "- -" << endl; + cout << "- -" << endl; + cout << "- -" << endl; + cout << "----------------------------------------------------------------\n" << endl; + + cout << "< Hello there! Here we'll test out reading Fault Codes from the PM100 >" << endl; + cout << "< >" << endl; + cout << "< >" << endl; + cout << "< >\n" << endl; + + cout << "< The CAN message we're testing is: >" << endl; + + broadcast_message testing_class; + int test_message_2[9] = { 0x0AB, 128, 32, 0, 0, 0, 0, 2, 0 }; + + cout << "< {"; + for ( int i = 0; i < 8; i++ ){ + /* + if(i == 0){ + cout << " 0x0" << hex << test_message_2[i] << ","; + continue; + } + */ + cout << " " << test_message_2[i] << ","; + } + cout << " }\n" << endl; + + + + vector returned_faults_vector; + returned_faults_vector = testing_class.read_fault_codes_VER_2( test_message_2 ); + + + + + +} + diff --git a/Inverter/old/BROADCAST_FAULTS.h b/Inverter/old/BROADCAST_FAULTS.h new file mode 100644 index 0000000..9a39ec2 --- /dev/null +++ b/Inverter/old/BROADCAST_FAULTS.h @@ -0,0 +1,118 @@ +#ifndef BROADCAST_FAULTS_H +#define BROADCAST_FAULTS_H + +#include +//#include +#include +#include +//types of CAN messages +typedef enum fault_code { + //POST FAULTS + //Byte 0 + Hardware_Gate_Desaturation_Fault, + HW_Over_current_Fault, + Accelerator_Shorted, + Accelerator_Open, + Current_Sensor_Low, + Current_Sensor_High, + Module_Temperature_Low, + Module_Temperature_High, + //Byte 1 + Control_PCB_Temperature_Low, + Control_PCB_Temperature_High, + Gate_Drive_PCB_Temperature_Low, + Gate_Drive_PCB_Temperature_High, + Sense_Voltage_Low_5V, + Sense_Voltage_High_5V, + Sense_Voltage_Low_12V, + Sense_Voltage_High_12V, + //Byte 2 + Sense_Voltage_Low_2_5V, + Sense_Voltage_High_2_5V, + Sense_Voltage_Low_1_5V, + Sense_Voltage_High_1_5V, + DC_Bus_Voltage_High, + DC_Bus_Voltage_Low, + Pre_charge_Timeout, + Pre_charge_Voltage_Failure, + //Byte 3 + EEPROM_Checksum_Invalid, + EEPROM_Data_Out_of_Range, + EEPROM_Update_Required, + RESERVED_1, + RESERVED_2, + RESERVED_3, + Brake_Shorted, + Brake_Open, + //Byte 4 + //RUN FAULTS + Motor_Over_speed_Fault, + Over_current_Fault, + Over_voltage_Fault, + Inverter_Over_temperature_Fault, + Accelerator_Input_Shorted_Fault, + Accelerator_Input_Open_Fault, + Direction_Command_Fault, + Inverter_Response_Time_out_Fault, + //Byte 5 + Hardware_Gate_Desaturation_RUN_Fault, + Hardware_Over_current_Fault, + Under_voltage_Fault, + CAN_Command_Message_Lost_Fault, + Motor_Over_temperature_Fault, + RESERVED_4, + RESERVED_5, + RESERVED_6, + //Byte 6 + Brake_Input_Shorted_Fault, + Brake_Input_Open_Fault, + Module_A_Over_temperature_Fault, + Module_B_Over_temperature_Fault, + Module_C_Over_temperature_Fault, + PCB_Over_temperature_Fault, + Gate_Drive_Board_1_Over_temperature_Fault, + Gate_Drive_Board_2_Over_temperature_Fault, + //Byte 7 + Gate_Drive_Board_3_Over_temperature_Fault, + Current_Sensor_Fault, + RESERVED_7, + Hardware_Over_Voltage_Fault, + RESERVED_8, + RESERVED_9, + Resolver_Not_Connected, + Inverter_Discharge_Active, + + //Finally, error if the CAN mssg is NOT for fault codes + NOT_FAULT_CAN_MSSG + + +} PM100_FAULT_CODE; + + + +using namespace std; + + + +class broadcast_message{ + + public: + + message_type command_message; + + friend ostream& operator<<( ostream& lhs, PM100_FAULT_CODE fault ); + + friend int return_fault_index_val( PM100_FAULT_CODE fault ); + + vector read_fault_codes_VER_2( int CAN_mssg[9] ); + + + + + + + + +}; + +#endif diff --git a/Inverter/old/BROADCAST_MESSAGE.cpp b/Inverter/old/BROADCAST_MESSAGE.cpp new file mode 100644 index 0000000..8edc713 --- /dev/null +++ b/Inverter/old/BROADCAST_MESSAGE.cpp @@ -0,0 +1,539 @@ +#include +#include +#include +//#include +#include + +using namespace std; + +std::ostream &operator<<(std::ostream &lhs, vsm_state state) +{ + switch (state) { + case VSM_START: lhs << "VSM Start State"; break; + case PRE_CHARGE_INIT: lhs << "Pre-Charge Init State"; break; + case PRE_CHARGE_ACTIVE: lhs << "Pre-Charge Active State"; break; + case PRE_CHARGE_COMPLETE: lhs << "Pre-Charge Complete State"; break; + case VSM_WAIT: lhs << "VSM Wait State"; break; + case VSM_READY: lhs << "VSM Ready State"; break; + case MOTOR_RUNNING: lhs << "Motor Running State"; break; + case BLINK_FAULT_CODE: lhs << "Blink Fault Code State"; break; + case SHUTDOWN_IN_PROGRESS: lhs << "Shutdown in Process"; break; + case RECYCLE_POWER: lhs << "Recycle Power State"; break; + case NOT_A_VSM_STATE: lhs << "ERROR - NOT a VSM State - Invalid Value"; break; + } + + return lhs; +} + +int return_vsm_state_val(vsm_state state) +{ + int index_value = state; + return index_value; +} + +vsm_state broadcast_message::read_vsm_state(int CAN_mssg[9]) +{ + vsm_state state; + + if (CAN_mssg[0] != 0x0AA) + { + cout << "Message CAN ID is not 0x0AA, this is NOT a VSM message" << endl; + return state = NOT_A_VSM_STATE; + } + + switch (CAN_mssg[2]) + { + case 0: + cout << "VSM State: VSM Start State"; + state = VSM_START; break; + case 1: + cout << "VSM State: Pre-charge Init State"; + state = PRE_CHARGE_INIT; break; + case 2: + cout << "VSM State: Pre-charge Active State"; + state = PRE_CHARGE_ACTIVE; break; + case 3: + cout << "VSM State: Pre-charge Complete State"; + state = PRE_CHARGE_COMPLETE; break; + case 4: + cout << "VSM State: VSM Wait State"; + state = VSM_WAIT; break; + case 5: + cout << "VSM State: VSM Ready State"; + state = VSM_READY; break; + case 6: + cout << "VSM State: Motor Running State"; + state = MOTOR_RUNNING; break; + case 7: + cout << "VSM State: Blink Fault Code State"; + state = BLINK_FAULT_CODE; break; + case 14: + cout << "VSM State: Shutdown in Process"; + state = SHUTDOWN_IN_PROGRESS; break; + case 15: + cout << "VSM State: Recycle Power State"; + state = RECYCLE_POWER; break; + default: + cout << "Invalid VSM State"; + state = NOT_A_VSM_STATE; + } + + return state; +} + +std::ostream &operator<<(std::ostream &lhs, inverter_state state) +{ + switch (state) { + case POWER_ON: lhs << "Power On State"; break; + case STOP: lhs << "Stop State"; break; + case OPEN_LOOP: lhs << "Open Loop State"; break; + case CLOSED_LOOP: lhs << "Closed Loop State"; break; + case WAIT: lhs << "Wait State"; break; + case IDLE_RUN: lhs << "Idle Run State"; break; + case IDLE_STOP: lhs << "Idle Stop State"; break; + case NOT_AN_INVERTER_STATE: lhs << "ERROR - NOT an Inverter State - Invalid Value"; break; + } + + return lhs; +} + +int return_inverter_state_val(inverter_state state) +{ + int index_value = state; + return index_value; +} + +inverter_state broadcast_message::read_inverter_state(int CAN_mssg[9]) +{ + inverter_state state; + + if (CAN_mssg[0] != 0x0AA) + { + cout << "Message CAN ID is not 0xAA" << endl; + return state = NOT_AN_INVERTER_STATE; + } + + switch (CAN_mssg[3]) + { + case 0: + cout << "Inverter State: Power on State" << endl; + state = POWER_ON; break; + case 1: + cout << "Inverter State: Stop State" << endl; + state = STOP; break; + case 2: + cout << "Inverter State: Open Loop State" << endl; + state = OPEN_LOOP; break; + case 3: + cout << "Inverter State: Closed Loop State" << endl; + state = CLOSED_LOOP; break; + case 4: + cout << "Inverter State: Wait State" << endl; + state = WAIT; break; + case 8: + cout << "Inverter State: Idle Run State" << endl; + state = IDLE_RUN; break; + case 9: + cout << "Inverter State: Idle Stop State" << endl; + state = IDLE_STOP; break; + default: + cout << "Invalid Inverter State" << endl; + state = NOT_AN_INVERTER_STATE; break; + } + + return state; +} + +/* Disable one or more messages at a time + * Example usage: disable_broadcast_message(test_msg, TEMPERATURE_2 | CURRENT_INFORMATION | DIAG_DATA); + */ +void disable_broadcast_message(int CAN_mssg[9], int listOfMsgs) +{ + if (CAN_mssg[0] != 0x0C1) // CAN ID + { + cout << "Message CAN Address is not 0x0C1" << endl; + return; + } + + if (CAN_mssg[1] != 148) // Data Byte 0 + { + cout << "Message Parameter Address is not 148" << endl; + return; + } + + int loWord = (CAN_mssg[6] << 8) | CAN_mssg[5]; // loWord = [6] concatenated with [5] + + if ((TEMPERATURE_1 & listOfMsgs) == TEMPERATURE_1) + loWord &= ~(1U); + if ((TEMPERATURE_2 & listOfMsgs) == TEMPERATURE_2) + loWord &= ~(1U << 1); + if ((TEMPERATURE_3 & listOfMsgs) == TEMPERATURE_3) + loWord &= ~(1U << 2); + if ((ANALOG_INPUT_VOLTAGES & listOfMsgs) == ANALOG_INPUT_VOLTAGES) + loWord &= ~(1U << 3); + if ((DIGITAL_INPUT_STATUS & listOfMsgs) == DIGITAL_INPUT_STATUS) + loWord &= ~(1U << 4); + if ((MOTOR_POSITION_INFORMATION & listOfMsgs) == MOTOR_POSITION_INFORMATION) + loWord &= ~(1U << 5); + if ((CURRENT_INFORMATION & listOfMsgs) == CURRENT_INFORMATION) + loWord &= ~(1U << 6); + if ((VOLTAGE_INFORMATION & listOfMsgs) == VOLTAGE_INFORMATION) + loWord &= ~(1U << 7); + + if ((FLUX_INFORMATION & listOfMsgs) == FLUX_INFORMATION) + loWord &= ~(1U << 8); + if ((INTERNAL_VOLTAGES & listOfMsgs) == INTERNAL_VOLTAGES) + loWord &= ~(1U << 9); + if ((INTERNAL_STATES & listOfMsgs) == INTERNAL_STATES) + loWord &= ~(1U << 10); + if ((FAULT_CODES & listOfMsgs) == FAULT_CODES) + loWord &= ~(1U << 11); + if ((TORQUE_AND_TIMER_INFORMATION & listOfMsgs) == TORQUE_AND_TIMER_INFORMATION) + loWord &= ~(1U << 12); + if ((MOD_INDEX_FLUX_WEAKENING_OUTPUT_INFO & listOfMsgs) == MOD_INDEX_FLUX_WEAKENING_OUTPUT_INFO) + loWord &= ~(1U << 13); + if ((FIRMWARE_INFORMATION & listOfMsgs) == FIRMWARE_INFORMATION) + loWord &= ~(1U << 14); + if ((DIAG_DATA & listOfMsgs) == DIAG_DATA) + loWord &= ~(1U << 15); + + // Separate loWord back into two bytes + CAN_mssg[5] = loWord & 0xFF; + CAN_mssg[6] = (loWord >> 8) & 0xFF; +} + + + + +//Fault Code Functions and Array defined below + +PM100_FAULT_CODE FAULT_CODE_ARRAY[65] = { + //POST FAULTS + //Byte 0 + Hardware_Gate_Desaturation_Fault, + HW_Over_current_Fault, + Accelerator_Shorted, + Accelerator_Open, + Current_Sensor_Low, + Current_Sensor_High, + Module_Temperature_Low, + Module_Temperature_High, + //Byte 1 + Control_PCB_Temperature_Low, + Control_PCB_Temperature_High, + Gate_Drive_PCB_Temperature_Low, + Gate_Drive_PCB_Temperature_High, + Sense_Voltage_Low_5V, + Sense_Voltage_High_5V, + Sense_Voltage_Low_12V, + Sense_Voltage_High_12V, + //Byte 2 + Sense_Voltage_Low_2_5V, + Sense_Voltage_High_2_5V, + Sense_Voltage_Low_1_5V, + Sense_Voltage_High_1_5V, + DC_Bus_Voltage_High, + DC_Bus_Voltage_Low, + Pre_charge_Timeout, + Pre_charge_Voltage_Failure, + //Byte 3 + EEPROM_Checksum_Invalid, + EEPROM_Data_Out_of_Range, + EEPROM_Update_Required, + RESERVED_1, + RESERVED_2, + RESERVED_3, + Brake_Shorted, + Brake_Open, + //Byte 4 + //RUN FAULTS + Motor_Over_speed_Fault, + Over_current_Fault, + Over_voltage_Fault, + Inverter_Over_temperature_Fault, + Accelerator_Input_Shorted_Fault, + Accelerator_Input_Open_Fault, + Direction_Command_Fault, + Inverter_Response_Time_out_Fault, + //Byte 5 + Hardware_Gate_Desaturation_RUN_Fault, + Hardware_Over_current_Fault, + Under_voltage_Fault, + CAN_Command_Message_Lost_Fault, + Motor_Over_temperature_Fault, + RESERVED_4, + RESERVED_5, + RESERVED_6, + //Byte 6 + Brake_Input_Shorted_Fault, + Brake_Input_Open_Fault, + Module_A_Over_temperature_Fault, + Module_B_Over_temperature_Fault, + Module_C_Over_temperature_Fault, + PCB_Over_temperature_Fault, + Gate_Drive_Board_1_Over_temperature_Fault, + Gate_Drive_Board_2_Over_temperature_Fault, + //Byte 7 + Gate_Drive_Board_3_Over_temperature_Fault, + Current_Sensor_Fault, + RESERVED_7, + Hardware_Over_Voltage_Fault, + RESERVED_8, + RESERVED_9, + Resolver_Not_Connected, + Inverter_Discharge_Active, + + //Finally, error if the CAN mssg is NOT for fault codes + NOT_FAULT_CAN_MSSG + +}; + + +std::ostream& operator<<(std::ostream& lhs, PM100_FAULT_CODE fault) +{ + switch(fault) + { + case Hardware_Gate_Desaturation_Fault: lhs << "Hardware_Gate_Desaturation_Fault"; break; + case HW_Over_current_Fault: lhs << "HW_Over_current_Fault"; break; + case Accelerator_Shorted: lhs << "Accelerator_Shorted"; break; + case Accelerator_Open: lhs << "Accelerator_Open"; break; + case Current_Sensor_Low: lhs << "Current_Sensor_Low"; break; + case Current_Sensor_High: lhs << "Current_Sensor_High"; break; + case Module_Temperature_Low: lhs << "Module_Temperature_Low"; break; + case Module_Temperature_High: lhs << "Module_Temperature_High"; break; + case Control_PCB_Temperature_Low: lhs << "Control_PCB_Temperature_Low"; break; + case Control_PCB_Temperature_High: lhs << "Control_PCB_Temperature_High"; break; + case Gate_Drive_PCB_Temperature_Low: lhs << "Gate_Drive_PCB_Temperature_Low"; break; + case Gate_Drive_PCB_Temperature_High: lhs << "Gate_Drive_PCB_Temperature_High"; break; + case Sense_Voltage_Low_5V: lhs << "Sense_Voltage_Low_5V"; break; + case Sense_Voltage_High_5V: lhs << "Sense_Voltage_High_5V"; break; + case Sense_Voltage_Low_12V: lhs << "Sense_Voltage_Low_12V"; break; + case Sense_Voltage_High_12V: lhs << "Sense_Voltage_High_12V"; break; + case Sense_Voltage_Low_2_5V: lhs << "Sense_Voltage_Low_2_5V"; break; + case Sense_Voltage_High_2_5V: lhs << "Sense_Voltage_High_2_5V"; break; + case Sense_Voltage_Low_1_5V: lhs << "Sense_Voltage_Low_1_5V"; break; + case Sense_Voltage_High_1_5V: lhs << "Sense_Voltage_High_1_5V"; break; + case DC_Bus_Voltage_High: lhs << "DC_Bus_Voltage_High"; break; + case DC_Bus_Voltage_Low: lhs << "DC_Bus_Voltage_Low"; break; + case Pre_charge_Timeout: lhs << "Pre_charge_Timeout"; break; + case Pre_charge_Voltage_Failure: lhs << "Pre_charge_Voltage_Failure"; break; + case EEPROM_Checksum_Invalid: lhs << "EEPROM_Checksum_Invalid"; break; + case EEPROM_Data_Out_of_Range: lhs << "EEPROM_Data_Out_of_Range"; break; + case EEPROM_Update_Required: lhs << "EEPROM_Update_Required"; break; + case RESERVED_1: lhs << "RESERVED_1"; break; + case RESERVED_2: lhs << "RESERVED_2"; break; + case RESERVED_3: lhs << "RESERVED_3"; break; + case Brake_Shorted: lhs << "Brake_Shorted"; break; + case Brake_Open: lhs << "Brake_Open"; break; + case Motor_Over_speed_Fault: lhs << "Motor_Over_speed_Fault"; break; + case Over_current_Fault: lhs << "Over_current_Fault"; break; + case Over_voltage_Fault: lhs << "Over_voltage_Fault"; break; + case Inverter_Over_temperature_Fault: lhs << "Inverter_Over_temperature_Fault"; break; + case Accelerator_Input_Shorted_Fault: lhs << "Accelerator_Input_Shorted_Fault"; break; + case Accelerator_Input_Open_Fault: lhs << "Accelerator_Input_Open_Fault"; break; + case Direction_Command_Fault: lhs << "Direction_Command_Fault"; break; + case Inverter_Response_Time_out_Fault: lhs << "Inverter_Response_Time_out_Fault"; break; + case Hardware_Gate_Desaturation_RUN_Fault: lhs << "Hardware_Gate_Desaturation_RUN_Fault"; break; + case Hardware_Over_current_Fault: lhs << "Hardware_Over_current_Fault"; break; + case Under_voltage_Fault: lhs << "Under_voltage_Fault"; break; + case CAN_Command_Message_Lost_Fault: lhs << "CAN_Command_Message_Lost_Fault"; break; + case Motor_Over_temperature_Fault: lhs << "Motor_Over_temperature_Fault"; break; + case RESERVED_4: lhs << "RESERVED_4"; break; + case RESERVED_5: lhs << "RESERVED_5"; break; + case RESERVED_6: lhs << "RESERVED_6"; break; + case Brake_Input_Shorted_Fault: lhs << "Brake_Input_Shorted_Fault"; break; + case Brake_Input_Open_Fault: lhs << "Brake_Input_Open_Fault"; break; + case Module_A_Over_temperature_Fault: lhs << "Module_A_Over_temperature_Fault"; break; + case Module_B_Over_temperature_Fault: lhs << "Module_B_Over_temperature_Fault"; break; + case Module_C_Over_temperature_Fault: lhs << "Module_C_Over_temperature_Fault"; break; + case PCB_Over_temperature_Fault: lhs << "PCB_Over_temperature_Fault"; break; + case Gate_Drive_Board_1_Over_temperature_Fault: lhs << "Gate_Drive_Board_1_Over_temperature_Fault"; break; + case Gate_Drive_Board_2_Over_temperature_Fault: lhs << "Gate_Drive_Board_2_Over_temperature_Fault"; break; + case Gate_Drive_Board_3_Over_temperature_Fault: lhs << "Gate_Drive_Board_3_Over_temperature_Fault"; break; + case Current_Sensor_Fault: lhs << "Current_Sensor_Fault"; break; + case RESERVED_7: lhs << "RESERVED_7"; break; + case Hardware_Over_Voltage_Fault: lhs << "Hardware_Over_Voltage_Fault"; break; + case RESERVED_8: lhs << "RESERVED_8"; break; + case RESERVED_9: lhs << "RESERVED_9"; break; + case Resolver_Not_Connected: lhs << "Resolver_Not_Connected"; break; + case Inverter_Discharge_Active: lhs << "Inverter_Discharge_Active"; break; + case NOT_FAULT_CAN_MSSG: lhs << "ERROR - This CAN Message is NOT for FAULT CODES!"; break; + } + + return lhs; +} + + + +int return_fault_index_val( PM100_FAULT_CODE fault ) +{ + int index_value = fault; + return index_value; +} + + + +std::vector broadcast_message::read_fault_codes_VER_2( int CAN_mssg[9] ) +{ + //extract the CAN ID & define return vector of fault codes + int CAN_ID = CAN_mssg[0]; + vector faults_found; + PM100_FAULT_CODE fault; + + //check if CAN message is FAULT message + if( CAN_ID != 0x0AB ) + { + cout << NOT_FAULT_CAN_MSSG; + faults_found.push_back( NOT_FAULT_CAN_MSSG ); + } + else if( CAN_ID == 0x0AB ) + { + int fault_code_index = 0; //var used for indexing fault code array + + //here we'll loop 8 times, analyze each CAN data byte + for( int i = 1; i < 9; i++ ) + { + int byte_i = CAN_mssg[i]; + cout << "Byte " << i << " Faults: " << endl; + + //vars to check each bit of current byte + int current_bit; + int int_to_binary = byte_i; + for( int i = 0; i < 8; i++ ) + { + current_bit = int_to_binary % 2; + int_to_binary = int_to_binary / 2; + + if( current_bit ) + { + fault = FAULT_CODE_ARRAY[ fault_code_index + i ]; + cout << " " << fault << " -- Fault #" << return_fault_index_val( fault ) << endl; + faults_found.push_back( fault ); + } + } + + fault_code_index = fault_code_index + 8; + } + } + + return faults_found; +} + + + +int main() +{ + cout << "Testing print_vms_state function: " << endl; + + broadcast_message testing_class; + vsm_state CAN_MSSG_VSM_STATE; + + int test_CAN_message[9] = {0x0AA, 0, 1, 0, 0, 0, 0, 0, 0}; + + cout << "CAN Message--------------------" << endl; + cout << "{"; + for (int i = 0; i < 9; i++) + { + + cout << " " << test_CAN_message[i]; + if (i != 8) + { + cout << ","; + } + } + cout << " }\n" << endl; + + CAN_MSSG_VSM_STATE = testing_class.read_vsm_state(test_CAN_message); + cout << "\n\nThe VSM State retrieved from the CAN Message is: " << CAN_MSSG_VSM_STATE << endl; + cout << "Value of VSM State: " << return_vsm_state_val(CAN_MSSG_VSM_STATE) << endl; + + + /////////////////////////////////////////////////////////////////////////////////////////////// + + + cout << "\n\n\nTesting print_inverter_state function: " << endl; + inverter_state CAN_MSSG_INVERTER_STATE; + + int test_CAN_message_2[9] = {0x0AA, 0, 0, 2, 0, 0, 0, 0, 0}; + + cout << "CAN Message--------------------" << endl; + cout << "{"; + for (int i = 0; i < 9; i++) + { + + cout << " " << test_CAN_message_2[i]; + if (i != 8) + { + cout << ","; + } + } + cout << " }\n" << endl; + + CAN_MSSG_INVERTER_STATE = testing_class.read_inverter_state(test_CAN_message_2); + cout << "\nThe Inverter State retrieved from the CAN Message is: " << CAN_MSSG_INVERTER_STATE << endl; + cout << "Value of Inverter State: " << return_inverter_state_val(CAN_MSSG_INVERTER_STATE) << endl; + + + /////////////////////////////////////////////////////////////////////////////////////////////// + + + cout << "\n\n\nTesting disable_broadcast_message function: " << endl; + + int test_msg[9] = {0x0C1, 148, 0, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF}; + + cout << "CAN Message--------------------" << endl; + cout << "{ " << test_msg[0]; + for (int i = 1; i < 9; i++) + cout << ", " << test_msg[i]; + cout << " }\n" << endl; + + disable_broadcast_message(test_msg, TEMPERATURE_2 | DIAG_DATA); + + cout << "New CAN Message--------------------" << endl; + cout << "{ " << test_msg[0]; + for (int i = 1; i < 9; i++) + cout << ", " << test_msg[i]; + cout << " }\n" << endl; + + + /////////////////////////////////////////////////////////////////////////////////////////////// + + + cout << "----------------------------------------------------------------" << endl; + cout << "- -" << endl; + cout << "- CAN PM100 -" << endl; + cout << "- Fault Code Function Testing -" << endl; + cout << "- -" << endl; + cout << "- -" << endl; + cout << "- -" << endl; + cout << "----------------------------------------------------------------\n" << endl; + + cout << "< Hello there! Here we'll test out reading Fault Codes from the PM100 >" << endl; + cout << "< >" << endl; + cout << "< >" << endl; + cout << "< >\n" << endl; + + cout << "< The CAN message we're testing is: >" << endl; + + broadcast_message testing_class; + int test_message_2[9] = { 0x0AB, 128, 32, 0, 0, 0, 0, 2, 0 }; + + cout << "< {"; + for ( int i = 0; i < 8; i++ ) + { + /* + if(i == 0) + { + cout << " 0x0" << hex << test_message_2[i] << ","; + continue; + } + */ + cout << " " << test_message_2[i] << ","; + } + cout << " }\n" << endl; + + vector returned_faults_vector; + returned_faults_vector = testing_class.read_fault_codes_VER_2( test_message_2 ); + + +} diff --git a/Inverter/old/BROADCAST_MESSAGE.h b/Inverter/old/BROADCAST_MESSAGE.h new file mode 100644 index 0000000..1ce598a --- /dev/null +++ b/Inverter/old/BROADCAST_MESSAGE.h @@ -0,0 +1,183 @@ +#ifndef BROADCAST_MESSAGE_H +#define BROADCAST_MESSAGE_H + +//#include +#include +#include +#include + +// Reference 0x0AA - Internal States, Byte #0,1 +typedef enum vsm_state +{ + VSM_START, + PRE_CHARGE_INIT, + PRE_CHARGE_ACTIVE, + PRE_CHARGE_COMPLETE, + VSM_WAIT, + VSM_READY, + MOTOR_RUNNING, + BLINK_FAULT_CODE, + SHUTDOWN_IN_PROGRESS = 14, + RECYCLE_POWER, + NOT_A_VSM_STATE +} vsm_state; + +// Reference 0x0AA - Internal States, Byte #2 +typedef enum inverter_state +{ + POWER_ON, + STOP, + OPEN_LOOP, + CLOSED_LOOP, + WAIT, + IDLE_RUN = 8, + IDLE_STOP, + NOT_AN_INVERTER_STATE = 13 +} inverter_state; + +// Reference Param Address 148 +typedef enum can_active_messages_lo_word +{ + // Data Byte 4 + TEMPERATURE_1 = 0x0001, + TEMPERATURE_2 = 0x0002, + TEMPERATURE_3 = 0x0004, + ANALOG_INPUT_VOLTAGES = 0x0008, + DIGITAL_INPUT_STATUS = 0x0010, + MOTOR_POSITION_INFORMATION = 0x0020, + CURRENT_INFORMATION = 0x0040, + VOLTAGE_INFORMATION = 0x0080, + // Data Byte 5 + FLUX_INFORMATION = 0x0100, + INTERNAL_VOLTAGES = 0x0200, + INTERNAL_STATES = 0x0400, + FAULT_CODES = 0x0800, + TORQUE_AND_TIMER_INFORMATION = 0x1000, + MOD_INDEX_FLUX_WEAKENING_OUTPUT_INFO = 0x2000, + FIRMWARE_INFORMATION = 0x4000, + DIAG_DATA = 0x8000 +} can_active_messages_lo_word; + +// Reference Param Address 148, should always be enabled (default) +typedef enum can_active_messages_hi_word +{ + // Data Byte 6 + SLAVE_MODE_COMMAND_MESSAGE = 6, + BMS_COMMAND_MESSAGE, + // Data Byte 7 + OBD2_GENERAL_QUERY, + OBD2_SPECIFIC_QUERY, + OBD2_RESPONSE, + U2C_TX_MESSAGE, + U2C_RX_MESSAGE, + PARAMETER_RESPONSE_MESAGE, + PARAMETER_COMMAND_MESSAGE, + CAN_COMMAND_MESSAGE +} can_active_messages_hi_word; + +//All types of Fault Codes +typedef enum fault_code +{ + //POST FAULTS + //Byte 0 + Hardware_Gate_Desaturation_Fault, + HW_Over_current_Fault, + Accelerator_Shorted, + Accelerator_Open, + Current_Sensor_Low, + Current_Sensor_High, + Module_Temperature_Low, + Module_Temperature_High, + //Byte 1 + Control_PCB_Temperature_Low, + Control_PCB_Temperature_High, + Gate_Drive_PCB_Temperature_Low, + Gate_Drive_PCB_Temperature_High, + Sense_Voltage_Low_5V, + Sense_Voltage_High_5V, + Sense_Voltage_Low_12V, + Sense_Voltage_High_12V, + //Byte 2 + Sense_Voltage_Low_2_5V, + Sense_Voltage_High_2_5V, + Sense_Voltage_Low_1_5V, + Sense_Voltage_High_1_5V, + DC_Bus_Voltage_High, + DC_Bus_Voltage_Low, + Pre_charge_Timeout, + Pre_charge_Voltage_Failure, + //Byte 3 + EEPROM_Checksum_Invalid, + EEPROM_Data_Out_of_Range, + EEPROM_Update_Required, + RESERVED_1, + RESERVED_2, + RESERVED_3, + Brake_Shorted, + Brake_Open, + //Byte 4 + //RUN FAULTS + Motor_Over_speed_Fault, + Over_current_Fault, + Over_voltage_Fault, + Inverter_Over_temperature_Fault, + Accelerator_Input_Shorted_Fault, + Accelerator_Input_Open_Fault, + Direction_Command_Fault, + Inverter_Response_Time_out_Fault, + //Byte 5 + Hardware_Gate_Desaturation_RUN_Fault, + Hardware_Over_current_Fault, + Under_voltage_Fault, + CAN_Command_Message_Lost_Fault, + Motor_Over_temperature_Fault, + RESERVED_4, + RESERVED_5, + RESERVED_6, + //Byte 6 + Brake_Input_Shorted_Fault, + Brake_Input_Open_Fault, + Module_A_Over_temperature_Fault, + Module_B_Over_temperature_Fault, + Module_C_Over_temperature_Fault, + PCB_Over_temperature_Fault, + Gate_Drive_Board_1_Over_temperature_Fault, + Gate_Drive_Board_2_Over_temperature_Fault, + //Byte 7 + Gate_Drive_Board_3_Over_temperature_Fault, + Current_Sensor_Fault, + RESERVED_7, + Hardware_Over_Voltage_Fault, + RESERVED_8, + RESERVED_9, + Resolver_Not_Connected, + Inverter_Discharge_Active, + + //Finally, error if the CAN mssg is NOT for fault codes + NOT_FAULT_CAN_MSSG + +} PM100_FAULT_CODE; + + + +class broadcast_message +{ +public: + message_type broadcast_message; + + vsm_state read_vsm_state(int message_arr[9]); + friend std::ostream &operator<<(std::ostream &lhs, vsm_state state); + friend int return_vsm_state_val(vsm_state state); + + inverter_state read_inverter_state(int message_arr[9]); + friend std::ostream &operator<<(std::ostream &lhs, inverter_state state); + friend int return_inverter_state_val(inverter_state state); + + void disable_broadcast_message(int CAN_mssg[9], int listOfMsgs); + + vector read_fault_codes_VER_2( int CAN_mssg[9] ); + friend ostream& operator<<( ostream& lhs, PM100_FAULT_CODE fault ); + friend int return_fault_index_val( PM100_FAULT_CODE fault ); +}; + +#endif diff --git a/Inverter/old/COMMAND_MESSAGE.cpp b/Inverter/old/COMMAND_MESSAGE.cpp new file mode 100644 index 0000000..05f9027 --- /dev/null +++ b/Inverter/old/COMMAND_MESSAGE.cpp @@ -0,0 +1,215 @@ +//#include +//#include +//#include +#include +#include +//#include +#include + +using namespace std; + + +//given all inverter parameters, this creates an int array of the CAN message data bytes +int* command_message::create_command_message ( message_type command_message, + float torque_val, //Value in N.m + float speed_val, //RPM + inverter_direction direction_command, + inverter_enable enable_command ){ + + //All necessary variables for CAN Message (data bytes) + int inverter_torque_val; + int data_high_byte; + int data_low_byte; + int direction_byte; + int enable_byte; + + //There are 2 types of CAN Command Messages to generate: + //Torque Message code below + if( command_message == COMMAND_TOURQUE_M ){ + + //Calculate the int values for byte 0 & byte 1 (torque data) + //PM100 requires (Torque Val * 10) to be sent through CAN + if( torque_val > 0 ){ + inverter_torque_val = int(torque_val * 10); + data_low_byte = inverter_torque_val % 256; + data_high_byte = inverter_torque_val / 256; + } + else if( torque_val < 0 ){ + inverter_torque_val = int(torque_val * 10); + data_low_byte = ( inverter_torque_val & 255 ); + data_high_byte = ( inverter_torque_val & 65280 ) >> 8; + } + + + //Set direction command byte accordingly + if( direction_command == REVERSE ){ direction_byte = 0; } + else if( direction_command == FORWARD ){ direction_byte = 1; } + else{ + //SHOULD NOT BE HERE, raise ERROR + cout << "--ERROR-- Un-identified Inverter Direction Command" << endl; + } + + //Set inverter enable byte accordingly + if( enable_command == ENABLE ){ enable_byte = 1; } + else if( enable_command == DISABLE ){ enable_byte = 0; } + else{ + //SHOULD NOT BE HERE, raise ERROR + cout << "--ERROR-- Un-identified Inverter Enable Command" << endl; + } + + + //Finally, format the CAN message data bytes + //Represented as int array + static int can_data_bytes[8] = { data_low_byte, data_high_byte, 0, 0, direction_byte, enable_byte, 0, 0 }; + + /* DEBUG---PRINT OUT CAN DATA BYTES---------------------------------- + cout << "Printintg CAN Message inside the function here:..." << endl; + for ( int i = 0; i < 8; i++ ) { + cout << can_data_bytes[i] << endl; + }------------------------------------------------------------------- + */ + + return can_data_bytes; + } + + + + + + + else if( command_message == COMMAND_SPEED_M ){ + + + data_low_byte = int(speed_val) % 256; + data_high_byte = speed_val / 256; + + + if( direction_command == REVERSE ){ direction_byte = 0; } + else if( direction_command == FORWARD ){ direction_byte = 1; } + else{ + //SHOULD NOT BE HERE, raise ERROR + cout << "--ERROR-- Un-identified Inverter Direction Command" << endl; + } + + if( enable_command == ENABLE ){ enable_byte = 1; } + else if( enable_command == DISABLE ){ enable_byte = 0; } + else{ + //SHOULD NOT BE HERE, raise ERROR + cout << "--ERROR-- Un-identified Inverter Enable Command" << endl; + } + + + //Finally, format the CAN message data bytes + static int can_data_bytes[8] = { 0, 0, data_low_byte, data_high_byte, direction_byte, enable_byte, 0, 0 }; + + /* DEBUG---PRINT OUT CAN DATA BYTES---------------------------------- + cout << "Printintg CAN Message inside the function here:..." << endl; + for ( int i = 0; i < 8; i++ ) { + cout << can_data_bytes[i] << endl; + }------------------------------------------------------------------- + */ + + + return can_data_bytes; + } + + + +} + + + +int main(){ + + char speed_or_torque; + char inv_direction; + float torque_val = 0; + float speed_val = 0; + + //These variables are all custom made + command_message test_message; //message class + message_type test_type; + inverter_direction test_direction; + inverter_enable test_enable = ENABLE; //inverter enable + + + //BITWISE TESTING (ADAM) + /* + int test_int = 100; + int bitwise_not = ~test_int + 1; + + cout << "test int: " << test_int << endl; + cout << "bitwise NOT: " << bitwise_not << endl; + + cout << "binary of test int: " << bitset<16>(test_int) << endl; + cout << "binary of bitwise NOT: " << bitset<16>(bitwise_not) << endl; + + int low_byte = ( bitwise_not & 255 ); + int high_byte = ( bitwise_not & 65280 ) >> 8; + cout << "low byte: " << low_byte << endl; + cout << "high byte: " << high_byte << endl; + */ + + + cout << "-----------------------------------------------------------------------------" << endl; + cout << "| PM100 CAN Bus Message Generator (TESTING) |" << endl; + cout << "| |" << endl; + cout << "| |" << endl; + cout << "| |" << endl; + cout << "-----------------------------------------------------------------------------" << endl; + cout << "\nWelcome :) \n" << endl; + cout << "Do you want to make a Speed or Torque Command Message?" << endl; + cout << " _______________________________" << endl; + cout << "| [s] for Speed, [t] for Torque |" << endl; + cout << "|_______________________________|" << endl; + cout << ">"; + cin >> speed_or_torque; + + if( speed_or_torque == 's' || speed_or_torque == 'S' ){ + + test_type = COMMAND_SPEED_M; + cout << "\nPlease enter a Speed Value: (RPM)" << endl; + cout << ">"; + cin >> speed_val; + } + else if( speed_or_torque == 't' || speed_or_torque == 'T' ){ + + test_type = COMMAND_TOURQUE_M; + cout << "\nPlease enter a Torque Value: (N*m)" << endl; + cout << ">"; + cin >> torque_val; + } + + cout << "\nNow, specify the Inverter's Direction:" << endl; + cout << " ____________________________________________" << endl; + cout << "| [f] for FORWARD (default), [r] for REVERSE |" << endl; + cout << "|____________________________________________|" << endl; + cout << ">"; + cin >> inv_direction; + + if( inv_direction == 'f' || inv_direction == 'F' ){ test_direction = FORWARD; } + else if( inv_direction == 'r' || inv_direction == 'R' ){ test_direction = REVERSE; } + + + + + //test command message + //pass all the necessary parameters needed to make CAN Message + int *CAM_mssg = test_message.send_command_message( test_type, torque_val, speed_val, test_direction, test_enable ); + + //Printing out CAN Message (data bytes) + cout << "\n _______________________________________" << endl; + cout << "| CAN Message generated: |" << endl; + cout << "| { "; + for ( int i = 0; i < 8; i++ ) { + cout << CAM_mssg[i]; + if( i != 7 ){ cout << ", "; } + } + cout << " }" << endl; + cout << "| |" << endl; + cout << "|_______________________________________|" << endl; + + + +} + diff --git a/Inverter/old/COMMAND_MESSAGE.h b/Inverter/old/COMMAND_MESSAGE.h new file mode 100644 index 0000000..3c306f1 --- /dev/null +++ b/Inverter/old/COMMAND_MESSAGE.h @@ -0,0 +1,46 @@ +#ifndef COMMAND_MESSAGE_H +#define COMMAND_MESSAGE_H + +//types of CAN messages +typedef enum m_type { + BROADCAST_M, + COMMAND_TOURQUE_M, + COMMAND_SPEED_M +} message_type; + +//command message variables for inverter +typedef enum i_direction { + REVERSE, //clock-wise + FORWARD //counter-clock-wise +} inverter_direction; + +typedef enum i_enable { + ENABLE, + DISABLE +} inverter_enable; + + + +class command_message{ + + public: + + message_type command_message; + + int* create_command_message( message_type command_message, + float torque_val, //Value in N.m + float speed_val, //RPM + inverter_direction direction_command, + inverter_enable enable_command ); + + + + + + + + + +}; + +#endif diff --git a/Inverter/src/Actuator.h b/Inverter/src/Actuator.h new file mode 100644 index 0000000..37d7675 --- /dev/null +++ b/Inverter/src/Actuator.h @@ -0,0 +1,32 @@ +#ifndef Actuator_H +#define Actuator_H + +#include "Base.h" + +// Actuator identifiers +typedef enum actuators_t { + A_BRAKES, + A_INVERTER +} actuators_t; + +typedef struct ActuatorState { + errorlevel_t error; + debuglevel_t debug; + float target; +} ActuatorState; + +class Actuator{ + protected: + virtual errorlevel_t set(float target) = 0; + virtual errorlevel_t init() = 0; + ActuatorState state; + public: + arduino_t arduino; + actuators_t actuator; + float failtarget; // what should we default to in case of failure? + Actuator(actuators_t actuator, arduino_t arduino, float failtarget); + ActuatorState* update(); + ActuatorState* begin(); +}; + +#endif \ No newline at end of file diff --git a/Inverter/src/Base.h b/Inverter/src/Base.h new file mode 100644 index 0000000..623ae26 --- /dev/null +++ b/Inverter/src/Base.h @@ -0,0 +1,32 @@ +#ifndef BASE_H +#define BASE_H + +#include "Arduino.h" +#include "stdlib.h" + +// Arduino identifiers +typedef enum arduino_t { + ARDUINO_ONE, + ARDUINO_TWO, + ARDUINO_THREE +} arduino_t; + +// Degree of error occurred +// TODO: Maybe add more specific codes? (i.e. hardware/wiring fail, comms/protocol fail, etc.) +typedef enum errorlevel_t { + ERR_NONE, + ERR_WARN, + ERR_FAIL //NOTE: Implies debug level 'DISABLED' +} errorlevel_t; + +// General state - On fail != 0, what state did it last complete successfully? +typedef enum debuglevel_t { + //NOTE: The various debug states imply the value of cache.state.data as follows: + DS_DISABLED, //NULL + DS_INIT, //NULL + // DS_CALIBRATING, //NULL if first time, otherwise unknown + DS_WAITING, //NOT NULL, age > 0 + DS_SUCCESS //NOT NULL, age == 0 +} debuglevel_t; + +#endif \ No newline at end of file diff --git a/Inverter/src/Inverter.cpp b/Inverter/src/Inverter.cpp new file mode 100644 index 0000000..ffdb9db --- /dev/null +++ b/Inverter/src/Inverter.cpp @@ -0,0 +1,33 @@ +#include "Actuator.h" +#include "Inverter.h" + +Inverter::Inverter(Serial_CAN* CANBus, arduino_t arduino) : Actuator(A_INVERTER, arduino, 0) { + this->CANBus = CANBus; +} + +int* create_command_message (message_type command, float value, inverter_direction direction, inverter_enable enable){ + int data_high_byte; + int data_low_byte; + + if(command == COMMAND_TOURQUE_M){ + if(value >= 0){ + data_low_byte = int(value * 10) % 256; + data_high_byte = int(value * 10) / 256; + } else{ + data_low_byte = ( int(value * 10) & 255 ); + data_high_byte = ( int(value * 10) & 65280 ) >> 8; + } + + static int can_data_bytes[8] = { data_low_byte, data_high_byte, 0, 0, direction, enable, 0, 0 }; + + return can_data_bytes; + } else if(command == COMMAND_SPEED_M){ + + data_low_byte = int(value) % 256; + data_high_byte = value / 256; + + static int can_data_bytes[8] = { 0, 0, data_low_byte, data_high_byte, direction, enable, 0, 0 }; + + return can_data_bytes; + } +} \ No newline at end of file diff --git a/Inverter/src/Inverter.h b/Inverter/src/Inverter.h new file mode 100644 index 0000000..755b7ba --- /dev/null +++ b/Inverter/src/Inverter.h @@ -0,0 +1,36 @@ +#ifndef INVERTER_H +#define INVERTER_H + +#include "Actuator.h" +#include "Serial_CAN_Module.h" + +//types of CAN messages +typedef enum m_type { + BROADCAST_M, + COMMAND_TOURQUE_M, + COMMAND_SPEED_M +} message_type; + +// COMMAND + +//command message variables for inverter +typedef enum i_direction { + REVERSE, //clock-wise + FORWARD //counter-clock-wise +} inverter_direction; + +typedef enum i_enable { + DISABLE, + ENABLE +} inverter_enable; + +class Inverter : public Actuator { + public: + Inverter(Serial_CAN* CANBus, arduino_t arduino); + private: + Serial_CAN* CANBus; + errorlevel_t set(float target) override; + errorlevel_t init() override; +}; + +#endif \ No newline at end of file diff --git a/Inverter/src/InverterDebug.cpp b/Inverter/src/InverterDebug.cpp new file mode 100644 index 0000000..ba5fad7 --- /dev/null +++ b/Inverter/src/InverterDebug.cpp @@ -0,0 +1,127 @@ +#include "Sensor.h" +#include "InverterDebug.h" + +InverterDebug::InverterDebug(Serial_CAN* CANBus, arduino_t arduino) : Sensor(S_INVERTERDEBUG, arduino, 1000) { + this->CANBus = CANBus; +} + +InverterDebug::init(){ + return ERR_NONE; +} + +errorlevel_t InverterDebug::read(t_datum* data, uint8_t numdata){ + // TODO: Get can message + int msg[9] = {0,0,0,0,0,0,0,0,0}; + data[0].data = read_vsm_state(msg); + data[1].data = read_inverter_state(msg); + data[2].data = read_fault_codes(msg); + // TODO: fault triggers return error + return ERR_NONE; +} + +vsm_state read_vsm_state(int CAN_msg[9]) +{ + if (CAN_msg[0] != 0x0AA || !((CAN_msg[2] >= 0 && CAN_msg[2] <= 7) || CAN_msg[2] == 14 || CAN_msg[2] == 15)){ + // cout << "Message CAN ID is not 0x0AA, this is NOT a VSM message" << endl; + return NOT_A_VSM_STATE; + } + return (vsm_state)CAN_msg[2]; +} + +inverter_state read_inverter_state(int CAN_msg[9]) +{ + if (CAN_msg[0] != 0x0AA || !((CAN_msg[3] >=0 && CAN_msg[3] <= 4) || CAN_msg[3] == 8 || CAN_msg[3] == 9)) + { + // cout << "Message CAN ID is not 0xAA, this is NOT an inverter" << endl; + return NOT_AN_INVERTER_STATE; + } + + return (inverter_state)CAN_msg[3]; +} + +/* Disable one or more messages at a time + * Example usage: disable_broadcast_message(test_msg, TEMPERATURE_2 | CURRENT_INFORMATION | DIAG_DATA); + */ +void disable_broadcast_message(int CAN_msg[9], int listOfMsgs) +{ + if (CAN_msg[0] != 0x0C1 || CAN_msg[1] != 148) // CAN ID + { + // cout << "Message CAN Address is not 0x0C1" << endl; + // cout << "Message Parameter Address is not 148" << endl; + return; + } + + int loWord = (CAN_msg[6] << 8) | CAN_msg[5]; // loWord = [6] concatenated with [5] + + if ((TEMPERATURE_1 & listOfMsgs) == TEMPERATURE_1) + loWord &= ~(1U); + if ((TEMPERATURE_2 & listOfMsgs) == TEMPERATURE_2) + loWord &= ~(1U << 1); + if ((TEMPERATURE_3 & listOfMsgs) == TEMPERATURE_3) + loWord &= ~(1U << 2); + if ((ANALOG_INPUT_VOLTAGES & listOfMsgs) == ANALOG_INPUT_VOLTAGES) + loWord &= ~(1U << 3); + if ((DIGITAL_INPUT_STATUS & listOfMsgs) == DIGITAL_INPUT_STATUS) + loWord &= ~(1U << 4); + if ((MOTOR_POSITION_INFORMATION & listOfMsgs) == MOTOR_POSITION_INFORMATION) + loWord &= ~(1U << 5); + if ((CURRENT_INFORMATION & listOfMsgs) == CURRENT_INFORMATION) + loWord &= ~(1U << 6); + if ((VOLTAGE_INFORMATION & listOfMsgs) == VOLTAGE_INFORMATION) + loWord &= ~(1U << 7); + if ((FLUX_INFORMATION & listOfMsgs) == FLUX_INFORMATION) + loWord &= ~(1U << 8); + if ((INTERNAL_VOLTAGES & listOfMsgs) == INTERNAL_VOLTAGES) + loWord &= ~(1U << 9); + if ((INTERNAL_STATES & listOfMsgs) == INTERNAL_STATES) + loWord &= ~(1U << 10); + if ((FAULT_CODES & listOfMsgs) == FAULT_CODES) + loWord &= ~(1U << 11); + if ((TORQUE_AND_TIMER_INFORMATION & listOfMsgs) == TORQUE_AND_TIMER_INFORMATION) + loWord &= ~(1U << 12); + if ((MOD_INDEX_FLUX_WEAKENING_OUTPUT_INFO & listOfMsgs) == MOD_INDEX_FLUX_WEAKENING_OUTPUT_INFO) + loWord &= ~(1U << 13); + if ((FIRMWARE_INFORMATION & listOfMsgs) == FIRMWARE_INFORMATION) + loWord &= ~(1U << 14); + if ((DIAG_DATA & listOfMsgs) == DIAG_DATA) + loWord &= ~(1U << 15); + + // Separate loWord back into two bytes + CAN_msg[5] = loWord & 0xFF; + CAN_msg[6] = (loWord >> 8) & 0xFF; +} + +int64_t read_fault_codes(int CAN_msg[9]) { + //extract the CAN ID & define return vector of fault codes + int CAN_ID = CAN_msg[0]; + int64_t faults; + + //check if CAN message is FAULT message + if( CAN_ID != 0x0AB ){ + faults |= 1UL << 64; + } else if( CAN_ID == 0x0AB ){ + int fault_byte = 0; //var used for indexing fault code array + + //here we'll loop 8 times, analyze each CAN data byte + for( int msgbyte = 0; msgbyte < 8; msgbyte++ ) + { + int byte_i = CAN_msg[msgbyte]; + + //vars to check each bit of current byte + int current_bit; + int int_to_binary = byte_i; + for( int i = 0; i < 8; i++ ){ + current_bit = int_to_binary % 2; + int_to_binary = int_to_binary / 2; + + if( current_bit ){ + faults |= 1ULL << (fault_byte*8 + i); + } + } + + fault_byte++; + } + } + + return faults; +} \ No newline at end of file diff --git a/Inverter/src/InverterDebug.h b/Inverter/src/InverterDebug.h new file mode 100644 index 0000000..de65ce4 --- /dev/null +++ b/Inverter/src/InverterDebug.h @@ -0,0 +1,176 @@ +#ifndef INVERTERDEBUG_H +#define INVERTERDEBUG_H + +#include "Sensor.h" +#include "Serial_CAN_Module.h" + +//types of CAN messages +typedef enum m_type { + BROADCAST_M, + COMMAND_TOURQUE_M, + COMMAND_SPEED_M +} message_type; + +// BROADCAST + +typedef enum vsm_state +{ + VSM_START, + PRE_CHARGE_INIT, + PRE_CHARGE_ACTIVE, + PRE_CHARGE_COMPLETE, + VSM_WAIT, + VSM_READY, + MOTOR_RUNNING, + BLINK_FAULT_CODE, + SHUTDOWN_IN_PROGRESS = 14, + RECYCLE_POWER, + NOT_A_VSM_STATE +} vsm_state; + +// Reference 0x0AA - Internal States, Byte #2 +typedef enum inverter_state +{ + POWER_ON, + STOP, + OPEN_LOOP, + CLOSED_LOOP, + WAIT, + IDLE_RUN = 8, + IDLE_STOP, + NOT_AN_INVERTER_STATE = 13 +} inverter_state; + +// Reference Param Address 148 +typedef enum can_active_messages_lo_word +{ + // Data Byte 4 + TEMPERATURE_1 = 0x0001, + TEMPERATURE_2 = 0x0002, + TEMPERATURE_3 = 0x0004, + ANALOG_INPUT_VOLTAGES = 0x0008, + DIGITAL_INPUT_STATUS = 0x0010, + MOTOR_POSITION_INFORMATION = 0x0020, + CURRENT_INFORMATION = 0x0040, + VOLTAGE_INFORMATION = 0x0080, + // Data Byte 5 + FLUX_INFORMATION = 0x0100, + INTERNAL_VOLTAGES = 0x0200, + INTERNAL_STATES = 0x0400, + FAULT_CODES = 0x0800, + TORQUE_AND_TIMER_INFORMATION = 0x1000, + MOD_INDEX_FLUX_WEAKENING_OUTPUT_INFO = 0x2000, + FIRMWARE_INFORMATION = 0x4000, + DIAG_DATA = 0x8000 +} can_active_messages_lo_word; + +// Reference Param Address 148, should always be enabled (default) +typedef enum can_active_messages_hi_word +{ + // Data Byte 6 + SLAVE_MODE_COMMAND_MESSAGE = 6, + BMS_COMMAND_MESSAGE, + // Data Byte 7 + OBD2_GENERAL_QUERY, + OBD2_SPECIFIC_QUERY, + OBD2_RESPONSE, + U2C_TX_MESSAGE, + U2C_RX_MESSAGE, + PARAMETER_RESPONSE_MESAGE, + PARAMETER_COMMAND_MESSAGE, + CAN_COMMAND_MESSAGE +} can_active_messages_hi_word; + +//All types of Fault Codes +typedef enum fault_code +{ + //POST FAULTS + //Byte 0 + Hardware_Gate_Desaturation_Fault, + HW_Over_current_Fault, + Accelerator_Shorted, + Accelerator_Open, + Current_Sensor_Low, + Current_Sensor_High, + Module_Temperature_Low, + Module_Temperature_High, + //Byte 1 + Control_PCB_Temperature_Low, + Control_PCB_Temperature_High, + Gate_Drive_PCB_Temperature_Low, + Gate_Drive_PCB_Temperature_High, + Sense_Voltage_Low_5V, + Sense_Voltage_High_5V, + Sense_Voltage_Low_12V, + Sense_Voltage_High_12V, + //Byte 2 + Sense_Voltage_Low_2_5V, + Sense_Voltage_High_2_5V, + Sense_Voltage_Low_1_5V, + Sense_Voltage_High_1_5V, + DC_Bus_Voltage_High, + DC_Bus_Voltage_Low, + Pre_charge_Timeout, + Pre_charge_Voltage_Failure, + //Byte 3 + EEPROM_Checksum_Invalid, + EEPROM_Data_Out_of_Range, + EEPROM_Update_Required, + RESERVED_1, + RESERVED_2, + RESERVED_3, + Brake_Shorted, + Brake_Open, + //Byte 4 + //RUN FAULTS + Motor_Over_speed_Fault, + Over_current_Fault, + Over_voltage_Fault, + Inverter_Over_temperature_Fault, + Accelerator_Input_Shorted_Fault, + Accelerator_Input_Open_Fault, + Direction_Command_Fault, + Inverter_Response_Time_out_Fault, + //Byte 5 + Hardware_Gate_Desaturation_RUN_Fault, + Hardware_Over_current_Fault, + Under_voltage_Fault, + CAN_Command_Message_Lost_Fault, + Motor_Over_temperature_Fault, + RESERVED_4, + RESERVED_5, + RESERVED_6, + //Byte 6 + Brake_Input_Shorted_Fault, + Brake_Input_Open_Fault, + Module_A_Over_temperature_Fault, + Module_B_Over_temperature_Fault, + Module_C_Over_temperature_Fault, + PCB_Over_temperature_Fault, + Gate_Drive_Board_1_Over_temperature_Fault, + Gate_Drive_Board_2_Over_temperature_Fault, + //Byte 7 + Gate_Drive_Board_3_Over_temperature_Fault, + Current_Sensor_Fault, + RESERVED_7, + Hardware_Over_Voltage_Fault, + RESERVED_8, + RESERVED_9, + Resolver_Not_Connected, + Inverter_Discharge_Active, + + //Finally, error if the CAN mssg is NOT for fault codes + NOT_FAULT_CAN_MSSG + +} PM100_FAULT_CODE; + +class InverterDebug : public Sensor { + public: + InverterDebug(Serial_CAN* CANBus, arduino_t arduino); + private: + Serial_CAN* CANBus; + errorlevel_t read(t_datum* data, uint8_t numdata) override; + errorlevel_t init() override; +}; + +#endif \ No newline at end of file diff --git a/Inverter/src/Sensor.h b/Inverter/src/Sensor.h new file mode 100644 index 0000000..3fa9c50 --- /dev/null +++ b/Inverter/src/Sensor.h @@ -0,0 +1,69 @@ +#ifndef Sensor_H +#define Sensor_H + +#include "Base.h" + +// Sensor identifiers +typedef enum sensors_t { + S_OPT2002, + S_VN200, + S_PROSENSERTD, + S_TMP006, + S_MPU9250, + S_DCT500, + S_SPTD25_20_1000H, + S_SPTD25_20_0200A, + S_CANBUS, + S_INVERTERDEBUG +} sensors_t; + +// Single datapoint +typedef struct t_datum { + float data; + const char* units; +} t_datum; + +// All sensor state info + latest datum - used as the "cache" in the sensor object +// TODO: Replace state enums with state structs containing messages, etc. +typedef struct SensorState { + errorlevel_t error; + debuglevel_t debug; + uint16_t timestamp; //Last data update (millis since start) + t_datum* data; //Array of datum + uint8_t numdata; +} SensorState; + +// Wrapper for all sensor stuff - this is what gets passed to the main computer +typedef struct SensorData { + sensors_t sensor; + arduino_t arduino; + SensorState state; +} SensorData; + +struct t_datasetup { + uint8_t numdata; + const char** units; +}; + +// Sensor class - note the difference in exposure and implementation in read/init and getRead/begin +class Sensor{ + private: + unsigned long delta; //The minimum time (milliseconds) between sensor updates. + unsigned long lastread; //Timestamp of last read ATTEMPT + protected: + // Sensor-specific functionality initialize and read functions - to be implemented by sensor classes + virtual errorlevel_t init() = 0; //Connect to sensor, calibrate, set data count and units, and update state accordingly + virtual errorlevel_t read(t_datum* data, uint8_t numdata) = 0; //Get ALL data from the sensor hardware -> data[i in numdata] + + // State and IDs + SensorState state; //Stores all the latest state data for this sensor. + public: + arduino_t arduino; + sensors_t sensor; + // Wrappers return pointer to updated state + SensorState* update(); //Calls read(), manages delta, and wraps all t_datum + SensorState* begin(); //Sets state in accordance with init() + Sensor(sensors_t sensor, arduino_t arduino, t_datasetup setup, unsigned long delta); +}; + +#endif \ No newline at end of file diff --git a/Inverter/src/Serial_CAN_Module.cpp b/Inverter/src/Serial_CAN_Module.cpp new file mode 100644 index 0000000..c1c6638 --- /dev/null +++ b/Inverter/src/Serial_CAN_Module.cpp @@ -0,0 +1,408 @@ +// ID3 ID2 ID1 ID0 EXT RTR DTA0 DTA1 DTA2 DTA3 DTA4 DTA5 DTA6 DTA7 + +#include +#include + +SoftwareSerial *canSerial = NULL; + +void Serial_CAN::begin(int can_tx, int can_rx, unsigned long baud) +{ + canSerial = new SoftwareSerial(can_tx, can_rx); + //Serial.println("Hello, we are inside begin()"); + canSerial->begin(baud); +} + +unsigned char Serial_CAN::send(unsigned long id, uchar ext, uchar rtrBit, uchar len, const uchar *buf) +{ + unsigned char dta[14] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + dta[0] = id>>24; // id3 + dta[1] = id>>16&0xff; // id2 + dta[2] = id>>8&0xff; // id1 + dta[3] = id&0xff; // id0 + + dta[4] = ext; + dta[5] = rtrBit; + + + for(int i=0; iwrite(dta[i]); + } + + for(int i=0; i<14; i++) + { + //Serial.print( "Sending data frame:" ); + //Serial.println( dta[i] ); + } + + +} + + +// 0: no data +// 1: get data +unsigned char Serial_CAN::recv(unsigned long *id, uchar *buf) +{ + if(canSerial->available()) + { + unsigned long timer_s = millis(); + + int len = 0; + uchar dta[20]; + + while(1) + { + while(canSerial->available()) + { + dta[len++] = canSerial->read(); + if(len == 12) + break; + + if((millis()-timer_s) > 10) + { + canSerial->flush(); + return 0; // Reading 12 bytes should be faster than 10ms, abort if it takes longer, we loose the partial message in this case + } + } + + if(len == 12) // Just to be sure, must be 12 here + { + unsigned long __id = 0; + + for(int i=0; i<4; i++) // Store the id of the sender + { + __id <<= 8; + __id += dta[i]; + } + + *id = __id; + + for(int i=0; i<8; i++) // Store the message in the buffer + { + buf[i] = dta[i+4]; + } + return 1; + } + + if((millis()-timer_s) > 10) + { + canSerial->flush(); + return 0; // Reading 12 bytes should be faster than 10ms, abort if it takes longer, we loose the partial message in this case + } + + } + } + + return 0; +} + +unsigned char Serial_CAN::cmdOk(char *cmd) +{ + + unsigned long timer_s = millis(); + unsigned char len = 0; + + canSerial->println(cmd); + + //Serial.println(cmd); + //Serial.println("Printing cmd above."); + + while(1) + { + if(millis()-timer_s > 500) + { + return 0; + } + + while(canSerial->available()) + { + + str_tmp[len++] = canSerial->read(); + timer_s = millis(); + } + + if(len >= 4 && str_tmp[len-1] == '\n' && str_tmp[len-2] == '\r' && str_tmp[len-3] == 'K' && str_tmp[len-4] == 'O') + { + clear(); + return 1; + } + + } +} + +/* +value 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 +rate(kb/s) 5 10 20 25 31.2 33 40 50 80 83.3 95 100 125 200 250 500 666 1000 +*/ +unsigned char Serial_CAN::canRate(unsigned char rate) +{ + double rates[18] = {5, 10, 20, 25, 31.2, 33, 40, 50, 80, 83.3, 95, 100, 125, 200, 250, 500, 666, 1000}; + + enterSettingMode(); + if(rate < 10) + sprintf(str_tmp, "AT+C=0%d\r\n", rate); + else + sprintf(str_tmp, "AT+C=%d\r\n", rate); + + int ret = cmdOk(str_tmp); + + Serial.print("Serial CAN Rate set to: "); + Serial.println(rates[rate-1]); + + exitSettingMode(); + return ret; +} + +/* +value 0 1 2 3 4 +baud rate(b/s) 9600 19200 38400 57600 115200 +*/ + +unsigned char Serial_CAN::baudRate(unsigned char rate) +{ + unsigned long baud[5] = {9600, 19200, 38400, 57600, 115200}; + int baudNow = 0; + + for(int i=0; i<5; i++) + { + canSerial->begin(baud[i]); + canSerial->print("+++"); + delay(100); + + if(cmdOk( (char*)"AT\r\n" )) + { + //Serial.print("SERIAL BAUD RATE IS: "); + //Serial.println(baud[i]); + baudNow = i; + break; + } + } + + sprintf(str_tmp, "AT+S=%d\r\n", rate); + cmdOk(str_tmp); + + canSerial->begin(baud[rate]); + + int ret = cmdOk( (char*)"AT\r\n" ); + + if(ret) + { + Serial.print("Serial Baud Rate set to: "); + Serial.println(baud[rate]); + } + + exitSettingMode(); + return ret; +} + + +void Serial_CAN::clear() +{ + unsigned long timer_s = millis(); + while(1) + { + if(millis()-timer_s > 50)return; + while(canSerial->available()) + { + canSerial->read(); + timer_s = millis(); + } + } +} + +unsigned char Serial_CAN::enterSettingMode() +{ + canSerial->print("+++"); + clear(); + + //Serial.println("Inside enterSettingMode()"); + + return 1; +} + +unsigned char Serial_CAN::exitSettingMode() +{ + clear(); + int ret = cmdOk((char*)"AT+Q\r\n"); + clear(); + return ret; +} + +void make8zerochar(int n, char *str, unsigned long num) +{ + for(int i=0; i>= 4; + } + str[n] = '\0'; +} + +/* ++++ Switch from Normal mode to Config mode +AT+S=[value] Set serial baud rate +AT+C=[value] Set CAN Bus baud rate +AT+M=[N][EXT][value] Set mask,AT+M=[1][0][000003DF] +AT+F=[N][EXT][value] Set filter,AT+F=[1][0][000003DF] +AT+Q Switch to Normal Mode +*/ +unsigned char Serial_CAN::setMask(unsigned long *dta) +{ + enterSettingMode(); + char __str[10]; + + + for(int i=0; i<2; i++) + { + make8zerochar(8, __str, dta[1+2*i]); + //Serial.println(__str); + sprintf(str_tmp, "AT+M=[%d][%d][", i, dta[2*i]); + for(int i=0; i<8; i++) + { + str_tmp[12+i] = __str[i]; + } + str_tmp[20] = ']'; + str_tmp[21] = '\r'; + str_tmp[22] = '\n'; + str_tmp[23] = '\0'; + + //Serial.println(str_tmp); + + if(!cmdOk(str_tmp)) + { + Serial.print("mask fail - "); + Serial.println(i); + exitSettingMode(); + return 0; + } + clear(); + delay(10); + // + } + exitSettingMode(); + return 1; + +} + +unsigned char Serial_CAN::setFilt(unsigned long *dta) +{ + enterSettingMode(); + + char __str[10]; + + for(int i=0; i<6; i++) + { + make8zerochar(8, __str, dta[1+2*i]); + //Serial.println(__str); + sprintf(str_tmp, "AT+F=[%d][%d][", i, dta[2*i]); + for(int i=0; i<8; i++) + { + str_tmp[12+i] = __str[i]; + } + str_tmp[20] = ']'; + str_tmp[21] = '\r'; + str_tmp[22] = '\n'; + str_tmp[23] = '\0'; + + //Serial.println(str_tmp); + + clear(); + if(!cmdOk(str_tmp)) + { + //Serial.print("filt fail at - "); + //Serial.println(i); + exitSettingMode(); + return 0; + } + clear(); + delay(10); + // + } + exitSettingMode(); + return 1; +} + +/* +value 0 1 2 3 4 +baud rate(b/s) 9600 19200 38400 57600 115200 +*/ +unsigned char Serial_CAN::factorySetting() +{ + // check baudrate + unsigned long baud[5] = {9600, 19200, 38400, 57600, 115200}; + + for(int i=0; i<5; i++) + { + canSerial->begin(baud[i]); + canSerial->print("+++"); + delay(100); + + if(cmdOk( (char*)"AT\r\n")) + { + Serial.print("SERIAL BAUD RATE IS: "); + Serial.println(baud[i]); + baudRate(0); // set serial baudrate to 9600 + Serial.println("SET SERIAL BAUD RATE TO: 9600 OK"); + canSerial->begin(9600); + break; + } + } + + if(canRate(CAN_RATE_500)) + { + Serial.println("SET CAN BUS BAUD RATE TO 500Kb/s OK"); + } + else + { + Serial.println("SET CAN BUS BAUD RATE TO 500Kb/s FAIL"); + return 0; + } + + unsigned long mask[4] = {0, 0, 0, 0,}; + unsigned long filt[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; + + if(setFilt(filt)) + { + Serial.println("FACTORY SETTING FILTS OK"); + } + else + { + Serial.println("FACTORY SETTING FILTS FAIL"); + return 0; + } + + if(setMask(mask)) + { + Serial.println("FACTORY SETTING MASKS OK"); + } + else + { + Serial.println("FACTORY SETTING MASKS FAIL"); + return 0; + } + + return 1; +} + +void Serial_CAN::debugMode() +{ + while(Serial.available()) + { + canSerial->write(Serial.read()); + } + + while(canSerial->available()) + { + Serial.write(canSerial->read()); + } +} + +// END FILE diff --git a/Inverter/src/Serial_CAN_Module.h b/Inverter/src/Serial_CAN_Module.h new file mode 100644 index 0000000..c053ccf --- /dev/null +++ b/Inverter/src/Serial_CAN_Module.h @@ -0,0 +1,57 @@ +#ifndef __SERIAL_CAN_MODULE_H__ +#define __SERIAL_CAN_MODULE_H__ +// ID3 ID2 ID1 ID0 EXT RTR DTA0 DTA1 DTA2 DTA3 DTA4 DTA5 DTA6 DTA7 +#include +#define uchar unsigned char + + +#define CAN_RATE_5 1 +#define CAN_RATE_10 2 +#define CAN_RATE_20 3 +#define CAN_RATE_25 4 +#define CAN_RATE_31_2 5 +#define CAN_RATE_33 6 +#define CAN_RATE_40 7 +#define CAN_RATE_50 8 +#define CAN_RATE_80 9 +#define CAN_RATE_83_3 10 +#define CAN_RATE_95 11 +#define CAN_RATE_100 12 +#define CAN_RATE_125 13 +#define CAN_RATE_200 14 +#define CAN_RATE_250 15 +#define CAN_RATE_500 16 +#define CAN_RATE_666 17 +#define CAN_RATE_1000 18 + +#define SERIAL_RATE_9600 0 +#define SERIAL_RATE_19200 1 +#define SERIAL_RATE_38400 2 +#define SERIAL_RATE_57600 3 +#define SERIAL_RATE_115200 4 + +class Serial_CAN +{ +private: + unsigned char cmdOk(char *cmd); + unsigned char enterSettingMode(); + unsigned char exitSettingMode(); + void clear(); + char str_tmp[100]; +public: + + void begin(int can_tx, int can_rx, unsigned long baud); + unsigned char send(unsigned long id, uchar ext, uchar rtrBit, uchar len, const uchar *buf); + unsigned char recv(unsigned long *id, uchar *buf); + + unsigned char canRate(unsigned char rate); + unsigned char baudRate(unsigned char rate); + + unsigned char setMask(unsigned long *dta); + unsigned char setFilt(unsigned long *dta); + + unsigned char factorySetting(); + void debugMode(); + +}; +#endif \ No newline at end of file diff --git a/Inverter/tests/recv_basic_test.ino b/Inverter/tests/recv_basic_test.ino new file mode 100644 index 0000000..29a3b51 --- /dev/null +++ b/Inverter/tests/recv_basic_test.ino @@ -0,0 +1,56 @@ +// RECV EXAMPLE OF SERIAL CAN MODULE +// unsigned char recv(unsigned long *id, uchar *buf); +// SUPPORT: joney.sui@longan-labs.cc +//First recv() test by Adam P + +#include +#include + +Serial_CAN can; + +#define can_tx 10 //TX of Serial CAN Module connected to D10 +#define can_rx 11 //RX of Serial CAN Module connected to D11 + + +void setup() +{ + Serial.begin(9600); + while(!Serial); + can.begin(can_tx, can_rx, 9600); + + if(can.canRate(CAN_RATE_500)) + { + Serial.println("Set CAN rate OK"); + } + else + { + Serial.println("Set CAN rate FAIL"); + } +} + +unsigned long id = 5; +unsigned char dta[8]; + +// send(unsigned long id, byte ext, byte rtrBit, byte len, const byte *buf); +void loop() +{ + + can.debugMode(); + if(can.recv(&id, dta)) + { + Serial.print("GETTING DATA FROM ID: "); + Serial.println(id); + for(int i=0; i<8; i++) + { + Serial.print("0x"); + Serial.print(dta[i], HEX); + Serial.print('\t'); + } + Serial.println(); + } + else{ + //Serial.print("Didn't work!!!"); + } +} + +// END FILE diff --git a/Inverter/tests/recv_mask_filt_test_2.ino b/Inverter/tests/recv_mask_filt_test_2.ino new file mode 100644 index 0000000..17c653a --- /dev/null +++ b/Inverter/tests/recv_mask_filt_test_2.ino @@ -0,0 +1,75 @@ +// RECV EXAMPLE OF SERIAL CAN MODULE - WITH MASK/FILTERING +// +// SUPPORT: joney.sui@longan-labs.cc +//Second recv() test by Adam P + +#include +#include + +Serial_CAN can; + +#define can_tx 10 //TX of Serial CAN Module connected to D10 +#define can_rx 11 //RX of Serial CAN Module connected to D11 + +unsigned long mask[4] = +{ + 0, 0x0f, // ext, maks 0 + 0, 0x0f, // ext, mask 1 +}; + +unsigned long filt[12] = +{ + 0, 0xff, // ext, filt 0 + 0, 0xff, // ext, filt 1 + 0, 0xff, // ext, filt 2 + 0, 0xff, // ext, filt 3 + 0, 0xff, // ext, filt 4 + 0, 0xff, // ext, filt 5 +}; + +void setup() +{ + Serial.begin(9600); + while(!Serial); + can.begin(can_tx, can_rx, 9600); // tx, rx + + if(can.setFilt(filt)) + { + Serial.println("set filt ok"); + } + else + { + Serial.println("set filt fail"); + } + + if(can.setMask(mask)) + { + Serial.println("set mask ok"); + } + else + { + Serial.println("set mask fail"); + } + +} + +void loop() +{ + unsigned long id = 0; + unsigned char dta[8]; + + if(can.recv(&id, dta)) + { + Serial.print("GET DATA FROM ID: "); + Serial.println(id); + for(int i=0; i<8; i++) + { + Serial.print("0x"); + Serial.print(dta[i], HEX); + Serial.print('\t'); + } + Serial.println(); + } +} + +// END FILE diff --git a/Inverter/tests/send_basic_test.ino b/Inverter/tests/send_basic_test.ino new file mode 100644 index 0000000..39368be --- /dev/null +++ b/Inverter/tests/send_basic_test.ino @@ -0,0 +1,37 @@ +// SEND EXAMPLE OF SERIAL CAN MODULE +// unsigned char send(unsigned long id, uchar ext, uchar rtrBit, uchar len, const uchar *buf); +// SUPPORT: joney.sui@longan-labs.cc +//First send() test by Adam P + +#include +#include + +Serial_CAN can; + +#define can_tx 10 //TX of Serial CAN Module connected to D10 +#define can_rx 11 //RX of Serial CAN Module connected to D11 + + +void setup() +{ + Serial.begin(9600); //Baud Rates: 9600, 19200, 38400, 57600, 74880, 115200 + //9600 works the best, higher rates start to have problems + can.begin(can_tx, can_rx, 9600); + Serial.println("Starting:"); + //can.debugMode(); +} + + +unsigned char dta[8] = {1, 2, 3, 4, 5, 10, 11, 12}; + + +// send(unsigned long id, byte ext, byte rtrBit, byte len, const byte *buf); +void loop() +{ + can.send(0x77, 0, 0, 8, dta); // SEND TO ID:0X77 + // CAN ID is not important for testing, all frames will be recieved + delay(100); + //can.debugMode(); +} + +// END FILE diff --git a/Inverter/tests/send_mask_filt_test_2.ino b/Inverter/tests/send_mask_filt_test_2.ino new file mode 100644 index 0000000..7d556e7 --- /dev/null +++ b/Inverter/tests/send_mask_filt_test_2.ino @@ -0,0 +1,37 @@ +// SEND EXAMPLE OF SERIAL CAN MODULE - WITH MASK/FILTERING +// unsigned char send(unsigned long id, uchar ext, uchar rtrBit, uchar len, const uchar *buf); +// SUPPORT: joney.sui@longan-labs.cc +//Second send() test by Adam P + +#include +#include + +Serial_CAN can; + +#define can_tx 10 //TX of Serial CAN Module connected to D10 +#define can_rx 11 //RX of Serial CAN Module connected to D11 + + +void setup() +{ + Serial.begin(9600); //Baud Rates: 9600, 19200, 38400, 57600, 74880, 115200 + //9600 works the best, higher rates start to have problems + can.begin(can_tx, can_rx, 9600); + Serial.println("Starting:"); + //can.debugMode(); +} + + +unsigned char dta[8] = {1, 2, 3, 4, 5, 10, 11, 12}; + + +// send(unsigned long id, byte ext, byte rtrBit, byte len, const byte *buf); +void loop() +{ + can.send(0x0f, 0, 0, 8, dta); // SEND TO ID:0x0f + // CAN ID is not important for testing, all frames will be recieved + delay(100); + //can.debugMode(); +} + +// END FILE diff --git a/Sensor.h b/Sensor.h index 9d384e4..3fa9c50 100644 --- a/Sensor.h +++ b/Sensor.h @@ -13,7 +13,8 @@ typedef enum sensors_t { S_DCT500, S_SPTD25_20_1000H, S_SPTD25_20_0200A, - S_CANBUS + S_CANBUS, + S_INVERTERDEBUG } sensors_t; // Single datapoint