CRC-16 0x8005 polynominal, from C to C#. SOS - c#

I have this block of C code that I can not for the life of me understand. I need to calculate the CRC-16 for a certain byte array I send to the method and it should give me the msb(most significant byte) and the lsb(least significant byte). I was also given a C written app to test some functionality and that app also gives me a log of what is sent and what is received via COM port.
What is weird is that I entered the hex string that I found in the log into this online calculator, but it gives me a different result.
I took a stab at translating the method to C#, but I don't understand certain aspects:
What is pucPTR doing there (it's not beeing used anywhere else)?
What do the 2 lines of code mean, under the first for?
Why in the second for the short "i" is <=7, shouldn't it be <=8?
Last line in if statement means that usCRC is in fact ushort 8005?
Here is the block of code:
unsigned short CalculateCRC(unsigned char* a_szBufuer, short a_sBufferLen)
{
unsigned short usCRC = 0;
for (short j = 0; j < a_sBufferLen; j++)
{
unsigned char* pucPtr = (unsigned char*)&usCRC;
*(pucPtr + 1) = *(pucPtr + 1) ^ *a_szBufuer++;
for (short i = 0; i <= 7; i++)
{
if (usCRC & ((short)0x8000))
{
usCRC = usCRC << 1;
usCRC = usCRC ^ ((ushort)0x8005);
}
else
usCRC = usCRC << 1;
}
}
return (usCRC);
}
This is the hex string that I convert to byte array and send to the method:
02 00 04 a0 00 01 01 03
This is the result that should be given from the CRC calculus:
06 35
The document I have been given says that this is a CRC16 IBM (msb, lsb) of the entire data.
Can anyone please help? I've been stuck on it for a while now.
Any code guru out there capable of translating that C method to C#? Apparently I'm not capable of such sourcery.

First of all, please note than in C, the ^ operator means bitwise XOR.
What is pucPTR doing there (it's not beeing used anywhere else)?
What do the 2 lines of code mean, under the first for?
Causing bugs, by the looks of it. It is only used to grab one of the two bytes of the FCS, but the code is written in an endianess-dependent way.
Endianess is very important when dealing with checksum algorithms, since they were originally designed for hardware shift registers, that require MSB first, aka big endian. In addition, CRC often means data communication, and data communication means possibly different endianess between the sender, the protocol and the receiver.
I would guess that this code was written for little endian machines only and the intent is to XOR with the ms byte. The code points to the first byte then uses +1 pointer arithmetic to get to the second byte. Corrected code should be something like:
uint8_t puc = (unsigned int)usCRC >> 8;
puc ^= *a_szBufuer;
usCRC = (usCRC & 0xFF) | ((unsigned int)puc << 8);
a_szBufuer++;
The casts to unsigned int are there to portably prevent mishaps with implicit integer promotion.
Why in the second for the short "i" is <=7, shouldn't it be <=8?
I think it is correct, but more readably it could have been written as i < 8.
Last line in if statement means that usCRC is in fact ushort 8005?
No, it means to XOR your FCS with the polynomial 0x8005. See this.
The document I have been given says that this is a CRC16 IBM
Yeah it is sometimes called that. Though from what I recall, "CRC16 IBM" also involves some bit inversion of the final result(?). I'd double check that.
Overall, be careful with this code. Whoever wrote it didn't have much of a clue about endianess, integer signedness and implicit type promotions. It is amateur-level code. You should be able to find safer, portable professional versions of the same CRC algorithm on the net.
Very good reading about the topic is A Painless Guide To CRC.

What is pucPTR doing there (it's not beeing used anywhere else)?
pucPtr is used to transform uglily an unsigned short to an array of 2 unsigned char. According endianess of platform, pucPtr will point on first byte of unsigned short and pucPtr+1 will point on second byte of unsigned short (or vice versa). You have to know if this algorithm is designed for little or big endian.
Code equivalent (and portable, if code have been developed for big endian):
unsigned char rawCrc[2];
rawCrc[0] = (unsigned char)(usCRC & 0x00FF);
rawCrc[1] = (unsigned char)((usCRC >> 8) & 0x00FF);
rawCrc[1] = rawCrc[1] ^ *a_szBufuer++;
usCRC = (unsigned short)rawCrc[0]
| (unsigned short)((unsigned int)rawCrc[1] << 8);
For little endian, you have to inverse raw[0] and raw[1]
What do the 2 lines of code mean, under the first for?
First line does the ugly transformation described in 1.
Second line retrieves value pointed by a_szBufuer and increment it. And does a "xor" with second (or first, according endianess) byte of crc (note *(pucPtr +1) is equivalent of pucPtr[1]) and stores results inside second (or first, according endianess) byte of crc.
*(pucPtr + 1) = *(pucPtr + 1) ^ *a_szBufuer++;
is equivalent to
pucPtr[1] = pucPtr[1] ^ *a_szBufuer++;
Why in the second for the short "i" is <=7, shouldn't it be <=8?
You have to do 8 iterations, from 0 to 7. You can change condition to i = 0; i<8 or i=1; i<=8
Last line in if statement means that usCRC is in fact ushort 8005?
No, it doesn't. It means that usCRC is now equal to usCRC XOR 0x8005. ^ is XOR bitwise operation (also called or-exclusive). Example:
0b1100110
^0b1001011
----------
0b0101101

Related

How to bit-shift a register to zero?

When you left-shift (<<) or right-shift (>>) an integer register, you pull in zeros from the opposite side. It stands to reason that if you shift by more than the width of a register (e.g. shift a uint by 32 or more bits), it should become all zeros. In C#, this is not what happens. Instead, the shift count is effectively interpreted mod the register width, so it is impossible to definitively make the register zero using shifts. This is a pain.
I got hit by this because I am representing an extra-large integer via a unit[]. When you perform bit shifts on the extra-large register, in general bits from different uint instances in the array must "mix", so the code does stuff like:
s[i] = (s[i+k] << n) | (s[i+k+1] >> (32 - n))
but this code fails when n = 0 or 32, i.e. when the shift corresponds to a pure shift among uint values with no mixing. (It's easy to write the code so that n = 32 never appears, but then the shift by (32 - n) still fails when n = 0.) For now, I have got around this problem by special-casing n = 0, but this is extra code (ugly) and an extra test-and-branch in a performance-critical spot (bad).
Can anyone suggest a modification (maybe using masking instead of or in addition to bit shifting?) to get around this difficulty? Can anyone explain why C# made the choice to make shift counts not behave according to naive expectations?

What is code for logical right shift in C#?

I am trying to translate Java code with logical right shift (>>>) (Difference between >>> and >>) to C#
Java code is
return hash >>> 24 ^ hash & 0xFFFFFF;
C# is marked >>> as syntax error.
How to fix that?
Update 1
People recommend to use >> in C#, but it didn't solve problem.
System.out.println("hash 1 !!! = " + (-986417464>>>24));
is 197
but
Console.WriteLine("hash 1 !!! = " + (-986417464 >> 24));
is -59
Thank you!
Java needed to introduce >>> because its only unsigned type is char, whose operations are done in integers.
C#, on the other hand, has unsigned types, which perform right shift without sign extension:
uint h = (uint)hash;
return h >> 24 ^ h & 0xFFFFFF;
For C# you can just use >>
If the left-hand operand is of type uint or ulong, the right-shift operator performs a logical shift: the high-order empty bit positions are always set to zero.
From the docs.

C++ to .NET : I need help with understanding C++ code to convert it to .NET

C++ code is :
unsigned short* ui=(unsigned short*)&buf[110];
CountDev=ui[0];
buf is byte[] and CountDev is unsigned int
(BCB6 Compiler x86)
My try is :
F#
...CountDev = System.BitConverter.ToInt32( [| arrayRead.[110]; arrayRead.[111] |] , 0 )
C#
...CountDev = System.BitConverter.ToInt32( [arrayRead[110]; arrayRead[111]] , 0 )
But seriously I can't be sure about it. Check my try and tell me if I am doing it wrong please.
You might be able to use:
... = System.BitConverter.ToUint16(arrayRead, 110);
But it does depend on big/little endian (the order of the bytes in the array).
You will need specifications for that or a good test case.
I would just do this to simply concatenate the two bytes and putting it into an int:
UInt32 CountDev = (UInt32)arrayRead[111] << 8 | (UInt32)arrayRead[110];
since you just need the least significant two byte, and int is 4 byte long (the most significant or sign bit is not touched), you can also use a signed int:
int CountDev = (int)arrayRead[111] << 8 | (int)arrayRead[110];
Edit:
Henk Holtermans solution is definitely the better choice as it uses the endianess of the current machine:
UInt32 CountDev = (UInt32)System.BitConverter.ToUint16(arrayRead, 110);
You need to use System.BitConverter.ToUInt16 instead of System.BitConverter.ToInt32

How to perform a Bitwise Operator on a byte array in C#

I am using C# and Microsoft.Xna.Framework.Audio;
I have managed to record some audio into a byte[] array and I am able to play it back.
The audio comes in as 8 bit unsigned data, and I would like to convert it into 16 bit mono signed audio so I can read the frequency what not.
I have read a few places that for sound sampling you perform a Bitwise Operator Or and shift the bits 8 places.
I have performed the code as follows;
soundArray[i] = (short)(buffer[i] | (buffer[i + 1] << 8));
What I end up with is a lot of negative data.
From my understanding it would mostly need to be in the positive and would represent a wave length of data.
Any suggestions or help greatly appreciated,
Cheers.
MonkeyGuy.
This combines two 8-bit unsigned integers into one 16-bit signed integer:
soundArray[i] = (short)(buffer[i] | (buffer[i + 1] << 8));
I think what you might want is to simply scale each 8-bit unsigned integer to a 16-bit signed integer:
soundArray[i] = (short)((buffer[i] - 128) << 8);
Have you tried converting the byte to short before shifting?

How do I encode a 4-byte string as a single 32-bit integer?

First, a disclaimer. I'm not a CS grad nor a math major, so simplicity is important.
I have a four-character string (e.g. "isoy") that I need to pass as a single 32-bit integer field. Of course at the other end, I need to decode it back to a string. The string will only contain A-Z, and case is not important, if that helps.
The funny part is that I'm starting with PowerShell on the sending end and Linux at the receiving end. I can use Perl or Python there, with a preference for Python. I don't actually need answers in each language, I'm most interested in a PowerShell (C# also good) example for going both ways.
To 32-bit unsigned integer:
uint x = BitConverter.ToUInt32(Encoding.ASCII.GetBytes("isoy"), 0); // 2037347177
To string:
string s = Encoding.ASCII.GetString(BitConverter.GetBytes(x)); // "isoy"
BitConverter uses the native endianness of the machine.
For Python, struct.unpack does the job (to make a 4-byte string into an int -- struct.pack goes the other way):
>>> import struct
>>> struct.unpack('i', 'isoy')[0]
2037347177
>>> struct.pack('i', 2037347177)
'isoy'
>>>
(you can use different formats to ensure big-endian or little-endian encoding, if you need that -- '>i' and '<i' respectively -- instead of just plain 'i' which uses whatever encoding is native to the machine).
// string -> int
uint ret = 0;
for ( int i = 0; i < 4; ++i )
{
ret |= ( str[i] << ( i * 8 ) );
}
// int -> string
for ( int i = 0; i < 4; ++i )
{
str[i] = ( ret >> ( i * 8 ) ) & 0xff;
}
Using PowerShell syntax you can do it this way (pretty much like dtb solution):
PS> $x = [BitConverter]::ToUInt32([byte[]][char[]]'isoy', 0)
PS> [char[]][BitConverter]::GetBytes($x) -join ''
isoy
You do have to watch out for endian-ness on the Linux side. If it is running on an Intel processor I believe should be fine (same endian-ness as the PowerShell side).
Please take a look at the struct standard library module in Python's Manual. It has two functions for this: struct.pack and struct.unpack. You can use the 'L' (unsigned long) format character for this.
Aside from byte packing, you can also consider that your 26-character alphabet can be encoded as 0-25 instead of A-Z.
So without worrying about big and little endians, you can go from "letters" to a number like this:
val=letter0+letter1*26+letter2*26*26+letter3*26*26*26;
to go from val back to letters, you do something like this:
letter0=val%26;
letter1=(val/26)%26;
letter2=(val/(26*26))%26;
letter3=(val/(26*26*26))%26;
where "%" is your language's modulus operator and "/" is an integer division.
You'll obviously need a way to get from 'A'-'Z' to 0-25 and back. That's language dependent.
You can easily put this into loops. I show the loops unrolled to make things a bit more obvious.
It's more common to pack letters into bytes, so you can use shift and and bitwise operations to encode and decode. But by doing it the way I show above, you could pack six letters into a 32-bit number, rather than just four. Which is nice, since you can hold things like stock market ticker symbols in a single 32-bit value (mutual funds ticker symbols are 5 characters).

Categories

Resources