ANT_Device.cs 93 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869
  1. /*
  2. This software is subject to the license described in the License.txt file
  3. included with this software distribution. You may not use this file except in compliance
  4. with this license.
  5. Copyright (c) Dynastream Innovations Inc. 2013
  6. All rights reserved.
  7. */
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Linq;
  11. using System.Text;
  12. using System.Runtime.InteropServices;
  13. //using System.Management;
  14. using Debug = UnityEngine.Debug;
  15. namespace ANT_Managed_Library
  16. {
  17. /// <summary>
  18. /// Control class for a given ANT device. An instance of this class is an open connection to the given ANT USB device.
  19. /// Handles creating channels and device setup.
  20. /// </summary>
  21. public class ANT_Device : IDisposable
  22. {
  23. #region variables
  24. ANT_ReferenceLibrary.FramerType frameType;
  25. ANT_ReferenceLibrary.PortType portType;
  26. IntPtr unmanagedANTSerialPtr = IntPtr.Zero;
  27. IntPtr unmanagedANTFramerPtr = IntPtr.Zero;
  28. IntPtr unmanagedCancelBool = IntPtr.Zero; //The bool type def in the unmanaged code is an int, so 4 bytes
  29. bool? cancelTxFlag //Handles accessing the unmanged bool as a normal nullable bool
  30. {
  31. get
  32. {
  33. if(unmanagedCancelBool == IntPtr.Zero)
  34. return null;
  35. return Convert.ToBoolean(Marshal.ReadInt32(unmanagedCancelBool));
  36. }
  37. set //TODO: Should we send out a deviceNotification when this occurs?
  38. {
  39. if (unmanagedCancelBool != IntPtr.Zero)
  40. Marshal.WriteInt32(unmanagedCancelBool, Convert.ToInt32(value));
  41. }
  42. }
  43. bool initializedUSB = false;
  44. byte USBDeviceNum = 255; //Device num of instance
  45. uint USBBaudRate = 0;
  46. ANT_DeviceCapabilities capabilities = null;
  47. bool pollingOn;
  48. int numDeviceChannels;
  49. ANT_Channel[] antChannels;
  50. #endregion
  51. #region DeviceCallback variables
  52. //This struct is used by the unmanaged code to pass response messages
  53. [StructLayout(LayoutKind.Sequential)]
  54. struct ANTMessageItem
  55. {
  56. public byte dataSize;
  57. public ANTMessage antMsgData;
  58. }
  59. /// <summary>
  60. /// ANTMessage struct as defined in unmanaged code for marshalling ant messages with unmanaged code
  61. /// </summary>
  62. [StructLayout(LayoutKind.Sequential)]
  63. public struct ANTMessage
  64. {
  65. /// <summary>
  66. /// Message ID byte
  67. /// </summary>
  68. public byte msgID;
  69. /// <summary>
  70. /// Data buffer
  71. /// </summary>
  72. [MarshalAs(UnmanagedType.ByValArray, SizeConst = ANT_ReferenceLibrary.MAX_MESG_SIZE)] //We have to make sure the marshalling knows the unmanaged equivalent is a fixed array of the maximum ANT message size
  73. public byte[] ucharBuf; //The size of this should match the SizeConst
  74. }
  75. /// <summary>
  76. /// Codes for the device notification event
  77. /// </summary>
  78. public enum DeviceNotificationCode : byte
  79. {
  80. /// <summary>
  81. /// The device is being reset
  82. /// </summary>
  83. Reset = 0x01,
  84. /// <summary>
  85. /// The device is being shutdown
  86. /// </summary>
  87. Shutdown = 0x02,
  88. }
  89. System.Threading.Thread responsePoller; //This thread is in charge of monitoring the device for new messages and forwards them to the appropriate handler function
  90. /// <summary>
  91. /// Delegate for device response event
  92. /// </summary>
  93. /// <param name="response">Message details received from device</param>
  94. public delegate void dDeviceResponseHandler(ANT_Response response); //The delegate for the managed callback functions
  95. /// <summary>
  96. /// The channel callback event. Triggered every time a message is received from the ANT device.
  97. /// Examples include requested responses and setup status messages.
  98. /// </summary>
  99. public event dDeviceResponseHandler deviceResponse; //The event to assign callback functions to in a managed application
  100. /// <summary>
  101. /// Function to handle ANT_Device serial errors
  102. /// </summary>
  103. /// <param name="sender">The ANT_Device reporting the error</param>
  104. /// <param name="error">The serial error that occured</param>
  105. /// <param name="isCritical">If true, the communication with the device is lost and this device object should be disposed</param>
  106. public delegate void dSerialErrorHandler(ANT_Device sender, serialErrorCode error, bool isCritical); //The delegate for the serialError callback function
  107. /// <summary>
  108. /// This event is triggered when there is a serial communication error with the ANT Device.
  109. /// If the error is critical all communication with the device is dead and the
  110. /// device reference is sent in this function to allow the application
  111. /// to know which device is dead and to dispose of it.
  112. /// </summary>
  113. public event dSerialErrorHandler serialError;
  114. /// <summary>
  115. /// ANT Device Serial Error Codes
  116. /// </summary>
  117. public enum serialErrorCode
  118. {
  119. /// <summary>
  120. /// A write command to the device failed, could be a usb communication issue or due to invalid paramters passed to the write function.
  121. /// If it is a device communication failure, a serial read error will most likely occur shortly.
  122. /// </summary>
  123. SerialWriteError,
  124. /// <summary>
  125. /// A failure occured reading data from the device.
  126. /// </summary>
  127. SerialReadError,
  128. /// <summary>
  129. /// Communication with the device has been lost.
  130. /// </summary>
  131. DeviceConnectionLost,
  132. /// <summary>
  133. /// A message received by the device failed the crc check and was discarded.
  134. /// </summary>
  135. MessageLost_CrcError,
  136. /// <summary>
  137. /// The message queue for received messages has overflowed and one or more messages were lost.
  138. /// </summary>
  139. MessageLost_QueueOverflow,
  140. /// <summary>
  141. /// A message received was over the maximum message size, and the message was discarded.
  142. /// This is usually due to a communication error or an error in the library or library compilation settings.
  143. /// </summary>
  144. MessageLost_TooLarge,
  145. /// <summary>
  146. /// A channel event was received for a channel which does not exist and the message was dropped (but will still appear in the logs)
  147. /// </summary>
  148. MessageLost_InvalidChannel,
  149. /// <summary>
  150. /// Unspecified error, most likely a new or changed error definition
  151. /// </summary>
  152. Unknown
  153. }
  154. #endregion
  155. #region ANT_DLL Imports
  156. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention=CallingConvention.Cdecl)]
  157. private static extern int ANT_Init(byte ucUSBDeviceNum, UInt32 usBaudrate, ref IntPtr returnSerialPtr, ref IntPtr returnFramerPtr, byte ucPortType, byte ucHCIFrameTpye);
  158. //Note: Before uncommenting this read todo comment on constructor, we don't use this now because we want to know the device number we opened
  159. //[DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention=CallingConvention.Cdecl)]
  160. //private static extern int ANT_AutoInit(ref IntPtr returnSerialPtr, ref IntPtr returnFramerPtr);
  161. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention=CallingConvention.Cdecl)]
  162. private static extern void ANT_Close(IntPtr SerialPtr, IntPtr FramerPtr);
  163. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention=CallingConvention.Cdecl)]
  164. private static extern int ANT_USBReset(IntPtr SerialPtr);
  165. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention=CallingConvention.Cdecl)]
  166. private static extern int ANT_ResetSystem(IntPtr FramerPtr, UInt32 ulResponseTime_);
  167. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention=CallingConvention.Cdecl)]
  168. private static extern void ANT_SetCancelParameter(IntPtr FramerPtr, IntPtr pbCancel);
  169. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_SetNetworkKey_RTO", CallingConvention=CallingConvention.Cdecl)]
  170. private static extern int ANT_SetNetworkKey(IntPtr FramerPtr, byte ucNetNumber, byte[] pucKey, UInt32 ulResponseTime_);
  171. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_EnableLED_RTO", CallingConvention=CallingConvention.Cdecl)]
  172. private static extern int ANT_EnableLED(IntPtr FramerPtr, byte ucEnable, UInt32 ulResponseTime_);
  173. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention=CallingConvention.Cdecl)]
  174. private static extern int ANT_GetDeviceUSBPID(IntPtr FramerPtr, ref UInt16 usbPID);
  175. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention=CallingConvention.Cdecl)]
  176. private static extern int ANT_GetDeviceUSBVID(IntPtr FramerPtr, ref UInt16 usbVID);
  177. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  178. private static extern int ANT_ConfigureSplitAdvancedBursts(IntPtr FramerPtr, int bEnabelSplitBursts);
  179. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_ConfigureAdvancedBurst_RTO", CallingConvention = CallingConvention.Cdecl)]
  180. private static extern int ANT_ConfigureAdvancedBurst(IntPtr FramerPtr, int enable, byte ucMaxPacketLength, UInt32 ulRequiredFields, UInt32 ulOptionalFields, UInt32 ulResponseTime_);
  181. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_ConfigureAdvancedBurst_ext_RTO", CallingConvention = CallingConvention.Cdecl)]
  182. private static extern int ANT_ConfigureAdvancedBurst_ext(IntPtr FramerPtr, int enable, byte ucMaxPacketLength, UInt32 ulRequiredFields, UInt32 ulOptionalFields, UInt16 usStallCount, byte ucRetryCount, UInt32 ulResponseTime_);
  183. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_SetCryptoKey_RTO", CallingConvention = CallingConvention.Cdecl)]
  184. private static extern int ANT_SetCryptoKey(IntPtr FramerPtr, byte ucVolatileKeyIndex, byte[] pucKey, UInt32 ulResponseTime_);
  185. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_SetCryptoID_RTO", CallingConvention = CallingConvention.Cdecl)]
  186. private static extern int ANT_SetCryptoID(IntPtr FramerPtr, byte[] pucData, UInt32 ulResponseTime_);
  187. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_SetCryptoUserInfo_RTO", CallingConvention = CallingConvention.Cdecl)]
  188. private static extern int ANT_SetCryptoUserInfo(IntPtr FramerPtr, byte[] pucData, UInt32 ulResponseTime_);
  189. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_SetCryptoRNGSeed_RTO", CallingConvention = CallingConvention.Cdecl)]
  190. private static extern int ANT_SetCryptoRNGSeed(IntPtr FramerPtr, byte[] pucData, UInt32 ulResponseTime_);
  191. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_SetCryptoInfo_RTO", CallingConvention = CallingConvention.Cdecl)]
  192. private static extern int ANT_SetCryptoInfo(IntPtr FramerPtr, byte ucParameter, byte[] pucData, UInt32 ulResponseTime_);
  193. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_LoadCryptoKeyNVMOp_RTO", CallingConvention = CallingConvention.Cdecl)]
  194. private static extern int ANT_LoadCryptoKeyNVMOp(IntPtr FramerPtr, byte ucNVMKeyIndex, byte ucVolatileKeyIndex, UInt32 ulResponseTime_);
  195. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_StoreCryptoKeyNVMOp_RTO", CallingConvention = CallingConvention.Cdecl)]
  196. private static extern int ANT_StoreCryptoKeyNVMOp(IntPtr FramerPtr, byte ucNVMKeyIndex, byte[] pucKey, UInt32 ulResponseTime_);
  197. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_CryptoKeyNVMOp_RTO", CallingConvention = CallingConvention.Cdecl)]
  198. private static extern int ANT_CryptoKeyNVMOp(IntPtr FramerPtr, byte ucOperation, byte ucNVMKeyIndex, byte[] pucData, UInt32 ulResponseTime_);
  199. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  200. private static extern uint ANT_GetDeviceSerialNumber(IntPtr SerialPtr);
  201. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  202. private static extern int ANT_GetDeviceUSBInfo(IntPtr FramerPtr, byte ucDeviceNum_,
  203. [MarshalAs(UnmanagedType.LPArray)] byte[] pucProductString_,
  204. [MarshalAs(UnmanagedType.LPArray)] byte[] pucSerialString_);
  205. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_SetTransmitPower_RTO", CallingConvention=CallingConvention.Cdecl)]
  206. private static extern int ANT_SetTransmitPower(IntPtr FramerPtr, byte ucTransmitPower_, UInt32 ulResponseTime_);
  207. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  208. private static extern int ANT_ConfigEventFilter(IntPtr FramerPtr, UInt16 usFilter_, UInt32 ulResponseTime_);
  209. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  210. private static extern int ANT_ConfigEventBuffer(IntPtr FramerPtr, byte ucConfig_, UInt16 usSize_, UInt16 usTime_, UInt32 ulResponseTime_);
  211. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  212. private static extern int ANT_ConfigHighDutySearch(IntPtr FramerPtr, byte ucEnable_, byte ucSuppressionCycles_, UInt32 ulResponseTime_);
  213. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  214. private static extern int ANT_SetSelectiveDataUpdateMask(IntPtr FramerPtr, byte ucMaskNumber_, byte[] ucSduMask_, UInt32 ulResponseTime_);
  215. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  216. private static extern int ANT_ConfigUserNVM(IntPtr FramerPtr, UInt16 usAddress_, byte[] pucData_, byte ucSize_, UInt32 ulResponseTime_);
  217. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention=CallingConvention.Cdecl)]
  218. private static extern int ANT_RequestMessage(IntPtr FramerPtr, byte ucANTChannel, byte ucMessageID, ref ANTMessageItem ANT_MESSAGE_ITEM_response, UInt32 ulResponseTime_);
  219. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  220. private static extern int ANT_RequestUserNvmMessage(IntPtr FramerPtr, byte ucANTChannel, byte ucMessageID, ref ANTMessageItem ANT_MESSAGE_ITEM_response, UInt16 usAddress, byte ucSize, UInt32 ulResponseTime_);
  221. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention=CallingConvention.Cdecl)]
  222. private static extern UInt16 ANT_WaitForMessage(IntPtr FramerPtr, UInt32 ulMilliseconds_);
  223. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention=CallingConvention.Cdecl)]
  224. private static extern UInt16 ANT_GetMessage(IntPtr FramerPtr, ref ANTMessage ANT_MESSAGE_response);
  225. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  226. private static extern byte ANT_GetChannelNumber(IntPtr FramerPtr, ref ANTMessage pstANTMessage);
  227. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  228. private static extern int ANT_GetCapabilities(IntPtr FramerPtr,
  229. [MarshalAs(UnmanagedType.LPArray)] byte[] pucCapabilities_,
  230. UInt32 ulResponseTime_);
  231. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_InitCWTestMode_RTO", CallingConvention = CallingConvention.Cdecl)]
  232. private static extern int ANT_InitCWTestMode(IntPtr FramerPtr, UInt32 ulResponseTime_);
  233. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_SetCWTestMode_RTO", CallingConvention=CallingConvention.Cdecl)]
  234. private static extern int ANT_SetCWTestMode(IntPtr FramerPtr, byte ucTransmitPower_, byte ucRFChannel_, UInt32 ulResponseTime_);
  235. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_OpenRxScanMode_RTO", CallingConvention=CallingConvention.Cdecl)]
  236. private static extern int ANT_OpenRxScanMode(IntPtr FramerPtr, UInt32 ulResponseTime_);
  237. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_Script_Write_RTO", CallingConvention=CallingConvention.Cdecl)]
  238. private static extern int ANT_Script_Write(IntPtr FramerPtr, byte ucSize_, byte[] pucData_, UInt32 ulResponseTime_);
  239. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_Script_Clear_RTO", CallingConvention=CallingConvention.Cdecl)]
  240. private static extern int ANT_Script_Clear(IntPtr FramerPtr, UInt32 ulResponseTime_);
  241. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_Script_SetDefaultSector_RTO", CallingConvention=CallingConvention.Cdecl)]
  242. private static extern int ANT_Script_SetDefaultSector(IntPtr FramerPtr, byte ucSectNumber_, UInt32 ulResponseTime_);
  243. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_Script_EndSector_RTO", CallingConvention=CallingConvention.Cdecl)]
  244. private static extern int ANT_Script_EndSector(IntPtr FramerPtr, UInt32 ulResponseTime_);
  245. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_Script_Dump_RTO", CallingConvention=CallingConvention.Cdecl)]
  246. private static extern int ANT_Script_Dump(IntPtr FramerPtr, UInt32 ulResponseTime_);
  247. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_Script_Lock_RTO", CallingConvention=CallingConvention.Cdecl)]
  248. private static extern int ANT_Script_Lock(IntPtr FramerPtr, UInt32 ulResponseTimeout_);
  249. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "ANT_RxExtMesgsEnable_RTO", CallingConvention=CallingConvention.Cdecl)]
  250. private static extern int ANT_RxExtMesgsEnable(IntPtr FramerPtr, byte ucEnable_, UInt32 ulResponseTimeout_);
  251. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention=CallingConvention.Cdecl)]
  252. private static extern int ANT_CrystalEnable(IntPtr FramerPtr, UInt32 ulResponseTime_);
  253. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention=CallingConvention.Cdecl)]
  254. private static extern int ANT_WriteMessage(IntPtr FramerPtr, ANTMessage pstANTMessage, UInt16 usMessageSize);
  255. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention=CallingConvention.Cdecl)]
  256. private static extern int ANT_SetLibConfig(IntPtr FramerPtr, byte ucLibConfigFlags_, UInt32 ulResponseTime_);
  257. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "FIT_SetFEState_RTO", CallingConvention=CallingConvention.Cdecl)]
  258. private static extern int FIT_SetFEState(IntPtr FramerPtr, byte ucFEState_, UInt32 ulResponseTime_);
  259. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, EntryPoint = "FIT_AdjustPairingSettings_RTO", CallingConvention=CallingConvention.Cdecl)]
  260. private static extern int FIT_AdjustPairingSettings(IntPtr FramerPtr, byte ucSearchLv_, byte ucPairLv_, byte ucTrackLv_, UInt32 ulResponseTime_);
  261. #endregion
  262. #region Constructors and Destructor
  263. /// <overloads>
  264. /// Opens a connection to an ANT device attached by USB.
  265. /// Throws exception if a connection can not be established.
  266. /// </overloads>
  267. /// <summary>
  268. /// Attempts to open a connection to an ANT device attached by USB using the given deviceNum and baud rate
  269. /// Throws exception if a connection can not be established.
  270. /// </summary>
  271. /// <param name="USBDeviceNum">The device number of the ANT USB device (the first connected device starts at 0 and so on)</param>
  272. /// <param name="baudRate">The baud rate to connect at (AP2/AT3=57600, AP1=50000)</param>
  273. public ANT_Device(byte USBDeviceNum, uint baudRate)
  274. :this(ANT_ReferenceLibrary.PortType.USB, USBDeviceNum, baudRate, ANT_ReferenceLibrary.FramerType.basicANT)
  275. {
  276. }
  277. /// <overloads>
  278. /// Opens a connection to an ANT device attached by USB.
  279. /// Throws exception if a connection can not be established.
  280. /// </overloads>
  281. /// <summary>
  282. /// Attempts to open a connection to an ANT device attached by USB using the given deviceNum and baud rate
  283. /// Throws exception if a connection can not be established.
  284. /// </summary>
  285. /// <param name="portType">The type of connection to use when talking to the device</param>
  286. /// <param name="USBDeviceNum">If port type is USB, device number of the ANT USB device.
  287. /// If port type is COM this is the COM port number</param>
  288. /// <param name="baudRate">The baud rate to connect at (USB: AP2/AT3=57600, AP1=50000)</param>
  289. /// <param name="frameType">The framing method to use for the connection to the chip.
  290. /// Needed for multimode chips and currently only supported on COM connections.</param>
  291. public ANT_Device(ANT_ReferenceLibrary.PortType portType, byte USBDeviceNum, uint baudRate, ANT_ReferenceLibrary.FramerType frameType)
  292. {
  293. try
  294. {
  295. startUp(USBDeviceNum, baudRate, frameType, portType, false); // Let exceptions propagate
  296. }
  297. catch
  298. {
  299. // If constructor throws an exception, release acquired resources and suppress finalization
  300. this.Dispose();
  301. throw;
  302. }
  303. }
  304. /// <summary>
  305. /// Automatically connects to first availiable ANTDevice.
  306. /// Throws exception if a connection can not be established.
  307. /// Will not auto find COM-connected devices.
  308. /// </summary>
  309. public ANT_Device() //TODO: Need to change this to use the c++ library auto open, so it will check device strings, etc. NOT as now where it could open any SI device...the problem is that currently if the autoinit is used the device number is not accessible which we want to keep for ANTWare II
  310. {
  311. ulong numDevices = ANT_Common.getNumDetectedUSBDevices();
  312. if (numDevices == 0)
  313. {
  314. throw new ANT_Exception("No ANT devices detected");
  315. }
  316. bool fail = true;
  317. for (byte i = 0; i < numDevices && fail; ++i)
  318. {
  319. try
  320. {
  321. //Try 57600 baud first
  322. startUp(i, 57600, ANT_ReferenceLibrary.FramerType.basicANT, ANT_ReferenceLibrary.PortType.USB, true); //If this fails it will throw an exception, and we'll try 50000
  323. fail = false; //If no exception is thrown we are good to go
  324. }
  325. catch (Exception)
  326. {
  327. //Try 50000 baudRate then
  328. try
  329. {
  330. startUp(i, 50000, ANT_ReferenceLibrary.FramerType.basicANT, ANT_ReferenceLibrary.PortType.USB, true);
  331. fail = false; //If no exception is thrown we are good to go
  332. }
  333. catch (Exception)
  334. {
  335. fail = true; //Both baud rates failed
  336. }
  337. }
  338. }
  339. if (fail)
  340. {
  341. // If constructor throws an exception, release acquired resources and suppress finalization
  342. this.Dispose();
  343. throw new ANT_Exception("Failed to connect to any ANT devices");
  344. }
  345. }
  346. //This is all the initialization, pulled out to this method so it could be called by both constructors
  347. private void startUp(byte USBDeviceNum, uint baudRate, ANT_ReferenceLibrary.FramerType frameType, ANT_ReferenceLibrary.PortType portType, bool calledByAutoInit)
  348. {
  349. // The SI libraries are not required for USB2, so attempt to connect first and only throw an
  350. // exception if this fails.
  351. int ret = ANT_Init(USBDeviceNum, baudRate, ref unmanagedANTSerialPtr, ref unmanagedANTFramerPtr, (byte)portType, (byte)frameType);
  352. if (ret != 0)
  353. {
  354. switch(ret)
  355. {
  356. case -1:
  357. throw new ANT_Exception("Unexpected init library error. This is typically a problem with the c++ library");
  358. case -2:
  359. throw new ANT_Exception("Unrecognized type parameters");
  360. case -3:
  361. throw new ANT_Exception("Unable to initialize USB:" + USBDeviceNum + " at Baud:" + baudRate + ", probably device not present or already in use, or drivers not installed");
  362. default:
  363. throw new ANT_Exception("Unrecognized error code received from c++ library");
  364. }
  365. }
  366. initializedUSB = true; //Keep track of whether device is connected or not
  367. this.USBDeviceNum = USBDeviceNum; //Keep the parameters for reference
  368. this.USBBaudRate = baudRate;
  369. this.frameType = frameType;
  370. this.portType = portType;
  371. #if (ANTFS_DEBUGGING)
  372. //This logging is used in the ANT-FS libraries. Will not create any files if logging not enabled
  373. ANT_Common.initDebugLogThread("Device" + USBDeviceNum + "_Application");
  374. ANT_Common.ANT_DebugResetTime();
  375. ANT_Common.writeToDebugLog("ANT_NET.DLL " + ANT_VersionInfo.getManagedLibraryVersion() + " with ANT_WrappedLib.DLL " + ANT_VersionInfo.getUnmanagedLibraryVersion());
  376. #endif
  377. try
  378. {
  379. responsePoller = new System.Threading.Thread(responsePollFunc);
  380. responsePoller.Name = this.ToString() + " Receive Thread";
  381. responsePoller.IsBackground = true; //Make this a background thread so it will terminate when a program closes
  382. responsePoller.Start();
  383. //Get capabilities so we know how many channels we have
  384. //If this throws an exception it is probably connected at the wrong baud rate, so we send a descriptive exception
  385. try
  386. {
  387. getDeviceCapabilities(true, 200);
  388. }
  389. catch (ANT_Exception ex)
  390. {
  391. throw new ANT_Exception(ex.Message.Remove(0, 22) + ", probably connecting at wrong baud rate");
  392. }
  393. if(ANT_Common.autoResetIsEnabled)
  394. ANT_ResetSystem(unmanagedANTFramerPtr, 200); //Send a reset so by the time the user gets this handle the device is viable
  395. numDeviceChannels = capabilities.maxANTChannels;
  396. // Set up the channel list to the right size
  397. antChannels = new ANT_Channel[numDeviceChannels];
  398. unmanagedCancelBool = Marshal.AllocHGlobal(4);
  399. cancelTxFlag = false;
  400. ANT_SetCancelParameter(unmanagedANTFramerPtr, unmanagedCancelBool);
  401. }
  402. catch (Exception) // clean up
  403. {
  404. shutdown();
  405. throw; //Forward the error to caller
  406. }
  407. }
  408. /// <summary>
  409. /// Destructor closes all opened resources
  410. /// </summary>
  411. ~ANT_Device()
  412. {
  413. shutdown();
  414. }
  415. /// <summary>
  416. /// Dispose method for explicit resource cleanup. Same as shutdownDeviceInstance() but doesn't nullify reference.
  417. /// </summary>
  418. public void Dispose()
  419. {
  420. shutdown();
  421. GC.SuppressFinalize(this);
  422. }
  423. //This function cleans up all opened resources
  424. //This is accessed externally by calling Dispose()
  425. private void shutdown()
  426. {
  427. try
  428. {
  429. lock (this) //To prevent multiple threads calling shutdown concurrently...not sure why because none of our other code is really thread safe
  430. {
  431. if (initializedUSB) //if reference is already disposed, there is no cleanup to do
  432. {
  433. //Notify and Close the channels first
  434. if (antChannels != null)
  435. {
  436. NotifyDeviceEvent(DeviceNotificationCode.Shutdown, null);
  437. foreach (ANT_Channel i in antChannels)
  438. {
  439. //We dispose any channel references because since the c++ framer is being destroyed dereferencing it later will blow it up,
  440. //By disposing the channel the user will know from the ObjectDisposed exceptions instead of an undeterministic c++ explosion
  441. if (i != null)
  442. i.Dispose(); //Since this nullifies all the list references, it will stop all further feedback to the channels
  443. }
  444. }
  445. //Now shutdown all the device resources
  446. //Set cancel so if we are in a transfer it has a chance to shutdown gracefully
  447. cancelTxFlag = true;
  448. //Exit the response polling thread
  449. pollingOn = false;
  450. if (!responsePoller.Join(1500)) //Wait for the poll thread to terminate
  451. {
  452. responsePoller.Abort(); //Abort poll thread if it doesn't join
  453. Debug.Log("Response poll thread did not join in timeout and was aborted. Was the application slow/stalling, or should we increase the join timeout?");
  454. }
  455. //We call reset directly, because we don't care about notifying the mgd channels because we just closed them
  456. //If capabilities is null, it means init failed and we don't have an open line of communication to send a reset
  457. if (capabilities != null && ANT_Common.autoResetIsEnabled)
  458. ANT_ResetSystem(unmanagedANTFramerPtr, 0);
  459. //This is the most important part: clean up the big unmanged objects
  460. ANT_Close(unmanagedANTSerialPtr, unmanagedANTFramerPtr);
  461. if (unmanagedCancelBool != IntPtr.Zero)
  462. {
  463. Marshal.FreeHGlobal(unmanagedCancelBool);
  464. unmanagedCancelBool = IntPtr.Zero;
  465. }
  466. //Mark as disposed
  467. initializedUSB = false;
  468. }
  469. }
  470. }
  471. catch (Exception ex)
  472. {
  473. //Ignore all exceptions because this is only called on destruction or critical failure anyway
  474. Debug.Log("Exception on shutdown: " + ex.Message);
  475. }
  476. }
  477. /// <summary>
  478. /// Shuts down all open resources, calls reset on the physical device, and nullifies the given ANTDevice and all its channels
  479. /// </summary>
  480. /// <param name="deviceToShutdown">ANTDevice to shutdown</param>
  481. public static void shutdownDeviceInstance(ref ANT_Device deviceToShutdown)
  482. {
  483. if (deviceToShutdown != null)
  484. {
  485. deviceToShutdown.Dispose();
  486. deviceToShutdown = null;
  487. }
  488. }
  489. //Allows a disposed channel to nullify its list reference, so the next call to getChannel() can get a new un-disposed reference
  490. internal void channelDisposed(byte channelNumber)
  491. {
  492. antChannels[channelNumber] = null;
  493. }
  494. #endregion
  495. #region non-ANTdll Functions
  496. /// <summary>
  497. /// Convert instance to a string including the USB device number the connection is on
  498. /// </summary>
  499. public override string ToString()
  500. {
  501. return base.ToString()+ " on USBdeviceNum: " + USBDeviceNum.ToString();
  502. }
  503. /// <summary>
  504. /// Returns the pointer to the underlying C++ ANT Framer used for messaging
  505. /// </summary>
  506. /// <returns>Pointer to C++ ANT Framer</returns>
  507. internal IntPtr getFramerPtr()
  508. {
  509. if (!initializedUSB)
  510. throw new ObjectDisposedException("ANTDevice object has been disposed");
  511. return unmanagedANTFramerPtr;
  512. }
  513. /// <summary>
  514. /// Returns the device number used when this instance was opened
  515. /// Note: For some device types this number is not static and can change whenever new devices are enumerated in the system
  516. /// </summary>
  517. public int getOpenedUSBDeviceNum()
  518. {
  519. return USBDeviceNum;
  520. }
  521. /// <summary>
  522. /// Returns the baud rate used when this instance was opened
  523. /// </summary>
  524. public uint getOpenedUSBBaudRate()
  525. {
  526. return USBBaudRate;
  527. }
  528. /// <summary>
  529. /// Returns the Frame Type used to open the device
  530. /// </summary>
  531. public ANT_ReferenceLibrary.FramerType getOpenedFrameType()
  532. {
  533. return frameType;
  534. }
  535. /// <summary>
  536. /// Returns the Port Type used to open the device
  537. /// </summary>
  538. public ANT_ReferenceLibrary.PortType getOpenedPortType()
  539. {
  540. return portType;
  541. }
  542. /// <summary>
  543. /// Returns the requested ANTChannel or throws an exception if channel doesn't exist.
  544. /// </summary>
  545. /// <param name="num">Channel number requested</param>
  546. public ANT_Channel getChannel(int num)
  547. {
  548. if (!initializedUSB)
  549. throw new ObjectDisposedException("ANTDevice object has been disposed");
  550. if(num > antChannels.Length-1 || num < 0)
  551. throw new ANT_Exception("Channel number invalid");
  552. if(antChannels[num] == null)
  553. antChannels[num] = new ANT_Channel(this, (byte)num);
  554. return antChannels[num];
  555. }
  556. /// <summary>
  557. /// Returns the number of ANTChannels owned by this device
  558. /// </summary>
  559. /// <returns>Number of ant channels on device</returns>
  560. public int getNumChannels()
  561. {
  562. if (!initializedUSB)
  563. throw new ObjectDisposedException("ANTDevice object has been disposed");
  564. return antChannels.Length;
  565. }
  566. void NotifyDeviceEvent(DeviceNotificationCode notification, Object notificationInfo)
  567. {
  568. foreach (ANT_Channel i in antChannels)
  569. {
  570. if(i != null)
  571. i.NotifyDeviceEvent(notification, notificationInfo);
  572. }
  573. }
  574. private void responsePollFunc()
  575. {
  576. ushort messageSize = 0;
  577. byte channelNum;
  578. bool isMsgForChannel;
  579. pollingOn = true; //Set to false on shutdown to terminate the thread
  580. #if (ANTFS_DEBUGGING)
  581. ANT_Common.initDebugLogThread("Device" + USBDeviceNum + "_ANTReceive"); // We still need this for ANT-FS! Will not be created if debug disabled
  582. #endif
  583. while (initializedUSB && pollingOn) //check continuously; this thread is terminated on destruction of the class
  584. {
  585. // We only wait in the unmanged code for 100 ms because we want this thread to be responsive on our side.
  586. // It does mean that we are running through a lot more cycles than we need to
  587. messageSize = ANT_WaitForMessage(unmanagedANTFramerPtr, 100);
  588. if (messageSize == (ushort)0xFFFE) //DSI_FRAMER_TIMEDOUT
  589. continue; //Expected, just keep looping
  590. ANTMessage newMessage = new ANTMessage();
  591. messageSize = ANT_GetMessage(unmanagedANTFramerPtr, ref newMessage);
  592. if (messageSize == (ushort)0xFFFF) // DSI_FRAMER_ERROR - in current library could be from CRC error, Write error, Read error, or DeviceGone
  593. {
  594. serialErrorCode error;
  595. bool isCritical = false;
  596. switch(newMessage.msgID)
  597. {
  598. case 0x02: //DSI_FRAMER_ANT_ESERIAL
  599. switch(newMessage.ucharBuf[0])
  600. {
  601. case 0x04: //ESERIAL -> DSI_FRAMER_ANT_CRC_ERROR
  602. error = serialErrorCode.MessageLost_CrcError;
  603. break;
  604. case 0x02: //ESERIAL -> DSI_SERIAL_EWRITE
  605. error = serialErrorCode.SerialWriteError;
  606. break;
  607. case 0x03: //ESERIAL -> DSI_SERIAL_EREAD
  608. error = serialErrorCode.SerialReadError;
  609. isCritical = true;
  610. break;
  611. case 0x01: //ESERIAL -> DSI_SERIAL_DEVICE_GONE
  612. error = serialErrorCode.DeviceConnectionLost;
  613. isCritical = true;
  614. break;
  615. default:
  616. error = serialErrorCode.Unknown;
  617. Debug.Log("Unknown serial failure, why isn't this known?");
  618. break;
  619. }
  620. break;
  621. case 0x01: //DSI_FRAMER_ANT_EQUEUE_OVERFLOW
  622. error = serialErrorCode.MessageLost_QueueOverflow;
  623. break;
  624. case 0x03: //DSI_FRAMER_ANT_EINVALID_SIZE
  625. error = serialErrorCode.MessageLost_TooLarge;
  626. break;
  627. default:
  628. error = serialErrorCode.Unknown;
  629. Debug.Log("Unknown serial failure, why isn't this known?");
  630. break;
  631. }
  632. if(isCritical)
  633. {
  634. //System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(x => shutdown())); //Clean up all resources on another thread to allow this one to close cleanly
  635. pollingOn = false; //Just stop polling, since we will never get new messages now. Allow the user to dispose of the device.
  636. }
  637. //If application has subscribed to the event we can inform them
  638. if (serialError != null)
  639. serialError(this, error, isCritical);
  640. if (isCritical)
  641. break; //If the device is dead, exit the polling loop
  642. else
  643. continue;
  644. }
  645. isMsgForChannel = false;
  646. channelNum = Byte.MaxValue;
  647. switch (newMessage.msgID) //Check if we send to channel or protocol response func
  648. {
  649. // Send on Channel event
  650. case (byte)ANT_ReferenceLibrary.ANTMessageID.RESPONSE_EVENT_0x40:
  651. if (newMessage.ucharBuf[1] == (byte)ANT_ReferenceLibrary.ANTMessageID.EVENT_0x01)
  652. isMsgForChannel = true;
  653. break;
  654. // or any of the transmission events
  655. case (byte)ANT_ReferenceLibrary.ANTMessageID.BROADCAST_DATA_0x4E:
  656. case (byte)ANT_ReferenceLibrary.ANTMessageID.ACKNOWLEDGED_DATA_0x4F:
  657. case (byte)ANT_ReferenceLibrary.ANTMessageID.EXT_BROADCAST_DATA_0x5D:
  658. case (byte)ANT_ReferenceLibrary.ANTMessageID.EXT_ACKNOWLEDGED_DATA_0x5E:
  659. case (byte)ANT_ReferenceLibrary.ANTMessageID.BURST_DATA_0x50:
  660. case (byte)ANT_ReferenceLibrary.ANTMessageID.EXT_BURST_DATA_0x5F:
  661. case (byte)ANT_ReferenceLibrary.ANTMessageID.RSSI_BROADCAST_DATA_0xC1:
  662. case (byte)ANT_ReferenceLibrary.ANTMessageID.RSSI_ACKNOWLEDGED_DATA_0xC2:
  663. case (byte)ANT_ReferenceLibrary.ANTMessageID.RSSI_BURST_DATA_0xC3:
  664. isMsgForChannel = true;
  665. break;
  666. }
  667. ANT_Response newResponse;
  668. //Now dispatch to appropriate event
  669. //The messages are buffered in the ant library so we just dispatch with current thread
  670. //then no matter how long the event call takes we still won't miss messages
  671. if (isMsgForChannel)
  672. {
  673. channelNum = (byte)(newMessage.ucharBuf[0] & 0x1F); //Mask out what channel this is for. [We can eventually switch to use the c++ code to determine the channel, but we should do it all together with getMessage to avoid extra marshalling and copying and remove the processing in C# above]
  674. if (antChannels != null && channelNum < antChannels.Length)
  675. {
  676. if (antChannels[channelNum] != null)
  677. antChannels[channelNum].MessageReceived(newMessage, messageSize);
  678. }
  679. else
  680. {
  681. if (serialError != null)
  682. serialError(this, serialErrorCode.MessageLost_InvalidChannel, false);
  683. }
  684. }
  685. else
  686. {
  687. newResponse = new ANT_Response(this, newMessage.ucharBuf[0], DateTime.Now, newMessage.msgID, newMessage.ucharBuf.Take(messageSize).ToArray());
  688. if (deviceResponse != null) //Ensure events are assigned before we call the event
  689. deviceResponse(newResponse);
  690. }
  691. }
  692. }
  693. /// <summary>
  694. /// Sets the cancel flag on all acknowledged and burst transfers in progress for the given amount of time.
  695. /// When these transmissions see the flag they will abort their operation and return as cancelled.
  696. /// </summary>
  697. /// <param name="cancelWaitTime">Time to set cancel flag for</param>
  698. public void cancelTransfers(int cancelWaitTime)
  699. {
  700. if (!initializedUSB)
  701. throw new ObjectDisposedException("ANTDevice object has been disposed");
  702. cancelTxFlag = true;
  703. System.Threading.Thread.Sleep(cancelWaitTime);
  704. cancelTxFlag = false;
  705. }
  706. /// <overloads>Returns the device capabilities</overloads>
  707. /// <summary>
  708. /// Returns the capabilities of this device.
  709. /// Throws an exception if capabilities are not received.
  710. /// </summary>
  711. /// <param name="forceNewCopy">Force function to send request message to device</param>
  712. /// <param name="responseWaitTime">Time to wait for device success response</param>
  713. /// <returns>Last device capabilities received or a new copy if forceNewCopy is true</returns>
  714. public ANT_DeviceCapabilities getDeviceCapabilities(bool forceNewCopy, UInt32 responseWaitTime)
  715. {
  716. if (!initializedUSB)
  717. throw new ObjectDisposedException("ANTDevice object has been disposed");
  718. if (forceNewCopy || capabilities == null)
  719. {
  720. try
  721. {
  722. ANT_DeviceCapabilities newCaps = null;
  723. ANT_Response response = requestMessageAndResponse(ANT_ReferenceLibrary.RequestMessageID.CAPABILITIES_0x54, responseWaitTime);
  724. if (response != null && response.responseID == (byte)ANT_ReferenceLibrary.RequestMessageID.CAPABILITIES_0x54)
  725. {
  726. byte[] padding = new byte[16 - response.messageContents.Length];
  727. newCaps = new ANT_DeviceCapabilities(response.messageContents.Concat(padding).ToArray());
  728. }
  729. capabilities = newCaps; //We replace the old capabilities because that is what forceNewCopy means
  730. }
  731. catch (Exception)
  732. {
  733. //If we timeout receiving the message or the interpretation fails
  734. throw new ANT_Exception("Retrieving Device Capabilities Failed");
  735. }
  736. }
  737. return capabilities;
  738. }
  739. /// <summary>
  740. /// Returns the device capabilities of this device.
  741. /// Throws an exception if capabilities are not received.
  742. /// </summary>
  743. public ANT_DeviceCapabilities getDeviceCapabilities() { return getDeviceCapabilities(false, 1500); }
  744. /// <summary>
  745. /// Returns the device capabilities of this device.
  746. /// Throws an exception if capabilities are not received.
  747. /// </summary>
  748. public ANT_DeviceCapabilities getDeviceCapabilities(UInt32 responseWaitTime) { return getDeviceCapabilities(false, responseWaitTime); }
  749. #endregion
  750. #region ANT Device Functions
  751. /// <overloads>Resets the USB device</overloads>
  752. /// <summary>
  753. /// Resets this USB device at the driver level
  754. /// </summary>
  755. public void ResetUSB()
  756. {
  757. if (portType != ANT_ReferenceLibrary.PortType.USB)
  758. throw new ANT_Exception("Can't call ResetUSB on non-USB devices");
  759. if (!initializedUSB)
  760. throw new ObjectDisposedException("ANTDevice object has been disposed");
  761. ANT_USBReset(unmanagedANTSerialPtr);
  762. }
  763. /// <overloads>Resets the device and all its channels</overloads>
  764. /// <summary>
  765. /// Reset this device and all associated channels
  766. /// </summary>
  767. /// <param name="responseWaitTime">Time to wait for device success response</param>
  768. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  769. public bool ResetSystem(UInt32 responseWaitTime)
  770. {
  771. if (!initializedUSB)
  772. throw new ObjectDisposedException("ANTDevice object has been disposed");
  773. // Notify channels
  774. NotifyDeviceEvent(DeviceNotificationCode.Reset, null);
  775. return (ANT_ResetSystem(unmanagedANTFramerPtr, responseWaitTime) == 1);
  776. }
  777. /// <summary>
  778. /// Reset this device and all associated channels
  779. /// </summary>
  780. public void ResetSystem(){ ResetSystem(500);}
  781. /// <overloads>Sets a network key</overloads>
  782. /// <summary>
  783. /// Set the network key for the given network
  784. /// Throws exception if net number is invalid or network key is not 8-bytes in length
  785. /// </summary>
  786. /// <param name="netNumber">The network number to set the key for</param>
  787. /// <param name="networkKey">The 8-byte network key</param>
  788. /// <param name="responseWaitTime">Time to wait for device success response</param>
  789. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  790. public bool setNetworkKey(byte netNumber, byte[] networkKey, UInt32 responseWaitTime)
  791. {
  792. if (!initializedUSB)
  793. throw new ObjectDisposedException("ANTDevice object has been disposed");
  794. if (capabilities != null)
  795. {
  796. if (netNumber >= capabilities.maxNetworks)
  797. throw new ANT_Exception("Network number must be less than the maximum capable networks of the device");
  798. }
  799. if (networkKey.Length != 8)
  800. throw new ANT_Exception("Network key must be 8 bytes");
  801. bool result = (ANT_SetNetworkKey(unmanagedANTFramerPtr, netNumber, networkKey, responseWaitTime) == 1);
  802. return result;
  803. }
  804. /// <summary>
  805. /// Set the network key for the given network
  806. /// Throws exception if net number is invalid or network key is not 8-bytes in length
  807. /// </summary>
  808. /// <param name="netNumber">The network number to set the key for</param>
  809. /// <param name="networkKey">The 8-byte network key</param>
  810. public void setNetworkKey(byte netNumber, byte[] networkKey) { setNetworkKey(netNumber, networkKey, 0); }
  811. /// <overloads>Sets the transmit power for all channels</overloads>
  812. /// <summary>
  813. /// Set the transmit power for all channels of this device
  814. /// </summary>
  815. /// <param name="transmitPower">Transmission power to set to</param>
  816. /// <param name="responseWaitTime">Time to wait for device success response</param>
  817. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  818. public bool setTransmitPowerForAllChannels(ANT_ReferenceLibrary.TransmitPower transmitPower, UInt32 responseWaitTime)
  819. {
  820. if (!initializedUSB)
  821. throw new ObjectDisposedException("ANTDevice object has been disposed");
  822. return (ANT_SetTransmitPower(unmanagedANTFramerPtr, (byte)transmitPower, responseWaitTime) == 1);
  823. }
  824. /// <summary>
  825. /// Set the transmit power for all channels of this device
  826. /// </summary>
  827. /// <param name="transmitPower">Transmission power to set to</param>
  828. public void setTransmitPowerForAllChannels(ANT_ReferenceLibrary.TransmitPower transmitPower) { setTransmitPowerForAllChannels(transmitPower, 0); }
  829. /// <summary>
  830. /// When enabled advanced burst messages will be split into standard burst packets when received.
  831. /// This is disabled by default.
  832. /// </summary>
  833. /// <param name="splitBursts">Whether to split advanced burst messages.</param>
  834. /// <returns>True on success.</returns>
  835. public bool configureAdvancedBurstSplitting(bool splitBursts)
  836. {
  837. if (!initializedUSB)
  838. throw new ObjectDisposedException("ANTDevice object has been disposed");
  839. return (ANT_ConfigureSplitAdvancedBursts(unmanagedANTFramerPtr, (splitBursts ? 1 : 0)) == 1);
  840. }
  841. /// <summary>
  842. /// Configure advanced bursting for this device.
  843. /// </summary>
  844. /// <param name="enable">Whether to enable advanced bursting messages</param>
  845. /// <param name="maxPacketLength">Maximum packet length allowed for bursting messages (valid values are 1-3)</param>
  846. /// <param name="requiredFields">Features that the application requires the device to use</param>
  847. /// <param name="optionalFields">Features that the device should use if it supports them</param>
  848. /// <param name="responseWaitTime">Time to wait for device success response</param>
  849. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  850. public bool configureAdvancedBursting(bool enable, byte maxPacketLength, ANT_ReferenceLibrary.AdvancedBurstConfigFlags requiredFields,
  851. ANT_ReferenceLibrary.AdvancedBurstConfigFlags optionalFields, UInt32 responseWaitTime)
  852. {
  853. if (!initializedUSB)
  854. throw new ObjectDisposedException("ANTDevice object has been disposed");
  855. return (ANT_ConfigureAdvancedBurst(unmanagedANTFramerPtr, (enable ? 1 : 0), maxPacketLength,
  856. (UInt32)requiredFields, (UInt32)optionalFields, responseWaitTime) == 1);
  857. }
  858. /// <summary>
  859. /// Configure advanced bursting for this device.
  860. /// </summary>
  861. /// <param name="enable">Whether to enable advanced bursting messages</param>
  862. /// <param name="maxPacketLength">Maximum packet length allowed for bursting messages (valid values are 1-3)</param>
  863. /// <param name="requiredFields">Features that the application requires the device to use</param>
  864. /// <param name="optionalFields">Features that the device should use if it supports them</param>
  865. public void configureAdvancedBursting(bool enable, byte maxPacketLength, ANT_ReferenceLibrary.AdvancedBurstConfigFlags requiredFields,
  866. ANT_ReferenceLibrary.AdvancedBurstConfigFlags optionalFields)
  867. {
  868. configureAdvancedBursting(enable, maxPacketLength, requiredFields, optionalFields, (UInt32)0);
  869. }
  870. /// <summary>
  871. /// Configure advanced bursting for this device including extended parameters.
  872. /// </summary>
  873. /// <param name="enable">Whether to enable advanced bursting messages</param>
  874. /// <param name="maxPacketLength">Maximum packet length allowed for bursting messages (valid values are 1-3)</param>
  875. /// <param name="requiredFields">Features that the application requires the device to use</param>
  876. /// <param name="optionalFields">Features that the device should use if it supports them</param>
  877. /// <param name="stallCount">Maximum number of burst periods (~3.1ms) to stall for while waiting for the next message</param>
  878. /// <param name="retryCount">Number of times (multiplied by 5) to retry burst</param>
  879. /// <param name="responseWaitTime">Time to wait for device success response</param>
  880. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  881. public bool configureAdvancedBursting_ext(bool enable, byte maxPacketLength, ANT_ReferenceLibrary.AdvancedBurstConfigFlags requiredFields,
  882. ANT_ReferenceLibrary.AdvancedBurstConfigFlags optionalFields, UInt16 stallCount, byte retryCount, UInt32 responseWaitTime)
  883. {
  884. if (!initializedUSB)
  885. throw new ObjectDisposedException("ANTDevice object has been disposed");
  886. return (ANT_ConfigureAdvancedBurst_ext(unmanagedANTFramerPtr, (enable ? 1 : 0), maxPacketLength,
  887. (UInt32)requiredFields, (UInt32)optionalFields, stallCount, retryCount, responseWaitTime) == 1);
  888. }
  889. /// <summary>
  890. /// Configure advanced bursting for this device including extended parameters.
  891. /// </summary>
  892. /// <param name="enable">Whether to enable advanced bursting messages</param>
  893. /// <param name="maxPacketLength">Maximum packet length allowed for bursting messages (valid values are 1-3)</param>
  894. /// <param name="requiredFields">Features that the application requires the device to use</param>
  895. /// <param name="optionalFields">Features that the device should use if it supports them</param>
  896. /// <param name="stallCount">Maximum number of burst periods (~3.1ms) to stall for while waiting for the next message</param>
  897. /// <param name="retryCount">Number of times (multiplied by 5) to retry burst</param>
  898. public void configureAdvancedBursting_ext(bool enable, byte maxPacketLength, ANT_ReferenceLibrary.AdvancedBurstConfigFlags requiredFields,
  899. ANT_ReferenceLibrary.AdvancedBurstConfigFlags optionalFields, UInt16 stallCount, byte retryCount)
  900. {
  901. configureAdvancedBursting_ext(enable, maxPacketLength, requiredFields, optionalFields, stallCount, retryCount, 0);
  902. }
  903. public bool setCryptoKey(byte volatileKeyIndex, byte[] encryptionKey, UInt32 responseWaitTime)
  904. {
  905. if (!initializedUSB)
  906. throw new ObjectDisposedException("ANTDevice object has been disposed");
  907. return (ANT_SetCryptoKey(unmanagedANTFramerPtr, volatileKeyIndex, encryptionKey, responseWaitTime) == 1);
  908. }
  909. public void setCryptoKey(byte volatileKeyIndex, byte[] encryptionKey)
  910. {
  911. setCryptoKey(volatileKeyIndex, encryptionKey, 0);
  912. }
  913. public bool setCryptoID(byte[] encryptionID, UInt32 responseWaitTime)
  914. {
  915. if (!initializedUSB)
  916. throw new ObjectDisposedException("ANTDevice object has been disposed");
  917. return (ANT_SetCryptoID(unmanagedANTFramerPtr, encryptionID, responseWaitTime) == 1);
  918. }
  919. public void setCryptoID(byte[] encryptionID)
  920. {
  921. setCryptoID(encryptionID, 0);
  922. }
  923. public bool setCryptoUserInfo(byte[] userInfoString, UInt32 responseWaitTime)
  924. {
  925. if (!initializedUSB)
  926. throw new ObjectDisposedException("ANTDevice object has been disposed");
  927. return (ANT_SetCryptoUserInfo(unmanagedANTFramerPtr, userInfoString, responseWaitTime) == 1);
  928. }
  929. public void setCryptoUserInfo(byte[] userInfoString)
  930. {
  931. setCryptoUserInfo(userInfoString, 0);
  932. }
  933. public bool setCryptoRNGSeed(byte[] cryptoRNGSeed, UInt32 responseWaitTime)
  934. {
  935. if (!initializedUSB)
  936. throw new ObjectDisposedException("ANTDevice object has been disposed");
  937. return (ANT_SetCryptoRNGSeed(unmanagedANTFramerPtr, cryptoRNGSeed, responseWaitTime) == 1);
  938. }
  939. public void setCryptoRNGSeed(byte[] cryptoRNGSeed)
  940. {
  941. setCryptoRNGSeed(cryptoRNGSeed, 0);
  942. }
  943. public bool setCryptoInfo(ANT_ReferenceLibrary.EncryptionInfo encryptionParameter, byte[] parameterData, UInt32 responseWaitTime)
  944. {
  945. if (!initializedUSB)
  946. throw new ObjectDisposedException("ANTDevice object has been disposed");
  947. return (ANT_SetCryptoInfo(unmanagedANTFramerPtr, (byte)encryptionParameter, parameterData, responseWaitTime) == 1);
  948. }
  949. public void setCryptoInfo(ANT_ReferenceLibrary.EncryptionInfo encryptionParameter, byte[] parameterData)
  950. {
  951. setCryptoInfo(encryptionParameter, parameterData, 0);
  952. }
  953. public bool loadCryptoKeyFromNVM(byte nonVolatileKeyIndex, byte volatileKeyIndex, UInt32 responseWaitTime)
  954. {
  955. if (!initializedUSB)
  956. throw new ObjectDisposedException("ANTDevice object has been disposed");
  957. return (ANT_LoadCryptoKeyNVMOp(unmanagedANTFramerPtr, nonVolatileKeyIndex, volatileKeyIndex, responseWaitTime) == 1);
  958. }
  959. public void loadCryptoKeyFromNVM(byte nonVolatileKeyIndex, byte volatileKeyIndex)
  960. {
  961. loadCryptoKeyFromNVM(nonVolatileKeyIndex, volatileKeyIndex, 0);
  962. }
  963. public bool storeCryptoKeyToNVM(byte nonVolatileKeyIndex, byte[] encryptionKey, UInt32 responseWaitTime)
  964. {
  965. if (!initializedUSB)
  966. throw new ObjectDisposedException("ANTDevice object has been disposed");
  967. return (ANT_StoreCryptoKeyNVMOp(unmanagedANTFramerPtr, nonVolatileKeyIndex, encryptionKey, responseWaitTime) == 1);
  968. }
  969. public void storeCryptoKeyToNVM(byte nonVolatileKeyIndex, byte[] encryptionKey)
  970. {
  971. storeCryptoKeyToNVM(nonVolatileKeyIndex, encryptionKey, 0);
  972. }
  973. public bool cryptoKeyNVMOp(ANT_ReferenceLibrary.EncryptionNVMOp memoryOperation, byte nonVolatileKeyIndex, byte[] operationData, UInt32 responseWaitTime)
  974. {
  975. if (!initializedUSB)
  976. throw new ObjectDisposedException("ANTDevice object has been disposed");
  977. return (ANT_CryptoKeyNVMOp(unmanagedANTFramerPtr, (byte)memoryOperation, nonVolatileKeyIndex, operationData, responseWaitTime) == 1);
  978. }
  979. public void cryptoKeyNVMOp(ANT_ReferenceLibrary.EncryptionNVMOp memoryOperation, byte nonVolatileKeyIndex, byte[] operationData)
  980. {
  981. cryptoKeyNVMOp(memoryOperation, nonVolatileKeyIndex, operationData, 0);
  982. }
  983. /// <overloads>Enables/Disables the device's LED</overloads>
  984. /// <summary>
  985. /// Enables/Disables the LED flashing when a transmission event occurs
  986. /// </summary>
  987. /// <param name="IsEnabled">Desired state</param>
  988. /// <param name="responseWaitTime">Time to wait for device success response</param>
  989. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  990. public bool EnableLED(bool IsEnabled, UInt32 responseWaitTime)
  991. {
  992. if (!initializedUSB)
  993. throw new ObjectDisposedException("ANTDevice object has been disposed");
  994. return (ANT_EnableLED(unmanagedANTFramerPtr, Convert.ToByte(IsEnabled), responseWaitTime) == 1);
  995. }
  996. /// <summary>
  997. /// Enables/Disables the LED flashing when a transmission event occurs
  998. /// </summary>
  999. /// <param name="IsEnabled">Desired state</param>
  1000. public void EnableLED(bool IsEnabled) { EnableLED(IsEnabled, 0); }
  1001. /// <overloads>Configures Event Buffering</overloads>
  1002. /// <summary>
  1003. /// Allows buffering of ANT events. Preset groups of events may be selected for buffering.
  1004. /// Events may be buffered by size or time and buffering can be used in conjunction with filtering.
  1005. /// </summary>
  1006. /// <param name="config">Selects which events are buffered</param>
  1007. /// <param name="size">Number of bytes that will be stored before a buffer flush occurs. Set to 0 to disable.</param>
  1008. /// <param name="time">Maximum time (in 10ms units) before a buffer flush occurs. Set to 0 to disable.
  1009. /// Buffer size must also be set to a non zero value.</param>
  1010. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1011. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1012. public bool configureEventBuffer(ANT_ReferenceLibrary.EventBufferConfig config, UInt16 size, UInt16 time, UInt32 responseWaitTime)
  1013. {
  1014. if (!initializedUSB)
  1015. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1016. return ANT_ConfigEventBuffer(unmanagedANTFramerPtr, (byte)config, size, time, responseWaitTime) == 1;
  1017. }
  1018. /// <summary>
  1019. /// Allows buffering of ANT events. Preset groups of events may be selected for buffering.
  1020. /// Events may be buffered by size or time and buffering can be used in conjunction with filtering.
  1021. /// </summary>
  1022. /// <param name="config">Selects which events are buffered</param>
  1023. /// <param name="size">Number of bytes that will be stored before a buffer flush occurs. Set to 0 to disable.</param>
  1024. /// <param name="time">Maximum time (in 10ms units) before a buffer flush occurs. Set to 0 to disable.
  1025. /// Buffer size must also be set to a non zero value.</param>
  1026. public void configureEventBuffer(ANT_ReferenceLibrary.EventBufferConfig config, UInt16 size, UInt16 time) { configureEventBuffer(config, size, time, 0); }
  1027. /// <overloads>Configures Event Filtering</overloads>
  1028. /// <summary>
  1029. /// Allows filtering of specified ANT events. Filtering can be used in conjunction with buffering.
  1030. /// </summary>
  1031. /// <param name="eventFilter">Bitfield of events to filter. Set Bit0 to filter event 0 etc.</param>
  1032. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1033. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1034. public bool configureEventFilter(UInt16 eventFilter, UInt32 responseWaitTime)
  1035. {
  1036. if (!initializedUSB)
  1037. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1038. return ANT_ConfigEventFilter(unmanagedANTFramerPtr, eventFilter, responseWaitTime) == 1;
  1039. }
  1040. /// <summary>
  1041. /// Allows filtering of specified ANT events. Filtering can be used in conjunction with buffering.
  1042. /// </summary>
  1043. /// <param name="eventFilter">Bitfield of events to filter. Set Bit0 to filter event 0 etc.</param>
  1044. public void configureEventFilter(UInt16 eventFilter) { configureEventFilter(eventFilter, 0); }
  1045. /// <overloads>Configures High Duty Search</overloads>
  1046. /// <summary>
  1047. /// Allows configuring High Duty Search if no channels have been opened yet
  1048. /// </summary>
  1049. /// <param name="enable">Enable or disable High Duty Search</param>
  1050. /// <param name="suppressionCycles">Search period to suppress high duty search in units of 250ms. 0=Allow full time, 5=Suppress entirely</param>
  1051. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1052. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1053. public bool configureHighDutySearch(bool enable, byte suppressionCycles, UInt32 responseWaitTime)
  1054. {
  1055. if (!initializedUSB)
  1056. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1057. return ANT_ConfigHighDutySearch(unmanagedANTFramerPtr, (enable ? (byte)1 : (byte)0), suppressionCycles, responseWaitTime) == 1;
  1058. }
  1059. /// <summary>
  1060. /// Allows configuring High Duty Search if no channels have been opened yet
  1061. /// </summary>
  1062. /// <param name="enable">Enable or disable High Duty Search</param>
  1063. /// <param name="suppressionCycles">Search period to suppress high duty search in units of 250ms. 0=Allow full time, 5=Suppress entirely</param>
  1064. public void configureHighDutySearch(bool enable, byte suppressionCycles) { configureHighDutySearch(enable, suppressionCycles, 0); }
  1065. /// <overloads>Allows defining a new Selective Data Update Mask</overloads>
  1066. /// <summary>
  1067. /// Allows defining a new Selective Data Update Mask
  1068. /// </summary>
  1069. /// <param name="maskNumber">Identifier for the SDU Mask</param>
  1070. /// <param name="mask">Rx Data Message Mask, 0=Ignore, 1=Update on Change</param>
  1071. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1072. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1073. public bool setSduMask(byte maskNumber, byte[] mask, UInt32 responseWaitTime)
  1074. {
  1075. if (!initializedUSB)
  1076. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1077. return ANT_SetSelectiveDataUpdateMask(unmanagedANTFramerPtr, maskNumber, mask, responseWaitTime) == 1;
  1078. }
  1079. /// <summary>
  1080. /// Allows defining a new Selective Data Update Mask
  1081. /// </summary>
  1082. /// <param name="maskNumber">Identifier for the SDU Mask</param>
  1083. /// <param name="mask">Rx Data Message Mask, 0=Ignore, 1=Update on Change</param>
  1084. public void setSduMask(byte maskNumber, byte[] mask) { setSduMask(maskNumber, mask, 0); }
  1085. /// <overloads>Configures User NVM</overloads>
  1086. /// <summary>
  1087. /// Allows configuring User NVM if available.
  1088. /// </summary>
  1089. /// <param name="address"> Nvm starting address</param>
  1090. /// <param name="data">Data block to write</param>
  1091. /// <param name="size">Size of data block</param>
  1092. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1093. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1094. public bool configureUserNvm(UInt16 address, byte[] data, byte size, UInt32 responseWaitTime)
  1095. {
  1096. if (!initializedUSB)
  1097. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1098. return ANT_ConfigUserNVM(unmanagedANTFramerPtr, address, data, size, responseWaitTime) == 1;
  1099. }
  1100. /// <summary>
  1101. /// Allows configuring User Nvm if available.
  1102. /// </summary>
  1103. /// <param name="address"> Nvm starting address</param>
  1104. /// <param name="data">Data block to write</param>
  1105. /// <param name="size">Size of data block</param>
  1106. public void configureUserNvm(UInt16 address, byte[] data, byte size) { configureUserNvm(address, data, size, 0); }
  1107. /// <overloads>Requests a message from the device and returns the response</overloads>
  1108. /// <summary>
  1109. /// Read User Nvm by sending Request Mesg capturing the response.
  1110. /// Throws exception on timeout.
  1111. /// </summary>
  1112. /// <param name="address">NVM Address to read from</param>
  1113. /// <param name="size">Number of bytes to read</param>
  1114. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1115. public ANT_Response readUserNvm(UInt16 address, byte size, UInt32 responseWaitTime)
  1116. {
  1117. if (!initializedUSB)
  1118. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1119. ANTMessageItem response = new ANTMessageItem();
  1120. if (ANT_RequestUserNvmMessage(unmanagedANTFramerPtr, 0, (byte)ANT_ReferenceLibrary.RequestMessageID.USER_NVM_0x7C, ref response, address, size, responseWaitTime) == 0)
  1121. throw new ANT_Exception("Timed out waiting for requested message");
  1122. ANT_Response retVal = new ANT_Response(this, 0, DateTime.Now, response.antMsgData.msgID, response.antMsgData.ucharBuf.Take(response.dataSize).ToArray());
  1123. return retVal;
  1124. }
  1125. /// <summary>
  1126. /// Read User Nvm by sending Request Mesg capturing the response.
  1127. /// Throws exception on timeout.
  1128. /// </summary>
  1129. /// <param name="address">NVM Address to read from</param>
  1130. /// <param name="size">Number of bytes to read</param>
  1131. public ANT_Response readUserNvm(UInt16 address, byte size)
  1132. {
  1133. return readUserNvm(address, size, 500);
  1134. }
  1135. /// <summary>
  1136. /// Obtains the PID (Product ID) of the USB device.
  1137. /// Throws an exception if the PID is not received.
  1138. /// </summary>
  1139. /// <returns>PID of the USB device.</returns>
  1140. public UInt16 getDeviceUSBPID()
  1141. {
  1142. if (!initializedUSB)
  1143. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1144. UInt16 returnPID = 0;
  1145. if(ANT_GetDeviceUSBPID(unmanagedANTFramerPtr, ref returnPID) != 1)
  1146. throw new ANT_Exception("Retrieving Device USB PID failed");
  1147. return (returnPID);
  1148. }
  1149. /// <summary>
  1150. /// Obtains the VID (Vendor ID) of the USB device
  1151. /// </summary>
  1152. /// <returns>VID of the USB device</returns>
  1153. public UInt16 getDeviceUSBVID()
  1154. {
  1155. if (!initializedUSB)
  1156. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1157. UInt16 returnVID = 0;
  1158. if (ANT_GetDeviceUSBVID(unmanagedANTFramerPtr, ref returnVID) != 1)
  1159. throw new ANT_Exception("Retrieving Device USB VID failed");
  1160. return (returnVID);
  1161. }
  1162. /// <summary>
  1163. /// Returns the USB device serial number.
  1164. /// This can be used to figure out the serial number if the option to use the USB device
  1165. /// serial number was selected.
  1166. /// </summary>
  1167. /// <returns>Client serial number</returns>
  1168. public uint getSerialNumber()
  1169. {
  1170. if (!initializedUSB)
  1171. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1172. return ANT_GetDeviceSerialNumber(unmanagedANTSerialPtr);
  1173. }
  1174. /// <overloads>Obtains the device USB Information</overloads>
  1175. /// <summary>
  1176. /// Obtains the USB information for the device
  1177. /// Throws an exception if no information is received
  1178. /// </summary>
  1179. /// <param name="deviceNum">USB Device Number</param>
  1180. /// <returns>USB Device Information</returns>
  1181. public ANT_DeviceInfo getDeviceUSBInfo(byte deviceNum)
  1182. {
  1183. if (!initializedUSB)
  1184. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1185. byte[] returnProdDescription = new byte[256]; // size should match that defined on the Unmanaged Wrapper
  1186. byte[] returnSerialString = new byte[256];
  1187. if (ANT_GetDeviceUSBInfo(unmanagedANTFramerPtr, deviceNum, returnProdDescription, returnSerialString) != 1)
  1188. throw new ANT_Exception("Retrieving USB device information failed");
  1189. return (new ANT_DeviceInfo(returnProdDescription, returnSerialString));
  1190. }
  1191. /// <summary>
  1192. /// Obtains the USB information for the device
  1193. /// Throws an exception if no information is received
  1194. /// </summary>
  1195. /// <returns>USB Device Information</returns>
  1196. public ANT_DeviceInfo getDeviceUSBInfo()
  1197. {
  1198. if (!initializedUSB)
  1199. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1200. return getDeviceUSBInfo(USBDeviceNum);
  1201. }
  1202. /// <overloads>Requests a message from the device and returns the response</overloads>
  1203. /// <summary>
  1204. /// Request a message from device and returns the response.
  1205. /// Throws exception on timeout.
  1206. /// </summary>
  1207. /// <param name="channelNum">Channel to send request on</param>
  1208. /// <param name="messageID">Request to send</param>
  1209. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1210. public ANT_Response requestMessageAndResponse(byte channelNum, ANT_ReferenceLibrary.RequestMessageID messageID, UInt32 responseWaitTime)
  1211. {
  1212. if (!initializedUSB)
  1213. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1214. ANTMessageItem response = new ANTMessageItem();
  1215. if (ANT_RequestMessage(unmanagedANTFramerPtr, channelNum, (byte)messageID, ref response, responseWaitTime) == 0)
  1216. throw new ANT_Exception("Timed out waiting for requested message");
  1217. ANT_Response retVal = new ANT_Response(this, channelNum, DateTime.Now, response.antMsgData.msgID, response.antMsgData.ucharBuf.Take(response.dataSize).ToArray());
  1218. return retVal;
  1219. }
  1220. /// <summary>
  1221. /// Request a message from device on channel 0 and returns the response.
  1222. /// Throws exception on timeout.
  1223. /// </summary>
  1224. /// <param name="messageID">Request to send</param>
  1225. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1226. public ANT_Response requestMessageAndResponse(ANT_ReferenceLibrary.RequestMessageID messageID, UInt32 responseWaitTime)
  1227. {
  1228. return requestMessageAndResponse(0, messageID, responseWaitTime);
  1229. }
  1230. /// <overloads>Requests a message from the device</overloads>
  1231. /// <summary>
  1232. /// Request a message from device
  1233. /// </summary>
  1234. /// <param name="channelNum">Channel to send request on</param>
  1235. /// <param name="messageID">Request to send</param>
  1236. public void requestMessage(byte channelNum, ANT_ReferenceLibrary.RequestMessageID messageID)
  1237. {
  1238. if (!initializedUSB)
  1239. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1240. ANTMessageItem dummystruct = new ANTMessageItem();
  1241. ANT_RequestMessage(unmanagedANTFramerPtr, channelNum, (byte)messageID, ref dummystruct, 0);
  1242. }
  1243. /// <summary>
  1244. /// Request a message from device
  1245. /// </summary>
  1246. /// <param name="messageID">Request to send</param>
  1247. public void requestMessage(ANT_ReferenceLibrary.RequestMessageID messageID)
  1248. {
  1249. requestMessage(0, messageID);
  1250. }
  1251. /// <overloads>Set device in continuous scanning mode</overloads>
  1252. /// <summary>
  1253. /// Starts operation in continuous scanning mode.
  1254. /// This allows the device to receive all messages matching the configured channel ID mask in an asynchronous manner.
  1255. /// This feature is not available on all ANT devices.
  1256. /// </summary>
  1257. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1258. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1259. public bool openRxScanMode(UInt32 responseWaitTime)
  1260. {
  1261. if (!initializedUSB)
  1262. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1263. return ANT_OpenRxScanMode(unmanagedANTFramerPtr, responseWaitTime) == 1;
  1264. }
  1265. /// <summary>
  1266. /// Starts operation in continuous scanning mode.
  1267. /// This allows the device to receive all messages matching the configured channel ID mask in an asynchronous manner.
  1268. /// </summary>
  1269. public void openRxScanMode() { openRxScanMode(0); }
  1270. /// <overloads>Initializes and starts CW test mode</overloads>
  1271. /// <summary>
  1272. /// Initialize and start CW test mode. This mode is to test your implementation for RF frequency requirements.
  1273. /// The device will transmit an unmodulated carrier wave at the RF frequency of 2400Mhz + RFFreqOffset at the specified power level.
  1274. /// This mode can then only be exited by a system reset.
  1275. /// Note: When this function call returns false, the system will be reset automatically.
  1276. /// </summary>
  1277. /// <param name="transmitPower">Transmission power to test at</param>
  1278. /// <param name="RFFreqOffset">Offset to add to 2400Mhz</param>
  1279. /// <param name="responseWaitTime">Time to wait for response, used for both initialization and start command</param>
  1280. /// <returns>False if initialization or starting of CW test mode fails. On false, the system is automatically reset.</returns>
  1281. /// <remarks>
  1282. /// This function encapsulates both ANT_InitCWTestMode and ANT_SetCWTestMode from the old library.
  1283. /// It will automatically reset the system if either call fails.
  1284. /// The given response time is used for both calls and the reset time is 500ms.
  1285. /// So max wait time = responseTime*2 + 500ms
  1286. /// </remarks>
  1287. public bool startCWTest(ANT_ReferenceLibrary.TransmitPower transmitPower, byte RFFreqOffset, UInt32 responseWaitTime)
  1288. {
  1289. if (!initializedUSB)
  1290. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1291. bool retVal = true;
  1292. ResetSystem(); //CW Mode is only supposed to be set up after a reset
  1293. if (ANT_InitCWTestMode(unmanagedANTFramerPtr, responseWaitTime) != 1)
  1294. retVal = false;
  1295. if (ANT_SetCWTestMode(unmanagedANTFramerPtr, (byte)transmitPower, RFFreqOffset, responseWaitTime) != 1)
  1296. retVal = false;
  1297. if (retVal == false && ANT_Common.autoResetIsEnabled) //If we messed up we want to make sure the module doesn't get messed up in CW mode, so we reset
  1298. ResetSystem(500);
  1299. return retVal;
  1300. }
  1301. /// <overloads>Enables extended message reception</overloads>
  1302. /// <summary>
  1303. /// Enables extended message receiving. When enabled, messages received will contain extended data.
  1304. /// </summary>
  1305. /// <param name="IsEnabled">Desired State</param>
  1306. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1307. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1308. public bool enableRxExtendedMessages(bool IsEnabled, UInt32 responseWaitTime)
  1309. {
  1310. if (!initializedUSB)
  1311. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1312. return ANT_RxExtMesgsEnable(unmanagedANTFramerPtr, Convert.ToByte(IsEnabled), responseWaitTime) == 1;
  1313. }
  1314. /// <summary>
  1315. /// Enables extended message receiving. When enabled, messages received will contain extended data.
  1316. /// </summary>
  1317. /// <param name="IsEnabled">Desired State</param>
  1318. public void enableRxExtendedMessages(bool IsEnabled) { enableRxExtendedMessages(IsEnabled, 0); }
  1319. /// <overloads>Enables the use of external 32kHz crystal</overloads>
  1320. /// <summary>
  1321. /// If the use of an external 32kHz crystal input is desired, this message must be sent once, each time a startup message is received
  1322. /// </summary>
  1323. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1324. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1325. /// <remarks> Enabling an external 32kHz crystal input as a low power clock source saves ~85uA while ANT is active when compared to using the internal clock source. </remarks>
  1326. public bool crystalEnable(UInt32 responseWaitTime)
  1327. {
  1328. if (!initializedUSB)
  1329. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1330. return ANT_CrystalEnable(unmanagedANTFramerPtr, responseWaitTime) == 1;
  1331. }
  1332. /// <summary>
  1333. /// If the use of an external 32kHz crystal input is desired, this message must be sent once, each time a startup message is received
  1334. /// </summary>
  1335. /// <remarks> Enabling an external 32kHz crystal input as a low power clock source saves ~85uA while ANT is active when compared to using the internal clock source. </remarks>
  1336. public void crystalEnable() { crystalEnable(0); }
  1337. /// <summary>
  1338. /// Writes a message to the device, this function allows sending manually formatted messages.
  1339. /// </summary>
  1340. /// <param name="msgID">msgID to write</param>
  1341. /// <param name="msgData">data buffer to write</param>
  1342. /// <returns>False if writing bytes to device fails</returns>
  1343. public bool writeRawMessageToDevice(byte msgID, byte[] msgData)
  1344. {
  1345. if (!initializedUSB)
  1346. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1347. //Create ANT_MESSAGE
  1348. ANTMessage aMsg = new ANTMessage();
  1349. aMsg.msgID = msgID;
  1350. //We create an array of max size, because the struct sizing expects a constant size array
  1351. int padNum = ANT_ReferenceLibrary.MAX_MESG_SIZE - msgData.Length;
  1352. if(padNum < 0)
  1353. throw new ANT_Exception("msgData max length is " + ANT_ReferenceLibrary.MAX_MESG_SIZE + " bytes");
  1354. aMsg.ucharBuf = msgData.Concat(new byte[padNum]).ToArray();
  1355. return ANT_WriteMessage(unmanagedANTFramerPtr, aMsg, (UInt16)msgData.Length) == 1;
  1356. }
  1357. /// <overloads>Configure the device ANT library, ie: to send extra msg info</overloads>
  1358. /// <summary>
  1359. /// Configure the device ANT library, ie: to send extra msg info
  1360. /// </summary>
  1361. /// <param name="libConfigFlags">Config flags</param>
  1362. /// <param name="responseWaitTime">Time to wait for response</param>
  1363. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1364. public bool setLibConfig(ANT_ReferenceLibrary.LibConfigFlags libConfigFlags, UInt32 responseWaitTime)
  1365. {
  1366. if (!initializedUSB)
  1367. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1368. return ANT_SetLibConfig(unmanagedANTFramerPtr, (byte)libConfigFlags, responseWaitTime) == 1;
  1369. }
  1370. /// <summary>
  1371. /// Configure the device ANT library, ie: to send extra msg info
  1372. /// </summary>
  1373. /// <param name="libConfigFlags">Config flags</param>
  1374. public void setLibConfig(ANT_ReferenceLibrary.LibConfigFlags libConfigFlags) { setLibConfig(libConfigFlags, 0); }
  1375. #region SensRcore NVM script commands
  1376. /// <overloads>Writes a SensRCore command to non-volatile memory</overloads>
  1377. /// <summary>
  1378. /// Writes a SensRcore command to non-volatile memory.
  1379. /// Throws exception if command string length > 255, although commands will be much smaller
  1380. /// </summary>
  1381. /// <param name="commandString">SensRcore command to write: [Cmd][CmdData0]...[CmdDataN], must be less than 256 bytes</param>
  1382. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1383. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1384. public bool script_Write(byte[] commandString, UInt32 responseWaitTime)
  1385. {
  1386. if (!initializedUSB)
  1387. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1388. if(!(commandString.Length < 256)) //We are casting to byte, so we need to be safe
  1389. throw new ANT_Exception("commandString max size is 255");
  1390. return ANT_Script_Write(unmanagedANTFramerPtr, (byte)commandString.Length, commandString, responseWaitTime) == 1;
  1391. }
  1392. /// <summary>
  1393. /// Writes a SensRcore command to non-volatile memory.
  1394. /// Throws exception if command string length > 255.
  1395. /// </summary>
  1396. /// <param name="commandString">SensRcore command to write: [Cmd][CmdData0]...[CmdDataN], must be less than 256 bytes</param>
  1397. public void script_Write(byte[] commandString) { script_Write(commandString, 0); }
  1398. /// <overloads>Clears the NVM</overloads>
  1399. /// <summary>
  1400. /// Clears the non-volatile memory. NVM should be cleared before beginning write operations.
  1401. /// </summary>
  1402. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1403. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1404. public bool script_Clear(UInt32 responseWaitTime)
  1405. {
  1406. if (!initializedUSB)
  1407. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1408. return ANT_Script_Clear(unmanagedANTFramerPtr, responseWaitTime) == 1;
  1409. }
  1410. /// <summary>
  1411. /// Clears the non-volatile memory. NVM should be cleared before beginning write operations.
  1412. /// </summary>
  1413. public void script_Clear() { script_Clear(0); }
  1414. /// <overloads>Sets the default SensRCore sector</overloads>
  1415. /// <summary>
  1416. /// Set the default sector which will be executed after mandatory execution of sector 0.
  1417. /// This command has no effect if it is set to 0 or the Read Pins for Sector command appears in sector 0.
  1418. /// </summary>
  1419. /// <param name="sectorNum">sector number to set as default</param>
  1420. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1421. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1422. public bool script_setDefaultSector(byte sectorNum, UInt32 responseWaitTime)
  1423. {
  1424. if (!initializedUSB)
  1425. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1426. return ANT_Script_SetDefaultSector(unmanagedANTFramerPtr, sectorNum, responseWaitTime) == 1;
  1427. }
  1428. /// <summary>
  1429. /// Set the default sector which will be executed after mandatory execution of sector 0.
  1430. /// This command has no effect if it is set to 0 or the Read Pins for Sector command appears in sector 0.
  1431. /// </summary>
  1432. /// <param name="sectorNum">sector number to set as default</param>
  1433. public void script_setDefaultSector(byte sectorNum) { script_setDefaultSector(sectorNum, 0); }
  1434. /// <overloads>Writes a sector break to NVM</overloads>
  1435. /// <summary>
  1436. /// Writes a sector break in the NVM image
  1437. /// </summary>
  1438. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1439. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1440. public bool script_endSector(UInt32 responseWaitTime)
  1441. {
  1442. if (!initializedUSB)
  1443. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1444. return ANT_Script_EndSector(unmanagedANTFramerPtr, responseWaitTime) == 1;
  1445. }
  1446. /// <summary>
  1447. /// Writes a sector break in the NVM image
  1448. /// </summary>
  1449. public void script_endSector() { script_endSector(0); }
  1450. /// <overloads>Request a dump of the device's script memory</overloads>
  1451. /// <summary>
  1452. /// Requests the device to return the current NVM contents through the device callback function.
  1453. /// The end of the dump is signified by a 0x57 NVM_Cmd msg, which contains 0x04 EndDump code followed by
  1454. /// a byte signifying how many instructions were read and returned.
  1455. /// </summary>
  1456. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1457. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1458. public bool script_requestNVMDump(UInt32 responseWaitTime)
  1459. {
  1460. if (!initializedUSB)
  1461. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1462. return ANT_Script_Dump(unmanagedANTFramerPtr, responseWaitTime) == 1;
  1463. }
  1464. /// <summary>
  1465. /// Requests the device to return the current NVM contents through the device callback function.
  1466. /// The end of the dump is signified by a 0x57 NVM_Cmd msg, which contains 0x04 EndDump code followed by
  1467. /// a byte signifying how many instructions were read and returned.
  1468. /// </summary>
  1469. public void script_requestNVMDump() { script_requestNVMDump(0); }
  1470. /// <overloads>Locks the NVM contents</overloads>
  1471. /// <summary>
  1472. /// Locks the NVM so that it can not be read by the dump function.
  1473. /// Can only be disabled by clearing the NVM.
  1474. /// </summary>
  1475. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1476. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1477. public bool script_lockNVM(UInt32 responseWaitTime)
  1478. {
  1479. if (!initializedUSB)
  1480. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1481. return ANT_Script_Lock(unmanagedANTFramerPtr, responseWaitTime) == 1;
  1482. }
  1483. /// <summary>
  1484. /// Locks the NVM so that it can not be read by the dump function.
  1485. /// Can only be disabled by clearing the NVM.
  1486. /// </summary>
  1487. public void script_lockNVM() { script_lockNVM(0); }
  1488. ///<overloads>Sets the equipment state</overloads>
  1489. /// <summary>
  1490. /// Sets the equipment state.
  1491. /// This command is specifically for use with the FIT1e module.
  1492. /// </summary>
  1493. /// <param name="feState">Fitness equipment state</param>
  1494. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1495. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1496. public bool fitSetFEState(byte feState, UInt32 responseWaitTime)
  1497. {
  1498. if (!initializedUSB)
  1499. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1500. if (!capabilities.FIT) // Check this is a FIT1e module
  1501. return false;
  1502. return FIT_SetFEState(unmanagedANTFramerPtr, feState, responseWaitTime) == 1;
  1503. }
  1504. /// <summary>
  1505. /// Sets the equipment state.
  1506. /// This command is specifically for use with the FIT1e module.
  1507. /// </summary>
  1508. /// <param name="feState">Fitness equipment state</param>
  1509. public void fitSetFEState(byte feState) { fitSetFEState(feState, 0);}
  1510. /// <summary>
  1511. /// Adjusts the pairing distance settings.
  1512. /// This command is specifically for use with the FIT1e module.
  1513. /// </summary>
  1514. /// <param name="searchLv">Minimum signal strength for a signal to be considered for pairing.</param>
  1515. /// <param name="pairLv">Signal strength required for the FIT1e to pair with an ANT+ HR strap or watch</param>
  1516. /// <param name="trackLv">An ANT+ device will unpair if the signal strength drops below this setting while in
  1517. /// READY state or within the first 30 secons of the IN_USE state</param>
  1518. /// <param name="responseWaitTime">Time to wait for device success response</param>
  1519. /// <returns>True on success. Note: Always returns true with a response time of 0</returns>
  1520. public bool fitAdjustPairingSettings(byte searchLv, byte pairLv, byte trackLv, UInt32 responseWaitTime)
  1521. {
  1522. if (!initializedUSB)
  1523. throw new ObjectDisposedException("ANTDevice object has been disposed");
  1524. if (!capabilities.FIT) // Check this is a FIT1e module
  1525. return false;
  1526. return FIT_AdjustPairingSettings(unmanagedANTFramerPtr, searchLv, pairLv, trackLv, responseWaitTime) == 1;
  1527. }
  1528. /// <summary>
  1529. /// Adjusts the pairing distance settings.
  1530. /// This command is specifically for use with the FIT1e module.
  1531. /// </summary>
  1532. /// <param name="searchLv">Minimum signal strength for a signal to be considered for pairing.</param>
  1533. /// <param name="pairLv">Signal strength required for the FIT1e to pair with an ANT+ HR strap or watch</param>
  1534. /// <param name="trackLv">An ANT+ device will unpair if the signal strength drops below this setting while in
  1535. /// READY state or within the first 30 secons of the IN_USE state</param>
  1536. public void fitAdjustPairingSettings(byte searchLv, byte pairLv, byte trackLv)
  1537. {
  1538. fitAdjustPairingSettings(searchLv, pairLv, trackLv, 0);
  1539. }
  1540. #endregion
  1541. #endregion
  1542. }
  1543. }