javascript - 使用 Vanilla JS 的 CRC-16 校验和计算器

标签 javascript checksum modbus crc16 com-port

我正在寻找用 JavaScript 编写并在普通浏览器中运行的 CRC-16 CRC 算法。我知道在各种编程语言中都有数量惊人的 CRC-16 实现代码示例。但我仍然无法解决我的问题。以下示例显示了 NodeJ 的 CRC-16 校验和检查。

https://github.com/donvercety/node-crc16/blob/master/crc16.js

为了让 NodeJS 代码在普通浏览器中运行,我对其进行了如下调整。

const crctab16 = new Uint16Array([
        0X0000, 0X1189, 0X2312, 0X329B, 0X4624, 0X57AD, 0X6536, 0X74BF,
        0X8C48, 0X9DC1, 0XAF5A, 0XBED3, 0XCA6C, 0XDBE5, 0XE97E, 0XF8F7,
        0X1081, 0X0108, 0X3393, 0X221A, 0X56A5, 0X472C, 0X75B7, 0X643E,
        0X9CC9, 0X8D40, 0XBFDB, 0XAE52, 0XDAED, 0XCB64, 0XF9FF, 0XE876,
        0X2102, 0X308B, 0X0210, 0X1399, 0X6726, 0X76AF, 0X4434, 0X55BD,
        0XAD4A, 0XBCC3, 0X8E58, 0X9FD1, 0XEB6E, 0XFAE7, 0XC87C, 0XD9F5,
        0X3183, 0X200A, 0X1291, 0X0318, 0X77A7, 0X662E, 0X54B5, 0X453C,
        0XBDCB, 0XAC42, 0X9ED9, 0X8F50, 0XFBEF, 0XEA66, 0XD8FD, 0XC974,
        0X4204, 0X538D, 0X6116, 0X709F, 0X0420, 0X15A9, 0X2732, 0X36BB,
        0XCE4C, 0XDFC5, 0XED5E, 0XFCD7, 0X8868, 0X99E1, 0XAB7A, 0XBAF3,
        0X5285, 0X430C, 0X7197, 0X601E, 0X14A1, 0X0528, 0X37B3, 0X263A,
        0XDECD, 0XCF44, 0XFDDF, 0XEC56, 0X98E9, 0X8960, 0XBBFB, 0XAA72,
        0X6306, 0X728F, 0X4014, 0X519D, 0X2522, 0X34AB, 0X0630, 0X17B9,
        0XEF4E, 0XFEC7, 0XCC5C, 0XDDD5, 0XA96A, 0XB8E3, 0X8A78, 0X9BF1,
        0X7387, 0X620E, 0X5095, 0X411C, 0X35A3, 0X242A, 0X16B1, 0X0738,
        0XFFCF, 0XEE46, 0XDCDD, 0XCD54, 0XB9EB, 0XA862, 0X9AF9, 0X8B70,
        0X8408, 0X9581, 0XA71A, 0XB693, 0XC22C, 0XD3A5, 0XE13E, 0XF0B7,
        0X0840, 0X19C9, 0X2B52, 0X3ADB, 0X4E64, 0X5FED, 0X6D76, 0X7CFF,
        0X9489, 0X8500, 0XB79B, 0XA612, 0XD2AD, 0XC324, 0XF1BF, 0XE036,
        0X18C1, 0X0948, 0X3BD3, 0X2A5A, 0X5EE5, 0X4F6C, 0X7DF7, 0X6C7E,
        0XA50A, 0XB483, 0X8618, 0X9791, 0XE32E, 0XF2A7, 0XC03C, 0XD1B5,
        0X2942, 0X38CB, 0X0A50, 0X1BD9, 0X6F66, 0X7EEF, 0X4C74, 0X5DFD,
        0XB58B, 0XA402, 0X9699, 0X8710, 0XF3AF, 0XE226, 0XD0BD, 0XC134,
        0X39C3, 0X284A, 0X1AD1, 0X0B58, 0X7FE7, 0X6E6E, 0X5CF5, 0X4D7C,
        0XC60C, 0XD785, 0XE51E, 0XF497, 0X8028, 0X91A1, 0XA33A, 0XB2B3,
        0X4A44, 0X5BCD, 0X6956, 0X78DF, 0X0C60, 0X1DE9, 0X2F72, 0X3EFB,
        0XD68D, 0XC704, 0XF59F, 0XE416, 0X90A9, 0X8120, 0XB3BB, 0XA232,
        0X5AC5, 0X4B4C, 0X79D7, 0X685E, 0X1CE1, 0X0D68, 0X3FF3, 0X2E7A,
        0XE70E, 0XF687, 0XC41C, 0XD595, 0XA12A, 0XB0A3, 0X8238, 0X93B1,
        0X6B46, 0X7ACF, 0X4854, 0X59DD, 0X2D62, 0X3CEB, 0X0E70, 0X1FF9,
        0XF78F, 0XE606, 0XD49D, 0XC514, 0XB1AB, 0XA022, 0X92B9, 0X8330,
        0X7BC7, 0X6A4E, 0X58D5, 0X495C, 0X3DE3, 0X2C6A, 0X1EF1, 0X0F78,
    ]);
  
  function crc16(data) {
        var res = 0x0ffff;

        for (let b of data) {
            res = ((res >> 8) & 0x0ff) ^ crctab16[(res ^ b) & 0xff];
        }

        return (~res) & 0x0ffff;
    }
  
  alert(crc16("010400030002"))

如果我用 01 04 0003 0002 测试它,我得到 13428。但我要找的是 81 CB。有谁知道如何解决这个问题?

screenshot of CRC calculation in online tool

link to the online CRC calculation tool

最佳答案

“我正在寻找 CRC-16 CRC 算法”——那将是一个错误。看看 Wikipedia page on "Cyclic redundancy check"你会注意到它列出了 11 种 CRC-16 算法(它们将为相同的输入提供不同的结果)。当您查看 this online calculator 时情况会变得更糟它支持 23 种不同的算法!

我不确定您找到的代码使用的是哪种算法,但它不是生成您期望的值的算法。

您似乎想要计算 MODBUS over Serial Line Specification and Implementation Guide 的附录 B 中指定的 CRC 值(基于 modbus 标记的使用和消息内容)。规范中提供的算法值得一看,因为它很容易理解(您可能可以自己将其转换为 Javascript)。

一个好的起点是现有的 Javascript Modbus 实现,所以让我们从 node-modbus-serial 中的代码开始(ISC 许可证)并将其与您的测试数据一起使用(也解决了 Mark Adler 指出的问题):

/**
 * Calculates the buffers CRC16.
 *
 * @param {Buffer} buffer the data buffer.
 * @return {number} the calculated CRC16.
 * 
 * Source: github.com/yaacov/node-modbus-serial
 */
function crc16(buffer) {
    var crc = 0xFFFF;
    var odd;

    for (var i = 0; i < buffer.length; i++) {
        crc = crc ^ buffer[i];

        for (var j = 0; j < 8; j++) {
            odd = crc & 0x0001;
            crc = crc >> 1;
            if (odd) {
                crc = crc ^ 0xA001;
            }
        }
    }

    return crc;
};

console.log(crc16(Uint8Array.from([01,04,00,03,00,02])).toString(16))

这将输出结果 CB81。 MODBUS 使用“big-Endian”表示寄存器等,但 for reasons... CRC 是“little-Endian”(“首先附加低位字节,然后是高位字节”)因此这将被编码为 81CB 并检查 01 04 00 03 00 02 81 CB 使用 modbus parser确认这是一个有效的 MODBUS RTU 请求。

关于javascript - 使用 Vanilla JS 的 CRC-16 校验和计算器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70916752/

相关文章:

javascript - 滚动类型 ="number"输入以更改其值 : How to stop parent's scrolling

passport.js - 为什么现代 Passport 的机器可读区域中的复合校验位没有考虑所有数据?

ios - 如何识别一个数字是 UPC 码还是简单的数字?是否有任何特定格式来识别 UPC 代码?

linux - 如何打印/记录 rsync 计算的校验和?

python - Pymodbus 读/写 float (真实)

javascript - 如何将动态数据放入数组并将其附加到 dom vue.js

javascript - 使用javascript获取文本框中数字的平均值

javascript - instanceof 和 constructor 属性之间的区别

java - 在 Android 上获取 CommPortIdentifier 实例

java - 如何解决ModbusSlaveException : Error Code = 3?