I've started with Arduino and the next task I set to myself is to unterstand how a CRC check could be implemented. I think I've found a decent code for that. But simply implementing...no, I want to learn. I searched a bit on CRC in general and I used a youtube video to learn the mathematical base principle and another site which taught me how to implement CRC in C language. Especially after reading this, my head is overloaded a bit but I think I understood the principle.
So, after I hopefully convinced you that I want to learn that stuff, here is the 2nd link which is giving the Arduino CRC Code Snippet that is too complicated for me.
There are several little things which are producing question marks in my head, e.g. what ~0L means, or why in the crc-strings function's while-loop there is the condition *s, and a lot of more things.
Can someone go through the code provided in the 2nd link and explain what it does in detail so that also average guys like me can understand instead just implement the code?
I'm very thankful.
Best regards
EDIT: I will post specific questions related to the 2nd link as requested in a comment.
In the crc_string function the variable crc is initialized with ~0L. I know that ~ is a bitwise operator that makes a 0 to a 1 and vice-versa. But what does it do to 0L? What is 0L at all? Another expression for NULL? Why is it written in such an abstract way? Is there maybe existing an easier way to code this?
next line in the crc_string function: while(*s) --> *s is "HELLO" in the example. But what is meant with this? Isn't it always true? When can it change to false? I know some pointer basics but I don't get this.
Now we dive into the while expression: crc_update(crc, *s++); --> what is the second argument in the case of "HELLO", what does ++ do in this case? I mean, how do you increment HELLO by 1?
I think after knowing this the rest becomes more clear but I can go on with some more questions:
Now we are going into the update function: I really don't get the whole function, why is there some shifting with 0*4 (isn't this useless?), how the heck behaves pgm_read_dword_near, why is there again some shifting and why, after returning crc, the crc is ~ again?
In the first link before I editted this post you can see that the author is using a table to store the crc's of 256 bits. Here in this tutorial, there is a table with 16 entries. I have a rough understanding why we use tables and I think the author uses only 16 entries because of the limited space arduino is providing. But nonetheless, how is this all working here? I really don't get it.
Hope that is specific enough for the beginning.
Another more general crc question: I mean, the basic idea of crc is to divide a byte-message with another mystical number and append the remaining part to the message --> crc is the remaining part. But what I do when I have 2 bytes, e.g. I want to transmit two chars like "H" and "W" at the same time? Then I have to crc's. How do I transform both crc's to one final crc?
EDIT 2 because I want to answer to the answer of James Bowman:
First of all, it's so great that only 1 day after I ask a question, the owner of the code comes and answers it.
With your instructions which already helped me a lot I try to go through one loop with the example of the first letter "H" till I get stuck.
I think that some more questions will occur and I hope that you can also correct me if I tell bullshit now:
2.1. First, crc is initialized with 0xFFFFFFFF.
2.2. "HELLO" is like an array. What the pointer does in the while-loop is to dereference the first address of that array, so it's the "H"
2.3. crc_update is called with the arguments: 0xFFFFFFFF and "H". AFTER that is done the Pointer is going to "E".
2.4. In the update function tbl_idx gets initialized with 0xFFFFFFFF ^ 0x48 (ASCII Code for "H"). So how is it exactly here since 0x48 is only 1 byte? I transform 0x48 to binary which is: 0100 1000. Then, after the bitwise operation, it's: 1011 0111. Is that correct? So tbl_idx is now 1011 0111.
2.5. Then the pgm search function comes. In the documentation I found something confusing about the "dword": "Read a double word from the program space with a 16-bit (near) address." But in the table, it's all about 32 bit? Can you explain me that?
2.6. I go on with this function. So it searches in the table for: 1011 0111 & 0x0f which is 0000 0111 and then ^ with crc>>4 (0000 1111 1111 1111 1111 1111 1111 1111 - correct?) which is: good question...again different byte sizes... in case that the byte most right is taken into consideration, then the result would be: 1111 1000, so it looks in the table for that value but there are only 16 entries, not 248 :(
I think I have a thinking error here so that I can not go on. It would be too kind if you could help me out here.
If you also have a nice and easy documentation about CRC32 which may be also understandable for me, don't hesitate to share it :-)
I wrote the code you're linking to, so I will attempt to answer your questions.
Using ~0L. This is necessary because the algorithm works on 32-bit numbers, and the Arduino's code uses 16-bit numbers by default. The "L" suffix tells the compiler that the value is "long", so it does the math on it in 32-bits.
The type of "s" is "pointer to char" - this is often thought of as "string" but in a few situations they differ. In particular, "*s" is the current character that s is pointing to. Initially *s is H, then E, L, L, O. Finally it points to the end of the string so *s is zero. At this point the while loop exits.
Because "s" is "pointer to char" then s++ means the next char.
Shift with "0*4" doesn't do anything - it's just there to show the symmetry present in the original algorithm. pgm_read_dword_near() is a fetch function to access the array - it is necessary because the table is stored in Arduino flash memory. The final inversion (~) is part of the CRC-32 algorithm.
In fact many table sizes are possible: 1-bit, 2, 4, and 8-bit are popular. The pycrc tool lets you generate the table for any size. In general there is a tradeoff of table size against computation. Here the code uses a fairly small table, but need to do two lookups per byte.