You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

WDObuDataUtil.js 31KB

hace 2 años
hace 1 año
hace 2 años
hace 2 años
hace 2 años
hace 2 años
hace 2 años
hace 2 años
hace 2 años
hace 2 años
hace 2 años
hace 2 años
hace 2 años
hace 2 años
hace 2 años
hace 2 años
hace 2 años
hace 2 años
hace 2 años
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227
  1. /*!
  2. * WATCHDATA OBU Ble Javascript Library
  3. * @author Mi.Li on 2018/11/14
  4. * @version - v1.0.0
  5. */
  6. var dataArrayTopacg = [];
  7. var mExpLength = 0;
  8. var mExpPackets = 0;
  9. var delayTimer; //停止循环获取tag
  10. var sendTimeout = 0;
  11. var isFound = false
  12. var isConnected = 1 //1 是未连接 0是链接 -1连接失败
  13. var isResponse = false
  14. var isConnecting = false
  15. var expPktNum = 0;
  16. var expPktLen = 0;
  17. var recBuffer = [];
  18. var currentDevice = {}; //ble设备
  19. var currentService = {}; //写入服务
  20. var currentCharacteristic = {}; //特征值
  21. var currentDeviceService = {}; //服务
  22. var writeCharacteristic = {}; //写入特征值
  23. var indicateCharacteristic = {}; //indicate特征值
  24. var readCharacteristic = {}; //读取特征值
  25. var onSendSuccessCallBack = undefined; //发送成功回调
  26. var onSendFailCallBack = undefined; //发送失败回调
  27. var lastErrorCode = 0; //default ok
  28. var sendTO; //send timeout
  29. var retDeivces ={
  30. name:"",
  31. deviceId:"",
  32. RSSI:0,
  33. localName:"",
  34. services:null,
  35. characteristics:null,
  36. }
  37. var defaultRes = {
  38. errMsg: "ok",
  39. errCode: 0
  40. };
  41. const ERROR_CONNECT_FAIL = 80000;
  42. const ERROR_SERACH_TIMEOUT = 80001;
  43. const ERROR_CONNECT_TIMEOUT = 80002;
  44. const ERROR_SEND_TIMEOUT = 80003;
  45. const ERROR_DATA_ERROR = 80004;
  46. const LENGTH_PER_PACKET = 95; //TODO:?92
  47. const LENGTH_HEADER = 5; //skip st
  48. const common_vendor = require("../../../common/vendor.js");
  49. var uni = common_vendor.index
  50. module.exports = {
  51. startConnectDevice: startConnectDevice,
  52. disconnectBleDevice: disconnectBleDevice,
  53. transCmd: transCmd,
  54. packPkt: packPkt,
  55. unpackPkt: unpackPkt,
  56. bytes2HexStr: bytes2HexStr,
  57. hexStr2Bytes: hexStr2Bytes,
  58. sync_transCmd: sync_transCmd,
  59. isConnectionStateChange: isConnectionStateChange,
  60. isConnectingStateChange: isConnectingStateChange,
  61. setConnectingState: setConnectingState,
  62. arrayBuffer2HexString: arrayBuffer2HexString,
  63. createBLEConnection: createBLEConnection
  64. }
  65. /**
  66. * @method startConnectDevice
  67. * @param {params}
  68. * @desc 开始连接WATCHDATA低功耗蓝⽛设备
  69. */
  70. function startConnectDevice(params,callback_0) {
  71. console.log('start connect>>>');
  72. console.log("connecting === " + isConnecting);
  73. isConnecting = true;
  74. console.log("connecting1111 === " + isConnecting);
  75. openBluetoothAdapter(params, callback_0);
  76. }
  77. /**
  78. * @desc 断开连接WATCHDATA低功耗蓝⽛设备
  79. */
  80. function disconnectBleDevice(params) {
  81. if (isConnectionStateChange()==0) {
  82. closeBLEConnection(params);
  83. } else {
  84. //console.log("当前无连接");
  85. params({
  86. code: 0,
  87. data : [],
  88. msg: "断开连接成功"
  89. })
  90. }
  91. }
  92. /**
  93. * @method isConnectionStateChange
  94. * @param
  95. * @desc 查询蓝牙是否正处于链接状态
  96. */
  97. function isConnectionStateChange() {
  98. return isConnected;
  99. }
  100. /**
  101. * 获取当前是否处于连接中
  102. */
  103. function isConnectingStateChange() {
  104. return isConnecting;
  105. }
  106. function setConnectingState(state) {
  107. isConnecting = state;
  108. }
  109. /**
  110. * @desc 初始化蓝牙适配器
  111. */
  112. function openBluetoothAdapter(params,callback_0) {
  113. //reset bt adapter
  114. clearInterval(delayTimer);
  115. uni.closeBluetoothAdapter({
  116. success: function(res) {
  117. console.log("复位蓝牙适配器成功")
  118. console.log(res)
  119. params.success({
  120. code:1000,
  121. msg: "复位蓝牙适配器成功",
  122. })
  123. },
  124. fail: function(res) {
  125. console.log("复位蓝牙适配器失败")
  126. console.log(res)
  127. params.fail({
  128. errMsg: "复位蓝牙适配器失败",
  129. errCode: res.errCode
  130. })
  131. return
  132. }
  133. })
  134. uni.openBluetoothAdapter({
  135. success: function(res) {
  136. console.log("初始化蓝牙适配器成功")
  137. console.log(res)
  138. uni.getBluetoothAdapterState({
  139. success(res) {
  140. console.log('getBluetoothAdapterState success' + res)
  141. },
  142. fail(res) {
  143. console.log('getBluetoothAdapterState fail' + res)
  144. }
  145. })
  146. startBluetoothDevicesDiscovery(params,callback_0)
  147. },
  148. fail: function(res) {
  149. console.log("初始化蓝牙适配器失败" + res.errMsg)
  150. params.fail({
  151. errMsg: "初始化蓝牙适配器失败",
  152. errCode: res.errCode
  153. })
  154. return
  155. },
  156. complete: function(res) {
  157. console.log(res);
  158. }
  159. })
  160. }
  161. /**
  162. * @desc 开始搜寻附近的蓝牙外围设备。注意,该操作比较耗费系统资源,在搜索并连接到设备后调用 stop 方法停止搜索。
  163. */
  164. function startBluetoothDevicesDiscovery(params,callback_0) {
  165. console.log(params);
  166. setTimeout(function() {
  167. if (isFound) {
  168. return;
  169. } else {
  170. defaultRes.errCode = ERROR_SERACH_TIMEOUT;
  171. defaultRes.errMsg = "搜索设备超时";
  172. console.log("搜索设备超时");
  173. stopBluetoothDevicesDiscovery();
  174. clearInterval(delayTimer)
  175. params.fail({
  176. errCode :2000,
  177. errMsg:"搜索设备超时"
  178. });
  179. return
  180. }
  181. }, params.discoveryTimeout);
  182. uni.startBluetoothDevicesDiscovery({
  183. services: ['0000fee7-0000-1000-8000-00805f9b34fb'],
  184. success: function(res) {
  185. console.log("开启搜索成功")
  186. console.log(res)
  187. getBluetoothDevices(params,callback_0)
  188. },
  189. fail: function(res) {
  190. console.log("开启搜索失败")
  191. params.fail({
  192. errMsg: "开启搜索失败",
  193. errCode: res.errCode
  194. })
  195. return
  196. }
  197. })
  198. //每隔delayTime获取一次
  199. delayTimer = setInterval(function() {
  200. if (!isFound)
  201. getBluetoothDevices(params,callback_0)
  202. }, params.delayTime)
  203. }
  204. /**
  205. * @desc 获取所有已发现的蓝牙设备,包括已经和本机处于连接状态的设备
  206. */
  207. function getBluetoothDevices(params,callback_0) {
  208. uni.getBluetoothDevices({
  209. success: function(res) {
  210. console.log("getBluetoothDevices 扫描成功");
  211. console.log(res.devices);
  212. for (var i = 0; i < res.devices.length; i++) {
  213. var obuNameFinal = removeBytes(params.adviceId, ":")
  214. if (isContains(res.devices[i].name, obuNameFinal)) {
  215. console.log("搜索到要链接的设备....")
  216. console.log(res)
  217. stopBluetoothDevicesDiscovery();
  218. isFound = true
  219. clearInterval(delayTimer)
  220. currentDevice = res.devices[i]
  221. console.log(currentDevice)
  222. }
  223. }
  224. },
  225. fail: function(res) {
  226. clearInterval(delayTimer)
  227. console.log("没有搜索到OBU设备")
  228. console.log(res)
  229. params.fail({
  230. errMsg: "没有搜索到OBU设备",
  231. errCode: res.errCode
  232. })
  233. stopBluetoothDevicesDiscovery();
  234. return
  235. }
  236. })
  237. }
  238. /**
  239. *@desc 停止搜寻附近的蓝牙外围设备。请在确保找到需要连接的设备后调用该方法停止搜索。
  240. */
  241. function stopBluetoothDevicesDiscovery() {
  242. uni.stopBluetoothDevicesDiscovery({
  243. success: function(res) {
  244. console.log("停止搜索设备")
  245. console.log(res)
  246. }
  247. })
  248. }
  249. /**
  250. *@desc 连接低功耗蓝牙设备
  251. */
  252. function createBLEConnection(params,callback_0) {
  253. setTimeout(function() {
  254. console.log("链接定时器", isConnected)
  255. if (isConnected == 0 || isConnected == -1) return;
  256. defaultRes.errCode = ERROR_CONNECT_TIMEOUT;
  257. defaultRes.errMsg = "连接设备超时";
  258. console.log("连接设备超时");
  259. params.fail({
  260. code :1,
  261. meg : "连接设备超时"
  262. })
  263. return
  264. }, params.connectTimeout)
  265. uni.createBLEConnection({
  266. // 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
  267. deviceId: params.adviceId,
  268. success: function(res) {
  269. //console.log(`成功: ${currentDevice.deviceId}`)
  270. isConnected = 0
  271. sendTimeout = params.sendTimeout;
  272. getBLEDeviceServices(params,callback_0);
  273. },
  274. fail: function(res) {
  275. isConnected = -1
  276. return null
  277. }
  278. })
  279. }
  280. /**
  281. *@desc 断开与低功耗蓝牙设备的连接
  282. */
  283. function closeBLEConnection(params) {
  284. uni.closeBLEConnection({
  285. deviceId: currentDevice.deviceId + "",
  286. success: function(res) {
  287. isConnected = 1
  288. isFound = false
  289. params({
  290. code: 0,
  291. data : [],
  292. msg: "断开连接成功"
  293. })
  294. },
  295. fail: function(res) {
  296. params({
  297. code : 1,
  298. data: [],
  299. msg: "断开连接失败",
  300. })
  301. }
  302. })
  303. }
  304. /**
  305. *@desc 获取蓝牙设备所有 service(服务)
  306. */
  307. function getBLEDeviceServices(params,callback_0) {
  308. uni.onBLEConnectionStateChange(function(res) {
  309. if (res.connected) {
  310. isConnected = 0
  311. } else {
  312. if (isConnected == 0) {
  313. callback_0({
  314. code: 1,
  315. data: [],
  316. msg: "设备意外,断开连接",
  317. })
  318. isConnected = -1
  319. return
  320. }
  321. }
  322. if (res.connected)
  323. {
  324. callback_0({
  325. code: 0,
  326. data: [],
  327. msg: "链接成功",
  328. })
  329. }else
  330. {
  331. callback_0({
  332. code: 1,
  333. data: [],
  334. msg: "断开连接",
  335. })
  336. }
  337. });
  338. uni.getBLEDeviceServices({
  339. // 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
  340. deviceId: params.adviceId + "",
  341. success: function(res) {
  342. for (var i = 0; i < res.services.length; i++) {
  343. if (res.services[i].uuid.toUpperCase() === params.srv_uuid.toUpperCase()) {
  344. currentService = res.services[i]
  345. break;
  346. }
  347. }
  348. currentDeviceService = res.services;
  349. //获取Characteristics
  350. getBLEDeviceCharacteristics(params);
  351. },
  352. fail: function(res) {
  353. params.fail({
  354. code: 1,
  355. data: [],
  356. msg: "获取服务失败",
  357. })
  358. }
  359. })
  360. }
  361. /**
  362. *@desc 获取蓝牙设备唤醒characteristic(特征值)
  363. */
  364. function getBLEDeviceCharacteristics(params) {
  365. uni.getBLEDeviceCharacteristics({
  366. // 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
  367. deviceId: params.adviceId + "",
  368. // 这里的 serviceId 需要在上面的 getBLEDeviceServices 接口中获取
  369. serviceId: params.srv_uuid + "",
  370. success: function(res) {
  371. for (var i = 0; i < res.characteristics.length; i++) {
  372. if (res.characteristics[i].uuid.toUpperCase() === params.chr_read_uuid.toUpperCase()) {
  373. readCharacteristic = res.characteristics[i];
  374. }
  375. if (res.characteristics[i].uuid.toUpperCase() === params.chr_write_uuid.toUpperCase()) {
  376. writeCharacteristic = res.characteristics[i];
  377. }
  378. if (res.characteristics[i].uuid.toUpperCase() === params.chr_indicate_uuid.toUpperCase()) {
  379. indicateCharacteristic = res.characteristics[i];
  380. }
  381. }
  382. currentCharacteristic = res.characteristics;
  383. // initNotifyListener(params);
  384. subscribeIndicateCharacteristic(params);
  385. },
  386. fail: function(res) {
  387. params.fail({
  388. errMsg: "唤醒特征值获取失败",
  389. errCode: res.errCode
  390. })
  391. }
  392. })
  393. }
  394. /**
  395. *
  396. * @desc 连接成功后,初始化回调监听
  397. */
  398. function initNotifyListener(params) {
  399. uni.readBLECharacteristicValue({
  400. deviceId: params.adviceId + "",
  401. serviceId: params.srv_uuid + "",
  402. characteristicId: readCharacteristic.uuid + "",
  403. success: function (res) {
  404. subscribeIndicateCharacteristic(params)
  405. },
  406. fail: function (res) {
  407. params.fail({
  408. errMsg: "开启监听失败",
  409. errCode: res.errCode
  410. })
  411. }
  412. })
  413. }
  414. function subscribeIndicateCharacteristic (params) {
  415. uni.notifyBLECharacteristicValueChange({
  416. deviceId: params.adviceId + "",
  417. serviceId: params.srv_uuid + "",
  418. characteristicId: indicateCharacteristic.uuid + "",
  419. state: true,
  420. success: function (res) {
  421. onBLECharacteristicValueChange();
  422. setTimeout(function () {
  423. //连接成功
  424. lastErrorCode = res.errCode;
  425. retDeivces.name = currentDevice.name;
  426. retDeivces.deviceId = currentDevice.deviceId;
  427. retDeivces.RSSI = currentDevice.RSSI;
  428. retDeivces.localName = currentDevice.localName;
  429. retDeivces.services = currentDeviceService;
  430. retDeivces.characteristics = currentCharacteristic;
  431. currentDevice.deviceId = params.adviceId
  432. params.success({
  433. code: 0,
  434. msg: "连接成功",
  435. })
  436. }, params.accTimeout);
  437. },
  438. fail: function (res) {
  439. params.fail({
  440. msg: "开启监听失败",
  441. code: res.errCode
  442. })
  443. }
  444. });
  445. }
  446. /**
  447. *@desc 启用低功耗蓝牙设备特征值变化时的 notify
  448. */
  449. function onBLECharacteristicValueChange() {
  450. uni.onBLECharacteristicValueChange(function (res) {
  451. //check pkt
  452. //每次发送可能多次触发此通知,检查返回包的完整性,否则触发接收等待超时
  453. let rValue = new Uint8Array(res.value);
  454. let pktArray = Array.prototype.slice.call(new Uint8Array(res.value));
  455. if ((expPktLen <= 0) && (pktArray.length < 4)) {
  456. //丢弃无效包
  457. console.log('incomplete data:expPktLen=${expPktLen},pktArray.length=${pktArray.lengths}');
  458. return false;
  459. }
  460. if (expPktLen <= 0) {
  461. expPktLen = pktArray[3] /*+ LENGTH_HEADER 3*/;
  462. expPktNum = pktArray[2] & 0x7F;
  463. }
  464. recBuffer = recBuffer.concat(pktArray.slice(0));
  465. expPktLen -= pktArray.length;
  466. if (expPktLen <= 0 && expPktNum <= 0) {
  467. //所有帧都收到了
  468. //接收的所有数据
  469. let allCmd = arrayBuffer2HexString(new Uint8Array(recBuffer).buffer);
  470. //得到有用的数据长度
  471. let dLen = allCmd.substring(22, 24);
  472. let rCommand = allCmd.substring(24, (24 + parseInt(dLen, 16)) * 2);
  473. let bufferArrs = hexStr2Bytes(rCommand);
  474. isResponse = true;
  475. clearTimeout(sendTO);
  476. //unpack
  477. // let retbuf = unpackPkt(recBuffer);
  478. let retbuf
  479. if (bufferArrs[2]==128){
  480. retbuf = unpackPkt(bufferArrs);
  481. }else{
  482. retbuf = bye2to(bufferArrs)
  483. }
  484. if (allCmd != null) {
  485. if (bufferArrs[0] == 40 && bufferArrs[1] == 2 && bufferArrs[2] == 58 && bufferArrs[3] == 6) {
  486. console.log("连接指令不返回")
  487. return
  488. }
  489. if (onSendSuccessCallBack != undefined) {
  490. onSendSuccessCallBack(retbuf);
  491. }
  492. } else {
  493. defaultRes.errCode = ERROR_DATA_ERROR;
  494. defaultRes.errMsg = "接收失败";
  495. onSendFailCallBack(defaultRes);
  496. }
  497. recBuffer = []
  498. return;
  499. }
  500. })
  501. }
  502. /**
  503. *@desc sync_delay 阻塞
  504. */
  505. function sync_delay(ms) {
  506. return new Promise((resolve, reject) => {
  507. setTimeout(resolve, ms);
  508. });
  509. }
  510. function sync_transCmd(cmd){
  511. return new Promise((resolve, reject) => {
  512. transCmd({ data: cmd, success:resolve,fail:reject});
  513. });
  514. }
  515. /**
  516. *@desc 收发ble通道数据
  517. */
  518. function transCmd(data,success,fail) {
  519. // uni.onBLEConnectionStateChange(function (res) {
  520. // // if (isConnected == 0) {
  521. // // if (!res.connected) {
  522. // // isResponse = true;
  523. // // fail({
  524. // // code: 1,
  525. // // data:[],
  526. // // msg: "设备连接已断开,发送指令失败"
  527. // // })
  528. // // }
  529. // // }
  530. // isConnected = -1
  531. // return null;
  532. // });
  533. if (isConnectionStateChange()!=0) {
  534. console.log("连接断开,发送失败")
  535. defaultRes.errCode = ERROR_CONNECT_FAIL;
  536. defaultRes.errMsg = "连接断开,发送失败";
  537. fail(defaultRes);
  538. } else {
  539. //pack
  540. let cmd = packPkt(data).toUpperCase();
  541. sendCmd(cmd, success, fail);
  542. }
  543. }
  544. /**
  545. * @desc 发送指令,不关心指令具体长度,从第一个字节开始
  546. */
  547. function sendCmd(cmd, successCb, failCb) {
  548. //清空接收buf
  549. isResponse = false;
  550. expPktLen = 0;
  551. expPktNum = 0;
  552. recBuffer = [];
  553. //设置发送超时
  554. sendTO = setTimeout(function(){
  555. if (isConnected != 0) return
  556. if (isResponse ) {
  557. return;
  558. } else {
  559. console.log("还是进来了isConnected", isConnected)
  560. defaultRes.errCode = ERROR_SEND_TIMEOUT;
  561. defaultRes.errMsg = "接收超时";
  562. console.log("接收超时");
  563. failCb({
  564. code: 1,
  565. data: [],
  566. msg: "接收超时",
  567. })
  568. onSendSuccessCallBack = undefined;
  569. onSendFailCallBack = undefined;
  570. isResponse = true;
  571. failCb(defaultRes);
  572. return
  573. }
  574. }, sendTimeout);
  575. //接收ble返回数据
  576. onSendSuccessCallBack = successCb;
  577. onSendFailCallBack = failCb;
  578. //递归发送
  579. sendCmds(cmd, 0, failCb);
  580. }
  581. /**
  582. *
  583. * @desc 逐条发送指令,小程序不会对写入数据包大小做限制,但系统与蓝牙设备会限制蓝牙4.0单次传输的数据大小,超过最大字节数后会发生写入错误,建议每次写入不超过20字节。
  584. */
  585. function sendCmds(command, index, onFailCallback) {
  586. var itemCmd;
  587. var isLast = false; // 判断是否是最后一条
  588. if (command.length > index + 40) {
  589. itemCmd = command.substr(index, 40);
  590. } else {
  591. isLast = true;
  592. itemCmd = command.substr(index);
  593. }
  594. writeCommandToBle(itemCmd, function(errMsg) {
  595. if (errMsg == 'ok' && !isLast) { // 发送成功并且不是最后一条时,执行下一条
  596. sendCmds(command, index + 40);
  597. }
  598. },
  599. onFailCallback)
  600. }
  601. /**
  602. *
  603. * @desc 向蓝牙中写入数据(ble蓝牙)
  604. */
  605. function writeCommandToBle(commonds, onSendCallback, onFailCallback) {
  606. var commond = commonds;
  607. let buffer = hexString2ArrayBuffer(commond);
  608. console.log("发送的数据",buffer)
  609. uni.writeBLECharacteristicValue({
  610. deviceId: currentDevice.deviceId + "",
  611. serviceId: currentService.uuid + '',
  612. characteristicId: writeCharacteristic.uuid + '',
  613. // 这里的value是ArrayBuffer类型
  614. value: buffer,
  615. success: function(res) {
  616. onSendCallback('ok');
  617. },
  618. fail: function(res) {
  619. onFailCallback({
  620. msg: "发送指令失败",
  621. code: res.errCode
  622. })
  623. }
  624. })
  625. }
  626. /**
  627. * @desc 打包16进制字符帧
  628. * @return Hex string packet
  629. */
  630. function packPkt(hexStr) {
  631. let dataArrayBuf = hexString2ArrayBuffer(hexStr);
  632. let dataArray = Array.prototype.slice.call(new Uint8Array(dataArrayBuf));
  633. let pkt = [];
  634. let buf = [];
  635. let pktSN = 0;
  636. let pktNum = Math.ceil(dataArray.length / LENGTH_PER_PACKET);
  637. let dataLen = 0;
  638. let offset = 0;
  639. //console.log('CMD:' + hexStr);
  640. if (dataArray.length <= 0) {
  641. console.log('Hex string pack fail:', hexStr);
  642. return null;
  643. }
  644. for (var i = 0; i < pktNum; i++) {
  645. buf = [];
  646. //ST:0x33
  647. buf.push(0x33);
  648. //SN
  649. pktSN++;
  650. buf.push(pktSN);
  651. //CTL
  652. if (pktNum > 1) {
  653. if (i == 0) {
  654. buf.push(0x80 | (pktNum - 1));
  655. } else {
  656. buf.push(pktNum - 1 - i);
  657. }
  658. } else {
  659. buf.push(0);
  660. }
  661. //LEN
  662. if (i == (pktNum - 1)) {
  663. dataLen = dataArray.length - offset;
  664. } else {
  665. dataLen = LENGTH_PER_PACKET;
  666. }
  667. buf.push(dataLen);
  668. //DATA
  669. buf = buf.concat(dataArray.slice(offset, offset + dataLen));
  670. offset += dataLen;
  671. //BCC: xor From SN to Data
  672. let xor = calXor(buf, 1, buf.length - 1);
  673. buf.push(xor);
  674. pkt = pkt.concat(buf);
  675. }
  676. let pktArrayBuffer = new Uint8Array(pkt).buffer;
  677. //console.log('packed cmd:' + arrayBuffer2HexString(pktArrayBuffer));
  678. //头
  679. let header = "FE01";
  680. //命令代码
  681. let cmdCode = "753100000A0012";
  682. //发送的数据
  683. let dataCmd = arrayBuffer2HexString(pktArrayBuffer);
  684. //发送数据的长度
  685. let cLen = wxNumberToHexString(dataCmd.length / 2, 1, true);
  686. //尾
  687. let footer = "1800";
  688. //总数据
  689. let ddd = header + cmdCode + cLen + footer + dataCmd;
  690. //总长度
  691. let cmdLen = wxNumberToHexString(ddd.length / 2, 2, true);
  692. let rCmd1 = header + cmdLen + cmdCode + cLen + arrayBuffer2HexString(pktArrayBuffer) + footer;
  693. let cmdLen1 = wxNumberToHexString(rCmd1.length / 2, 2, true);
  694. let rCmd = header + cmdLen1 + cmdCode + cLen + arrayBuffer2HexString(pktArrayBuffer) + footer;
  695. // return arrayBuffer2HexString(pktArrayBuffer);
  696. console.log("打包数据",rCmd)
  697. return rCmd;
  698. }
  699. // number转换成指定字节数的hexString
  700. // num:要转换的数(number) bitNum:转换后的字节数(number) isBig:是不是大端模式(boolean)
  701. function wxNumberToHexString(num, bitNum, isBig) {
  702. // 转大端hex并补足
  703. let hex = num.toString(16);
  704. for (let i = hex.length; i < bitNum * 2; i++) {
  705. hex = '0' + hex;
  706. }
  707. // 多位截取
  708. if (hex.length > bitNum * 2) {
  709. hex = hex.substring(hex.length - bitNum * 2);
  710. }
  711. // 转小端
  712. if (isBig == false) {
  713. let temp = '';
  714. for (let i = hex.length - 2; i >= 0; i -= 2) {
  715. temp = temp + hex.substring(i, i + 2);
  716. }
  717. hex = temp;
  718. }
  719. return hex;
  720. }
  721. /**
  722. * @desc 解包16进制字符帧
  723. * @return Hex string data
  724. */
  725. function unpackPkt(pktArray) {
  726. let buf = [];
  727. let pktNum = Math.ceil(pktArray.length / (LENGTH_PER_PACKET + LENGTH_HEADER));
  728. let dataLen = 0;
  729. let offset = 0;
  730. for (var i = 0; i < pktNum; i++) {
  731. //head
  732. offset += 3; //skip ST,SN,CTL
  733. dataLen = pktArray[offset];
  734. offset++;
  735. //data
  736. if (offset + dataLen >= pktArray.length) {
  737. //Incomplete data
  738. console.log('unpack length fail');
  739. return null
  740. }
  741. buf = buf.concat(pktArray.slice(offset, offset + dataLen));
  742. //xor
  743. var xor = calXor(pktArray, offset - 3, dataLen + 3);
  744. offset += dataLen;
  745. if (xor != pktArray[offset]) {
  746. console.log('unpack fail xor:', xor);
  747. return null;
  748. }
  749. offset++;
  750. }
  751. return buf;
  752. }
  753. /**
  754. * @desc 异或运算
  755. */
  756. function calXor(dataArray, offset, len) {
  757. var ret = 0;
  758. for (var i = 0; i < len; i++) {
  759. ret ^= dataArray[offset + i];
  760. }
  761. return ret;
  762. }
  763. /**
  764. * ArrayBuffer转16进制字符串
  765. */
  766. function arrayBuffer2HexString(buf) {
  767. var out = "";
  768. var u8a = new Uint8Array(buf);
  769. var single;
  770. for (var i = 0; i < u8a.length; i++) {
  771. single = u8a[i].toString(16)
  772. while (single.length < 2) single = "0".concat(single);
  773. out += single;
  774. }
  775. return out;
  776. }
  777. /**
  778. * 1、字符串转换为十六进制
  779. * 主要使用 charCodeAt()方法,此方法返回一个字符的 Unicode 值,该字符位于指定索引位置。
  780. */
  781. function stringToHex(str) {
  782. var val = "";
  783. for (var i = 0; i < str.length; i++) {
  784. val += str.charCodeAt(i).toString(16);
  785. }
  786. return val;
  787. }
  788. function filterChinese(str) {
  789. var tmp = str.split(''),
  790. arr = [];
  791. for (var i = 0, c = tmp.length; i < c; i++) {
  792. var s = tmp[i].charCodeAt();
  793. if (s > 0 && s < 127) {
  794. arr.push(tmp[i]);
  795. }
  796. }
  797. return arr;
  798. };
  799. function strToHex(hex, isFilterChinese) {
  800. hex = isFilterChinese ? filterChinese(hex).join('') : convertChinese(hex).join('');
  801. //清除所有空格
  802. hex = hex.replace(/\s/g, "");
  803. //若字符个数为奇数,补一个空格
  804. hex += hex.length % 2 != 0 ? " " : "";
  805. var c = hex.length / 2,
  806. arr = [];
  807. for (var i = 0; i < c; i++) {
  808. arr.push(parseInt(hex.substr(i * 2, 2), 16));
  809. }
  810. return arr;
  811. };
  812. /**
  813. * 16进制字符串转ArrayBuffer
  814. */
  815. function hexString2ArrayBuffer(hexStr) {
  816. var count = hexStr.length / 2;
  817. let buffer = new ArrayBuffer(count);
  818. let dataView = new DataView(buffer);
  819. for (var i = 0; i < count; i++) {
  820. var curCharCode = parseInt(hexStr.substr(i * 2, 2), 16);
  821. dataView.setUint8(i, curCharCode);
  822. }
  823. return buffer;
  824. }
  825. /**
  826. * 字符串转为ArrayBuffer对象,参数为字符串
  827. */
  828. function string2ArrayBuffer(str) {
  829. var buf = new ArrayBuffer(str.length * 2); // 每个字符占用2个字节
  830. var bufView = new Uint8Array(buf);
  831. for (var i = 0, strLen = str.length; i < strLen; i++) {
  832. bufView[i] = str.charCodeAt(i);
  833. }
  834. return buf;
  835. }
  836. function isArray(arr) {
  837. return Object.prototype.toString.call(arr) === '[object Array]';
  838. };
  839. function strToByte(str) {
  840. var tmp = str.split(''),
  841. arr = [];
  842. for (var i = 0, c = tmp.length; i < c; i++) {
  843. var j = encodeURI(tmp[i]);
  844. if (j.length == 1) {
  845. arr.push(j.charCodeAt());
  846. } else {
  847. var b = j.split('%');
  848. for (var m = 1; m < b.length; m++) {
  849. arr.push(parseInt('0x' + b[m]));
  850. }
  851. }
  852. }
  853. return arr;
  854. };
  855. function convertChinese(str) {
  856. var tmp = str.split(''),
  857. arr = [];
  858. for (var i = 0, c = tmp.length; i < c; i++) {
  859. var s = tmp[i].charCodeAt();
  860. if (s <= 0 || s >= 127) {
  861. arr.push(s.toString(16));
  862. } else {
  863. arr.push(tmp[i]);
  864. }
  865. }
  866. return arr;
  867. };
  868. // function filterChinese(str) {
  869. // var tmp = str.split(''),
  870. // arr = [];
  871. // for (var i = 0, c = tmp.length; i < c; i++) {
  872. // var s = tmp[i].charCodeAt();
  873. // if (s > 0 && s < 127) {
  874. // arr.push(tmp[i]);
  875. // }
  876. // }
  877. // return arr;
  878. // };
  879. // function strToHex(hex, isFilterChinese) {
  880. // hex = isFilterChinese ? filterChinese(hex).join('') : convertChinese(hex).join('');
  881. // //清除所有空格
  882. // hex = hex.replace(/\s/g, "");
  883. // //若字符个数为奇数,补一个空格
  884. // hex += hex.length % 2 != 0 ? " " : "";
  885. // var c = hex.length / 2,
  886. // arr = [];
  887. // for (var i = 0; i < c; i++) {
  888. // arr.push(parseInt(hex.substr(i * 2, 2), 16));
  889. // }
  890. // return arr;
  891. // };
  892. function padLeft(s, w, pc) {
  893. if (pc == undefined) {
  894. pc = '0';
  895. }
  896. for (var i = 0, c = w - s.length; i < c; i++) {
  897. s = pc + s;
  898. }
  899. return s;
  900. };
  901. function toString(arr, isReverse) {
  902. if (typeof isReverse == 'undefined') {
  903. isReverse = true;
  904. }
  905. var hi = arr[0],
  906. lo = arr[1];
  907. return padLeft((isReverse ? hi + lo * 0x100 : hi * 0x100 + lo).toString(16).toUpperCase(), 4, '0');
  908. };
  909. /**
  910. * 16进制字符串异或处理
  911. *
  912. * @param str1
  913. * @param str2
  914. * @return
  915. */
  916. function stringXor(str1, str2) {
  917. if (!str1 && !str2) {
  918. return "";
  919. }
  920. if (!str1 && str2) {
  921. return str2;
  922. }
  923. if (str1 && !str2) {
  924. return str1;
  925. }
  926. var longStr;
  927. var shortStr;
  928. if (str1.length >= str2.length) {
  929. longStr = str1;
  930. shortStr = str2;
  931. } else {
  932. longStr = str2;
  933. shortStr = str1;
  934. }
  935. var count = parseInt(shortStr.length / 2);
  936. var leftCount = longStr.length - shortStr.length;
  937. var resultStr = "";
  938. if (leftCount > 0) {
  939. resultStr += longStr.substr(0, leftCount);
  940. }
  941. for (var i = 0; i < count; i++) {
  942. var shortCharCode = parseInt(shortStr.substr(i * 2, 2), 16);
  943. var longCharCode = parseInt(longStr.substr(leftCount + i * 2, 2), 16);
  944. var resultCode = shortCharCode ^ longCharCode;
  945. var single = resultCode.toString(16);
  946. while (single.length < 2) single = "0".concat(single);
  947. resultStr += single;
  948. }
  949. return resultStr.toUpperCase();
  950. }
  951. /**
  952. * 指令两个16进制字符串异或处理
  953. *
  954. * @param command
  955. * @param secretKey
  956. * @return
  957. */
  958. function getSecretEncoding(command, secretKey) {
  959. if (!command || !secretKey) {
  960. return "";
  961. }
  962. var secretLength = secretKey.length;
  963. var length = parseInt(command.length / secretLength);
  964. console.log(`command(${command.length})/secretLength(${secretLength}) = ${length}`);
  965. var resultCmd = "";
  966. console.log(`secretKey(${secretKey.length}):${secretKey}`);
  967. for (var i = 0; i < length; i++) {
  968. var part = command.substr(i * secretLength, secretLength);
  969. resultCmd += stringXor(part, secretKey);
  970. console.log(`part${i}:${stringXor(part, secretKey)}`);
  971. }
  972. var lastLen = command.length % secretLength;
  973. if (lastLen > 0) {
  974. console.log(`lastCMD:${command.substr(command.length - lastLen, lastLen)}`);
  975. console.log(`lastSecretKey:${secretKey.substr(0, lastLen)}`);
  976. var lastPart = command.substr(command.length - lastLen, lastLen);
  977. var lastCmd = stringXor(lastPart, secretKey.substr(0, lastLen));
  978. resultCmd += lastCmd;
  979. console.log(`lastPart:${lastCmd}`);
  980. }
  981. return resultCmd;
  982. }
  983. /**
  984. * 2、十六进制转换为字符串
  985. *主要使用 fromCharCode()方法,此方法将 Unicode 码转换为与之对应的字符。
  986. */
  987. function hexToString(str) {
  988. var val = "";
  989. var arr = str.split(",");
  990. for (var i = 0; i < arr.length; i++) {
  991. val += arr[i].fromCharCode(i);
  992. }
  993. return val;
  994. }
  995. /**
  996. * 获取随机长度16进制字符串
  997. */
  998. function getRamNumber(length) {
  999. var result = '';
  1000. for (var i = 0; i < length; i++) {
  1001. result += Math.floor(Math.random() * 16).toString(16); //获取0-15并通过toString转16进制
  1002. }
  1003. //默认字母小写,手动转大写
  1004. return result.toUpperCase(); //另toLowerCase()转小写
  1005. }
  1006. /**
  1007. * 得到BCD码时间字符串
  1008. *
  1009. * @param datetime
  1010. * @return
  1011. */
  1012. function getBCDTime(datetime, needWeek) {
  1013. if (typeof datetime == 'undefined') {
  1014. datetime = new Date();
  1015. }
  1016. if (typeof needWeek == 'undefined') {
  1017. needWeek = true;
  1018. }
  1019. var year = datetime.getFullYear() - 2000; //获取年份,从2000年开始计算
  1020. if (year < 0) year = 0; // 不允许小于2000年的年份出现
  1021. var month = datetime.getMonth() + 1; //获取月份 0-11 所以需要加1
  1022. var day = datetime.getDate(); //获取日
  1023. var hour = datetime.getHours(); //小时
  1024. var minute = datetime.getMinutes(); //分
  1025. var second = datetime.getSeconds(); //秒
  1026. if (needWeek) {
  1027. var dayOfWeek = datetime.getDay(); //一周的第几天 0-6
  1028. return formatNumber(year) + formatNumber(month) + formatNumber(day) + formatNumber(dayOfWeek) +
  1029. formatNumber(hour) + formatNumber(minute) + formatNumber(second); // 得到BCD码的时间字符串
  1030. } else {
  1031. return formatNumber(year) + formatNumber(month) + formatNumber(day) +
  1032. formatNumber(hour) + formatNumber(minute) + formatNumber(second); // 得到BCD码的时间字符串
  1033. }
  1034. }
  1035. function formatNumber(n) {
  1036. n = n.toString()
  1037. return (n[1] ? n : '0' + n) + "";
  1038. }
  1039. /**
  1040. * 判断一个字符串是否包含子串
  1041. */
  1042. function isContains(str, substr) {
  1043. var strUp = str.toUpperCase();
  1044. var substrUp = substr.toUpperCase()
  1045. return new RegExp(substrUp).test(strUp);
  1046. }
  1047. /**
  1048. * 去除字符串中特定的字符
  1049. */
  1050. function removeBytes(str, substr) {
  1051. console.log("split",str)
  1052. var items = str.split(substr)
  1053. // 会得到一个数组,数组中包括利用o分割后的多个字符串(不包括o)
  1054. var newStr = items.join("");
  1055. return newStr
  1056. // }
  1057. }
  1058. //十六进制字符串转字节数组
  1059. function hexStr2Bytes(str) {
  1060. var pos = 0;
  1061. var len = str.length;
  1062. if (len % 2 != 0) {
  1063. return null;
  1064. }
  1065. len /= 2;
  1066. var hexA = new Array();
  1067. for (var i = 0; i < len; i++) {
  1068. var s = str.substr(pos, 2);
  1069. var v = parseInt(s, 16);
  1070. hexA.push(v);
  1071. pos += 2;
  1072. }
  1073. return hexA;
  1074. }
  1075. //字节数组转十六进制字符串
  1076. function bytes2HexStr(arr) {
  1077. var str = "";
  1078. for (var i = 0; i < arr.length; i++) {
  1079. var tmp = arr[i].toString(16);
  1080. if (tmp.length == 1) {
  1081. tmp = "0" + tmp;
  1082. }
  1083. str += tmp;
  1084. }
  1085. return str;
  1086. }
  1087. function bye2to(byte){
  1088. if (byte[2]!=129){
  1089. //console.log("第二包", arrayBuffer2HexString(byte))
  1090. byte.splice(0,4)
  1091. dataArrayTopacg = dataArrayTopacg.concat(byte.slice(0));
  1092. dataArrayTopacg.splice(3, 1, dataArrayTopacg.length-7);
  1093. //console.log("第二包", arrayBuffer2HexString(byte), dataArrayTopacg)
  1094. let retbuf = unpackPktTo(dataArrayTopacg)
  1095. return retbuf
  1096. }else{
  1097. dataArrayTopacg = []
  1098. byte.splice(byte.length - 3, byte.length)
  1099. dataArrayTopacg = dataArrayTopacg.concat(byte.slice(0));
  1100. }
  1101. /**
  1102. * @desc 解包16进制字符帧
  1103. * @return Hex string data
  1104. */
  1105. function unpackPktTo(pktArray) {
  1106. pktArray.splice(0, 4)
  1107. pktArray.splice(pktArray.length - 3, pktArray.length)
  1108. return pktArray
  1109. }
  1110. }