Cell voltages fork (SoC)

Dependencies:   CUER_CAN CUER_DS1820 LTC2943 LTC6804 mbed PowerControl

CANParserBMU.cpp

Committer:
maxv008
Date:
2017-08-19
Revision:
53:4277cdcff69b
Parent:
48:5c3f42c44036
Child:
66:c884fba9eaea

File content as of revision 53:4277cdcff69b:

// 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;
    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, must be consistent    
    }
    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 = ((float) decode.get_16(3))/100;
    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)
{
    float result = 0;
    CAN_Data decode;
    decode.importCANData(msg);
    result = decode.getUpperFloat();
    return result;
}

CANMessage createIVTACurrent(int32_t current)
{
    CANMessage msg;
    msg.len = 8;
    msg.id = BMS_BASE_ID + IVTA_ID;

    CAN_Data data;
    data.setLower_Long(current);
    data.setHigher_Long(0);
    
    for(int i=0; i<8; i++) {
        msg.data[i] = data.get_u8(i);
    }
    return msg;
} 

int32_t decodeIVTACurrent(CANMessage msg)
{
    int32_t result = 0;
    CAN_Data decode;
    decode.importCANData(msg);
    result = decode.getLower_Long();
    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;
}

CANMessage createEEPROMReset(float init_SOC, float init_SOC_Percent) //TODO: Ensure ID doesn't conflict more carefully (It should be fine)
{
    CANMessage msg;
    msg.len = 8;
    msg.id = BMS_BASE_ID + EEPROM_RESET_ID;
    
    CAN_Data data;
    data.setLowerFloat(init_SOC);
    data.setUpperFloat(init_SOC_Percent);
    
    for(int i=0; i<8; i++) {
        msg.data[i] = data.get_u8(i);
    }
    return msg;    
}

float decodeEEPROMSOC(CANMessage msg)
{
    float result = 0;
    CAN_Data decode;
    decode.importCANData(msg);
    result = decode.getLowerFloat();
    return result;
}

float decodeEEPROMSOCPercentage(CANMessage msg)
{
    float result = 0;
    CAN_Data decode;
    decode.importCANData(msg);
    result = decode.getUpperFloat();
    return result;   
}

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];
        }
    }
}