Cell voltages fork (SoC)
Dependencies: CUER_CAN CUER_DS1820 LTC2943 LTC6804 mbed PowerControl
CANParserBMU.cpp
- Committer:
- maxv008
- Date:
- 2017-07-13
- Revision:
- 31:888b2602aab2
- Parent:
- 29:44924d2b1293
- Child:
- 45:c288d7cbdb4a
File content as of revision 31:888b2602aab2:
// Here are the functions to generate the CAN messages #include "CANParserBMU.h" #include "mbed.h" #include "Data_Types_BMU.h" #include "CAN_IDs.h" using namespace CAN_IDs; /** * This function is rewritten to give readings for individual probes rather than * for specific CMU. As a consequence, 0x800 onwards is being used for these probes, * as everything above about 0x700 is unused by the Tritium standard. The ID value * for the probe is based on the ROM field of DS1820, entries 1-6 being the unique * serial value. */ CANMessage createTemperatureTelemetry(uint8_t offset, char ProbeROM[8], float Temperature) { CANMessage msg; msg.len = 8; msg.id = TEMPERATURE_BASE_ID + offset; // for temp it is 0x800 onwards CAN_Data data; for(int i = 1; i <= 6; i++) //ID portion of ROM array { data.set_u8(i - 1, ProbeROM[i]); } //Conversion of float to a short, requires multiplying by 100 to not lose precision float temp100 = Temperature * 100; short shortTemp = (short) temp100; data.set_16(3, shortTemp);//There seems to be an error in the function definition for set_16, (ushort instead of short) for (int i = 0; i<8; i++) { msg.data[i] = data.get_u8(i); } return msg; } /** * Takes a CANMessage with precondition that it stores temperature of an individual * probe and returns an individual_temperature object containing ID and reading. * The ID is stores in ROM array entry 1-6, other entries may be invalid. */ individual_temperature decodeTemperatureTelemetry(CANMessage msg) { individual_temperature probe_reading; CAN_Data decode; unsigned long fullID = 0; decode.importCANData(msg); short shortTemp = decode.get_16(3); probe_reading.measurement = ((float)shortTemp) / 100; for(int i = 1; i <=6; i++) { probe_reading.ROMID[i] = decode.get_u8(i-1); fullID += (probe_reading.ROMID[i] << (8 * (i-1))); //Bit order not particularly important } probe_reading.ID = fullID; return probe_reading; } CANMessage createVoltageTelemetry(int offset_id, uint16_t voltage[]) { CANMessage msg; msg.len = 8; msg.id = BMS_BASE_ID + offset_id; // for voltage 0x601 - 0x6EF @TODO CAN_Data data; data.set_u16(0, voltage[0]); data.set_u16(1, voltage[1]); data.set_u16(2, voltage[2]); data.set_u16(3, voltage[3]); for (int i = 0; i<8; i++) { msg.data[i] = data.get_u8(i); } return msg; } /** * This function will properly fill the appropriate entry in an array of voltage * readings of the form CMU_voltage voltage[NO_CMUS]. Uses the msg ID and the standard * meanings of them as decided in the transmit data function (modified Tritium specs). * Function must only be called when the msg has a valid ID for voltage! */ bool decodeVoltageTelemetry(CANMessage msg, CMU_voltage readings[NO_CMUS]) { CAN_Data voltData; voltData.importCANData(msg); int repeating_length = NO_READINGS_PER_CMU /4 + 1; int offset = msg.id - BMS_BASE_ID; if(offset <= 0 || offset >= 0x10 || offset % 4 == 1) return false; int cellsubset = ((offset-1) % repeating_length) - 1; //Which set of 4 voltages within the CMU int CMU_number = (offset-1) / repeating_length; for(int i = 0; i < 4; i++) { readings[CMU_number].voltages[cellsubset*4 + i] = voltData.get_u16(i); } return true; } CANMessage createPackSOC(float SOC, float percentageCharge) { CANMessage msg; msg.len = 8; msg.id = BMS_BASE_ID + BATTERY_SOC_ID; //0x6F4 CAN_Data data; data.setLowerFloat(SOC); data.setUpperFloat(percentageCharge); for(int i=0; i<8; i++) { msg.data[i] = data.get_u8(i); } return msg; } CANMessage createPackBalanceSOC(float SOC, float percentageCharge) { // @TODO - check is this being used?? section 5.4 trituim BMU CAN data sheet CANMessage msg; msg.len = 8; msg.id = BMS_BASE_ID + BATTERY_SOC_BASE_ID; CAN_Data data; data.setLowerFloat(SOC); data.setUpperFloat(percentageCharge); for(int i=0; i<8; i++) { msg.data[i] = data.get_u8(i); } return msg; } /** * decodePackSOC and decodePackSOCPercentage can be used with both of the SOC msg types */ float decodePackSOC(CANMessage msg) { CAN_Data data; data.importCANData(msg); return data.getLowerFloat(); } float decodePackSOCPercentage(CANMessage msg) { CAN_Data data; data.importCANData(msg); return data.getUpperFloat(); } CANMessage createCellVoltageMAXMIN(pack_voltage_extremes max_voltage, pack_voltage_extremes min_voltage) { CANMessage msg; msg.len = 8; msg.id = BMS_BASE_ID + MAX_MIN_VOLTAGE; CAN_Data data; data.set_u16(0,min_voltage.voltage); //Min voltage data.set_u16(1,max_voltage.voltage); //Max voltage data.set_u8(4,min_voltage.CMU_number); //CMU number of lowest cell data.set_u8(5,min_voltage.cell_number); //Cell number in CMU with lowest voltage data.set_u8(6,max_voltage.CMU_number); //CMU number of maxiumum cell data.set_u8(7,max_voltage.cell_number); //Cell number in CMU with highest voltage for(int i=0; i<8; i++) { msg.data[i] = data.get_u8(i); } return msg; } void decodeCellVoltageMAXMIN(CANMessage msg, pack_voltage_extremes &min, pack_voltage_extremes &max) { CAN_Data decode; decode.importCANData(msg); min.voltage = decode.get_u16(0); max.voltage = decode.get_u16(1); min.CMU_number = decode.get_u8(4); min.cell_number = decode.get_u8(5); max.CMU_number = decode.get_u8(6); max.cell_number = decode.get_u8(7); } //Since each CAN message can only support 1 ID, need to send 2 using this function //Use bool isMin to say if its a minimum or maximum CANMessage createCellTemperatureMAXMIN(pack_temperature_extremes ex_temperature, bool isMin) { CANMessage msg; msg.len = 8; msg.id = BMS_BASE_ID + (isMin ? MIN_TEMPERATURE : MAX_TEMPERATURE) ; //TODO, CHANGE CMU NUMBER TO ROMID CAN_Data data; data.set_u16(3,ex_temperature.temperature); //Extreme temperature for(int i = 1; i <= 6; i++) //ID portion of ROM array { data.set_u8(i - 1, ex_temperature.ROMID[i]); } for(int i=0; i<8; i++) { msg.data[i] = data.get_u8(i); } return msg; } //It is up to function caller to decide by msg.ID if it is minimum or not pack_temperature_extremes decodeCellTemperatureMAXMIN(CANMessage msg) { pack_temperature_extremes result; CAN_Data decode; unsigned long fullID = 0; decode.importCANData(msg); result.temperature = decode.get_16(3); for(int i = 1; i <=6; i++) { result.ROMID[i] = decode.get_u8(i-1); fullID += (result.ROMID[i] << (8 * (i-1))); //Bit order not particularly important } result.ID = fullID; return result; } CANMessage createBatteryVI(uint32_t batteryVoltage, float batteryCurrent) { CANMessage msg; msg.len = 8; msg.id = BMS_BASE_ID + BATTERY_VI_ID; CAN_Data data; data.setLower_uLong(batteryVoltage); data.setUpperFloat(batteryCurrent); for(int i=0; i<8; i++) { msg.data[i] = data.get_u8(i); } return msg; } uint32_t decodeBatteryVoltage(CANMessage msg) { uint32_t result = 0; CAN_Data decode; decode.importCANData(msg); result = decode.getLower_uLong(); return result; } float decodeBatteryCurrent(CANMessage msg) { uint32_t result = 0; CAN_Data decode; decode.importCANData(msg); result = decode.getUpperFloat(); return result; } CANMessage createBatteryPackStatus(uint16_t voltageThreshold[], uint8_t statusFlag,uint8_t BMS_CMU_Count,uint16_t BMS_Firmware_Build) { CANMessage msg; msg.len = 8; msg.id = BMS_BASE_ID + BATTERY_PACK_STATUS_ID; CAN_Data data; data.set_u16(0,voltageThreshold[0]); data.set_u16(1,voltageThreshold[1]); data.set_16(3,BMS_Firmware_Build); data.set_u8(4,statusFlag); data.set_u8(5,BMS_CMU_Count); for(int i=0; i<8; i++) { msg.data[i] = data.get_u8(i); } return msg; } CANMessage createExtendedBatteryPackStatus(uint32_t status) { CANMessage msg; msg.len = 8; msg.id = BMS_BASE_ID + BATTERY_STATUS_ID; CAN_Data data; data.setLower_uLong(status); //@TODO see the data sheet for this data.set_u8(4,0x00);//Hardware version random data @TODO check this data.set_u8(5,0x00);//Model ID @TODO check this data.set_u16(3,0x00); // Unused for(int i=0; i<8; i++) { msg.data[i] = data.get_u8(i); } return msg; } uint32_t decodeExtendedBatteryPackStatus(CANMessage msg) { CAN_Data decode; decode.importCANData(msg); return decode.getLower_uLong(); } //Values here don't matter, added just in case. CANMessage createBMSHeartbeat(uint32_t val1, uint32_t val2) { CANMessage msg; msg.len = 8; msg.id = BMS_BASE_ID; CAN_Data data; data.setLower_uLong(val1); data.setHigher_uLong(val2); for(int i=0; i<8; i++) { msg.data[i] = data.get_u8(i); } return msg; } void convertFloatFloat(float lower, float upper, CANMessage& msg, bool littleEndian) { // Code taken from driver_controls //two converters for lower and higher float float2byte convL; float2byte convH; convL.f = lower; convH.f = upper; if(littleEndian) { for(int i=0; i<4; i++) { msg.data[i] = convL.b[i]; //offset for upper float msg.data[i+4]=convH.b[i]; } } else { for(int i=0; i<4; i++) { /* * Subtract because output data is Big Endian * i.e. convL/H is LSB --> MSB * output is MSB --> LSB */ msg.data[4-i] = convL.b[i]; msg.data[7-i] = convH.b[i]; } } }