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

503 lines
20 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;
2022-06-08 13:05:56 +08:00
using System.Timers;
2021-08-19 18:03:25 +08:00
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;
}
//Debug.Log($"設備{App.IsRowerMode}信息,{item.IdGuid},{string.Join(";", item.IdByteArray)}");
2022-05-09 13:18:14 +08:00
if (item.IdByteArray == ServiceUuids.Ftms || item.IdByteArray == ServiceUuids.C2Rower)
2021-08-24 18:34:41 +08:00
{
sensor = SensorType.Rower;
//else
//{
// sensor = SensorType.FtmsTrainer;
//}
2021-08-24 18:34:41 +08:00
}
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>();
2022-06-08 13:05:56 +08:00
2021-08-19 18:03:25 +08:00
public void ConnectPeripheral(BlePeripheralInfo info, Action<IBleWinHwInterface, BlePeripheralInfo, BleResponse> callback)
{
2022-06-08 13:05:56 +08:00
var exsit = this.callbacks.Where(c => c.Key.Address == info.Address).Any();
if (!exsit)
{
this.callbacks.Add(info, callback);
}
else
2021-08-20 18:45:16 +08:00
{
2022-06-08 13:05:56 +08:00
var obj = this.callbacks.Where(c => c.Key.Address == info.Address).FirstOrDefault();
this.callbacks.Remove(obj.Key);
2021-08-30 18:28:26 +08:00
this.callbacks.Add(info, callback);
}
2021-09-15 14:17:11 +08:00
Debug.Log("try connect device" + info.Name + this.callbacks.Count.ToString());
2022-06-08 13:05:56 +08:00
var self = this;
2021-08-30 18:28:26 +08:00
if (this.callbacks.Count == 1)
2021-08-19 18:03:25 +08:00
{
2021-08-30 18:28:26 +08:00
BluetoothLEHardwareInterface.ConnectToPeripheral(info.Address, (address) =>
{
2022-06-08 13:05:56 +08:00
BleResponse s = new BleResponse
{
IsSuccess = true,
Error = null
};
2021-08-30 18:28:26 +08:00
callback?.Invoke(self, info, s);
this.callbacks.Remove(info);
2022-06-08 13:05:56 +08:00
Debug.Log("连接成功!" + info.Name);
2021-08-30 18:28:26 +08:00
if (this.callbacks.Any())
{
this.ConnectPeripheral(this.callbacks.First().Key, this.callbacks.First().Value);
}
}, (address, service) =>
{
2022-06-08 13:05:56 +08:00
Debug.Log("发现服务");
2021-08-30 18:28:26 +08:00
ServicesDiscovered(address, service);
}, (address, service, characteristic) =>
{
CharacteristicsDiscovered(address, service, characteristic);
}, (address) =>
{
2021-09-15 14:17:11 +08:00
Debug.Log("disconnect device:" + address);
2021-08-30 18:28:26 +08:00
PeripheralDisconnected(address, info);
2022-06-08 13:05:56 +08:00
},
(address, error) =>
{
BleResponse s = new BleResponse
{
IsSuccess = false,
Error = new BleHwInterfaceError(error)
};
callback?.Invoke(self, info, s);
this.callbacks.Remove(info);
if (this.callbacks.Any())
{
this.ConnectPeripheral(this.callbacks.First().Key, this.callbacks.First().Value);
}
}
);
2021-08-30 18:28:26 +08:00
}
2021-08-26 19:33:43 +08:00
}
2022-06-08 13:05:56 +08:00
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));
2022-06-08 13:05:56 +08:00
if (characteristicsDiscoveredCallback.Any())
2021-08-26 19:33:43 +08:00
{
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-09-15 14:17:11 +08:00
Debug.Log("断开回调"+ 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-26 19:33:43 +08:00
}
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);
}
Debug.Log("SubscribeCharacteristic" + characteristic.Peripheral.Name + characteristic.Service.ToString() + characteristic.Service.ToString());
BluetoothLEHardwareInterface.SubscribeCharacteristicWithDeviceAddress(characteristic.Peripheral.Address, characteristic.Service.ToString(), characteristic.Id.ToString(), (a,b)=>
{
Debug.Log("返回特征值," + a + "," + b);
}, (deviceAddress, characteristric, bytes) =>
2021-08-24 18:34:41 +08:00
{
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)
{
bool withResponse = false;
#if UNITY_IOS
withResponse = characteristic.Id.ToString().ToLower().Contains("2AD9".ToLower());
#endif
BluetoothLEHardwareInterface.WriteCharacteristic(characteristic.Peripheral.Address, characteristic.Service.Id.ToString(), characteristic.Id.ToString(), data, data.Length, withResponse, (characteristicUUID) => {
Debug.Log("相应" + characteristicUUID);
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
}
}