powerfun-unity/Assets/Scripts/Devices/Ble/Win/BleWinHwInterface.cs
2021-06-08 10:30:26 +08:00

487 lines
19 KiB
C#

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.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 BleWinHwInterface
{
private static BleWinHwInterface hwInterface;
private WclBleMainThread wclBleMainThread;
private readonly Dictionary<string, BleAdvertisementInfo> pCache = new Dictionary<string, BleAdvertisementInfo>();
private Action<BleAdvertisementInfo> _discoveredCallback;
private Dictionary<BlePeripheralInfo, Action<BleWinHwInterface, BlePeripheralInfo, BleResponse>> callbacks = new Dictionary<BlePeripheralInfo, Action<BleWinHwInterface, BlePeripheralInfo, BleResponse>>();
private Dictionary<BlePeripheralInfo, Action<BleWinHwInterface, BlePeripheralInfo, BleResponse<List<BleServiceInfo>>>> servicesCallbacks = new Dictionary<BlePeripheralInfo, Action<BleWinHwInterface, BlePeripheralInfo, BleResponse<List<BleServiceInfo>>>>();
//private Dictionary<BlePeripheralInfo, Action<BleWinHwInterface, BleServiceInfo, BleResponse<List<BleCharacteristicInfo>>>> characteristicsCallbacks = new Dictionary<BlePeripheralInfo, Action<BleWinHwInterface, BleServiceInfo, BleResponse<List<BleCharacteristicInfo>>>>();
private Dictionary<BlePeripheralInfo, Action<BleWinHwInterface, BleCharacteristicInfo, BleResponse>> characteristicNotificationCallbacks = new Dictionary<BlePeripheralInfo, Action<BleWinHwInterface, BleCharacteristicInfo, BleResponse>>();
private Dictionary<BleCharacteristicInfo, CharacteristicReadCallback> characteristicReadCallbacks = new Dictionary<BleCharacteristicInfo, CharacteristicReadCallback>();
private Dictionary<BleServiceInfo, CharacteristicsDiscoveredCallback> characteristicsDiscoveredCallbacks = new Dictionary<BleServiceInfo, CharacteristicsDiscoveredCallback>();
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;
}
private 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 BleWinHwInterface()
{
wclBleMainThread = new WclBleMainThread();
wclBleMainThread.ManagerStatusChanged += ManagerStatusChanged;
wclBleMainThread.ScanInfoReceived += WatcherScanInfoReceived;
//wclBleMainThread.gatt
wclBleMainThread.Start();
}
private void WatcherScanInfoReceived(WclBleMainThread sender, long address, string name, int rssi, CPPBridge.WclBleAdvertisementType packetType, Guid? service)
{
//if(address != 224160707349234)
//{
//return;
//}
//Debug.Log($"address:{ address }, name:{ name }, service:{ (service == null ? "" : service.Value.ToString()) }");
SensorType sensor = SensorType.None;
List<Guid> services = new List<Guid>();
if (service != null)
{
services = new List<Guid> { 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.ToString("X12");
if (!pCache.ContainsKey(addressStr))
{
var device = new BleAdvertisementInfo(new WinBlePeripheralInfo(addressStr, name), rssi, true, services, null, sensor);
pCache.Add(addressStr, device);
//WclBleGattThread gattClient = this.SetUpGattClient(device.Peripheral);
//this.ConnectInternal(gattClient);
}
if (!string.IsNullOrWhiteSpace(name))
{
(pCache[addressStr].Peripheral as WinBlePeripheralInfo).SetName(name);
}
if(sensor == SensorType.None)
{
return;
}
pCache[addressStr].SensorType = sensor;
//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]);
}
}
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;
}
internal void ConnectPeripheral(BlePeripheralInfo info, Action<BleWinHwInterface, BlePeripheralInfo, BleResponse> 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);
}
}
private void ConnectInternal(WclBleGattThread gattClient)
{
//Task.Run(() =>
//{
int num = gattClient.Connect();
Debug.Log("连接设备返回" + num);
//});
}
internal void DisconnectPeripheral(BlePeripheralInfo peripheral, Action callback)
{
var gattThread = this.wclBleMainThread.GetGattThread(peripheral);
if(gattThread != null)
{
this.callbacks.Remove(peripheral);
this.servicesCallbacks.Remove(peripheral);
this.characteristicNotificationCallbacks.Remove(peripheral);
gattThread.Discounect();
callback?.Invoke();
}
}
public static BleWinHwInterface GetInterface()
{
if(hwInterface == null)
{
hwInterface = new BleWinHwInterface();
}
return hwInterface;
}
public void StartScan(Action<BleAdvertisementInfo> discoveredCallBack)
{
_discoveredCallback = discoveredCallBack;
this.wclBleMainThread.StartWatcher();
}
private void ManagerStatusChanged(WclBleMainThread sender, WclBleManagerStatus status)
{
this.BleState = BleWinHwInterface.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();
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");
}
private void GattServicesDiscovered(WclBleGattThread gattClient, BleResponse<List<BleServiceInfo>> 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<List<BleCharacteristicInfo>> 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<byte[]> 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<BleCharacteristicWriteType> response)
{
Debug.Log("characteristic wrote");
}
private void GattCharacteristicChanged(WclBleGattThread gattClient, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
{
//Debug.Log("characteristic changed");
if(this.wclBleMainThread.GetGattThread(characteristic.Peripheral) != null)
{
this.characteristicReadEvent.Invoke(this, characteristic, response);
}
}
public void DiscoverServices(BlePeripheralInfo peripheral, Action<BleWinHwInterface, BlePeripheralInfo, BleResponse<List<BleServiceInfo>>> callback)
{
WclBleGattThread gattThread = this.wclBleMainThread.GetGattThread(peripheral);
if(gattThread == null)
{
return;
}
this.servicesCallbacks.Add(peripheral, callback);
int num = gattThread.DiscoverServices();
if (WclBleErrors.IsSuccessCode(num))
{
return;
}
BleResponse<List<BleServiceInfo>> response = new BleResponse<List<BleServiceInfo>>
{
IsSuccess = false,
Error = new BleHwInterfaceError(new int?(num), "WclBleGattClientErrorDomain", string.Format("Error discovering services - {0}", num))
};
this.GattServicesDiscovered(gattThread, response);
}
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<List<BleCharacteristicInfo>> response = new BleResponse<List<BleCharacteristicInfo>>
{
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<BleWinHwInterface, BleCharacteristicInfo, BleResponse> 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<List<BleServiceInfo>> response = new BleResponse<List<BleServiceInfo>>
{
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;
}
}
}
}