ANTFS_ClientChannel.cs 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032
  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
  4. in compliance with this license.
  5. Copyright (c) Dynastream Innovations Inc. 2016
  6. All rights reserved.
  7. */
  8. using System;
  9. using System.Threading;
  10. using System.Collections.Generic;
  11. using System.Linq;
  12. using System.Text;
  13. using System.Runtime.InteropServices;
  14. using System.ComponentModel;
  15. using System.Reflection;
  16. using ANT_Managed_Library;
  17. namespace ANT_Managed_Library.ANTFS
  18. {
  19. /// <summary>
  20. /// Control class for an ANT-FS client channel.
  21. /// Handles creating channels and device setup, as well as the ANT-FS client implementation.
  22. /// </summary>
  23. public class ANTFS_ClientChannel : IDisposable
  24. {
  25. #region Public Definitions
  26. #pragma warning disable 1591
  27. /// <summary>
  28. /// ANT-FS Client Responses
  29. /// </summary>
  30. /// !!! Must match the enum in antfs_client_channel.hpp
  31. public enum Response : byte
  32. {
  33. [Description("No response")]
  34. None = 0,
  35. [Description("Idle")]
  36. InitPass,
  37. [Description("Error: Serial failure")]
  38. SerialFail,
  39. [Description("Beacon opened successfully")]
  40. BeaconOpen,
  41. [Description("Beacon closed successfully")]
  42. BeaconClosed,
  43. [Description("Connected to remote device")]
  44. ConnectPass,
  45. [Description("Disconnected successfully")]
  46. DisconnectPass,
  47. [Description("Lost connection")]
  48. ConnectionLost,
  49. [Description("Request for serial number successful")]
  50. AuthenticateNA,
  51. [Description("Authentication passed")]
  52. AuthenticatePass,
  53. [Description("Authentication rejected")]
  54. AuthenticateReject,
  55. [Description("Pairing request received")]
  56. PairingRequest,
  57. [Description("Pairing request timed out")]
  58. PairingTimeout,
  59. [Description("Download requested")]
  60. DownloadRequest,
  61. [Description("Download complete")]
  62. DownloadPass,
  63. [Description("Download rejected")]
  64. DownloadReject,
  65. [Description("Download failed, invalid index requested")]
  66. DownloadInvalidIndex,
  67. [Description("Download failed, file not readable")]
  68. DownloadFileNotReadable,
  69. [Description("Download failed, not ready")]
  70. DownloadNotReady,
  71. [Description("Download failed")]
  72. DownloadFail,
  73. [Description("Upload requested")]
  74. UploadRequest,
  75. [Description("Uploaded data")]
  76. UploadPass,
  77. [Description("Upload rejected")]
  78. UploadReject,
  79. [Description("Upload failed, invalid index requested")]
  80. UploadInvalidIndex,
  81. [Description("Upload failed, file not writeable")]
  82. UploadFileNotWriteable,
  83. [Description("Upload failed, insufficient space")]
  84. UploadInsufficientSpace,
  85. [Description("Upload failed")]
  86. UploadFail,
  87. [Description("Erase requested")]
  88. EraseRequest,
  89. [Description("Erased data")]
  90. ErasePass,
  91. [Description("Erase rejected")]
  92. EraseReject,
  93. [Description("Erase failed")]
  94. EraseFail,
  95. [Description("Request canceled")]
  96. CancelDone
  97. };
  98. /// <summary>
  99. /// ANT-FS Client State
  100. /// </summary>
  101. /// !!! Must match the enum in antfs_client_channel.hpp
  102. public enum State : byte
  103. {
  104. [Description("Off, state machine not initialized")]
  105. Off = 0,
  106. [Description("ANT-FS Client Idle")]
  107. Idle,
  108. [Description("Opening beacon")]
  109. Opening,
  110. [Description("Disconnecting")]
  111. Disconnecting,
  112. [Description("Beaconing")] // LINK
  113. Beaconing,
  114. [Description("Connected")] // AUTH
  115. Connected,
  116. [Description("Authenticating")]
  117. Authenticating,
  118. [Description("Authenticating, waiting for response to pairing request")]
  119. WaitingForPairingResponse,
  120. [Description("Transport")]
  121. Transport,
  122. [Description("Downloading data")]
  123. Downloading,
  124. [Description("Downloading, waiting for data to send")]
  125. WaitingForDownloadData,
  126. [Description("Uploading data")]
  127. Uploading,
  128. [Description("Waiting for response to an upload request")]
  129. WaitingForUploadResponse,
  130. [Description("Erasing data")]
  131. Erasing
  132. };
  133. #pragma warning restore 1591
  134. #endregion
  135. #region Variables
  136. bool bInitialized;
  137. bool bResponseThreadExit; // Flag response thread to exit
  138. Thread ResponseThread; // This thread is in charge of monitoring the device for responses and forwarding them to the appropiate handler
  139. Object syncToken = new object();
  140. ushort? usCurrentTransfer = null; // Current transfer being processed
  141. IntPtr unmanagedClientPtr = IntPtr.Zero; // Holder for the pointer to unmanaged ANTFSClientChannel object
  142. GCHandle? ghDownloadData = null; // Handle to allow pinning the managed download buffer
  143. byte networkNumber = 0; // ANT network number used for the ANT-FS client
  144. IANT_Channel channel; // ANT channel ClientChannel is using
  145. dRawChannelResponseHandler rawChannelResponseHandler; // ANT channel response handler
  146. dDeviceNotificationHandler deviceNotificationHandler; // ANT device notification handler
  147. #endregion
  148. #region Events
  149. /// <summary>
  150. /// The ANT-FS host callback event, triggered every time a response is received from the ANT-FS client library
  151. /// </summary>
  152. public event Action<Response> OnResponse;
  153. #endregion
  154. #region DllImports
  155. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  156. private static extern int ANTFSClient_New(ref IntPtr ClientPtr);
  157. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  158. private static extern int ANTFSClient_Init(IntPtr ClientPtr, IntPtr FramerPtr, byte ucANTChannel);
  159. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  160. private static extern int ANTFSClient_Close(IntPtr ClientPtr);
  161. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  162. private static extern int ANTFSClient_Delete(IntPtr ClientPtr);
  163. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  164. private static extern int ANTFSClient_Cancel(IntPtr ClientPtr);
  165. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  166. private static extern int ANTFSClient_ProcessDeviceNotification(
  167. IntPtr ClientPtr,
  168. byte ucCode,
  169. IntPtr pvParameter);
  170. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  171. private static extern byte ANTFSClient_ConfigureClientParameters(
  172. IntPtr ClientPtr,
  173. ref ANTFS_ClientParameters pstInitParams);
  174. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  175. private static extern byte ANTFSClient_SetPairingEnabled(IntPtr ClientPtr, bool bEnable);
  176. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  177. private static extern byte ANTFSClient_SetUploadEnabled(IntPtr ClientPtr, bool bEnable);
  178. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  179. private static extern byte ANTFSClient_SetDataAvailable(IntPtr ClientPtr, bool bDataAvailable);
  180. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  181. private static extern int ANTFSClient_SetBeaconTimeout(IntPtr ClientPtr, byte ucTimeout);
  182. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  183. private static extern int ANTFSClient_SetPairingTimeout(IntPtr ClientPtr, byte ucTimeout);
  184. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  185. private static extern int ANTFSClient_SetFriendlyName(
  186. IntPtr ClientPtr,
  187. [MarshalAs(UnmanagedType.LPArray)] byte[] pucFriendlyName,
  188. byte ucFriendlyNameSize);
  189. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  190. private static extern int ANTFSClient_SetPassKey(
  191. IntPtr ClientPtr,
  192. [MarshalAs(UnmanagedType.LPArray)] byte[] pucPassKey,
  193. byte ucPassKeySize);
  194. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  195. private static extern int ANTFSClient_SetChannelID(IntPtr ClientPtr, byte ucDeviceType, byte ucTransmissionType);
  196. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  197. private static extern int ANTFSClient_SetChannelPeriod(IntPtr ClientPtr, ushort usChannelPeriod);
  198. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  199. private static extern int ANTFSClient_SetNetworkKey(IntPtr ClientPtr, byte networkNumber, byte[] pucKey);
  200. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  201. private static extern int ANTFSClient_SetTxPower(IntPtr ClientPtr, byte ucPairingLv, byte ucConnectedLv);
  202. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  203. private static extern byte ANTFSClient_OpenBeacon(IntPtr ClientPtr);
  204. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  205. private static extern byte ANTFSClient_CloseBeacon(IntPtr ClientPtr, bool bReturnToBroadcast);
  206. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  207. private static extern int ANTFSClient_ProcessMessage(IntPtr ClientPtr, ref ANT_Device.ANTMessage pstANTMessage, ushort usMessageSize);
  208. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  209. private static extern byte ANTFSClient_SendPairingResponse(IntPtr ClientPtr, bool bAccept);
  210. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  211. private static extern byte ANTFSClient_SendDownloadResponse(
  212. IntPtr ClientPtr,
  213. byte ucResponse,
  214. ref ANTFS_DownloadParameters pstDownloadInfo,
  215. uint ulDataLength,
  216. IntPtr pvData); // Pointer is cached by unmanaged code for use after this call has ended, so pointer needs to be pinned
  217. // TODO: Add UploadResponse
  218. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  219. private static extern byte ANTFSClient_SendUploadResponse(
  220. IntPtr ClientPtr,
  221. byte ucResponse,
  222. ref ANTFS_UploadParameters pstUploadInfo,
  223. uint ulDataLength,
  224. IntPtr pvData); // Pointer is cached by unmanaged code for use after this call has ended, so pointer needs to be pinned
  225. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  226. private static extern byte ANTFSClient_SendEraseResponse(IntPtr ClientPtr, byte ucResponse);
  227. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  228. private static extern int ANTFSClient_GetEnabled(IntPtr ClientPtr);
  229. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  230. private static extern byte ANTFSClient_GetChannelNumber(IntPtr ClientPtr);
  231. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  232. private static extern int ANTFSClient_GetVersion(
  233. [MarshalAs(UnmanagedType.LPArray)] byte[] pucVersion,
  234. byte ucBufferSize);
  235. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  236. private static extern byte ANTFSClient_GetStatus(IntPtr ClientPtr);
  237. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  238. private static extern int ANTFSClient_GetHostName(
  239. IntPtr ClientPtr,
  240. [MarshalAs(UnmanagedType.LPArray)] byte[] pucFriendlyName,
  241. ref byte pucBufferSize);
  242. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  243. private static extern byte ANTFSClient_GetRequestParameters(
  244. IntPtr ClientPtr,
  245. ref ANTFS_RequestParameters pstRequestParams);
  246. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  247. private static extern byte ANTFSClient_GetRequestedFileIndex(
  248. IntPtr ClientPtr,
  249. ref ushort pusIndex);
  250. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  251. private static extern byte ANTFSClient_GetDownloadStatus(
  252. IntPtr ClientPtr,
  253. ref uint pulByteProgress,
  254. ref uint pulTotalLength);
  255. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  256. private static extern uint ANTFSClient_GetTransferSize(IntPtr ClientPtr);
  257. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  258. private static extern byte ANTFSClient_GetTransferData(
  259. IntPtr ClientPtr,
  260. ref ulong pulOffset,
  261. ref ulong pulDataSize,
  262. [MarshalAs(UnmanagedType.LPArray)] byte[] pucData);
  263. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  264. private static extern byte ANTFSClient_GetDisconnectParameters(
  265. IntPtr ClientPtr,
  266. ref ANTFS_DisconnectParameters pstDisconnectParams);
  267. [DllImport(ANT_Common.ANT_UNMANAGED_WRAPPER, CallingConvention = CallingConvention.Cdecl)]
  268. private static extern byte ANTFSClient_WaitForResponse(IntPtr ClientPtr, uint ulMilliseconds);
  269. #endregion
  270. #region Constructor, Finalizer & Dispose
  271. /// <summary>
  272. /// Constructor attempts to automatically detect an ANT USB device and open a connection to it
  273. /// </summary>
  274. public ANTFS_ClientChannel(IANT_Channel channel_)
  275. {
  276. try
  277. {
  278. channel = channel_;
  279. // Create the ANT-FS client object
  280. if (ANTFSClient_New(ref unmanagedClientPtr) == 0)
  281. throw new ANTFS_Exception("Unable to initialize ANT-FS Client");
  282. if (ANTFSClient_Init(unmanagedClientPtr, channel.getUnmgdFramer(), channel.getChannelNum()) == 0)
  283. throw new ANTFS_Exception("Unable to initialize client");
  284. rawChannelResponseHandler += new dRawChannelResponseHandler((msg,size) => ANTFSClient_ProcessMessage(unmanagedClientPtr, ref msg,size));
  285. deviceNotificationHandler += new dDeviceNotificationHandler(channel_DeviceNotification);
  286. channel.rawChannelResponse += rawChannelResponseHandler;
  287. channel.DeviceNotification += deviceNotificationHandler;
  288. // Setup thread to handle responses from the ANT-FS library
  289. bResponseThreadExit = false;
  290. ResponseThread = new Thread(new ThreadStart(ResponseThreadHandler));
  291. ResponseThread.Name = "ANT-FS Client Response Thread";
  292. ResponseThread.IsBackground = true; // Make this a background thread so it will terminate when main program closes
  293. ResponseThread.Start();
  294. bInitialized = true;
  295. }
  296. catch (Exception) // Catch so we can cleanup
  297. {
  298. this.Dispose();
  299. throw; // Forward the error to the caller
  300. }
  301. }
  302. /// <summary>
  303. /// Destructor closes all opened resources
  304. /// </summary>
  305. ~ANTFS_ClientChannel()
  306. {
  307. Dispose(false);
  308. }
  309. /// <summary>
  310. /// Dispose method for explicit resource cleanup
  311. /// </summary>
  312. public void Dispose()
  313. {
  314. Dispose(true);
  315. GC.SuppressFinalize(this);
  316. }
  317. /// <summary>
  318. /// Close connection, and release all resources
  319. /// Inherit public finalizer from ANT_Device
  320. /// </summary>
  321. protected virtual void Dispose(bool bDisposing)
  322. {
  323. if (bInitialized)
  324. {
  325. if (bDisposing)
  326. {
  327. // Dispose of other managed resources here
  328. channel.rawChannelResponse -= rawChannelResponseHandler;
  329. channel.DeviceNotification -= deviceNotificationHandler;
  330. }
  331. // Terminate the response handler thread
  332. if (ResponseThread != null && ResponseThread.IsAlive)
  333. {
  334. bResponseThreadExit = true;
  335. if (!ResponseThread.Join(3000))
  336. ResponseThread.Abort();
  337. }
  338. if (unmanagedClientPtr != IntPtr.Zero)
  339. {
  340. ANTFSClient_Cancel(unmanagedClientPtr); // Cancel any pending operations
  341. ANTFSClient_Close(unmanagedClientPtr); // Close object (incl. unmanaged thread)
  342. ANTFSClient_Delete(unmanagedClientPtr); // Delete unmanaged object
  343. unmanagedClientPtr = IntPtr.Zero;
  344. }
  345. // If upload buffer is still pinned, unpin it
  346. releaseDownloadBuffer();
  347. bInitialized = false;
  348. }
  349. }
  350. /// <summary>
  351. /// Unpin and release buffer holding unmanaged data
  352. /// </summary>
  353. private void releaseDownloadBuffer()
  354. {
  355. if (ghDownloadData != null)
  356. {
  357. ghDownloadData.Value.Free();
  358. ghDownloadData = null;
  359. }
  360. }
  361. #endregion
  362. #region ANT-FS Client Methods
  363. /// <summary>
  364. /// Cancels any pending actions and returns the library
  365. /// to the appropriate ANTFS layer
  366. /// </summary>
  367. public void Cancel()
  368. {
  369. if (!bInitialized)
  370. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  371. ANTFSClient_Cancel(unmanagedClientPtr);
  372. }
  373. void channel_DeviceNotification(ANT_Device.DeviceNotificationCode notification, object notificationInfo)
  374. {
  375. ANTFSClient_ProcessDeviceNotification(unmanagedClientPtr, (byte)notification, IntPtr.Zero);
  376. //TODO: Once an object is defined for specific notification types, need to marshal it - pin it and pass it...
  377. }
  378. /// <summary>
  379. /// Gets the version string of the underlying ANT-FS library
  380. /// </summary>
  381. /// <returns>ANT-FS Library Version String</returns>
  382. public static string GetLibraryVersion()
  383. {
  384. byte[] returnVersion = new byte[Byte.MaxValue]; // maximum size
  385. if (ANTFSClient_GetVersion(returnVersion, (byte)returnVersion.Length) == 0)
  386. return ""; // blank string
  387. else
  388. return (Common.ConvertToString(returnVersion));
  389. }
  390. /// <summary>
  391. /// Returns the current library status
  392. /// </summary>
  393. /// <returns>Current library status</returns>
  394. public State GetStatus()
  395. {
  396. if (!bInitialized)
  397. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  398. return (State) ANTFSClient_GetStatus(unmanagedClientPtr);
  399. }
  400. /// <summary>
  401. /// Gets the host's friendly name string from the most recent session
  402. /// </summary>
  403. /// <returns>Host friendly name</returns>
  404. public string GetHostName()
  405. {
  406. if (!bInitialized)
  407. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  408. byte[] aucFriendlyName = new byte[Byte.MaxValue];
  409. byte ucSize = (byte)aucFriendlyName.Length;
  410. if (ANTFSClient_GetHostName(unmanagedClientPtr, aucFriendlyName, ref ucSize) == 0)
  411. return ""; // blank name
  412. if (ucSize != 0)
  413. return Common.ConvertToString(aucFriendlyName);
  414. else
  415. return ""; // blank name
  416. }
  417. /// <summary>
  418. /// Gets the transfer data from the pucTransferBufferDynamic.
  419. /// </summary>
  420. /// <returns>Data that will be uploaded in the specified file</returns>
  421. /// <param name="offset">Offset where to write on the client file</param>
  422. /// <param name="size">Size of the file that will be uploaded</param>
  423. public byte[] GetTransferData(out ulong offset, out ulong size)
  424. {
  425. if (!bInitialized)
  426. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  427. byte[] aucUploadData = new byte[0xFFFFFF];
  428. ulong ulSize = 0;
  429. ulong ulOffset = 0;
  430. if (ANTFSClient_GetTransferData(unmanagedClientPtr, ref ulOffset, ref ulSize, aucUploadData) == 0)
  431. throw new ANTFS_Exception("No upload data");
  432. size = ulSize;
  433. offset = ulOffset;
  434. return aucUploadData;
  435. }
  436. /// <summary>
  437. /// Gets the full parameters for a download, upload or erase request
  438. /// from the host
  439. /// </summary>
  440. /// <returns>Request parameters</returns>
  441. public ANTFS_RequestParameters GetRequestParameters()
  442. {
  443. if (!bInitialized)
  444. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  445. ANTFS_RequestParameters returnRequest = new ANTFS_RequestParameters();
  446. if (ANTFSClient_GetRequestParameters(unmanagedClientPtr, ref returnRequest) == 0)
  447. throw new ANTFS_Exception("No request parameters are available, probably in wrong state");
  448. return returnRequest;
  449. }
  450. /// <summary>
  451. /// Gets the file index for a download, upload or erase request from
  452. /// the host. If more details are desired, use GetRequestParameters().
  453. /// </summary>
  454. /// <returns>Requested file index</returns>
  455. public ushort GetRequestedFileIndex()
  456. {
  457. if (!bInitialized)
  458. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  459. ushort index = 0;
  460. if (ANTFSClient_GetRequestedFileIndex(unmanagedClientPtr, ref index) == 0)
  461. throw new ANTFS_Exception("No request available, probably in wrong state");
  462. return index;
  463. }
  464. /// <summary>
  465. /// Gets the transfer progress of a pending or complete download
  466. /// </summary>
  467. /// <returns>The transfer status, including the current byte progress,
  468. /// total expected length of the download, and current percentage.
  469. /// Returns null if no valid status could be obtained.</returns>
  470. public int GetDownloadStatus()
  471. {
  472. if (!bInitialized)
  473. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  474. uint totalSize = 10;
  475. uint byteProgress = 0;
  476. if (ANTFSClient_GetDownloadStatus(unmanagedClientPtr, ref byteProgress, ref totalSize) == 0)
  477. throw new ANTFS_Exception("No download in progress");
  478. return (int) (byteProgress * 100 / totalSize); // return as percentage
  479. }
  480. /// <summary>
  481. /// Gets the parameters of a disconnect command requested by the host
  482. /// </summary>
  483. /// <returns>Disconnect parameters</returns>
  484. public ANTFS_DisconnectParameters GetDisconnectParameters()
  485. {
  486. if (!bInitialized)
  487. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  488. ANTFS_DisconnectParameters returnRequest = new ANTFS_DisconnectParameters();
  489. if (ANTFSClient_GetDisconnectParameters(unmanagedClientPtr, ref returnRequest) == 0)
  490. throw new ANTFS_Exception("No disconnect parameters are available, probably in wrong state");
  491. return returnRequest;
  492. }
  493. /// <summary>
  494. /// Configures the friendly name for the ANT-FS client
  495. /// </summary>
  496. /// <param name="friendlyName">Client friendly name</param>
  497. public void SetFriendlyName(string friendlyName)
  498. {
  499. if (!bInitialized)
  500. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  501. if (friendlyName == null)
  502. {
  503. ANTFSClient_SetFriendlyName(unmanagedClientPtr, null, 0);
  504. }
  505. else
  506. {
  507. if (friendlyName.Length > Byte.MaxValue)
  508. throw new ANTFS_Exception("Invalid friendly name length, maximum value is 255");
  509. byte[] charArray = Common.ConvertToByteArray(friendlyName);
  510. ANTFSClient_SetFriendlyName(unmanagedClientPtr, charArray, (byte)friendlyName.Length);
  511. }
  512. }
  513. /// <summary>
  514. /// Configures the passkey for a client to establish authenticated
  515. /// sessions with a host device, if passkey authentication is
  516. /// selected. If a passkey is not configured, all passkey authentication
  517. /// requests will be rejected.
  518. /// </summary>
  519. /// <param name="passKey">Authentication passkey (max 255 bytes)</param>
  520. public void SetPassKey(byte[] passKey)
  521. {
  522. if (!bInitialized)
  523. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  524. if (passKey == null)
  525. {
  526. ANTFSClient_SetPassKey(unmanagedClientPtr, null, 0);
  527. }
  528. else
  529. {
  530. if (passKey.Length > Byte.MaxValue)
  531. throw new ANTFS_Exception("Invalid pass key length, maximum value is 255");
  532. ANTFSClient_SetPassKey(unmanagedClientPtr, passKey, (byte)passKey.Length);
  533. }
  534. }
  535. /// <summary>
  536. /// Set the channel ID of the ANT-FS client
  537. /// If this function is not used to explicitly configure the channel ID, the ANT-FS host will use the following defaults:
  538. /// Device type: 1
  539. /// Transmission type: 5
  540. /// </summary>
  541. /// <param name="deviceType">Device type to assign to channel (ANT Channel ID)</param>
  542. /// <param name="transmissionType">Transmission type to assign to channel (ANT Channel ID)</param>
  543. public void SetChannelID(byte deviceType, byte transmissionType)
  544. {
  545. if (!bInitialized)
  546. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  547. if(deviceType == 0)
  548. throw new ANTFS_Exception("Device type cannot be wild carded on the client device!");
  549. if (transmissionType == 0)
  550. throw new ANTFS_Exception("Transmission type cannot be wild carded on the client device!");
  551. ANTFSClient_SetChannelID(unmanagedClientPtr, deviceType, transmissionType);
  552. }
  553. /// <summary>
  554. /// Sets a custom channel period for the ANT-FS beacon
  555. /// </summary>
  556. /// <param name="channelPeriod">Channel period, in 1/32768 counts</param>
  557. public void SetChannelPeriod(ushort channelPeriod)
  558. {
  559. if (!bInitialized)
  560. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  561. ANTFSClient_SetChannelPeriod(unmanagedClientPtr, channelPeriod);
  562. }
  563. /// <summary>
  564. /// Set the network key for the ANT-FS client
  565. /// If this function is not used to explicitly configure the network key, the ANT-FS client will use the
  566. /// ANT-FS network key, as set in the base ANT Library, and network number 0.
  567. /// Configuration is applied when the beacon is open
  568. /// </summary>
  569. /// <param name="netNumber">network number</param>
  570. /// <param name="networkKey">8-byte network key</param>
  571. public void SetClientNetworkKey(byte netNumber, byte[] networkKey)
  572. {
  573. if (!bInitialized)
  574. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  575. if (networkKey.Length != 8)
  576. throw new ANTFS_Exception("Network key must be 8 bytes");
  577. networkNumber = netNumber;
  578. ANTFSClient_SetNetworkKey(unmanagedClientPtr, netNumber, networkKey);
  579. }
  580. /// <summary>
  581. /// Configures the transmit power for the ANT-FS channel, in case
  582. /// different power levels are desired in the link and connected states,
  583. /// for example, to allow the use of proximity search in a host device.
  584. /// If not configured, the transmit power will be set to 0dBm.
  585. /// </summary>
  586. /// <param name="pairingLevel">Transmit power to use while in Link state</param>
  587. /// <param name="connectedLevel">Transmit power to use after a connection has been established to a host</param>
  588. public void SetTransmitPower(ANT_ReferenceLibrary.TransmitPower pairingLevel, ANT_ReferenceLibrary.TransmitPower connectedLevel)
  589. {
  590. if (!bInitialized)
  591. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  592. ANTFSClient_SetTxPower(unmanagedClientPtr, (byte) pairingLevel, (byte) connectedLevel);
  593. }
  594. /// <summary>
  595. /// Enable pairing authentication
  596. /// </summary>
  597. /// <param name="enable">Selects whether pairing authentication is enabled or not in the device</param>
  598. public void SetPairingEnabled(bool enable)
  599. {
  600. if (!bInitialized)
  601. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  602. ReturnCode theReturn = (ReturnCode)ANTFSClient_SetPairingEnabled(unmanagedClientPtr, enable);
  603. if (theReturn != ReturnCode.Pass)
  604. throw new ANTFS_RequestFailed_Exception("SetPairingEnabled", theReturn);
  605. }
  606. /// <summary>
  607. /// Enable uploads
  608. /// </summary>
  609. /// <param name="enable">Selects whether upload functionality is supported</param>
  610. public void SetUploadEnabled(bool enable)
  611. {
  612. if (!bInitialized)
  613. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  614. ReturnCode theReturn = (ReturnCode)ANTFSClient_SetUploadEnabled(unmanagedClientPtr, enable);
  615. if (theReturn != ReturnCode.Pass)
  616. throw new ANTFS_RequestFailed_Exception("SetUploadEnabled", theReturn);
  617. }
  618. /// <summary>
  619. /// Indicate if data is available for download
  620. /// </summary>
  621. /// <param name="dataIsAvailable">Selects whether data is available for download</param>
  622. public void SetDataAvailable(bool dataIsAvailable)
  623. {
  624. if (!bInitialized)
  625. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  626. ReturnCode theReturn = (ReturnCode)ANTFSClient_SetDataAvailable(unmanagedClientPtr, dataIsAvailable);
  627. if (theReturn != ReturnCode.Pass)
  628. throw new ANTFS_RequestFailed_Exception("SetDataAvailable", theReturn);
  629. }
  630. /// <summary>
  631. /// Configures the beacon timeout
  632. /// </summary>
  633. /// <param name="timeoutSeconds">Timeout, in seconds</param>
  634. public void SetBeaconTimeout(byte timeoutSeconds)
  635. {
  636. if (!bInitialized)
  637. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  638. if (timeoutSeconds == 0)
  639. throw new ANTFS_Exception("Invalid beacon timeout");
  640. ANTFSClient_SetBeaconTimeout(unmanagedClientPtr, timeoutSeconds);
  641. }
  642. /// <summary>
  643. /// Configures the pairing timeout
  644. /// </summary>
  645. /// <param name="timeoutSeconds">Timeout, in seconds</param>
  646. public void SetPairingTimeout(byte timeoutSeconds)
  647. {
  648. if (!bInitialized)
  649. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  650. if (timeoutSeconds == 0)
  651. throw new ANTFS_Exception("Invalid pairing timeout");
  652. ANTFSClient_SetPairingTimeout(unmanagedClientPtr, timeoutSeconds);
  653. }
  654. /// <summary>
  655. /// Sets up the ANT-FS client configuration parameters. This function can only be used
  656. /// while the beacon is not open. Individual parameters can be configured while the beacon is open
  657. /// If this function is not called, default beacon parameters are used.
  658. /// </summary>
  659. /// <see>SetPairingEnabled</see>
  660. /// <see>SetUploadEnabled</see>
  661. /// <see>SetDataAvailable</see>
  662. /// <see>SetBeaconTimeout</see>
  663. /// <see>SetPairingTimeout</see>
  664. /// <param name="clientParameters">ANT-FS Client parameters</param>
  665. public void Configure(ANTFS_ClientParameters clientParameters)
  666. {
  667. if (!bInitialized)
  668. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  669. ReturnCode theReturn = (ReturnCode) ANTFSClient_ConfigureClientParameters(unmanagedClientPtr, ref clientParameters);
  670. if (theReturn != ReturnCode.Pass)
  671. throw new ANTFS_RequestFailed_Exception("Configure", theReturn);
  672. }
  673. /// <summary>
  674. /// Begins the channel configuration to transmit the ANT-FS beacon.
  675. /// If the channel has already been configured (ANT-FS broadcast), the
  676. /// channel period needs to be specified in this function to let the
  677. /// client know the current period. If a channel period is not specified (0),
  678. /// the channel configuration is performed as specified in the beacon parameters.
  679. /// </summary>
  680. public void OpenBeacon()
  681. {
  682. if (!bInitialized)
  683. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  684. ReturnCode theReturn = (ReturnCode) ANTFSClient_OpenBeacon(unmanagedClientPtr);
  685. if (theReturn != ReturnCode.Pass)
  686. throw new ANTFS_RequestFailed_Exception("OpenBeacon", theReturn);
  687. }
  688. /// <summary>
  689. /// Ends the ANT-FS session.
  690. /// </summary>
  691. /// <param name="returnToBroadcast">Set to true to return to broadcast (leave the channel open), and to false to close the channel.</param>
  692. public void CloseBeacon(bool returnToBroadcast)
  693. {
  694. if (!bInitialized)
  695. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  696. ReturnCode theReturn = (ReturnCode)ANTFSClient_CloseBeacon(unmanagedClientPtr, returnToBroadcast);
  697. if (theReturn != ReturnCode.Pass)
  698. throw new ANTFS_RequestFailed_Exception("CloseBeacon", theReturn);
  699. }
  700. /// <summary>
  701. /// Ends the ANT-FS session and closes the channel.
  702. /// </summary>
  703. public void CloseBeacon()
  704. {
  705. CloseBeacon(false);
  706. }
  707. /// <summary>
  708. /// Sends a response to a pairing request.
  709. /// </summary>
  710. /// <param name="acceptRequest">Select whether to accept or reject the request</param>
  711. public void SendPairingResponse(bool acceptRequest)
  712. {
  713. if (!bInitialized)
  714. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  715. ReturnCode theReturn = (ReturnCode)ANTFSClient_SendPairingResponse(unmanagedClientPtr, acceptRequest);
  716. if (theReturn != ReturnCode.Pass)
  717. throw new ANTFS_RequestFailed_Exception("SendPairingResponse", theReturn);
  718. }
  719. /// <summary>
  720. /// Sends a response to a request to erase a file from an
  721. /// authenticated remote device
  722. /// </summary>
  723. /// <param name="response">The response to the erase request</param>
  724. public void SendEraseResponse(EraseResponse response)
  725. {
  726. if (!bInitialized)
  727. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  728. ReturnCode theReturn = (ReturnCode)ANTFSClient_SendEraseResponse(unmanagedClientPtr, (byte)response);
  729. if (theReturn != ReturnCode.Pass)
  730. throw new ANTFS_RequestFailed_Exception("SendEraseRequest", theReturn);
  731. }
  732. /// <summary>
  733. /// Sends a response to a request to download a file to a host device
  734. /// </summary>
  735. /// <param name="response">The response to the download request</param>
  736. /// <param name="fileIndex">The file index to download</param>
  737. /// <param name="blockSize">The maximum number of bytes to send in a single block</param>
  738. /// <param name="downloadData">File to download. The entire file most be provided, even if the host requested an offset.</param>
  739. public void SendDownloadResponse(DownloadResponse response, ushort fileIndex, uint blockSize, byte[] downloadData)
  740. {
  741. if (!bInitialized)
  742. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  743. IntPtr pvData = IntPtr.Zero;
  744. uint dataLength = 0;
  745. ANTFS_DownloadParameters responseParameters;
  746. releaseDownloadBuffer(); // If we had not freed the handle from a previous download, do it now
  747. responseParameters.FileIndex = fileIndex;
  748. responseParameters.MaxBlockSize = blockSize;
  749. if (response == DownloadResponse.Ok)
  750. {
  751. if (downloadData == null)
  752. throw new ANT_Exception("Download request accepted, but no data provided");
  753. ghDownloadData = GCHandle.Alloc(downloadData, GCHandleType.Pinned); // Pin managed buffer
  754. pvData = ghDownloadData.Value.AddrOfPinnedObject(); // Get address of managed buffer
  755. if (pvData == IntPtr.Zero)
  756. throw new ANTFS_Exception("Download request failed: Unable to pin managed buffer for download");
  757. dataLength = (uint) downloadData.Length;
  758. if(blockSize == 0 || dataLength < blockSize)
  759. responseParameters.MaxBlockSize = dataLength;
  760. }
  761. ReturnCode theReturn = (ReturnCode)ANTFSClient_SendDownloadResponse(unmanagedClientPtr, (byte)response, ref responseParameters, dataLength, pvData);
  762. if (theReturn == ReturnCode.Pass)
  763. {
  764. usCurrentTransfer = responseParameters.FileIndex; // Track current transfer
  765. }
  766. else
  767. {
  768. // If the request was not successful, we should free the handle here
  769. // Otherwise, buffer needs to remain pinned while download completes (pass/fail/etc...)
  770. // GCHandle will be freed when we receive an ANT-FS response, or the application is terminated
  771. releaseDownloadBuffer();
  772. throw new ANTFS_RequestFailed_Exception("SendDownloadResponse", theReturn);
  773. }
  774. }
  775. /// <summary>
  776. /// Sends a response to a request to download a file to a host device.
  777. /// Will attempt to send the entire download in a single block.
  778. /// </summary>
  779. /// <param name="response">The response to the download request</param>
  780. /// <param name="fileIndex">The file index to download</param>
  781. /// <param name="downloadData">File to download. The entire file most be provided, even if the host requested an offset.</param>
  782. public void SendDownloadResponse(DownloadResponse response, ushort fileIndex, byte[] downloadData)
  783. {
  784. if (!bInitialized)
  785. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  786. SendDownloadResponse(response, fileIndex, 0, downloadData);
  787. }
  788. /// <summary>
  789. /// Sends a response to a request to upload a file from a host device
  790. /// </summary>
  791. /// <param name="response">The response to the upload request</param>
  792. /// <param name="fileIndex">The file index to upload</param>
  793. /// <param name="blockSize">The maximum number of bytes to send in a single block</param>
  794. /// <param name="maxFileSize">The maximum file size.</param>
  795. public void SendUploadResponse(UploadResponse response, ushort fileIndex, uint blockSize, uint maxFileSize)
  796. {
  797. if (!bInitialized)
  798. throw new ObjectDisposedException("ANTFSClient object has been disposed");
  799. //IntPtr pvData = IntPtr.Zero;
  800. //uint dataLength = 0;
  801. ANTFS_UploadParameters responseParameters;
  802. //releaseDownloadBuffer(); // If we had not freed the handle from a previous download, do it now
  803. responseParameters.FileIndex = fileIndex;
  804. responseParameters.MaxBlockSize = blockSize;
  805. responseParameters.MaxFileSize = maxFileSize;
  806. if (response == UploadResponse.Ok)
  807. {
  808. //if (downloadData == null)
  809. // throw new ANT_Exception("Download request accepted, but no data provided");
  810. //ghDownloadData = GCHandle.Alloc(downloadData, GCHandleType.Pinned); // Pin managed buffer
  811. //pvData = ghDownloadData.Value.AddrOfPinnedObject(); // Get address of managed buffer
  812. //if (pvData == IntPtr.Zero)
  813. // throw new ANTFS_Exception("Download request failed: Unable to pin managed buffer for download");
  814. //dataLength = (uint)downloadData.Length;
  815. if (blockSize == 0 || maxFileSize < blockSize)
  816. responseParameters.MaxBlockSize = maxFileSize;
  817. }
  818. ReturnCode theReturn = (ReturnCode)ANTFSClient_SendUploadResponse(unmanagedClientPtr, (byte)response, ref responseParameters, 0, IntPtr.Zero);
  819. if (theReturn == ReturnCode.Pass)
  820. {
  821. usCurrentTransfer = responseParameters.FileIndex; // Track current transfer
  822. }
  823. else
  824. {
  825. // If the request was not successful, we should free the handle here
  826. // Otherwise, buffer needs to remain pinned while download completes (pass/fail/etc...)
  827. // GCHandle will be freed when we receive an ANT-FS response, or the application is terminated
  828. //releaseDownloadBuffer();
  829. throw new ANTFS_RequestFailed_Exception("SendUploadResponse", theReturn);
  830. }
  831. }
  832. #endregion
  833. #region Private Methods
  834. /// <summary>
  835. /// Processing of incoming ANT-FS responses
  836. /// </summary>
  837. private void ResponseThreadHandler()
  838. {
  839. bResponseThreadExit = false;
  840. Response eThreadResponse = Response.None;
  841. while (!bResponseThreadExit)
  842. {
  843. eThreadResponse = (Response)ANTFSClient_WaitForResponse(unmanagedClientPtr, 999);
  844. if (eThreadResponse != Response.None) // We got a response
  845. {
  846. // If we were processing a download, release handle
  847. releaseDownloadBuffer();
  848. // Dispatch response if we got one
  849. if (OnResponse != null)
  850. {
  851. OnResponse(eThreadResponse);
  852. }
  853. }
  854. }
  855. }
  856. #endregion
  857. }
  858. }