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

459 lines
18 KiB
C#
Raw Normal View History

2021-08-19 18:03:25 +08:00
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
{
2021-08-24 18:34:41 +08:00
public sealed class BleMobileInterface : IBleWinHwInterface
2021-08-19 18:03:25 +08:00
{
private static BleMobileInterface hwInterface;
2021-08-20 18:45:16 +08:00
private BleMobileThread bleMobileThread;
2021-08-19 18:03:25 +08:00
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;
}
}
2021-08-24 18:34:41 +08:00
2021-08-19 18:03:25 +08:00
private BleState nativeState;
public BleState BleState
{
get
{
return this.nativeState;
}
set
{
2021-08-24 18:34:41 +08:00
if (this.nativeState != value)
2021-08-19 18:03:25 +08:00
{
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()
{
2021-08-20 18:45:16 +08:00
bleMobileThread = new BleMobileThread();
2021-08-24 18:34:41 +08:00
bleMobileThread.ManagerInitialized += BleMobileThread_ManagerInitialized;
bleMobileThread.ManagerStatusChanged += ManagerStatusChanged;
2021-08-20 18:45:16 +08:00
bleMobileThread.ScanInfoReceived += WatcherScanInfoReceived;
2021-08-19 18:03:25 +08:00
}
2021-08-24 18:34:41 +08:00
private void BleMobileThread_ManagerInitialized(BleMobileThread thread)
{
this.BleState = BleState.On;
}
private void ManagerStatusChanged(BleMobileThread sender, WclBleManagerStatus status)
2021-08-19 18:03:25 +08:00
{
2021-08-24 18:34:41 +08:00
this.BleState = BleMobileInterface.StateFromNativeState(status);
}
2021-08-20 18:45:16 +08:00
2021-08-24 18:34:41 +08:00
private void WatcherScanInfoReceived(BleMobileThread sender, string address, string name, int rssi,string[] uuids)
{
2021-08-19 18:03:25 +08:00
SensorType sensor = SensorType.None;
List<Guid> services = new List<Guid>();
2021-08-24 18:34:41 +08:00
if (uuids != null && uuids.Length > 0)
2021-08-20 18:45:16 +08:00
{
2021-08-30 18:28:26 +08:00
foreach (var item1 in uuids)
2021-08-24 18:34:41 +08:00
{
2021-08-30 18:28:26 +08:00
services.Add(new Guid(item1));
2021-08-24 18:34:41 +08:00
}
foreach (var item in ServiceUuids.Services)
{
2021-08-30 18:28:26 +08:00
if (!services.Contains(item.IdGuid))
2021-08-24 18:34:41 +08:00
{
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;
}
}
};
2021-08-20 18:45:16 +08:00
var addressStr = address;
2021-08-19 18:03:25 +08:00
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);
}
2021-08-20 18:45:16 +08:00
if (sensor == SensorType.None)
2021-08-19 18:03:25 +08:00
{
return;
}
pCache[addressStr].SensorType = sensor;
pCache[addressStr].Rssi = rssi;
//Debug.Log(sensor);
//pCache[address.ToString()].SensorType = sensor;
2021-08-20 18:45:16 +08:00
2021-08-24 18:34:41 +08:00
foreach (var item in uuids)
{
pCache[addressStr].TryAddService(new Guid(item));
}
2021-08-20 18:45:16 +08:00
2021-08-19 18:03:25 +08:00
pCache[addressStr].Index++;
2021-08-20 18:45:16 +08:00
if (pCache[addressStr].SensorType == SensorType.Power && pCache[addressStr].Services.Any(s => s.Equals(ServiceUuids.Get(ServiceUuids.TacxBle).IdGuid)))
2021-08-19 18:03:25 +08:00
{
pCache[addressStr].SensorType = SensorType.Trainer;
//Debug.Log("纠正为trainer, "+ pCache[address.ToString()].Index);
}
2021-08-20 18:45:16 +08:00
2021-08-19 18:03:25 +08:00
if (pCache[addressStr].SensorType == SensorType.Power)
{
if (pCache[addressStr].Index > 4)
{
_discoveredCallback?.Invoke(pCache[addressStr]);
}
}
2021-08-20 18:45:16 +08:00
else if (pCache[addressStr].SensorType != SensorType.None)
2021-08-19 18:03:25 +08:00
{
_discoveredCallback?.Invoke(pCache[addressStr]);
}
}
2021-08-20 18:45:16 +08:00
List<BleServiceInfo> servicelist = new List<BleServiceInfo>();
List<BleCharacteristicInfo> characteristilist = new List<BleCharacteristicInfo>();
2021-08-19 18:03:25 +08:00
public void ConnectPeripheral(BlePeripheralInfo info, Action<IBleWinHwInterface, BlePeripheralInfo, BleResponse> callback)
{
2021-08-30 18:28:26 +08:00
if (!this.callbacks.ContainsKey(info))
2021-08-20 18:45:16 +08:00
{
2021-08-30 18:28:26 +08:00
this.callbacks.Add(info, callback);
}
if (this.callbacks.Count == 1)
2021-08-19 18:03:25 +08:00
{
2021-08-30 18:28:26 +08:00
BleResponse s = new BleResponse();
s.IsSuccess = true;
s.Error = null;
var self = this;
BluetoothLEHardwareInterface.ConnectToPeripheral(info.Address, (address) =>
{
callback?.Invoke(self, info, s);
this.callbacks.Remove(info);
if (this.callbacks.Any())
{
this.ConnectPeripheral(this.callbacks.First().Key, this.callbacks.First().Value);
}
}, (address, service) =>
{
ServicesDiscovered(address, service);
}, (address, service, characteristic) =>
{
CharacteristicsDiscovered(address, service, characteristic);
}, (address) =>
{
PeripheralDisconnected(address, info);
});
}
2021-08-26 19:33:43 +08:00
}
#region
//服务发现
private void ServicesDiscovered(string address, string service)
{
2021-08-30 18:28:26 +08:00
BluetoothLEHardwareInterface.Log(address+"FOUNDFSERVICE" + service);
2021-08-26 19:33:43 +08:00
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>>
2021-08-20 18:45:16 +08:00
{
2021-08-26 19:33:43 +08:00
IsSuccess = true,
Error = null,
Data = servicelist,
};
serviceCallback.Value?.Invoke(this, serviceCallback.Key, response);
}
2021-08-19 18:03:25 +08:00
}
2021-08-26 19:33:43 +08:00
//特征值发现
private void CharacteristicsDiscovered(string address, string service, string characteristic)
{
2021-08-30 18:28:26 +08:00
BluetoothLEHardwareInterface.Log(address + "发现特征值:" + characteristic);
2021-08-26 19:33:43 +08:00
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);
}
}
//设备主动断开处理
private void PeripheralDisconnected(string address, BlePeripheralInfo info)
{
2021-08-30 18:28:26 +08:00
var currentCallback = this.callbacks.Where(c => c.Key.MatchAddress(address));
if (currentCallback.Any())
{
this.callbacks.Remove(currentCallback.First().Key);
}
2021-08-26 19:33:43 +08:00
var characteristicCallback = characteristicNotificationCallbacks.Where(c => c.Key.MatchAddress(address));
if (characteristicCallback.Any())
{
characteristicNotificationCallbacks.Remove(characteristicCallback.First().Key);
}
2021-08-30 18:28:26 +08:00
2021-08-26 19:33:43 +08:00
var serviceCallback = servicesCallbacks.Where(c => c.Key.MatchAddress(address));
if (serviceCallback.Any())
{
servicesCallbacks.Remove(serviceCallback.First().Key);
}
var characteristicsDiscoveredCallback = characteristicsDiscoveredCallbacks.Where(c => c.Key.MatchAddress(address));
if (serviceCallback.Any())
{
characteristicsDiscoveredCallbacks.Remove(characteristicsDiscoveredCallback.First().Key);
}
peripheralDisconnectedEvent(this, info, null, false);
}
#endregion
2021-08-19 18:03:25 +08:00
2021-08-24 18:34:41 +08:00
//设备断开连接
2021-08-19 18:03:25 +08:00
public void DisconnectPeripheral(BlePeripheralInfo peripheral, Action callback)
{
2021-08-24 18:34:41 +08:00
BluetoothLEHardwareInterface.DisconnectPeripheral(peripheral.Address, (address) =>
{
2021-08-26 19:33:43 +08:00
peripheralDisconnectedEvent(this, peripheral, null, true);
2021-08-24 18:34:41 +08:00
callback?.Invoke();
});
2021-08-19 18:03:25 +08:00
}
public static BleMobileInterface GetInterface()
{
if(hwInterface == null)
{
hwInterface = new BleMobileInterface();
}
return hwInterface;
}
2021-08-24 18:34:41 +08:00
//扫描设备
2021-08-19 18:03:25 +08:00
public void StartScan(Action<BleAdvertisementInfo> discoveredCallBack)
{
pCache.Clear();
_discoveredCallback = discoveredCallBack;
2021-08-20 18:45:16 +08:00
bleMobileThread.StartWatcher();
2021-08-19 18:03:25 +08:00
}
2021-08-26 19:33:43 +08:00
public void StopScan()
{
bleMobileThread.Stop();
}
2021-08-24 18:34:41 +08:00
//发现服务列表
2021-08-19 18:03:25 +08:00
public void DiscoverServices(BlePeripheralInfo peripheral, Action<IBleWinHwInterface, BlePeripheralInfo, BleResponse<List<BleServiceInfo>>> callback)
{
2021-08-30 18:28:26 +08:00
if (!this.servicesCallbacks.ContainsKey(peripheral))
{
this.servicesCallbacks.Add(peripheral, callback);
}
2021-08-19 18:03:25 +08:00
}
2021-08-24 18:34:41 +08:00
//发现特征值
2021-08-19 18:03:25 +08:00
public void DiscoverCharacteristic(BleServiceInfo service, CharacteristicsDiscoveredCallback callback)
{
2021-08-30 18:28:26 +08:00
if (!this.characteristicsDiscoveredCallbacks.ContainsKey(service))
{
this.characteristicsDiscoveredCallbacks.Add(service, callback);
}
2021-08-19 18:03:25 +08:00
}
2021-08-24 18:34:41 +08:00
//订阅特征值
2021-08-19 18:03:25 +08:00
public void SubscribeCharacteristic(BleCharacteristicInfo characteristic, Action<IBleWinHwInterface, BleCharacteristicInfo, BleResponse> callback)
{
2021-08-30 18:28:26 +08:00
if (!this.characteristicNotificationCallbacks.ContainsKey(characteristic.Peripheral))
{
this.characteristicNotificationCallbacks.Add(characteristic.Peripheral, callback);
}
BluetoothLEHardwareInterface.Log("SubscribeCharacteristic" + characteristic.Peripheral.Name + characteristic.Service.ToString() + characteristic.Service.ToString());
2021-08-24 18:34:41 +08:00
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);
}
});
2021-08-19 18:03:25 +08:00
}
2021-08-24 18:34:41 +08:00
//写入特征值
2021-08-19 18:03:25 +08:00
public void WriteCharacteristic(BleCharacteristicInfo characteristic, byte[] data)
{
2021-08-24 18:34:41 +08:00
BluetoothLEHardwareInterface.WriteCharacteristic(characteristic.Peripheral.Address, characteristic.Service.Id.ToString(), characteristic.Id.ToString(), data, data.Length, false, (characteristicUUID) => {
2021-08-19 18:03:25 +08:00
2021-08-24 18:34:41 +08:00
BluetoothLEHardwareInterface.Log("Write Succeeded");
});
2021-08-19 18:03:25 +08:00
}
public void Dispose()
{
2021-08-24 18:34:41 +08:00
bleMobileThread.ManagerInitialized -= BleMobileThread_ManagerInitialized;
bleMobileThread.ManagerStatusChanged -= ManagerStatusChanged;
bleMobileThread.ScanInfoReceived -= WatcherScanInfoReceived;
2021-08-26 19:33:43 +08:00
bleMobileThread.Dispose();
2021-08-24 18:34:41 +08:00
bleMobileThread = null;
hwInterface = null;
pCache.Clear();
2021-08-19 18:03:25 +08:00
}
public void ReadCharacteristic(BleCharacteristicInfo characteristic, CharacteristicReadCallback callback)
{
2021-08-24 18:34:41 +08:00
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);
});
2021-08-19 18:03:25 +08:00
}
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;
}
}
2021-08-20 18:45:16 +08:00
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)
{
}
}
2021-08-19 18:03:25 +08:00
}
}