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 Services; private TacxFecNotify tacxFecNotify; private BleCharacteristicInfo tacxFecWriteCharacteristic; private TacxFecWrite tacxFecWrite; private List otherGuids = new List() { 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"), }; /// /// 当前坡度,当切换到其他模式的时候,需要把坡度设置为0 /// 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 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 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 data = new List { 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()); } /// /// 阻力模式 /// /// 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 data = new List { 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()); } /// /// 风阻 /// /// 海拔高度,单位米 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 data = new List { 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()); } /// /// 轨道阻力 /// /// 坡度百分比的值,单位是% 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 data = new List { 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 data = new List { 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()); } } }