using Assets.Scripts.Ble.Scan; using Assets.Scripts.Ble.Win; using Assets.Scripts.Devices.Ant; using Assets.Scripts.Devices.Ble; using Assets.Scripts.Devices.Ble.Interfaces; using Assets.Scripts.Devices.Ble.Win; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using UnityEngine; namespace Assets.Scripts.Ble { public sealed class BleMobileInterface: IBleWinHwInterface { private static BleMobileInterface hwInterface; private BleMobileThread bleMobileThread; private Dictionary _pCache; public Dictionary pCache { get { if (_pCache == null) { _pCache = new Dictionary(); } return _pCache; } set { _pCache = value; } } private Action _discoveredCallback; private Dictionary> callbacks = new Dictionary>(); private Dictionary>>> servicesCallbacks = new Dictionary>>>(); //private Dictionary>>> characteristicsCallbacks = new Dictionary>>>(); private Dictionary> characteristicNotificationCallbacks = new Dictionary>(); private Dictionary characteristicReadCallbacks = new Dictionary(); private Dictionary characteristicsDiscoveredCallbacks = new Dictionary(); private Dictionary disconnectedCallback = new Dictionary(); private CharacteristicReadCallback characteristicReadEvent; public event CharacteristicReadCallback CharacteristicReadEvent { add { this.characteristicReadEvent += value; } remove { this.characteristicReadEvent -= value; } } private BluetoothStateChangedCallback bluetoothStateChanged; public event BluetoothStateChangedCallback BluetoothStateChangedEvent { add { this.bluetoothStateChanged += value; } remove { this.bluetoothStateChanged -= value; } } private BleState nativeState; public BleState BleState { get { return this.nativeState; } set { if(this.nativeState != value) { this.nativeState = value; this.bluetoothStateChanged?.Invoke(this, this.nativeState); } } } private PeripheralDisconnectedCallback peripheralDisconnectedEvent; public event PeripheralDisconnectedCallback PeripheralDisconnectedEvent { add { this.peripheralDisconnectedEvent += value; } remove { this.peripheralDisconnectedEvent -= value; } } private BleMobileInterface() { bleMobileThread = new BleMobileThread(); bleMobileThread.ScanInfoReceived += WatcherScanInfoReceived; } private void WatcherScanInfoReceived(BleMobileThread sender, string address, string name, int rssi,string type) { //if (address != 224160707349234) //{ // return; //} SensorType sensor = SensorType.None; List services = new List(); if (type.Equals("trainer")) { sensor = SensorType.Trainer; } else { sensor = SensorType.HeartRate; } //if (service != null) //{ // services = new List { service.Value }; // foreach (var item in ServiceUuids.Services) // { // if (item.IdGuid != service.Value) // { // continue; // } // if (item.IdByteArray == ServiceUuids.Ftms) // { // sensor = SensorType.Trainer; // } // else if (item.IdByteArray == ServiceUuids.HeartRate) // { // sensor = SensorType.HeartRate; // } // else if (item.IdByteArray == ServiceUuids.CyclingPower) // { // sensor = SensorType.Power; // //sensor = SensorType.Trainer; // } // else if (item.IdByteArray == ServiceUuids.CyclingSpeedCadence) // { // sensor = SensorType.SpeedCadence; // } // else if (item.IdByteArray == ServiceUuids.TacxBle) // { // sensor = SensorType.Trainer; // } // } //}; var addressStr = address; if (!pCache.ContainsKey(addressStr)) { var device = new BleAdvertisementInfo(new WinBlePeripheralInfo(addressStr, name), rssi, true, services, null, sensor); pCache.Add(addressStr, device); } if (!string.IsNullOrWhiteSpace(name)) { (pCache[addressStr].Peripheral as WinBlePeripheralInfo).SetName(name); } if (sensor == SensorType.None) { return; } pCache[addressStr].SensorType = sensor; pCache[addressStr].Rssi = rssi; //Debug.Log(sensor); //pCache[address.ToString()].SensorType = sensor; //foreach (var item in services) //{ // pCache[addressStr].TryAddService(item); //} pCache[addressStr].Index++; if (pCache[addressStr].SensorType == SensorType.Power && pCache[addressStr].Services.Any(s => s.Equals(ServiceUuids.Get(ServiceUuids.TacxBle).IdGuid))) { pCache[addressStr].SensorType = SensorType.Trainer; //Debug.Log("纠正为trainer, "+ pCache[address.ToString()].Index); } if (pCache[addressStr].SensorType == SensorType.Power) { if (pCache[addressStr].Index > 4) { _discoveredCallback?.Invoke(pCache[addressStr]); } } else if (pCache[addressStr].SensorType != SensorType.None) { _discoveredCallback?.Invoke(pCache[addressStr]); } this.BleState = BleState.On; } //private WclBleGattThread SetUpGattClient(BlePeripheralInfo peripheral) //{ // WclBleGattThread wclBleGattThread = this.wclBleMainThread.CreateGattThread(peripheral); // wclBleGattThread.GattConnected += this.GattConnected; // wclBleGattThread.GattDisconnected += this.GattDisconnected; // wclBleGattThread.GattServicesDiscovered += this.GattServicesDiscovered; // wclBleGattThread.GattCharacteristicsDiscovered += this.GattCharacteristicsDiscovered; // wclBleGattThread.GattCharacteristicSubscribed += this.GattCharacteristicSubscribed; // wclBleGattThread.GattCharacteristicRead += this.GattCharacteristicRead; // wclBleGattThread.GattCharacteristicWrote += this.GattCharacteristicWrote; // wclBleGattThread.GattCharacteristicChanged += this.GattCharacteristicChanged; // wclBleGattThread.Start(); // return wclBleGattThread; //} List servicelist = new List(); List characteristilist = new List(); public void ConnectPeripheral(BlePeripheralInfo info, Action callback) { //this.callbacks.Add(info, callback); //WclBleGattThread wclBleGattThread = this.wclBleMainThread.GetGattThread(info); //if (wclBleGattThread == null) //{ // wclBleGattThread = this.SetUpGattClient(info); // this.ConnectInternal(wclBleGattThread); // return; //} //else //{ // this.ConnectInternal(wclBleGattThread); //}\ BleResponse s = new BleResponse(); s.IsSuccess = true; s.Error = null; var self = this; BluetoothLEHardwareInterface.ConnectToPeripheral(info.Address, (address) => { callback?.Invoke(self, info, s); }, (address, service) => { var l = servicelist.Where(c => c.Id.ToString().Equals(service)).ToList(); if (l.Count == 0) { servicelist.Add(new WinBleServiceInfo(info,new Guid(service))); } }, (address, service, characteristic) => { var l = characteristilist.Where(c => c.Id.ToString().Equals(characteristic)).ToList(); if (l.Count == 0) { //characteristilist.Add(new BleCharacteristicInfo new WinBleServiceInfo(info, new Guid(characteristic))); } }, null); } private void ConnectInternal(WclBleGattThread gattClient) { //Task.Run(() => //{ //int num = gattClient.Connect(); //Debug.Log("连接设备返回" + num); //}); } public void DisconnectPeripheral(BlePeripheralInfo peripheral, Action callback) { //var gattThread = this.wclBleMainThread.GetGattThread(peripheral); //if(gattThread != null && gattThread.CanLoadWork) //{ // this.callbacks.Remove(peripheral); // this.servicesCallbacks.Remove(peripheral); // this.characteristicNotificationCallbacks.Remove(peripheral); // this.disconnectedCallback.Add(peripheral, callback); // gattThread.Discounect(); //} } public static BleMobileInterface GetInterface() { if(hwInterface == null) { hwInterface = new BleMobileInterface(); } return hwInterface; } public void StartScan(Action discoveredCallBack) { pCache.Clear(); _discoveredCallback = discoveredCallBack; bleMobileThread.StartWatcher(); } private void ManagerStatusChanged(WclBleMainThread sender, WclBleManagerStatus status) { //this.BleState = BleMobileInterface.StateFromNativeState(status); //Debug.Log("win hw:" + status); } private void GattConnected(WclBleGattThread gattClient, BleResponse response) { //Debug.Log($"gatt connected { response.ToString() }"); //if (!response.IsSuccess) //{ // gattClient.Stop(); // this.callbacks[gattClient.Peripheral].Invoke(this, gattClient.Peripheral, response); // this.callbacks.Remove(gattClient.Peripheral); // return; //} //this.callbacks[gattClient.Peripheral].Invoke(this, gattClient.Peripheral, response); //this.callbacks.Remove(gattClient.Peripheral); } private void CleanUpPeripheral(BlePeripheralInfo peripheralInfo) { //this.callbacks.Clear() } private void GattDisconnected(WclBleGattThread gattClient, BleResponse response) { //Debug.Log($"gatt disconnected { gattClient.Peripheral.Name }"); //this.callbacks.Remove(gattClient.Peripheral); //this.servicesCallbacks.Remove(gattClient.Peripheral); //this.characteristicNotificationCallbacks.Remove(gattClient.Peripheral); ////App.MainDeviceAdapter.PrintStatus(); //var manualDisconnect = disconnectedCallback.ContainsKey(gattClient.Peripheral); //this.peripheralDisconnectedEvent(this, gattClient.Peripheral, response, manualDisconnect); ////App.MainDeviceAdapter.PrintStatus(); //if (disconnectedCallback.ContainsKey(gattClient.Peripheral)) //{ // disconnectedCallback[gattClient.Peripheral].Invoke(); // disconnectedCallback.Remove(gattClient.Peripheral); //} ////this.pCache.Remove(gattClient.Peripheral.Address); } private void GattServicesDiscovered(WclBleGattThread gattClient, BleResponse> response) { ////Debug.Log("services discovered"); ////this.callbacks[gattClient.Peripheral].Invoke(this, gattClient.Peripheral, response); ////foreach (var item in response.Data) ////{ //// Debug.Log(item.ToString()); ////} //if (this.servicesCallbacks.ContainsKey(gattClient.Peripheral)) //{ // this.servicesCallbacks[gattClient.Peripheral].Invoke(this, gattClient.Peripheral, response); //} } private void GattCharacteristicsDiscovered(WclBleGattThread gattClient, BleServiceInfo service, BleResponse> response) { //Debug.Log("characteristics discovered"); if (this.characteristicsDiscoveredCallbacks.ContainsKey(service)) { this.characteristicsDiscoveredCallbacks[service].Invoke(this, service, response); } } private void GattCharacteristicSubscribed(WclBleGattThread gattClient, BleCharacteristicInfo characteristic, BleResponse response) { ////Debug.Log("characteristics subscribed"); //if (this.characteristicNotificationCallbacks.ContainsKey(gattClient.Peripheral)) //{ // this.characteristicNotificationCallbacks[gattClient.Peripheral].Invoke(this, characteristic, response); //} } private void GattCharacteristicRead(WclBleGattThread gattClient, BleCharacteristicInfo characteristic, BleResponse response) { //Debug.Log("characteristic read"); //if (this.characteristicReadCallbacks.ContainsKey(characteristic)) //{ // this.characteristicReadCallbacks[characteristic].Invoke(this, characteristic, response); // this.characteristicReadCallbacks.Remove(characteristic); //} //this.characteristicReadEvent.Invoke(this, characteristic, response); } private void GattCharacteristicWrote(WclBleGattThread gattClient, BleCharacteristicInfo characteristic, BleResponse response) { Debug.Log("characteristic wrote"); } private void GattCharacteristicChanged(WclBleGattThread gattClient, BleCharacteristicInfo characteristic, BleResponse response) { ////Debug.Log("characteristic changed"); //if(this.wclBleMainThread.GetGattThread(characteristic.Peripheral) != null) //{ // this.characteristicReadEvent.Invoke(this, characteristic, response); //} } public void DiscoverServices(BlePeripheralInfo peripheral, Action>> callback) { this.servicesCallbacks.Add(peripheral, callback); if (servicelist.Count > 0) { BleResponse> response = new BleResponse> { IsSuccess = true, Error = null, Data = (List)servicelist, }; callback.Invoke(this, peripheral, response); return; } } public void DiscoverCharacteristic(BleServiceInfo service, CharacteristicsDiscoveredCallback callback) { //WclBleGattThread gattThread = this.wclBleMainThread.GetGattThread(service.Peripheral); //if(gattThread == null) //{ // return; //} //if (!this.characteristicsDiscoveredCallbacks.ContainsKey(service)) //{ // this.characteristicsDiscoveredCallbacks.Add(service, callback); //} //int num = gattThread.DiscoverCharacteristics(service); //if (WclBleErrors.IsSuccessCode(num)) //{ // return; //} //BleResponse> response = new BleResponse> //{ // IsSuccess = false, // Error = new BleHwInterfaceError(new int?(num), "WclBleGattClientErrorDomain", string.Format("Error discovering characteristics - {0}", num)) //}; //this.GattCharacteristicsDiscovered(gattThread, service, response); } public void SubscribeCharacteristic(BleCharacteristicInfo characteristic, Action callback) { //WclBleGattThread gattThread = this.wclBleMainThread.GetGattThread(characteristic.Peripheral); //this.characteristicNotificationCallbacks.Add(gattThread.Peripheral, callback); //int num = gattThread.SubscribeCharacteristic(characteristic); //if (WclBleErrors.IsSuccessCode(num)) //{ // return; //} //BleResponse> response = new BleResponse> //{ // IsSuccess = false, // Error = new BleHwInterfaceError(new int?(num), "WclBleGattClientErrorDomain", string.Format("Error subscribing characteristic - {0}", num)) //}; //this.GattCharacteristicSubscribed(gattThread, characteristic, response); } public void WriteCharacteristic(BleCharacteristicInfo characteristic, byte[] data) { //var gattThread = this.wclBleMainThread.GetGattThread(characteristic.Peripheral); //if(gattThread == null) //{ // return; //} //int num = gattThread.WriteCharacteristic(characteristic, data); //if (WclBleErrors.IsSuccessCode(num)) //{ // Debug.Log("设置命令成功"); // return; //} } public void Dispose() { //this.wclBleMainThread.ManagerStatusChanged -= ManagerStatusChanged; //this.wclBleMainThread.ScanInfoReceived -= WatcherScanInfoReceived; //this.wclBleMainThread.Stop(); //this.wclBleMainThread = null; //hwInterface = null; //pCache.Clear(); } public void ReadCharacteristic(BleCharacteristicInfo characteristic, CharacteristicReadCallback callback) { //WclBleGattThread gattThread = this.wclBleMainThread.GetGattThread(characteristic.Peripheral); //if(gattThread == null) //{ // return; //} //this.characteristicReadCallbacks.Add(characteristic, callback); //int num = gattThread.ReadCharacteristicValue(characteristic); //if (WclBleErrors.IsSuccessCode(num)) //{ // return; //} } private static BleState StateFromNativeState(WclBleManagerStatus status) { switch (status) { case WclBleManagerStatus.RadioOff: return BleState.Off; case WclBleManagerStatus.RadioOn: return BleState.On; case WclBleManagerStatus.Unknown: return BleState.Unknown; default: return BleState.Unavailable; } } private class WinBlePeripheralInfo : BlePeripheralInfo { // Token: 0x06003F35 RID: 16181 RVA: 0x000E9FBF File Offset: 0x000E81BF public WinBlePeripheralInfo(string address, string name) : base(address, name) { } // Token: 0x06003F36 RID: 16182 RVA: 0x000E9FC9 File Offset: 0x000E81C9 public void SetName(string name) { base.Name = name; } } private class WinBleServiceInfo : BleServiceInfo { // Token: 0x06003F86 RID: 16262 RVA: 0x000EA27F File Offset: 0x000E847F public WinBleServiceInfo(BlePeripheralInfo peripheral, Guid id) : base(id, peripheral) { } } private class WinBleCharacteristicInfo : BleCharacteristicInfo { // Token: 0x06003F86 RID: 16262 RVA: 0x000EA27F File Offset: 0x000E847F public WinBleCharacteristicInfo(Guid id, BleServiceInfo service, BleCharacteristicProperties properties) : base(id,service, properties) { } } } }