PowerMeterReceiver.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using ANT_Managed_Library;
  5. using System;
  6. /*
  7. Frequencies such as 4.06 Hz (ANT+ Heart
  8. Rate) and 4.005 Hz (ANT+ Bike Power) will
  9. periodically “drift” into each other, or into
  10. other channel periods that may be present
  11. in the vicinity. During this overlap, channel
  12. collisions may occur as the radio can only
  13. service channel at a time.
  14. */
  15. public class PowerMeterReceiver
  16. {
  17. private int deviceID = 0; //set this to connect to a specific device ID
  18. private bool connected = false; //will be set to true once connected
  19. private List<AntDevice> scanResult;
  20. private int instantaneousPower; // the instantaneous power in watt
  21. private int instantaneousCadence; // crank cadence in RPM if available ( 255 indicates invalid)
  22. private float crankTorque;
  23. private AntChannel backgroundScanChannel;
  24. private AntChannel deviceChannel;
  25. public int DeviceID => deviceID;
  26. public bool Connected => connected;
  27. public List<AntDevice> ScanResult => scanResult;
  28. public int InstantaneousPower => instantaneousPower;
  29. public int InstantaneousCadence => instantaneousCadence;
  30. public float CrankTorque => crankTorque;
  31. private byte[] pageToSend;
  32. public PowerMeterReceiver()
  33. {
  34. }
  35. public PowerMeterReceiver(int deviceID) => this.deviceID = deviceID;
  36. public void StartScan()
  37. {
  38. Debug.Log("Looking for ANT + power meter sensor");
  39. AntManager.Instance.Init();
  40. scanResult = new List<AntDevice>();
  41. backgroundScanChannel = AntManager.Instance.OpenBackgroundScanChannel(0);
  42. backgroundScanChannel.onReceiveData += ReceivedBackgroundScanData;
  43. }
  44. void ReceivedBackgroundScanData(Byte[] data)
  45. {
  46. byte deviceType = (data[12]); // extended info Device Type byte
  47. switch (deviceType)
  48. {
  49. case AntplusDeviceType.BikePower:
  50. {
  51. int deviceNumber = (data[10]) | data[11] << 8;
  52. byte transType = data[13];
  53. foreach (AntDevice d in scanResult)
  54. {
  55. if (d.deviceNumber == deviceNumber && d.transType == transType) //device already found
  56. return;
  57. }
  58. AntDevice foundDevice = new AntDevice();
  59. foundDevice.deviceType = deviceType;
  60. foundDevice.deviceNumber = deviceNumber;
  61. foundDevice.transType = transType;
  62. foundDevice.period = 8182;
  63. foundDevice.radiofreq = 57;
  64. foundDevice.name = "Powermeter(" + foundDevice.deviceNumber + ")";
  65. scanResult.Add(foundDevice);
  66. if (deviceNumber == deviceID)
  67. {
  68. Debug.Log($"Desired Power Sensor with id {deviceNumber} found!");
  69. ConnectToDevice(foundDevice);
  70. }
  71. else
  72. {
  73. Debug.Log($"Power sensor ({deviceNumber}) found and added to ScanResult");
  74. }
  75. break;
  76. }
  77. }
  78. }
  79. void ConnectToDevice(AntDevice device)
  80. {
  81. AntManager.Instance.CloseBackgroundScanChannel();
  82. byte channelID = AntManager.Instance.GetFreeChannelID();
  83. deviceChannel = AntManager.Instance.OpenChannel(ANT_ReferenceLibrary.ChannelType.BASE_Slave_Receive_0x00,
  84. channelID, (ushort) device.deviceNumber, device.deviceType, device.transType, (byte) device.radiofreq,
  85. (ushort) device.period, false);
  86. connected = true;
  87. deviceChannel.onReceiveData += Data;
  88. deviceChannel.onChannelResponse += ChannelResponse;
  89. deviceChannel.hideRXFAIL = true;
  90. }
  91. private readonly Dictionary<int, int> updateEventCount = new Dictionary<int, int> {{0x10, 0}, {0x12, 0}};
  92. private readonly Dictionary<int, int> sameEventCounter = new Dictionary<int, int> {{0x10, 0}, {0x12, 0}};
  93. private int previousAccumulatedTorqueValue = 0;
  94. private int previousTorqueEventCount = 0;
  95. //Deal with the received Data
  96. private void Data(Byte[] data)
  97. {
  98. if (data[0] == 0x10) // Standard Power-Only Main Data Page
  99. {
  100. if (data[1] == updateEventCount[0x10])
  101. sameEventCounter[0x10]++;
  102. else
  103. sameEventCounter[0x10] = 0;
  104. updateEventCount[0x10] = data[1];
  105. if (sameEventCounter[0x10] > 3)
  106. {
  107. instantaneousPower = 0;
  108. instantaneousCadence = 0;
  109. }
  110. else
  111. {
  112. instantaneousPower = data[6] | data[7] << 8;
  113. instantaneousCadence = data[3];
  114. }
  115. }
  116. if (data[0] == 0x12) // Standard Crank Torque Main Data Page
  117. {
  118. Debug.Log($"Torque Data {data}");
  119. if (data[1] == updateEventCount[0x12])
  120. sameEventCounter[0x12]++;
  121. else
  122. sameEventCounter[0x12] = 0;
  123. updateEventCount[0x12] = data[1];
  124. if (sameEventCounter[0x12] > 3)
  125. {
  126. crankTorque = 0;
  127. }
  128. else
  129. {
  130. int accumulatedTorque = data[6] | data[7] << 8;
  131. float divisor = (32 * (updateEventCount[0x12] - previousTorqueEventCount));
  132. if (divisor > 0)
  133. {
  134. crankTorque = (accumulatedTorque - previousAccumulatedTorqueValue) / divisor;
  135. }
  136. Debug.Log($"instantaneousCrankTorque = {crankTorque}");
  137. previousAccumulatedTorqueValue = accumulatedTorque;
  138. previousTorqueEventCount = updateEventCount[0x12];
  139. }
  140. }
  141. }
  142. public void Calibrate()
  143. {
  144. Debug.Log("Sending : Manual Zero Calibration request");
  145. pageToSend = new byte[8] {0x01, 0xAA, 0x0FF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  146. deviceChannel.sendAcknowledgedData(pageToSend);
  147. }
  148. void ChannelResponse(ANT_Response response)
  149. {
  150. if (response.getChannelEventCode() == ANT_ReferenceLibrary.ANTEventID.EVENT_TRANSFER_TX_FAILED_0x06)
  151. {
  152. deviceChannel.sendAcknowledgedData(pageToSend); //send the page again if the transfer failed
  153. }
  154. }
  155. }