2

I am trying to convert a C function to PHP that does 8 bit CRC calculation.

The original C code:

uint8_t CRCCalc (uint8_t* pointer, uint16_t len) {

    uint8_t CRC = 0x00;

    uint16_t tmp;

    while(len > 0) {

        tmp = CRC << 1;

        tmp += *pointer;

        CRC = (tmp & 0xFF) + (tmp >> 8);

        pointer++;

        --len;

    }

    return CRC;

}

The PHP code that I have come up with is:

function crc8_calc($hex_string)
{
    $bin_data = pack('H*',$hex_string);
    $bin_length = strlen($bin_data);

    $CRC    =   0x00;
    $pos    =   0;

    while($bin_length>0)
    {
        //$pos = $CRC << 1;

        $CRC = ($bin_data[$pos] & 0xFF) + ($bin_data[$pos] >> 8);
        $bin_length --;
        $pos++ ;
    }

    return $CRC;
}

There is something that is missing as the results from the PHP functions are not correct. I am not very familiar with C, so not sure if my conversion is correct. The C function gives out the correct CRC

For example, if the hex representation of the string is: 280500000805151001240000000010017475260004041001372068828503000000000000

The CRC should be D4.

I have already seen the following links for CRC8 calculation, but I seem to missing something

how to generate 8bit crc in php CRC8-Check in PHP

I have taken some bits of my conversion code from this answer too Convert C to PHP for CRC16 Function

Community
  • 1
  • 1
Amitabh Kant
  • 145
  • 2
  • 6
  • Why don't you try and translate the C code *exactly*? Note that the C code is working on a *16-bit* variable `tmp`. Why did you omit the `<<` shift operation? Note also that `tmp += *pointer;` means `tmp = tmp + *pointer` and *not* `tmp = *pointer`. – JimmyB May 11 '15 at 12:02
  • the C - code in your example does not compile. – specializt May 11 '15 at 12:07
  • @specializt Because of the typo in `Pointer++`? – JeremyP May 11 '15 at 12:15
  • The shift operator got commented out by mistake. JeremyP has already corrected the typo in C code. Thanks – Amitabh Kant May 11 '15 at 12:44

3 Answers3

3

It's obvious that the two code fragments don't do the same thing. In the C function, the first thing that happens is you shift the CRC (that you've calculated so far) left by 1 bit (same as multiplying it by 2), then you add the next byte from the array, then you recalculate the CRC by adding the two bytes of tmp together.

Your PHP example doesn't do the initial shift, or mix in the previous version of the CRC into the calculation for the next byte..

JeremyP
  • 84,577
  • 15
  • 123
  • 161
2

Try it like this:

function crc8_calc($hex_string)
{
    $bin_data = pack('H*',$hex_string);
    $bin_length = strlen($bin_data);

    $CRC = 0;
    $tmp = 0;
    $pos = 0;

    while($bin_length>0)
    {
        $tmp = $CRC << 1;
        $tmp = $tmp + ord($bin_data[$pos]); //Added ord

        $CRC = ($tmp + ($tmp >> 8)) & 0xFF;
        $bin_length --;
        $pos++ ;
    }
    return $CRC;
}
Amitabh Kant
  • 145
  • 2
  • 6
JimmyB
  • 12,101
  • 2
  • 28
  • 44
  • No, I beat *you* by 13 seconds! :o) – JimmyB May 11 '15 at 12:08
  • I beat you both by minutes :-) . @Misunderstood has a mistake in his/her code. – JeremyP May 11 '15 at 12:09
  • @JeremyP He, has not slept yet, been up all night. I did not know what was being passed by reference. so I called it value. – Misunderstood May 11 '15 at 12:12
  • There's also a bug in this answer. You need this `$CRC = (($tmp & 0xFF) + ($tmp >> 8)) & 0xFF;` – JeremyP May 11 '15 at 12:13
  • Not sure if it actually makes a difference (unless `$CRC` would overflow at some point), but I'll edit it in. – JimmyB May 11 '15 at 12:15
  • @Misunderstood It makes a difference because CRC in the C example is only 8 bits so you lose the overflow bits from tmp. In the code above, the overflow bits could cause $CRC to get bigger and bigger with the right sequence of bytes in the input. – JeremyP May 11 '15 at 12:19
  • @HannoBinder Looking at it now, you don't need the original mask `$CRC = ($tmp + ($tmp >> 8)) & 0xFF;` – JeremyP May 11 '15 at 12:21
  • @HannoBinder The PHP function does not output the same values as the C function. If I use the C function on the example string **280500000805151001240000000010017475260004041001372068828503000000000000** , I get **D4** , but if I use the php function, I get **38** . – Amitabh Kant May 11 '15 at 13:03
  • Are you sure you're giving the same binary data to both functions? Check to see if `2*strlen($bin_data)` equals `strlen($hex_string)` (-> "word size"), and maybe verify that `$bindata[1]` is the same value as `*(pointer+1)` in C (-> "endianness"). – JimmyB May 11 '15 at 14:15
  • @HannoBinder Yes, the length in PHP is same. 2*strlen($bin_data) equals strlen($hex_string) . Just a small matter though, I initialized `code`$pos = 0`code` , which I hope is ok. I am not very conversant in C on how to do it. But this is how the complete code in C which compiles and works with the right value. – Amitabh Kant May 11 '15 at 17:09
  • Finally was able to get it working. The only change was to get the ascii value from $bin_data . `$tmp = $tmp + ord($bin_data[$pos]);` I have updated your code for the correct answer. Thanks for the help – Amitabh Kant May 12 '15 at 05:56
0

($tmp & 0xFF) just lower byte

($tmp >> 8) shift right 8

I have not tested, but this is a quick attempt.

function CRCCalc ($value, $len) {
    $CRC = 0;
    while($len > 0) {
        $tmp = $CRC << 1;  // shift left 1
        $tmp += $value;
        $CRC = ($tmp & 0xFF) + ($tmp >> 8); //  ($tmp & 0xFF) just lower byte    ($tmp >> 8: shift right 8
        $value++;
        $len--;
    }
    return $CRC;
}
Misunderstood
  • 5,534
  • 1
  • 18
  • 25
  • What is `$value`? Why are you adding it directly to the CRC and then incrementing it? It should be an array or a pointer and you add what it's pointing to to the CRC – JeremyP May 11 '15 at 12:08