crc16.nx source
↩ module page · 109 lines · 3182 B
1// crc16.nx -- CRC-16 variants (CCITT, IBM, MODBUS).
2//
3// Used by serial / wire protocols where 16-bit checksums are
4// adequate (link-layer error detection). Three common variants
5// shipped:
6//
7// CCITT-FALSE (poly 0x1021, init 0xFFFF, no reflection)
8// Used by: XMODEM, MAVLink, DNP3, Bluetooth HCI
9// IBM (poly 0x8005, init 0x0000, reflected)
10// Used by: Modbus RTU, USB token CRC, ISO/IEC 13239
11// MODBUS (poly 0x8005, init 0xFFFF, reflected)
12// Used by: Modbus serial framing
13//
14// All NOT cryptographic. Burst-error detection only.
15//
16// Invariants:
17// CR1 Pure functions; no global state; deterministic.
18// CR2 Result fits in low 16 bits of i64.
19// CR3 Bit-by-bit implementation (no 256-entry table) -- slower
20// than tabulated variants but ~50 LoC instead of 50 LoC +
21// 256-byte data + per-variant table.
22
23import "syscalls.nx"
24
25const CR_POLY_CCITT: i64 = 0x1021
26const CR_POLY_IBM: i64 = 0x8005
27const CR_INIT_FFFF: i64 = 0xFFFF
28const CR_INIT_0000: i64 = 0x0000
29const CR_U16_MASK: i64 = 0xFFFF
30
31// Reflect 8 bits (LSB <-> MSB).
32func crc16_reflect8(b: i64) -> i64 {
33 var v: i64 = b
34 var r: i64 = 0
35 var i: i64 = 0
36 while i < 8 {
37 r = (r << 1) | (v & 1)
38 v = (v >> 1) & 0x7F
39 i = i + 1
40 }
41 return r
42}
43
44// Reflect 16 bits.
45func crc16_reflect16(x: i64) -> i64 {
46 var v: i64 = x & CR_U16_MASK
47 var r: i64 = 0
48 var i: i64 = 0
49 while i < 16 {
50 r = (r << 1) | (v & 1)
51 v = (v >> 1) & 0x7FFF
52 i = i + 1
53 }
54 return r
55}
56
57// CRC-16/CCITT-FALSE: poly 0x1021, init 0xFFFF, no reflection,
58// no final XOR. Standard XMODEM / MAVLink usage.
59func crc16_ccitt(bytes: *u8, n: i64) -> i64 {
60 var crc: i64 = CR_INIT_FFFF
61 var i: i64 = 0
62 while i < n {
63 crc = crc ^ (bytes[i] << 8)
64 var bit: i64 = 0
65 while bit < 8 {
66 if (crc & 0x8000) != 0 {
67 crc = ((crc << 1) ^ CR_POLY_CCITT) & CR_U16_MASK
68 } else {
69 crc = (crc << 1) & CR_U16_MASK
70 }
71 bit = bit + 1
72 }
73 i = i + 1
74 }
75 return crc & CR_U16_MASK
76}
77
78// CRC-16/MODBUS: poly 0x8005 reflected (0xA001), init 0xFFFF,
79// reflected input + output, no final XOR. The Modbus RTU
80// framing checksum.
81func crc16_modbus(bytes: *u8, n: i64) -> i64 {
82 var crc: i64 = CR_INIT_FFFF
83 var i: i64 = 0
84 while i < n {
85 crc = crc ^ bytes[i]
86 var bit: i64 = 0
87 while bit < 8 {
88 if (crc & 1) != 0 {
89 crc = ((crc >> 1) ^ 0xA001) & CR_U16_MASK
90 } else {
91 crc = (crc >> 1) & CR_U16_MASK
92 }
93 bit = bit + 1
94 }
95 i = i + 1
96 }
97 return crc & CR_U16_MASK
98}
99
100// Compile-only smoke. Known KAT for CRC-16/CCITT-FALSE on
101// "123456789" = 0x29B1.
102func main() -> i64 {
103 let msg: *u8 = "123456789"
104 let c: i64 = crc16_ccitt(msg, 9)
105 if c == 0 { return 1 }
106 let m: i64 = crc16_modbus(msg, 9)
107 if m == c { return 2 } // different polys -> different output
108 return 0
109}