CRC16 多项式为x16+x12+x5+1(0x1021),被用在各个规范中,其算法原理基本一致,就是在数据的输入和输出有所差异,下边把这些标准的差异列出,并给出小程序的算法实现。
CRC16_CCITT:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在前,高位在后,结果与0x0000异或
CRC16_CCITT_FALSE:多项式x16+x12+x5+1(0x1021),初始值0xFFFF,低位在后,高位在前,结果与0x0000异或
CRC16_XMODEM:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在后,高位在前,结果与0x0000异或
CRC16_X25:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在前,高位在后,结果与0xFFFF异或
我这边的文档有点瓜皮,CRC校验算法是用CRC16_CCITT的,但是他的输出对不上,噗!!!心态都被搞蹦了,直接素质三连。
怎么算都不对,然后CRC16_XMODEM算出来的对的上,输出是反向的,再次确认,却还是说CRC16_CCITT,素质三连,最后也懒得跟他BB直接用CRC16_XMODEM,按低位在前,高位在后计算,校验就对的上了,真的是不安常理出牌,裂开!。
Let the code speak!
//CRC蓝牙校验
var crc16 = function (buffer) {
var crc = 0x0000;
var odd;
for(var i = 0; i < buffer.length; i++) {
crc ^= (buffer[i] << 8)
for(var j = 0; j < 8; j++) {
odd = crc & 0x8000;
crc = crc << 1;
if(odd) {
crc = crc ^ 0x1021
}
}
}
var hi = ((crc & 0xFF00) >> 8); //高位置
var lo = (crc & 0x00FF); //低位置
var crcArr = []
crcArr.push(hi)
crcArr.push(lo)
crc &= 0xFFFF
return crcToString(crcArr, true)
};
//转为大写String
function crcToString(arr, isReverse) {
if(typeof isReverse == 'undefined') {
isReverse = true;
}
var hi = arr[0],
lo = arr[1];
return CRC.padLeft((isReverse ? hi + lo * 0x100 : hi * 0x100 + lo).toString(16).toUpperCase(), 4, '0');
};
var padLeft = function (s, w, pc) {
if (pc == undefined) {
pc = '0';
}
for (var i = 0, c = w - s.length; i < c; i++) {
s = pc + s;
}
return s;
};
//十六进制字符串转字节数组
function HexString2Bytes(str) {
var pos = 0;
var len = str.length;
if (len % 2 != 0) {
return null;
}
len /= 2;
var arrBytes = new Array();
for (var i = 0; i < len; i++) {
var s = str.substr(pos, 2);
var v = parseInt(s, 16);
arrBytes.push(v);
pos += 2;
}
return arrBytes;
}
实例:
const byteData= util.hexString2Bytes("20200616")
let crc = util.crc16(byteData)
console.log("CRC转换:",crc)
结果:D969
个人结论:
其实CRC16 多项式为x16+x12+x5+1(0x1021)的算法都差不多,只是初始值,高低位和结果异或有所不同。