2021-03-30 14:23:41 +08:00
|
|
|
|
using Assets.Scripts.Devices.Ant.Interfaces;
|
|
|
|
|
|
using Assets.Scripts.Devices.Ant.Messages;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Assets.Scripts.Devices.Ant
|
|
|
|
|
|
{
|
2021-06-04 10:35:58 +08:00
|
|
|
|
public class FitDevice : AbstractAntDevice, ISpeedDevice, IPowerDevice, ICadenceDevice, IRequiresRiderWeight, ITrainerDevice
|
2021-03-30 14:23:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
public const int MAX_NO_EVENT_STOP_COUNT = 12;
|
|
|
|
|
|
|
|
|
|
|
|
//byte lastElapsedTimeAcc;
|
|
|
|
|
|
//byte lastDistAcc;
|
|
|
|
|
|
//double calcSpeed = 0; //Averaged Speed over several msgs in case instSpeed is not available
|
|
|
|
|
|
|
|
|
|
|
|
int lastInstCadence = -1;
|
|
|
|
|
|
ushort lastInstPower = 0xFFFF;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 当前坡度,当切换到其他模式的时候,需要把坡度设置为0
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private double _grade = 0;
|
|
|
|
|
|
private bool IsCalibrating { get; set; }
|
2021-06-04 18:28:11 +08:00
|
|
|
|
public FitDevice(string id)
|
|
|
|
|
|
: base(id, "Ant+ Trainer", racerSportType.Unknown, SensorType.Trainer)
|
2021-03-30 14:23:41 +08:00
|
|
|
|
{
|
2021-04-01 09:33:19 +08:00
|
|
|
|
Priority = 0;
|
2021-03-30 14:23:41 +08:00
|
|
|
|
this.StateChange = (state) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (state == DeviceState.Connected)
|
|
|
|
|
|
{
|
|
|
|
|
|
Calibrate();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 发送校准命令
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void Calibrate()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (this.IsCalibrating)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
this.IsCalibrating = true;
|
|
|
|
|
|
|
|
|
|
|
|
base.SendMessage(new FecCalibrate(GetChannelId()));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected override AntChannelProfile getDefaultSearchProfile()
|
|
|
|
|
|
{
|
|
|
|
|
|
return new AntChannelProfile()
|
|
|
|
|
|
{
|
|
|
|
|
|
rfOffset = 57,
|
|
|
|
|
|
transType = 0,
|
|
|
|
|
|
deviceType = 17,
|
|
|
|
|
|
deviceNumber = 0,
|
|
|
|
|
|
messagePeriod = 8192,
|
|
|
|
|
|
pairingEnabled = false,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
//private byte _previousEventCount;
|
|
|
|
|
|
|
|
|
|
|
|
// Token: 0x0400054F RID: 1359
|
|
|
|
|
|
//private ushort _previousPeriod;
|
|
|
|
|
|
|
|
|
|
|
|
// Token: 0x04000550 RID: 1360
|
|
|
|
|
|
//private ushort _previousAccumulatedTorque;
|
|
|
|
|
|
|
|
|
|
|
|
private DateTime _lastEventChange = DateTime.UtcNow;
|
|
|
|
|
|
|
|
|
|
|
|
public double Speed { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
private int _Power;
|
|
|
|
|
|
public int Power
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
return _Power;
|
|
|
|
|
|
}
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_Power = DeviceValueFilter.Power(value);
|
2021-04-01 09:33:19 +08:00
|
|
|
|
//Debug.Log(_Power);
|
2021-03-30 14:23:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _Cadence;
|
|
|
|
|
|
public int Cadence
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
return _Cadence;
|
|
|
|
|
|
}
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_Cadence = DeviceValueFilter.Cadence(value);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private double _riderWeight = 75.0;
|
|
|
|
|
|
|
|
|
|
|
|
public double RiderWeight
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _riderWeight;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (value <= 0) return;
|
|
|
|
|
|
this._riderWeight = value;
|
|
|
|
|
|
this.UpdateUserConfiguration();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public DateTime LastCalibration { get; protected set; }
|
|
|
|
|
|
public int? Offset { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public override void handleChannelResponse(ANT_Managed_Library.ANT_Response response)
|
|
|
|
|
|
{
|
|
|
|
|
|
//Console.WriteLine(string.Join(",", response.messageContents));
|
|
|
|
|
|
//Log.LogInfo(string.Join(",", response.messageContents));
|
|
|
|
|
|
if (response.responseID == (byte)ANT_Managed_Library.ANT_ReferenceLibrary.ANTMessageID.BROADCAST_DATA_0x4E)
|
|
|
|
|
|
{
|
|
|
|
|
|
var pageNumber = response.messageContents[1];
|
|
|
|
|
|
switch (pageNumber)
|
|
|
|
|
|
{
|
|
|
|
|
|
case 16: //Page 16 - General Page
|
|
|
|
|
|
{
|
|
|
|
|
|
HandleGeneralDataPage(response.messageContents.Skip(1).ToArray());
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
//case 17: //general settings Page, not on bike, shows on rower, but not very useful
|
|
|
|
|
|
// {
|
|
|
|
|
|
// System.Console.Out.WriteLine("Cycle Length:" + response.messageContents[4] + ",Incline:" + (response.messageContents[5] + (response.messageContents[5] << 8)) + ",Resist:" + response.messageContents[7]);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// break;
|
|
|
|
|
|
//case 18: //metabolic data, doesn't show on rower or bike
|
|
|
|
|
|
// {
|
|
|
|
|
|
// System.Console.Out.WriteLine("BurnRate:" + (response.messageContents[5] + (response.messageContents[6] << 8)) + ",Cal:" + response.messageContents[7]);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// break;
|
|
|
|
|
|
case 19: //treadmill data
|
|
|
|
|
|
{
|
|
|
|
|
|
lastInstCadence = response.messageContents[5];
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 21: //bike data
|
|
|
|
|
|
case 22: //Row data, same format as bike for cad and power
|
|
|
|
|
|
case 20: //Elliptical, same format as bike for cad and power
|
|
|
|
|
|
case 24: //Nordic Skier, same format as bike for cad and power
|
|
|
|
|
|
{
|
|
|
|
|
|
lastInstCadence = response.messageContents[5];
|
|
|
|
|
|
lastInstPower = (ushort)(response.messageContents[6] + (response.messageContents[7] << 8));
|
|
|
|
|
|
//System.Console.Out.WriteLine("Cadence:" + response.messageContents[5] + ",Power:" + (response.messageContents[6] + (response.messageContents[7] << 8)));
|
|
|
|
|
|
//System.Console.Out.WriteLine("SPM:"+response.messageContents[5]+"Power:"+(response.messageContents[6] + (response.messageContents[7] << 8)));
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 25:
|
|
|
|
|
|
|
|
|
|
|
|
HandleTrainerDataPage(response.messageContents.Skip(1).ToArray());
|
|
|
|
|
|
break;
|
|
|
|
|
|
//case 80:
|
|
|
|
|
|
// new ManufacturerDataPageHandler().Handle(response.messageContents.Skip(1).ToArray(), this);
|
|
|
|
|
|
// break;
|
|
|
|
|
|
case 122:
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
foreach (var handler in pageHandlers)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (handler.CanHandle(pageNumber))
|
|
|
|
|
|
{
|
|
|
|
|
|
handler.Handle(response.messageContents.Skip(1).ToArray(), this);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void HandleGeneralDataPage(byte[] dataPayload)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
byte equipmentType = dataPayload[1];
|
|
|
|
|
|
byte elapsedTime = dataPayload[2];
|
|
|
|
|
|
byte distanceTraveled = dataPayload[3];
|
|
|
|
|
|
|
|
|
|
|
|
//byte heartRate = dataPayload[6];
|
|
|
|
|
|
//FecPageHandler.HeartRateDataSource heartRateDataSource = (FecPageHandler.HeartRateDataSource)(dataPayload[7] & 3);
|
|
|
|
|
|
//bool traveledEnabled = (dataPayload[7] & 4) == 1;
|
|
|
|
|
|
//bool distanceTraveledEnabled = (dataPayload[7] & 8) == 1;
|
|
|
|
|
|
//FecPageHandler.FeState feState = (FecPageHandler.FeState)(dataPayload[7] & 128);
|
|
|
|
|
|
//bool lapToggle = (dataPayload[7] & 128) == 1;
|
|
|
|
|
|
//this._fecGeneralData = new FecGeneralData(equipmentType, elapsedTime, distanceTraveled, (short)num, feState, lapToggle, heartRate, heartRateDataSource, traveledEnabled, distanceTraveledEnabled);
|
|
|
|
|
|
bool traveledEnabled = ((int)dataPayload[7] & 4) == 1;
|
|
|
|
|
|
bool distanceTraveledEnabled = ((int)dataPayload[7] & 8) == 1;
|
|
|
|
|
|
|
|
|
|
|
|
int num1 = (int)dataPayload[4] | (int)dataPayload[5] << 8; // Instantaneous speed, m/s
|
|
|
|
|
|
Speed = (double)num1 / 1000.0 * 60.0 * 60.0 / 1000.0; //转换成公里/小时
|
|
|
|
|
|
//Console.WriteLine(num1 +"-----"+Speed);
|
|
|
|
|
|
//fecDevice.UpdateSpeed(new double?(value));
|
|
|
|
|
|
//PubCommData.Speed = num2;
|
|
|
|
|
|
|
|
|
|
|
|
//byte? b2 = (heartRate == 255) ? null : new byte?(heartRate);
|
|
|
|
|
|
//int? xl = b2.HasValue ? new int?((int)b2.GetValueOrDefault()) : 0;
|
|
|
|
|
|
//Console.WriteLine("最新速度" + Speed);
|
|
|
|
|
|
//Console.WriteLine("最新心率" + xl);
|
|
|
|
|
|
|
|
|
|
|
|
//string str = "";
|
|
|
|
|
|
//for (int i = 0; i < response.messageContents.Length; i++)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// str += "," + response.messageContents[i];
|
|
|
|
|
|
//}
|
|
|
|
|
|
//PubCommData.sp = "速度:" + str;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void HandleTrainerDataPage(byte[] dataPayload)
|
|
|
|
|
|
{
|
|
|
|
|
|
//if (response.messageContents.Length < 11) break;
|
|
|
|
|
|
//double value = 0;
|
|
|
|
|
|
//for (int i = 0; i < response.messageContents.Length; i++)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// if (i < 8)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// value += response.messageContents[i];
|
|
|
|
|
|
// }
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
//double value1 = response.messageContents[10] * 256 + response.messageContents[9];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//double power = response.messageContents[7] * 256 + response.messageContents[6];
|
|
|
|
|
|
//Console.WriteLine("power:" + power);
|
|
|
|
|
|
//PubCommData.power = power;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (dataPayload[5] > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
//Console.WriteLine(dataPayload[5] + "," + dataPayload[6]);//瞬时功率
|
|
|
|
|
|
}
|
|
|
|
|
|
byte num1 = dataPayload[1];
|
|
|
|
|
|
byte num2 = dataPayload[2];
|
|
|
|
|
|
int accumulatedPower = (int)dataPayload[3] | (int)dataPayload[4] << 8;
|
|
|
|
|
|
int instantaneousPower = (int)dataPayload[5] | ((int)dataPayload[6] & 15) << 8; //Watts
|
|
|
|
|
|
bool bikePowerCalibrationRequired = ((int)dataPayload[6] >> 4 & 1) == 1;
|
|
|
|
|
|
bool resistanceCalibrationRequired = ((int)dataPayload[6] >> 5 & 1) == 1;
|
|
|
|
|
|
bool userConfigurationRequired = ((int)dataPayload[6] >> 6 & 1) == 1;
|
|
|
|
|
|
bool speedIsTooLow = ((int)dataPayload[7] & 1) == 1;
|
|
|
|
|
|
bool speedIsTooHigh = ((int)dataPayload[7] & 2) == 1;
|
|
|
|
|
|
|
|
|
|
|
|
//PubCommData.power = instantaneousPower;
|
|
|
|
|
|
Power = instantaneousPower;
|
|
|
|
|
|
|
|
|
|
|
|
//bool bikePowerCalibrationRequired = (response.messageContents[6] >> 4 & 1) == 1;
|
|
|
|
|
|
//bool resistanceCalibrationRequired = (response.messageContents[6] >> 5 & 1) == 1;
|
|
|
|
|
|
//bool flag = (response.messageContents[6] >> 6 & 1) == 1;
|
|
|
|
|
|
//bool speedIsTooLow = (response.messageContents[7] & 1) == 1;
|
|
|
|
|
|
//bool speedIsTooHigh = (response.messageContents[7] & 2) == 1;
|
|
|
|
|
|
//FecPageHandler.FeState feState = (FecPageHandler.FeState)(dataPayload[7] & 112);
|
|
|
|
|
|
//bool lapToggle = (dataPayload[7] & 128) == 1;
|
|
|
|
|
|
//this._fecTrainerData = new FecTrainerData((int)eventCount, (int)b, accumulatedPower, num, bikePowerCalibrationRequired, resistanceCalibrationRequired, flag, speedIsTooLow, speedIsTooHigh, feState, lapToggle);
|
|
|
|
|
|
//device.UpdatePower(new int?(num));
|
|
|
|
|
|
byte? nullable = (int)num2 == (int)byte.MaxValue ? new byte?() : new byte?(num2);
|
|
|
|
|
|
int? cadence = nullable.HasValue ? new int?((int)nullable.GetValueOrDefault()) : new int?();
|
|
|
|
|
|
this.Cadence = cadence.GetValueOrDefault();
|
|
|
|
|
|
|
|
|
|
|
|
//Console.WriteLine($"power:{ instantaneousPower },Cadence:{ cadence }, data:{ string.Join(",", dataPayload) }");
|
|
|
|
|
|
|
|
|
|
|
|
if (!userConfigurationRequired)
|
|
|
|
|
|
return;
|
|
|
|
|
|
UpdateUserConfiguration();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void SetErgMode(int targetPower)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (this.State != DeviceState.Connected)
|
|
|
|
|
|
return;
|
|
|
|
|
|
if (_grade > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
SetTrackResistance(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var channelId = GetChannelId();
|
|
|
|
|
|
|
|
|
|
|
|
//byte id = (byte)79;
|
|
|
|
|
|
//byte[] Data = new byte[9]
|
|
|
|
|
|
// {
|
|
|
|
|
|
// channelId,
|
|
|
|
|
|
// (byte) 49,
|
|
|
|
|
|
// byte.MaxValue,
|
|
|
|
|
|
// byte.MaxValue,
|
|
|
|
|
|
// byte.MaxValue,
|
|
|
|
|
|
// byte.MaxValue,
|
|
|
|
|
|
// byte.MaxValue,
|
|
|
|
|
|
// (byte)(targetPower & (int) byte.MaxValue),
|
|
|
|
|
|
// (byte)(targetPower >> 8 & (int) byte.MaxValue)
|
|
|
|
|
|
// };
|
|
|
|
|
|
AntConnector.Instance().SendMessage(new FecErgMode(channelId, targetPower).GetMessage());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void SetResistanceMode(double value)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (this.State != DeviceState.Connected)
|
|
|
|
|
|
return;
|
|
|
|
|
|
if (_grade > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
SetTrackResistance(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
Console.WriteLine($"阻力模式{ value }");
|
|
|
|
|
|
var channelId = GetChannelId();
|
|
|
|
|
|
|
|
|
|
|
|
double resistance = value / 100 * 200;
|
|
|
|
|
|
byte id = (byte)79;
|
|
|
|
|
|
byte[] Data = new byte[9]
|
|
|
|
|
|
{
|
|
|
|
|
|
channelId,
|
|
|
|
|
|
(byte) 48,
|
|
|
|
|
|
byte.MaxValue,
|
|
|
|
|
|
byte.MaxValue,
|
|
|
|
|
|
byte.MaxValue,
|
|
|
|
|
|
byte.MaxValue,
|
|
|
|
|
|
byte.MaxValue,
|
|
|
|
|
|
byte.MaxValue,
|
|
|
|
|
|
(byte)resistance
|
|
|
|
|
|
};
|
|
|
|
|
|
AntConnector.Instance().SendMessage(id, Data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 风阻
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="height">海拔高度,单位米</param>
|
|
|
|
|
|
public void SetWindResistance(double? height = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (this.State != DeviceState.Connected)
|
|
|
|
|
|
return;
|
|
|
|
|
|
if (_grade > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
SetTrackResistance(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
Console.WriteLine($"自由骑{ height }");
|
|
|
|
|
|
var channelId = GetChannelId();
|
|
|
|
|
|
//double resistance = value / 100 * 200;
|
|
|
|
|
|
|
|
|
|
|
|
byte windResistance = 0; //Product of Frontal Surface Area, Drag Coefficient and Air Density. Use default value: 0xFF, range: 0.00 – 1.86 kg/m
|
|
|
|
|
|
|
|
|
|
|
|
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 = (byte)79;
|
|
|
|
|
|
byte[] Data = new byte[9]
|
|
|
|
|
|
{
|
|
|
|
|
|
channelId,
|
|
|
|
|
|
(byte) 50,
|
|
|
|
|
|
byte.MaxValue,
|
|
|
|
|
|
byte.MaxValue,
|
|
|
|
|
|
byte.MaxValue,
|
|
|
|
|
|
byte.MaxValue,
|
|
|
|
|
|
//Wind Resistance Coefficient 0.00 – 1.86kg/m Product of Frontal Surface Area, Drag Coefficient and Air Density.Use default value: 0xFF
|
|
|
|
|
|
windResistance,
|
|
|
|
|
|
//Wind Speed -127 – +127km/h
|
|
|
|
|
|
0xFF,
|
|
|
|
|
|
0xFF
|
|
|
|
|
|
};
|
|
|
|
|
|
AntConnector.Instance().SendMessage(id, Data);
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 轨道阻力
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="grade">坡度百分比的值,单位是%</param>
|
|
|
|
|
|
public void SetTrackResistance(double grade)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (this.State != DeviceState.Connected)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
_grade = grade;
|
|
|
|
|
|
if (_grade > 15)
|
|
|
|
|
|
{
|
|
|
|
|
|
_grade = 15;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (_grade < -5)
|
|
|
|
|
|
{
|
|
|
|
|
|
_grade = -5;
|
|
|
|
|
|
}
|
|
|
|
|
|
//Console.WriteLine($"轨道阻力{ grade }");
|
|
|
|
|
|
var channelId = GetChannelId();
|
|
|
|
|
|
//double resistance = value / 100 * 200;
|
|
|
|
|
|
|
|
|
|
|
|
//var windResistance = 0.00; //Product of Frontal Surface Area, Drag Coefficient and Air Density. Use default value: 0xFF, range: 0.00 – 1.86kg/m
|
|
|
|
|
|
|
|
|
|
|
|
byte id = (byte)79;
|
|
|
|
|
|
|
|
|
|
|
|
// zwift started
|
|
|
|
|
|
// 0000 a4 09 4e 00 10 19 18 19 1a 41 00 30 80 00 00
|
|
|
|
|
|
// reply a4 09 4f 00 33 ff ff ff ff 45 4e ff 25 # p.74 [33] track resistance, ff ff ff ff reserved, [45] slope lsb, [4e] slope msb in 1/100%, [ff] coefficient rolling resistance
|
|
|
|
|
|
// Simulated Grade(%) = (Raw Grade Value x 0.01%) – 200.00% , 454e = 20037 x 0.01 -200 = 0.37%
|
|
|
|
|
|
//var gradeBytes = BitConverter.GetBytes(0x4E20);
|
|
|
|
|
|
|
|
|
|
|
|
var gradeValue = Convert.ToInt32((grade + 200) * 100);
|
|
|
|
|
|
var gradeBytes = BitConverter.GetBytes(gradeValue);
|
|
|
|
|
|
//var gradeBytes = BitConverter.GetBytes(20004);
|
|
|
|
|
|
byte[] Data = new byte[9]
|
|
|
|
|
|
{
|
|
|
|
|
|
channelId,
|
|
|
|
|
|
(byte) 51,
|
|
|
|
|
|
byte.MaxValue,
|
|
|
|
|
|
byte.MaxValue,
|
|
|
|
|
|
byte.MaxValue,
|
|
|
|
|
|
byte.MaxValue,
|
|
|
|
|
|
gradeBytes[0],
|
|
|
|
|
|
gradeBytes[1],
|
|
|
|
|
|
byte.MaxValue
|
|
|
|
|
|
};
|
|
|
|
|
|
AntConnector.Instance().SendMessage(id, Data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void UpdateUserConfiguration()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (this.State != DeviceState.Connected)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
var channelId = GetChannelId();
|
|
|
|
|
|
//var _weight = (int)(this._riderWeight * 100.0);
|
|
|
|
|
|
//byte id = (byte)79;
|
|
|
|
|
|
//byte[] Data = new byte[9]
|
|
|
|
|
|
// {
|
|
|
|
|
|
// channelId,
|
|
|
|
|
|
// (byte) 55,
|
|
|
|
|
|
// (byte)(_weight & (int) byte.MaxValue),
|
|
|
|
|
|
// (byte)(_weight >> 8 & (int) byte.MaxValue),
|
|
|
|
|
|
// byte.MaxValue,
|
|
|
|
|
|
// (byte) 143,
|
|
|
|
|
|
// (byte) 12,
|
|
|
|
|
|
// (byte) 70,
|
|
|
|
|
|
// (byte) 0
|
|
|
|
|
|
// };
|
|
|
|
|
|
//AntConnector.Instance().SendMessage(id, Data);
|
|
|
|
|
|
AntConnector.Instance().SendMessage(new FecUserConfiguration(channelId, this._riderWeight).GetMessage());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
internal void DoCalibrationSuccess(int? offset)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.LastCalibration = DateTime.UtcNow;
|
|
|
|
|
|
this.Offset = offset;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|