ZXCar.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  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. // if (data.name === "ZX2202220000000") {
  37. if (data.name === "865416038002201") {
  38. return true
  39. }
  40. return false;
  41. }
  42. function alterConnect(device, deviceId) {
  43. //登录 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]
  44. //登录 [[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]]
  45. //时间戳 0x67AC53E7 0x65,0xB3,0xED,0x6F 16:00:05
  46. //切换正常,工厂下发指令 [[0x22,0x22,0x54,0x01,0x01,0x12,0xAA,0xAA]]
  47. //OTA 升级指令 [[0x22,0x22,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,n,0xCB,0xAA,0xAA]]
  48. // const data = [0x1F, 0x0F, ,0x5A,0x58, 0x35, 0x32, 0x30, 0x32, 0x32, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
  49. 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]
  50. // console.log(data,'datatest');
  51. const crc_data = crc8IEEE8023(data)
  52. // console.log(crc_data, 111);
  53. // 示例数据(16进制字符串转换为字节数组)
  54. // const hexString = "1F0F38363534313630333830303232303108313233343536373867AC53E70800";
  55. // const byteArray = hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16));
  56. // console.log(byteArray,'byteArray');
  57. // 计算 CRC-8 IEEE 802.3 校验值
  58. // const crcResult = crc8IEEE8023(byteArray).toString(16).toUpperCase();
  59. // console.log("CRC-8 IEEE 802.3 Checksum:", crcResult.toString(16).toUpperCase());
  60. return [
  61. [0x22, 0x22, 0x01, 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,
  62. crc_data, 0xAA, 0xAA
  63. ]
  64. ]
  65. //return [sendCommand(0x01, [0xAB, 0xCD, 0xAB, 0xCD])]
  66. }
  67. function crc8IEEE8023(data) {
  68. const poly = 0x07; // IEEE 802.3 polynomial x^8 + x^2 + x + 1
  69. let crc = 0x00;
  70. for (let i = 0; i < data.length; i++) {
  71. crc ^= data[i];
  72. for (let j = 0; j < 8; j++) {
  73. if (crc & 0x80) {
  74. crc = ((crc << 1) ^ poly) & 0xFF;
  75. } else {
  76. crc = (crc << 1) & 0xFF;
  77. }
  78. }
  79. }
  80. return crc;
  81. }
  82. //收到硬件方向软件方发送的数据
  83. function readData(device, value, data) {
  84. // console.log(value, 'test1111');
  85. var value = new Uint8Array(value);
  86. const normalArray = Array.from(value); // 或 [...uint8Array]
  87. console.log(normalArray, 'value**************************');
  88. // switch (value[0]) {
  89. // case 0:
  90. // //登陆成功准备
  91. // switchFactory(device)
  92. // break;
  93. // }
  94. switch(normalArray[3]){
  95. case 0x00:
  96. sendNextCommand(device.mac_id)
  97. break;
  98. case 0x01:
  99. test()
  100. break;
  101. }
  102. return data;
  103. }
  104. function test(){
  105. currentCommandIndex=1
  106. console.log(commands[currentCommandIndex],'test');
  107. }
  108. function sendCommand(cmd, data = []) {
  109. const startCmd = [0x02, 0x02]
  110. const endCmd = [0xAA, 0xAA]
  111. data = startCmd.concat(cmd).concat(endCmd)
  112. console.log(data,'打印是否切换正常模式');
  113. return data
  114. }
  115. function stateUpdate(device, deviceId) {
  116. return [sendCommand(0x04), sendCommand(0x02, FMBMS
  117. .BMSRead())]; //return [[0x02,0x00,0x15,0x15,0x00,0x4e,0x57,0x00,0x13,0x00,0x00,0x00,0x00,0x06,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x01,0x27,0x7b]]
  118. }
  119. function turnOn(device, deviceId) {
  120. return [sendCommand(0x02, FMBMS.BMSTurnOn())];
  121. }
  122. function turnOff(device, deviceId) {
  123. return [sendCommand(0x02, FMBMS.BMSTurnOff())];
  124. }
  125. function switchFactory(device, deviceId) {
  126. //切换正常,工厂模式指令
  127. //切换工厂模式 [[0x22,0x22,0x54,0x01,0x01,0x12,0xAA,0xAA]]
  128. //切换正常模式 [[0x22,0x22,0x54,0x01,0x00,0x15,0xAA,0xAA]]
  129. return [[0x22,0x22,0x54,0x01,0x01,0x12,0xAA,0xAA]]
  130. // return [sendCommand([0x54, 0x01, 0x01, 0x12])];
  131. }
  132. //升级按钮
  133. function otaUpgrade(device){
  134. const data = readBinBinarayToCommand()
  135. data.then(result=>{commands=result})
  136. // console.log(data,'datatest111');
  137. return data
  138. }
  139. async function readBinBinarayToCommand() {
  140. let res =await uni.request({
  141. url: 'https://opt.bms16.com/ota.BIN', // 文件的网络地址
  142. method: 'GET',
  143. responseType: 'arraybuffer', // 指定响应类型为 arraybuffer
  144. });
  145. const arrayBuffer=res[1].data
  146. const uint8Array = new Uint8Array(arrayBuffer); // 转换为 Uint8Array
  147. const test = splitArrayIntoChunks(uint8Array, 80); // 分割成长度为 80 的数组
  148. const data =makeArr(test)
  149. // const tests=data.slice(data.length-3)
  150. // console.log(data.length,tests[0],'testtest数组');
  151. // console.log(tests,'tests');
  152. return data
  153. }
  154. function sendNextCommand(mac_id) {
  155. console.log(commands[currentCommandIndex],'command');
  156. if (currentCommandIndex >= commands.length) {
  157. console.log('所有指令发送完成');
  158. return;
  159. }
  160. const deviceId = Object.keys(app.globalData.connectionState).find((i) => app.globalData.connectionState[i].device.mac_id == mac_id);
  161. if (deviceId == undefined) {
  162. console.log('deviceId == undefined');
  163. return ;
  164. }
  165. const command = [commands[currentCommandIndex]];
  166. if(command.length==0){
  167. return
  168. }
  169. // 将数据转换为ArrayBuffer类型
  170. var buffer;
  171. buffer = common.toArrayBuffer(command.shift());
  172. // console.log(command,'command');
  173. uni.writeBLECharacteristicValue({
  174. deviceId: deviceId, // 替换为实际的设备 ID
  175. serviceId: writeServiceID, // 替换为实际的服务 ID
  176. characteristicId: writeID, // 替换为可写入的特征值 ID
  177. value: buffer,
  178. success() {
  179. // console.log('指令发送成功,等待设备响应');
  180. },
  181. fail(err) {
  182. console.error('指令发送失败', err);
  183. }
  184. });
  185. currentCommandIndex++;
  186. }
  187. function splitArrayIntoChunks(array, chunkSize) {
  188. const numChunks = Math.ceil(array.length / chunkSize);
  189. return Array.from({ length: numChunks }, (_, i) => {
  190. return array.slice(i * chunkSize, (i + 1) * chunkSize);
  191. });
  192. }
  193. // 处理分割后的数组
  194. function makeArr(array) {
  195. const result = [];
  196. for (let i = 0; i < array.length; i ++) {
  197. let endPackage = 0x00
  198. if((i + 1) >= array.length){
  199. //当前是最后一次循环
  200. endPackage = 0x01
  201. }
  202. //协议号 30 包长度未固定array.length+8 转16进制 固件类型0x00 升级包大小(总包大小) 125396字节-》0x00,0x01,0xE9,0xD4
  203. let startArray = []
  204. const packageLen=parseInt((array[i].length+8).toString(16).toUpperCase(), 16)
  205. // const totalPackageSize=[0x00,0x00,0x01,0xE9,0xD4]
  206. const totalPackageSize=[0x00,0x00,0x01,0xE9,0xac]
  207. startArray.push(packageLen,...totalPackageSize)
  208. //软件包id
  209. const ids=splitNumber(i) // 0x00,0x01
  210. startArray.push(...ids)
  211. //是否为最后一个包
  212. startArray.push(endPackage)
  213. //软件数据包
  214. const formattedChunk = array[i].map(byte => `0x${byte.toString(16).padStart(2, '0')}`); // 转换为 0xXX 格式
  215. startArray.push(...formattedChunk)
  216. // if(i==2){
  217. // console.log(startArray,'startArraystartArray');
  218. // }
  219. //crc检验
  220. const crcStr='0x'+crc8IEEE8023(startArray).toString(16).toUpperCase()
  221. const testCrc=parseInt(crcStr,16)
  222. startArray.push(crcStr)
  223. // if(i==2){
  224. // console.log(startArray,crcStr,testCrc,'crcStr');
  225. // }
  226. startArray.push(0xAA,0xAA)
  227. startArray.unshift(0x22,0x22,0x30)
  228. result.push(startArray);
  229. }
  230. // 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])
  231. return result;
  232. }
  233. function splitNumber(num) {
  234. // 将数字转换为字符串
  235. const numStr = num.toString();
  236. // 使用正则表达式分割字符串为两位一组
  237. const parts = numStr.match(/.{1,2}/g) || [];
  238. // 将字符串数组转换为数字数组
  239. let result = parts.map(part => parseInt(part, 10));
  240. // 如果数组长度为 1,前面补一个 0
  241. if (result.length === 1) {
  242. result = [0, ...result];
  243. }
  244. return result;
  245. }
  246. function dataRecursion(subPackage){
  247. subIndex += 1
  248. let endPackage = 0x00
  249. if(subPackage.groupedArray.length - 1 == subIndex){
  250. endPackage = 0x01
  251. }
  252. // let startArray = [0x22,0x22,0x30, 0x30,0x00, 0x58,0x00]
  253. let startArray = [0x00,0x58,0x00]
  254. //包长度 固件类型到前一位 0x00,0x58 0x00
  255. //crc 包长度到crc前一位
  256. //升级包大小
  257. startArray = startArray.concat(decimalToHexBytes(subPackage.size,4))
  258. //软件包id
  259. startArray = startArray.concat(decimalToHexBytes(subIndex + 1,2))
  260. //是否为最后一个包
  261. startArray.push(endPackage)
  262. //软件数据包
  263. startArray = startArray.concat(subPackage.groupedArray[subIndex])
  264. //crc检验
  265. const crcStr=crc8IEEE8023(startArray)
  266. startArray.push(crcStr)
  267. startArray.unshift(0x22,0x22,0x30)
  268. startArray = startArray.concat([0xAA,0xAA])
  269. // console.log(startArray)
  270. return [startArray]
  271. }
  272. function arrayBufferToHexWithPrefix(buffer,groupSize = 80) {
  273. const uint8Array = new Uint8Array(buffer);
  274. const groupedArray = [];
  275. const size = uint8Array.length
  276. // 遍历数据,每 groupSize 个字节为一组
  277. for (let i = 0; i < size; i += groupSize) {
  278. const group = Array.from(uint8Array.slice(i, i + groupSize)) // 获取当前分组
  279. // .map(byte => '0x' + byte.toString(16).padStart(2, 0)); // 添加 0x 前缀
  280. groupedArray.push(group); // 将分组添加到结果中
  281. }
  282. return {
  283. size,
  284. groupedArray
  285. };
  286. }
  287. //进制转化
  288. function decimalToHexBytes(decimal,bytes){
  289. const maxValue = Math.pow(2, 8 * bytes) - 1;
  290. // 创建一个数组来存储字节
  291. const byteArray = new Array(bytes);
  292. // 将十进制数分解为字节
  293. for (let i = 0; i < bytes; i++) {
  294. // 每次取最低的8位(一个字节)
  295. byteArray[bytes - 1 - i] = decimal & 0xff;
  296. // 右移8位,处理下一个字节
  297. decimal >>>= 8;
  298. }
  299. return byteArray;
  300. }
  301. module.exports = {
  302. readServiceID: readServiceID,
  303. readID: readID,
  304. writeServiceID: writeServiceID,
  305. writeID: writeID,
  306. MTU: MTU,
  307. acceptDevice: acceptDevice,
  308. isDevice: isDevice,
  309. alterConnect: alterConnect,
  310. readData: readData,
  311. stateUpdate: stateUpdate,
  312. turnOn: turnOn,
  313. turnOff: turnOff,
  314. isSingleBt: isSingleBt,
  315. haveBms: haveBms,
  316. switchFactory: switchFactory,
  317. otaUpgrade
  318. };