接入基本设备

This commit is contained in:
suntao committed 2021-06-04 13:22:59 +08:00
1 parent 2f84f70a5f
commit 7729332f41
62 files changed
+2880 -86

No files matched your search

@@ -1,5 +1,6 @@
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;
@@ -12,12 +13,16 @@ namespace Assets.Scripts.Devices.Ble.Devices
public class CyclingPower : BleDevice, IPowerDevice
{
private List<BleServiceInfo> Services;
private CyclingPowerMeasurement cyclingPowerMeasurement;
public CyclingPower(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Power)
{
cyclingPowerMeasurement = new CyclingPowerMeasurement(1920);
base.Characteristics.Add(cyclingPowerMeasurement);
bleWinHwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
}
public int Power { get => 999; set => throw new NotImplementedException(); }
public int Power { get => cyclingPowerMeasurement.Power; set => throw new NotImplementedException(); }
protected override void CreateServices(List<BleServiceInfo> discoveredServices)
{
@@ -35,7 +40,7 @@ namespace Assets.Scripts.Devices.Ble.Devices
this.hwInterface.SubscribeCharacteristic(character, (hw, cha, res) =>
{
Debug.Log("1111111111111111111111");
//Debug.Log("1111111111111111111111");
});
}
}
@@ -46,7 +51,22 @@ namespace Assets.Scripts.Devices.Ble.Devices
private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
{
Debug.Log("main call" + string.Join(",", response.Data));
//Debug.Log("power main call" + string.Join(",", response.Data));
//Debug.Log(characteristic.MatchGuid(cyclingPowerMeasurement.Uuid));
//Debug.Log(characteristic.Service.MatchGuid(cyclingPowerMeasurement.ServiceUuid));
//if (characteristic.MatchGuid(cyclingPowerMeasurement.Uuid))
//{
// cyclingPowerMeasurement.HandleAttributeReceived(response.Data);
//}
foreach (var item in base.Characteristics)
{
if (characteristic.MatchGuid(item.Uuid))
{
item.HandleAttributeReceived(response.Data);
}
}
}
}
}
+104 -3
View File
@@ -1,5 +1,6 @@
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;
@@ -8,19 +9,119 @@ using System.Threading.Tasks;
namespace Assets.Scripts.Devices.Ble.Devices
{
public class Ftms : BleDevice, IPowerDevice
public class Ftms : BleDevice, ISpeedDevice, IPowerDevice, ICadenceDevice, ITrainerDevice
{
public int Power { get => _ftmsIndoorBikeData.InstantPower.GetValueOrDefault(0); set => throw new NotImplementedException(); }
public double Speed { get => _ftmsIndoorBikeData.InstantSpeed.GetValueOrDefault(0); set => throw new NotImplementedException(); }
public int Cadence { get => _ftmsIndoorBikeData.InstantCadence.GetValueOrDefault(0); set => throw new NotImplementedException(); }
private FtmsIndoorBikeData _ftmsIndoorBikeData;
private List<BleServiceInfo> Services;
private BleCharacteristicInfo controlPointCharacteristic;
public Ftms(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) :base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Trainer)
{
this._ftmsIndoorBikeData = new FtmsIndoorBikeData();
base.Characteristics.Add(this._ftmsIndoorBikeData);
base.Characteristics.Add(new FtmsFitnessMachineFeature());
bleWinHwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
}
public int Power { get => throw new NotImplementedException(); 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.IndoorBikeData))
{
//Debug.Log("功率功能");
this.hwInterface.SubscribeCharacteristic(character, (hw, cha, res) =>
{
//Debug.Log("1111111111111111111111");
});
}
else if (character.MatchGuid(ServiceUuids.Characteristics.FitnessMachineControlPoint))
{
this.controlPointCharacteristic = character;
}
}
});
}
}
private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
{
foreach (var item in base.Characteristics)
{
if (characteristic.MatchGuid(item.Uuid))
{
//Debug.Log(string.Join(",", response.Data));
item.HandleAttributeReceived(response.Data);
}
}
}
public void SetErgMode(int targetPower)
{
//throw new NotImplementedException();
byte[] bytes = BitConverter.GetBytes(targetPower);
this.hwInterface.WriteCharacteristic(this.controlPointCharacteristic, new byte[3] {
(byte)5,
bytes[0],
bytes[1]
});
}
public void SetResistanceMode(double value)
{
//throw new NotImplementedException();
var data = new byte[]
{
(byte)4,
(byte)0.1
};
}
public void SetWindResistance(double? height = null)
{
throw new NotImplementedException();
}
/// <summary>
/// 轨道阻力
/// </summary>
/// <param name="grade"></param>
public void SetTrackResistance(double grade)
{
if (this.State != Ant.DeviceState.Connected)
return;
if (controlPointCharacteristic == null)
return;
short windSpeed = 0;
short value2 = (short)(grade);
byte rollingResistanceCoefficient = (byte)(0.004 * 10000);
byte windResistanceCoefficient = 0;
var data = new List<byte>();// { 17, (byte)windSpeed, (byte)value2, rollingResistanceCoefficient, windResistanceCoefficient };
data.Add(17);
data.AddRange(BitConverter.GetBytes(windSpeed));
data.AddRange(BitConverter.GetBytes(value2));
data.AddRange(BitConverter.GetBytes(rollingResistanceCoefficient));
data.AddRange(BitConverter.GetBytes(windResistanceCoefficient));
this.hwInterface.WriteCharacteristic(this.controlPointCharacteristic, data.ToArray());
}
}
}
@@ -18,14 +18,13 @@ namespace Assets.Scripts.Devices.Ble.Devices
private HeartRateMeasurement heartRateMeasurement;
public HeartRate(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.HeartRate)
{
Debug.Log("创建心率设备");
heartRateMeasurement = new HeartRateMeasurement();
base.Characteristics.Add(heartRateMeasurement);
bleWinHwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
}
protected override void CreateServices(List<BleServiceInfo> discoveredServices)
{
//throw new NotImplementedException();
@@ -33,18 +32,33 @@ namespace Assets.Scripts.Devices.Ble.Devices
foreach (var service in this.Services)
{
//Debug.Log($"11111 "+ service.Id.ToString());
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");
//Debug.Log($"心率计subscribe char:{ }");
});
continue;
}
}
foreach (var item in Characteristics.Where(c=>c.IsOptional))
{
//Debug.Log(item.GetType() + "服务可用"+ item.Uuid.ToString() +", service:" + item.ServiceUuid);
var ccc = response.Data.FirstOrDefault(r => r.MatchGuid(item.Uuid));
if (ccc == null)
{
item.SetUnavailable();
}
else
{
Debug.Log(item.GetType() + "服务可用");
GetBatteryLevel(ccc);
}
}
});
@@ -52,10 +66,26 @@ namespace Assets.Scripts.Devices.Ble.Devices
}
public void GetBatteryLevel(BleCharacteristicInfo bbbb)
{
this.hwInterface.ReadCharacteristic(bbbb, (hwInterface1, characteristic1, response1) => {
Debug.Log("read收到消息:" + string.Join(",", response1));
});
}
private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
{
Debug.Log("main call" + string.Join(",", response.Data));
heartRateMeasurement.HandleAttributeReceived(response.Data);
//Debug.Log("heart rate main call" + string.Join(",", response.Data));
foreach (var item in base.Characteristics)
{
if (characteristic.MatchGuid(item.Uuid))
{
item.HandleAttributeReceived(response.Data);
}
}
//heartRateMeasurement.HandleAttributeReceived(response.Data);
}
}
@@ -0,0 +1,103 @@
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 SpeedCadence : BleDevice, ISpeedDevice, ICadenceDevice
{
private CyclingSpeedCadenceMeasurement _cyclingSpeedCadenceMeasurement;
public int Cadence { get => _cyclingSpeedCadenceMeasurement.Cadence; set => throw new NotImplementedException(); }
public double Speed { get => _cyclingSpeedCadenceMeasurement.Speed; set => throw new NotImplementedException(); }
private double _wheelCircumference;
private List<BleServiceInfo> Services;
public SpeedCadence(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.SpeedCadence)
{
Debug.Log("创建速度踏频设备");
_cyclingSpeedCadenceMeasurement = new CyclingSpeedCadenceMeasurement(this._wheelCircumference);
base.Characteristics.Add(_cyclingSpeedCadenceMeasurement);
bleWinHwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
}
public void SetWheelCircumference(double value)
{
}
protected override void CreateServices(List<BleServiceInfo> discoveredServices)
{
this.Services = discoveredServices;
foreach (var service in this.Services)
{
//Debug.Log($"11111 "+ service.Id.ToString());
hwInterface.DiscoverCharacteristic(service, (hwInterface, service1, response) =>
{
Debug.Log($"设备{ this.Name }的char: { string.Join("\r\n", response.Data.Select(d=>d.Id)) }");
foreach (var character in response.Data)
{
if (character.MatchGuid(_cyclingSpeedCadenceMeasurement.Uuid))
{
this.hwInterface.SubscribeCharacteristic(character, (hw, cha, res) =>
{
//Debug.Log("1111111111111111111111");
});
continue;
}
}
foreach (var item in Characteristics.Where(c => c.IsOptional))
{
//Debug.Log(item.GetType() + "服务可用"+ item.Uuid.ToString() +", service:" + item.ServiceUuid);
var ccc = response.Data.FirstOrDefault(r => r.MatchGuid(item.Uuid));
if (ccc == null)
{
item.SetUnavailable();
}
else
{
Debug.Log(item.GetType() + "服务可用");
GetBatteryLevel(ccc);
}
}
});
}
}
public void GetBatteryLevel(BleCharacteristicInfo bbbb)
{
this.hwInterface.ReadCharacteristic(bbbb, (hwInterface1, characteristic1, response1) => {
Debug.Log("read收到消息:" + string.Join(",", response1));
});
}
private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
{
//Debug.Log("power main call" + string.Join(",", response.Data));
//Debug.Log(characteristic.MatchGuid(cyclingPowerMeasurement.Uuid));
//Debug.Log(characteristic.Service.MatchGuid(cyclingPowerMeasurement.ServiceUuid));
//if (characteristic.MatchGuid(cyclingPowerMeasurement.Uuid))
//{
// cyclingPowerMeasurement.HandleAttributeReceived(response.Data);
//}
foreach (var item in base.Characteristics)
{
if (characteristic.MatchGuid(item.Uuid))
{
item.HandleAttributeReceived(response.Data);
}
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3fc83bb07e841d04bb491332cdfeb669
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+262
View File
@@ -0,0 +1,262 @@
using Assets.Scripts.Ble;
using Assets.Scripts.Devices.Ant;
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 Tacx : BleDevice, IPowerDevice, ICadenceDevice, ISpeedDevice, ITrainerDevice
{
public int Power { get => tacxFecNotify.Power; set => throw new NotImplementedException(); }
public int Cadence { get => tacxFecNotify.Cadence; set => throw new NotImplementedException(); }
public double Speed { get => tacxFecNotify.Speed; set => throw new NotImplementedException(); }
private List<BleServiceInfo> Services;
private TacxFecNotify tacxFecNotify;
private BleCharacteristicInfo tacxFecWriteCharacteristic;
private TacxFecWrite tacxFecWrite;
/// <summary>
/// 当前坡度,当切换到其他模式的时候,需要把坡度设置为0
/// </summary>
private double _grade = 0;
public Tacx(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Trainer)
{
tacxFecNotify = new TacxFecNotify();
base.Characteristics.Add(tacxFecNotify);
tacxFecWrite = new TacxFecWrite();
base.Characteristics.Add(tacxFecWrite);
bleWinHwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
//bleWinHwInterface.WriteCharacteristic()
}
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.TacxFecRead))
{
//Debug.Log("功率功能");
this.hwInterface.SubscribeCharacteristic(character, (hw, cha, res) =>
{
//Debug.Log("1111111111111111111111");
});
}
else if (character.MatchGuid(ServiceUuids.Characteristics.TacxFecWrite))
{
this.tacxFecWriteCharacteristic = character;
}
}
});
}
}
private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
{
foreach (var item in base.Characteristics)
{
if (characteristic.MatchGuid(item.Uuid))
{
//Debug.Log(string.Join(",", response.Data));
item.HandleAttributeReceived(response.Data);
}
}
}
public void SetErgMode(int targetPower)
{
Debug.Log("目标功率1");
if (this.State != Ant.DeviceState.Connected)
return;
if (tacxFecWriteCharacteristic == null)
return;
Debug.Log($"目标功率:{ targetPower }");
List<byte> data = new List<byte> { 164, 9, 79, 5, 49,
byte.MaxValue,
byte.MaxValue,
byte.MaxValue,
byte.MaxValue,
byte.MaxValue,
(byte)(targetPower & byte.MaxValue),
(byte)(targetPower >> 8 & byte.MaxValue)
};
byte checksum = (byte)0;
data.ForEach(b => checksum ^= b);
data.Add(checksum);
this.hwInterface.WriteCharacteristic(this.tacxFecWriteCharacteristic, data.ToArray());
}
/// <summary>
/// 阻力模式
/// </summary>
/// <param name="value"></param>
public void SetResistanceMode(double value)
{
if (this.State != Ant.DeviceState.Connected)
return;
if (tacxFecWriteCharacteristic == null)
return;
if(_grade > 0)
{
this.SetTrackResistance(0);
}
double resistance = value / 100 * 200;
List<byte> data = new List<byte> { 164, 9, 79, 5, 48,
byte.MaxValue,
byte.MaxValue,
byte.MaxValue,
byte.MaxValue,
byte.MaxValue,
byte.MaxValue,
(byte)resistance
};
byte checksum = (byte)0;
data.ForEach(b => checksum ^= b);
data.Add(checksum);
this.hwInterface.WriteCharacteristic(this.tacxFecWriteCharacteristic, data.ToArray());
}
/// <summary>
/// 风阻
/// </summary>
/// <param name="height">海拔高度,单位米</param>
public void SetWindResistance(double? height = null)
{
if (this.State != Ant.DeviceState.Connected)
return;
if (tacxFecWriteCharacteristic == null)
return;
if (_grade > 0)
{
this.SetTrackResistance(0);
}
byte windResistance = 0;
if (height.HasValue)
{
//Wind Resistance Coefficient [kg/m] = Frontal Surface Area [m2] x Drag Coefficient x Air Density[kg / m3]
var wr = 0.40 * 1.0 * AirDensity.GetAirDensity(height.Value);
if (wr > 1.86)
{
wr = 1.86;
}
windResistance = (byte)(Convert.ToInt32(Math.Round(wr, 2) / 0.01));
Console.WriteLine($"风阻系数:{ windResistance }");
}
byte id = 79;
byte size = 9;
byte channel = 5;
List<byte> data = new List<byte> { 164, size, id, channel, 50,
byte.MaxValue,
byte.MaxValue,
byte.MaxValue,
byte.MaxValue,
windResistance,
byte.MaxValue,
byte.MaxValue,
};
byte checksum = (byte)0;
data.ForEach(b => checksum ^= b);
data.Add(checksum);
this.hwInterface.WriteCharacteristic(this.tacxFecWriteCharacteristic, data.ToArray());
}
/// <summary>
/// 轨道阻力
/// </summary>
/// <param name="grade">坡度百分比的值,单位是%</param>
public void SetTrackResistance(double grade)
{
if (this.State != Ant.DeviceState.Connected)
return;
if (tacxFecWriteCharacteristic == null)
return;
_grade = grade;
if (_grade > 15)
{
_grade = 15;
}
else if (_grade < -5)
{
_grade = -5;
}
var gradeValue = Convert.ToInt32((grade + 200) * 100);
var gradeBytes = BitConverter.GetBytes(gradeValue);
byte id = 79;
byte size = 9;
byte channel = 5;
List<byte> data = new List<byte> { 164, size, id, channel, 51,
byte.MaxValue,
byte.MaxValue,
byte.MaxValue,
byte.MaxValue,
gradeBytes[0],
gradeBytes[1],
byte.MaxValue,
};
byte checksum = (byte)0;
data.ForEach(b => checksum ^= b);
data.Add(checksum);
this.hwInterface.WriteCharacteristic(this.tacxFecWriteCharacteristic, data.ToArray());
}
private void UpdateUserConfiguration(double weight)
{
var _weight = (int)(weight * 100);
if (this.State != Ant.DeviceState.Connected)
return;
if (tacxFecWriteCharacteristic == null)
return;
byte id = 79;
byte size = 4;
byte channel = 5;
List<byte> data = new List<byte> { 164, size, id, channel, 55,
(byte) (_weight & (int) byte.MaxValue),
(byte) (_weight >> 8 & (int) byte.MaxValue),
byte.MaxValue,
(byte) 143,
(byte) 12,
(byte) 70,
(byte) 0
};
byte checksum = (byte)0;
data.ForEach(b => checksum ^= b);
data.Add(checksum);
this.hwInterface.WriteCharacteristic(this.tacxFecWriteCharacteristic, data.ToArray());
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d133d5406fc475841a781b88d91dc139
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: