I have the following code in C to calculate a CRC16-USB for some data flows:
uint16_t DRV_CANFDSPI_CalculateCRC16(uint8_t* data, uint16_t size)
{
uint16_t init = CRCBASE;
uint8_t index;
while (size-- != 0) {
index = ((uint8_t*) & init)[1] ^ *data++;
init = (init << 8) ^ crc16_table[index];
}
return init;
}
Where crc16_table is an array of some hex values of 2 bytes (like 0xAFF3) , and data is an array of hex values of 1 byte (like 0xA3) representing the data stream (aqcuired by other means). Size is the length of the data array.
I want to reproduce this piece of code in Python, but I don't know that this statement means:
index = ((uint8_t*) & init)[1] ^ *data++;
I would like to understand that does this statament means and does, so I can reproduce it in Python. I am not an expert in C but have some knowledge, and I mostly undestand the rest of the code, but this line is giving me a headache.
Thanks and have a nice day!
init
has type uint16_t
, so the expression &init
has type "pointer to uint16_t
", or uint16_t *
. The expression (uint8_t *) &init
means "get the address of init
, but treat that as the address of a uint8_t
object, rather than a uint16_t
object".
That address is then used with a subscript operator - ((uint8_t *) &init)[1]
, which is basically equivalent to "treat init
as an array of two uint8_t
objects, and give me the value of the second element in that array".
Graphically:
+---+
init: | | <-- ((uint8_t *) &init)[0]
+---+
| | <-- ((uint8_t *) &init)[1]
+---+
So, basically, you're grabbing the lower 8 bits of init
, bitwise XORing that with the value of the current byte of the input message, and then advancing data
to point to the next byte of the input message.
I found a solution for my problem, with the following code:
def calculateCRC16(data):
init = 0xFFFF
for byte in data:
index = (init >> 8) ^ byte
init = ((init << 8) ^ crc16_table[index]) & 0xFFFF
return init
I think it is fairly simple. I tested this code with the above one in C and the results are the same. The masking in Python in the variable init is necessary as Python does not limit int variables to a fixed bit size. Also, in C, lib should be included for the code to work.
The intent of the index = ((uint8_t*) & init)[1] ^ *data++;
statement is to XOR the high eight bits of init
with the next byte of data
(and to increment `data). Unfortunately, it is written improperly.
In the statement index = ((uint8_t*) & init)[1] ^ *data++;
:
& init
takes the address of init
(which was defined with uint16_t init = CRCBASE;
). (uint8_t*)
converts that address to a pointer to uint8_t
. Further use of this pointer requires that uint8_t
be a character type in the C implementation, which is likely but is not guaranteed by the C standard. [1]
to this pointer fetches the next byte beyond where the pointer points. The fact that the second line uses init << 8
, which results in a value solely dependent on the *low** eight bits of init
, suggests that the intent in this first line was to fetch the high eight bits of init
. However, the C standard does not require that the bytes of a uint16_t
be in any particular order, so it is not assured that using [1]
will fetch the desired bits. And it is unnecessary; using init >> 8
in place of ((uint8_t*) & init)[1]
would provide the desired bits.
Thus, the code could have been simply:
while (size--)
init = init << 8 ^ crc16_table[init>>8 ^ *data++];
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.