powerfun-unity/Assets/Scripts/Devices/Ble/mobile/BleMobileInterface.cs

400 lines
17 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.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<string, BleAdvertisementInfo> _pCache;
public Dictionary<string, BleAdvertisementInfo> pCache
{
get
{
if (_pCache == null)
{
_pCache = new Dictionary<string, BleAdvertisementInfo>();
}
return _pCache;
}
set { _pCache = value; }
}
private Action<BleAdvertisementInfo> _discoveredCallback;
private Dictionary<BlePeripheralInfo, Action<IBleWinHwInterface, BlePeripheralInfo, BleResponse>> callbacks = new Dictionary<BlePeripheralInfo, Action<IBleWinHwInterface, BlePeripheralInfo, BleResponse>>();
private Dictionary<BlePeripheralInfo, Action<IBleWinHwInterface, BlePeripheralInfo, BleResponse<List<BleServiceInfo>>>> servicesCallbacks = new Dictionary<BlePeripheralInfo, Action<IBleWinHwInterface, 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<IBleWinHwInterface, BleCharacteristicInfo, BleResponse>> characteristicNotificationCallbacks = new Dictionary<BlePeripheralInfo, Action<IBleWinHwInterface, BleCharacteristicInfo, BleResponse>>();
private Dictionary<BleCharacteristicInfo, CharacteristicReadCallback> characteristicReadCallbacks = new Dictionary<BleCharacteristicInfo, CharacteristicReadCallback>();
private Dictionary<BleServiceInfo, CharacteristicsDiscoveredCallback> characteristicsDiscoveredCallbacks = new Dictionary<BleServiceInfo, CharacteristicsDiscoveredCallback>();
private Dictionary<BlePeripheralInfo, Action> disconnectedCallback = new Dictionary<BlePeripheralInfo, Action>();
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.ManagerInitialized += BleMobileThread_ManagerInitialized;
bleMobileThread.ManagerStatusChanged += ManagerStatusChanged;
bleMobileThread.ScanInfoReceived += WatcherScanInfoReceived;
}
private void BleMobileThread_ManagerInitialized(BleMobileThread thread)
{
this.BleState = BleState.On;
}
private void ManagerStatusChanged(BleMobileThread sender, WclBleManagerStatus status)
{
this.BleState = BleMobileInterface.StateFromNativeState(status);
}
private void WatcherScanInfoReceived(BleMobileThread sender, string address, string name, int rssi,string[] uuids)
{
SensorType sensor = SensorType.None;
List<Guid> services = new List<Guid>();
if (uuids != null && uuids.Length > 0)
{
foreach (var item in uuids)
{
services.Add(new Guid(item));
}
foreach (var item in ServiceUuids.Services)
{
if (!uuids.Contains(item.IdGuid.ToString()))
{
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 uuids)
{
pCache[addressStr].TryAddService(new Guid(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;
//}
List<BleServiceInfo> servicelist = new List<BleServiceInfo>();
List<BleCharacteristicInfo> characteristilist = new List<BleCharacteristicInfo>();
public void ConnectPeripheral(BlePeripheralInfo info, Action<IBleWinHwInterface, BlePeripheralInfo, BleResponse> callback)
{
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) => {
if (servicesCallbacks.Where(c => c.Key.Address == address).Any())
{
var serviceCallback = servicesCallbacks.Where(c => c.Key.Address == address).FirstOrDefault();
List<BleServiceInfo> servicelist = new List<BleServiceInfo>();
servicelist.Add(new WinBleServiceInfo(serviceCallback.Key,new Guid(service)));
BleResponse<List<BleServiceInfo>> response = new BleResponse<List<BleServiceInfo>>
{
IsSuccess = true,
Error = null,
Data = servicelist,
};
serviceCallback.Value?.Invoke(this, serviceCallback.Key, response);
}
}, (address, service, characteristic) =>
{
if (characteristicsDiscoveredCallbacks.Where(c => c.Key.Peripheral.Address == address).Any())
{
var characteristicCallback = characteristicsDiscoveredCallbacks.Where(c => c.Key.Peripheral.Address == address).FirstOrDefault();
List<BleCharacteristicInfo> characteristiclist = new List<BleCharacteristicInfo>();
characteristiclist.Add(new WinBleCharacteristicInfo(new Guid(characteristic), new WinBleServiceInfo(characteristicCallback.Key.Peripheral, new Guid(service)),0));
BleResponse<List<BleCharacteristicInfo>> response = new BleResponse<List<BleCharacteristicInfo>>
{
IsSuccess = true,
Error = null,
Data = characteristiclist,
};
characteristicCallback.Value?.Invoke(this, characteristicCallback.Key, response);
}
}, null);
}
//设备断开连接
public void DisconnectPeripheral(BlePeripheralInfo peripheral, Action callback)
{
BluetoothLEHardwareInterface.DisconnectPeripheral(peripheral.Address, (address) =>
{
//peripheralDisconnectedEvent(this, peripheral, null, true);
callback?.Invoke();
});
}
public static BleMobileInterface GetInterface()
{
if(hwInterface == null)
{
hwInterface = new BleMobileInterface();
}
return hwInterface;
}
//扫描设备
public void StartScan(Action<BleAdvertisementInfo> discoveredCallBack)
{
pCache.Clear();
_discoveredCallback = discoveredCallBack;
bleMobileThread.StartWatcher();
}
//发现服务列表
public void DiscoverServices(BlePeripheralInfo peripheral, Action<IBleWinHwInterface, BlePeripheralInfo, BleResponse<List<BleServiceInfo>>> callback)
{
this.servicesCallbacks.Add(peripheral, callback);
}
//发现特征值
public void DiscoverCharacteristic(BleServiceInfo service, CharacteristicsDiscoveredCallback callback)
{
this.characteristicsDiscoveredCallbacks.Add(service, callback);
}
//订阅特征值
public void SubscribeCharacteristic(BleCharacteristicInfo characteristic, Action<IBleWinHwInterface, BleCharacteristicInfo, BleResponse> callback)
{
this.characteristicNotificationCallbacks.Add(characteristic.Peripheral, callback);
BluetoothLEHardwareInterface.SubscribeCharacteristicWithDeviceAddress(characteristic.Peripheral.Address, characteristic.Service.ToString(), characteristic.Id.ToString(), null, (deviceAddress, characteristric, bytes) =>
{
if (characteristicReadEvent != null)
{
BleResponse<byte[]> response = new BleResponse<byte[]>
{
IsSuccess = true,
Error = null,
Data = bytes,
};
characteristicReadEvent.Invoke(this, characteristic, response);
}
});
}
//写入特征值
public void WriteCharacteristic(BleCharacteristicInfo characteristic, byte[] data)
{
BluetoothLEHardwareInterface.WriteCharacteristic(characteristic.Peripheral.Address, characteristic.Service.Id.ToString(), characteristic.Id.ToString(), data, data.Length, false, (characteristicUUID) => {
BluetoothLEHardwareInterface.Log("Write Succeeded");
});
}
public void Dispose()
{
bleMobileThread.ManagerInitialized -= BleMobileThread_ManagerInitialized;
bleMobileThread.ManagerStatusChanged -= ManagerStatusChanged;
bleMobileThread.ScanInfoReceived -= WatcherScanInfoReceived;
bleMobileThread.Stop();
bleMobileThread = null;
hwInterface = null;
pCache.Clear();
}
public void ReadCharacteristic(BleCharacteristicInfo characteristic, CharacteristicReadCallback callback)
{
BluetoothLEHardwareInterface.ReadCharacteristic(characteristic.Peripheral.Address, characteristic.Service.Id.ToString(), characteristic.Id.ToString(), (c, bytes) => {
BleResponse<byte[]> response = new BleResponse<byte[]>
{
IsSuccess = true,
Error = null,
Data = bytes,
};
callback?.Invoke(this, characteristic, response);
});
}
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)
{
}
}
}
}