接入蓝牙基本结构

This commit is contained in:
suntao 2021-05-19 14:38:48 +08:00
parent 84e8b50bbf
commit 2f84f70a5f
152 changed files with 6426 additions and 56 deletions

Binary file not shown.

View File

@ -0,0 +1,27 @@
fileFormatVersion: 2
guid: cfc0710c09383b54f8aa661624975c47
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

View File

@ -7,6 +7,7 @@ using UnityEngine;
using System.Net;
using System.Globalization;
using System.Threading;
using Assets.Scripts.Devices;
public static class App
{
@ -50,6 +51,19 @@ public static class App
//public static string AppDownloadUrl { get; internal set; }
//public static string AppVersionCode { get; internal set; }
private static MainDeviceAdapter mainDeviceAdapter;
public static MainDeviceAdapter MainDeviceAdapter
{
get
{
if(mainDeviceAdapter == null)
{
mainDeviceAdapter = new MainDeviceAdapter();
}
return mainDeviceAdapter;
}
}
static App()
{
CultureInfo currentCulture = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone();

View File

@ -0,0 +1,33 @@
using Assets.Scripts.Devices.Ant;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Devices
{
public abstract class AbstractDevice
{
public virtual DeviceState State { get; set; } = DeviceState.Disconnected;
public SensorType Sensor { get; protected set; }
public virtual string Name
{
get;
protected set;
}
public virtual ushort DeviceNumber { get; set; }
public virtual int Priority
{
get; protected set;
}
public abstract void Connect();
public abstract void Disconnect(bool save = true);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c92a5d01ab0176b46bb79faf3ffa2fc0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -12,16 +12,12 @@ namespace Assets.Scripts.Devices.Ant
{
public abstract class AbstractAntDevice : DataSourceBase
{
public string Name
{
get;
protected set;
}
public AntChannelProfile searchProfile;
public bool isInitialized = false;
private DeviceState state;
public DeviceState State
public override DeviceState State
{
get
{
@ -37,7 +33,7 @@ namespace Assets.Scripts.Devices.Ant
StateChange?.Invoke(state);
}
}
public SensorType Sensor { get; private set; }
private int _ManufacturerId;
/// <summary>
@ -56,7 +52,7 @@ namespace Assets.Scripts.Devices.Ant
}
private ushort _DeviceNumber;
public ushort DeviceNumber
public override ushort DeviceNumber
{
get
{
@ -92,10 +88,6 @@ namespace Assets.Scripts.Devices.Ant
public bool pairingEnabled;
}
public virtual int Priority
{
get; protected set;
}
//private readonly Rhino.PowerFun.Services.DeviceService deviceService;
//private readonly DeviceDetailService _deviceDetailService;
@ -174,7 +166,7 @@ namespace Assets.Scripts.Devices.Ant
// base.reset();
//}
public void Connect()
public override void Connect()
{
if (State == DeviceState.Connected || State == DeviceState.Connecting)
return;
@ -182,7 +174,7 @@ namespace Assets.Scripts.Devices.Ant
AntConnector.Instance().ConnectDevice(this);
}
public void Disconnect(bool save = true)
public override void Disconnect(bool save = true)
{
if (State == DeviceState.Disconnected || State == DeviceState.Disconnecting)
return;

View File

@ -0,0 +1,61 @@
using Assets.Scripts.UI.Prefab.Device;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Assets.Scripts.Devices.Ant
{
public class AntDeviceAdapter : DeviceAdapter
{
public override ConnectionInterface Interface => ConnectionInterface.ANT;
public AntDeviceAdapter()
{
AntConnector.Instance((device2) => {
if (device2.State == DeviceState.Disconnected)
{
//Debug.Log($"探索到新的设备{ device2.DeviceNumber }");
//自动连接
if (DeviceCache.Exist(device2))
{
Debug.Log("自动连接" + device2.DeviceNumber);
device2.Connect();
}
}
}, Debug.Log);
}
public override DeviceAdapterState GetState()
{
if (AntConnector.Instance().IsAvailable)
{
return DeviceAdapterState.On;
}
return DeviceAdapterState.Unavailable;
}
public override IEnumerable<AbstractDevice> GetDevices()
{
return AntConnector.Instance().discoveredDevices;
}
public override void StartScan()
{
//throw new NotImplementedException();
}
public override void StopScan()
{
//throw new NotImplementedException();
}
public override void Dispose()
{
AntConnector.Instance().Dispose();
base.Dispose();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aa2b23675a0486a40881d44a57de8d73
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace Assets.Scripts.Devices.Ant
{
public abstract class DataSourceBase
public abstract class DataSourceBase : AbstractDevice
{
//double distanceTravelled = 0;
//DataSourcePacket lastPacketRcvd = null;

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 157803f0c8b4ed542a209a947896097b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts
{
public static class BitConvertHelper
{
public static byte Lsn(byte b)
{
return (byte)(b & 15);
}
// Token: 0x060032F7 RID: 13047 RVA: 0x000C22C3 File Offset: 0x000C04C3
public static byte Lsn(byte[] bytes, int index)
{
return BitConvertHelper.Lsn(bytes[index]);
}
public static byte ToUInt8(byte[] bytes, int index)
{
return bytes[index];
}
// Token: 0x060032FB RID: 13051 RVA: 0x000C22E8 File Offset: 0x000C04E8
public static ushort ToUInt12(byte[] bytes, int index)
{
return (ushort)((int)bytes[index] + ((int)BitConvertHelper.Lsn(bytes[index + 1]) << 8));
}
public static ushort ToUInt16(byte[] bytes, int startIndex)
{
return BitConverter.ToUInt16(bytes, startIndex);
}
public static short ToInt16(byte[] bytes, int startIndex)
{
return BitConverter.ToInt16(bytes, startIndex);
}
public static uint ToUInt32(byte[] bytes, int startIndex)
{
return BitConverter.ToUInt32(bytes, startIndex);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 26dac648c68553d4bb2bccf4e54c4dfc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,77 @@
using Assets.Scripts.Devices.Ble;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble
{
public abstract class BleCharacteristicInfo
{
// Token: 0x170005BF RID: 1471
// (get) Token: 0x06001FE3 RID: 8163 RVA: 0x00085CF7 File Offset: 0x00083EF7
public BlePeripheralInfo Peripheral
{
get
{
return this.Service.Peripheral;
}
}
// Token: 0x170005C0 RID: 1472
// (get) Token: 0x06001FE4 RID: 8164 RVA: 0x00085D04 File Offset: 0x00083F04
public BleServiceInfo Service { get; }
// Token: 0x170005C1 RID: 1473
// (get) Token: 0x06001FE5 RID: 8165 RVA: 0x00085D0C File Offset: 0x00083F0C
public Guid Id { get; }
// Token: 0x170005C2 RID: 1474
// (get) Token: 0x06001FE6 RID: 8166 RVA: 0x00085D14 File Offset: 0x00083F14
public BleCharacteristicProperties Properties { get; }
// Token: 0x06001FE7 RID: 8167 RVA: 0x00085D1C File Offset: 0x00083F1C
protected BleCharacteristicInfo(Guid id, BleServiceInfo service, BleCharacteristicProperties properties)
{
this.Id = id;
this.Service = service;
this.Properties = properties;
}
// Token: 0x06001FE8 RID: 8168 RVA: 0x00085D3C File Offset: 0x00083F3C
public bool MatchGuid(Guid guid)
{
return this.Id.Equals(guid);
}
// Token: 0x06001FE9 RID: 8169 RVA: 0x00085D58 File Offset: 0x00083F58
public bool MatchAddress(string address)
{
return this.Peripheral.MatchAddress(address);
}
// Token: 0x06001FEA RID: 8170 RVA: 0x00085D68 File Offset: 0x00083F68
public override bool Equals(object obj)
{
if (obj == null || !(base.GetType() == obj.GetType()))
{
return false;
}
BleCharacteristicInfo bleCharacteristicInfo = (BleCharacteristicInfo)obj;
return this.Id.Equals(bleCharacteristicInfo.Id) && this.Service.Equals(bleCharacteristicInfo.Service);
}
// Token: 0x06001FEB RID: 8171 RVA: 0x00085DC0 File Offset: 0x00083FC0
public override int GetHashCode()
{
return (17 * 23 + this.Id.GetHashCode()) * 23 + this.Peripheral.GetHashCode();
}
// Token: 0x06001FEC RID: 8172 RVA: 0x00085DF6 File Offset: 0x00083FF6
public override string ToString()
{
return this.Id.ToString();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f417f704e04e35e4aaef2dcd366551ab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble
{
[Flags]
public enum BleCharacteristicProperties
{
// Token: 0x0400115A RID: 4442
Broadcast = 1,
// Token: 0x0400115B RID: 4443
Read = 2,
// Token: 0x0400115C RID: 4444
WriteWithoutResponse = 4,
// Token: 0x0400115D RID: 4445
Write = 8,
// Token: 0x0400115E RID: 4446
Notify = 16,
// Token: 0x0400115F RID: 4447
Indicate = 32,
// Token: 0x04001160 RID: 4448
SignedWrites = 64,
// Token: 0x04001161 RID: 4449
ExtendedProperties = 128
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 44ea993e814c6f8408d93324b7cf4232
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble
{
public enum BleCharacteristicWriteType
{
// Token: 0x04001163 RID: 4451
WriteWithResponse,
// Token: 0x04001164 RID: 4452
WriteWithoutResponse
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 849439c6d534a5f4c9fd3ae52018478f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,236 @@
using Assets.Scripts.Ble;
using Assets.Scripts.Ble.HeartRate;
using Assets.Scripts.Ble.Service;
using Assets.Scripts.Devices.Ant;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Assets.Scripts.Devices.Ble
{
public abstract class BleDevice : AbstractDevice
{
protected BleWinHwInterface hwInterface;
protected BlePeripheralInfo peripheralInfo;
private readonly HashSet<BleService> services = new HashSet<BleService>();
private readonly HashSet<BleServiceInfo> pendingServices = new HashSet<BleServiceInfo>();
public override string Name { get => peripheralInfo.Name; protected set => base.Name = value; }
public BleDevice(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface, SensorType sensor) //: base(peripheralInfo)
{
this.hwInterface = bleWinHwInterface;
this.hwInterface.BluetoothStateChangedEvent += BluetoothStateChangedEvent;
this.peripheralInfo = peripheralInfo;
base.Sensor = sensor;
//base.Name = this.peripheralInfo.Name;
//Debug.Log(base.Name + "," + sensor.ToString());
}
public void ConnectToPeripheralIfPossible()
{
this.hwInterface.ConnectPeripheral(this.peripheralInfo, PeripheralConnectedAction);
}
private void PeripheralConnectedAction(BleWinHwInterface hwInterface, BlePeripheralInfo sender, BleResponse response)
{
if (response.IsSuccess)
{
State = DeviceState.Connected;
Debug.Log("连接成功");
hwInterface.DiscoverServices(this.peripheralInfo, ServicesDiscoveredAction);//, this.ServicesDiscoveredAction);
}
}
private void ServicesDiscoveredAction(BleWinHwInterface hwInterface, BlePeripheralInfo sender, BleResponse<List<BleServiceInfo>> response)
{
//Debug.Log("hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh");
this.CreateServices(response.Data);
}
protected abstract void CreateServices(List<BleServiceInfo> discoveredServices);
//private void CreateServices(List<BleServiceInfo> discoveredServices)
//{
// foreach (var item in discoveredServices)
// {
//BleService service = null;
//if (item.MatchGuid(ServiceUuids.Services.Single(s => s.IdByteArray == ServiceUuids.DeviceInformation).IdGuid))
//{
// Debug.Log("device infomation");
//}
//else if (item.MatchGuid(ServiceUuids.Services.Single(s => s.IdByteArray == ServiceUuids.Battery).IdGuid))
//{
// Debug.Log("battery");
// //service = new BatteryService(item, this.hwInterface);
//}
//else if (item.MatchGuid(ServiceUuids.Get(ServiceUuids.HeartRate).IdGuid))
//{
// Debug.Log("发现 heartRate 服务");
// service = new HeartRateService(item, this.hwInterface);
//}
//else if (item.MatchGuid(ServiceUuids.Get(ServiceUuids.CyclingSpeedCadence).IdGuid))
//{
// //service = new CyclingSpeedCadence.CyclingSpeedCadenceService(item, this.hwInterface);
//}
//else if (item.MatchGuid(ServiceUuids.Get(ServiceUuids.CyclingPower).IdGuid))
//{
// Debug.Log("cycling power");
// this.CreateCyclingPowerService(item);
//}
//else if (item.MatchGuid(ServiceUuids.Services.Single(s => s.IdByteArray == ServiceUuids.Ftms).IdGuid))
//{
// Debug.Log("ftms");
// this.CreateFtmsService(item);
//}
//else if (item.MatchGuid(ServiceUuids.Services.Single(s => s.IdByteArray == ServiceUuids.TacxBle).IdGuid))
//{
// Debug.Log("tacx ble");
// //service = new TacxFecService(item, this.hwInterface);
//}
//this.AddService(service, null);
// }
//}
private void CreateFtmsService(BleServiceInfo serviceInfo)
{
this.hwInterface.DiscoverCharacteristic(serviceInfo, (hwInterface, bleServiceInfo, response) =>
{
if (this.CheckPendingServiceCharacteristicsResponse(serviceInfo, response))
{
this.CreateFtmsService(serviceInfo, response);
}
});
}
private void CreateFtmsService(BleServiceInfo serviceInfo, BleResponse<List<BleCharacteristicInfo>> response)
{
BleService service;
//if (response.Data.Any((BleCharacteristicInfo characteristicInfo) => characteristicInfo.MatchGuid(BleApi.Characteristics.CycleOpsFtmsSystemWeight)))
//{
//service = new CycleOpsFtmsService(serviceInfo, base.Settings, this.hwInterface, new ServiceStateChanged(this.ServiceStateChanged), new ServiceCapabilitiesUpdated(this.ServiceCapabilitiesUpdated));
//}
//else
//{
//FixType fixType = FixType.FtmsFeature7ByteResponse;
//if (this.IsWattbike())
//{
// fixType |= FixType.WattbikeFeatureInconsistency;
//}
//service = new FtmsService(serviceInfo, base.Settings, this.hwInterface, new ServiceStateChanged(this.ServiceStateChanged), new ServiceCapabilitiesUpdated(this.ServiceCapabilitiesUpdated), fixType);
//service = new Ftms.FtmsService(serviceInfo, hwInterface);
//}
//this.AddService(service, response);
}
private void CreateCyclingPowerService(BleServiceInfo serviceInfo)
{
this.pendingServices.Add(serviceInfo);
this.hwInterface.DiscoverCharacteristic(serviceInfo, (hwInterface, service, response) =>
{
if (this.CheckPendingServiceCharacteristicsResponse(serviceInfo, response))
{
this.CreateCyclingPowerService(serviceInfo, response);
}
});
}
private void CreateCyclingPowerService(BleServiceInfo serviceInfo, BleResponse<List<BleCharacteristicInfo>> response)
{
//BleService service = null;
//if (response.Data.Any((BleCharacteristicInfo characteristicInfo) => characteristicInfo.MatchGuid(ServiceUuids.Characteristics.WahooControlPoint)))
//{
// //service = new WahooService(serviceInfo, base.Settings, this.hwInterface, new ServiceStateChanged(this.ServiceStateChanged), new ServiceCapabilitiesUpdated(this.ServiceCapabilitiesUpdated), fixType);
//}
//else
//{
// service = new CyclingPowerService(serviceInfo, this.hwInterface);
// this.AddService(service, response);
//}
}
private void AddService(BleService service, BleResponse<List<BleCharacteristicInfo>> scanCharacteristicsResponse = null)
{
if (service == null)
{
return;
}
this.services.Add(service);
service.DiscoverCharacteristics(scanCharacteristicsResponse);
}
private bool CheckPendingServiceCharacteristicsResponse(BleServiceInfo serviceInfo, BleResponse bleResponse)
{
if (bleResponse.IsSuccess)
{
return true;
}
this.pendingServices.Remove(serviceInfo);
this.CheckAndSetConnectionStatus();
return false;
}
public void SendCommand()
{
}
private void CheckAndSetConnectionStatus()
{
}
private void Disconnect()
{
if (this.State != DeviceState.Disconnected)
{
this.hwInterface.DisconnectPeripheral(this.peripheralInfo, ()=> {
this.State = DeviceState.Disconnected;
});
}
}
private void BluetoothStateChangedEvent(BleWinHwInterface hwInterface, BleState state)
{
switch (state)
{
case BleState.Unknown:
break;
case BleState.Unavailable:
break;
case BleState.Unauthorize:
break;
case BleState.Reseting:
break;
case BleState.Off:
this.Disconnect();
break;
case BleState.On:
break;
default:
break;
}
}
public override void Connect()
{
this.ConnectToPeripheralIfPossible();
}
public override void Disconnect(bool save = true)
{
//throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b14e74cc46a1e184ea96a01f17bb4e3a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,78 @@
using Assets.Scripts.Ble;
using Assets.Scripts.Ble.Service;
using Assets.Scripts.Devices.Ble.Devices;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Assets.Scripts.Devices.Ble
{
public class BleDeviceAdapter : DeviceAdapter
{
public override ConnectionInterface Interface => ConnectionInterface.BLE;
private IDictionary<string, BleDevice> discoveredDevices = new Dictionary<string, BleDevice>();
private BleWinHwInterface hwInterface;
public BleDeviceAdapter()
{
hwInterface = BleWinHwInterface.GetInterface();
}
public override IEnumerable<AbstractDevice> GetDevices()
{
//throw new NotImplementedException();
return discoveredDevices.Select(d => d.Value);
}
public override DeviceAdapterState GetState()
{
if(hwInterface.BleState == BleState.On)
{
return DeviceAdapterState.On;
}
return DeviceAdapterState.Unavailable;
}
public override void StartScan()
{
hwInterface.StartScan((device) =>
{
if (!discoveredDevices.ContainsKey(device.Peripheral.Address))
{
Debug.Log("发现设备" + device.Peripheral.Address + device.Peripheral.Name + ", type:" + device.SensorType);
if(device.SensorType == Ant.SensorType.Trainer)
{
//var device1 = new Ftms(device.Peripheral, hwInterface);
//discoveredDevices.Add(device.Peripheral.Address, device1);
}
else if(device.SensorType == Ant.SensorType.HeartRate)
{
var device1 = new HeartRate(device.Peripheral, hwInterface);
discoveredDevices.Add(device.Peripheral.Address, device1);
}
else if(device.SensorType == Ant.SensorType.Power)
{
var device1 = new CyclingPower(device.Peripheral, hwInterface);
discoveredDevices.Add(device.Peripheral.Address, device1);
}
//discoveredDevices.Add(device.Peripheral.Address, new BleDevice(device.Peripheral, hwInterface, device.SensorType));
}
});
}
public override void StopScan()
{
}
public override void Dispose()
{
hwInterface.Dispose();
base.Dispose();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 21c2c84c243633f4ba4403b51c0272c9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Devices.Ble
{
public class BleHwInterfaceError
{
public int? Code { get; }
// Token: 0x170005C4 RID: 1476
// (get) Token: 0x06001FEE RID: 8174 RVA: 0x00085E0B File Offset: 0x0008400B
public string Domain { get; }
// Token: 0x170005C5 RID: 1477
// (get) Token: 0x06001FEF RID: 8175 RVA: 0x00085E13 File Offset: 0x00084013
public string Description { get; }
// Token: 0x06001FF0 RID: 8176 RVA: 0x00085E1B File Offset: 0x0008401B
public BleHwInterfaceError(int? code, string domain, string description)
{
this.Code = code;
this.Domain = domain;
this.Description = description;
}
// Token: 0x06001FF1 RID: 8177 RVA: 0x00085E38 File Offset: 0x00084038
public BleHwInterfaceError(string description) : this(null, null, description)
{
}
// Token: 0x06001FF2 RID: 8178 RVA: 0x00085E58 File Offset: 0x00084058
public override string ToString()
{
int? code = this.Code;
if (code != null && this.Domain == "WclBleGattClientErrorDomain")
{
string str = "BleHWPluginError:\n";
code = this.Code;
return str + ((code != null) ? code.GetValueOrDefault().ToString() : null) + "\n-Description: " + this.Description;
}
code = this.Code;
if (code != null && this.Domain != null)
{
return string.Format("BleHWPluginError:\n-Domain: {0}\n-Code: {1}\n-Description: {2}", this.Domain, this.Code, this.Description);
}
return "BleHWPluginError:-Description: " + this.Description;
}
// Token: 0x06001FF3 RID: 8179 RVA: 0x00085F08 File Offset: 0x00084108
public static BleHwInterfaceError ParseFromString(string message)
{
string[] array = (message != null) ? message.Split(new char[]
{
'|'
}, 3, StringSplitOptions.RemoveEmptyEntries) : null;
if (array == null || array.Length == 0)
{
return null;
}
int value;
if (array.Length == 3 && int.TryParse(array[1], out value))
{
return new BleHwInterfaceError(new int?(value), array[0], array[2]);
}
return new BleHwInterfaceError(message);
}
// Token: 0x06001FF4 RID: 8180 RVA: 0x00085F64 File Offset: 0x00084164
public override int GetHashCode()
{
return (this.Code.GetHashCode() * 397 ^ ((this.Domain != null) ? this.Domain.GetHashCode() : 0)) * 397 ^ ((this.Description != null) ? this.Description.GetHashCode() : 0);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 58ab8c2cfa7e96e43b69bb7e0e7e10c3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Devices.Ble
{
public abstract class BlePeripheralInfo
{
// Token: 0x170005C6 RID: 1478
// (get) Token: 0x06001FF5 RID: 8181 RVA: 0x00085FBF File Offset: 0x000841BF
// (set) Token: 0x06001FF6 RID: 8182 RVA: 0x00085FC7 File Offset: 0x000841C7
public string Name { get; protected set; }
// Token: 0x170005C7 RID: 1479
// (get) Token: 0x06001FF7 RID: 8183 RVA: 0x00085FD0 File Offset: 0x000841D0
public string Address { get; }
// Token: 0x06001FF8 RID: 8184 RVA: 0x00085FD8 File Offset: 0x000841D8
protected BlePeripheralInfo(string address, string name)
{
this.Address = address;
this.Name = name;
}
// Token: 0x06001FF9 RID: 8185 RVA: 0x00085FEE File Offset: 0x000841EE
public bool MatchAddress(string address)
{
return address != null && address.Equals(this.Address);
}
// Token: 0x06001FFA RID: 8186 RVA: 0x00086001 File Offset: 0x00084201
public override bool Equals(object other)
{
return other != null && base.GetType() == other.GetType() && this.Address.Equals(((BlePeripheralInfo)other).Address);
}
// Token: 0x06001FFB RID: 8187 RVA: 0x00086031 File Offset: 0x00084231
public override int GetHashCode()
{
return this.Address.GetHashCode();
}
// Token: 0x06001FFC RID: 8188 RVA: 0x00086040 File Offset: 0x00084240
public override string ToString()
{
return string.Concat(new string[]
{
base.GetType().Name,
": ",
string.IsNullOrEmpty(this.Name) ? "" : (this.Name + " "),
"[",
this.Address,
"]"
});
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 006773ea103cc3042a0b5e2f815a24eb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Devices.Ble
{
public class BleResponse
{
// Token: 0x170005C8 RID: 1480
// (get) Token: 0x06001FFD RID: 8189 RVA: 0x000860AE File Offset: 0x000842AE
// (set) Token: 0x06001FFE RID: 8190 RVA: 0x000860B6 File Offset: 0x000842B6
public bool IsSuccess { get; set; }
// Token: 0x170005C9 RID: 1481
// (get) Token: 0x06001FFF RID: 8191 RVA: 0x000860BF File Offset: 0x000842BF
// (set) Token: 0x06002000 RID: 8192 RVA: 0x000860C7 File Offset: 0x000842C7
public BleHwInterfaceError Error { get; set; }
// Token: 0x06002001 RID: 8193 RVA: 0x000860D0 File Offset: 0x000842D0
public override string ToString()
{
return (this.IsSuccess ? "Success" : "Fail") + "\n" + ((this.Error == null) ? "" : this.Error.ToString());
}
}
public class BleResponse<T> : BleResponse
{
// Token: 0x170005CA RID: 1482
// (get) Token: 0x06002003 RID: 8195 RVA: 0x00086112 File Offset: 0x00084312
// (set) Token: 0x06002004 RID: 8196 RVA: 0x0008611A File Offset: 0x0008431A
public T Data { get; set; }
// Token: 0x06002005 RID: 8197 RVA: 0x00086123 File Offset: 0x00084323
public override string ToString()
{
return base.ToString() + "\n" + this.Data;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8d19e34c55f7b3347ac0cbc36b231d9e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Devices.Ble
{
public abstract class BleServiceInfo
{
// Token: 0x170005CB RID: 1483
// (get) Token: 0x06002007 RID: 8199 RVA: 0x00086148 File Offset: 0x00084348
public BlePeripheralInfo Peripheral { get; }
// Token: 0x170005CC RID: 1484
// (get) Token: 0x06002008 RID: 8200 RVA: 0x00086150 File Offset: 0x00084350
public Guid Id { get; }
// Token: 0x06002009 RID: 8201 RVA: 0x00086158 File Offset: 0x00084358
protected BleServiceInfo(Guid id, BlePeripheralInfo peripheral)
{
this.Id = id;
this.Peripheral = peripheral;
}
// Token: 0x0600200A RID: 8202 RVA: 0x00086170 File Offset: 0x00084370
public bool MatchGuid(Guid serviceId)
{
return this.Id.Equals(serviceId);
}
// Token: 0x0600200B RID: 8203 RVA: 0x0008618C File Offset: 0x0008438C
public bool MatchAddress(string address)
{
return this.Peripheral.MatchAddress(address);
}
// Token: 0x0600200C RID: 8204 RVA: 0x0008619C File Offset: 0x0008439C
public override bool Equals(object obj)
{
if (obj == null || !(base.GetType() == obj.GetType()))
{
return false;
}
BleServiceInfo bleServiceInfo = (BleServiceInfo)obj;
return this.Id.Equals(bleServiceInfo.Id) && this.Peripheral.Equals(bleServiceInfo.Peripheral);
}
// Token: 0x0600200D RID: 8205 RVA: 0x000861F4 File Offset: 0x000843F4
public override int GetHashCode()
{
return (17 * 23 + this.Id.GetHashCode()) * 23 + this.Peripheral.GetHashCode();
}
// Token: 0x0600200E RID: 8206 RVA: 0x0008622A File Offset: 0x0008442A
public override string ToString()
{
return this.Id.ToString();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 06cb344f28950ca4496070fab301ae52
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble
{
public enum BleState
{
// Token: 0x04001072 RID: 4210
Unknown,
// Token: 0x04001073 RID: 4211
Unavailable,
// Token: 0x04001074 RID: 4212
Unauthorize,
// Token: 0x04001075 RID: 4213
Reseting,
// Token: 0x04001076 RID: 4214
Off,
// Token: 0x04001077 RID: 4215
On
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3ac691d8c317dd743bf581fce607c5a3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble
{
public delegate void BluetoothStateChangedCallback(BleWinHwInterface hwInterface, BleState bleState);
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 663a2ebaee4b5a6428d06a6d0a113f9a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fb86ae4477864e74bb38dbdbf83bd787
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,29 @@
using Assets.Scripts.Ble.Commands;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.Characteristic
{
public abstract class BaseCharacteristicValue
{
protected BaseCharacteristicValue(Guid id, byte[] data)
{
this.RawData = data;
this.Id = id;
}
// Token: 0x17000665 RID: 1637
// (get) Token: 0x060022A2 RID: 8866 RVA: 0x0008F366 File Offset: 0x0008D566
public Guid Id { get; }
// Token: 0x17000666 RID: 1638
// (get) Token: 0x060022A3 RID: 8867 RVA: 0x0008F36E File Offset: 0x0008D56E
public byte[] RawData { get; }
// Token: 0x060022A4 RID: 8868
public abstract CommandResponseCode ToDeviceCommandResponseCode();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b2b671ee375ec854c8074b434d7ef555
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.Characteristic
{
public static class BleMathHelper
{
// Token: 0x06000028 RID: 40 RVA: 0x00002740 File Offset: 0x00000940
public static double WheelFrequency(WheelRevolution? lastWheelRevolution, WheelRevolution? newWheelRevolution, uint timeResolution)
{
return WheelRevolution.ComputeValue(lastWheelRevolution, newWheelRevolution, delegate (WheelRevolution lastValue, WheelRevolution newValue)
{
WheelRevolution wheelRevolution = newValue - lastValue;
return wheelRevolution.Count / ((double)wheelRevolution.Time / timeResolution);
});
}
// Token: 0x06000029 RID: 41 RVA: 0x0000276D File Offset: 0x0000096D
public static double CrankFrequency(CrankRevolution? lastCrankRevolutions, CrankRevolution? newCrankRevolutions)
{
return CrankRevolution.ComputeValue(lastCrankRevolutions, newCrankRevolutions, delegate (CrankRevolution lastValue, CrankRevolution newValue)
{
CrankRevolution crankRevolution = newValue - lastValue;
return (double)crankRevolution.Count / ((double)crankRevolution.Time / 1024.0);
});
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 94d000bcb9e71fe4cbc87260ce666252
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.Characteristic
{
public struct CrankRevolution
{
// Token: 0x060022A5 RID: 8869 RVA: 0x0008F378 File Offset: 0x0008D578
public static CrankRevolution operator -(CrankRevolution obj1, CrankRevolution obj2)
{
return new CrankRevolution
{
Count = (ushort)(obj1.Count - obj2.Count),
Time = (ushort)(obj1.Time - obj2.Time)
};
}
// Token: 0x060022A6 RID: 8870 RVA: 0x0008F3B8 File Offset: 0x0008D5B8
public static double ComputeValue(CrankRevolution? lastValue, CrankRevolution? newValue, Func<CrankRevolution, CrankRevolution, double> validValueComputation)
{
if (newValue == null || lastValue == null || validValueComputation == null)
{
return double.NaN;
}
if (newValue.Value.Time != lastValue.Value.Time)
{
return validValueComputation(lastValue.Value, newValue.Value);
}
if (newValue.Value.Count == lastValue.Value.Count)
{
return double.NaN;
}
throw new ArgumentException("CrankRevolution Count changed but Time remain same -> strange behaviour");
}
// Token: 0x060022A7 RID: 8871 RVA: 0x0008F441 File Offset: 0x0008D641
public override string ToString()
{
return string.Format("Time: {0}, Count: {1}", this.Time, this.Count);
}
// Token: 0x04001543 RID: 5443
public const ushort MaxCount = 65535;
// Token: 0x04001544 RID: 5444
public const ushort MaxTime = 65535;
// Token: 0x04001545 RID: 5445
public ushort Count;
// Token: 0x04001546 RID: 5446
public ushort Time;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1dea0a9f55f16ac45bfd5aa6a6eda4f4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,76 @@
using Assets.Scripts.Ble;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Assets.Scripts.Devices.Ble.Characteristic
{
public class HeartRateMeasurement
{
public Guid Uuid
{
get
{
return ServiceUuids.Characteristics.HrMeasurement;
}
}
public Guid ServiceUuid
{
get
{
return ServiceUuids.Get(ServiceUuids.HeartRate).IdGuid;
}
}
private HrmFormat Format { get; set; }
// Token: 0x170005EB RID: 1515
// (get) Token: 0x0600214D RID: 8525 RVA: 0x0008999B File Offset: 0x00087B9B
public int BeatsPerMinute { get; private set; }
public void HandleAttributeReceived(byte[] data)
{
HrmFlags hrmFlags = (HrmFlags)BitConvertHelper.ToUInt8(data, 0);
this.Format = (HrmFormat)(hrmFlags.HasFlag(HrmFlags.Format) ? 1 : 0);
if (this.Format == HrmFormat.Short)
{
this.BeatsPerMinute = BitConvertHelper.ToUInt8(data, 1);
Debug.Log("心率:" + this.BeatsPerMinute);
return;
}
if (data.Length < 3)
{
throw new ArgumentException("数据出错");
}
this.BeatsPerMinute = BitConvertHelper.ToUInt16(data, 1);
}
[Flags]
private enum HrmFlags
{
// Token: 0x040029D0 RID: 10704
Format = 1,
// Token: 0x040029D1 RID: 10705
SensorContactStatus1 = 2,
// Token: 0x040029D2 RID: 10706
SensorContactStatus2 = 4,
// Token: 0x040029D3 RID: 10707
Energy = 8,
// Token: 0x040029D4 RID: 10708
RR = 16
}
// Token: 0x02000921 RID: 2337
private enum HrmFormat
{
// Token: 0x040029D6 RID: 10710
Short,
// Token: 0x040029D7 RID: 10711
Long
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c3d7a13de9df31a478b0a0c9dbcb1ac4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,22 @@
using Assets.Scripts.Ble.Commands;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.Characteristic
{
public abstract class SuccessOnlyCharacteristicValue : BaseCharacteristicValue
{
protected SuccessOnlyCharacteristicValue(Guid id, byte[] data) : base(id, data)
{
}
// Token: 0x060022AB RID: 8875 RVA: 0x0008F4F0 File Offset: 0x0008D6F0
public override CommandResponseCode ToDeviceCommandResponseCode()
{
return CommandResponseCode.Success;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: afeabe604a3dc29409ecbf61f6939275
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.Characteristic
{
public struct WheelRevolution
{
// Token: 0x060022AE RID: 8878 RVA: 0x0008F510 File Offset: 0x0008D710
public static WheelRevolution operator -(WheelRevolution obj1, WheelRevolution obj2)
{
return new WheelRevolution
{
Count = obj1.Count - obj2.Count,
Time = (ushort)(obj1.Time - obj2.Time)
};
}
// Token: 0x060022AF RID: 8879 RVA: 0x0008F550 File Offset: 0x0008D750
public static double ComputeValue(WheelRevolution? lastValue, WheelRevolution? newValue, Func<WheelRevolution, WheelRevolution, double> validValueComputation)
{
if (newValue == null || lastValue == null)
{
return double.NaN;
}
if (newValue.Value.Time != lastValue.Value.Time)
{
return validValueComputation(lastValue.Value, newValue.Value);
}
if (newValue.Value.Count == lastValue.Value.Count)
{
return double.NaN;
}
throw new ArgumentException("WheelRevolution Count changed but Time remain same -> strange behaviour");
}
// Token: 0x060022B0 RID: 8880 RVA: 0x0008F5D6 File Offset: 0x0008D7D6
public override string ToString()
{
return string.Format("Time: {0}, Count: {1}", this.Time, this.Count);
}
// Token: 0x04001548 RID: 5448
public const uint MaxCount = 4294967295U;
// Token: 0x04001549 RID: 5449
public const ushort MaxTime = 65535;
// Token: 0x0400154A RID: 5450
public uint Count;
// Token: 0x0400154B RID: 5451
public ushort Time;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ee3e38fcbff71ea4f90a92eb251bcad4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,11 @@
using Assets.Scripts.Devices.Ble;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble
{
public delegate void CharacteristicReadCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response);
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c69fa47ce56b72942920665130ab2bde
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,11 @@
using Assets.Scripts.Devices.Ble;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble
{
public delegate void CharacteristicsDiscoveredCallback(BleWinHwInterface hwInterface, BleServiceInfo service, BleResponse<List<BleCharacteristicInfo>> response);
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 18b405762349d704d807b732d2ddb8b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b91b6f3c17790a0429113c8b8cba4da1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.Commands
{
public enum CommandResponseCode
{
// Token: 0x04000FEB RID: 4075
Success = 1,
// Token: 0x04000FEC RID: 4076
NotSupported,
// Token: 0x04000FED RID: 4077
InvalidParameter,
// Token: 0x04000FEE RID: 4078
OperationFailed,
// Token: 0x04000FEF RID: 4079
UnexpectedResult,
// Token: 0x04000FF0 RID: 4080
TypeMismatch,
// Token: 0x04000FF1 RID: 4081
Expired
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 49da5bf4f261fb04b927a90f0e1dd85b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 925f23e73bb082b4f8420a22aa1a96e6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,52 @@
using Assets.Scripts.Ble;
using Assets.Scripts.Devices.Ant.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Assets.Scripts.Devices.Ble.Devices
{
public class CyclingPower : BleDevice, IPowerDevice
{
private List<BleServiceInfo> Services;
public CyclingPower(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Power)
{
bleWinHwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
}
public int Power { get => 999; set => throw new NotImplementedException(); }
protected override void CreateServices(List<BleServiceInfo> discoveredServices)
{
this.Services = discoveredServices;
foreach (var service in this.Services)
{
hwInterface.DiscoverCharacteristic(service, (hwInterface, service1, response) =>
{
foreach (var character in response.Data)
{
if (character.MatchGuid(ServiceUuids.Characteristics.CyclingPowerMeasurement))
{
Debug.Log("功率功能");
this.hwInterface.SubscribeCharacteristic(character, (hw, cha, res) =>
{
Debug.Log("1111111111111111111111");
});
}
}
});
}
}
private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
{
Debug.Log("main call" + string.Join(",", response.Data));
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1bfee528ff9d5854a87190f63ce65ee6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,26 @@
using Assets.Scripts.Ble;
using Assets.Scripts.Devices.Ant.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Devices.Ble.Devices
{
public class Ftms : BleDevice, IPowerDevice
{
public Ftms(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) :base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Trainer)
{
}
public int Power { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
protected override void CreateServices(List<BleServiceInfo> discoveredServices)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3c3826d0749b3b743876392548083207
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,62 @@
using Assets.Scripts.Ble;
using Assets.Scripts.Devices.Ant.Interfaces;
using Assets.Scripts.Devices.Ble.Characteristic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Assets.Scripts.Devices.Ble.Devices
{
public class HeartRate : BleDevice, IHeartRateDevice
{
int IHeartRateDevice.HeartRate { get => heartRateMeasurement.BeatsPerMinute; set => throw new NotImplementedException(); }
private List<BleServiceInfo> Services;
private HeartRateMeasurement heartRateMeasurement;
public HeartRate(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.HeartRate)
{
Debug.Log("创建心率设备");
heartRateMeasurement = new HeartRateMeasurement();
bleWinHwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
}
protected override void CreateServices(List<BleServiceInfo> discoveredServices)
{
//throw new NotImplementedException();
this.Services = discoveredServices;
foreach (var service in this.Services)
{
hwInterface.DiscoverCharacteristic(service, (hwInterface, service1, response) =>
{
foreach (var character in response.Data)
{
if (character.MatchGuid(heartRateMeasurement.Uuid))
{
Debug.Log("心率功能");
this.hwInterface.SubscribeCharacteristic(character, (hw, cha, res) =>
{
Debug.Log("1111111111111111111111");
});
}
}
});
}
}
private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
{
Debug.Log("main call" + string.Join(",", response.Data));
heartRateMeasurement.HandleAttributeReceived(response.Data);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b880a0d1b518452488d5e1a69d0cc1ff
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f4e5e995271d2b04ea04a51eb6c999c5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,17 @@
using Assets.Scripts.Ble.Commands;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Devices.Ble.Extension
{
public static class EnumExtensions
{
public static CommandResponseCode ToDeviceCommandResponseType(this BleHwInterfaceError error)
{
return CommandResponseCode.OperationFailed;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2e363293eef5f264c9de132f6c24b01e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d9ddacaed9a7562489aa2476a0f74aca
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,70 @@
using Assets.Scripts.Ble.Characteristic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.HeartRate
{
public class HeartRateMeasurementValue : SuccessOnlyCharacteristicValue
{
private HeartRateMeasurementValue.HrmFormat Format { get; }
// Token: 0x170005EB RID: 1515
// (get) Token: 0x0600214D RID: 8525 RVA: 0x0008999B File Offset: 0x00087B9B
public int BeatsPerMinute { get; }
public HeartRateMeasurementValue(byte[] data): base(ServiceUuids.Characteristics.HrMeasurement, data)
{
if(data == null || data.Length < 2)
{
throw new ArgumentException(string.Concat(new string[]
{
"Invalid data for ",
base.Id.ToString(),
" ",
(data != null) ? string.Join(",", data) : null,
"."
}), "data");
}
HeartRateMeasurementValue.HrmFlags hrmFlags = (HeartRateMeasurementValue.HrmFlags)BitConvertHelper.ToUInt8(data, 0);
this.Format = (HrmFormat)(hrmFlags.HasFlag(HeartRateMeasurementValue.HrmFlags.Format) ? 1 : 0);
if (this.Format == HeartRateMeasurementValue.HrmFormat.Short)
{
this.BeatsPerMinute = BitConvertHelper.ToUInt8(data, 1);
return;
}
if(data.Length < 3)
{
throw new ArgumentException("数据出错");
}
this.BeatsPerMinute = BitConvertHelper.ToUInt16(data, 1);
}
[Flags]
private enum HrmFlags
{
// Token: 0x040029D0 RID: 10704
Format = 1,
// Token: 0x040029D1 RID: 10705
SensorContactStatus1 = 2,
// Token: 0x040029D2 RID: 10706
SensorContactStatus2 = 4,
// Token: 0x040029D3 RID: 10707
Energy = 8,
// Token: 0x040029D4 RID: 10708
RR = 16
}
// Token: 0x02000921 RID: 2337
private enum HrmFormat
{
// Token: 0x040029D6 RID: 10710
Short,
// Token: 0x040029D7 RID: 10711
Long
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3668128267e8c52448ad703e31f8bd88
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,60 @@
using Assets.Scripts.Ble.Commands;
using Assets.Scripts.Ble.Service;
using Assets.Scripts.Commands;
using Assets.Scripts.Devices.Ble;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Assets.Scripts.Ble.HeartRate
{
public class HeartRateService : BleService
{
private BleCharacteristicInfo heartRateCharacteristic;
public HeartRateService(BleServiceInfo serviceInfo, BleWinHwInterface bleWinHwInterface) :base(serviceInfo, bleWinHwInterface)
{
}
protected override void CharacteristicsDiscovered(BleResponse<List<BleCharacteristicInfo>> response)
{
foreach (var item in response.Data)
{
if (item.MatchGuid(ServiceUuids.Characteristics.HrMeasurement))
{
this.heartRateCharacteristic = item;
base.SubscribeCharacteristic(item, HrmCharacteristicSubscribed, HrmCharacteristicRead);
}
if (item.MatchGuid(ServiceUuids.Characteristics.BodySensorLocation))
{
}
}
}
private void HrmCharacteristicSubscribed(BleWinHwInterface winHwInterface, BleCharacteristicInfo characteristic, BleResponse response)
{
}
private void HrmCharacteristicRead(BleWinHwInterface winHwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
{
HeartRateMeasurementValue heartRateMeasurementValue;
if(base.CheckCharacteristicResponse<HeartRateMeasurementValue>(characteristic, response, (BleCharacteristicInfo info, BleResponse<byte[]> bleResponse) => new HeartRateMeasurementValue(bleResponse.Data), out heartRateMeasurementValue) != CommandResponseCode.Success)
{
return;
}
//Debug.Log("心率:"+heartRateMeasurementValue.BeatsPerMinute);
}
protected override BleCharacteristicInfo GetCharacteristicForCommandType(CommandType type)
{
return null;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d36bb0439a6a6c142af91aa05a67a7e0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,11 @@
using Assets.Scripts.Ble;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Devices.Ble
{
public delegate void PeripheralDisconnectedCallback(BleWinHwInterface hwInterface, BlePeripheralInfo peripheral, BleResponse response);
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 267fe052d333eec4db01b694b8d68180
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 42dcd8e06e630564bb971b809b953305
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,40 @@
using Assets.Scripts.Devices.Ant;
using Assets.Scripts.Devices.Ble;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.Scan
{
/// <summary>
/// 广播数据
/// </summary>
public class BleAdvertisementInfo
{
public BlePeripheralInfo Peripheral { get; }
public int Rssi { get; }
public SensorType SensorType { get; }
public BleAdvertisementInfo(BlePeripheralInfo peripheral, int rssi, bool connectible, List<Guid> services, byte[] manufactureData, SensorType sensor)
{
this.Peripheral = peripheral;
this.Rssi = rssi;
//this.Connectible = connectible;
this.services = services;
//this.ManufactureData = manufactureData;
this.SensorType = sensor;
}
private readonly List<Guid> services;
public IReadOnlyList<Guid> Services
{
get
{
return this.services;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4809c38d934e9a247a4e70bbcf6fd67b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ffc07810002114f4e845efdbc1f8f47e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Assets.Scripts.Ble.Characteristic;
using Assets.Scripts.Ble.Commands;
using Assets.Scripts.Commands;
using Assets.Scripts.Devices.Ble;
using Assets.Scripts.Devices.Ble.Extension;
using UnityEngine;
namespace Assets.Scripts.Ble.Service
{
public abstract class BleService
{
private BleWinHwInterface hwInterface;
private BleServiceInfo serviceInfo;
private List<BleCharacteristicInfo> characteristics;
private readonly Dictionary<Guid, Action<BleWinHwInterface, BleCharacteristicInfo, BleResponse<byte[]>>> registeredCharacteristicReadEvents = new Dictionary<Guid, Action<BleWinHwInterface, BleCharacteristicInfo, BleResponse<byte[]>>>();
public IReadOnlyList<BleCharacteristicInfo> Characteristics
{
get
{
return this.characteristics;
}
}
private CommandType supportedCommands;
// Token: 0x0400110D RID: 4365
private CommandType tempCommands;
public CommandType SupportedCommands
{
get
{
return this.supportedCommands;
}
private set
{
if (this.supportedCommands.HasFlag(value))
{
return;
}
this.supportedCommands |= value;
}
}
public BleService(BleServiceInfo serviceInfo, BleWinHwInterface bleHwInterface)
{
this.hwInterface = bleHwInterface;
this.serviceInfo = serviceInfo;
this.hwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
}
private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
{
//Debug.Log("read main callback");
if (this.registeredCharacteristicReadEvents.ContainsKey(characteristic.Id) && characteristic.Service.Equals(this.serviceInfo))
{
//Debug.Log("read main callback 1111111111111");
this.registeredCharacteristicReadEvents[characteristic.Id](hwInterface, characteristic, response);
}
}
public void DiscoverCharacteristics(BleResponse<List<BleCharacteristicInfo>> scanCharacteristicsResponse = null)
{
if (scanCharacteristicsResponse == null)
{
Debug.Log("ccc ======================================== "+this.serviceInfo.Peripheral.Name);
this.hwInterface.DiscoverCharacteristic(this.serviceInfo, this.CheckCharacteristicDiscoveredResponse);
return;
}
this.CheckCharacteristicDiscoveredResponse(this.hwInterface, this.serviceInfo, scanCharacteristicsResponse);
}
private void CheckCharacteristicDiscoveredResponse(BleWinHwInterface hwInterface, BleServiceInfo service, BleResponse<List<BleCharacteristicInfo>> response)
{
if (!service.Equals(this.serviceInfo))
{
return;
}
if (!response.IsSuccess)
{
return;
}
//if(response.Data)
this.characteristics = response.Data;
this.CharacteristicsDiscovered(response);
}
protected abstract void CharacteristicsDiscovered(BleResponse<List<BleCharacteristicInfo>> response);
protected void SubscribeCharacteristic(BleCharacteristicInfo characteristic, Action<BleWinHwInterface, BleCharacteristicInfo, BleResponse> notificationCallback,
Action<BleWinHwInterface, BleCharacteristicInfo, BleResponse<byte[]>> readCallback)
{
this.hwInterface.SubscribeCharacteristic(characteristic, (hw, info, response) =>
{
if (readCallback != null)
{
this.registeredCharacteristicReadEvents[characteristic.Id] = readCallback;
Debug.Log("添加callback");
}
if (notificationCallback == null)
{
return;
}
notificationCallback.Invoke(hw, info, response);
});
}
protected Commands.CommandResponseCode CheckCharacteristicResponse<TResponseValue>(BleCharacteristicInfo characteristic, BleResponse<byte[]> response,
Func<BleCharacteristicInfo, BleResponse<byte[]>, TResponseValue> valueCreator, out TResponseValue value) where TResponseValue : BaseCharacteristicValue
{
value = default(TResponseValue);
if (!response.IsSuccess)
{
return response.Error.ToDeviceCommandResponseType();
}
try
{
value = valueCreator(characteristic, response);
}
catch (Exception ex)
{
throw;
}
CommandResponseCode commandResponseCode = value.ToDeviceCommandResponseCode();
return commandResponseCode;
}
protected void AddSupportedCommand(CommandType newCommands)
{
this.SupportedCommands |= newCommands;
if (newCommands.HasFlag(CommandType.SetSimParameters))
{
}
}
protected void ReadCharacteristic(BleCharacteristicInfo characteristic, CharacteristicReadCallback callback)
{
this.hwInterface.ReadCharacteristic(characteristic, callback);
}
protected BleCharacteristicInfo CheckServiceCanSendCommand(Command command)
{
CommandType type = command.Type;
//if (!this.SupportedCommands(type))
//{
//}
BleCharacteristicInfo characteristicForCommandType = this.GetCharacteristicForCommandType(type);
return characteristicForCommandType;
}
protected abstract BleCharacteristicInfo GetCharacteristicForCommandType(CommandType type);
public bool SupportsCommands(CommandType flags)
{
return this.SupportedCommands.HasFlag(flags);
}
public virtual bool SendCommand(Command command)
{
return false;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 927b28f8d3c950b4793567e37f28d27c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bee6ebee782762641bf45036d063e6d5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble
{
/// <summary>
/// rouvy里的 WinBlePeripheralInfo类
/// </summary>
public class BleDeviceProxy
{
public string Address { get; set; }
public string Name { get; set; }
public int Rssi { get; set; }
public List<Guid> Services { get; set; }
public BleDeviceProxy()
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 33bb64404b5022f4d888be258a6b970a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,409 @@
using Assets.Scripts.Ble.Scan;
using Assets.Scripts.Ble.Win;
using Assets.Scripts.Devices.Ant;
using Assets.Scripts.Devices.Ble;
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)
{
//Debug.Log($"address:{ address }, name:{ name }, service:{ (service == null ? "" : service.Value.ToString()) }");
if (!string.IsNullOrWhiteSpace(name))
{
if (pCache.ContainsKey(address.ToString()))
{
((pCache[address.ToString()].Peripheral) as WinBlePeripheralInfo).SetName(name);
}
}
//Debug.Log("service:" + service.ToString()+",name:" + name);
if (service.HasValue && ServiceUuids.Services.Select(s => s.IdGuid).Any(x => x.Equals(service.Value)))
{
SensorType sensor = SensorType.None;
List<Guid> services = null;
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;
}
}
};
if (!pCache.ContainsKey(address.ToString())) {
var device = new BleAdvertisementInfo(new WinBlePeripheralInfo(address.ToString(), name), rssi, true, services, null, sensor);
pCache.Add(address.ToString(), device);
WclBleGattThread gattClient = this.SetUpGattClient(device.Peripheral);
//this.ConnectInternal(gattClient);
}
_discoveredCallback?.Invoke(pCache[address.ToString()]);
}
}
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)
{
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() }");
this.callbacks[gattClient.Peripheral].Invoke(this, gattClient.Peripheral, response);
}
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;
}
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 Dispose()
{
this.wclBleMainThread.Dispose();
this.wclBleMainThread = null;
hwInterface = null;
}
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;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8749d096f14d0ea44ad8ab90a45d70f1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a5379f968d8a33a4fa0f222d169164d4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.Win.CPPBridge
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct GattCharacteristic
{
// Token: 0x04001350 RID: 4944
[MarshalAs(UnmanagedType.U2)]
public ushort ServiceHandle;
// Token: 0x04001351 RID: 4945
public GattUuid Uuid;
// Token: 0x04001352 RID: 4946
[MarshalAs(UnmanagedType.U2)]
public ushort Handle;
// Token: 0x04001353 RID: 4947
[MarshalAs(UnmanagedType.U2)]
public ushort ValueHandle;
// Token: 0x04001354 RID: 4948
[MarshalAs(UnmanagedType.Bool)]
public bool IsBroadcastable;
// Token: 0x04001355 RID: 4949
[MarshalAs(UnmanagedType.Bool)]
public bool IsReadable;
// Token: 0x04001356 RID: 4950
[MarshalAs(UnmanagedType.Bool)]
public bool IsWritable;
// Token: 0x04001357 RID: 4951
[MarshalAs(UnmanagedType.Bool)]
public bool IsWritableWithoutResponse;
// Token: 0x04001358 RID: 4952
[MarshalAs(UnmanagedType.Bool)]
public bool IsSignedWritable;
// Token: 0x04001359 RID: 4953
[MarshalAs(UnmanagedType.Bool)]
public bool IsNotifiable;
// Token: 0x0400135A RID: 4954
[MarshalAs(UnmanagedType.Bool)]
public bool IsIndicatable;
// Token: 0x0400135B RID: 4955
[MarshalAs(UnmanagedType.Bool)]
public bool HasExtendedProperties;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7e3cd838ef790974db97b48787131436
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.Win.CPPBridge
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct GattCharacteristics
{
// Token: 0x0400135C RID: 4956
[MarshalAs(UnmanagedType.U1)]
public byte Count;
// Token: 0x0400135D RID: 4957
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
public GattCharacteristic[] Chars;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 34261dc02869ee243a7168adabe60fc9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.Win.CPPBridge
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct GattService
{
// Token: 0x0400135E RID: 4958
public GattUuid Uuid;
// Token: 0x0400135F RID: 4959
[MarshalAs(UnmanagedType.U2)]
public ushort Handle;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2daabe73d2950c243a1a6a872bd74445
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.Win.CPPBridge
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct GattServices
{
// Token: 0x04001360 RID: 4960
[MarshalAs(UnmanagedType.U1)]
public byte Count;
// Token: 0x04001361 RID: 4961
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
public GattService[] Services;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fb895de0d5e252c4e9cf793690ddf39c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.Win.CPPBridge
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct GattUuid
{
// Token: 0x06002139 RID: 8505 RVA: 0x000896C8 File Offset: 0x000878C8
public override string ToString()
{
if (!this.IsShortUuid)
{
return string.Format("{0:D}", this.LongUuid);
}
return string.Format("0x{0:X}", this.ShortUuid);
}
// Token: 0x04001362 RID: 4962
[MarshalAs(UnmanagedType.Bool)]
public bool IsShortUuid;
// Token: 0x04001363 RID: 4963
[MarshalAs(UnmanagedType.U2)]
public ushort ShortUuid;
// Token: 0x04001364 RID: 4964
public Guid LongUuid;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 980c29814813f4c419759b2b0f6158eb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.Win.CPPBridge
{
internal static class GattUuidExtension
{
// Token: 0x0600213A RID: 8506 RVA: 0x000896FD File Offset: 0x000878FD
public static Guid WclShortGuidToGuid(this ushort shortUuid)
{
return new Guid("0000XXXX-0000-1000-8000-00805F9B34FB".Replace("XXXX", shortUuid.ToString("X4")));
}
// Token: 0x0600213B RID: 8507 RVA: 0x0008971F File Offset: 0x0008791F
public static Guid WclGuidToNormalizedGuid(this GattUuid uuid)
{
if (uuid.IsShortUuid)
{
return new Guid("0000XXXX-0000-1000-8000-00805F9B34FB".Replace("XXXX", uuid.ShortUuid.ToString("X4")));
}
return uuid.LongUuid;
}
// Token: 0x04001365 RID: 4965
public const string GuidTemplate = "0000XXXX-0000-1000-8000-00805F9B34FB";
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9a96dd52c07e9f749806d13f85953f1c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
using System;
using System.Runtime.InteropServices;
namespace Assets.Scripts.Ble.CPPBridge
{
[UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = false)]
internal delegate void WCL_NOTIFY_EVENT([MarshalAs(UnmanagedType.SysInt)][In] IntPtr sender);
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 857859a8d81c3474d98b6f9a08158d1c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.CPPBridge
{
internal enum WclBleAdvertisementType
{
// Token: 0x0400136D RID: 4973
ConnectableUndirected,
// Token: 0x0400136E RID: 4974
ConnectableDirected,
// Token: 0x0400136F RID: 4975
ScannableUndirected,
// Token: 0x04001370 RID: 4976
NonConnectableUndirected,
// Token: 0x04001371 RID: 4977
ScanResponse,
// Token: 0x04001372 RID: 4978
Unknown
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: da17e15eaae28fb4aaa037e484e6563b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assets.Scripts.Ble.Win.CPPBridge
{
internal enum WclBleGattClientState
{
// Token: 0x04001374 RID: 4980
Disconnected,
// Token: 0x04001375 RID: 4981
Preparing,
// Token: 0x04001376 RID: 4982
Connecting,
// Token: 0x04001377 RID: 4983
Connected,
// Token: 0x04001378 RID: 4984
Disconnecting
}
}

Some files were not shown because too many files have changed in this diff Show More