ZXCar.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. const common = require('../common.js');
  2. const FMBMS = require('./FMBMS.js');
  3. const readServiceID = '0000FEE7-0000-1000-8000-00805F9B34FB';
  4. const readID = '000036F6-0000-1000-8000-00805F9B34FB';
  5. const writeServiceID = '0000FEE7-0000-1000-8000-00805F9B34FB';
  6. const writeID = '000036F5-0000-1000-8000-00805F9B34FB';
  7. const MTU = 115;
  8. const app = getApp();
  9. let subIndex = -1
  10. let commands = []; // 升级包指令数组,每个指令是一个 ArrayBuffer
  11. let currentCommandIndex = 1;
  12. function acceptDevice(device) {
  13. return device.btid ? true : false;
  14. }
  15. function isSingleBt() {
  16. console.log('是单蓝牙');
  17. return true;
  18. }
  19. function haveBms() {
  20. console.log('是单蓝牙并且带bms');
  21. return true;
  22. }
  23. function isDevice(device, data) {
  24. // console.log(device,data,'device111');
  25. const advertisData = new Uint8Array(data.advertisData);
  26. // console.log(advertisData,'判断返回第几个字段是正常模式还是升级模式');
  27. //打印返回广播 判断返回字段是正常模式还是升级模式
  28. // console.log(advertisData.slice(4, 10).toString(),'device2222');
  29. const mac = device.btid
  30. .split('')
  31. .map((p, i) => parseInt(p + device.btid[i + 1], 16))
  32. .filter((p, i) => i % 2 == 0);
  33. // if ( advertisData.slice(4, 10).toString() == "095A5832") {
  34. // return true;
  35. // }
  36. //判断是否是智寻的蓝牙
  37. const result = data.name.startsWith("ZX");
  38. // if (data.name === "865416038002201") {
  39. // if (data.name === "ZX2503140000000") {
  40. if (result) {
  41. return true
  42. }
  43. return false;
  44. }
  45. function alterConnect(device, deviceId) {
  46. // console.log(device,app.globalData.connectionState[deviceId],'deviceliuwei');
  47. //登录 crc[0x1F,0x0F,0x5A,0x58,0x32,0x32,0x30,0x32,0x32,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x08,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x67,0xAC,0x53,0xE7,0x08,0x00]
  48. //登录 [[0x22,0x22,0x01,0x1F,0x0F,0x5A,0x58,0x32,0x32,0x30,0x32,0x32,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x08,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x67,0xAC,0x53,0xE7,0x08,0x00,crc_data,0xAA,0xAA]]
  49. //时间戳 0x67AC53E7 0x65,0xB3,0xED,0x6F 16:00:05
  50. //切换正常,工厂下发指令 [[0x22,0x22,0x54,0x01,0x01,0x12,0xAA,0xAA]]
  51. //OTA 升级指令 [[0x22,0x22,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,n,0xCB,0xAA,0xAA]]
  52. // const data = [0x1F, 0x0F, ,0x5A,0x58, 0x35, 0x32, 0x30, 0x32, 0x32, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  53. let data=[ 0x1F, 0x0F]
  54. const device_name=app.globalData.connectionState[deviceId].deviceName
  55. const device_sn=stringToHexArray(device_name)
  56. data.push(...device_sn)
  57. data.push(0x08, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x67, 0xAC, 0x53, 0xE7, 0x08, 0x00)
  58. // const data=[ 0x1F, 0x0F,0x38, 0x36, 0x35, 0x34, 0x31, 0x36, 0x30, 0x33, 0x38, 0x30, 0x30, 0x32, 0x32, 0x30, 0x31,0x08, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x67, 0xAC, 0x53, 0xE7, 0x08, 0x00]
  59. // console.log(data,'datatest');
  60. const crc_data = '0x'+crc8IEEE8023(data).toString(16).toUpperCase()
  61. data.push(crc_data,0xAA,0xAA)
  62. data.unshift(0x22,0x22,0x01)
  63. return [data]
  64. }
  65. function crc8IEEE8023(data) {
  66. const poly = 0x07; // IEEE 802.3 polynomial x^8 + x^2 + x + 1
  67. let crc = 0x00;
  68. for (let i = 0; i < data.length; i++) {
  69. crc ^= data[i];
  70. for (let j = 0; j < 8; j++) {
  71. if (crc & 0x80) {
  72. crc = ((crc << 1) ^ poly) & 0xFF;
  73. } else {
  74. crc = (crc << 1) & 0xFF;
  75. }
  76. }
  77. }
  78. return crc;
  79. }
  80. function stringToHexArray(str) {
  81. const result = [];
  82. for (let i = 0; i < str.length; i++) {
  83. const charCode = str.charCodeAt(i); // 获取字符的 ASCII 码值
  84. const hexValue=`0x${charCode.toString(16).toUpperCase()}`
  85. const hexDataValue=parseInt(hexValue,16)
  86. result.push(hexDataValue);
  87. }
  88. return result;
  89. }
  90. //收到硬件方向软件方发送的数据
  91. function readData(device, value, data) {
  92. // console.log(value, 'test1111');
  93. var test = new Uint8Array(value);
  94. const normalArray = Array.from(test); // 或 [...uint8Array]
  95. // console.log(normalArray,'normalArray---------------');
  96. // console.log(normalArray,currentCommandIndex-1,commands[currentCommandIndex],commands[currentCommandIndex-1], 'value**************************');
  97. if((normalArray[0]==0x00) && (normalArray[1]==0x01) && normalArray.length==2){
  98. switch (normalArray[1]) {
  99. case 0x01:
  100. uni.showModal({
  101. title: '提示',
  102. confirmText: '开始升级',
  103. content: '登陆成功,当前处于升级模式是否开始升级',
  104. success: function(res) {
  105. if (res.confirm) {
  106. currentCommandIndex=0
  107. otaUpgrade().then(()=>{
  108. //登陆成功 且当前为升级模式可以发送升级文件
  109. sendNextCommand(device.mac_id)
  110. })
  111. } else {}
  112. }
  113. });
  114. break;
  115. }
  116. }
  117. switch(normalArray[3]){
  118. case 0x00:
  119. sendNextCommand(device.mac_id)
  120. break;
  121. case 0x01:
  122. uni.hideLoading();
  123. console.log(normalArray,commands.length,currentCommandIndex-1,commands[currentCommandIndex-3],commands[currentCommandIndex-2],commands[currentCommandIndex-1], 'value**************************');
  124. common.simpleToast('升级文件回复失败', 2000)
  125. // test() 升级文件回复失败
  126. break;
  127. }
  128. return data;
  129. }
  130. //发送指令封装
  131. function sendCommand(cmd, data = []) {
  132. let cmdData = [0x22, 0x22]
  133. // cmdData.push(cmd)
  134. //协议号 cmd
  135. //包长度 data.length
  136. const dataLen=parseInt(data.length.toString(16).toUpperCase(), 16)
  137. //信息内容 cmd
  138. //crc校验
  139. const pData=[dataLen,cmd]
  140. const crcData='0x'+crc8IEEE8023(pData).toString(16).toUpperCase()
  141. cmdData.push(cmd,dataLen,cmd,crcData,0xAA, 0xAA)
  142. // console.log(cmdData,'cmdDatacmdData');
  143. return cmdData
  144. }
  145. function turnOnCar(device, deviceId) {
  146. return [sendCommand(0x02,[0x02])];
  147. }
  148. function turnOffCar(device, deviceId) {
  149. return [sendCommand(0x03,[0x03])];
  150. }
  151. function findCarCmd(device, deviceId) {
  152. return [sendCommand(0x06,[0x06])];
  153. }
  154. function openCarSeat(device, deviceId) {
  155. return [sendCommand(0x07,[0x07])];
  156. }
  157. function openCarTrunk(device, deviceId) {
  158. return [sendCommand(0x08,[0x08])];
  159. }
  160. function getCarPressure(device, deviceId) {
  161. return [sendCommand(0x4A,[0x4A])];
  162. }
  163. function switchFactory(device, deviceId) {
  164. //切换正常,工厂模式指令
  165. //切换工厂模式 [[0x22,0x22,0x54,0x01,0x01,0x12,0xAA,0xAA]]
  166. //切换正常模式 [[0x22,0x22,0x54,0x01,0x00,0x15,0xAA,0xAA]]
  167. return [[0x22,0x22,0x54,0x01,0x01,0x12,0xAA,0xAA]]
  168. // return [sendCommand([0x54, 0x01, 0x01, 0x12])];
  169. }
  170. //升级按钮
  171. function otaUpgrade(device){
  172. const data = readBinBinarayToCommand()
  173. data.then(result=>{commands=result})
  174. // console.log(data,'datatest111');
  175. return data
  176. }
  177. async function readBinBinarayToCommand() {
  178. let res =await uni.request({
  179. url: 'https://opt.bms16.com/ota.BIN', // 文件的网络地址
  180. method: 'GET',
  181. responseType: 'arraybuffer', // 指定响应类型为 arraybuffer
  182. });
  183. const arrayBuffer=res[1].data
  184. const uint8Array = new Uint8Array(arrayBuffer); // 转换为 Uint8Array
  185. const test = splitArrayIntoChunks(uint8Array, 80); // 分割成长度为 80 的数组
  186. const data =makeArr(test)
  187. return data
  188. }
  189. function sendNextCommand(mac_id) {
  190. console.log('开始发送指令');
  191. // console.log(commands[currentCommandIndex],'command');
  192. if (currentCommandIndex >= commands.length-1) {
  193. uni.hideLoading();
  194. common.simpleToast('所有指令发送完成', 2000)
  195. return;
  196. }
  197. const deviceId = Object.keys(app.globalData.connectionState).find((i) => app.globalData.connectionState[i].device.mac_id == mac_id);
  198. if (deviceId == undefined) {
  199. console.log('deviceId == undefined');
  200. return ;
  201. }
  202. const command = [commands[currentCommandIndex]];
  203. if(command.length==0){
  204. return
  205. }
  206. // 将数据转换为ArrayBuffer类型
  207. var buffer;
  208. buffer = common.toArrayBuffer(command.shift());
  209. // console.log(command,'command');
  210. uni.writeBLECharacteristicValue({
  211. deviceId: deviceId, // 替换为实际的设备 ID
  212. serviceId: writeServiceID, // 替换为实际的服务 ID
  213. characteristicId: writeID, // 替换为可写入的特征值 ID
  214. value: buffer,
  215. success() {
  216. // console.log('指令发送成功,等待设备响应',currentCommandIndex,commands[currentCommandIndex]);
  217. },
  218. fail(err) {
  219. console.error('指令发送失败', err);
  220. }
  221. });
  222. currentCommandIndex++;
  223. }
  224. function splitArrayIntoChunks(array, chunkSize) {
  225. const numChunks = Math.ceil(array.length / chunkSize);
  226. return Array.from({ length: numChunks }, (_, i) => {
  227. return array.slice(i * chunkSize, (i + 1) * chunkSize);
  228. });
  229. }
  230. // 处理分割后的数组
  231. function makeArr(array) {
  232. const result = [];
  233. let endPackage;
  234. for (let i = 0; i < array.length; i ++) {
  235. endPackage = 0x00
  236. if((i + 1) >= array.length){
  237. //当前是最后一次循环
  238. endPackage = 0x01
  239. }
  240. // if(i==2) return
  241. //协议号 30 包长度未固定array.length+8 转16进制 固件类型0x00 升级包大小(总包大小) 125396字节-》0x00,0x01,0xE9,0xD4
  242. let startArray = []
  243. const packageLen=parseInt((array[i].length+8).toString(16).toUpperCase(), 16)
  244. // const totalPackageSize=[0x00,0x00,0x01,0xE9,0xD4]
  245. const totalPackageSize=[0x00,0x00,0x01,0xeb,0xfc]
  246. startArray.push(packageLen,...totalPackageSize)
  247. //软件包id
  248. const ids=splitNumber(i) // 0x00,0x01
  249. startArray.push(...ids)
  250. //是否为最后一个包
  251. startArray.push(endPackage)
  252. //软件数据包
  253. const formattedChunk = array[i].map(byte => `0x${byte.toString(16).toUpperCase()}`); // 转换为 0xXX 格式
  254. startArray.push(...formattedChunk)
  255. // if(i>95&& i<105){
  256. // console.log(startArray,'startArray-------');
  257. // }
  258. //crc检验
  259. const crcStr='0x'+crc8IEEE8023(startArray).toString(16).toUpperCase()
  260. const testCrc=parseInt(crcStr,16)
  261. startArray.push(crcStr)
  262. startArray.push(0xAA,0xAA)
  263. startArray.unshift(0x22,0x22,0x30)
  264. result.push(startArray);
  265. }
  266. // result.push([0x22,0x22,0x30,0x58,0x00,0x00,0x00,0xE9,0xD4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2C,0xAA,0xAA])
  267. return result;
  268. }
  269. function splitNumber(num) {
  270. let highByte = (num >> 8) & 0xFF; // 对于0-255的数字,结果总是0
  271. // 低字节
  272. let lowByte = num & 0xFF;
  273. // 将每个字节转换为两位的十六进制字符串,并添加'0x'前缀
  274. let highHex = highByte.toString(16).toUpperCase().padStart(2, '0'); // 确保是两位十六进制数
  275. let lowHex = lowByte.toString(16).toUpperCase().padStart(2, '0'); // 确保是两位十六进制数
  276. // 返回结果数组(这里实际上可以返回一个对象或字符串,根据需求调整)
  277. return ['0x' + highHex, '0x' + lowHex];
  278. }
  279. module.exports = {
  280. readServiceID: readServiceID,
  281. readID: readID,
  282. writeServiceID: writeServiceID,
  283. writeID: writeID,
  284. MTU: MTU,
  285. acceptDevice: acceptDevice,
  286. isDevice: isDevice,
  287. alterConnect: alterConnect,
  288. readData: readData,
  289. turnOffCar: turnOffCar,
  290. isSingleBt: isSingleBt,
  291. haveBms: haveBms,
  292. switchFactory: switchFactory,
  293. otaUpgrade,
  294. findCarCmd,
  295. turnOffCar,
  296. turnOnCar,
  297. getCarPressure
  298. };