php對接電信平臺,對接lot裝置傳送or接收資料(一)

wavebossy6666發表於2021-04-01

程式碼備份錄
1、大端模式單通道(10位編碼版)
2、crc16位校驗
3、16進位制轉float

直接上程式碼

trait tcp_V1_3Traits{

    /***
     * 16進位制轉float
     * @param $strHex
     * @return float|int
     */
    public function hexTo32Float($strHex) {
        $v = hexdec($strHex);
        $x = ($v & ((1 << 23) - 1)) + (1 << 23) * ($v >> 31 | 1);
        $exp = ($v >> 23 & 0xFF) - 127;
        return $x * pow(2, $exp - 23);
    }

    /**
     * 將一個字元按位元位進行反轉 eg: 65 (01000001) --> 130(10000010)
     * @param $char
     * @return string $char
     */
    private function reverseChar($char) {
        $byte = ord($char);
        $tmp = 0;
        for ($i = 0; $i < 8; ++$i) {
            if ($byte & (1 << $i)) {
                $tmp |= (1 << (7 - $i));
            }
        }
        return chr($tmp);
    }

    /**
     * 將一個位元組流按位元位反轉 eg: 'AB'(01000001 01000010)  --> '\x42\x82'(01000010 10000010)
     * @param $str
     * @return mixed
     */
    private function reverseString($str) {
        $m = 0;
        $n = strlen($str) - 1;
        while ($m <= $n) {
            if ($m == $n) {
                $str{$m} = $this->reverseChar($str{$m});
                break;
            }
            $ord1 = $this->reverseChar($str{$m});
            $ord2 = $this->reverseChar($str{$n});
            $str{$m} = $ord2;
            $str{$n} = $ord1;
            $m++;
            $n--;
        }
        return $str;
    }

    /**
     * @param string $str 待校驗字串
     * @param int $polynomial 二項式
     * @param int $initValue 初始值
     * @param int $xOrValue 輸出結果前異或的值
     * @param bool $inputReverse 輸入字串是否每個位元組按位元位反轉
     * @param bool $outputReverse 輸出是否整體按位元位反轉
     * @return int
     */
    public function crc16($str, $polynomial, $initValue, $xOrValue, $inputReverse = false, $outputReverse = false) {
        $crc = $initValue;

        for ($i = 0; $i < strlen($str); $i++) {
            if ($inputReverse) {
                // 輸入資料每個位元組按位元位逆轉
                $c = ord($this->reverseChar($str{$i}));
            } else {
                $c = ord($str{$i});
            }
            $crc ^= ($c << 8);
            for ($j = 0; $j < 8; ++$j) {
                if ($crc & 0x8000) {
                    $crc = (($crc << 1) & 0xffff) ^ $polynomial;
                } else {
                    $crc = ($crc << 1) & 0xffff;
                }
            }
        }
        if ($outputReverse) {
            // 把低地址存低位,即採用小端法將整數轉換為字串
            $ret = pack('cc', $crc & 0xff, ($crc >> 8) & 0xff);
            // 輸出結果按位元位逆轉整個字串
            $ret = $this->reverseString($ret);
            // 再把結果按小端法重新轉換成整數
            $arr = unpack('vshort', $ret);
            $crc = $arr['short'];
        }
        return $crc ^ $xOrValue;
    }
}

使用方式

$crc = $this->crc16(hex2bin("你要檢驗的值"), 0x8005, 0xffff, 0, true, true);
// 將你要檢驗的值去和資料返回的crc進行校驗,來確保資料沒有被篡改

關於本次使用的crc模式【CRC-16/MODBUS】

CRC-16/CCITT:除數選定為 0x1021,初始值為0,最終結果輸出前異或0,輸入的每個位元組按位元位反轉,結果在最終異或前按位元位反轉

CRC-16/MODBUS:除數選定為 0x8005,初始值為 0xffff,最終結果輸出前異或0, 輸入的每個位元組按位元位反轉,結果在最終異或前按位元位反轉。

心得記錄

以往都是做api介面,這是第一次使用php除錯物聯網的裝置,裡面資料互動都是採用16進位制進行換算
比如對方文件寫的1個位元組,實際上對應的是兩位長度的字串01 ; 反向傳送資料需要用函式補齊位數 如你要傳送已知1個位元組的01,要使用 sprintf("%02s", 1) 去拼接資料得到01 

暫時先寫到這吧,tcp模式給裝置傳送接收資料等下一回附上

更多crc使用參考這

本作品採用《CC 協議》,轉載必須註明作者和本文連結
朝著夢,踏平坎坷

相關文章