bt_parse.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. import {
  2. BtCmd,
  3. CmdBase,
  4. CmdEarPhone,
  5. CmdRtc,
  6. // CmdRgb,
  7. CmdKwh,
  8. CmdKey,
  9. CmdVoice,
  10. CmdWeek
  11. } from './bt_cmd';
  12. import {
  13. CmdEvent,
  14. EnumCmdEvent,
  15. EnumPlayStatus,
  16. EnumSupplier
  17. } from '../cmd_key_event';
  18. import EventManager from '../../utils/event_bus'
  19. class BtParse {
  20. // 型号名称
  21. // static mateX2 = "MW-Mate X(4G_WIFI)";
  22. // static matePVX = "猫王音响·Mate_PVX";
  23. // static matePVXL = "猫王音响·Mate_PVXL";
  24. // 防止收到另外的消息
  25. static isReceiveCmd = false;
  26. // 如果10ms内获取两个一模一样的就删除一个
  27. static lastCmd = null;
  28. static lastTime = null;
  29. constructor() { }
  30. // 解析命令
  31. static parseTLV(cmd) {
  32. console.log("gadsfasdfadfaf===惺惺相惜==" + cmd);
  33. BtCmd.printTLV(cmd, false);
  34. // todo 在线
  35. // if (!PlayDevice.isOnline) {
  36. // return;
  37. // }
  38. // if (!BtParse.isReceiveCmd) {
  39. // return;
  40. // }
  41. if (cmd.length > 5) {
  42. // 指令类别
  43. const type = cmd[6];
  44. if (cmd.length < 9) {
  45. // 杰里、领芯的语音控制指令
  46. BtParse._voiceCmd(cmd);
  47. } else {
  48. // cmd[7]为命令长度
  49. // 命令类型
  50. const value = cmd[8];
  51. // 第二部分走杰理
  52. if (type === CmdVoice.jlReceiveVoiceData) {
  53. BtParse._receiveRecordData(cmd);
  54. }
  55. // 查询版本号后校验设备
  56. else if (type === CmdBase.queryVersion) {
  57. const version = CmdBase.parseVersion(value);
  58. EventManager.fire(CmdEvent.version({ version }));
  59. EventManager.fire(CmdEvent.getDeviceInfo());
  60. } else if (BtParse._getDataHeader(cmd)) {
  61. // 控制指令
  62. BtParse._controlCmd(cmd);
  63. } else {
  64. // console.log("收到不明指令:", cmd);
  65. const manufacturer = "";
  66. // DeviceManager.instance.device?.manufacturer ?? "";
  67. // 山景的语音判断
  68. // if (manufacturer === EnumSupplier.shanJing) {
  69. // const sjCmd = cmd[4];
  70. // if (sjCmd === CmdVoice.sjStartVoice) {
  71. // BtParse._startRecord(EnumSupplier.shanJing);
  72. // } else if (sjCmd === CmdVoice.sjStopVoice) {
  73. // BtParse._stopRecord(EnumSupplier.shanJing);
  74. // }
  75. // // 山景的都要走接收数据
  76. // BtParse._receiveRecordData(cmd);
  77. // } else {
  78. // // b1耳机、领芯、杰里p2第二部分语音数据直接走这里
  79. // BtParse._receiveRecordData(cmd);
  80. // }
  81. }
  82. }
  83. }
  84. }
  85. static _send(cmdEvent) {
  86. EventManager.fire(CmdEvent[cmdEvent]);
  87. }
  88. static _getDataHeader(cmd) {
  89. if (cmd.length < 4) {
  90. return false;
  91. }
  92. ["54", "44", "44", "48", "1", "9", "22", "1", "4"]
  93. const header = [0x54, 0x44, 0x44, 0x48];
  94. let isCmd = cmd[0] === header[0] && cmd[1] === header[1] && cmd[2] === header[2] && cmd[3] === header[3];
  95. // console.log("收到数据头:", cmd[0], header[0], cmd[1], header[1], cmd[2], header[2], cmd[3], header[3],);
  96. return isCmd;
  97. }
  98. // todo 暂时不要
  99. static _voiceCmd(cmd) {
  100. const type = cmd[6];
  101. console.log("收到语音指令:", cmd);
  102. // switch (type) {
  103. // // 杰理语音开始
  104. // case CmdVoice.jlStartVoice:
  105. // BtParse._startRecord(EnumSupplier.jieLi);
  106. // break;
  107. // // 杰理结束
  108. // case CmdVoice.jlStopVoice:
  109. // BtParse._stopRecord(EnumSupplier.jieLi);
  110. // break;
  111. // // 发给插件
  112. // case CmdVoice.jlReceiveVoiceData:
  113. // console.log("发送杰里的p1语音:没有进来过,不走这里的,直接判断0x70 && jieLi");
  114. // BtParse._receiveRecordData(cmd);
  115. // break;
  116. // // 领心语音开始
  117. // case CmdVoice.lxStartVoice:
  118. // BtParse._startRecord(EnumSupplier.lingXin);
  119. // break;
  120. // // 领心语音结束
  121. // case CmdVoice.lxStopVoice:
  122. // BtParse._stopRecord(EnumSupplier.lingXin);
  123. // break;
  124. // default:
  125. // console.log("发送语音:默认发送,不走这里", cmd);
  126. // break;
  127. // }
  128. }
  129. static async _startRecord(supplier) {
  130. console.log("StartVoice======语音开始", supplier);
  131. }
  132. static async _stopRecord(supplier) {
  133. console.log("stopRecord======语音结束", supplier);
  134. }
  135. // 杰理接收设备第二部分 发送给插件
  136. static _receiveRecordData(cmd) {
  137. // todo 暂时不要
  138. // RecordVoiceManager.sendDataToPlugin(cmd);
  139. }
  140. static async _controlCmd(cmd) {
  141. const type = cmd[6];
  142. const value = cmd[8];
  143. // mqttAddDebugCmd("收到蓝牙指令:" + cmd);
  144. // console.log("收到控制指令:", cmd, type)
  145. switch (type) {
  146. // 校验设备
  147. case CmdBase.checkDeviceSuccess:
  148. case CmdBase.checkDevice:
  149. // [84, 68, 68, 72, 1, 17, 40, 9, 115, 109, 97, 114, 116, 95, 65, 50, 70]
  150. break;
  151. // 按键 短按、长按等
  152. case CmdKey.type:
  153. // IOS的不要了
  154. // if (DeviceUtil.isIOS) {
  155. // if (BtParse.lastCmd && JSON.stringify(BtParse.lastCmd) === JSON.stringify(cmd)) {
  156. // if (BtParse.lastTime) {
  157. // const curTime = TimeUtil.getCurrentMillis();
  158. // if (curTime - BtParse.lastTime < 5) {
  159. // return;
  160. // }
  161. // }
  162. // }
  163. // BtParse.lastCmd = cmd;
  164. // BtParse.lastTime = TimeUtil.getCurrentMillis();
  165. // }
  166. let t = 0;
  167. if (cmd.length > 9) {
  168. t = cmd[9];
  169. }
  170. switch (t) {
  171. // 0x54 44 44 48 01 0a 21 02 01 02
  172. // 54, 44, 44, 48, 1, a, 21, 2, 1(value), 2(type)
  173. // 上一曲
  174. case CmdKey.previousSong:
  175. BtParse._send(EnumCmdEvent.previousSong);
  176. break;
  177. // 下一曲
  178. case CmdKey.nextSong:
  179. BtParse._send(EnumCmdEvent.nextSong);
  180. break;
  181. // 上一频道
  182. case CmdKey.previousChannel:
  183. BtParse._send(EnumCmdEvent.previousChannel);
  184. break;
  185. // 下一频道
  186. case CmdKey.nextChannel:
  187. BtParse._send(EnumCmdEvent.nextChannel);
  188. break;
  189. // 0x02 2
  190. case CmdKey.pressShort:
  191. // 1 下一个频道
  192. if (value === CmdKey.next) {
  193. BtParse._send(EnumCmdEvent.nextChannel);
  194. }
  195. // 2 上一个频道
  196. else if (value === CmdKey.previous) {
  197. BtParse._send(EnumCmdEvent.previousChannel);
  198. }
  199. // 3 单击下一个专辑 或者下一曲
  200. else if (value === CmdKey.changeProgram) {
  201. // if (ProviderUtil.device.mDevice?.clientType === BtParse.mateX2) {
  202. // BtParse._send(EnumCmdEvent.nextAlbum);
  203. // } else {
  204. // BtParse._send(EnumCmdEvent.nextSong);
  205. // }
  206. }
  207. break;
  208. // 0x09 9
  209. case CmdKey.pressDouble:
  210. // 1 双击下一曲
  211. if (value === CmdKey.next) {
  212. BtParse._send(EnumCmdEvent.nextSong);
  213. }
  214. // 2 双击上一曲
  215. else if (value === CmdKey.previous) {
  216. BtParse._send(EnumCmdEvent.previousSong);
  217. }
  218. // 3 单击上一专辑或者上一曲
  219. else if (value === CmdKey.changeProgram) {
  220. // todo
  221. // if (ProviderUtil.device.mDevice?.clientType === BtParse.mateX2) {
  222. // BtParse._send(EnumCmdEvent.previousAlbum);
  223. // } else {
  224. // BtParse._send(EnumCmdEvent.previousSong);
  225. // }
  226. }
  227. break;
  228. // 0x08 8
  229. case CmdKey.pressLong:
  230. if (value === CmdKey.previous) {
  231. console.log("快退");
  232. BtParse._send(EnumCmdEvent.fastback);
  233. } else if (value === CmdKey.next) {
  234. console.log("快进");
  235. BtParse._send(EnumCmdEvent.speed);
  236. }
  237. break;
  238. // 0x04 4
  239. case CmdKey.pressLongUp:
  240. if (value === CmdKey.previous) {
  241. console.log("停止快退");
  242. BtParse._send(EnumCmdEvent.stopFastback);
  243. } else if (value === CmdKey.next) {
  244. console.log("停止快进");
  245. BtParse._send(EnumCmdEvent.stopSpeed);
  246. } else if (value === CmdKey.pressLongUp) {
  247. // [54, 44, 44, 48, 1, a, 21, 2, 4, 4]
  248. console.log("录音结束");
  249. BtParse._send(EnumCmdEvent.stopRecord);
  250. }
  251. break;
  252. }
  253. BtHelper.instance.changeChannelCallBack();
  254. break;
  255. // 音量 54 44 44 48 1 a 32 2 b 0
  256. case CmdBase.queryVolume:
  257. // 手机最大音量 需要获取
  258. const phoneMax = 15;
  259. // todo 音量
  260. //await VolumeUtil.getMaxVolume();
  261. const max = CmdBase.volumeMax;
  262. const d = phoneMax / max;
  263. const result = (d * value).toFixed(2);
  264. var trueVolume = parseFloat(result) ?? 0;
  265. console.log("trueVolume=====", max, "===", d, ",,,,", value, ",,,,", result, ",,,,", trueVolume);
  266. if (trueVolume > phoneMax) {
  267. trueVolume = phoneMax;
  268. }
  269. // 仅用于记录设备音量,播控页面显示用
  270. EventManager.fire(CmdEvent.volume({ volume: trueVolume }));
  271. // if (DeviceUtil.isAndroid) {
  272. // const name = "";
  273. // // todo
  274. // // DeviceManager.instance.name;
  275. // if (name === "猫王·霹雳唱机") {
  276. // // VolumeUtil.setVolume(trueVolume);
  277. // }
  278. // }
  279. break;
  280. // 查询电量
  281. case CmdKwh.queryKwh:
  282. EventManager.fire(CmdEvent.battery({ kwh: value }));
  283. break;
  284. // 自动播放 54, 44, 44, 48, 1, 9, 24, 1, 1
  285. case CmdBase.getAutoPlay:
  286. case CmdBase.setAutoPlay:
  287. setTimeout(() => {
  288. EventManager.fire(CmdEvent.playStatus({
  289. playStatus: value === EnumOpen.open ? EnumPlayStatus.play : EnumPlayStatus.pause,
  290. }));
  291. }, 300);
  292. break;
  293. // 查询低电量设置
  294. case CmdKwh.queryLowKwhWarningTone:
  295. EventManager.fire(CmdEvent.queryLowKwn({ kwh: value }));
  296. break;
  297. // 耳机电量 index0 :左耳机, index1:左耳机 ,index2: 充电盒。value: 0-9代表10-100% 获取不到用-1
  298. // [54, 44, 44, 48, 1, b, b1, 3, 8, 8, 2]
  299. case CmdEarPhone.queryEarPhoneKwh:
  300. const rightKwh = cmd[9];
  301. const boxKwh = cmd[10];
  302. let kwh = 0;
  303. if (value > 0 && rightKwh > 0) {
  304. kwh = Math.min(value, rightKwh);
  305. } else {
  306. kwh = Math.max(value, rightKwh);
  307. }
  308. EventManager.fire(CmdEvent.batteryEarphone({
  309. kwhLeft: value,
  310. kwhBox: boxKwh,
  311. kwhRight: rightKwh,
  312. kwh: kwh,
  313. }));
  314. break;
  315. // EQ [84, 68, 68, 72, 1, 18, 180, 10, 0, 0, 240, 237, 236, 0, 236, 0, 0, 0]
  316. // B5耳机获取EQ
  317. case CmdEarPhone.queryEQ:
  318. if (cmd.length > 15) {
  319. const result = cmd.slice(8, cmd.length);
  320. const list = result.map(element => parseInt(element, 16));
  321. console.log("eq==============", list);
  322. EventManager.fire(CmdEvent.eqs({ eqs: list }));
  323. }
  324. break;
  325. // 低延迟 [54, 44, 44, 48, 1, a, b2, 2, 0, 2]
  326. case CmdEarPhone.queryLowDelayMode:
  327. const lowDelayMode = cmd[9];
  328. EventManager.fire(CmdEvent.lowDelayMode({ lowDelayMode, lowDelayModeOpen: value }));
  329. break;
  330. // 耳机低电量
  331. case CmdEarPhone.queryLowPower:
  332. const lowPowerOpen = cmd[8];
  333. EventManager.fire(CmdEvent.lowPowerOpen({ lowPowerOpen }));
  334. break;
  335. // 查询唤醒闹钟
  336. case CmdRtc.queryAlarm:
  337. const wakeSwitch = cmd[8];
  338. if (cmd.length > 9) {
  339. const week = cmd[9];
  340. const hour = cmd[10];
  341. const minutes = cmd[11];
  342. const wakeCycle = CmdWeek.cmd2Week(week);
  343. console.log("queryAlarm=====", wakeSwitch, "=", wakeCycle);
  344. EventManager.fire(CmdEvent.wake({
  345. wakeSwitch,
  346. wakeCycle,
  347. wakeHour: hour,
  348. wakeMinutes: minutes,
  349. }));
  350. }
  351. break;
  352. // 查询自动休眠状态
  353. case CmdRtc.querySleepAfterPlayPause:
  354. case CmdRtc.setSleepAfterPlayPause:
  355. {
  356. let hour = cmd[8] ?? 0;
  357. let minutes = cmd[9] ?? 0;
  358. var seconds = cmd[10] ?? 0;
  359. console.log("hour=====", hour, "minutes=====", minutes, "seconds=====", seconds)
  360. hour = hour > 24 ? 0 : hour;
  361. minutes = minutes > 60 ? 0 : minutes;
  362. seconds = seconds > 60 ? 0 : seconds;
  363. let allSeconds = hour * 3600 + minutes * 60 + seconds;
  364. // [84, 68, 68, 72, 1, 12, 90, 4, 0, 14, 0, 72]
  365. EventManager.fire(CmdEvent.pauseSleep({ pauseSleep: allSeconds }));
  366. }
  367. break;
  368. // 查询休眠
  369. case CmdRtc.querySleep:
  370. const sleepSwitch = cmd[8];
  371. const hour = cmd[9];
  372. const minutes = cmd[10];
  373. const leftHour = cmd[11];
  374. const leftMinutes = cmd[12];
  375. EventManager.fire(CmdEvent.sleep({
  376. sleepSwitch,
  377. sleepHour: hour,
  378. sleepMinutes: minutes,
  379. }));
  380. break;
  381. // 开始录音
  382. case CmdVoice.startVoice:
  383. console.log("没有意义的开始录音");
  384. // _send(EnumCmdEvent.startRecord);
  385. break;
  386. // 查询 耳机手势
  387. case CmdEarPhone.queryCtrlStatus:
  388. const singleC = cmd[8];
  389. const doubleC = cmd[9];
  390. const longC = cmd[10];
  391. EventManager.fire(CmdEvent.ctrlStatus({ ctrlStatus: [singleC, doubleC, longC] }));
  392. break;
  393. case CmdBase.getMac:
  394. {
  395. var values = ""
  396. // [54:44:44:48:01:0D:35:90:9D:99:CF:34:5B:]
  397. for (let i = 7; i < cmd.length; i++) {
  398. values += cmd[i].toString(16);
  399. if (i != cmd.length - 1) {
  400. values += ":";
  401. }
  402. }
  403. // let str = this.hexArrayToString(values);
  404. // getMac===== ?MV-SR1(4G_WIFI)
  405. // let device = getApp().globalData.mDeviceList[0] ?? {};
  406. // device["mac"] = values;
  407. console.log("getMac=====", values)
  408. EventManager.fire(CmdEvent.btMac({ "btMac": values }));
  409. }
  410. // [84, 68, 68, 72, 1, 23, 53, 16, 77, 86, 45, 83, 82, 49, 40, 52, 71, 95, 87, 73, 70, 73, 41]
  411. break;
  412. case CmdBase.getClientType:
  413. {
  414. var values = []
  415. for (let i = 8; i < cmd.length; i++) {
  416. values.push(cmd[i]);
  417. }
  418. let str = this.hexArrayToString(values);
  419. let device = getApp().globalData.mDeviceList[0] ?? {};
  420. device["trueClientType"] = str;
  421. console.log("getClientType=====", device)
  422. EventManager.fire(CmdEvent.clientType(str));
  423. }
  424. //  [84, 68, 68, 72, 1, 14, 49, 7, 228, 159, 128, 9, 224, 236]
  425. break;
  426. case CmdBase.getIsConnect:
  427. // [84, 68, 68, 72, 1, 10, 54, 2, 0, 1]
  428. let device = getApp().globalData.mDeviceList[0] ?? {};
  429. device["isConnectMac"] = value;
  430. console.log("getIsConnect=====", device)
  431. break;
  432. case CmdBase.heiJiaoOta:
  433. // [54:44:44:48:01:0A:74:01:01:00]
  434. {
  435. let kind = cmd[9]
  436. EventManager.fire(CmdEvent.otaCmd({ value: value, kind: kind }));
  437. }
  438. break;
  439. case CmdBase.heijiaoBackImg:
  440. // 0x76
  441. {
  442. let kind = cmd[9]
  443. EventManager.fire(CmdEvent.otaWifi({ value: value, kind: kind }));
  444. }
  445. break;
  446. case CmdBase.wallPaper:
  447. // [54:44:44:48:01:0A:78:01:01:00]
  448. {
  449. let kind = cmd[9]
  450. EventManager.fire(CmdEvent.wallpaper({ value: value, kind: kind }));
  451. }
  452. break;
  453. case CmdBase.wallPaperData:
  454. // [54:44:44:48:01:0A:78:01:01:00]
  455. {
  456. let kind = cmd[9]
  457. EventManager.fire(CmdEvent.wallPaperData({ value: value, kind: kind }));
  458. }
  459. break;
  460. case CmdBase.heiJiaoOtaData:
  461. //0x75
  462. {
  463. let kind = cmd[9]
  464. EventManager.fire(CmdEvent.otaUrl({ value: value, kind: kind }));
  465. }
  466. break;
  467. case CmdBase.wallPaperMD5:
  468. //0x80
  469. {
  470. let kind = cmd[9]
  471. EventManager.fire(CmdEvent.wallPaperMD5({ value: value, kind: kind }));
  472. }
  473. break;
  474. default:
  475. console.log("接收到语音:", cmd);
  476. // _receiveRecordData(cmd);
  477. break;
  478. }
  479. }
  480. static hexArrayToString(hexArray) {
  481. let str = '';
  482. for (let i = 0; i < hexArray.length; i++) {
  483. const charCode = hexArray[i];
  484. if (charCode >= 32 && charCode <= 126) { // 可打印的ASCII字符范围
  485. str += String.fromCharCode(charCode);
  486. } else {
  487. str += '?'; // 替换为问号或其他符号
  488. }
  489. }
  490. return str;
  491. }
  492. static ab2hex(buffer) {
  493. var hexArr = Array.prototype.map.call(
  494. new Uint8Array(buffer),
  495. function (bit) {
  496. return ('00' + bit.toString(16)).slice(-2)
  497. }
  498. )
  499. return hexArr.join(':');
  500. }
  501. }
  502. // 导出类
  503. module.exports = BtParse;