简体   繁体   中英

CRC-16 Checksum calculator with Vanilla JS

I am looking for a CRC-16 CRC algorithm which is written in JavaScript and runs in a normal browser. I know there are an incredible amount of code examples for CRC-16 implementations in all sorts of programming languages. But still I could not solve my question. The following example shows a CRC-16 checksum check for NodeJs.

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

To get the NodeJS code to run in the normal browser I adapted it as follows.

 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"))

If I test it with 01 04 0003 0002 I get 13428. But what I am looking for is 81 CB. Does anyone know how to fix this problem?

screenshot of CRC calculation in online tool

link to the online CRC calculation tool

First off, Javascript strings are stored as UTF-16, two bytes per character. You can use b.charCodeAt(0) to turn each character into an integer, but that only works when b is an ASCII character in 0..127. Due to Javascript's conversion rules, what you are actually computing the CRC of are the bytes 00 01 00 04 00 00 00 03 00 00 00 02 .

You are not giving the CRC the data you think you're giving it. You should use a Uint8Array for a series of bytes.

Second, what is it exactly you want the CRC of? Where did you get 81 CB from? You say you test it with "01 04 0003 0002", but in fact you (tried to) test it with "010400030002" (with no spaces). Which is it? Or do you really mean the bytes 01 04 00 03 00 02 ? Or since you grouped them oddly, maybe those second two are 16-bits words which need to be little endian? Then the bytes would be 01 04 03 00 02 00 . Is it one of those?

You need to understand exactly what they used in your example to arrive at a CRC of 81 CB . You also need to know if that CRC itself is little endian or big endian. Is the CRC 81cb , or is it cb81 ?

"I am looking for a CRC-16 CRC algorithm" - that would be a mistake. Take a look at the Wikipedia page on "Cyclic redundancy check" and you will note it lists 11 CRC-16 algorithms (that will provide different results for the same input). It gets worse when you look at this online calculator which supports 23 different algorithms!

I'm not sure which algorithm the code you found is using but it's not the one that generated the value you are expecting.

It looks like you want to calculate the CRC value as specified in appendix B of the MODBUS over Serial Line Specification and Implementation Guide (based on the use of the modbus tag and the message content). Its worth looking at the algorithm presented in the spec because it's pretty easy to follow (and you could probably convert it to Javascript yourself).

A good starting point would be an existing Javascript Modbus implementation so lets start with the code from node-modbus-serial (ISC License) and use that with your test data (fixing the issue pointed out by Mark Adler too):

 /** * 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))

This outputs the result CB81 . MODBUS uses a 'big-Endian' representation so this would be encoded as 81CB and checking 01 04 00 03 00 02 81 CB using a modbus parser confirms that this is a valid MODBUS RTU request.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM