Skip to content

Instantly share code, notes, and snippets.

@stephanedeluca
Last active June 21, 2022 09:21
Show Gist options
  • Save stephanedeluca/da2e2dbf34478b5ad144e512a0d3e91e to your computer and use it in GitHub Desktop.
Save stephanedeluca/da2e2dbf34478b5ad144e512a0d3e91e to your computer and use it in GitHub Desktop.
Compute a CRC-16/Modbus
//import 'dart:ffi';
int crc16Modbus(List<int> bytes){
const crc16 = 0xA001;
int crc = 0xFFFF;
if (false) {
for (int pos = 0; pos < bytes.length; pos++) {
crc ^= bytes[pos]; // XOR byte into least sig. byte of crc
for (int i = 8; i != 0; i--) { // Loop over each bit
if ((crc & 0x0001) != 0) { // If the LSB is set
crc >>= 1; // Shift right and
crc ^= crc16; // XOR 0xA001
}
else { // Else LSB is not set
crc >>= 1; // Just shift right
}
}
}
}
else {
for(int i=0;i<bytes.length;i++) {
crc ^= bytes[i];
crc = (crc>>1) ^ (crc16&-(crc&1));
crc = (crc>>1) ^ (crc16&-(crc&1));
crc = (crc>>1) ^ (crc16&-(crc&1));
crc = (crc>>1) ^ (crc16&-(crc&1));
crc = (crc>>1) ^ (crc16&-(crc&1));
crc = (crc>>1) ^ (crc16&-(crc&1));
crc = (crc>>1) ^ (crc16&-(crc&1));
crc = (crc>>1) ^ (crc16&-(crc&1));
}
}
// swap CRC
return (crc & 0xff) << 8 | crc >> 8;
}
final dalyBmsBleMessages = {
0x80: "nominal capacity",
0x81: "cell reference voltage",
0x82: "boards count",
0x83: "cell string count board 1",
0x84: "cell string count board 2",
0x85: "cell string count board 3",
0x86: "temp sensors count board 1",
0x87: "temp sensors count board 2",
0x88: "temp sensors count board 3",
0x89: "unknown",
0x8A: "sleep after",
0x8B: "cell protection overvoltage L1",
0x8C: "cell protection overvoltage L2",
0x8D: "cell protection undervoltage L1",
0x8E: "cell protection undervoltage L2",
0x8F: "battery overvoltage L1",
0x90: "battery overvoltage L2",
0x91: "battery undervoltage L1",
0x92: "battery undervoltage L2",
0x93: "battery discharging overcurrent L1",
0x94: "battery discharging overcurrent L2",
0x95: "battery charging overcurrent L1",
0x96: "battery charging overcurrent L2",
0x97: "battery charging temp too high L1",
0x98: "battery charging temp too high L2",
0x99: "battery charging temp too low L1",
0x9A: "battery charging temp too low L2",
0x9B: "battery discharging temp too high L1",
0x9C: "battery discharging temp too high L2",
0x9D: "battery discharging temp too low L1",
0x9E: "battery discharging temp too low L2",
0x9F: "cell voltage diff threshold alarm L1",
0xA0: "cell voltage diff threshold alarm L2",
0xA1: "temp sensor diff threshold alarm L1",
0xA2: "temp sensor diff threshold alarm L2",
0xA3: "cell voltage threshold at balancing is enable",
0xA4: "voltage diff btw cells that is acceptable",
0xA5: "rated capacity",
0xA6: "unknown",
0xA7: "setup SoC",
0xA8: "temp MOS protection",
0xA9: "unknown"
};
void main() {
const table = [
// == Writes
// -- 8
[0xd2, 0x06, 0x00, 0x80, 0x01, 0xF4, 0x9B, 0x96],
[0xd2, 0x06, 0x00, 0x81, 0x0C, 0xB2, 0x4F, 0x34],
[0xd2, 0x06, 0x00, 0x82, 0x00, 0x01, 0xFB, 0x81],
[0xd2, 0x06, 0x00, 0x83, 0x00, 0x08, 0x6A, 0x47],
[0xd2, 0x06, 0x00, 0x84, 0x00, 0x00, 0xDA, 0x40],
[0xd2, 0x06, 0x00, 0x85, 0x00, 0x00, 0x8B, 0x80],
[0xd2, 0x06, 0x00, 0x86, 0x00, 0x01, 0xBA, 0x40],
[0xd2, 0x06, 0x00, 0x87, 0x00, 0x00, 0x2A, 0x40],
[0xd2, 0x06, 0x00, 0x88, 0x00, 0x00, 0x1A, 0x43],
// 89
[0xd2, 0x06, 0x00, 0x8A, 0xFF, 0xFF, 0xBA, 0x33],
// 8B
[0xd2, 0x06, 0x00, 0x8C, 0x0E, 0x42, 0xDF, 0xD3],
// 8D
[0xd2, 0x06, 0x00, 0x8E, 0x07, 0xD0, 0xF9, 0xEE],
// 8F
// -- 9
[0xd2, 0x06, 0x00, 0x90, 0x01, 0x2C, 0x9A, 0x09],
// 91
[0xd2, 0x06, 0x00, 0x92, 0x00, 0xA0, 0x3B, 0xFC],
// 93
[0xd2, 0x06, 0x00, 0x94, 0x72, 0x42, 0x7F, 0x14],
// 95
[0xd2, 0x06, 0x00, 0x96, 0x78, 0x1E, 0XD8, 0x4D],
// 97
[0xd2, 0x06, 0x00, 0x98, 0x00, 0x69, 0xDB, 0xA8],
// 99
[0xd2, 0x06, 0x00, 0x9A, 0x00, 0x1E, 0x3A, 0x4E],
[0xd2, 0x06, 0x00, 0x9C, 0x00, 0x69, 0x9A, 0x69],
// 9D
[0xd2, 0x06, 0x00, 0x9E, 0x00, 0x0A, 0x7B, 0x80],
// 9F
// -- A
[0xd2, 0x06, 0x00, 0xA0, 0x03, 0x20, 0x9B, 0x63],
// A1
[0xd2, 0x06, 0x00, 0xA2, 0x00, 0x0F, 0x7B, 0x8F],
[0xd2, 0x06, 0x00, 0xA3, 0x0C, 0x1C, 0x6E, 0x82],
[0xd2, 0x06, 0x00, 0xA4, 0x00, 0x32, 0x5A, 0x5F],
// A5
// A6
[0xd2, 0x06, 0x00, 0xA7, 0x03, 0x81, 0xEB, 0x1A],
[0xd2, 0x06, 0x00, 0xA8, 0x00, 0x57, 0x5A, 0x77],
// A9, AA, AB, AC, AD, AE, AF
];
for (final m in table) {
final id = m[3];
final readWrite = m[1] == 6 ? "write" : "read";
final message = dalyBmsBleMessages[id] ?? "—";
final write = m.sublist(0, m.length-2);
final writeCrc = m.sublist(m.length-2);
final transmitCrc = writeCrc[0]<<8|writeCrc[1];
final computedCrc = crc16Modbus(write);
final match = transmitCrc == computedCrc;
print("$readWrite ${m.map((e) => e.toRadixString(16).padLeft(2,'0'))}| computed CRC: ${computedCrc.toRadixString(16).padLeft(2,'0')} ${match ? '🟢':'🔴 should be ${transmitCrc.toRadixString(16).padLeft(2,'0')}'} | $message");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment