CRC Maxim / Dallas 1Wire Generation:将Visual Basic转换为PHP

i Need a function that generates the Maxim/Dallas 1-Wire CRC 8bit-Code like this page: http://www.datastat.com/sysadminjournal/maximcrc.cgi

For that problem I found an little Excel Calculator for solution. It works correctly, but I got the Problem to translate it into PHP language.

Original VB Code:

Private Sub ROMCRC_Click()

    Dim InHex, OutBinStr As String
    Dim OutBinArr(1 To 56) As Integer
    Dim OutDec, i, CRC(1 To 8), CRCTemp As Integer

    InHex = Range("ROMByte1").Value & Range("ROMByte2").Value & Range("ROMByte3").Value & Range("ROMByte4").Value & Range("ROMByte5").Value & Range("ROMByte6").Value & Range("ROMByte7").Value
    OutBinStr = HexToBin(InHex)

    ' Convert string to array, LSB = OutBinArr(1)
    For i = 1 To 56
    OutBinArr(57 - i) = Mid$(OutBinStr, i, 1) ' Split(OutBinStr)
    Next i

    'Initialize CRC
    For i = 1 To 8
        CRC(i) = 0
    Next i

    'Calculate CRC
    For i = 1 To 56
        CRCTemp = CRC(1) Xor OutBinArr(i)
        CRC(1) = CRC(2)
        CRC(2) = CRC(3)
        CRC(3) = CRC(4) Xor CRCTemp
        CRC(4) = CRC(5) Xor CRCTemp
        CRC(5) = CRC(6)
        CRC(6) = CRC(7)
        CRC(7) = CRC(8)
        CRC(8) = CRCTemp
    Next i

    DecCRC = BinToDec(CRC)

    Range("ROMCRCValue").Value = DecCRC

End Sub


Private Function HexToBin(hstr)
'convert hex string to binary string
    cnvarr = Array("0000", "0001", "0010", "0011", _
             "0100", "0101", "0110", "0111", "1000", _
             "1001", "1010", "1011", "1100", "1101", _
             "1110", "1111")
    bstr = ""
    For i = 1 To Len(hstr)
        hdgt = Mid(hstr, i, 1)
        cix = CInt("&H" & hdgt)
        bstr = bstr & cnvarr(cix)
    Next
    HexToBin = bstr
End Function

Function BinToDec(bstr)
'convert 8 bit Binary number to Decimal
    Dim j, Out As Integer

    Out = 0
    For j = 1 To 8
        Out = Out + bstr(j) * 2 ^ (j - 1)
    Next j

    BinToDec = Out
End Function

My PHP test code:

protected function HexToBin($hstr) {
    //convert hex string to binary string
    $cnvarr = array(
        '0000',
        '0001',
        '0010',
        '0011',
        '0100',
        '0101',
        '0110',
        '0111',
        '1000',
        '1001',
        '1010',
        '1011',
        '1100',
        '1101',
        '1110',
        '1111'
    );
    $bstr = "";
    for ($i = 1; $i <= strlen($hstr); $i++) {
        $hdgt = substr($hstr, $i, 1);
        $cix = intval($hdgt);
        echo $cix.'|';
        $bstr .= $cnvarr[$cix];
    }
    return $bstr;
}

protected function createHash($data) {
    //$OutBinStr = $this->HexToBin($data);
    $OutBinStr = hex2bin($data);

    $OutBinArr = array();
    $crc = array();

    //Convert string to array, LSB = OutBinArr(1)
    for ($i = 1; $i <= 56; $i++) {
        $OutBinArr[57 - $i] = substr($OutBinStr, $i - 1, 1);
    }

    //initialize crc
    for ($i = 1; $i <= 8; $i++) {
        $crc[$i] = 0;
    }

    // calculate
    for ($i = 1; $i <= 56; $i++) {

        $CRCTemp = $crc[1] ^ $OutBinArr[$i];
        $crc[1] = $crc[2];
        $crc[2] = $crc[3];
        $crc[3] = $crc[4] ^ $CRCTemp;
        $crc[4] = $crc[5] ^ $CRCTemp;
        $crc[5] = $crc[6];
        $crc[6] = $crc[7];
        $crc[7] = $crc[8];
        $crc[8] = $CRCTemp;
    }

    return implode('', $crc);
}

Example call:

$buttonId = '0000145D6E0F01';
echo $this->createHash($buttonId);

I thank you if you have any Ideas why the Script does not generate the correct crc.

Thank you, nice regards Michael

Your HexToBin() was generating wrong string. The for loop for substr() started with 1 instead of 0. See substr manual.

Imploding $crc resulted an reverse bit order value.

<?PHP    
function HexToBin($hstr){
    $hstr = str_replace(' ','',$hstr);
    $hArr = str_split($hstr);
    $bstr = "";
    foreach($hArr AS $c){
        $cix = sprintf("0x0{$c}");
        // echo sprintf("%04b|",hexdec($cix));
        $bstr .= sprintf("%04b",hexdec($cix));
    }

    return $bstr;
}

function createHash($data){
    $OutBinStr = HexToBin($data);
    $crc = array_fill(0,8,0);
    $OutBinArr = array_reverse(str_split($OutBinStr));

    // calculate
    foreach($OutBinArr AS $i){
        $CRCTemp = $crc[0] ^ $i;
        $crc[0] = $crc[1];
        $crc[1] = $crc[2];
        $crc[2] = $crc[3] ^ $CRCTemp;
        $crc[3] = $crc[4] ^ $CRCTemp;
        $crc[4] = $crc[5];
        $crc[5] = $crc[6];
        $crc[6] = $crc[7];
        $crc[7] = $CRCTemp;
    }
    $crc = array_reverse($crc);
    return implode('', $crc);
}

$buttonId = '00 00 14 5D 6E 0F 01';     // 59 => 3B
// $buttonId = '12 AA 12 5F 14 A2 12 12';   // 109 => 6D
$crc = bindec(createHash($buttonId));
printf("
%d => %X",$crc,$crc);
?>