Skip to content

Commit 0b16abc

Browse files
committed
Add CRC16 tables for ARC, MCRF4XX, and NRSC-5
1 parent 4acec76 commit 0b16abc

File tree

2 files changed

+339
-29
lines changed

2 files changed

+339
-29
lines changed

src/main/java/org/apache/commons/codec/digest/CRC16.java

Lines changed: 237 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@
2222
import java.util.zip.Checksum;
2323

2424
/**
25-
* CRC-16 checksum implementations you can customize with a table and input value.
25+
* CRC-16 checksum implementations you can customize with a table and init value.
2626
* <p>
2727
* Since there are so many CRC-16 variants, we do not pick a default.
2828
* </p>
2929
* <p>
30-
* To create a create a custom variant of CRC16-MODBUS with a init value of {@code 0x0000}, call:
30+
* For example, to create a create a custom variant of CRC16-MODBUS with an init value of {@code 0x0000}, use:
3131
* </p>
3232
* <pre>
3333
* Checksum crc16 = CRC16.builder()
@@ -49,7 +49,7 @@ public class CRC16 implements Checksum {
4949
*/
5050
public static class Builder implements Supplier<CRC16> {
5151

52-
private int init = INIT_DEFAULT;
52+
private int init;
5353
private int[] table;
5454

5555
/**
@@ -100,9 +100,8 @@ private Builder table(final int[] table) {
100100
}
101101
}
102102

103-
private static final int INIT_DEFAULT = 0x0000;
104103
// @formatter:off
105-
private static final int[] T_MODBUS = {
104+
private static final int[] ARC = {
106105
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
107106
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
108107
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
@@ -137,8 +136,49 @@ private Builder table(final int[] table) {
137136
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
138137
};
139138
// @formatter:on
139+
private static final int ARC_INIT = 0x0000;
140+
141+
// @formatter:off
142+
private static final int[] CCITT = {
143+
0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
144+
0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
145+
0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
146+
0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
147+
0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
148+
0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
149+
0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
150+
0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
151+
0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
152+
0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
153+
0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
154+
0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
155+
0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
156+
0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
157+
0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
158+
0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
159+
0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
160+
0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
161+
0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
162+
0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
163+
0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
164+
0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
165+
0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
166+
0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
167+
0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
168+
0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
169+
0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
170+
0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
171+
0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
172+
0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
173+
0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
174+
0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
175+
};
176+
// @formatter:on
177+
178+
private static final int CCITT_INIT = 0x0000;
179+
140180
// @formatter:off
141-
private static final int[] T_CCITT = {
181+
private static final int[] MCRF4XX = {
142182
0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
143183
0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
144184
0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
@@ -174,6 +214,107 @@ private Builder table(final int[] table) {
174214
};
175215
// @formatter:on
176216

217+
private static final int MCRF4XX_INIT = 0xFFFF;
218+
219+
// @formatter:off
220+
private static final int[] MODBUS = {
221+
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
222+
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
223+
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
224+
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
225+
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
226+
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
227+
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
228+
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
229+
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
230+
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
231+
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
232+
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
233+
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
234+
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
235+
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
236+
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
237+
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
238+
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
239+
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
240+
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
241+
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
242+
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
243+
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
244+
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
245+
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
246+
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
247+
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
248+
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
249+
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
250+
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
251+
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
252+
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
253+
};
254+
// @formatter:on
255+
256+
private static final int MODBUS_INIT = 0xFFFF;
257+
258+
private static final int[] NRSC5 = {
259+
0x0000, 0x35A4, 0x6B48, 0x5EEC, 0xD690, 0xE334, 0xBDD8, 0x887C,
260+
0x0D01, 0x38A5, 0x6649, 0x53ED, 0xDB91, 0xEE35, 0xB0D9, 0x857D,
261+
0x1A02, 0x2FA6, 0x714A, 0x44EE, 0xCC92, 0xF936, 0xA7DA, 0x927E,
262+
0x1703, 0x22A7, 0x7C4B, 0x49EF, 0xC193, 0xF437, 0xAADB, 0x9F7F,
263+
0x3404, 0x01A0, 0x5F4C, 0x6AE8, 0xE294, 0xD730, 0x89DC, 0xBC78,
264+
0x3905, 0x0CA1, 0x524D, 0x67E9, 0xEF95, 0xDA31, 0x84DD, 0xB179,
265+
0x2E06, 0x1BA2, 0x454E, 0x70EA, 0xF896, 0xCD32, 0x93DE, 0xA67A,
266+
0x2307, 0x16A3, 0x484F, 0x7DEB, 0xF597, 0xC033, 0x9EDF, 0xAB7B,
267+
0x6808, 0x5DAC, 0x0340, 0x36E4, 0xBE98, 0x8B3C, 0xD5D0, 0xE074,
268+
0x6509, 0x50AD, 0x0E41, 0x3BE5, 0xB399, 0x863D, 0xD8D1, 0xED75,
269+
0x720A, 0x47AE, 0x1942, 0x2CE6, 0xA49A, 0x913E, 0xCFD2, 0xFA76,
270+
0x7F0B, 0x4AAF, 0x1443, 0x21E7, 0xA99B, 0x9C3F, 0xC2D3, 0xF777,
271+
0x5C0C, 0x69A8, 0x3744, 0x02E0, 0x8A9C, 0xBF38, 0xE1D4, 0xD470,
272+
0x510D, 0x64A9, 0x3A45, 0x0FE1, 0x879D, 0xB239, 0xECD5, 0xD971,
273+
0x460E, 0x73AA, 0x2D46, 0x18E2, 0x909E, 0xA53A, 0xFBD6, 0xCE72,
274+
0x4B0F, 0x7EAB, 0x2047, 0x15E3, 0x9D9F, 0xA83B, 0xF6D7, 0xC373,
275+
0xD010, 0xE5B4, 0xBB58, 0x8EFC, 0x0680, 0x3324, 0x6DC8, 0x586C,
276+
0xDD11, 0xE8B5, 0xB659, 0x83FD, 0x0B81, 0x3E25, 0x60C9, 0x556D,
277+
0xCA12, 0xFFB6, 0xA15A, 0x94FE, 0x1C82, 0x2926, 0x77CA, 0x426E,
278+
0xC713, 0xF2B7, 0xAC5B, 0x99FF, 0x1183, 0x2427, 0x7ACB, 0x4F6F,
279+
0xE414, 0xD1B0, 0x8F5C, 0xBAF8, 0x3284, 0x0720, 0x59CC, 0x6C68,
280+
0xE915, 0xDCB1, 0x825D, 0xB7F9, 0x3F85, 0x0A21, 0x54CD, 0x6169,
281+
0xFE16, 0xCBB2, 0x955E, 0xA0FA, 0x2886, 0x1D22, 0x43CE, 0x766A,
282+
0xF317, 0xC6B3, 0x985F, 0xADFB, 0x2587, 0x1023, 0x4ECF, 0x7B6B,
283+
0xB818, 0x8DBC, 0xD350, 0xE6F4, 0x6E88, 0x5B2C, 0x05C0, 0x3064,
284+
0xB519, 0x80BD, 0xDE51, 0xEBF5, 0x6389, 0x562D, 0x08C1, 0x3D65,
285+
0xA21A, 0x97BE, 0xC952, 0xFCF6, 0x748A, 0x412E, 0x1FC2, 0x2A66,
286+
0xAF1B, 0x9ABF, 0xC453, 0xF1F7, 0x798B, 0x4C2F, 0x12C3, 0x2767,
287+
0x8C1C, 0xB9B8, 0xE754, 0xD2F0, 0x5A8C, 0x6F28, 0x31C4, 0x0460,
288+
0x811D, 0xB4B9, 0xEA55, 0xDFF1, 0x578D, 0x6229, 0x3CC5, 0x0961,
289+
0x961E, 0xA3BA, 0xFD56, 0xC8F2, 0x408E, 0x752A, 0x2BC6, 0x1E62,
290+
0x9B1F, 0xAEBB, 0xF057, 0xC5F3, 0x4D8F, 0x782B, 0x26C7, 0x1363
291+
};
292+
// @formatter:on
293+
294+
private static final int NRSC5_INIT = 0xFFFF;
295+
296+
/**
297+
* Creates a new CRC16-CCITT Checksum.
298+
* <p>
299+
* The init value is {@code 0x0000}.
300+
* </p>
301+
* <p>
302+
* Also known as:
303+
* </p>
304+
* <ul>
305+
* <li>CRC-16/ARC</li>
306+
* <li>ARC</li>
307+
* <li>CRC-16</li>
308+
* <li>CRC-16/LHA</li>
309+
* <li>CRC-IBM</li>
310+
* </ul>
311+
*
312+
* @return a new CRC16-CCITT Checksum.
313+
*/
314+
public static CRC16 arc() {
315+
return builder().setInit(ARC_INIT).table(ARC).get();
316+
}
317+
177318
/**
178319
* Creates a new builder.
179320
* <p>
@@ -187,48 +328,118 @@ public static Builder builder() {
187328
}
188329

189330
/**
190-
* Creates a new CRC16-CCITT.
331+
* Creates a new CRC16-CCITT Checksum.
191332
* <p>
192333
* The init value is {@code 0x0000}.
193334
* </p>
335+
* <p>
336+
* Also known as:
337+
* </p>
338+
* <ul>
339+
* <li>CRC-16/KERMIT</li>
340+
* <li>CRC-16/BLUETOOTH</li>
341+
* <li>CRC-16/CCITT</li>
342+
* <li>CRC-16/CCITT-TRUE</li>
343+
* <li>CRC-16/V-41-LSB</li>
344+
* <li>CRC-CCITT</li>
345+
* <li>KERMIT</li>
346+
* </ul>
194347
*
195-
* @return a new CRC16-CCITT.
348+
* @return a new CRC16-CCITT Checksum.
196349
*/
197350
public static CRC16 ccitt() {
198-
return builder().setInit(0x0000).table(T_CCITT).get();
351+
return builder().setInit(CCITT_INIT).table(CCITT).get();
352+
}
353+
354+
/**
355+
* Gets a copy of the CRC16-CCITT table.
356+
*
357+
* @return a copy of the CCRC16-CITT table.
358+
*/
359+
public static int[] getArcTable() {
360+
return ARC.clone();
199361
}
200362

201363
/**
202-
* Gets a copy of the CCITT table.
364+
* Gets a copy of the CRC16-CCITT table.
203365
*
204-
* @return a copy of the CCITT table.
366+
* @return a copy of the CCRC16-CITT table.
205367
*/
206368
public static int[] getCcittTable() {
207-
return T_CCITT.clone();
369+
return CCITT.clone();
370+
}
371+
372+
/**
373+
* Gets a copy of the CRC16-MCRF4XX table.
374+
*
375+
* @return a copy of the CRC16-MCRF4XX table.
376+
*/
377+
public static int[] getMcrf4xxTable() {
378+
return MCRF4XX.clone();
208379
}
209380

210381
/**
211-
* Gets a copy of the MODBUS table.
382+
* Gets a copy of the CRC16-MODBUS table.
212383
*
213-
* @return a copy of the MODBUS table.
384+
* @return a copy of the CRC16-MODBUS table.
214385
*/
215386
public static int[] getModbusTable() {
216-
return T_MODBUS.clone();
387+
return MODBUS.clone();
388+
}
389+
390+
/**
391+
* Gets a copy of the CRC16-NRSC-5 table.
392+
*
393+
* @return a copy of the CRC16-NRSC-5 table.
394+
*/
395+
public static int[] getNrsc5Table() {
396+
return NRSC5.clone();
397+
}
398+
399+
/**
400+
* Creates a new instance for CRC16-MCRF4XX Checksum.
401+
* <p>
402+
* The init value is {@code 0xFFFF}.
403+
* </p>
404+
*
405+
* @return a new CRC16-MCRF4XX Checksum.
406+
*/
407+
public static CRC16 mcrf4xx() {
408+
return builder().setInit(MCRF4XX_INIT).table(MCRF4XX).get();
217409
}
218410

219411
/**
220-
* Creates a new CRC16-MODBUS.
412+
* Creates a new instance for CRC16-MODBUS Checksum.
221413
* <p>
222414
* CRC-16 checksum implementation based on polynomial {@code x<sup>16</spu> + x^15 + x^2 + 1 (0x8005)}.
223415
* </p>
224416
* <p>
225417
* The init value is {@code 0xFFFF}.
226418
* </p>
419+
* <p>
420+
* Also known as:
421+
* </p>
422+
* <ul>
423+
* <li>CRC-16/MODBUST</li>
424+
* <li>MODBUST</li>
425+
* </ul>
227426
*
228-
* @return a new CRC16-MODBUS.
427+
* @return a new CRC16-MODBUS Checksum.
229428
*/
230429
public static CRC16 modbus() {
231-
return builder().setInit(0xFFFF).table(T_MODBUS).get();
430+
return builder().setInit(MODBUS_INIT).table(MODBUS).get();
431+
}
432+
433+
/**
434+
* Creates a new instance for CRC16-NRSC-5 Checksum.
435+
* <p>
436+
* The init value is {@code 0xFFFF}.
437+
* </p>
438+
*
439+
* @return a new CRC16-NRSC-5 Checksum.
440+
*/
441+
public static CRC16 nrsc5() {
442+
return builder().setInit(NRSC5_INIT).table(NRSC5).get();
232443
}
233444

234445
/**
@@ -266,10 +477,16 @@ public void reset() {
266477
crc = init;
267478
}
268479

480+
@Override
481+
public String toString() {
482+
return String.format("CRC16 [init=0x%04X, crc=0x%04X]", init, crc);
483+
}
484+
269485
@Override
270486
public void update(final byte[] b, final int off, final int len) {
271-
for (int i = 0; i < len; i++) {
272-
update(b[off + i]);
487+
final int end = len + off;
488+
for (int i = off; i < end; i++) {
489+
update(b[i]);
273490
}
274491
}
275492

0 commit comments

Comments
 (0)