I have been tasked with implementing a CRC using Java. I wasn't given a specs to follow, but I am following this PDF:
https://cdn.standards.iteh.ai/samples/6904/2c02d323a7ae41838de8b8b806cf3725/ISO-2111-1985.pdf
I was given two sample strings to compare:
Byte Stream (Hex): 220017e11201040c9ebce8003201028149d3d904808d14
Byte Stream with ISO2111 (Hex): 1002220017e11201040c9ebce8003201028149d3d904808d141003939c
The first string is the raw data that I have received and the second string is how it should look after ISO2111 has been applied (according to the person that made the request).
Adding the DLEs (1002 at start, 1003 at end) was trivial, but I cannot reproduce the checksum at the end of the transmission (939c).
I first transform the string into an array of bytes and then pass it in to the below function.
The java code I was using to calculate the CRC16 is:
public static String calculateCRC16(final byte[] bytes) {
int CRC = 0xFFFF; // initial CRC value : 0xFFFF -> max value of 65535
int POLYNOMIAL = 0x1021; // 0x1021 = x^16 + x^12 + x^5 + 1
for (byte b : bytes) {
for (int i = 0; i < 8; i++) {
boolean bit = ((b >> (7 - i) & 1) == 1);
boolean c15 = ((CRC >> 15 & 1) == 1);
CRC <<= 1;
if (c15 ^ bit) {
CRC ^= POLYNOMIAL;
}
}
}
CRC &= 0xffff;
return Integer.toHexString(CRC);
}
The problem is that, for the given string, it outputs d806, not 939c. The value d806 seems to be correct according to some online CRC calculators. Am I missing something? Is the data they sent just made up? Have I misinterpreted section 8 in the PDF? This is what it says:
8 Block check sequence (BCS) The BCS shall conform to the following rules : 8.1 It shall be a 16 bit sequence (two octets).
8.2 The sequence of information bits contained in the data block to be protected may be represented by a polynomial L(x) (GF 2): The BCS is the remainder after the division of the polynomial Lfxi IGF2), multiplied by x16, by the generating polynomial p(x) = x16 + x12 + x5 + 1 (GF2). GF2 means that these polynomials have their coefficients in a two element Galois field.
8.3 The BCS shall be transmitted to the line commencing with the coefficient of the highest term.
8.4 At the receiver, the serial incoming protected data and the BCS when divided by the generating polynomial results in a zero remainder in the absence of transmission errors."
There is no other info about this anywhere else online as far as I can see.
There are rules in the document about what the CRC (they call it a BCS) is calculated over, and about getting rid of DLE bytes before doing that. As a result, the CRC for the example message starts after the leading 1002
and goes up to the 03
before the CRC, but the DLE (10
) before the 03
is deleted.
So the CRC is calculated over:
220017e11201040c9ebce8003201028149d3d904808d1403
Then the forward CRC with polynomial 0x1021
, zero initial value, and zero final exclusive-or gives the result 0x939c
. You may find that particular 16-bit CRC referred to as CRC-16/XMODEM. The calculation is:
static private int crc16xmodem(byte[] message) {
int crc = 0;
for (byte octet : message) {
crc ^= (int)octet << 8;
for (int k = 0; k < 8; k++)
crc = (crc & 0x8000) != 0 ? (crc << 1) ^ 0x1021 : crc << 1;
}
return crc & 0xffff;
}
Read the DLE rules. A case that doesn't occur in your example is: DLE DLE in the message becomes DLE, since that first DLE is an escape so that the second DLE can be transmitted as part of the message.