code wiki / (root) / crc16.nx

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}