modbus-connect
Version:
Modbus RTU over Web Serial and Node.js SerialPort
214 lines (201 loc) • 5.6 kB
JavaScript
// utils/crc.js
// CRC16 Modbus (полином 0x8005 в отражённом виде 0xA001, init 0xFFFF)
function crc16Modbus(buffer) {
let crc = 0xFFFF;
for (let pos = 0; pos < buffer.length; pos++) {
crc ^= buffer[pos];
for (let i = 0; i < 8; i++) {
if ((crc & 0x0001) !== 0) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return new Uint8Array([crc & 0xFF, (crc >> 8) & 0xFF]);
}
// CRC16-CCITT-FALSE (полином 0x1021, init 0xFFFF, без отражения)
function crc16CcittFalse(buffer) {
let crc = 0xFFFF;
for (let pos = 0; pos < buffer.length; pos++) {
crc ^= (buffer[pos] << 8);
for (let i = 0; i < 8; i++) {
if ((crc & 0x8000) !== 0) {
crc = (crc << 1) ^ 0x1021;
} else {
crc <<= 1;
}
crc &= 0xFFFF; // Ограничение 16 бит
}
}
return new Uint8Array([(crc >> 8) & 0xFF, crc & 0xFF]); // Big-endian
}
// CRC32 (полином 0x04C11DB7, init 0xFFFFFFFF, отражение и финальный XOR)
function crc32(buffer) {
let crc = 0xFFFFFFFF;
for (let pos = 0; pos < buffer.length; pos++) {
crc ^= buffer[pos];
for (let i = 0; i < 8; i++) {
if ((crc & 1) !== 0) {
crc = (crc >>> 1) ^ 0xEDB88320;
} else {
crc >>>= 1;
}
}
}
crc ^= 0xFFFFFFFF;
return new Uint8Array([
crc & 0xFF,
(crc >>> 8) & 0xFF,
(crc >>> 16) & 0xFF,
(crc >>> 24) & 0xFF
]); // Little-endian
}
// CRC8 (полином 0x07, init 0x00, без отражения)
function crc8(buffer) {
let crc = 0x00;
for (let pos = 0; pos < buffer.length; pos++) {
crc ^= buffer[pos];
for (let i = 0; i < 8; i++) {
if ((crc & 0x80) !== 0) {
crc = (crc << 1) ^ 0x07;
} else {
crc <<= 1;
}
crc &= 0xFF; // Ограничение 8 бит
}
}
return new Uint8Array([crc]);
}
// CRC-1 (простейший CRC, полином 0x01, init 0x00)
function crc1(buffer) {
let crc = 0x00;
for (let byte of buffer) {
for (let i = 0; i < 8; i++) {
crc ^= (byte >> (7 - i)) & 0x01;
}
}
return new Uint8Array([crc & 0x01]);
}
// CRC-8 1-Wire (полином 0x31, init 0x00, отражение, нет финального XOR)
function crc8_1wire(buffer) {
let crc = 0x00;
for (let b of buffer) {
crc ^= b;
for (let i = 0; i < 8; i++) {
if (crc & 0x01) {
crc = (crc >> 1) ^ 0x8C; // отражённый 0x31 → 0x8C
} else {
crc >>= 1;
}
}
}
return new Uint8Array([crc]);
}
// CRC-8 DVB-S2 (полином 0xD5, init 0x00, нет отражения и финального XOR)
function crc8_dvbs2(buffer) {
let crc = 0x00;
for (let b of buffer) {
crc ^= b;
for (let i = 0; i < 8; i++) {
crc = (crc & 0x80) ? ((crc << 1) ^ 0xD5) : (crc << 1);
crc &= 0xFF;
}
}
return new Uint8Array([crc]);
}
// CRC-16 Kermit (полином 0x1021, init 0x0000, отражение, финальный XOR = 0x0000)
function crc16_kermit(buffer) {
let crc = 0x0000;
for (let b of buffer) {
crc ^= b;
for (let i = 0; i < 8; i++) {
if (crc & 0x0001) {
crc = (crc >> 1) ^ 0x8408; // отражённый 0x1021
} else {
crc >>= 1;
}
}
}
return new Uint8Array([crc & 0xFF, (crc >> 8) & 0xFF]);
}
// CRC-16 XModem (полином 0x1021, init 0x0000, без отражения)
function crc16_xmodem(buffer) {
let crc = 0x0000;
for (let b of buffer) {
crc ^= (b << 8);
for (let i = 0; i < 8; i++) {
crc = (crc & 0x8000) ? ((crc << 1) ^ 0x1021) : (crc << 1);
crc &= 0xFFFF;
}
}
return new Uint8Array([(crc >> 8) & 0xFF, crc & 0xFF]);
}
// CRC-24 (полином 0x864CFB, init 0xB704CE) — часто используется в Bluetooth, OpenPGP
function crc24(buffer) {
let crc = 0xB704CE;
for (let b of buffer) {
crc ^= (b << 16);
for (let i = 0; i < 8; i++) {
crc = (crc & 0x800000) ? ((crc << 1) ^ 0x864CFB) : (crc << 1);
crc &= 0xFFFFFF;
}
}
return new Uint8Array([
(crc >> 16) & 0xFF,
(crc >> 8) & 0xFF,
crc & 0xFF
]);
}
// CRC-32 MPEG-2 (полином 0x04C11DB7, init 0xFFFFFFFF, без отражения, финальный XOR = 0x00000000)
function crc32mpeg(buffer) {
let crc = 0xFFFFFFFF;
for (let b of buffer) {
crc ^= (b << 24);
for (let i = 0; i < 8; i++) {
crc = (crc & 0x80000000) ? ((crc << 1) ^ 0x04C11DB7) : (crc << 1);
crc >>>= 0; // Принудительно как unsigned 32-bit
}
}
return new Uint8Array([
(crc >>> 24) & 0xFF,
(crc >>> 16) & 0xFF,
(crc >>> 8) & 0xFF,
crc & 0xFF
]);
}
// CRC-JAM (иногда называют CRC-32-JAMCRC, как CRC-32, но без финального XOR)
function crcjam(buffer) {
let crc = 0xFFFFFFFF;
for (let b of buffer) {
crc ^= b;
for (let i = 0; i < 8; i++) {
if ((crc & 1) !== 0) {
crc = (crc >>> 1) ^ 0xEDB88320;
} else {
crc >>>= 1;
}
}
}
return new Uint8Array([
crc & 0xFF,
(crc >>> 8) & 0xFF,
(crc >>> 16) & 0xFF,
(crc >>> 24) & 0xFF
]);
}
module.exports = {
crc16Modbus,
crc16CcittFalse,
crc32,
crc8,
crc1,
crc8_1wire,
crc8_dvbs2,
crc16_kermit,
crc16_xmodem,
crc24,
crc32mpeg,
crcjam
}