using ArduinoBluetoothAPI; using System; using UnityEngine; using System.Collections.Generic; using UnityEngine.UI; using DG.Tweening; /* 蓝牙瞄准模块 */ public class BluetoothAim : MonoBehaviour { readonly string targetDeviceName = "Bbow_20210501"; string targetDeviceService { get { if (CommonConfig.devicePlan == 0) return "0000fff0"; return "6e400001"; } } string targetDeviceCharacteristicWrite { get { if (CommonConfig.devicePlan == 0) return "0000fff2"; return "6e400002"; } } string targetDeviceCharacteristicNotify { get { if (CommonConfig.devicePlan == 0) return "0000fff1"; return "6e400003"; } } BluetoothHelper bluetoothHelper; BluetoothHelperCharacteristic characteristicWrite; BluetoothHelperService bluetoothService; string deviceName = ""; bool canConnect = true; [SerializeField] Text textUI; public BluetoothStatusEnum status = BluetoothStatusEnum.Connect; public bool hasData = false; public long hasDataTime; public static bool scanLock = false; //防止同时扫描冲突 public static BluetoothAim ins; void Start() { ins = this; InitAutoDormancy(); #if UNITY_STANDALONE_WIN new GameObject("BleUDP").AddComponent(); #endif Debug.LogWarning("设置开始自动连接蓝牙"); userDoConnect = true; } void OnDestroy() { DisconnectBleHelper(); } private bool userDoConnect = false; private bool doConnect = false; public void DoConnect() { if (status == BluetoothStatusEnum.Connect) { userDoConnect = true; doConnect = true; SetStatus(BluetoothStatusEnum.Connecting); } else if (status == BluetoothStatusEnum.ConnectSuccess) { userDoConnect = false; doConnect = false; OnDisconnect(); #if UNITY_ANDROID DisconnectBleHelper(); #elif UNITY_STANDALONE_WIN BleUDP.ins.Disconnect(); #endif } } void OnDisconnect() { hasData = false; canConnect = true; SetStatus(BluetoothStatusEnum.ConnectFail); BowCamera.isTouchMode = true; DestroyWhenDisconenct(); if (AimHandler.ins) AimHandler.ins.msOld = default; } void Update() { if (userDoConnect && status == BluetoothStatusEnum.Connect) { DoConnect(); } if (doConnect) Connect(); } void SetStatus(BluetoothStatusEnum statusValue) { status = statusValue; if (status == BluetoothStatusEnum.ConnectFail) { Sequence sequence = DOTween.Sequence(); sequence.AppendInterval(2f); sequence.AppendCallback(delegate () { if (status == BluetoothStatusEnum.ConnectFail) { status = BluetoothStatusEnum.Connect; } }); sequence.SetUpdate(true); DeviceReconnectView.Show(); } } void DisconnectBleHelper() { if (bluetoothHelper != null) bluetoothHelper.Disconnect(); } void Connect() { if (BluetoothShoot.scanLock) { return; } if (!canConnect) { return; } doConnect = false; scanLock = true; canConnect = false; SetStatus(BluetoothStatusEnum.Connecting); #if UNITY_ANDROID ConnectBleHelper(); #elif UNITY_STANDALONE_WIN ConnectBleByUDP(); #endif } void ConnectBleHelper() { try { BluetoothHelper.BLE = true; bluetoothHelper = BluetoothHelper.GetNewInstance(); bluetoothHelper.OnConnected += (BluetoothHelper helper) => { Log("连接成功\n" + helper.getDeviceName()); SetStatus(BluetoothStatusEnum.ConnectSuccess); BowCamera.isTouchMode = false; foreach (BluetoothHelperService service in helper.getGattServices()) { if (service.getName().ToLower().StartsWith(targetDeviceService)) { bluetoothService = service; foreach (BluetoothHelperCharacteristic characteristic in service.getCharacteristics()) { if (characteristic.getName().ToLower().StartsWith(targetDeviceCharacteristicWrite)) { characteristicWrite = characteristic; } else if (characteristic.getName().ToLower().StartsWith(targetDeviceCharacteristicNotify)) { BluetoothHelperCharacteristic ch = new BluetoothHelperCharacteristic(characteristic.getName()); ch.setService(bluetoothService.getName()); bluetoothHelper.Subscribe(ch); } } } } // CallDelay(1, OpenInfrared); // CallDelay(2, OpenReceiveData); // CallDelay(3, RequestBattery); CallDelay(2, () => { if (status != BluetoothStatusEnum.ConnectSuccess) return; InitWhenConenct(); }); }; bluetoothHelper.OnConnectionFailed += (BluetoothHelper helper) => { Log("连接失败\n" + helper.getDeviceName()); OnDisconnect(); }; bluetoothHelper.OnCharacteristicChanged += (helper, value, characteristic) => { if (!hasData) { hasDataTime = JC.CS.Utility.GetTimestamp(); UploadMacAddress(value); } hasData = true; byte[] bytes = value; // Log(String.Join(",", bytes)); BluetoothClient.UploadData(0, bytes); if (AimHandler.ins) { AimHandler.ins.OnDataReceived(bytes); } }; int scanCount = 0; bluetoothHelper.OnScanEnded += (BluetoothHelper helper, LinkedList nearbyDevices) => { scanLock = false; foreach (BluetoothDevice device in nearbyDevices) { if (device.DeviceName == targetDeviceName) { deviceName = device.DeviceName; bluetoothHelper.setDeviceName(deviceName); bluetoothHelper.Connect(); Log("发现设备\n" + device.DeviceName); return; } } if (scanCount < 3) { //如果没扫描到,则重新扫描,达到延迟提示失败的效果 scanCount++; scanLock = true; bluetoothHelper.ScanNearbyDevices(); } else { canConnect = true; Log("没有发现设备"); SetStatus(BluetoothStatusEnum.ConnectFail); } }; bluetoothHelper.ScanNearbyDevices(); Log("正在扫描设备"); } catch (Exception e) { Debug.LogError(e.Message); Debug.LogError(e.StackTrace); scanLock = false; canConnect = true; SetStatus(BluetoothStatusEnum.ConnectFail); // status = BluetoothStatusEnum.Connect; // userDoConnect = false; PopupMgr.ins.ShowTip(TextAutoLanguage2.GetTextByKey("ble-please-open-ble")); } } void ConnectBleByUDP() { try { BleUDP.ins.OnConnected = () => { Log("连接成功\n" + deviceName); SetStatus(BluetoothStatusEnum.ConnectSuccess); BowCamera.isTouchMode = false; InitWhenConenct(); }; BleUDP.ins.OnConnectionFailed = () => { Log("连接失败\n" + deviceName); OnDisconnect(); }; BleUDP.ins.OnCharacteristicChanged = (byte[] value) => { if (!hasData) { hasDataTime = JC.CS.Utility.GetTimestamp(); UploadMacAddress(value); } hasData = true; byte[] bytes = value; // Log(String.Join(",", bytes)); BluetoothClient.UploadData(0, bytes); if (AimHandler.ins) { AimHandler.ins.OnDataReceived(bytes); } }; BleUDP.ins.OnScanEnded = () => { scanLock = false; deviceName = targetDeviceName; BleUDP.ins.Connect(); Log("发现设备\n" + deviceName); }; BleUDP.ins.ScanNearbyDevices(); } catch (Exception e) { Debug.LogError(e.Message); Debug.LogError(e.StackTrace); scanLock = false; canConnect = true; SetStatus(BluetoothStatusEnum.ConnectFail); } } #region 自动进入/退出休眠状态, 这里做程指令发送队列,为了控制连续发送指令的间隔,避免硬件收不到或处理不过来 class CmdToSend { public string[] cmds; public Action onComplete; public Func canDo; public CmdToSend(string[] cmds, Action onComplete, Func canDo) { this.cmds = cmds; this.onComplete = onComplete; this.canDo = canDo; } } Queue cmdWaitingList = new Queue(); bool isSendCmdLocked = false; bool canAutoDormancy = false; bool isStartUp = false; JC.CS.CountLocker needModularAwake = new JC.CS.CountLocker(); void CheckAndStartUp() { if (needModularAwake.IsLocked()) { StartUp(); } else { Dormancy(); } } void InitAutoDormancy() { // GlobalEventCenter.ins.onGameSceneLoad += () => { // needModularAwake.Lock(); // CheckAndStartUp(); // }; // GlobalEventCenter.ins.onGameSceneDestroy += () => { // needModularAwake.Unlock(); // CheckAndStartUp(); // }; // GlobalEventCenter.ins.onSimulateMouseAwakeChanged += (waked) => { // if (waked) needModularAwake.Lock(); // else needModularAwake.Unlock();; // CheckAndStartUp(); // }; // GlobalEventCenter.ins.onDeviceCalibrateViewAwakeChanged += (waked) => { // if (waked) needModularAwake.Lock(); // else needModularAwake.Unlock();; // CheckAndStartUp(); // }; //暂时关闭自动休眠,默认是需要模块保持激活 needModularAwake.Lock(); } void InitWhenConenct() { canAutoDormancy = true; List cmds = new List(); cmds.Add("M"); //获取Mac地址 cmds.Add("b"); //确保开启stm32 cmds.Add("b"); //获取初始电量 cmds.Add("1"); //开启发送逻辑 Action onComplete = null; if (needModularAwake.IsLocked()) { cmds.Add("w"); //红外灯开启 cmds.Add("3"); //九轴开启 onComplete = () => { isStartUp = true; }; } else { cmds.Add("s"); //红外灯关闭 cmds.Add("S"); //Stm32关闭 cmds.Add("4"); //九轴关闭 onComplete = () => { isStartUp = false; }; } SendCDM(null, onComplete, cmds.ToArray()); } void DestroyWhenDisconenct() { canAutoDormancy = false; sendCMD_CheckAndDoStop(null); } //启动 void StartUp() { SendCDM(() => { return !isStartUp; }, () => { isStartUp = true; }, "b", "w", "3"); } //休眠 void Dormancy() { SendCDM(() => { return isStartUp; }, () => { isStartUp = false; }, "4", "s", "S"); } void SendCDM(Func canDo, Action onComplete, params string[] cmds) { CmdToSend cmdToSend = new CmdToSend(cmds, onComplete, canDo); if (isSendCmdLocked) { cmdWaitingList.Enqueue(cmdToSend); return; } sendCMD_NotCheck(cmdToSend); } void sendCMD_NotCheck(CmdToSend cmdToSend) { if (cmdToSend.canDo != null && !cmdToSend.canDo.Invoke()) { sendCMD_CheckNext(); return; } isSendCmdLocked = true; Sequence sequence = DOTween.Sequence(); sequence.PrependInterval(0.3f); foreach (var cmd in cmdToSend.cmds) { sequence.AppendCallback(() => { bool stopped = sendCMD_CheckAndDoStop(sequence); if (!stopped) WriteData(cmd); }); sequence.AppendInterval(0.5f); } sequence.AppendCallback(() => { bool stopped = sendCMD_CheckAndDoStop(sequence); if (!stopped) { isSendCmdLocked = false; cmdToSend.onComplete?.Invoke(); sendCMD_CheckNext(); } }); sequence.SetUpdate(true); } void sendCMD_CheckNext() { if (cmdWaitingList.Count <= 0) return; CmdToSend cmdToSend = cmdWaitingList.Dequeue(); sendCMD_NotCheck(cmdToSend); } bool sendCMD_CheckAndDoStop(Sequence sequence) { if (canAutoDormancy) return false; isStartUp = false; isSendCmdLocked = false; cmdWaitingList.Clear(); if (sequence != null) sequence.Kill(); return true; } #endregion public void RequestBattery() { if (!isStartUp) return; if (isSendCmdLocked) return; WriteData("b"); } public void ReplyInfraredShoot() { if (isSendCmdLocked) return; WriteData("I"); } void CallDelay(float delayTime, TweenCallback callback) { Sequence sequence = DOTween.Sequence(); sequence.PrependInterval(delayTime).AppendCallback(callback); sequence.SetUpdate(true); } public void WriteData(string data) { #if UNITY_ANDROID if (DebugDeviceCMD.ins) DebugDeviceCMD.ins.ShowCMD(data); BluetoothHelperCharacteristic ch = new BluetoothHelperCharacteristic(characteristicWrite.getName()); ch.setService(bluetoothService.getName()); bluetoothHelper.WriteCharacteristic(ch, data); #elif UNITY_STANDALONE_WIN BleUDP.ins.SendMsg(data); #endif } void Log(string text) { if (textUI) { textUI.text = text; } } void UploadMacAddress(byte[] bytes) { Debug.LogWarning("阻止上传Mac"); // if (hasData) return; // string str = System.Text.Encoding.ASCII.GetString (bytes); // if (str == null) return; // if (str.Contains(":")) { // if (!str.Equals(LoginMgr.myUserInfo.mac)) { // LoginMgr.myUserInfo.mac = str; // } // UserPlayer.ins.call("userComp.saveMac", str); // } } }