Jwgps.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. <?php
  2. namespace Workerman\Protocols;
  3. class Jwgps {
  4. public static function bin2str( $hex, $space ){
  5. $data = unpack("C*chars",$hex);
  6. $bin = '';
  7. foreach($data as $key=>$value){
  8. $bin .= sprintf('%02X',$value);
  9. if($space)
  10. $bin .= ' ';
  11. }
  12. return trim($bin);
  13. }
  14. private static function packValue( $value ){
  15. if($value['cmd'] == 0x81){//登录后响应
  16. return pack('C1C1C1N1',$value['version'],$value['cmd'],$value['result'],time());
  17. }
  18. elseif($value['cmd'] == 0x82){//定位数据上报后响应
  19. return pack('C1C1',$value['version'],$value['cmd']);
  20. }elseif($value['cmd'] == 0x83){//心跳上报后响应
  21. return pack('C1C1C1',$value['version'],$value['cmd'],$value['result']);
  22. }elseif($value['cmd'] == 0x04){//下发远程控制数据
  23. return pack('C1C1C1H10H10',$value['version'],$value['cmd'],$value['type'],$value['tid'],$value['msgid']);
  24. }elseif($value['cmd'] == 0x94){//下发远程控制数据后,二次下发应答
  25. return pack('C1C1C1',$value['version'],$value['cmd'],$value['result']);
  26. }elseif($value['cmd'] == 0x05){//下发远程查询参数
  27. $bin = pack('C1C1C1H10H10',$value['version'],$value['cmd'],$value['type'],$value['tid'],$value['msgid']);
  28. /*
  29. $data = unpack("C*chars",$bin);
  30. $hex = '';
  31. foreach($data as $key=>$value){
  32. $hex .= sprintf('%02X',$value);
  33. if($space)
  34. $hex .= ' ';
  35. }
  36. echo 'pack_hex:'.$hex.PHP_EOL;
  37. */
  38. return $bin;
  39. //return pack('C1C1C1H10H10',$value['version'],$value['cmd'],$value['type'],$value['tid'],$value['msgid']);
  40. }elseif($value['cmd'] == 0x06){//下发远程设置参数
  41. //设置域名及端口时,指令值是32字节(域名)+2字节(端口号)
  42. if($value['type'] == 0xC){
  43. return pack('C1C1C1a32n1H10H10',$value['version'],$value['cmd'],$value['type'],$value['domain'],$value['port'],$value['tid'],$value['msgid']);
  44. }
  45. return pack('C1C1C1v1H10H10',$value['version'],$value['cmd'],$value['type'],$value['code'],$value['tid'],$value['msgid']);
  46. }
  47. /*
  48. if($value['cmd'] == 0x01){//登录后响应
  49. return pack('C1C1C1H*',$value['type'],$value['cmd'],$value['result'],$value['time']);
  50. }
  51. elseif($value['cmd'] == 0x02){//运动上报后响应
  52. return pack('C1C1H*',$value['type'],$value['cmd'],$value['ext']);
  53. }
  54. elseif($value['cmd'] == 0x03){//静止上报后响应
  55. return pack('C1C1C1H*',$value['type'],$value['cmd'],$value['alarm_status'],$value['ext']);
  56. }
  57. elseif($value['cmd'] == 0x04){//测试上报后响应
  58. return pack('C1C1C1',$value['type'],$value['cmd'],$value['result']);
  59. }
  60. elseif($value['cmd'] == 0x05){//配置下发
  61. return pack('C1C1C1C1C1',$value['type'],$value['cmd'],$value['vibrate_time'],$value['vibrate_count'],$value['report_time']);
  62. }
  63. elseif($value['cmd'] == 0x07){//重启或恢复出厂设置
  64. return pack('C1C1C1',$value['type'],$value['cmd'],$value['reset']);
  65. }
  66. elseif($value['cmd'] == 0x08){//开锁
  67. return pack('C1C1C1',$value['type'],$value['cmd'],$value['unlock']);
  68. }
  69. elseif($value['cmd'] == 0x09){//锁状态上报响应
  70. return pack('C1C1',$value['cmd'],$value['lock_status']);
  71. }
  72. */
  73. else{
  74. return false;
  75. }
  76. }
  77. private static function unpackValue( $cmd, $value, $length ){
  78. if($length != strlen($value)){
  79. return null;
  80. }
  81. if($cmd == 0x01){ //gps设备登录
  82. //解析时间
  83. //$info = unpack('C1version/C1cmd/N1time/H10tid/H16imei/H16imsi/a20iccid',$value);
  84. $info = unpack('C1version/C1cmd/N1time/H10tid/H16imei/H16imsi',$value);
  85. return array(
  86. 'version' => $info['version'],//版本号
  87. 'cmd' => $info['cmd'],//功能码
  88. 'time' => $info['time'],//时间戳
  89. 'tid' => $info['tid'],//终端id
  90. 'imei' => $info['imei'],
  91. 'imsi' => $info['imsi'],
  92. //'iccid' => $info['iccid'],//sim卡卡号(20字节字符)
  93. );
  94. }
  95. elseif($cmd == 0x02){ //运动中/静止时数据上报
  96. $info = unpack('C1version/C1cmd/H10tid/N1time/nlng1/nlng2/nlat1/nlat2/n1altitude/n1max_speed/C1state/H4lac/H4cid/C1gps_satellite_count/C1gsm_rssi/n1main_bettery_voltage/C1spare_bettery_voltage/C1lock',$value);
  97. //经纬度解析
  98. $lat_a = floor($info['lat1']/100);
  99. $lat_b = (($info['lat1'] - $lat_a*100).'.'.sprintf("%04d",$info['lat2']) )/60;
  100. $lat = $lat_a + $lat_b;
  101. $lng_a = floor($info['lng1']/100);
  102. $lng_b = (($info['lng1'] - $lng_a*100).'.'.sprintf("%04d",$info['lng2']) )/60;
  103. $lng = $lng_a + $lng_b;
  104. return array(
  105. 'version' => $info['version'],//版本号
  106. 'cmd' => $info['cmd'],//功能码
  107. 'tid' => $info['tid'],//终端id
  108. 'time' => $info['time'],//时间戳
  109. 'lat' => $lat,
  110. 'lng' => $lng,
  111. 'altitude' => $info['altitude'], //海拔
  112. 'max_speed' => $info['max_speed']/10,//gps在十秒内的最大速度,换算后单位: km/h
  113. 'status_hex' => self::bin2str(substr($value,23,1), false),//车辆状态
  114. 'state' => $info['state'],//车辆状态
  115. 'lac' => $info['lac'],
  116. 'cid' => $info['cid'],
  117. 'gps_satellite_count' => $info['gps_satellite_count'],//gps卫星颗数
  118. 'gsm_rssi_hex' => self::bin2str(substr($value,29,1), false),
  119. 'gsm_rssi' => $info['gsm_rssi'],
  120. 'main_bettery_voltage' => $info['main_bettery_voltage']/10, //主电池电压
  121. 'spare_bettery_voltage' => $info['spare_bettery_voltage'], //备用电池电压
  122. 'lock' => $info['lock'] //车辆开关状态 0-关锁 1-开锁
  123. );
  124. }
  125. elseif($cmd == 0x03){ //心跳信息
  126. $info = unpack('C1version/C1cmd/H10tid/n1main_bettery_voltage/C1spare_bettery_voltage',$value);
  127. return array(
  128. 'version' => $info['version'],//版本号
  129. 'cmd' => $info['cmd'],//功能码
  130. 'tid' => $info['tid'],//终端id
  131. 'main_bettery_voltage' => $info['main_bettery_voltage']/10, //主电池电压
  132. 'spare_bettery_voltage' => $info['spare_bettery_voltage'], //备用电池电压
  133. );
  134. }elseif($cmd == 0x04){ //指定一个设备,下发控制指令(转发服务端下发指令)
  135. $info = unpack('C1version/C1cmd/C1type/H10tid/H10msgid',$value);
  136. return array(
  137. "version" => $info['version'],
  138. "cmd" => $info['cmd'],
  139. "type" => $info['type'],
  140. "tid" => $info['tid'],
  141. "msgid" => $info['msgid']
  142. );
  143. }elseif($cmd == 0x05){ //下发查询指令(转发服务端下发指令)
  144. $info = unpack('C1version/C1cmd/C1type/H10tid/H10msgid',$value);
  145. return array(
  146. "version" => $info['version'],
  147. "cmd" => $info['cmd'],
  148. "type" => $info['type'],
  149. "tid" => $info['tid'],
  150. "msgid" => $info['msgid']
  151. );
  152. }elseif($cmd == 0x06){ //下发设置指令(转发服务端下发指令)
  153. $type = ord(substr($value, 2, 1));
  154. if($type == 0x0C){ //设置域名和端口
  155. $info = unpack('C1version/C1cmd/C1type/a32domain/n1port/H10tid/H10msgid',$value);
  156. return array(
  157. "version" => $info['version'],
  158. "cmd" => $info['cmd'],
  159. "type" => $info['type'],
  160. "domain" => $info['domain'],
  161. "port" => $info['port'],
  162. "tid" => $info['tid'],
  163. "msgid" => $info['msgid']
  164. );
  165. }
  166. $info = unpack('C1version/C1cmd/C1type/v1code/H10tid/H10msgid',$value);
  167. return array(
  168. "version" => $info['version'],
  169. "cmd" => $info['cmd'],
  170. "type" => $info['type'],
  171. "code" => $info['code'],
  172. "tid" => $info['tid'],
  173. "msgid" => $info['msgid']
  174. );
  175. }elseif($cmd == 0x84){ //服务端下发远程控制后gps应答
  176. $info = unpack('C1version/C1cmd/C1result/H10tid/H10msgid',$value);
  177. return array(
  178. 'version' => $info['version'],//版本号
  179. 'cmd' => $info['cmd'],//功能码
  180. 'tid' => $info['tid'],//终端id
  181. 'result' => $info['result'],//执行结果 0x00:失败 0x01:成功 0x02:运动中 0x03:外接电源不在位
  182. "msgid" => $info['msgid']
  183. );
  184. }elseif($cmd == 0x85){ //远程查询后终端上报
  185. $type = ord(substr($value, 2, 1));
  186. if($type == 0x05){ //查询电压终端响应结果
  187. $info = unpack('C1version/C1cmd/C1type/H10tid/H10msgid/n1result',$value);
  188. return array(
  189. 'version' => $info['version'],//版本号
  190. 'cmd' => $info['cmd'],//功能码
  191. 'type' => $info['type'], //应答指令
  192. 'tid' => $info['tid'],//终端id
  193. "msgid" => $info['msgid'],
  194. 'result' => $info['result']/10 //应答结果:电压要除以10
  195. );
  196. }elseif($type == 0x06){ //查询经纬度终端响应结果
  197. $info = unpack('C1version/C1cmd/C1type/H10tid/H10msgid/nlng1/nlng2/nlat1/nlat2',$value);
  198. //经纬度解析
  199. $lat_a = floor($info['lat1']/100);
  200. $lat_b = (($info['lat1'] - $lat_a*100).'.'.sprintf("%04d",$info['lat2']) )/60;
  201. $lat = $lat_a + $lat_b;
  202. $lng_a = floor($info['lng1']/100);
  203. $lng_b = (($info['lng1'] - $lng_a*100).'.'.sprintf("%04d",$info['lng2']) )/60;
  204. $lng = $lng_a + $lng_b;
  205. return array(
  206. 'version' => $info['version'],//版本号
  207. 'cmd' => $info['cmd'],//功能码
  208. 'type' => $info['type'], //应答指令
  209. 'tid' => $info['tid'],//终端id
  210. "msgid" => $info['msgid'],
  211. 'lat' => $lat, //纬度
  212. 'lng' => $lng //经度
  213. );
  214. }else{
  215. return $value;
  216. }
  217. }elseif($cmd == 0x86){ //远程设置下发后终端上报
  218. $info = unpack('C1version/C1cmd/C1type/C1result/H10tid/H10msgid',$value);
  219. return array(
  220. 'version' => $info['version'],//版本号
  221. 'cmd' => $info['cmd'],//功能码
  222. 'type' => $info['type'],//指令类型
  223. 'result' => $info['result'],//指令值
  224. 'tid' => $info['tid'],//终端id
  225. "msgid" => $info['msgid'],
  226. );
  227. }
  228. return $value;
  229. }
  230. private static function unpackValue_old( $cmd, $value, $length ){
  231. if($length != strlen($value)){
  232. return null;
  233. }
  234. if($cmd == 0x01){ //gps设备登录
  235. //解析时间
  236. $year = Ord(substr($value,2,1))+2000;
  237. $month = Ord(substr($value,3,1));
  238. $day = Ord(substr($value,4,1));
  239. $hour = Ord(substr($value,5,1));
  240. $minute = Ord(substr($value,6,1));
  241. $second = Ord(substr($value,7,1));
  242. $time = sprintf("%d-%02d-%02d %02d:%02d:%02d",$year ,$month, $day, $hour, $minute, $second);
  243. return array(
  244. 'type' => self::bin2str(substr($value,0,1), false) ,
  245. 'cmd' => self::bin2str(substr($value,1,1), false),//功能码
  246. 'time' => $time,
  247. 'code' => self::bin2str(substr($value,8,2), false),//产品代码
  248. 'version' => self::bin2str(substr($value,10,1), false),
  249. 'imei' => self::bin2str(substr($value,11,8), false),
  250. 'imsi' => self::bin2str(substr($value,19,8), false),
  251. 'ext' => self::bin2str(substr($value,27,$length-27), false)
  252. );
  253. }
  254. elseif($cmd == 0x02){ //运动时数据上报
  255. //解析时间
  256. $year = Ord(substr($value,2,1))+2000;
  257. $month = Ord(substr($value,3,1));
  258. $day = Ord(substr($value,4,1));
  259. $hour = Ord(substr($value,5,1));
  260. $minute = Ord(substr($value,6,1));
  261. $second = Ord(substr($value,7,1));
  262. $time = sprintf("%d-%02d-%02d %02d:%02d:%02d",$year ,$month, $day, $hour, $minute, $second);
  263. //解析最大速度
  264. $max_speed = unpack('n1',substr($value,8,2));
  265. //经纬度解析
  266. $lng1 = unpack('nlng1',substr($value,15,2));
  267. $lng2 = unpack('nlng2',substr($value,17,2));
  268. $lng = $lng1['lng1'].'.'.sprintf("%04d",$lng2['lng2']);
  269. $lat1 = unpack('nlat1',substr($value,19,2));
  270. $lat2 = unpack('nlat2',substr($value,21,2));
  271. $lat = $lat1['lat1'].'.'.sprintf("%04d",$lat2['lat2']);
  272. //解析x,y,z加速度
  273. $x_max_acc = unpack('n1',substr($value,24,2));
  274. $y_max_acc = unpack('n1',substr($value,26,2));
  275. $z_max_acc = unpack('n1',substr($value,28,2));
  276. //解析海拔高度
  277. $altitude = unpack('n1',substr($value,30,2));
  278. return array(
  279. 'type' => self::bin2str(substr($value,0,1), false) ,
  280. 'cmd' => self::bin2str(substr($value,1,1), false),//功能码
  281. 'time' => $time,
  282. 'max_speed' => $max_speed[1]/10,
  283. 'error_code' => self::bin2str(substr($value,10,1), false),//故障代码
  284. 'lac' => self::bin2str(substr($value,11,2), false),
  285. 'cid' => self::bin2str(substr($value,13,2), false),
  286. 'lng' => $lng,
  287. 'lat' => $lat,
  288. 'status' => self::bin2str(substr($value,23,1), false),
  289. 'x_max_acc' => $x_max_acc[1],
  290. 'y_max_acc' => $y_max_acc[1],
  291. 'z_max_acc' => $z_max_acc[1],
  292. 'altitude' => $altitude[1], //海拔
  293. 'voltage' => Ord(substr($value,32,1))/10, //备用电池电压
  294. 'gps_satellite_count' => Ord(substr($value,33,1)),//gps卫星颗数
  295. 'gsm_rssi' => Ord(substr($value,34,1)),
  296. 'ext' => self::bin2str(substr($value, 35, $length-35), false), //扩展字节
  297. );
  298. }
  299. elseif($cmd == 0x03){ //静止时数据上报
  300. //解析时间
  301. $year = Ord(substr($value,2,1))+2000;
  302. $month = Ord(substr($value,3,1));
  303. $day = Ord(substr($value,4,1));
  304. $hour = Ord(substr($value,5,1));
  305. $minute = Ord(substr($value,6,1));
  306. $second = Ord(substr($value,7,1));
  307. $time = sprintf("%d-%02d-%02d %02d:%02d:%02d",$year ,$month, $day, $hour, $minute, $second);
  308. //解析最大速度
  309. $max_speed = unpack('n1',substr($value,8,2));
  310. //经纬度解析
  311. $lng1 = unpack('nlng1',substr($value,15,2));
  312. $lng2 = unpack('nlng2',substr($value,17,2));
  313. $lng = $lng1['lng1'].'.'.sprintf("%04d",$lng2['lng2']);
  314. $lat1 = unpack('nlat1',substr($value,19,2));
  315. $lat2 = unpack('nlat2',substr($value,21,2));
  316. $lat = $lat1['lat1'].'.'.sprintf("%04d",$lat2['lat2']);
  317. //解析x,y,z加速度
  318. $x_max_acc = unpack('n1',substr($value,24,2));
  319. $y_max_acc = unpack('n1',substr($value,26,2));
  320. $z_max_acc = unpack('n1',substr($value,28,2));
  321. //解析海拔高度
  322. $altitude = unpack('n1',substr($value,30,2));
  323. return array(
  324. 'type' => self::bin2str(substr($value,0,1), false) ,
  325. 'cmd' => self::bin2str(substr($value,1,1), false),//功能码
  326. 'time' => $time,
  327. 'max_speed' => $max_speed[1]/10,
  328. 'error_code' => self::bin2str(substr($value,10,1), false),//故障代码
  329. 'lac' => self::bin2str(substr($value,11,2), false),
  330. 'cid' => self::bin2str(substr($value,13,2), false),
  331. 'lng' => $lng,
  332. 'lat' => $lat,
  333. 'status' => self::bin2str(substr($value,23,1), false),
  334. 'x_max_acc' => $x_max_acc[1],
  335. 'y_max_acc' => $y_max_acc[1],
  336. 'z_max_acc' => $z_max_acc[1],
  337. 'altitude' => $altitude[1], //海拔
  338. 'voltage' => Ord(substr($value,32,1))/10, //备用电池电压
  339. 'gps_satellite_count' => Ord(substr($value,33,1)),//gps卫星颗数
  340. 'gsm_rssi' => Ord(substr($value,34,1)),
  341. 'ext' => self::bin2str(substr($value, 35, $length-35), false), //扩展字节
  342. );
  343. }elseif($cmd == 0x04){ //测试
  344. //解析时间
  345. $year = Ord(substr($value,2,1))+2000;
  346. $month = Ord(substr($value,3,1));
  347. $day = Ord(substr($value,4,1));
  348. $hour = Ord(substr($value,5,1));
  349. $minute = Ord(substr($value,6,1));
  350. $second = Ord(substr($value,7,1));
  351. $time = sprintf("%d-%02d-%02d %02d:%02d:%02d",$year ,$month, $day, $hour, $minute, $second);
  352. return array(
  353. 'type' => self::bin2str(substr($value,0,1), false) ,
  354. 'cmd' => self::bin2str(substr($value,1,1), false),//功能码
  355. 'time' => $time,
  356. 'ext' => self::bin2str(substr($value, 8, $length-8), false), //扩展字节
  357. );
  358. }elseif($cmd == 0x05){ //配置下发后响应
  359. return array(
  360. 'type' => self::bin2str(substr($value,0,1), false) ,
  361. 'cmd' => self::bin2str(substr($value,1,1), false),//功能码
  362. 'resp' => self::bin2str(substr($value,2,1), false),//应答字 0x00-成功 0x01-失败
  363. );
  364. }elseif($cmd == 0x05){ //重启或恢复出厂设置后响应
  365. return array(
  366. 'type' => self::bin2str(substr($value,0,1), false) ,
  367. 'cmd' => self::bin2str(substr($value,1,1), false),//功能码
  368. 'resp' => self::bin2str(substr($value,2,1), false),//应答字 0x00-成功 0x01-失败
  369. );
  370. }elseif($cmd == 0x08){ //开锁下发后响应
  371. return array(
  372. 'type' => self::bin2str(substr($value,0,1), false) ,
  373. 'cmd' => self::bin2str(substr($value,1,1), false),//功能码
  374. 'resp' => self::bin2str(substr($value,2,1), false),//应答字 0x00-成功 0x01-失败
  375. );
  376. }elseif($cmd == 0x09){ //锁状态请求
  377. return array(
  378. 'type' => self::bin2str(substr($value,0,1), false) ,
  379. 'cmd' => self::bin2str(substr($value,1,1), false),//功能码
  380. 'req' => self::bin2str(substr($value,2,1), false),//状态字 0x00-开启 0x01-关闭
  381. );
  382. }
  383. return $value;
  384. }
  385. public static function crc8( $ptr ){
  386. $crc = 0;
  387. $len = strlen($ptr);
  388. echo 'crc8_len:'.$len.PHP_EOL;
  389. $j = 0;
  390. while($len--)
  391. {
  392. //$crc ^= ord(substr($ptr,$j,1));
  393. $chr = ord($ptr[$j]);
  394. //echo '$chr:'.$chr.PHP_EOL;
  395. //echo '$crc:'.$crc.PHP_EOL;
  396. $crc ^= $chr;
  397. //echo '$crc ^= $chr:'.$crc.PHP_EOL;
  398. if($crc>=256){
  399. $crc %= 256;
  400. }
  401. $j++;
  402. for($i = 0;$i < 8;$i++){
  403. //echo '$crc & 0x80:'. ($crc & 0x80) .PHP_EOL;
  404. if($crc & 0x80){
  405. //echo '$crc << 1:'.($crc << 1) .PHP_EOL;
  406. $crc = ($crc << 1) ^ 0x07;
  407. if($crc>=256){
  408. $crc %= 256;
  409. }
  410. //echo '($crc << 1) ^ 0x07:'.(($crc << 1) ^ 0x07) .PHP_EOL;
  411. }else{
  412. $crc <<= 1;
  413. //echo '$crc << 1:'.($crc << 1) .PHP_EOL;
  414. }
  415. }
  416. }
  417. return $crc;
  418. }
  419. public static function decode( $buffer ){
  420. //解码头部数据
  421. $unpack_head = unpack('C1magic/C1length/C1version/C1cmd', $buffer);
  422. //****临时处理: 0x86指令且长度为0x0D,修改长度为0x0E ****
  423. if($unpack_head['cmd'] == 0x86 && $unpack_head['length'] == 0x0D){
  424. //重新设置长度
  425. $buffer = substr($buffer,0,1).chr(hexdec('0E')).substr($buffer,2);
  426. $unpack_head = unpack('C1magic/C1length/C1version/C1cmd', $buffer);
  427. //重新计算校验码
  428. $bin = substr($buffer,1,$unpack_head['length']+1);
  429. $sign = self::crc8($bin);
  430. $buffer = substr($buffer,0,strlen($buffer)-1).chr($sign);
  431. }
  432. $unpack_head['method'] = sprintf("method%'04x", $unpack_head['cmd']);
  433. //判断头部引导符
  434. if( $unpack_head['magic'] != 0xFF )
  435. return null;
  436. echo 'buffer_length:'.strlen($buffer).PHP_EOL;
  437. $packet = self::bin2str($buffer, true);
  438. echo 'packet:'.$packet.PHP_EOL;
  439. //判断签名是否正确
  440. $crc_bin = substr($buffer,1,$unpack_head['length']+1);
  441. $decode_sign = self::crc8($crc_bin);
  442. //echo sprintf("decode_sign = %02x\n", $decode_sign).PHP_EOL;
  443. $real_sign = Ord(substr($buffer,-1));
  444. //echo sprintf("real_sign = %02x\n", $real_sign).PHP_EOL;
  445. if($decode_sign != $real_sign){
  446. echo 'decode sign error! '.sprintf("decode_sign = %02x", $decode_sign) .','.sprintf("real_sign = %02x", $real_sign) .PHP_EOL;
  447. return null;
  448. }
  449. //如果长度等于0则没有值数据
  450. if($unpack_head['length'] == 0)
  451. return $unpack_head;
  452. //解码值数据
  453. $value = substr($buffer,2,$unpack_head['length']);
  454. $unpack_value = self::unpackValue($unpack_head['cmd'],$value,$unpack_head['length']);
  455. if(!$unpack_value)
  456. return null;
  457. $unpack_value['packet'] = $packet;
  458. //头部+值一起返回
  459. return array_merge($unpack_head,$unpack_value);
  460. }
  461. public static function encode( $value ){
  462. echo 'encode:'.PHP_EOL;
  463. var_dump($value);
  464. //版本号+命令码+装载数据 打包为二进制数据包
  465. $pack_value = self::packValue($value);
  466. echo 'pack_value:'.self::bin2str($pack_value).PHP_EOL;
  467. $length = strlen($pack_value);
  468. echo 'length:'.$length.PHP_EOL;
  469. //准备生成校验码的数据(从包长度开始,到装载数据结束)
  470. $bin = chr($length).$pack_value;
  471. //生成校验码
  472. $sign = self::crc8($bin);
  473. echo sprintf("encode_sign_hex = %02x\n", $sign).PHP_EOL;
  474. //最终响应数据
  475. $buf = pack('C1C1', 0xFF,$length) . $pack_value . pack('C1', $sign);
  476. echo 'encode_value:'.self::bin2str($buf).PHP_EOL;
  477. return $buf;
  478. }
  479. public static function input( $buffer, $connection ){
  480. if (strlen($buffer) < 2) {
  481. return 0;
  482. }
  483. $unpack_data = unpack('C1magic/C1length/C1version/C1cmd', $buffer);
  484. if($unpack_data['length']==0){
  485. return $unpack_data['length'] + 2;
  486. }
  487. //****临时代码:嘉为86指令数据长度有错误,少了一个字节,暂时特殊处理下****
  488. if($unpack_data['cmd']==0x86 && $unpack_data['length']==0x0D){
  489. return $unpack_data['length'] + 4;
  490. }
  491. return $unpack_data['length'] + 3;
  492. }
  493. public static function str2bin( $text ){
  494. if (!is_string($text))
  495. return null;
  496. $arr = explode(' ',$text);
  497. $bin = '';
  498. foreach($arr as $hex){
  499. if(strlen($hex) == 2){
  500. $bin .= chr( hexdec($hex) );
  501. }
  502. }
  503. return $bin;
  504. }
  505. }