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

478 lines
19 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 item1 in uuids)
{
services.Add(new Guid(item1));
}
foreach (var item in ServiceUuids.Services)
{
if (!services.Contains(item.IdGuid))
{
continue;
}
//Debug.Log($"設備信息,{item.IdGuid},{string.Join(";", item.IdByteArray)}");
if (item.IdByteArray == ServiceUuids.Ftms)
{
if (App.IsRowerMode == true)
{
sensor = SensorType.Rower;
}
else
{
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]);
}
}
List<BleServiceInfo> servicelist = new List<BleServiceInfo>();
List<BleCharacteristicInfo> characteristilist = new List<BleCharacteristicInfo>();
public void ConnectPeripheral(BlePeripheralInfo info, Action<IBleWinHwInterface, BlePeripheralInfo, BleResponse> callback)
{
if (!this.callbacks.ContainsKey(info))
{
this.callbacks.Add(info, callback);
}
Debug.Log("try connect device" + info.Name + this.callbacks.Count.ToString());
if (this.callbacks.Count == 1)
{
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);
Debug.Log("连接成功!"+info.Name);
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) =>
{
Debug.Log("disconnect device:" + address);
PeripheralDisconnected(address, info);
});
}
}
#region
//服务发现
private void ServicesDiscovered(string address, string service)
{
BluetoothLEHardwareInterface.Log(address+"FOUNDFSERVICE" + 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);
}
}
//特征值发现
private void CharacteristicsDiscovered(string address, string service, string characteristic)
{
BluetoothLEHardwareInterface.Log(address + "发现特征值:" + 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);
}
}
//设备主动断开处理
private void PeripheralDisconnected(string address, BlePeripheralInfo info)
{
var currentCallback = this.callbacks.Where(c => c.Key.MatchAddress(address));
if (currentCallback.Any())
{
this.callbacks.Remove(currentCallback.First().Key);
}
var characteristicCallback = characteristicNotificationCallbacks.Where(c => c.Key.MatchAddress(address));
if (characteristicCallback.Any())
{
characteristicNotificationCallbacks.Remove(characteristicCallback.First().Key);
}
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
//设备断开连接
public void DisconnectPeripheral(BlePeripheralInfo peripheral, Action callback)
{
BluetoothLEHardwareInterface.DisconnectPeripheral(peripheral.Address, (address) =>
{
Debug.Log("断开回调"+ 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 StopScan()
{
bleMobileThread?.Stop();
}
//发现服务列表
public void DiscoverServices(BlePeripheralInfo peripheral, Action<IBleWinHwInterface, BlePeripheralInfo, BleResponse<List<BleServiceInfo>>> callback)
{
if (!this.servicesCallbacks.ContainsKey(peripheral))
{
this.servicesCallbacks.Add(peripheral, callback);
}
}
//发现特征值
public void DiscoverCharacteristic(BleServiceInfo service, CharacteristicsDiscoveredCallback callback)
{
if (!this.characteristicsDiscoveredCallbacks.ContainsKey(service))
{
this.characteristicsDiscoveredCallbacks.Add(service, callback);
}
}
//订阅特征值
public void SubscribeCharacteristic(BleCharacteristicInfo characteristic, Action<IBleWinHwInterface, BleCharacteristicInfo, BleResponse> callback)
{
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) =>
{
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)
{
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);
BluetoothLEHardwareInterface.Log("Write Succeeded");
});
}
public void Dispose()
{
bleMobileThread.ManagerInitialized -= BleMobileThread_ManagerInitialized;
bleMobileThread.ManagerStatusChanged -= ManagerStatusChanged;
bleMobileThread.ScanInfoReceived -= WatcherScanInfoReceived;
bleMobileThread.Dispose();
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)
{
}
}
}
}