Generate a 4 bit checksum of an integer - c

I have an Arduino serial connection with 4 bits per transmission left for a check sum. I have never done a check sum algorithm before and am sadly lost right now.
CRC-4 implementation in C# has already started a question but the answer isn't really helping me go forward.
Input should be an integer of which only 10 bits are important.
Output should be 4 bits of a byte.
Can someone explain to me how I can adapt the answer from the other question or point me another direction?
byte checksum(int message)
{
//Check sum algorithm
}

well the other algorithm is easily translatable to pure C:
uint8_t calculate(byte[] bytes) {
uint16_t crc = 0xFFFF; // initial value
// loop, calculating CRC for each byte of the string
for (uint8_t byteIndex = 0; byteIndex < bytes.Length; ++byteIndex) {
uint8_t bit = 0x80; // initialize bit currently being tested
for (uint8_t bitIndex = 0; bitIndex < 8; ++bitIndex) {
bool xorFlag = ((crc & 0x8000) == 0x8000);
crc <<= 1;
if (((bytes[byteIndex] & bit) ^ (uint8_t)0xff) != (uint8_t)0xff)
crc = crc + 1;
if (xorFlag)
crc = crc ^ 0x1021;
bit >>= 1;
}
}
return (uint8_t)crc;
}
the only difference being the use of the stdint.h types.
I also changed the type of crc to be exactly a 16 bits unsigned, and for the
indexes, only for sparing some arduino memory which is precious (every byte counts
when you got only 2.5k of RAM! :-) )
Though, I did neither test or proof read that code, so it should be as good as the
original C# one. If it's buggy, that one will be as well.
EDIT: As the OP added in comment, this resource is a good explanation of how the above CRC algorithm work: http://www.barrgroup.com/Embedded-Systems/How-To/CRC-Calculation-C-Code.
HTH

Related

Bit mask operation: what does the following code mean in C?

I am trying to debugging a piece of code at the moment and I could not figure it out what the following piece of code really does. Could anyone help me explain or give me ideas on the functionality of the following code?
uint8_t get_pca9955a_slave_loaded(uint8_t _slave)
{
uint8_t x = (uint8_t)(_slave / 16);
uint8_t y = (uint8_t)(_slave % 16);
uint16_t mask = 1U << y;
if (check_pca9955a_slave_valid(_slave)) {
return (uint8_t)((pca9955a_slaves_loaded[x] & mask) ? 1U : 0U);
} else {
return 0U;
}
}
Kind Regards,
Cheung
It unpacks a byte into its high nibble x and its low nibble y. Taking mod 16 is the same as taking the four lowest bits, and dividing by 16 is the same as taking the remaining bits.
It then uses y to calculate a bitmask and x as an offset into some kind of table of global variables that you didn’t share, checks that bit y is set in entry x or not, and returns either 1 or 0 in an unsigned byte.

CRC-15 giving wrong values

I am trying to create a CRC-15 check in c and the output is never correct for each line of the file. I am trying to output the CRC for each line cumulatively next to each line. I use: #define POLYNOMIAL 0xA053 for the divisor and text for the dividend. I need to represent numbers as 32-bit unsigned integers. I have tried printing out the hex values to keep track and flipping different shifts around. However, I just can't seem to figure it out! I have a feeling it has something to do with the way I am padding things. Is there a flaw to my logic?
The CRC is to be represented in four hexadecimal numbers, that sequence will have four leading 0's. For example, it will look like 0000xxxx where the x's are the hexadecimal digits. The polynomial I use is 0xA053.
I thought about using a temp variable and do 4 16 bit chunks of code per line every XOR, however, I'm not quite sure how I could use shifts to accomplish this so I settled for a checksum of the letters on the line and then XORing that to try to calculate the CRC code.
I am testing my code using the following input and padding with . until the string is of length 504 because that is what the pad character needs to be via the requirements given:
"This is the lesson: never give in, never give in, never, never, never, never - in nothing, great or small, large or petty - never give in except to convictions of honor and good sense. Never yield to force; never yield to the apparently overwhelming might of the enemy."
The CRC of the first 64 char line ("This is the lesson: never give in, never give in, never, never,) is supposed to be 000015fa and I am getting bfe6ec00.
My logic:
In CRCCalculation I add each character to a 32-bit unsigned integer and after 64 (the length of one line) I send it into the XOR function.
If it the top bit is not 1, I shift the number to the left one
causing 0s to pad the right and loop around again.
If the top bit is 1, I XOR the dividend with the divisor and then shift the dividend to the left one.
After all calculations are done, I return the dividend shifted to the left four ( to add four zeros to the front) to the calculation function
Add result to the running total of the result
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#define POLYNOMIAL 0xA053
void crcCalculation(char *text, int length)
{
int i;
uint32_t dividend = atoi(text);
uint32_t result;
uint32_t sumText = 0;
// Calculate CRC
printf("\nCRC 15 calculation progress:\n");
i = length;
// padding
if(i < 504)
{
for(; i!=504; i++)
{
// printf("i is %d\n", i);
text[i] = '.';
}
}
// Try calculating by first line of crc by summing the values then calcuating, then add in the next line
for (i = 0; i < 504; i++)
{
if(i%64 == 0 && i != 0)
{
result = XOR(POLYNOMIAL, sumText);
printf(" - %x\n",result);
}
sumText +=(uint32_t)text[i];
printf("%c", text[i]);
}
printf("\n\nCRC15 result : %x\n", result);
}
uint32_t XOR(uint32_t divisor, uint32_t dividend)
{
uint32_t divRemainder = dividend;
uint32_t currentBit;
// Note: 4 16 bit chunks
for(currentBit = 32; currentBit > 0; --currentBit)
{
// if topbit is 1
if(divRemainder & 0x80)
{
//divRemainder = (divRemainder << 1) ^ divisor;
divRemainder ^= divisor;
printf("%x %x\n", divRemainder, divisor);
}
// else
// divisor = divisor >> 1;
divRemainder = (divRemainder << 1);
}
//return divRemainder; , have tried shifting to right and left, want to add 4 zeros to front so >>
//return divRemainder >> 4;
return divRemainder >> 4;
}
The first issue I see is the top bit check, it should be:
if(divRemainder & 0x8000)
The question doesn't state if the CRC is bit reflected (xor data into low order bits of CRC, right shift for cycle) or not (xor data into high order bits of CRC, left shift for cycle), so I can't offer help for the rest of the code.
The question doesn't state the initial value of CRC (0x0000 or 0x7fff), or if the CRC is post complemented.
The logic for a conventional CRC is:
xor a byte of data into the CRC (upper or lower bits)
cycle the CRC 8 times (or do a table lookup)
After generating the CRC for an entire message, the CRC can be appended to the message. If a CRC is generated for a message with the appended CRC and there are no errors, the CRC will be zero (or a constant value if the CRC is post complemented).
here is a typical CRC16, extracted from: <www8.cs.umu.se/~isak/snippets/crc-16.c>
#define POLY 0x8408
/*
// 16 12 5
// this is the CCITT CRC 16 polynomial X + X + X + 1.
// This works out to be 0x1021, but the way the algorithm works
// lets us use 0x8408 (the reverse of the bit pattern). The high
// bit is always assumed to be set, thus we only use 16 bits to
// represent the 17 bit value.
*/
unsigned short crc16(char *data_p, unsigned short length)
{
unsigned char i;
unsigned int data;
unsigned int crc = 0xffff;
if (length == 0)
return (~crc);
do
{
for (i=0, data=(unsigned int)0xff & *data_p++;
i < 8;
i++, data >>= 1)
{
if ((crc & 0x0001) ^ (data & 0x0001))
crc = (crc >> 1) ^ POLY;
else crc >>= 1;
}
} while (--length);
crc = ~crc;
data = crc;
crc = (crc << 8) | (data >> 8 & 0xff);
return (crc);
}
Since you want to calculate a CRC15 rather than a CRC16, the logic will be more complex as cannot work with whole bytes, so there will be a lot of bit shifting and ANDing to extract the desire 15 bits.
Note: the OP did not mention if the initial value of the CRC is 0x0000 or 0x7FFF, nor if the result is to be complemented, nor certain other criteria, so this posted code can only be a guide.

CRC bit-order confusion

I'm calculating a CCITT CRC-16 bit by bit. I do this that way because it's a prototype that later should be ported to VHDL and end up in hardware to check a serial bit-stream.
On the net I found a single bit CRC-16 update step code. Wrote a test-program and it works. Except for one strange thing: I have to feed the bits of a byte from lowest to highest bit. If I do it this way, I get correct results.
In the CCITT definition of CRC-16 the bits should be feed highest bit to lowest bit though. The data-stream that I want to calculate the CRC from comes in this format as well, so my current code is kind of useless for me.
I'm confused. I would have not expected that feeding the bits the wrong way around could work at all.
Question: Why is it possible that a CRC can be written to take the data in two different bit-orders, and how do I transform my single bit update code that it accepts the data MSB first?
For reference, here is the relevant code. Initialization and the final check have been removed to keep the example short:
typedef unsigned char bit;
void update_crc_single_bit (bit * crc, bit data)
{
// update CRC for a single bit:
bit temp[16];
int i;
temp[0] = data ^ crc[15];
temp[1] = crc[0];
temp[2] = crc[1];
temp[3] = crc[2];
temp[4] = crc[3];
temp[5] = data ^ crc[4] ^ crc[15];
temp[6] = crc[5];
temp[7] = crc[6];
temp[8] = crc[7];
temp[9] = crc[8];
temp[10] = crc[9];
temp[11] = crc[10];
temp[12] = data ^ crc[11] ^ crc[15];
temp[13] = crc[12];
temp[14] = crc[13];
temp[15] = crc[14];
for (i=0; i<16; i++)
crc[i] = temp[i];
}
void update_crc_byte (bit * crc, unsigned char data)
{
int j;
// calculate CRC lowest bit first
for (j=0; j<8; j++)
{
bit b = (data>>j)&1;
update_crc_single_bit(crc, b);
}
}
Edit: Since there is some confusion here: I have to compute the CRC bit by bit, and for each byte MSB first. I can't simply store the bits because the code shown above is a prototype for something that will end up in hardware (without memory).
The code shown above generates the correct result if I feed in a bit-stream in the following order (shown is the index of the received bit. Each byte gets transmitted MSB first):
|- first byte -|- second byte -|- third byte
7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,....
I need the single update loop to be transformed that it generates the same CRC using natural order (e.g. as received):
|- first byte -|- second byte -|- third byte
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,....
If you look at the RevEng 16-bit CRC Catalogue, you see that there are two different CRCs called "CCITT", one of which is labeled there "CCITT-False". Somewhere along the way someone got confused about what the CCITT 16-bit CRC was, and that confusion was propagated widely. The two CRCs are described thusly, with the first one (KERMIT) being the true CCITT CRC:
KERMIT
width=16 poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 check=0x2189 name="KERMIT"
and
CRC-16/CCITT-FALSE
width=16 poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1 name="CRC-16/CCITT-FALSE"
You will note that the real one is reflected, and the false one is not, and there is another difference in the initialization. In reflected CRCs, the lowest bit of the data is processed first, so it appears that you are trying to compute the true CCITT CRC.
When the CRC is reflected, so is the order of the bits in the polynomial that is exclusive-ored into the register, so 0x1021 becomes 0x8408. Here is a simple C implementation that you can check against:
#include <stddef.h>
#define POLY 0x8408
unsigned crc16_ccitt(unsigned crc, unsigned char *buf, size_t len)
{
int k;
while (len--) {
crc ^= *buf++;
for (k = 0; k < 8; k++)
crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
}
return crc;
}
I don't know what you mean by "In the CCITT definition of CRC-16 the bits should be feed highest bit to lowest bit though". What definition are you referring to?
In this Altera document, you can see the shift register implementation of the CRC for a hardware implementation. Here is a copy of the diagram:
For your code, you need to reverse your register, temp[], indices. temp[0] is temp[15] and so on.
Update - If you look at:
RevEng 16-bit CRC Catalogue
there's a link to:
Online CRC calculator
The first three labeled as CRC-CCITT operate on data sent or received MSB to LSB using the polynomial 0x11021. The only difference is the starting value:
CRC-CCITT (XModem) - crc initialized to 0x0000, same as prefixing by 0x0000.
CRC-CCITT (0xFFFF) - crc initialized to 0xFFFF, same as prefixing by 0x84CF.
CRC-CCITT (0x1D0F) - crc initialized to 0x1D0F, same as prefixing by 0xFFFF.
So my guess is that you want to use one of these three.
normally, bits are transferred on the line least significant bit first. So, in case you have an array of bytes, first bit is least significant bit of first byte, then comes the next to least significant bit... so up to the most significant bit of the first byte and then comes the least significant bit of the next byte. This is the order of the bits (coefficients) in the polyonomial division you are making. Try my routines at https://github.com/mojadita/crc.git (you have there a table for CRC16-CCITT)

Easy way to convert a string of 0's and 1's into a character? Plain C

I'm doing a steganography project where I read in bytes from a ppm file and add the least significant bit to an array. So once 8 bytes are read in, I would have 8 bits in my array, which should equal some character in a hidden message. Is there an easy way to convert an array of 0's and 1's into an ascii value? For example, the array: char bits[] = {0,1,1,1,0,1,0,0} would equal 't'. Plain C
Thanks for all the answers. I'm gonna give some of these a shot.
A simple for loop would work - something like
unsigned char ascii = 0;
unsigned char i;
for(i = 0; i < 8; i++)
ascii |= (bits[7 - i] << i);
There might be a faster way to do this, but this is a start at least.
I wouldn't store the bits in an array -- I'd OR them with a char.
So you start off with a char value of 0: char bit = 0;
When you get the first bit, OR it with what you have: bit |= bit_just_read;
Keep doing that with each bit, shifting appropriately; i.e., after you get the next bit, do bit |= (next_bit << 1);. And so forth.
After you read your 8 bits, bit will be the appropriate ASCII value, and you can print it out or do whatever with it you want to do.
I agree with mipadi, don't bother storing in an array first, that's kind of pointless. Since you have to loop or otherwise keep track of the array index while reading it in, you might as well do it in one go. Something like this, perhaps?
bits = 0;
for ( i = 0; i < 8; ++i ) {
lsb = get_byte_from_ppm_somehow() & 0x01;
bits <<= 1 | lsb;
}
As long as the bit endian is correct, this should work and compile down pretty small.
If the bit endian is backwards then you should be able to change the initial value of mask to 1, the mask shift to <<= , and you might need to have (0x0ff & mask) as the do{}while conditional if your compiler doesn't do what it's supposed to with byte sized variables.
Don't forget to do something for the magic functions that I included where I didn't know what you wanted or how you did something
#include <stdint.h> // needed for uint8_t
...
uint8_t acc, lsb, mask;
uint8_t buf[SOME_SIZE];
size_t len = 0;
while (is_there_more_ppm_data()) {
acc = 0;
mask = 0x80; // This is the high bit
do {
if (!is_there_more() ) {
// I don't know what you think should happen if you run out on a non-byte boundary
EARLY_END_OF_DATA();
break;
}
lsb = 1 & get_next_ppm_byte();
acc |= lsb ? mask : 0; // You could use an if statement
mask >>= 1;
} while (mask);
buf[len] = acc; // NOTE: I didn't worry about the running off the end of the buff, but you should.
len++;
}

CRC Calculation

I'm trying to interface with a 3rd party system and they have provided a code sample to calculate a CRC value when sending text data.
The C code the vendor provided looks like this:
#define CRCRES 0xf0b8 /* residue for good verify */
#define DEBUG
unsigned crctbl[] = {0x0000, 0x1081, 0x2102, 0x3183,
0x4204, 0x5285, 0x6306, 0x7387,
0x8408, 0x9489, 0xa50a, 0xb58b,
0xc60c, 0xd68d, 0xe70e, 0xf78f};
/*
* This uses a 32 byte table to lookup the crc 4 bits at a time.
* The CRC CCITT is used.
*/
unsigned short calc_crc(unsigned char *ptr, unsigned length)
{
unsigned short crc;
unsigned short i;
unsigned char pos,ch;
crc = 0xffff; /* precondition crc */
for (i = 0; i < length; i++,ptr++) {
ch = *ptr;
pos = (crc ^ ch) & 15;
crc = ((crc >> 4) & 0x0fff) ^ crctbl[pos];
ch >>= 4;
pos = (crc^ch) & 15;
crc = ((crc >> 4) & 0xffff) ^ crctbl[pos];
}
crc = ~crc; /* post condition */
crc = (crc << 8) | (crc >> 8); /* bytewise reverse */
return crc;
}
/*
* tests the block of code containing the crc to verify it's
* content. This compares to the reversed and inverted
* residue.
*/
int test_crc(unsigned char *ptr, unsigned length)
{
unsigned short crc;
unsigned char arr [] = {'X','Y','Z'};
crc = calc_crc(arr,3);
printf("Calced crc of test to be %04x, (should be 470f)\n", crc);
return (crc == 0x470f);
}
I've copied this code and put in a sample C program. The test_crc method is not calculating the CRC to be 470f (its calculating it as DD7A).
I'm hoping someone can either verify that this code doesn't work as the vendor is saying it should or help me get test_crc to return the correct value.
Thanks for the help.
Problem solved. The specs from the vendor were incorrect. The correct checksum for XYZ is DD7A. The documentation was incorrect.
Add that to the fact that on the page before when they explain what data to pass to the calc_crc method to get the crc for an actual message is also incorrect it made it a tricky project.
Thanks for the help.
The calculation, as it goes, don't show any error that comes to my mind. Just review again the algorithm. In particular, looking for possible problems, note that constants being anded in different parts of the algorithm are 0x0fff and 0xffff. Maybe should it be 0x0fff and 0xfff0 to be more symmetric... Sometimes we think the real problem may come from another place, and forget to double check the obvious things... :)
Are the hardware platforms the same? Could it be you have different endianness?
(You have x86 they have 68000 cpu for example.)

Resources