BluetoothAim_SDK.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using ArduinoBluetoothAPI;
  6. using System.Linq;
  7. namespace SmartBowSDK
  8. {
  9. public class BluetoothAim_SDK : MonoBehaviour
  10. {
  11. public SmartBowHelper smartBowHelper;
  12. public BluetoothDeviceConfig deviceConfig;
  13. private BluetoothHelper _bluetoothHelper;
  14. private BluetoothHelperService _bluetoothService;
  15. private BluetoothHelperCharacteristic _characteristicWrite;
  16. private static HashSet<object> _ScanLocker = new HashSet<object>();
  17. private int _receivedDataCount = 0;
  18. public string macAddress = null;
  19. //设备固件版本
  20. public string deviceVersion = null;
  21. public BluetoothStatusEnum bluetoothStatus;
  22. private BluetoothWindows _bluetoothWindows;
  23. /// <summary>
  24. /// 6轴
  25. /// </summary>
  26. private o06DOF.SixAxisFusion sixAxisFusion;
  27. /// <summary>
  28. /// 过滤名称
  29. /// </summary>
  30. public string filters { get; set; } = "";
  31. /// <summary>
  32. /// 是否使用mac过滤
  33. /// </summary>
  34. public bool isConnectName { get; set; } = true;//默认用名字连接
  35. /// <summary>
  36. /// 传入的mac
  37. /// </summary>
  38. public string connectMacStr { get; set; } = "";
  39. /// <summary>
  40. /// 当前的传感器类型
  41. /// </summary>
  42. public SensorAxisType sensorAxisType { get; set; } = SensorAxisType.NineAxisSensor;
  43. private void SetStatus(BluetoothStatusEnum newStatus)
  44. {
  45. BluetoothStatusEnum oldStatus = bluetoothStatus;
  46. if (oldStatus == newStatus) return;
  47. bluetoothStatus = newStatus;
  48. SmartBowLogger.Log(this, $" oldStatus:[{oldStatus}]=> newStatus:[{newStatus}]");
  49. if (newStatus == BluetoothStatusEnum.None)
  50. {
  51. _bluetoothHelper = null;
  52. _bluetoothService = null;
  53. _characteristicWrite = null;
  54. _receivedDataCount = 0;
  55. macAddress = null;
  56. deviceVersion = null;
  57. _battery = 0;
  58. moduleInited = false;
  59. }
  60. smartBowHelper.InvokeOnBluetoothStatusChanged(oldStatus, newStatus);
  61. }
  62. void Awake()
  63. {
  64. DontDestroyOnLoad(gameObject);
  65. deviceConfig = BluetoothDeviceConfig.GetDefault();
  66. }
  67. void Update()
  68. {
  69. LoopHandleCommands();
  70. }
  71. private static int _NoneToConnectingStep = 0;
  72. public BluetoothWindows CreateWindowBLE() {
  73. //如果是window环境,直接实例化一个BluetoothWindows
  74. if (BluetoothWindows.IsWindows())
  75. {
  76. _bluetoothWindows = new BluetoothWindows();
  77. _bluetoothWindows.OnScanEnded = OnScanEnded_windows;
  78. _bluetoothWindows.OnConnected = OnConnected_windows;
  79. _bluetoothWindows.OnConnectionFailed = OnConnectionFailed_windows;
  80. _bluetoothWindows.OnCharacteristicChanged = OnCharacteristicChanged_windows;
  81. return _bluetoothWindows;
  82. }
  83. return null;
  84. }
  85. public void Connect()
  86. {
  87. if (BluetoothWindows.IsWindows())
  88. {
  89. if (bluetoothStatus == BluetoothStatusEnum.None)
  90. {
  91. //windos连接触发蓝牙
  92. _bluetoothWindows.Connect();
  93. SetStatus(BluetoothStatusEnum.Connecting);
  94. //初始化一次六轴解析
  95. if (sensorAxisType == SensorAxisType.SixAxisSensor && sixAxisFusion == null)
  96. {
  97. Vector3 accelOffset = Vector3.zero;
  98. Vector3 gyroOffset = Vector3.zero;
  99. float gForce = 1.0f;
  100. float gyroToDegree = 1.0f;
  101. sixAxisFusion = new o06DOF.SixAxisFusion(accelOffset, gyroOffset, gForce, gyroToDegree);
  102. }
  103. }
  104. return;
  105. }
  106. if (_ScanLocker.Count > 0) return;
  107. if (bluetoothStatus != BluetoothStatusEnum.None) return;
  108. if (_NoneToConnectingStep > 0) return;
  109. _NoneToConnectingStep = 1;
  110. if (Application.platform == RuntimePlatform.Android)
  111. {
  112. if (!BluetoothHelperAndroid_SDK.IsBluetoothEnabled())
  113. {
  114. HandleConnectError(BluetoothError.BluetoothNotEnabled, "蓝牙开关未打开");
  115. return;
  116. }
  117. if (BluetoothHelperAndroid_SDK.RequestBluetoothPermissions(() =>
  118. {
  119. _NoneToConnectingStep = 0;
  120. Connect();
  121. }, (permission) =>
  122. {
  123. if (permission.Contains("LOCATION"))
  124. {
  125. HandleConnectError(BluetoothError.LocationPermissionNotGranted, "尚未授予定位权限");
  126. }
  127. else if (permission.Contains("BLUETOOTH"))
  128. {
  129. HandleConnectError(BluetoothError.ScanPermissionNotGranted, "尚未授予扫描附近设备权限");
  130. }
  131. })) return;
  132. }
  133. try
  134. {
  135. BluetoothHelper.BLE = true;
  136. _bluetoothHelper = BluetoothHelper.GetNewInstance();
  137. _bluetoothHelper.OnConnected += OnConnected;
  138. _bluetoothHelper.OnConnectionFailed += OnConnectionFailed;
  139. SmartBowLogger.Log(this,"创建蓝牙的SensorAxisType类型:"+ sensorAxisType);
  140. if (sensorAxisType == SensorAxisType.SixAxisSensor)
  141. {
  142. //6轴时候,另外的解析操作
  143. _bluetoothHelper.OnCharacteristicChanged += OnCharacteristicChanged6Axis;
  144. //初始化一次六轴解析
  145. if (sixAxisFusion == null) {
  146. Vector3 accelOffset = Vector3.zero;
  147. Vector3 gyroOffset = Vector3.zero;
  148. float gForce = 1.0f;
  149. float gyroToDegree = 1.0f;
  150. sixAxisFusion = new o06DOF.SixAxisFusion(accelOffset, gyroOffset, gForce, gyroToDegree);
  151. }
  152. }
  153. else {
  154. //九轴的解析
  155. _bluetoothHelper.OnCharacteristicChanged += OnCharacteristicChanged;
  156. }
  157. _bluetoothHelper.OnScanEnded += OnScanEnded;
  158. _bluetoothHelper.ScanNearbyDevices();
  159. _NoneToConnectingStep = 2;
  160. }
  161. catch (Exception e)
  162. {
  163. HandleConnectError(BluetoothError.Unknown, e.ToString());
  164. }
  165. if (_NoneToConnectingStep == 2)
  166. {
  167. _NoneToConnectingStep = 0;
  168. _ScanLocker.Add(_bluetoothHelper);
  169. SetStatus(BluetoothStatusEnum.Connecting);
  170. }
  171. }
  172. private void HandleConnectError(BluetoothError error, string message)
  173. {
  174. _NoneToConnectingStep = 0;
  175. smartBowHelper.InvokeOnBluetoothError(error, message);
  176. }
  177. public void Disconnect()
  178. {
  179. //断开连接时候清除AimDeviceInfo
  180. ResetAimDeviceInfoToNull();
  181. if (BluetoothWindows.IsWindows())
  182. {
  183. if (_bluetoothWindows.Disconnect())
  184. SetStatus(BluetoothStatusEnum.None);
  185. return;
  186. }
  187. if (_bluetoothHelper != null)
  188. _bluetoothHelper.Disconnect();
  189. SetStatus(BluetoothStatusEnum.None);
  190. }
  191. void OnConnected(BluetoothHelper helper)
  192. {
  193. if (helper != _bluetoothHelper) return;
  194. SetStatus(BluetoothStatusEnum.Connected);
  195. foreach (BluetoothHelperService service in helper.getGattServices())
  196. {
  197. if (service.getName().ToLower().StartsWith(deviceConfig.service))
  198. {
  199. _bluetoothService = service;
  200. foreach (BluetoothHelperCharacteristic characteristic in service.getCharacteristics())
  201. {
  202. if (characteristic.getName().ToLower().StartsWith(deviceConfig.characteristicWrite))
  203. {
  204. _characteristicWrite = characteristic;
  205. }
  206. else if (characteristic.getName().ToLower().StartsWith(deviceConfig.characteristicNotify))
  207. {
  208. BluetoothHelperCharacteristic c = new BluetoothHelperCharacteristic(characteristic.getName());
  209. c.setService(_bluetoothService.getName());
  210. _bluetoothHelper.Subscribe(c);
  211. }
  212. }
  213. }
  214. }
  215. //指令区分
  216. if (sensorAxisType == SensorAxisType.SixAxisSensor)
  217. {
  218. //6轴指令
  219. StartCoroutine(InitWhenConnected6Axis());
  220. }
  221. else
  222. {
  223. //九轴
  224. StartCoroutine(InitWhenConnected());
  225. }
  226. }
  227. void OnConnected_windows()
  228. {
  229. SetStatus(BluetoothStatusEnum.Connected);
  230. if (sensorAxisType == SensorAxisType.SixAxisSensor)
  231. {
  232. //6轴指令
  233. StartCoroutine(InitWhenConnected6Axis());
  234. }
  235. else
  236. {
  237. //九轴
  238. StartCoroutine(InitWhenConnected());
  239. }
  240. }
  241. void OnConnectionFailed(BluetoothHelper helper)
  242. {
  243. if (helper != _bluetoothHelper) return;
  244. SetStatus(BluetoothStatusEnum.None);
  245. }
  246. void OnConnectionFailed_windows()
  247. {
  248. SetStatus(BluetoothStatusEnum.None);
  249. }
  250. /// <summary>
  251. /// 原九轴的传感器解析
  252. /// </summary>
  253. /// <param name="helper"></param>
  254. /// <param name="value"></param>
  255. /// <param name="characteristic"></param>
  256. void OnCharacteristicChanged(BluetoothHelper helper, byte[] value, BluetoothHelperCharacteristic characteristic)
  257. {
  258. if (helper != _bluetoothHelper) return;
  259. if (bluetoothStatus != BluetoothStatusEnum.Connected) return;
  260. byte[] bytes = value;
  261. if (_receivedDataCount++ < 500) { //旧的逻辑
  262. if (macAddress == null) ParseMacAddress(value);
  263. //固件版本号
  264. if (deviceVersion == null) ParseDeviceVersion(value);
  265. }
  266. smartBowHelper.aimHandler.OnDataReceived(bytes);
  267. }
  268. /// <summary>
  269. /// 六轴传感器时候使用的解析
  270. /// </summary>
  271. /// <param name="helper"></param>
  272. /// <param name="value"></param>
  273. /// <param name="characteristic"></param>
  274. void OnCharacteristicChanged6Axis(BluetoothHelper helper, byte[] value, BluetoothHelperCharacteristic characteristic)
  275. {
  276. if (helper != _bluetoothHelper) return;
  277. if (bluetoothStatus != BluetoothStatusEnum.Connected) return;
  278. byte[] bytes = value;
  279. if (macAddress == null && _receivedDataCount++ < 500) ParseMacAddress(value);
  280. //smartBowHelper.aimHandler.OnDataReceived(bytes);
  281. //转字符串后就是 Bat
  282. if (bytes.Length == 20 && bytes[19] == 0x0a
  283. //Bat
  284. && bytes[2] == 0x42 && bytes[3] == 0x61 && bytes[4] == 0x74) {
  285. //第一步 解析电量?
  286. string betty = System.Text.Encoding.ASCII.GetString(bytes);
  287. // SmartBowLogger.Log(this, BitConverter.ToString(bytes).Replace("-", ""));
  288. //SmartBowLogger.Log(this, "betty:" + betty);
  289. // 第二步:解析JSON字符串
  290. Newtonsoft.Json.Linq.JObject json = Newtonsoft.Json.Linq.JObject.Parse(betty);
  291. // 第三步:提取"Bat"的值
  292. int batValue = (int)json["Bat"];
  293. SmartBowLogger.Log(this, "Bat Value: " + batValue); // 输出: 100
  294. battery = batValue;
  295. }
  296. //传感器数据
  297. if (bytes.Length == 20 && bytes[0] == 0x7b && bytes[19] == 0x7d)
  298. {
  299. o06DOF.SixData sixData = sixAxisFusion.getSixAxisByBytes(bytes);
  300. Quaternion quaternion = sixAxisFusion.tranUpdateData(sixData);
  301. //输出欧拉角 pitch yaw roll
  302. smartBowHelper.InvokeOnSixAxisRotationUpdate(quaternion.eulerAngles);
  303. //smartBowHelper.InvokeOnAxisDataUpdateEvent(bytes);
  304. }
  305. }
  306. /// <summary>
  307. /// 重置6轴identify
  308. /// </summary>
  309. public void ResetSixAxisFusion() {
  310. if (sixAxisFusion != null) {
  311. sixAxisFusion.ResetToInitialRotation();
  312. }
  313. }
  314. /// <summary>
  315. /// pc调用
  316. /// </summary>
  317. /// <param name="deviceId"></param>
  318. /// <param name="value"></param>
  319. void OnCharacteristicChanged_windows(string deviceId, byte[] value)
  320. {
  321. if (sensorAxisType == SensorAxisType.SixAxisSensor)
  322. {
  323. //6轴指令
  324. OnCharacteristicChanged6Axis(null, value, null);
  325. }
  326. else
  327. {
  328. //九轴
  329. OnCharacteristicChanged(null, value, null);
  330. }
  331. }
  332. void OnScanEnded(BluetoothHelper helper, LinkedList<BluetoothDevice> nearbyDevices)
  333. {
  334. _ScanLocker.Remove(helper);
  335. if (helper != _bluetoothHelper) return;
  336. foreach (BluetoothDevice device in nearbyDevices)
  337. {
  338. if (isConnectName)
  339. {
  340. //if (device.DeviceName == deviceConfig.deviceName)
  341. //后续匹配名字 可以是多个设备
  342. string _filters = string.IsNullOrEmpty(filters) ? deviceConfig.deviceName : filters;
  343. SmartBowLogger.Log(this, $"发现设备{device.DeviceName},is fileters empty:{ string.IsNullOrEmpty(filters)},current filters:{_filters}");
  344. //if (_filters.Contains(device.DeviceName))
  345. //{
  346. // _bluetoothHelper.setDeviceName(device.DeviceName);
  347. // _bluetoothHelper.Connect();
  348. // SmartBowLogger.Log(this, $"Name匹配设备{device.DeviceName}");
  349. // return;
  350. //}
  351. // 精确匹配,大小写敏感,多设备名字用 " | " 分隔
  352. string[] filterArray = _filters.Split('|'); // 支持多个名字
  353. foreach (var f in filterArray)
  354. {
  355. string trimmedFilter = f.Trim();
  356. if (string.Equals(trimmedFilter, device.DeviceName.Trim(), StringComparison.OrdinalIgnoreCase))
  357. {
  358. _bluetoothHelper.setDeviceName(device.DeviceName);
  359. _bluetoothHelper.Connect();
  360. SmartBowLogger.Log(this, $"Name匹配设备 {device.DeviceName}");
  361. return;
  362. }
  363. }
  364. }
  365. else
  366. {
  367. SmartBowLogger.Log(this, $"发现设备 {device.DeviceAddress},is connectMacStr:{ connectMacStr },DeviceAddress:{device.DeviceAddress}");
  368. // 统一格式化:去掉非十六进制字符,转大写
  369. string FormatMac(string mac) =>
  370. string.Concat(mac.Where(c => Uri.IsHexDigit(c))).ToUpper();
  371. string deviceMac = FormatMac(device.DeviceAddress);
  372. string targetMac = FormatMac(connectMacStr);
  373. if (targetMac.Contains(deviceMac))
  374. {
  375. _bluetoothHelper.setDeviceName(device.DeviceName);
  376. _bluetoothHelper.setDeviceAddress(device.DeviceAddress);
  377. _bluetoothHelper.Connect();
  378. SmartBowLogger.Log(this, $"Mac匹配设备{device.DeviceAddress}");
  379. return;
  380. }
  381. //按mac地址匹配
  382. //if (connectMacStr.Contains(device.DeviceAddress))
  383. //{
  384. // _bluetoothHelper.setDeviceName(device.DeviceName);
  385. // _bluetoothHelper.setDeviceAddress(device.DeviceAddress);
  386. // _bluetoothHelper.Connect();
  387. // SmartBowLogger.Log(this, $"Mac匹配设备{device.DeviceAddress}");
  388. // return;
  389. //}
  390. }
  391. }
  392. SetStatus(BluetoothStatusEnum.None);
  393. smartBowHelper.InvokeOnBluetoothError(BluetoothError.ScanNotFoundTargetDevice, "扫描结束后未发现目标设备");
  394. }
  395. void OnScanEnded_windows(bool bSelectedDeviceId) {
  396. SmartBowLogger.Log(this, $"ScanEnded bSelectedDeviceId:" + bSelectedDeviceId);
  397. if (!bSelectedDeviceId)
  398. {
  399. SetStatus(BluetoothStatusEnum.None);
  400. smartBowHelper.InvokeOnBluetoothError(BluetoothError.ScanNotFoundTargetDevice, "扫描结束后未发现目标设备");
  401. }
  402. }
  403. private float _lastWriteDataTime;
  404. bool WriteData(string data)
  405. {
  406. try
  407. {
  408. if (BluetoothWindows.IsWindows())
  409. {
  410. return _bluetoothWindows.Write(data);
  411. }
  412. BluetoothHelperCharacteristic c = new BluetoothHelperCharacteristic(_characteristicWrite.getName());
  413. c.setService(_bluetoothService.getName());
  414. _bluetoothHelper.WriteCharacteristic(c, data);
  415. _lastWriteDataTime = Time.realtimeSinceStartup;
  416. return true;
  417. }
  418. catch (Exception e)
  419. {
  420. Debug.LogError(e);
  421. return false;
  422. }
  423. }
  424. bool WriteByteData(byte[] data)
  425. {
  426. try
  427. {
  428. if (BluetoothWindows.IsWindows())
  429. {
  430. return _bluetoothWindows.WriteByte(data);
  431. }
  432. BluetoothHelperCharacteristic c = new BluetoothHelperCharacteristic(_characteristicWrite.getName());
  433. c.setService(_bluetoothService.getName());
  434. _bluetoothHelper.WriteCharacteristic(c, data);
  435. _lastWriteDataTime = Time.realtimeSinceStartup;
  436. return true;
  437. }
  438. catch (Exception e)
  439. {
  440. Debug.LogError(e);
  441. return false;
  442. }
  443. }
  444. public bool moduleInited;
  445. private string _connectedHandlerID = "";
  446. IEnumerator InitWhenConnected()
  447. {
  448. string myConnectedHandlerID = Guid.NewGuid().ToString();
  449. _connectedHandlerID = myConnectedHandlerID;
  450. yield return new WaitForSecondsRealtime(BluetoothWindows.IsWindows() ? 0.3f : 2.2f);
  451. //获取Mac地址 获取设备固件版本号 获取设备信息(设备类型,系统类型) 获取初始电量 开启发送逻辑
  452. Queue<string> cmds = new Queue<string>(new string[] { "M","V","I", "b", "b", "1"});
  453. while (cmds.Count > 0)
  454. {
  455. if (bluetoothStatus != BluetoothStatusEnum.Connected || myConnectedHandlerID != _connectedHandlerID) yield break;
  456. string cmd = cmds.Dequeue();
  457. WriteData(cmd);
  458. yield return new WaitForSecondsRealtime(0.3f);
  459. }
  460. if (bluetoothStatus != BluetoothStatusEnum.Connected || myConnectedHandlerID != _connectedHandlerID) yield break;
  461. StartCoroutine(LoopRequestBattery(myConnectedHandlerID));
  462. moduleInited = true;
  463. smartBowHelper.InvokeOnBluetoothModuleInited();
  464. }
  465. /// <summary>
  466. /// 初始化6轴指令
  467. /// </summary>
  468. /// <returns></returns>
  469. IEnumerator InitWhenConnected6Axis()
  470. {
  471. string myConnectedHandlerID = Guid.NewGuid().ToString();
  472. _connectedHandlerID = myConnectedHandlerID;
  473. yield return new WaitForSecondsRealtime(BluetoothWindows.IsWindows() ? 0.3f : 2.2f);
  474. Queue<string> cmds = new Queue<string>(new string[] { "M", "B", "B" });
  475. while (cmds.Count > 0)
  476. {
  477. if (bluetoothStatus != BluetoothStatusEnum.Connected || myConnectedHandlerID != _connectedHandlerID) yield break;
  478. string cmd = cmds.Dequeue();
  479. WriteData(cmd);
  480. yield return new WaitForSecondsRealtime(0.3f);
  481. }
  482. if (bluetoothStatus != BluetoothStatusEnum.Connected || myConnectedHandlerID != _connectedHandlerID) yield break;
  483. StartCoroutine(LoopRequestBattery6Axis(myConnectedHandlerID));
  484. moduleInited = true;
  485. smartBowHelper.InvokeOnBluetoothModuleInited();
  486. }
  487. private int _battery = 0;
  488. public int battery
  489. {
  490. get => _battery;
  491. set
  492. {
  493. _battery = value;
  494. //SmartBowLogger.Log(this, "Battery缓存成功");
  495. }
  496. }
  497. /// <summary>
  498. /// 九轴原本的连接电池指令
  499. /// </summary>
  500. /// <param name="myConnectedHandlerID"></param>
  501. /// <returns></returns>
  502. IEnumerator LoopRequestBattery(string myConnectedHandlerID)
  503. {
  504. while (bluetoothStatus == BluetoothStatusEnum.Connected && myConnectedHandlerID == _connectedHandlerID)
  505. {
  506. yield return new WaitForSecondsRealtime(10);
  507. AddCommandToQueue("b");
  508. }
  509. }
  510. /// <summary>
  511. /// 6轴的连接电池指令
  512. /// </summary>
  513. /// <param name="myConnectedHandlerID"></param>
  514. /// <returns></returns>
  515. IEnumerator LoopRequestBattery6Axis(string myConnectedHandlerID)
  516. {
  517. while (bluetoothStatus == BluetoothStatusEnum.Connected && myConnectedHandlerID == _connectedHandlerID)
  518. {
  519. yield return new WaitForSecondsRealtime(10);
  520. AddCommandToQueue("B");
  521. }
  522. }
  523. private List<string> _commands = new List<string>();
  524. void LoopHandleCommands()
  525. {
  526. if (bluetoothStatus != BluetoothStatusEnum.Connected || !moduleInited)
  527. {
  528. if (_commands.Count > 0) _commands.Clear();
  529. return;
  530. }
  531. if (Time.realtimeSinceStartup - _lastWriteDataTime < 0.2f) return;
  532. if (_commands.Count == 0) return;
  533. string cmd = _commands[0];
  534. _commands.RemoveAt(0);
  535. WriteData(cmd);
  536. }
  537. bool AddCommandToQueue(string cmd)
  538. {
  539. if (bluetoothStatus != BluetoothStatusEnum.Connected || !moduleInited) return false;
  540. //如果待插入的指令跟队尾的指令一样,就不要插入了,因为冗余的指令无意义
  541. if (_commands.Count > 0 && _commands[_commands.Count - 1].Equals(cmd)) return true;
  542. _commands.Add(cmd);
  543. return true;
  544. }
  545. public void ReplyInfraredShoot()
  546. {
  547. if (bluetoothStatus != BluetoothStatusEnum.Connected || !moduleInited) return;
  548. WriteData("I");
  549. }
  550. public void ReplyByte(byte[] value)
  551. {
  552. if (bluetoothStatus != BluetoothStatusEnum.Connected || !moduleInited) return;
  553. WriteByteData(value);
  554. }
  555. public bool RequestOpen9Axis()
  556. {
  557. return AddCommandToQueue("3");
  558. }
  559. public bool RequestClose9Axis()
  560. {
  561. return AddCommandToQueue("4");
  562. }
  563. public bool RequestOpenInfrared()
  564. {
  565. return AddCommandToQueue("w");
  566. }
  567. public bool RequestCloseInfrared()
  568. {
  569. return AddCommandToQueue("s");
  570. }
  571. void ParseMacAddress(byte[] bytes)
  572. {
  573. string mac = System.Text.Encoding.ASCII.GetString(bytes);
  574. if (mac != null) mac = mac.Trim();
  575. if (CheckIsMacValid(mac))
  576. {
  577. #region 根据aimDeviceInfo存在添加一个判断
  578. if (aimDeviceInfo != null) {
  579. //需要增加一个判断,判断是否对应的mac设备。不是需要进行重新连接
  580. if (!aimDeviceInfo.bInitMac)
  581. {
  582. SmartBowLogger.Log(this, "设置设备mac:" + mac);
  583. SetAimDeviceMac(mac);
  584. }
  585. else if (aimDeviceInfo.mac != mac)
  586. {
  587. SmartBowLogger.LogError(this, "设备不一样,断开连接");
  588. Disconnect();
  589. //抛出一个错误,给用户处理其他业务流程
  590. smartBowHelper.InvokeOnBluetoothError(BluetoothError.MacAddressAndDeviceMismatch, "验证设备MAC和记录的MAC不匹配!");
  591. return;
  592. }
  593. }
  594. #endregion
  595. macAddress = mac;
  596. SmartBowLogger.Log(this, "MacAddress解析成功");
  597. //获取MacAddress对应的校准记录
  598. string macXXX = macAddress;
  599. smartBowHelper.smartBowNetwork.GetCalibrateRecord(macXXX, (record) =>
  600. {
  601. if (macAddress != macXXX) return;
  602. smartBowHelper.aimHandler.ResumeCalibrateRecord(record);
  603. });
  604. }
  605. else SmartBowLogger.LogWarning(this, "MacAddress解析失败");
  606. }
  607. bool CheckIsMacValid(string mac)
  608. {
  609. if (mac == null) return false;
  610. if (!mac.StartsWith("{")) return false;
  611. if (!mac.EndsWith("}")) return false;
  612. if (!mac.Contains(":")) return false;
  613. char[] validChars = { '{', '}', ':', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
  614. foreach (var c in mac.ToCharArray())
  615. {
  616. if (Array.IndexOf(validChars, c) == -1) return false;
  617. }
  618. if (mac.Length != 19) return false;
  619. string macNoneFrame = mac.Substring(1, mac.Length - 2);
  620. string[] macNoneFrameSplits = macNoneFrame.Split(':');
  621. if (macNoneFrameSplits.Length != 6) return false;
  622. foreach (var item in macNoneFrameSplits)
  623. {
  624. if (item.Length != 2) return false;
  625. foreach (var c in item.ToCharArray())
  626. if (Array.IndexOf(validChars, c) < 3) return false;
  627. }
  628. return true;
  629. }
  630. #region 校验固件版本信息
  631. bool CheckIsVersionValid(string version)
  632. {
  633. if (string.IsNullOrEmpty(version)) return false;
  634. if (!version.StartsWith("{")) return false;
  635. if (!version.EndsWith("}")) return false;
  636. // 去掉 { 和 }
  637. string versionInner = version.Substring(1, version.Length - 2);
  638. // 固件版本格式 Vx.y.z
  639. if (!versionInner.StartsWith("V")) return false;
  640. string[] parts = versionInner.Substring(1).Split('.');
  641. if (parts.Length != 3) return false;
  642. foreach (var part in parts)
  643. {
  644. if (!int.TryParse(part, out _)) return false;
  645. }
  646. return true;
  647. }
  648. void ParseDeviceVersion(byte[] bytes)
  649. {
  650. string version = System.Text.Encoding.ASCII.GetString(bytes);
  651. if (version != null) version = version.Trim();
  652. if (CheckIsVersionValid(version))
  653. {
  654. deviceVersion = version;
  655. SmartBowLogger.Log(this, "DeviceVersion解析成功:" + version);
  656. }
  657. else
  658. {
  659. SmartBowLogger.LogWarning(this, "DeviceVersion解析失败");
  660. }
  661. }
  662. #endregion
  663. #region 记录的设备处理部分
  664. //连接时候判断信息。存在对象则连接需要判断MAC
  665. //记录一个设备
  666. AimDeviceInfo aimDeviceInfo = null;
  667. //用户初始化一个保存数据的操作的id。
  668. //不设置情况下不给进行相关操作
  669. string keyPrefix = "aim-device-info-";
  670. string userTags = "";
  671. int deviceId = -1;
  672. //清空对应id的数据
  673. public void onClearAimDeviceInfoByDeviceId(string _userTags, int _deviceId)
  674. {
  675. string deviceInfo = PlayerPrefs.GetString(keyPrefix + _userTags + _deviceId, "");
  676. if (deviceInfo != "") {
  677. PlayerPrefs.DeleteKey(keyPrefix + _userTags + _deviceId);
  678. ResetAimDeviceInfoToNull();
  679. }
  680. }
  681. public AimDeviceInfo onGetAimDeviceInfos(string _userTags, int _deviceId)
  682. {
  683. OnGetAimDeviceInfo(_userTags, _deviceId);
  684. //SmartBowLogger.Log(this, $"onGetAimDeviceInfos[{JsonUtility.ToJson(aimDeviceInfo)}]");
  685. return aimDeviceInfo;
  686. }
  687. //根据设置的
  688. void OnGetAimDeviceInfo(string _userTags, int _deviceId)
  689. {
  690. string deviceInfo = PlayerPrefs.GetString(keyPrefix + _userTags + _deviceId, "");
  691. if (deviceInfo != "")
  692. {
  693. aimDeviceInfo = JsonUtility.FromJson<AimDeviceInfo>(deviceInfo);//这里的类是依据最外层{}决定的
  694. }
  695. }
  696. void OnSaveAimDeviceInfo(string _userTags, int _deviceId)
  697. {
  698. if (_userTags.Length == 0)
  699. {
  700. SmartBowLogger.LogError(this, $"存储标识不存在!");
  701. return;
  702. }
  703. SmartBowLogger.Log(this, $"OnSaveAimDeviceInfo [{JsonUtility.ToJson(aimDeviceInfo)}]");
  704. PlayerPrefs.SetString(keyPrefix + _userTags + _deviceId, JsonUtility.ToJson(aimDeviceInfo));
  705. }
  706. //连接蓝牙调用。连接时候创建一个连接信息,用于记录mac 是否要验证
  707. //传入一个id用于区分是哪个设备
  708. //bRecreateDeviceInfo 是否重新创建
  709. public void initAimDeviceInfo(string _userTags, int _deviceId, bool bRecreateDeviceInfo)
  710. {
  711. userTags = _userTags;
  712. deviceId = _deviceId;
  713. if (bRecreateDeviceInfo)
  714. {
  715. //直接覆盖设备信息
  716. onRecreateAimDeviceInfoById();
  717. }
  718. else
  719. {
  720. //获取设备信息。没有创建
  721. onCreateAimDeviceInfoById();
  722. }
  723. }
  724. //是否存在AimDeviceInfo,存在获取,不存在创建;
  725. void onCreateAimDeviceInfoById()
  726. {
  727. ResetAimDeviceInfoToNull();
  728. OnGetAimDeviceInfo(userTags, deviceId);
  729. if (aimDeviceInfo == null)
  730. {
  731. aimDeviceInfo = new AimDeviceInfo(deviceId);
  732. OnSaveAimDeviceInfo(userTags, deviceId);
  733. }
  734. }
  735. //直接覆盖新元素
  736. void onRecreateAimDeviceInfoById()
  737. {
  738. // 使用Lambda表达式删除特定条件的元素
  739. ResetAimDeviceInfoToNull();
  740. //添加一个新元素
  741. aimDeviceInfo = new AimDeviceInfo(deviceId);
  742. //更新信息
  743. OnSaveAimDeviceInfo(userTags, deviceId);
  744. }
  745. //APP连接需进行MAC地址的比对。
  746. void SetAimDeviceMac(string _mac)
  747. {
  748. aimDeviceInfo.setInitMac(_mac);
  749. OnSaveAimDeviceInfo(userTags, deviceId);
  750. }
  751. public void ResetAimDeviceInfoToNull()
  752. {
  753. aimDeviceInfo = null;
  754. }
  755. #endregion
  756. }
  757. #region 添加一个记录设备连接的信息,主要用于判断mac地址是否连接操作
  758. [Serializable]//需要在转换为json格式的类的上方添加序列化
  759. public class AimDeviceInfo
  760. {
  761. public int id; //区分用户设备对应的id
  762. public bool bInitMac = false; //是否初始化Mac
  763. public string mac; //记录当前
  764. public AimDeviceInfo(int _id)
  765. {
  766. this.id = _id;
  767. }
  768. public void setInitMac(string macTemp)
  769. {
  770. bInitMac = true;
  771. mac = macTemp;
  772. }
  773. public void resetInitMac()
  774. {
  775. bInitMac = false;
  776. mac = "";
  777. }
  778. }
  779. #endregion
  780. }