using System.Collections.Generic; using UnityEngine; using ArduinoBluetoothAPI; using System; using System.Text; using UnityEngine.UI; using DG.Tweening; namespace InfraredManager { public class ConnetDevicesSingle : MonoBehaviour { #region 连接弓箭蓝牙部分 private BluetoothHelper bluetoothHelperBow; public BluetoothHelper mBluetoothHelperBow { get { return bluetoothHelperBow; } } private BluetoothHelperCharacteristic characteristicWriteBow; private BluetoothHelperService bluetoothServiceBow; private string bowTargetDeviceName = "Bbow_20210501"; private string bowDeviceName = ""; string bowDeviceService = "0000fff0"; string bowDeviceCharacteristicWrite = "0000fff2"; string bowDeviceCharacteristicNotify = "0000fff1"; private bool isBowScanning; public bool mIsBowScanning { get { return isBowScanning; } } private bool isBowConnecting; public bool mIsBowConnecting { get { return isBowConnecting; } } private string data; #endregion private LinkedList devices; #region log输出 public Action OnLogAction; void logOutBow(string text) { Debug.Log("logOutBow:" + text); OnLogAction?.Invoke(text); } #endregion public static ConnetDevicesSingle ins; //默认关闭准心 public bool bCrosshair = false; #region 红外Demo相关监听操作 public Action posAction; public Action infraredShootAction; public Action crosshairAction; #endregion void Awake() { //初始化 ins = this; Debug.Log("ConnetDevicesSingle!"); InitAutoDormancy(); OnUpdateState(); } //获取一次初始值 public void OnInitConfig() { } public void OnUpdateState() { } public void ButtonShoot() { posAction?.Invoke(new Vector3(1 * Screen.width, 1 * Screen.height, 0)); //调用游戏中的射箭接口 if (ArmBow.ins) { ArmBow.ins.ADS_fire(true); } else { OnGameShoot?.Invoke(10); } } public void onShowCrosshair() { //显示游戏光标 PlayerPrefs.SetInt("CrossHairImageActive", 1); bCrosshair = true; crosshairAction?.Invoke(true); } public void onHideCrosshair() { //隐藏游戏光标 PlayerPrefs.SetInt("CrossHairImageActive", 0); bCrosshair = false; crosshairAction?.Invoke(false); } // Start is called before the first frame update void Start() { logOutBow("初始化BluetoothHelperAndroid"); if (BluetoothHelperAndroid.IsBluetoothEnabled() == false) { Debug.Log("蓝牙未打开!"); logOutBow("蓝牙未打开!"); return; } data = ""; try { BluetoothHelper.BLE = true; bluetoothHelperBow = BluetoothHelper.GetInstance(); bluetoothHelperBow.OnConnected += OnConnected; bluetoothHelperBow.OnConnectionFailed += OnConnectionFailed; bluetoothHelperBow.OnScanEnded += OnScanEnded2; bluetoothHelperBow.OnCharacteristicChanged += (helper, value, characteristic) => { // Debug.Log(characteristic.getName()); // Debug.Log(System.Text.Encoding.ASCII.GetString(value)); byte[] bytes = value; // Debug.Log("瞄准模块数据长度" + bytes.Length); if (bytes.Length != 27 && bytes.Length != 39) { if (bytes[0] == 0x5b) { //红外射击检测 ShootByInfrared(bytes); } } }; } catch (Exception e) { Debug.LogError(e); } } //Bow扫描结束 void OnScanEnded2(BluetoothHelper helper, LinkedList nearbyDevices) { Debug.Log("2 ended " + nearbyDevices.Count); logOutBow("2 ended " + nearbyDevices.Count); if (nearbyDevices.Count == 0) { isBowScanning = helper.ScanNearbyDevices(); return; } isBowScanning = false; foreach (BluetoothDevice device in nearbyDevices) { Debug.Log(device.DeviceName); if (device.DeviceName == bowTargetDeviceName) { logOutBow("匹配设备 " + device.DeviceName); bowDeviceName = bowTargetDeviceName; helper.setDeviceName(bowDeviceName); helper.Connect(); isBowConnecting = true; } } } void OnConnected(BluetoothHelper helper) { if (helper.getId() == bluetoothHelperBow.getId()) { Debug.Log("2 连接成功:" + helper.getDeviceName()); logOutBow("弓箭 连接成功:" + helper.getDeviceName()); isBowConnecting = false; foreach (BluetoothHelperService service in helper.getGattServices()) { if (service.getName().ToLower().StartsWith(bowDeviceService)) { bluetoothServiceBow = service; foreach (BluetoothHelperCharacteristic characteristic in service.getCharacteristics()) { if (characteristic.getName().ToLower().StartsWith(bowDeviceCharacteristicWrite)) { characteristicWriteBow = characteristic; } else if (characteristic.getName().ToLower().StartsWith(bowDeviceCharacteristicNotify)) { BluetoothHelperCharacteristic ch = new BluetoothHelperCharacteristic(characteristic.getName()); ch.setService(bluetoothServiceBow.getName()); bluetoothHelperBow.Subscribe(ch); } } } } CallDelay(2, () => { //if (status != BluetoothStatusEnum.ConnectSuccess) return; InitWhenConenct(); }); } } void OnConnectionFailed(BluetoothHelper helper) { Debug.Log("Connection lost"); if (helper.getId() == bluetoothHelperBow.getId()) { isBowConnecting = false; logOutBow("弓箭断开连接"); } } //Connect bow ble public void OnBowScanNearbyDevices() { if (bluetoothHelperBow == null) return; if (!bluetoothHelperBow.isConnected() && !isBowScanning && !isBowConnecting) { //未连接,未扫描,不是连接中 if (BluetoothHelperAndroid.IsBluetoothEnabled() == false) { Debug.Log("exception1"); logOutBow("蓝牙未打开"); return; } if (BluetoothHelperAndroid.RequestBluetoothPermissions(() => { //开始扫描。调用最后一个bluetoothHelperBow扫描即可 isBowScanning = bluetoothHelperBow.ScanNearbyDevices(); logOutBow("开始扫描连接!"); }, (permission) => { if (permission.Contains("LOCATION")) { Debug.LogError("Exception:LOCATION"); logOutBow("Exception:LOCATION"); } else if (permission.Contains("BLUETOOTH")) { Debug.LogError("Exception: BLUETOOTH"); logOutBow("Exception:BLUETOOTH"); } })) return; isBowScanning = bluetoothHelperBow.ScanNearbyDevices(); logOutBow("开始扫描连接!"); } else if (!bluetoothHelperBow.isConnected() && isBowScanning) { //扫描中 logOutBow("扫描中..."); } else if (bluetoothHelperBow.isConnected()) { logOutBow("断开Bow连接"); //已连接,断开连接 bluetoothHelperBow.Disconnect(); } } void OnDestroy() { if (bluetoothHelperBow != null) { bluetoothHelperBow.Disconnect(); OnDisconnect(); } } /// /// 字节数组转16进制字符串:空格分隔 /// /// /// public string ToHexStrFromByte(byte[] byteDatas) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < byteDatas.Length; i++) { builder.Append(string.Format("{0:X2} ", byteDatas[i])); } return builder.ToString().Trim(); } /// /// 字符串转16进制 /// /// 要转格式的字符串 public byte[] Convert16(string strText) { strText = strText.Replace(" ", ""); strText = strText.Replace(" ", ""); Debug.Log(strText); byte[] bText = new byte[strText.Length / 2]; for (int i = 0; i < strText.Length / 2; i++) { bText[i] = Convert.ToByte(Convert.ToInt32(strText.Substring(i * 2, 2), 16)); } return bText; } string getBytesToIndex(byte[] bytes, int index) { StringBuilder builderCrosshair = new StringBuilder(); builderCrosshair.Append(string.Format("{0:X2}", bytes[index])); return builderCrosshair.ToString().Trim(); } float onVectorValue(byte[] bytes, int startIndex) { //整数部分 string intPartHex = string.Format("{0:X2}", bytes[startIndex]).ToString().Trim(); ; int intPartNumber = Convert.ToInt32(intPartHex, 16); StringBuilder builder = new StringBuilder(); for (int i = 0; i < 2; i++) { builder.Append(string.Format("{0:X2}", bytes[i + startIndex + 1])); } string dataHex = builder.ToString().Trim(); int decimalPartNumber = Convert.ToInt32(dataHex, 16); return intPartNumber + (float)decimalPartNumber / 32768; } void CallDelay(float delayTime, TweenCallback callback) { Sequence sequence = DOTween.Sequence(); sequence.PrependInterval(delayTime).AppendCallback(callback); sequence.SetUpdate(true); } #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; JCUnityLib.CountLock needModularAwake = new JCUnityLib.CountLock(); void InitAutoDormancy() { //暂时关闭自动休眠,默认是需要模块保持激活 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 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) onWriteDataToBow(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 #region 弓箭部分代码操作 public Action OnGameShoot; [NonSerialized] public byte byteTime1; [NonSerialized] public byte byteTime2; /**通过红外线数据进行射击 */ public void ShootByInfrared(byte[] bytes) { byteTime1 = bytes[2]; byteTime1 = bytes[3]; int id = bytes[1]; //序号 float time1 = bytes[2] * 0.1f; //时区1耗时 float time2 = bytes[3] * 0.1f; //时区2耗时 float totalTime = time1 + time2; //校验和 int sumCheck = bytes[0] + bytes[1] + bytes[2] + bytes[3]; sumCheck &= 0xff; //校验和比较结果 bool sumCheckRes = sumCheck == bytes[4]; //弓轨速度 float speed = 0.05f / (totalTime / 1000f); //通过动能定理求箭的速度(实体箭质量*实体箭速度^2=游戏中箭的质量*游戏中箭的速度^2) float shootSpeed = Mathf.Sqrt(speed * speed * CommonConfig.arrowWeight / UserSettings.ins.actualArrowWeight); //打印 string logTxt = $"序号{id},时区1:{time1}毫秒,时区2:{time2}毫秒,校验:{sumCheckRes},弓轨速度:{speed}m/s,箭的速度:{shootSpeed}m/s"; logOutBow(logTxt); // if (DebugForDevice.ins) DebugForDevice.ins.LogInfrared(logTxt); //收到射箭数据,就回复硬件,否则n毫秒后硬件会认为丢包进行重传 try { if (sumCheckRes) ReplyInfraredShoot(); //如果数据正确,则回复硬件 } catch (Exception) { } //打开准心的时候,直接调用射击接口 if (ArmBow.ins) { ArmBow.ins.ADS_fire(true); } else if (DuckHunter.SmartBowController.Instance) { DuckHunter.SmartBowController.Instance.OnShooting(shootSpeed); } //else //{ // OnGameShoot?.Invoke(shootSpeed); //} } //断开弓箭连接 void OnDisconnect() { DestroyWhenDisconenct(); } public void RequestBattery() { if (!isStartUp) return; if (isSendCmdLocked) return; onWriteDataToBow("b"); } //回复弓箭红外 public void ReplyInfraredShoot() { if (isSendCmdLocked) return; onWriteDataToBow("I"); } public void onWriteDataToBow(string data) { BluetoothHelperCharacteristic ch = new BluetoothHelperCharacteristic(characteristicWriteBow.getName()); ch.setService(bluetoothServiceBow.getName()); bluetoothHelperBow.WriteCharacteristic(ch, data); } #endregion } }