BleReceiver.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. using System;
  2. using System.Threading.Tasks;
  3. using Sensors.Polar;
  4. using UniRx;
  5. using UnityEngine;
  6. namespace Sensors.Bluetooth
  7. {
  8. [Serializable]
  9. public struct BleSensorConfig
  10. {
  11. public int port;
  12. public string ipAddress;
  13. [Tooltip("25, 50, 100 or 200")] public int accSampleRate; //TODO: let user choose between 25, 50, 100, 200
  14. public BleSensorConfig(int port = 9099, string ipAddress = "0.0.0.0", int accSampleRate = 25)
  15. {
  16. this.port = port;
  17. this.ipAddress = ipAddress;
  18. this.accSampleRate = accSampleRate;
  19. }
  20. }
  21. public struct BleSensorData
  22. {
  23. public Vector3 Acc;
  24. public float EcgValue;
  25. public int Hr;
  26. public PowermeterData PowermeterData;
  27. }
  28. public class BleReceiver
  29. {
  30. private const float TOLERANCE = 0.001f;
  31. private readonly Subject<AccData> rawAccDataSubject = new Subject<AccData>();
  32. private readonly Subject<EcgData> rawEcgDataSubject = new Subject<EcgData>();
  33. private readonly Subject<HRData> rawHRDataSubject = new Subject<HRData>();
  34. private UdpConnection connection;
  35. private BleSensorData sensorData;
  36. public BleReceiver(BleSensorConfig config)
  37. {
  38. SensorConfig = config;
  39. }
  40. public IObservable<EcgData> RawEcgData => rawEcgDataSubject.AsObservable();
  41. public IObservable<AccData> RawAccData => rawAccDataSubject.AsObservable();
  42. public IObservable<HRData> RawHRData => rawHRDataSubject.AsObservable();
  43. public BleSensorConfig SensorConfig { get; }
  44. public BleSensorData SensorData => sensorData;
  45. private RawPowermeterData? currentRawPowermeterData = null;
  46. private RawPowermeterData? previousRawPowermeterData = null;
  47. public void StartListening()
  48. {
  49. connection = new UdpConnection(SensorConfig.ipAddress, SensorConfig.port, OnAccData, OnEcgData, OnHRData,
  50. OnPowermeterData);
  51. connection.Listen();
  52. Debug.Log("PolarReceiver: Listening!");
  53. }
  54. public void Dispose()
  55. {
  56. rawAccDataSubject.Dispose();
  57. rawEcgDataSubject.Dispose();
  58. rawHRDataSubject.Dispose();
  59. connection?.StopListening();
  60. }
  61. private async void OnAccData(AccData data)
  62. {
  63. rawAccDataSubject.OnNext(data);
  64. await UpdateSensorDataForAcc(data);
  65. }
  66. private async Task UpdateSensorDataForAcc(AccData data)
  67. {
  68. foreach (var item in data.Values)
  69. {
  70. sensorData.Acc = item;
  71. await Task.Delay(1000 / SensorConfig.accSampleRate);
  72. }
  73. }
  74. private void OnEcgData(EcgData data)
  75. {
  76. rawEcgDataSubject.OnNext(data);
  77. sensorData.EcgValue = data.Values[0]; //TODO
  78. }
  79. private void OnHRData(HRData data)
  80. {
  81. rawHRDataSubject.OnNext(data);
  82. sensorData.Hr = data.HeartRate;
  83. }
  84. private void OnPowermeterData(RawPowermeterData data)
  85. {
  86. previousRawPowermeterData = currentRawPowermeterData;
  87. currentRawPowermeterData = data;
  88. var previousCadence = sensorData.PowermeterData.cadence;
  89. var previousTorque = sensorData.PowermeterData.torque;
  90. if (previousRawPowermeterData != null)
  91. {
  92. var p = previousRawPowermeterData.Value;
  93. var crankEventDif = data.lastCrankEventTime - p.lastCrankEventTime;
  94. var accumulatedTorqueDif = data.accumulatedTorque - p.accumulatedTorque;
  95. var crankRevDif = data.crankRevolutions - p.crankRevolutions;
  96. var cadence = previousCadence;
  97. var torque = previousTorque;
  98. if (crankEventDif > TOLERANCE)
  99. {
  100. cadence = Mathf.RoundToInt((crankRevDif / crankEventDif) * 60f);
  101. }
  102. else if (data.instantaniousPower == 0 && p.instantaniousPower == 0)
  103. {
  104. cadence = 0;
  105. }
  106. if (accumulatedTorqueDif > 0)
  107. {
  108. torque = accumulatedTorqueDif;
  109. }
  110. else if (data.instantaniousPower == 0 && p.instantaniousPower == 0)
  111. {
  112. cadence = 0;
  113. }
  114. sensorData.PowermeterData = new PowermeterData(data.instantaniousPower, cadence, torque);
  115. }
  116. }
  117. }
  118. }