-
Notifications
You must be signed in to change notification settings - Fork 19
/
crc16.go
161 lines (132 loc) · 4.11 KB
/
crc16.go
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
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package crc16
// Predefined polynomials.
const (
// IBM is used by Bisync, Modbus, USB, ANSI X3.28, SIA DC-07, ...
IBM = 0xA001
// CCITT is used by X.25, V.41, HDLC FCS, XMODEM, Bluetooth, PACTOR, SD, ...
// CCITT forward is 0x8408. Reverse is 0x1021.
CCITT = 0x8408
CCITTFalse = 0x1021
// SCSI is used by SCSI
SCSI = 0xEDD1
// MBUS is used by Meter-Bus, DNP, ...
MBUS = 0x3D65
)
// Table is a 256-word table representing the polynomial for efficient processing.
type Table struct {
entries [256]uint16
reversed bool
noXOR bool
}
// IBMTable is the table for the IBM polynomial.
var IBMTable = makeTable(IBM)
// CCITTTable is the table for the CCITT polynomial.
var CCITTTable = makeTable(CCITT)
// CCITTFalseTable is the table for CCITT-FALSE.
var CCITTFalseTable = makeBitsReversedTable(CCITTFalse)
// SCSITable is the table for the SCSI polynomial.
var SCSITable = makeTable(SCSI)
// MBusTable is the tabe used for Meter-Bus polynomial.
var MBusTable = makeBitsReversedTable(MBUS)
// MakeTable returns the Table constructed from the specified polynomial.
func MakeTable(poly uint16) *Table {
return makeTable(poly)
}
// MakeBitsReversedTable returns the Table constructed from the specified polynomial.
func MakeBitsReversedTable(poly uint16) *Table {
return makeBitsReversedTable(poly)
}
// MakeTableNoXOR returns the Table constructed from the specified polynomial.
// Updates happen without XOR in and XOR out.
func MakeTableNoXOR(poly uint16) *Table {
tab := makeTable(poly)
tab.noXOR = true
return tab
}
// makeTable returns the Table constructed from the specified polynomial.
func makeBitsReversedTable(poly uint16) *Table {
t := &Table{
reversed: true,
}
width := uint16(16)
for i := uint16(0); i < 256; i++ {
crc := i << (width - 8)
for j := 0; j < 8; j++ {
if crc&(1<<(width-1)) != 0 {
crc = (crc << 1) ^ poly
} else {
crc <<= 1
}
}
t.entries[i] = crc
}
return t
}
func makeTable(poly uint16) *Table {
t := &Table{
reversed: false,
}
for i := 0; i < 256; i++ {
crc := uint16(i)
for j := 0; j < 8; j++ {
if crc&1 == 1 {
crc = (crc >> 1) ^ poly
} else {
crc >>= 1
}
}
t.entries[i] = crc
}
return t
}
func updateBitsReversed(crc uint16, tab *Table, p []byte) uint16 {
for _, v := range p {
crc = tab.entries[byte(crc>>8)^v] ^ (crc << 8)
}
return crc
}
func update(crc uint16, tab *Table, p []byte) uint16 {
crc = ^crc
for _, v := range p {
crc = tab.entries[byte(crc)^v] ^ (crc >> 8)
}
return ^crc
}
func updateNoXOR(crc uint16, tab *Table, p []byte) uint16 {
for _, v := range p {
crc = tab.entries[byte(crc)^v] ^ (crc >> 8)
}
return crc
}
// Update returns the result of adding the bytes in p to the crc.
func Update(crc uint16, tab *Table, p []byte) uint16 {
if tab.reversed {
return updateBitsReversed(crc, tab, p)
} else if tab.noXOR {
return updateNoXOR(crc, tab, p)
} else {
return update(crc, tab, p)
}
}
// Checksum returns the CRC-16 checksum of data
// using the polynomial represented by the Table.
func Checksum(data []byte, tab *Table) uint16 { return Update(0, tab, data) }
// ChecksumIBM returns the CRC-16 checksum of data
// using the IBM polynomial.
func ChecksumIBM(data []byte) uint16 { return Update(0, IBMTable, data) }
// ChecksumCCITTFalse returns the CRC-16 checksum using
// what some call the CCITT-False polynomial, which matches what is used
// by Perl Digest/CRC and Boost for example.
func ChecksumCCITTFalse(data []byte) uint16 { return Update(0xffff, CCITTFalseTable, data) }
// ChecksumCCITT returns the CRC-16 checksum of data
// using the CCITT polynomial.
func ChecksumCCITT(data []byte) uint16 { return Update(0, CCITTTable, data) }
// ChecksumSCSI returns the CRC-16 checksum of data
// using the SCSI polynomial.
func ChecksumSCSI(data []byte) uint16 { return Update(0, SCSITable, data) }
// ChecksumMBus returns the CRC-16 checksum of data
// using the MBus polynomial.
func ChecksumMBus(data []byte) uint16 { return Update(0, MBusTable, data) }