refactor!
This commit is contained in:
parent
bd1e96a7bc
commit
9cffaa9025
231
ESPBMS.ino
231
ESPBMS.ino
@ -4,6 +4,14 @@ static BLEUUID serviceUUID("0000ff00-0000-1000-8000-00805f9b34fb"); //xiaoxiang
|
||||
static BLEUUID charUUID_rx("0000ff01-0000-1000-8000-00805f9b34fb"); //xiaoxiang bms rx id
|
||||
static BLEUUID charUUID_tx("0000ff02-0000-1000-8000-00805f9b34fb"); //xiaoxiang bms tx id
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte start;
|
||||
byte type;
|
||||
byte status;
|
||||
byte dataLen;
|
||||
} bmsPacketHeaderStruct;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
BLEDevice::init(""); // Initialize BLE device
|
||||
@ -108,9 +116,9 @@ void loop() {
|
||||
|
||||
static void MyNotifyCallback(BLERemoteCharacteristic *pBLERemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify){
|
||||
hexDump((char*)pData, length);
|
||||
/*if(!bleCollectPacket((char *)pData, length)){
|
||||
if(!bleCollectPacket((char *)pData, length)){
|
||||
Serial.println("ERROR: packet could not be collected.");
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
void hexDump(const char *data, uint32_t dataSize)
|
||||
@ -123,3 +131,222 @@ void hexDump(const char *data, uint32_t dataSize)
|
||||
}
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
bool bleCollectPacket(char *data, uint32_t dataSize) // reconstruct packet, called by notifyCallback function
|
||||
{
|
||||
static uint8_t packetstate = 0; //0 - empty, 1 - first half of packet received, 2- second half of packet received
|
||||
|
||||
// packet sizes:
|
||||
// (packet ID 03) = 4 (header) + 23 + 2*N_NTCs + 2 (checksum) + 1 (stop)
|
||||
// (packet ID 04) = 4 (header) + 2*NUM_CELLS + 2 (checksum) + 1 (stop)
|
||||
static uint8_t packetbuff[4 + 2*25 + 2 + 1] = {0x0}; // buffer size suitable for up to 25 cells
|
||||
|
||||
static uint32_t totalDataSize = 0;
|
||||
bool retVal = false;
|
||||
hexDump(data,dataSize);
|
||||
|
||||
if(totalDataSize + dataSize > sizeof(packetbuff)){
|
||||
Serial.printf("ERROR: datasize is overlength.");
|
||||
|
||||
Serial.println(
|
||||
String("ERROR: datasize is overlength. ") +
|
||||
String("allocated=") +
|
||||
String(sizeof(packetbuff)) +
|
||||
String(", size=") +
|
||||
String(totalDataSize + dataSize)
|
||||
);
|
||||
|
||||
totalDataSize = 0;
|
||||
packetstate = 0;
|
||||
|
||||
retVal = false;
|
||||
}
|
||||
else if (data[0] == 0xdd && packetstate == 0) // probably got 1st half of packet
|
||||
{
|
||||
Serial.println("PKT1");
|
||||
packetstate = 1;
|
||||
for (uint8_t i = 0; i < dataSize; i++)
|
||||
{
|
||||
packetbuff[i] = data[i];
|
||||
}
|
||||
totalDataSize = dataSize;
|
||||
retVal = true;
|
||||
|
||||
if (data[dataSize - 1] == 0x77) {
|
||||
//its full packets
|
||||
packetstate = 2;
|
||||
}
|
||||
}
|
||||
else if (data[dataSize - 1] == 0x77 && packetstate == 1) //probably got 2nd half of the packet
|
||||
{
|
||||
Serial.println("PKT2");
|
||||
packetstate = 2;
|
||||
for (uint8_t i = 0; i < dataSize; i++)
|
||||
{
|
||||
packetbuff[i + totalDataSize] = data[i];
|
||||
}
|
||||
totalDataSize += dataSize;
|
||||
retVal = true;
|
||||
}
|
||||
|
||||
if (packetstate == 2) //got full packet
|
||||
{
|
||||
Serial.println("PKT3");
|
||||
uint8_t packet[totalDataSize];
|
||||
memcpy(packet, packetbuff, totalDataSize);
|
||||
|
||||
bmsProcessPacket(packet); //pass pointer to retrieved packet to processing function
|
||||
packetstate = 0;
|
||||
totalDataSize = 0;
|
||||
retVal = true;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool bmsProcessPacket(byte *packet)
|
||||
{
|
||||
|
||||
bool isValid = isPacketValid(packet);
|
||||
|
||||
if (isValid != true)
|
||||
{
|
||||
Serial.println("Invalid packer received");
|
||||
return false;
|
||||
}
|
||||
|
||||
bmsPacketHeaderStruct *pHeader = (bmsPacketHeaderStruct *)packet;
|
||||
byte *data = packet + sizeof(bmsPacketHeaderStruct); // TODO Fix this ugly hack
|
||||
unsigned int dataLen = pHeader->dataLen;
|
||||
|
||||
bool result = false;
|
||||
|
||||
// find packet type (basic info or cell info)
|
||||
switch (pHeader->type)
|
||||
{
|
||||
case 3:
|
||||
{
|
||||
// Process basic info
|
||||
result = processBasicInfo(data, dataLen);
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
// Process cell info
|
||||
result = processCellInfo(data, dataLen);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
result = false;
|
||||
Serial.printf("Unsupported packet type detected. Type: %d", pHeader->type);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool processBasicInfo(byte *data, unsigned int dataLen){
|
||||
uint16_t Volts = ((uint32_t)two_ints_into16(data[0], data[1])) * 10; // Resolution 10 mV -> convert to milivolts eg 4895 > 48950mV
|
||||
int32_t Amps = ((int32_t)two_ints_into16(data[2], data[3])) * 10; // Resolution 10 mA -> convert to miliamps
|
||||
|
||||
int32_t Watts = Volts * Amps / 1000000; // W
|
||||
|
||||
uint16_t CapacityRemainAh = ((uint16_t)two_ints_into16(data[4], data[5])) * 10;
|
||||
uint8_t CapacityRemainPercent = ((uint8_t)data[19]);
|
||||
|
||||
uint16_t Temp1 = (((uint16_t)two_ints_into16(data[23], data[24])) - 2731);
|
||||
uint16_t Temp2 = (((uint16_t)two_ints_into16(data[25], data[26])) - 2731);
|
||||
|
||||
uint16_t BalanceCodeLow = (two_ints_into16(data[12], data[13]));
|
||||
uint16_t BalanceCodeHigh = (two_ints_into16(data[14], data[15]));
|
||||
uint8_t MosfetStatus = ((byte)data[20]);
|
||||
|
||||
Serial.printf("Total voltage: %f\r\n", (float)Volts / 1000);
|
||||
Serial.printf("Amps: %f\r\n", (float)Amps / 1000);
|
||||
Serial.printf("CapacityRemainAh: %f\r\n", (float)CapacityRemainAh / 1000);
|
||||
Serial.printf("CapacityRemainPercent: %d\r\n", CapacityRemainPercent);
|
||||
Serial.printf("Temp1: %f\r\n", (float)Temp1 / 10);
|
||||
Serial.printf("Temp2: %f\r\n", (float)Temp2 / 10);
|
||||
Serial.printf("Balance Code Low: 0x%x\r\n", BalanceCodeLow);
|
||||
Serial.printf("Balance Code High: 0x%x\r\n", BalanceCodeHigh);
|
||||
Serial.printf("Mosfet Status: 0x%x\r\n", MosfetStatus);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool processCellInfo(byte *data, unsigned int dataLen)
|
||||
{
|
||||
uint16_t _cellSum;
|
||||
uint16_t _cellMin = 5000;
|
||||
uint16_t _cellMax = 0;
|
||||
uint16_t _cellAvg;
|
||||
uint16_t _cellDiff;
|
||||
|
||||
uint8_t NumOfCells = dataLen / 2; // data contains 2 bytes per cell
|
||||
|
||||
//go trough individual cells
|
||||
for (byte i = 0; i < dataLen / 2; i++){
|
||||
int CellVolt = ((uint16_t)two_ints_into16(data[i * 2], data[i * 2 + 1])); // Resolution 1 mV
|
||||
_cellSum += CellVolt;
|
||||
if (CellVolt > _cellMax)
|
||||
{
|
||||
_cellMax = CellVolt;
|
||||
}
|
||||
if (CellVolt < _cellMin)
|
||||
{
|
||||
_cellMin = CellVolt;
|
||||
}
|
||||
|
||||
Serial.printf("Cell %d volt: %f\r\n", i,(float)CellVolt/1000);
|
||||
}
|
||||
|
||||
Serial.printf("Max cell volt: %f\r\n", (float)_cellMax / 1000);
|
||||
Serial.printf("Min cell volt: %f\r\n", (float)_cellMin / 1000);
|
||||
Serial.printf("Difference cell volt: %f\r\n", (float)_cellMax - _cellMin / 1000);
|
||||
Serial.printf("Average cell volt: %f\r\n", (float)_cellSum / NumOfCells / 1000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isPacketValid(byte *packet) //check if packet is valid
|
||||
{
|
||||
if (packet == nullptr){
|
||||
return false;
|
||||
}
|
||||
|
||||
bmsPacketHeaderStruct *pHeader = (bmsPacketHeaderStruct *)packet;
|
||||
int checksumPos = pHeader->dataLen + 2; // status + data len + data
|
||||
|
||||
int offset = 2; // header 0xDD and command type are not in data length
|
||||
|
||||
if (packet[0] != 0xDD){
|
||||
// start bit missing
|
||||
return false;
|
||||
}
|
||||
|
||||
if (packet[offset + checksumPos + 2] != 0x77){
|
||||
// stop bit missing
|
||||
return false;
|
||||
}
|
||||
|
||||
byte checksum = 0;
|
||||
for (int i = 0; i < checksumPos; i++){
|
||||
checksum += packet[offset + i];
|
||||
}
|
||||
checksum = ((checksum ^ 0xFF) + 1) & 0xFF;
|
||||
|
||||
if (checksum != packet[offset + checksumPos + 1]){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int16_t two_ints_into16(int highbyte, int lowbyte) // turns two bytes into a single long integer
|
||||
{
|
||||
int16_t result = (highbyte);
|
||||
result <<= 8; //Left shift 8 bits,
|
||||
result = (result | lowbyte); //OR operation, merge the two
|
||||
return result;
|
||||
}
|
||||
|
56
datatypes.h
56
datatypes.h
@ -1,56 +0,0 @@
|
||||
#ifndef mydatatypes_H_
|
||||
#define mydatatypes_H_
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte start;
|
||||
byte type;
|
||||
byte status;
|
||||
byte dataLen;
|
||||
} bmsPacketHeaderStruct;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t Volts; // unit 1mV
|
||||
int32_t Amps; // unit 1mA
|
||||
int32_t Watts; // unit 1W
|
||||
uint16_t CapacityRemainAh;
|
||||
uint8_t CapacityRemainPercent; //unit 1%
|
||||
uint16_t Temp1; //unit 0.1C
|
||||
uint16_t Temp2; //unit 0.1C
|
||||
uint16_t BalanceCodeLow;
|
||||
uint16_t BalanceCodeHigh;
|
||||
uint8_t MosfetStatus;
|
||||
|
||||
} packBasicInfoStruct;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t NumOfCells;
|
||||
uint16_t CellVolt[BMS_MAX_CELLS]; //cell 1 has index 0 :-/
|
||||
uint16_t CellMax;
|
||||
uint16_t CellMin;
|
||||
uint16_t CellDiff; // difference between highest and lowest
|
||||
uint16_t CellAvg;
|
||||
} packCellInfoStruct;
|
||||
|
||||
/*
|
||||
struct packEepromStruct
|
||||
{
|
||||
uint16_t POVP;
|
||||
uint16_t PUVP;
|
||||
uint16_t COVP;
|
||||
uint16_t CUVP;
|
||||
uint16_t POVPRelease;
|
||||
uint16_t PUVPRelease;
|
||||
uint16_t COVPRelease;
|
||||
uint16_t CUVPRelease;
|
||||
uint16_t CHGOC;
|
||||
uint16_t DSGOC;
|
||||
};
|
||||
|
||||
#define STRINGBUFFERSIZE 300
|
||||
char stringBuffer[STRINGBUFFERSIZE];
|
||||
*/
|
||||
|
||||
#endif /* mydatatypes_H_ */
|
Loading…
Reference in New Issue
Block a user