<?php
class crc{
private $SerialNumber = 1; //自增加
private $SerialNumberXOR = 254; //自减少
function issleep($time = 1){
sleep($time);
}
private $binFile = '';
private $getSocketData = ''; //获取的16进制数据
function setBinFile($str){
$this->binFile .=$str;
}
function getBinFile($str){
$this->binFile .=$str;
//$this->getSocketData .=$str;
}
function CreateSetLogFile($file){
$file = SET_FILE;
if($this->binFile){
$hexstr = str_replace(" ","",$this->binFile);
$data = pack('H*', $hexstr);
file_put_contents($file, $data, true);
}
//因为获取的是16进制 所以直接写入16进制文件
$getfile = GET_FILE;
if($this->getSocketData){
//$hexstr = str_replace(" ","",$this->getSocketData);
//$data = pack('H*', $hexstr);
file_put_contents($getfile, $this->getSocketData, true);
}
}
public $str = array();
function setlog($str){
$this->str[] = $str;
$str = $str."\r\n";
echo iconv('utf-8','gbk//IGNORE',$str);
}
function chaString($string){
$str = '';
for($i=0;$i<strlen($string);$i++){
$str .= $this->getByteData($i, $string);
}
return $str;
}
function getByteData($k,$str){
if($k%2==0){
return " ".$str[$k];
} else {
return $str[$k];
}
}
//字符串转16进制
function strToHex($str){
$hex="";
for($i=0;$i<strlen($str);$i++)
$hex.=dechex(ord($str[$i]));
$hex=strtoupper($hex);
return $hex;
}
//16进制转字符串
function hexToStr($hex){
$str="";
for($i=0;$i<strlen($hex)-1;$i+=2)
$str.=chr(hexdec($hex[$i].$hex[$i+1]));
return $str;
}
function crc16($string) {
$crc = 0xA28C;
for ($x = 0; $x < strlen ($string); $x+=2) {
$sys = '';
if(isset($string[$x]) && isset($string[$x+1])){
$sys = $string[$x].$string[$x+1];
} else {
continue;
}
//echo "sys = ". $sys."\r\n";
$sys = hexdec($sys);
$crc ^= $sys;
for ($y = 0; $y < 8; $y++) {
$lbs = $crc & 0x0001;
$crc >>=1;
if($lbs == 1){
$crc ^= 0x8408;
}
}
}
$crc ^=0xFFFF;
return $crc;
}
private function dechexSerialNumber(){
$str = dechex($this->SerialNumber);
$str = $this->setHeadZero($str);
$this->SerialNumber++;
return $str;
}
private function dechexSerialNumberXOR(){
$str = dechex($this->SerialNumberXOR);
$str = $this->setHeadZero($str);
$this->SerialNumberXOR--;
return $str;
}
//前补0
private function setHeadZero($str,$max = 2){
$leng = strlen($str);
for($i=$leng;$i<$max;$i++){
$str = "0".$str;
}
return $str;
}
//后补0
private function setEndZero($str,$max = 4){
$leng = strlen($str);
for($i=$leng;$i<$max;$i++){
$str = $str."0";
}
return $str;
}
public function getdata($packet){
$data = array();
$data[0] = '6D';
$data[1] = 'AC';
$data[2] = $this->dechexSerialNumber();
$data[3] = $this->dechexSerialNumberXOR();
$packetNum = count($packet); //Packet Length
$packetNum = dechex($packetNum);
$packetNum = $this->setHeadZero($packetNum,4); //因为高字节要在前,比如包长度=10 那么实际就是0010,高低位转换就是10 00
//数据包长度高低位
$data[4] = substr($packetNum, 2,2);
$data[5] = substr($packetNum, 0,2);
//指令开始 协议头
$command = '';
for($i=0;$i<count($data);$i++){
$command = $command.$this->setHeadZero($data[$i])." ";
//$crcString .= $this->setHeadZero($data[$i]);
}
$crcString = '';
//指令内容体
for($i=0;$i<count($packet);$i++){
$command = $command.$this->setHeadZero($packet[$i])." ";
$crcString .= $this->setHeadZero($packet[$i]);
}
$crc = '';
$temp_crc = dechex($this->crc16($crcString));
$sum = strlen($temp_crc);
for($i=$sum;$i<4;$i++){
$temp_crc = "0".$temp_crc;
}
$crc = $temp_crc;
$crc1 = $this->setHeadZero(substr($crc,2,2));
$crc2 = $this->setHeadZero(substr($crc, 0,2));
$command = $command.$crc1. " ".$crc2;
$commandArray = array();
return $command;
}
private function heightlow($readInt){
$byte1 = (($readInt & 0xff));
$byte2 = (($readInt & 0xff00) >> 8);
// 拼装成 "高字节在后,低字节在前"的格式
$realint = ($byte1 & 0xff) << 0 | ($byte2 & 0xff) << 8;
//echo $byte1." = ".$byte2."\r\n";
return $realint;
}
//更新
public function getUpdatePacket(){
$data[0] = 26; //command
$data[1] = 11; //type
//p2-p9
for($i=2;$i<=9;$i++){
$data[$i] = 00;
}
return $data;
}
//握手
public function getHandshake(){
$data[0] = 20; //command
$data[1] = 11; //type
//p2-p9
for($i=2;$i<=9;$i++){
$data[$i] = 00;
}
return $data;
}
private $falshAddress = 64;
private $defaultFalshAddress = 64; //falsh默认的10进制地址
private function getFalshAddress($zizeng = true){
$falshAddress = $this->falshAddress;
if($zizeng == true){
$this->falshAddress = $this->falshAddress+2;
}
return dechex($falshAddress);
}
//跳转到Application
public function runApp(){
$data[0] = 21;
$data[1] = 11;
for($i=2;$i<=9;$i++){
$data[$i] = 00;
}
return $data;
}
//校验falsh
public function checkFalsh($res){
$data[0] = 25;
$data[1] = 12;
//p2-p9
for($i=2;$i<=9;$i++){
$data[$i] = 00;
}
$data[3] = dechex($this->defaultFalshAddress);
//大小 = 224*0x200;
$data[10] = dechex($this->defaultFalshAddress);
$data[11] = 56;
$data[12] = 00;
$data[13] = 00;
//dechex(224*0x200);
return $data;
}
//擦除
public function getRemove(){
$data[0] = 24; //command
$data[1] = 12; //type
//p2-p9
for($i=2;$i<=9;$i++){
$data[$i] = 00;
}
$data[3] = $this->getFalshAddress(false);
//大小 = 224*0x200;
$data[10] = dechex($this->defaultFalshAddress);
$data[11] = 56;
$data[12] = 00;
$data[13] = 00;
//dechex(224*0x200);
return $data;
}
//下载
public function getUpload($arr){
$data[0] = 22; //command
$data[1] = 12; //type
//p2-p9
for($i=2;$i<=9;$i++){
$data[$i] = 00;
}
$data[3] = $this->getFalshAddress(); //dechex();
$array = explode(" ",$arr);
for($i=0;$i<count($array);$i++){
if(!empty($array[$i])){
$data[] = $array[$i];
}
}
return $data;
}
}
使用方式:
$filename = “C:\crc\APP-2020-02-05.bin”;
$host = ‘192.168.1.122’;
$port = 502;
define(“SET_FILE”,’C:\crc\log.log’);
define(“GET_FILE”,’C:\crc\getlog.log’);
require_once ‘crc.php’;
$req = new crc();
$res = bin2hex(file_get_contents($filename));
if (!$res){
$req->setlog(“打开更新文件失败”);
return;
}
$req->setlog(“连接设备中…”);
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($sock, SOL_SOCKET, SO_SNDTIMEO,array(‘sec’ => 1, ‘usec’ => 1));
$result = @socket_connect($sock, $host, $port);
if($result == false){
$req->setlog(“设备连接失败”);
return false;
}
//发送数据
function send($sock,$packets,$crc){
$status = socket_last_error($sock);
if($status!=0){
return false;
}
//记录的数据为字符串,实际发送的时候 重新转换成16进制的数据格式
$t = $packets;
$packets = str_split(str_replace(‘ ‘, ”, $packets), 2); //chr(hexdec($packets));
$packet = null;
for($i=0;$isetBinFile($t);
$res = getrec($sock,$crc);
$crc->getBinFile(bin2hex($res));
$crc->setlog(“接收的16进制数据:”.bin2hex($res));
return true;
}
function getrec($socket,$crc){
$rec = null;
$time = time();
$crc->setlog(“接收数据”);
while (@socket_recv($socket, $rec, 4096, 0)) { //设置接收长度最大值缓冲区
if($time+10setlog(“接收数据超时”);
break;
}
return $rec;
}
return false;
}
//
$req->setlog(“设备连接成功”);
$req->setlog(“更新帧”);
$getUpdatePacket = $req->getUpdatePacket(); //更新的包
$packets = $req->getdata($getUpdatePacket);
$req->setlog($packets);
if(send($sock, $packets,$req) == false){
$req->setlog(“发送数据”.$packets.”失败”);
}
$req->issleep();
$req->setlog(“握手”);
$getHandshake = $req->getHandshake(); //更新的包
$packets = $req->getdata($getHandshake);
$req->setlog($packets);
if(send($sock, $packets,$req) == false){
$req->setlog(“发送数据”.$packets.”失败”);
}
$req->issleep();
$req->setlog(“擦除falsh”);
$getRemove = $req->getRemove();
$packets = $req->getdata($getRemove);
$req->setlog($packets);
if(send($sock, $packets,$req) == false){
$req->setlog(“发送数据”.$packets.”失败”);
}
$req->issleep();
$arr = array();
$head = 0;
$end = 1024;
$length = strlen($res);
while(true){
if($length<=0){ break; } $arr[] = substr($res, $head,$end); $head = ($head+1024); $length = ($length-1024); } for($i=0;$isetlog(“第”.($i+1).”次下载数据”);
$str = $req->chaString($arr[$i]);;
$getUpload = $req->getUpload($str);
$packets = $req->getdata($getUpload);
$req->setlog($packets);
if(send($sock, $packets,$req) == false){
$req->setlog(“发送数据”.$packets.”失败”);
}
$req->issleep();
}
$req->setlog(“校验falsh”);
$checkfalsh = $req->checkFalsh($res);
$packets = $req->getdata($checkfalsh);
$req->setlog($packets);
if(send($sock, $packets,$req) == false){
$req->setlog(“发送数据”.$packets.”失败”);
}
$req->issleep();
$req->setlog(“跳转到Application”);
$runApp = $req->runApp();
$packets = $req->getdata($runApp);
$req->setlog($packets);
if(send($sock, $packets,$req) == false){
$req->setlog(“发送数据”.$packets.”失败”);
}
$req->issleep();
$req->setlog(“执行完成”);
$req->setlog(“创建写入文件”);
$req->CreateSetLogFile(SET_FILE);
关于作者