0

I have this code written in C language, Which is representing CRC-16 algorithm using polynom 0x8005, I need to convert that code to PHP, I got stuck at the memcpypgm2ram part, I don't know what that function supposed to do and what's the equivalent to it in PHP. I have done this so far:

C code

    const rom unsigned far int CRC16tbl [ 256 ] = {
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 };

unsigned short addCRC(unsigned short crc, unsigned char dataByte)
{
    unsigned int crc16int;

    memcpypgm2ram(&crc16int, &CRC16tbl[ ( crc & 0xFF ) ^ dataByte ], 2); // Can't get idea behind this line

    return ( ( crc >> 8 ) ^ crc16int ); //neither this line
}

unsigned short crc16_calc(char *pBuffer, unsigned short length)
{
    unsigned short crc16 = 0;

    while (length--)
    crc16 = addCRC( crc16, *pBuffer++);

    return crc16;
}

PHP Code:

    public static function crc16Calc($buffer, $length){
        $crc16 = 0;
        while ($length--) {
            $crc16 = $this->addCRC($crc16, $buffer++);
        }
        return $crc16;
    }
    
    public static function addCRC($crc , $data_byte){
        $crc16;
        // Need some help here 
    }
Furqan S. Mahmoud
  • 1,417
  • 2
  • 13
  • 26

1 Answers1

4

The first line in question does the following:

  1. (crc & 0xFF) zeroes all but the 8 least significant bits of the CRC, effectively truncating it to one byte (i.e. 0xAABB becomes 0xBB).
  2. (...) ^ dataByte takes the XOR (exclusive or) of that with the new data byte.
  3. &CRC16tbl[...] treats the result of the above as an index into the table, and produces a pointer to that location in the table.
  4. The call to memcpypgm2ram copies two bytes starting at the pointer from above into the variable crc16int, effectively assigning to crc16int a value from the table.

From point 4, we can assume that the C environment that the code was written for uses 16-bit integers, and that it has separate memory for code and for data. memcpypgm2ram(a, b, len) can be assumed to copy len bytes from from code space (at pointer b) to data space (at pointer a). Most probably some sort of embedded platform was used to run the code.

  1. Finally, (crc >> 8) ^ crc16int shifts the 16-bit integer 8 places to the right, effectively taking the most significant byte (i.e. 0xAABB becomes 0xAA), then takes the XOR with the value that was read from the table.

In PHP, this could be written as:

// values are integers between 0 and 0xFFFF
$crc16table = array(
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
// ... copy from question ...
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 );

// $crc is an integer between 0 and 0xFFFF
// $dataByte is an integer between 0 and 0xFF
// The result is an integer between 0 and 0xFFFF
function addCRC($crc, $dataByte) {
    global $crc16table;
    $index = ($crc & 0xFF) ^ $dataByte;
    $crc16int = $crc16table[$index];
    return ($crc >> 8) ^ $crc16int;
}

// $buffer is a string containing the binary data
// The result is an integer between 0 and 0xFFFF
function crc16Calc($buffer) {
    $crc16 = 0;
    $length = strlen($buffer);
    for ($i = 0; $i < $length; $i++) {
        // Use ord() to go from a length-1 string to an integer between 0 and 0xFF
        $dataByte = ord($buffer[$i]);
        $crc16 = addCRC($crc16, $dataByte);
    }
    return $crc16;
}

In case you need more explanation on the bitwise operators, it can be found on the PHP website.

Notice also how I changed the iteration in crc16Calc. While in C it may be common to iterate by moving a pointer, PHP does not work that way. Instead, the buffer is passed in as a string with a known length strlen($buffer). *pBuffer++ cannot be directly translated to $buffer++.

rtoijala
  • 1,200
  • 10
  • 20
  • Thanks for your answer, I'm trying it now, Can I use the crc16Calc function to check the validity of a transformed binary data? I should call it and it should return zero if the data is not corrupted, correct? – Furqan S. Mahmoud Jul 25 '20 at 12:39
  • I am not sure what you mean by "transformed binary data". `crc16Calc` will not in general return 0. However, if you append the correct CRC (in Little Endian order) to binary data, the CRC for the resulting buffer will be zero. So if you have data followed by the correct CRC, the computed CRC for the that will be zero. – rtoijala Jul 25 '20 at 12:55
  • `$x = "foo"; $crc = crc16Calc($x); $y = $x . chr($crc & 0xFF) . chr($crc >> 8); $crc2 = crc16Calc($y);` Then `$crc2 == 0`. – rtoijala Jul 25 '20 at 12:57
  • Thanks, My case is that I'm receiving a binary data in a file, each line of the file consists of heard & info, the header has the CRC in it, I need to check the CRC validity for each line, I passed the lines to the crc16Calc and they all gave zeros. https://www.youtube.com/watch?v=iwj8ZgyzqZk In this video, they are explaining CRC, and they said that the device that will receive the data need to ably the same calculations, and if the string is fine, the result must be zero. which will means that the data in the receiver device = the data in the sender device.. – Furqan S. Mahmoud Jul 25 '20 at 13:55
  • please see a similar issue here: https://stackoverflow.com/questions/58393307/verification-of-a-crc-checksum-against-zero – Furqan S. Mahmoud Jul 25 '20 at 14:02
  • I am not very familiar with CRCs. If you have the CRC from the header, and you have the data which it is meant to protect, why not simply pass the data to `crc16Calc` and check that the resulting value is equal to the CRC in the header? – rtoijala Jul 25 '20 at 14:42
  • because I want to follow the standards here, I have read several articles and saw other questions, If you passed the whole data string to the crc16Calc and gave zero, that's means that the data is okay. – Furqan S. Mahmoud Jul 25 '20 at 15:20
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/218586/discussion-between-furqan-s-mahmoud-and-rtoijala). – Furqan S. Mahmoud Jul 25 '20 at 17:40