How to calculate CRC-16 (Modbus)?

Hi everyone,

I am trying to calculate CRC with a function I got from Node-RED forum, but when there is a 0 at the end or at the beginning of the CRC, it does not identify it, and I just get three bytes.

The fact is that I do not want to download any node, only a function for the CRC-16 (Modbus) like a frame like this: 010600000001 + CRC

Could anyone help me please?

Thank you very much,

Q.

Please post a flow using the function you have which works except in the leading/trailing zero case so we can see what you are have. Include inject nodes with test data that works and test data that doesn't, and tell us what output you expect.

This is my flow, and I attach the function node with the CRC-16 calculation I got from somewhere in Node-RED forum

[{"id":"60f6223737445c93","type":"function","z":"e6126f89.fbab88","name":"CRC16-modbus","func":"var CRCMaster = {\n    StringToCheck: \"\",\n    CleanedString: \"\",\n    CRCTableDNP: [],\n    init: function() {\n        this.CRCDNPInit();\n    },\n    CleanString: function(inputType) {\n        if (inputType == \"ASCII\") {\n            this.CleanedString = this.StringToCheck;\n        } else {\n            if (this.StringToCheck.match(/^[0-9A-F \\t]+$/gi) !== null) {\n                this.CleanedString = this._hexStringToString(this.StringToCheck.toUpperCase().replace(/[\\t ]/g, ''));\n            } else {\n                window.alert(\"String doesn't seem to be a valid Hex input.\");\n                return false;\n            }\n        }\n        return true;\n    },\n    CRCDNPInit: function() {\n        var i, j, crc, c;\n        for (i = 0; i < 256; i++) {\n            crc = 0;\n            c = i;\n            for (j = 0; j < 8; j++) {\n                if ((crc ^ c) & 0x0001) crc = (crc >> 1) ^ 0xA6BC;\n                else crc = crc >> 1;\n                c = c >> 1;\n            }\n            this.CRCTableDNP[i] = crc;\n        }\n    },\n    CRC16Modbus: function() {\n        var crc = 0xFFFF;\n        var str = this.CleanedString;\n        for (var pos = 0; pos < str.length; pos++) {\n            crc ^= str.charCodeAt(pos);\n            for (var i = 8; i !== 0; i--) {\n                if ((crc & 0x0001) !== 0) {\n                    crc >>= 1;\n                    crc ^= 0xA001;\n                } else\n                    crc >>= 1;\n            }\n        }\n        return crc;\n    },\n    _stringToBytes: function(str) {\n        var ch, st, re = [];\n        for (var i = 0; i < str.length; i++) {\n            ch = str.charCodeAt(i); // get char\n            st = []; // set up \"stack\"\n            do {\n                st.push(ch & 0xFF); // push byte to stack\n                ch = ch >> 8; // shift value down by 1 byte\n            }\n            while (ch);\n            // add stack contents to result\n            // done because chars have \"wrong\" endianness\n            re = re.concat(st.reverse());\n        }\n        // return an array of bytes\n        return re;\n    },\n    _hexStringToString: function(inputstr) {\n        var hex = inputstr.toString(); //force conversion\n        var str = '';\n        for (var i = 0; i < hex.length; i += 2)\n            str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));\n        return str;\n    },\n    Calculate: function(str, inputType) {\n        this.StringToCheck = str;\n        if (this.CleanString(inputType)) {\n            crcinputcrc16modbus=this.CRC16Modbus().toString(16).toUpperCase();\n            crcinputcrc16modbus=crcinputcrc16modbus.substr(2) + crcinputcrc16modbus.substr(0, 2); //swap bytes\n   \n        }\n    }\n};\n\nCRCMaster.init();\n\nvar inputType = \"HEX\";\nvar crcinputcrc16modbus;\nvar crcinput = msg.payload;\n\nCRCMaster.Calculate(crcinput, inputType);\n\nmsg.payload = crcinput + crcinputcrc16modbus;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1140,"y":300,"wires":[["6dd18cb44dba730b","e51d8658ec920d84","d3f9521b3ad8ac69"]]}]

You have only posted the function node. We need a flow that we can test.

[{"id":"55c99f3d9881b6a1","type":"tab","label":"Flow 4","disabled":false,"info":""},{"id":"42b2ad79813b38ca","type":"inject","z":"55c99f3d9881b6a1","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"010600000000","payloadType":"str","x":380,"y":140,"wires":[["6613dfcd1aaa2010"]]},{"id":"6613dfcd1aaa2010","type":"function","z":"55c99f3d9881b6a1","name":"CRC16-modbus","func":"var CRCMaster = {\n    StringToCheck: \"\",\n    CleanedString: \"\",\n    CRCTableDNP: [],\n    init: function() {\n        this.CRCDNPInit();\n    },\n    CleanString: function(inputType) {\n        if (inputType == \"ASCII\") {\n            this.CleanedString = this.StringToCheck;\n        } else {\n            if (this.StringToCheck.match(/^[0-9A-F \\t]+$/gi) !== null) {\n                this.CleanedString = this._hexStringToString(this.StringToCheck.toUpperCase().replace(/[\\t ]/g, ''));\n            } else {\n                window.alert(\"String doesn't seem to be a valid Hex input.\");\n                return false;\n            }\n        }\n        return true;\n    },\n    CRCDNPInit: function() {\n        var i, j, crc, c;\n        for (i = 0; i < 256; i++) {\n            crc = 0;\n            c = i;\n            for (j = 0; j < 8; j++) {\n                if ((crc ^ c) & 0x0001) crc = (crc >> 1) ^ 0xA6BC;\n                else crc = crc >> 1;\n                c = c >> 1;\n            }\n            this.CRCTableDNP[i] = crc;\n        }\n    },\n    CRC16Modbus: function() {\n        var crc = 0xFFFF;\n        var str = this.CleanedString;\n        for (var pos = 0; pos < str.length; pos++) {\n            crc ^= str.charCodeAt(pos);\n            for (var i = 8; i !== 0; i--) {\n                if ((crc & 0x0001) !== 0) {\n                    crc >>= 1;\n                    crc ^= 0xA001;\n                } else\n                    crc >>= 1;\n            }\n        }\n        return crc;\n    },\n    _stringToBytes: function(str) {\n        var ch, st, re = [];\n        for (var i = 0; i < str.length; i++) {\n            ch = str.charCodeAt(i); // get char\n            st = []; // set up \"stack\"\n            do {\n                st.push(ch & 0xFF); // push byte to stack\n                ch = ch >> 8; // shift value down by 1 byte\n            }\n            while (ch);\n            // add stack contents to result\n            // done because chars have \"wrong\" endianness\n            re = re.concat(st.reverse());\n        }\n        // return an array of bytes\n        return re;\n    },\n    _hexStringToString: function(inputstr) {\n        var hex = inputstr.toString(); //force conversion\n        var str = '';\n        for (var i = 0; i < hex.length; i += 2)\n            str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));\n        return str;\n    },\n    Calculate: function(str, inputType) {\n        this.StringToCheck = str;\n        if (this.CleanString(inputType)) {\n            crcinputcrc16modbus=this.CRC16Modbus().toString(16).toUpperCase();\n            crcinputcrc16modbus=crcinputcrc16modbus.substr(2) + crcinputcrc16modbus.substr(0, 2); //swap bytes\n   \n        }\n    }\n};\n\nCRCMaster.init();\n\nvar inputType = \"HEX\";\nvar crcinputcrc16modbus;\nvar crcinput = msg.payload;\n\nCRCMaster.Calculate(crcinput, inputType);\n\nmsg.payload = crcinput + crcinputcrc16modbus;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":700,"y":240,"wires":[["40b3a69e5f8c5291","98d620ed386faf37"]]},{"id":"40b3a69e5f8c5291","type":"debug","z":"55c99f3d9881b6a1","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":930,"y":240,"wires":[]},{"id":"2892e85f9e5d2a87","type":"debug","z":"55c99f3d9881b6a1","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1090,"y":120,"wires":[]},{"id":"98d620ed386faf37","type":"function","z":"55c99f3d9881b6a1","name":"get length","func":"msg.payload = msg.payload.length;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":920,"y":120,"wires":[["2892e85f9e5d2a87"]]},{"id":"71a4a81b240a5701","type":"inject","z":"55c99f3d9881b6a1","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"010600000001","payloadType":"str","x":380,"y":380,"wires":[["6613dfcd1aaa2010"]]},{"id":"c3abe52f59e42bd0","type":"comment","z":"55c99f3d9881b6a1","name":"CRC: CA89. Little Endian: 89CA","info":"","x":350,"y":180,"wires":[]},{"id":"353580a5edab4c4f","type":"comment","z":"55c99f3d9881b6a1","name":"CRC: 0A48. Little Endian: 480A","info":"","x":330,"y":420,"wires":[]}]

Admin edit: Corrected trailing backticks (need to be on new line).

Change the line
crcinputcrc16modbus=this.CRC16Modbus().toString(16).toUpperCase();
to
crcinputcrc16modbus=this.CRC16Modbus().toString(16).toUpperCase().padStart(4,"0");

1 Like

Thank you very much! It works now! :slight_smile:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.