274 lines
9.5 KiB
C#
274 lines
9.5 KiB
C#
using Assets.Scripts.Ble;
|
||
using Assets.Scripts.Devices.Ant;
|
||
using Assets.Scripts.Devices.Ant.Interfaces;
|
||
using Assets.Scripts.Devices.Ble.Characteristic;
|
||
using Assets.Scripts.Devices.Ble.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 Tacx : BleDevice, IPowerDevice, ICadenceDevice, ISpeedDevice, ITrainerDevice, IRequiresRiderWeight
|
||
{
|
||
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(); }
|
||
public double RiderWeight { get; set; }
|
||
|
||
private List<BleServiceInfo> Services;
|
||
|
||
private TacxFecNotify tacxFecNotify;
|
||
private BleCharacteristicInfo tacxFecWriteCharacteristic;
|
||
|
||
private TacxFecWrite tacxFecWrite;
|
||
private List<Guid> otherGuids = new List<Guid>()
|
||
{
|
||
new Guid("0000fff0-0000-1000-8000-00805f9b34fb"),
|
||
new Guid("0000180a-0000-1000-8000-00805f9b34fb"),
|
||
new Guid("00001826-0000-1000-8000-00805f9b34fb"),
|
||
new Guid("c1fe406e-a3b5-93f3-e0a9-e50e24dcca9e"),
|
||
};
|
||
/// <summary>
|
||
/// 当前坡度,当切换到其他模式的时候,需要把坡度设置为0
|
||
/// </summary>
|
||
private double _grade = 0;
|
||
|
||
public Tacx(BlePeripheralInfo peripheralInfo, IBleWinHwInterface 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) =>
|
||
{
|
||
if(!base.CheckPendingServiceCharacteristicsResponse(service1, response))
|
||
{
|
||
return;
|
||
}
|
||
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(IBleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
|
||
{
|
||
foreach (var item in base.Characteristics)
|
||
{
|
||
if (characteristic.MatchGuid(item.Uuid) || otherGuids.Contains(characteristic.Id))
|
||
{
|
||
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());
|
||
}
|
||
}
|
||
}
|