-
Notifications
You must be signed in to change notification settings - Fork 0
/
crc16.m
187 lines (170 loc) · 4.92 KB
/
crc16.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
function [crc,cfg,crctable] = crc16(octets,cfgin)
% Usage: [crc,cfg,crctable] = crc16(octets,cfgin)
%
% Compute CRC-16 of a vector of unsigned bytes
%
% octets.............input vector of unsigned bytes
% cfgin..............optional struct to customize CRC-16 parameters
% poly.............scalar CRC polynomial [0-0xffff] (default=0x1021)
% init.............scalar initial shift register value [0-0xffff] (default=0)
% refin............bool input reflection [0 or 1] (default=0)
% refout...........bool output reflection [0 or 1] (default=0)
% xorout...........scalar XOR'd with final CRC before returning (default=0)
% crc................output: computed CRC-16
% cfg................output: struct of configuration used to compute CRC
% cfg contains the same members as cfgin input struct
% crctable...........output: lookup table for fast CRC calculation
%
% CRC default parameters:
% - polynomial: 0x1021
% - shift register seed: 0
% - input reflection: no
% - output reflection: no
% - output Xor: no
%
% Examples:
%
% 1. CRC16 using default parameters corresponding to CRC-16/XMODEM:
% crc = crc16(uint8('123456789'));
% disp(dec2hex(crc))
% 31C3
%
% 2. CRC-16/KERMIT often identified as CRC-16/CCITT:
% crc = crc16(uint8('123456789'), struct('refin',1,'refout',1));
% disp(dec2hex(crc))
% 2189
%
% 3. CRC-16/MODBUS:
% cfg = struct('poly',0x8005,'init',0xffff,'refin',1,'refout',1,'xorout',0);
% crc = crc16(uint8('123456789'),cfg);
% disp(dec2hex(crc))
% 4B37
%
% Compare to the following online calculators:
% http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
% https://crccalc.com/
%
% References:
% https://reveng.sourceforge.io/crc-catalogue/16.htm
% https://www.drdobbs.com/tools/understanding-crcs/184410177
%
persistent Crc16Table
persistent lastPoly
% Validate inputs
narginchk(0,2);
if nargin == 0 || (nargin == 2 && ~isa(cfgin,'struct'))
crc = zeros(0,1);
cfg = struct();
crctable = [];
help crc16
return
elseif nargin == 1
cfgin = struct();
end
% Setup algorithm parameters
cfg = parse_inputs(cfgin,nargin);
octets = double(uint8(octets)); % cast avoids bitxor() warnings
% CRC LUT
if isempty(Crc16Table) || length(Crc16Table) ~= 256 ...
|| isempty(lastPoly) || lastPoly ~= cfg.poly
Crc16Table = buildTable(cfg.poly);
crctable = Crc16Table;
end
% Input reflection
if cfg.refin
octets = reflect(octets);
end
% CRC-16
ff = 255;
ffff = 65535;
crc = cfg.init;
for ii=1:length(octets)
idx = bitand(bitxor(bitshift(crc, -8), octets(ii)), ff);
crc = bitand(bitxor(Crc16Table(idx + 1), bitshift(crc, 8)), ffff);
end
% Output reflection
if cfg.refout
crc = reflect(uint16(crc));
end
% Final XOR
if cfg.xorout
crc = bitxor(crc, cfg.xorout);
end
end % function
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Generate CRC16 fast lookup table
function lut = buildTable(poly)
poly = double(poly);
ffff = 65535;
for ii=0:255
reg = bitshift(ii, 8);
for jj=1:8
if bitshift(reg, -15)
reg = bitand(bitxor(bitshift(reg,1), poly), ffff);
else
reg = bitand(bitshift(reg, 1), ffff);
end
end
lut(ii + 1) = bitand(reg, ffff);
end
end % function
% Build reflection table
function lut = buildReflectTable
bin = decimal2binary(0:255);
rev = bin(:,end:-1:1);
lut = binary2decimal(rev);
end % function
% Convert byte array to binary array
function b = decimal2binary(d)
b = zeros(numel(d),8);
for kk = 7:-1:0
b(:,8-kk) = bitand(d(:),2^kk) ~= 0;
end
end % function
% Convert binary array to byte array
% b is N-by-8 (convert each row to a byte)
function d = binary2decimal(b)
v = 2.^(7:-1:0);
d = b * v(:);
end % function
% Bit-reverse array of bytes or array of uint16s
function ref = reflect(d)
persistent reflTable
if isempty(reflTable) || length(reflTable) ~=256
reflTable = buildReflectTable();
end
if isa(d,'uint16')
lo = bitand(d(:),255); % 0x00ff
hi = bitshift(bitand(d(:),65280),-8); % 0xff00
reflo = reflTable(lo(:)+1);
refhi = reflTable(hi(:)+1);
ref = 2^8 * reflo(:) + refhi(:);
else % treat as uint8
ref = reflTable(d(:)+1);
end
end % function
% Setup algorithm parameters
function cfg = parse_inputs(cfg,N)
if N == 1
cfg.poly = 4129; % 0x1021
cfg.init = 0;
cfg.refin = 0;
cfg.refout = 0;
cfg.xorout = 0;
end
if ~isfield(cfg,'poly')
cfg.poly = 4129; % 0x1021
end
if ~isfield(cfg,'init')
cfg.init = 0;
end
if ~isfield(cfg,'refin')
cfg.refin = 0;
end
if ~isfield(cfg,'refout')
cfg.refout = 0;
end
if ~isfield(cfg,'xorout')
cfg.xorout = 0;
end
end % function