Last active
June 21, 2022 09:21
-
-
Save stephanedeluca/da2e2dbf34478b5ad144e512a0d3e91e to your computer and use it in GitHub Desktop.
Compute a CRC-16/Modbus
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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