ANT_IntegratedANTFSClient.cs 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068
  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.Collections.Generic;
  10. using System.Linq;
  11. using System.Text;
  12. namespace ANT_Managed_Library.ANTFS
  13. {
  14. /// <summary>
  15. /// Control class for a given ANT device, with Integrated ANT-FS Client functionality.
  16. /// An instance of this class is an open connection to the given ANT USB device.
  17. /// Handles creating channels and device setup, and allows managing the file system (EEPROM)
  18. /// as well as configuring and controlling ANT-FS sessions.
  19. /// </summary>
  20. public class ANT_IntegratedANTFSClient : ANT_Device
  21. {
  22. /// <summary>
  23. /// Queue with the responses received from ANT related to Integrated ANT-FS
  24. /// </summary>
  25. public Queue<ANT_Response> responseBuf = new Queue<ANT_Response>();
  26. /// <summary>
  27. /// Last received ANT Response
  28. /// </summary>
  29. public ANT_Response lastAcceptedResponse;
  30. /// <summary>
  31. /// Device events
  32. /// </summary>
  33. public byte[] hostdeviceEvents;
  34. /// <summary>
  35. /// Flag indicating availabity of device events
  36. /// </summary>
  37. public bool flagHostDeviceEvents;
  38. /// <summary>
  39. /// Default timeout for responses
  40. /// </summary>
  41. const int defaultWait = 3000;
  42. #region Setup
  43. /// <summary>
  44. /// Creates an Integrated ANT-FS Client object, by automatically trying to connect to the USB stick
  45. /// </summary>
  46. public ANT_IntegratedANTFSClient() : base() // 57600 is tried first
  47. {
  48. ANT_Common.enableDebugLogs();
  49. if (!this.getDeviceCapabilities().FS)
  50. {
  51. this.Dispose();
  52. throw new ANT_Exception("Found ANT USB device, but does not support FS"); //TODO This is not a very effective auto init, for example: What happens if FS device is second device and first device isn't? Should we connect to other devices to check?
  53. }
  54. deviceResponse += dev_deviceResponse;
  55. deviceResponse += dev_hostdeviceEvents;
  56. }
  57. /// <summary>
  58. /// Creates an Integrated ANT-FS Client object, specifying the USB device number. Baud rate is assumed to be 57600bps.
  59. /// </summary>
  60. /// <param name="USBDeviceNum">USB device number</param>
  61. public ANT_IntegratedANTFSClient(byte USBDeviceNum) : base (USBDeviceNum, 57600) // For FS-enabled parts, Baud rate is 57600
  62. {
  63. ANT_Common.enableDebugLogs();
  64. responseBuf = new Queue<ANT_Response>();
  65. if (!this.getDeviceCapabilities().FS)
  66. {
  67. this.Dispose();
  68. throw new ANT_Exception("Found ANT USB device, but does not support FS");
  69. }
  70. }
  71. /// <summary>
  72. /// Close connection to the ANT USB device
  73. /// </summary>
  74. public void shutdown()
  75. {
  76. this.Dispose();
  77. }
  78. //TODO: This buffer gets really big if we sit around for very long
  79. void dev_deviceResponse(ANT_Response response)
  80. {
  81. responseBuf.Enqueue(response);
  82. }
  83. void dev_hostdeviceEvents(ANT_Response response)
  84. {
  85. hostdeviceEvents = response.messageContents;
  86. flagHostDeviceEvents = true;
  87. }
  88. #endregion
  89. #region ANT Comm Helper Functions
  90. internal static byte getByte_usLE(int byteNum, ushort value)
  91. {
  92. if (byteNum == 1) //Return low byte
  93. return (byte)(value & 0x00FF);
  94. else if (byteNum == 2) //Return high byte
  95. return (byte)((value & 0xFF00) >> 8);
  96. else
  97. throw new Exception("Bad byte number");
  98. }
  99. internal static byte getByte_ulLE(int byteNum, ulong value)
  100. {
  101. if (byteNum == 1) //Return low byte
  102. return (byte)(value & 0x000000FF);
  103. else if (byteNum == 2) //Return mid-low byte
  104. return (byte)((value & 0x0000FF00) >> 8);
  105. else if (byteNum == 3) //Return mid-high byte
  106. return (byte)((value & 0x00FF0000) >> 16);
  107. else if (byteNum == 4) //Return high byte
  108. return (byte)((value & 0xFF000000) >> 24);
  109. else
  110. throw new Exception("Bad byte number");
  111. }
  112. private byte[] waitForMsg(byte[] leadingBytes)
  113. {
  114. return waitForMsg(leadingBytes, defaultWait);
  115. }
  116. private byte[] waitForMsg(byte[] leadingBytes, int wait_ms)
  117. {
  118. Queue<ANT_Response> msgSave = new Queue<ANT_Response>();
  119. int i = 0;
  120. ANT_Response curResponse;
  121. System.Diagnostics.Stopwatch waitTimer = new System.Diagnostics.Stopwatch();
  122. waitTimer.Start();
  123. do
  124. {
  125. while (responseBuf.Count > 0)
  126. {
  127. curResponse = responseBuf.Dequeue();
  128. msgSave.Enqueue(curResponse);
  129. //If the leading bytes match our expected response
  130. if (curResponse.responseID.Equals(leadingBytes[0]))
  131. {
  132. //Check message id matches
  133. for (i = 1; i < leadingBytes.Length; ++i)
  134. {
  135. //Check remaining bytes to check
  136. if (!curResponse.messageContents[i - 1].Equals(leadingBytes[i]))
  137. break;
  138. }
  139. //If all bytes matched return the remaining bytes of the message
  140. if (i == leadingBytes.Length)
  141. {
  142. //Save the seen messages back to the response buffer
  143. responseBuf = new Queue<ANT_Response>(msgSave.Concat(responseBuf));
  144. //Send out the information
  145. lastAcceptedResponse = curResponse;
  146. i -= 1; //Start at the byte we were at
  147. return curResponse.messageContents.Skip(i).ToArray();
  148. }
  149. }
  150. }
  151. } while (waitTimer.ElapsedMilliseconds < wait_ms);
  152. //If we didn't find a matching response
  153. responseBuf = new Queue<ANT_Response>(msgSave.Concat(responseBuf));
  154. lastAcceptedResponse = null;
  155. throw new Exception("Expected Message Timeout");
  156. }
  157. /// <summary>
  158. /// Get last ANT response
  159. /// </summary>
  160. /// <returns>Message code of the last response</returns>
  161. public byte[] getLastAcceptedResponse()
  162. {
  163. return new byte[] { lastAcceptedResponse.responseID }.Concat(lastAcceptedResponse.messageContents).ToArray();
  164. }
  165. #endregion
  166. #region Functions Used by Scripting
  167. /// <summary>
  168. /// Send a raw ANT message
  169. /// </summary>
  170. /// <param name="msgToWrite">byte array, with the raw ANT message to send</param>
  171. /// <returns>True if the message was written successfully</returns>
  172. public bool writeRawMessageToDevice(byte[] msgToWrite)
  173. {
  174. return writeRawMessageToDevice(msgToWrite[0], msgToWrite.Skip(1).ToArray());
  175. }
  176. /// <summary>
  177. /// Wait for a message matching the desired pattern
  178. /// </summary>
  179. /// <param name="matchPattern">Pattern to match</param>
  180. /// <param name="wait_ms">time to wait, in ms</param>
  181. /// <returns>True if the matching message is seen in the configured timeout</returns>
  182. public bool WaitForNextMatchMsg(int[] matchPattern, int wait_ms)
  183. {
  184. Queue<ANT_Response> msgSave = new Queue<ANT_Response>();
  185. ANT_Response curResponse;
  186. int i;
  187. responseBuf.Clear();
  188. System.Diagnostics.Stopwatch waitTimer = new System.Diagnostics.Stopwatch();
  189. waitTimer.Start();
  190. do
  191. {
  192. while (responseBuf.Count > 0)
  193. {
  194. System.Threading.Thread.Sleep(10); //Allow time for a new message to arrive
  195. curResponse = responseBuf.Dequeue();
  196. msgSave.Enqueue(curResponse);
  197. //Check each byte with the conditional match function against the given conditional byte match array
  198. if (compareConditionalByte(curResponse.responseID, matchPattern[0]) && curResponse.messageContents.Length == (matchPattern.Length - 1))
  199. {
  200. //Check message id matches
  201. for (i = 1; i < matchPattern.Length; ++i)
  202. {
  203. //Check remaining bytes to check
  204. if (!compareConditionalByte(curResponse.messageContents[i - 1], matchPattern[i]))
  205. break;
  206. }
  207. //If all bytes matched then we succeeded
  208. if (i == matchPattern.Length)
  209. {
  210. //Save all the seen messages back to the buffer
  211. responseBuf = new Queue<ANT_Response>(msgSave.Concat(responseBuf));
  212. lastAcceptedResponse = curResponse;
  213. return true;
  214. }
  215. }
  216. }
  217. } while (waitTimer.ElapsedMilliseconds < wait_ms);
  218. //If we didn't find a match
  219. responseBuf = new Queue<ANT_Response>(msgSave.Concat(responseBuf));
  220. lastAcceptedResponse = null;
  221. return false;
  222. }
  223. /// <summary>
  224. /// Compare a byte with a reference value
  225. /// </summary>
  226. /// <param name="b">Byte to check (unsigned)</param>
  227. /// <param name="condByte">Reference signed value</param>
  228. /// <returns>Comparison result</returns>
  229. public static bool compareConditionalByte(byte b, int condByte)
  230. {
  231. //WARN This function does not check the int value to ensure it is in the range of the byte
  232. if (condByte >= 0) //If it is not a special case
  233. return b == (byte)condByte;
  234. if (condByte == int.MinValue) //this means match anything
  235. return true;
  236. //Otherwise the request is to match only set bytes
  237. condByte = -condByte; //Convert back to original positive value
  238. return condByte == (b & condByte);
  239. }
  240. #endregion
  241. #region Request Function
  242. /// <summary>
  243. /// Get the status of the ANT-FS session
  244. /// </summary>
  245. /// <returns></returns>
  246. public byte[] FS_GetState()
  247. {
  248. responseBuf.Clear();
  249. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x30 });
  250. }
  251. #endregion
  252. #region Serial Commands
  253. #region MEMDev Commands
  254. /// <summary>
  255. /// MEMDEV initialization commands MUST be called after reset to set MEMDEV configuration prior to using FS Commands or requests.
  256. /// Init command must be called prior to issuing any FS command or requests.
  257. /// Currently, only SPI interface (min 2MHz rate) is supported with EEPROM devices.
  258. /// Configuration fields should be specified from information found from the EEPROM datasheet.
  259. /// Successful initialization results in FS_NO_ERROR response code.
  260. /// </summary>
  261. /// <param name="pageWriteSize"> Page Write Size is the physical page write boundary of the EEPROM Device.
  262. /// For EEPROM, this is considered the maximum number of bytes that can be written in one pass and it must be 2^x value. </param>
  263. /// <param name="AddrBytesCfg">The address bytes configuration field specifies the required number of bytes used to address the physical memory location
  264. /// on the EEPROM.
  265. /// For example, a 1MBit EEPROM device requires 3 address bytes. </param>
  266. /// <returns></returns>
  267. public byte MemDev_EEPROMInit(ushort pageWriteSize, byte AddrBytesCfg)
  268. {
  269. responseBuf.Clear();
  270. writeRawMessageToDevice(0xE2, new byte[] { 0x20, getByte_usLE(1, pageWriteSize), getByte_usLE(2, pageWriteSize), AddrBytesCfg });
  271. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x20 })[0];
  272. }
  273. #endregion MEMDev Commands
  274. #region FS Commands
  275. /// <summary>
  276. /// Initializes existing file system from saved directory information in NVM.
  277. /// Unsaved information on open files will be lost.
  278. /// Init command must be called prior to using any FS related commands or requests.
  279. /// Init command must also be called after issuing FS Format Memory.
  280. /// Also resets encryption key used for crypto operations.
  281. /// Successful initialization results in FS_NO_ERROR response code.
  282. /// </summary>
  283. /// <returns></returns>
  284. public byte InitMemory()
  285. {
  286. responseBuf.Clear();
  287. writeRawMessageToDevice(0xE2, new byte[] { 0x00 });
  288. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x00 })[0];
  289. }
  290. /// <summary>
  291. /// Command used to create a new empty file system.
  292. /// Any existing directory information and files will be discarded.
  293. /// Minimum number of sectors must be 2 (1 for directory and 1 for each file).
  294. /// Successful format operation results in FS_NO_ERROR response code.
  295. /// Number of Sectors * Num Pages per sector * Page Size must not exceed the size of the memory device.
  296. /// If inappropriate values are entered, format may succeed, but FS will be unusable.
  297. /// </summary>
  298. /// <param name="numSec"> Number of Sectors </param>
  299. /// <param name="pagesPerSector"> Num Pages per Sector. Defines sector size(X * page Size)
  300. /// Page Size is defined in MEMDEV_EEPROM_INIT for EEPROM Device</param>
  301. /// <returns></returns>
  302. public byte Format_Memory(ushort numSec, ushort pagesPerSector)
  303. {
  304. responseBuf.Clear();
  305. writeRawMessageToDevice(0xE2, new byte[] { 0x01, getByte_usLE(1, numSec), getByte_usLE(2, numSec), getByte_usLE(1, pagesPerSector), getByte_usLE(2, pagesPerSector) });
  306. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x01 })[0];
  307. }
  308. /// <summary>
  309. /// Save all open file information into the directory NVM.
  310. /// This should be called before device power off or any unsaved data will be lost.
  311. /// Successful save operation results in FS_NO_ERROR response code.
  312. /// </summary>
  313. /// <returns></returns>
  314. public byte DirectorySave()
  315. {
  316. responseBuf.Clear();
  317. writeRawMessageToDevice(0xE2, new byte[] { 0x07 });
  318. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x07 })[0];
  319. }
  320. /// <summary>
  321. /// Rebuilds FS directory and condenses directory size by removing invalidated entries.
  322. /// Rebuilding directory also updates auto file index counter.
  323. /// Successful rebuild results in FS_NO_ERROR response code.
  324. /// </summary>
  325. /// <returns></returns>
  326. public byte DirectoryRebuild()
  327. {
  328. responseBuf.Clear();
  329. writeRawMessageToDevice(0xE2, new byte[] { 0x09 });
  330. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x09 })[0];
  331. }
  332. /// <summary>
  333. /// Delete existing open file. Delete permission must be set on file handle. On successful deletion (FS_NO_ERROR response code), the file handle is freed.
  334. /// If FS_MEMORY_WRITE_ERROR is returned, memory occupied by file is lost but the handle is freed.
  335. /// Any other response codes results in file deletion failure and the file handle remains associated to the open file.
  336. /// </summary>
  337. /// <param name="handleNum"> File Handle Number</param>
  338. /// <returns></returns>
  339. public byte FileDelete(byte handleNum)
  340. {
  341. responseBuf.Clear();
  342. writeRawMessageToDevice(0xE2, new byte[] { 0x0C, handleNum });
  343. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x0C })[0];
  344. }
  345. /// <summary>
  346. /// Close open flag or file. Any open file handle information is saved to the directory.
  347. /// FS_NO_ERROR response code is returned if file close operation is successful.
  348. /// Any other response code resulted in file close failure and the file handle still assigned to the file.
  349. /// </summary>
  350. /// <param name="handleNum">File Handle Number</param>
  351. /// <returns></returns>
  352. public byte FileClose(byte handleNum)
  353. {
  354. responseBuf.Clear();
  355. writeRawMessageToDevice(0xE2, new byte[] { 0x0D, handleNum });
  356. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x0D })[0];
  357. }
  358. /// <summary>
  359. /// Update application defined flags on file, but it is not saved to directory NVM.
  360. /// On success, FS_NO_ERROR is returned.
  361. /// </summary>
  362. /// <param name="handleNum">File Handle Number</param>
  363. /// <param name="newSpecificFlags">Specific Flags</param>
  364. /// <returns></returns>
  365. public byte FileSetSpecificFlags(byte handleNum, byte newSpecificFlags)
  366. {
  367. responseBuf.Clear();
  368. writeRawMessageToDevice(0xE2, new byte[] { 0x12, handleNum, newSpecificFlags });
  369. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x12 })[0];
  370. }
  371. /// <summary>
  372. /// When directory is locked, directory information is prevented from changing.
  373. /// When directory is unlocked, directory information is allowed to change.
  374. /// Attempting to lock a directory that is already locked will result in an error.
  375. /// Attempting to unlock a directory that is already unlocked will result in an error.
  376. /// </summary>
  377. /// <param name="locked">1 - Lock, 0 - Unlock</param>
  378. /// <returns>FS Response</returns>
  379. public byte DirectoryReadLock(byte locked)
  380. {
  381. responseBuf.Clear();
  382. writeRawMessageToDevice(0xE2, new byte[] { 0x16, locked });
  383. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x16 })[0];
  384. }
  385. /// <summary>
  386. /// When this message ID is used in a command message, the specified starting value of the system time to be used in FS can be set.
  387. /// If successful, FS_NO_ERROR is returned
  388. /// </summary>
  389. /// <param name="seconds">Current Time</param>
  390. /// <returns></returns>
  391. public byte SetSystemTime(uint seconds)
  392. {
  393. //convert int to USHORT so can use in the getByte_usLE()
  394. ushort LSBytes;
  395. ushort MSbytes;
  396. LSBytes = (ushort)seconds;
  397. LSBytes |= (ushort)(seconds & 0x0000FF00);
  398. MSbytes = (ushort)((seconds & 0x00FF0000) >> 16);
  399. MSbytes |= (ushort)((seconds & 0xFF000000) >> 16);
  400. responseBuf.Clear();
  401. writeRawMessageToDevice(0xE2, new byte[] { 0x3D, getByte_usLE(1, LSBytes), getByte_usLE(2, LSBytes), getByte_usLE(1, MSbytes), getByte_usLE(2, MSbytes) });
  402. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x3D })[0];
  403. }
  404. #endregion FS Commands
  405. #region FS Requests
  406. /// <summary>
  407. /// Returns the FSResponse Byte when reponse != 0x00(NO_ERROR)
  408. /// </summary>
  409. /// <param name="FSResponse">FS Response byte from Response Buffer</param>
  410. /// <returns></returns>
  411. public byte FS_GetLastError(byte FSResponse)
  412. {
  413. return FSResponse;
  414. }
  415. /// <summary>
  416. /// Returns number of used bytes in FS in sector sized increments.
  417. /// On success, returns FS_NO_ERROR response code and the used space value.
  418. /// If any other response code is returned, an invalid used space size value is returned (0xFFFFFFFF).
  419. /// </summary>
  420. /// <returns>Used Space</returns>
  421. public ulong GetUsedSpace()
  422. {
  423. responseBuf.Clear();
  424. writeRawMessageToDevice(0xE1, new byte[] { 0x00, 0xE2, 0x02 });
  425. byte[] ret = waitForMsg(new byte[] { 0xE2, 0x02 });
  426. if (ret[0] == 0x00) //No Error
  427. return (ulong)ret[1] + ((ulong)ret[2] << 8) + ((ulong)ret[3] << 16) + ((ulong)ret[4] << 24);
  428. else //There is an error
  429. return FS_GetLastError(ret[0]);
  430. }
  431. /// <summary>
  432. /// Returns number of free bytes in FS in sector sized increments.
  433. /// On success, returns FS_NO_ERROR response code and the free space value.
  434. /// If any other response code is returned, an invalid free space size value is returned (0xFFFFFFFF).
  435. /// </summary>
  436. /// <returns>Free Space</returns>
  437. public ulong GetFreeSpace()
  438. {
  439. responseBuf.Clear();
  440. writeRawMessageToDevice(0xE1, new byte[] { 0x00, 0xE2, 0x03 });
  441. byte[] ret = waitForMsg(new byte[] { 0xE2, 0x03 });
  442. if (ret[0] == 0x00)
  443. return (ulong)ret[1] + ((ulong)ret[2] << 8) + ((ulong)ret[3] << 16) + ((ulong)ret[4] << 24);
  444. else
  445. return FS_GetLastError(ret[0]);
  446. }
  447. /// <summary>
  448. /// Return file index of first file in directory that matches specified identifier.
  449. /// On success, returns FS_NO_ERROR response code and the file index.
  450. /// If any other response code is returned, an invalid file index is returned (0x0000
  451. /// </summary>
  452. /// <param name="FileDataType"> File Data Type</param>
  453. /// <param name="FileSubType"> File Sub Type </param>
  454. /// <param name="FileNumber">File Number</param>
  455. /// <returns>File Index</returns>
  456. public ulong FindFileIndex(byte FileDataType, byte FileSubType, ushort FileNumber)
  457. {
  458. responseBuf.Clear();
  459. writeRawMessageToDevice(0xE1, new byte[] { 0x00, 0xE2, 0x04, FileDataType, FileSubType, getByte_usLE(1, FileNumber), getByte_usLE(2, FileNumber)});
  460. byte[] ret = waitForMsg(new byte[] { 0xE2, 0x04 });
  461. if (ret[0] == 0x00)
  462. return ((ulong)ret[1]) + ((ulong)ret[2] << 8);
  463. else
  464. return FS_GetLastError(ret[0]);
  465. }
  466. /// <summary>
  467. /// Read from absolute offset into directory as if it were an ANTFS directory.
  468. /// </summary>
  469. /// <param name="offset"> Offset </param>
  470. /// <param name="readSize"> Bytes Read Size</param>
  471. /// <returns></returns>
  472. public byte[] DirectoryReadAbsolute(ulong offset, byte readSize)
  473. {
  474. responseBuf.Clear();
  475. writeRawMessageToDevice(0xE1, new byte[] { 0x00, 0xE2, 0x05, getByte_ulLE(1, offset), getByte_ulLE(2, offset), getByte_ulLE(3, offset), getByte_ulLE(4, offset), readSize });
  476. return waitForMsg(new byte[] { 0xE2, 0x05 }, 10000);
  477. }
  478. /// <summary>
  479. /// Returns ANTFS directory entry for the file matching the specified file index
  480. /// </summary>
  481. /// <param name="FileIndex"></param>
  482. /// <returns>ANTFS_DIR_ENTRY</returns>
  483. public byte[] DirectoryReadEntry(ushort FileIndex)
  484. {
  485. responseBuf.Clear();
  486. writeRawMessageToDevice(0xE1, new byte[] { 0x00, 0xE2, 0x06, getByte_ulLE(1, FileIndex), getByte_ulLE(2, FileIndex)});
  487. byte[] ret = waitForMsg(new byte[] { 0xE2, 0x06 }, 10000);
  488. if(ret[0] == 0x00)
  489. return (new byte[]{ret[1], ret[2], ret[3], ret[4], ret[5], ret[6], ret[7], ret[8], ret[9], ret[10], ret[11], ret[12], ret[13], ret[14], ret[15], ret[16]});
  490. else
  491. return (new byte[]{FS_GetLastError(ret[0])});
  492. }
  493. /// <summary>
  494. /// Returns size in bytes as if it were an ANTFS directory (16-byte blocks).
  495. /// On success, returns FS_NO_ERROR response code and the ANTFS directory size value.
  496. /// If any other response code is returned, an invalid ANTFS directory size value is returned (0xFFFFFFFF).
  497. /// </summary>
  498. /// <returns>Directory Size</returns>
  499. public ulong DirectoryGetSize()
  500. {
  501. responseBuf.Clear();
  502. writeRawMessageToDevice(0xE1, new byte[] { 0x00, 0xE2, 0x08 });
  503. byte[] ret = waitForMsg(new byte[] { 0xE2, 0x08 });
  504. if (ret[0] == 0x00)
  505. return (ulong)ret[1] + ((ulong)ret[2] << 8) + ((ulong)ret[3] << 16) + ((ulong)ret[4] << 24);
  506. else
  507. return FS_GetLastError(ret[0]);
  508. }
  509. /// <summary>
  510. /// Allocates a free sector and saves directory entry of the new file.
  511. /// If 0x0000 is supplied as file index, FS will auto generated a valid index for the file,
  512. /// otherwise a valid index must manually be supplied.
  513. /// If file creation is successful (FS_NO_ERROR is returned), the file index assigned to the created file is returned.
  514. /// Any other errors results in an invalid file index being returned (0x0000).
  515. /// </summary>
  516. /// <param name="fileIndex">File Index</param>
  517. /// <param name="ucFileDataType">File Data Type</param>
  518. /// <param name="ucFileSubType">File Sub Type</param>
  519. /// <param name="usFileNumber">File Number</param>
  520. /// <param name="ucFileDataTypeSpecificFlags">File Data Type Specific Flags</param>
  521. /// <param name="ucFileGeneralFlags">File General Flags</param>
  522. /// <returns></returns>
  523. public Int32 FileCreate(ushort fileIndex, byte ucFileDataType, byte ucFileSubType, ushort usFileNumber, byte ucFileDataTypeSpecificFlags, byte ucFileGeneralFlags)
  524. {
  525. responseBuf.Clear();
  526. writeRawMessageToDevice(0xE1, new byte[] { 0x00, 0xE2, 0x0A, getByte_usLE(1, fileIndex), getByte_usLE(2, fileIndex), ucFileDataType, ucFileSubType, getByte_usLE(1, usFileNumber), getByte_usLE(2, usFileNumber), ucFileDataTypeSpecificFlags, ucFileGeneralFlags });
  527. try
  528. {
  529. //Check for the return index
  530. byte[] retAry = waitForMsg(new byte[] { 0xE2, 0x0A });
  531. if(retAry[0] == 0x00)
  532. return retAry[1] + (retAry[2] << 8);
  533. else
  534. return FS_GetLastError(retAry [0]);
  535. }
  536. catch (Exception)
  537. {
  538. //Otherwise return an error as a negative number
  539. return (Int32)(waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x0A })[0]) * -1;
  540. }
  541. }
  542. /// <summary>
  543. /// Open existing file in FS. By default, read and write pointers are set at the beginning of the file.
  544. /// If append flag is set in Open Flags parameter, then the write pointer is set to the end of the file.
  545. /// If file open is successful (FS_NO_ERROR, with the exceptions discussed in .FIT File and Crypto .FIT File),
  546. /// the file handle number is returned.
  547. /// Any other response code results in file open failure and the file handle returned being invalid (0xFF).
  548. /// </summary>
  549. /// <param name="fileIndex">File Index</param>
  550. /// <param name="openFlags">Open Flags</param>
  551. /// <returns></returns>
  552. public Int32 FileOpen(ushort fileIndex, byte openFlags)
  553. {
  554. responseBuf.Clear();
  555. writeRawMessageToDevice(0xE1, new byte[] { 0x00, 0xE2, 0x0B, getByte_usLE(1, fileIndex), getByte_usLE(2, fileIndex), openFlags });
  556. try
  557. {
  558. //Check for the return index
  559. byte[] retAry = waitForMsg(new byte[] { 0xE2, 0x0B });
  560. if (retAry[0] == 0x00)
  561. return retAry[1];
  562. else
  563. return FS_GetLastError(retAry [0]);
  564. }
  565. catch (Exception)
  566. {
  567. //Otherwise return an error as a negative number
  568. return (Int32)(waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x0B })[0]) * -1;
  569. }
  570. }
  571. /// <summary>
  572. /// Read from absolute offset into a file. File must be opened for reading beforehand.
  573. /// After reading, read pointers positioned at the end of the bytes read.
  574. /// On successful reads (FS_NO_ERROR), the returned number of bytes read as well as the payload is returned.
  575. /// Reading past the end of the directory results in FS_EOF_REACHED_ERROR, however the number of read bytes and the payload prior to reaching EOF is returned.
  576. /// </summary>
  577. /// <param name="handleNum">File Handle Number</param>
  578. /// <param name="offset">Offset</param>
  579. /// <param name="readSize">Read Size</param>
  580. /// <returns></returns>
  581. public byte[] FileReadAbsolute(byte handleNum, ulong offset, byte readSize)
  582. {
  583. responseBuf.Clear();
  584. writeRawMessageToDevice(0xE1, new byte[] { 0x00, 0xE2, 0x0E, handleNum, getByte_ulLE(1, offset), getByte_ulLE(2, offset), getByte_ulLE(3, offset), getByte_ulLE(4, offset), readSize });
  585. return waitForMsg(new byte[] { 0xE2, 0x0E });
  586. }
  587. /// <summary>
  588. /// Read from current read pointer position in file. File must be opened for reading beforehand.
  589. /// After reading, read pointers positioned at the end of the bytes read.
  590. /// </summary>
  591. /// <param name="handleNum">File Handle Number</param>
  592. /// <param name="readSize">Read Size</param>
  593. /// <returns></returns>
  594. public byte[] FileReadRelative(byte handleNum, byte readSize)
  595. {
  596. responseBuf.Clear();
  597. writeRawMessageToDevice(0xE1, new byte[] { 0x00, 0xE2, 0x0F, handleNum, readSize });
  598. return waitForMsg(new byte[] { 0xE2, 0x0F });
  599. }
  600. /// <summary>
  601. /// Write to absolute offset into a file. File cannot be written to if it was opened for reading.
  602. /// Write absolute cannot be used if file only opened for append operation.
  603. /// After writing, write positioned at the end of the bytes written.
  604. /// </summary>
  605. /// <param name="handleNum">File Handle Number</param>
  606. /// <param name="offset">Offset</param>
  607. /// <param name="bytesToWrite">Write Payload</param>
  608. /// <returns></returns>
  609. public byte[] FileWriteAbsolute(byte handleNum, ulong offset, byte[] bytesToWrite)
  610. {
  611. responseBuf.Clear();
  612. bytesToWrite = (new byte[] { 0x00, 0xE2, 0x10, handleNum, getByte_ulLE(1, offset), getByte_ulLE(2, offset), getByte_ulLE(3, offset), getByte_ulLE(4, offset), (byte)bytesToWrite.Length }.Concat(bytesToWrite)).ToArray();
  613. writeRawMessageToDevice(0xE1, bytesToWrite);
  614. return waitForMsg(new byte[] { 0xE2, 0x10 });
  615. }
  616. /// <summary>
  617. /// Write to current write pointer position in file. File cannot be written to if opened for reading.
  618. /// </summary>
  619. /// <param name="handleNum">File Handle Number</param>
  620. /// <param name="bytesToWrite">Write Payload</param>
  621. /// <returns></returns>
  622. public byte[] FileWriteRelative(byte handleNum, byte[] bytesToWrite)
  623. {
  624. responseBuf.Clear();
  625. bytesToWrite = (new byte[] { 0x00, 0xE2, 0x11, handleNum, (byte)bytesToWrite.Length }.Concat(bytesToWrite)).ToArray();
  626. writeRawMessageToDevice(0xE1, bytesToWrite);
  627. return waitForMsg(new byte[] { 0xE2, 0x11 });
  628. }
  629. /// <summary>
  630. /// Get size of open file in bytes. If successful, FS_NO_ERROR is returned along with the file size in bytes.
  631. /// If any other response code is returned, an invalid file size value is returned (0xFFFFFFFF).
  632. /// </summary>
  633. /// <param name="handleNum">File Handle Number</param>
  634. /// <returns>File Size</returns>
  635. public ulong FileGetSize(byte handleNum)
  636. {
  637. responseBuf.Clear();
  638. writeRawMessageToDevice(0xE1, new byte[] { 0x00, 0xE2, 0x13, handleNum });
  639. try
  640. {
  641. byte[] ret = waitForMsg(new byte[] { 0xE2, 0x13 });
  642. if(ret[0] == 0x00)
  643. return (ulong)ret[1] + ((ulong)ret[2] << 8) + ((ulong)ret[3] << 16) + ((ulong)ret[4] << 24);
  644. else
  645. return FS_GetLastError(ret[0]);
  646. }
  647. catch (Exception)
  648. {
  649. return 0xFFFFFF00 + waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x13 })[0];
  650. }
  651. }
  652. /// <summary>
  653. /// Get size of the file in terms of the number of total bytes allocated to the file in the FS (size in memory).
  654. /// If successful, FS_NO_ERROR is returned along with the size in bytes.
  655. /// If any other response code is returned, an invalid file size value is returned (0xFFFFFFFF).
  656. /// </summary>
  657. /// <param name="handleNum">File handle Number</param>
  658. /// <returns></returns>
  659. public ulong FileGetSizeInMem(byte handleNum)
  660. {
  661. responseBuf.Clear();
  662. writeRawMessageToDevice(0xE1, new byte[] { 0x00, 0xE2, 0x15, handleNum });
  663. try
  664. {
  665. byte[] ret = waitForMsg(new byte[] { 0xE2, 0x15 });
  666. if (ret[0] == 0x00)
  667. return (ulong)ret[1] + ((ulong)ret[2] << 8) + ((ulong)ret[3] << 16) + ((ulong)ret[4] << 24);
  668. else
  669. return FS_GetLastError(ret[0]);
  670. }
  671. catch (Exception)
  672. {
  673. return 0xFFFFFF00 + waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x13 })[0];
  674. }
  675. }
  676. /// <summary>
  677. /// Gets the application defined flags of opened file.
  678. /// If successful, FS_NO_ERROR is returned along with the application defined flags on the file.
  679. /// If any other response code is returned, flag value of 0x00 is returned.
  680. /// </summary>
  681. /// <param name="handleNum">File Handle Number</param>
  682. /// <returns>File Flags</returns>
  683. public ulong FileGetSpecificFileFlags(byte handleNum)
  684. {
  685. responseBuf.Clear();
  686. writeRawMessageToDevice(0xE1, new byte[] { 0x00, 0xE2, 0x14, handleNum });
  687. try
  688. {
  689. byte[] ret = waitForMsg(new byte[] { 0xE2, 0x14 });
  690. if(ret[0] == 0x00)
  691. return (ulong)ret[1] + ((ulong)ret[2] << 8);
  692. else
  693. return FS_GetLastError(ret[0]);
  694. }
  695. catch (Exception)
  696. {
  697. return 0xFFFFFF00 + waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x14 })[0];
  698. }
  699. }
  700. /// <summary>
  701. /// When this message ID is used in a request message, the current system time used in FS is returned.
  702. /// </summary>
  703. /// <param name="seconds">Current Time</param>
  704. /// <returns></returns>
  705. public ulong SystemTime(uint seconds)
  706. {
  707. responseBuf.Clear();
  708. writeRawMessageToDevice(0xE2, new byte[] { 0x3D});
  709. byte[] ret = waitForMsg(new byte[] {0xE2, 0x3D });
  710. return (ulong)ret[0] + ((ulong)ret[1] << 8) + ((ulong)ret[2] << 16) + ((ulong)ret[3] << 24);
  711. }
  712. #endregion
  713. #region FS-Crypto Commands
  714. /// <summary>
  715. /// Adds specified user key to be stored in internal memory.
  716. /// Keys are enumerated by Key Index. Up to 10 keys can be used.
  717. /// If successfully stored, FS_NO_ERROR is returned.
  718. /// </summary>
  719. /// <param name="keyindex">Key Index</param>
  720. /// <param name="CK">User Crypto Key</param>
  721. /// <returns>FS Response</returns>
  722. public byte Crypto_AddUserKeyIndex(byte keyindex, byte[] CK)
  723. {
  724. responseBuf.Clear();
  725. writeRawMessageToDevice(0xE2, new byte[] { 0x45, keyindex, CK[0], CK[1], CK[2], CK[3], CK[4], CK[5], CK[6], CK[7], CK[8], CK[9], CK[10], CK[1], CK[12], CK[13],
  726. CK[14], CK[15],CK[16], CK[17],CK[18], CK[19],CK[20], CK[21],CK[22], CK[23],CK[24], CK[25],CK[26], CK[27],CK[28], CK[29],CK[30], CK[31]});
  727. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x45 })[0];
  728. }
  729. /// <summary>
  730. /// Specify stored user key (specified by Key Index) to be used by FS Encryption/Decryption process.
  731. /// Key remains active until reset, memory re-initialization via MESG_FS_INIT MEMORY or another key is specified.
  732. /// If key successfully selected, FS_NO_ERROR is returned
  733. /// </summary>
  734. /// <param name="keyindex">User Key Index</param>
  735. /// <returns>FS Response</returns>
  736. public byte Crypto_SetUserKeyIndex(byte keyindex)
  737. {
  738. responseBuf.Clear();
  739. writeRawMessageToDevice(0xE2, new byte[] { 0x46, keyindex });
  740. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x46 })[0];
  741. }
  742. /// <summary>
  743. /// Specify non-stored user key to be used by FS Encryption/Decryption process.
  744. /// Key remains active until reset, memory re-initialization via MESG_FS_INIT_MEMORY or another key is specified.
  745. /// If key successfully set, FS_NO_ERROR is returned.d
  746. /// </summary>
  747. /// <param name="CK">User Crypto Key</param>
  748. /// <returns>FS Response</returns>
  749. public byte Crypto_SetUserKeyValue(byte[] CK)
  750. {
  751. responseBuf.Clear();
  752. writeRawMessageToDevice(0xE2, new byte[] { 0x47, CK[0], CK[1], CK[2], CK[3], CK[4], CK[5], CK[6], CK[7], CK[8], CK[9], CK[10], CK[1], CK[12], CK[13],
  753. CK[14], CK[15],CK[16], CK[17],CK[18], CK[19],CK[20], CK[21],CK[22], CK[23],CK[24], CK[25],CK[26], CK[27],CK[28], CK[29],CK[30], CK[31]});
  754. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x47 })[0];
  755. }
  756. #endregion
  757. #region FS_FIT Commands
  758. /// <summary>
  759. /// When this command is issued, a file integrity check is performed on the selected .FIT file
  760. /// by calculating the file 2 byte CRC and comparing it versus the appended 2 byte CRC.
  761. /// If file integrity is intact, then FS_NO_ERROR is returned.Provided file handle must be pointing to a .FIT file (0x80 data type in file directory entry) as well as opened as read-only.
  762. /// Performing an integrity check on a non .FIT file and/or a write handle (write/erase/append open flags) is not allowed.
  763. /// </summary>
  764. /// <param name="handle">File Handle Number</param>
  765. /// <returns>FS Response</returns>
  766. public byte FIT_FileIntegrityCheck(byte handle)
  767. {
  768. responseBuf.Clear();
  769. writeRawMessageToDevice(0xE2, new byte[] { 0x50, handle });
  770. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x50 })[0];
  771. }
  772. #endregion
  773. #region ANTFS Commands
  774. /// <summary>
  775. /// Start ANTFS beacon.
  776. /// </summary>
  777. /// <returns>FS Response</returns>
  778. public byte ANTFS_Open()
  779. {
  780. responseBuf.Clear();
  781. writeRawMessageToDevice(0xE2, new byte[] { 0x31 });
  782. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x31 })[0];
  783. }
  784. /// <summary>
  785. /// Stop ANTFS beacon.
  786. /// </summary>
  787. /// <returns>FS Response</returns>
  788. public byte ANTFS_Close()
  789. {
  790. responseBuf.Clear();
  791. writeRawMessageToDevice(0xE2, new byte[] { 0x32 });
  792. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x32 })[0];
  793. }
  794. /// <summary>
  795. /// Configures the ANTFS Beacon properties.
  796. /// </summary>
  797. /// <param name="BeaconDeviceType">Beacon Device Type ID</param>
  798. /// <param name="ManID">Manufacturers ID</param>
  799. /// <param name="AuthKey">Authentication Type</param>
  800. /// <param name="Status">Beacon Status</param>
  801. /// <returns>FS Response</returns>
  802. public byte ANTFS_ConfigBeacon(ushort BeaconDeviceType, ushort ManID, byte AuthKey, byte Status)
  803. {
  804. responseBuf.Clear();
  805. writeRawMessageToDevice(0xE2, new byte[] { 0x33, getByte_usLE(1, BeaconDeviceType), getByte_usLE(2, BeaconDeviceType), getByte_usLE(1, ManID), getByte_usLE(2, ManID), AuthKey, Status });
  806. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x33 })[0];
  807. }
  808. /// <summary>
  809. /// Set the Friendlyname
  810. /// </summary>
  811. /// <param name="friendlyname">Friendlyname as a string</param>
  812. /// <returns>FS Response</returns>
  813. public byte ANTFS_SetFriendlyName(string friendlyname)
  814. {
  815. responseBuf.Clear();
  816. int stringlength = friendlyname.Length;
  817. byte[] temp = System.Text.Encoding.ASCII.GetBytes(friendlyname);
  818. byte[] asciibytes = new byte[16];
  819. for (int i = 0; i < stringlength; i++)
  820. asciibytes[i] = System.Convert.ToByte(temp[i]);
  821. writeRawMessageToDevice(0xE2, new byte[] {0x34, 0x00, asciibytes[0],asciibytes[1],asciibytes[2],asciibytes[3],asciibytes[4],asciibytes[5],asciibytes[6],
  822. asciibytes[7],asciibytes[8],asciibytes[9],asciibytes[10],asciibytes[11],asciibytes[12],asciibytes[13],asciibytes[14],asciibytes[15]});
  823. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x34 })[0];
  824. }
  825. /// <summary>
  826. /// Sets the Passkey
  827. /// </summary>
  828. /// <param name="passkey">Passkey as a string</param>
  829. /// <returns>FS Response</returns>
  830. public byte ANTFS_SetPasskey(string passkey)
  831. {
  832. responseBuf.Clear();
  833. System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(",");
  834. String[] DataArray = regex.Split(passkey);
  835. int arraylength = DataArray.Length;
  836. byte[] passkeybytes = new byte[16];
  837. for (int i = 0; i < arraylength; i++)
  838. passkeybytes[i] = System.Convert.ToByte(DataArray[i], 16);
  839. writeRawMessageToDevice(0xE2, new byte[] {0x34,0x01,passkeybytes[0],passkeybytes[1],passkeybytes[2],passkeybytes[3],passkeybytes[4],passkeybytes[5],passkeybytes[6],
  840. passkeybytes[7],passkeybytes[8],passkeybytes[9],passkeybytes[10],passkeybytes[11],passkeybytes[12],passkeybytes[13],passkeybytes[14],passkeybytes[15]});
  841. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x34 })[0];
  842. }
  843. /// <summary>
  844. /// Sets the ANTFS beacon status byte.
  845. /// </summary>
  846. /// <param name="Status">Bits 0 -2 are invalid</param>
  847. /// <returns>FS Response</returns>
  848. public byte ANTFS_SetBeaconState(byte Status)
  849. {
  850. responseBuf.Clear();
  851. writeRawMessageToDevice(0xE2, new byte[] { 0x35, Status});
  852. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x35 })[0];
  853. }
  854. /// <summary>
  855. /// Command to respond to pairing request.
  856. /// </summary>
  857. /// <param name="decision">0 - Reject , 1 - Accept</param>
  858. /// <returns>FS Response</returns>
  859. public byte ANTFS_PairResponse(byte decision)
  860. {
  861. responseBuf.Clear();
  862. writeRawMessageToDevice(0xE2, new byte[] { 0x36, decision });
  863. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x36 })[0];
  864. }
  865. /// <summary>
  866. /// Set the Beacon/Link RF frequency of the ANTFS connection
  867. /// </summary>
  868. /// <param name="channelnum">Channel Number</param>
  869. /// <param name="frequency">24xxMhz, xx as byte, 0xFF is to Disable</param>
  870. /// <returns>FS Response</returns>
  871. public byte ANTFS_SetLinkFrequency(byte channelnum, byte frequency)
  872. {
  873. responseBuf.Clear();
  874. writeRawMessageToDevice(0xE2, new byte[] { 0x37, channelnum, frequency });
  875. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x37 })[0];
  876. }
  877. /// <summary>
  878. /// Configure timeout for ANTFS beacon.
  879. /// </summary>
  880. /// <param name="timeout">Timeout in seconds</param>
  881. /// <returns>FS Response</returns>
  882. public byte ANTFS_SetBeaconTimeout(byte timeout)
  883. {
  884. responseBuf.Clear();
  885. writeRawMessageToDevice(0xE2, new byte[] { 0x38, timeout });
  886. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x38 })[0];
  887. }
  888. /// <summary>
  889. /// Configure timeout for ANTFS pairing process
  890. /// </summary>
  891. /// <param name="PairTimeout">Timeout in seconds</param>
  892. /// <returns>FS Response</returns>
  893. public byte ANTFS_SetPairingTimeout(byte PairTimeout)
  894. {
  895. responseBuf.Clear();
  896. writeRawMessageToDevice(0xE2, new byte[] { 0x39, PairTimeout });
  897. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x39 })[0];
  898. }
  899. /// <summary>
  900. /// Enables or disables file creation in FS through ANTFS.
  901. /// </summary>
  902. /// <param name="enable">1 - Enable, 0 - Disable</param>
  903. /// <returns>FS Response</returns>
  904. public byte ANTFS_RemoteFileCreateEnable(byte enable)
  905. {
  906. responseBuf.Clear();
  907. writeRawMessageToDevice(0xE2, new byte[] { 0x3A, enable });
  908. return waitForMsg(new byte[] { 0xE0, 0x00, 0xE2, 0x3A })[0];
  909. }
  910. #endregion
  911. #region ANTFS Requests
  912. /// <summary>
  913. /// Command to read ANTFS command pipe data.
  914. /// </summary>
  915. /// <param name="offset">Offset</param>
  916. /// <param name="readsize">Read Size</param>
  917. /// <returns>Read Size and Read Payload</returns>
  918. public byte[] ANTFS_GetCmdPipe(byte offset, byte readsize)
  919. {
  920. responseBuf.Clear();
  921. writeRawMessageToDevice(0xE1, new byte[] { 0x00, 0xE2, 0x3B, offset, readsize });
  922. return waitForMsg(new byte[] { 0xE2, 0x3B }, 10000);
  923. }
  924. /// <summary>
  925. /// Command to write ANTFS command pipe data.
  926. /// </summary>
  927. /// <param name="offset">Offset</param>
  928. /// <param name="bytesToWrite">Bytes to be written</param>
  929. /// <returns>Size written</returns>
  930. public byte ANTFS_SetCmdPipe(byte offset, byte[] bytesToWrite)
  931. {
  932. responseBuf.Clear();
  933. bytesToWrite = (new byte[] { 0x00, 0xE2, 0x3C, offset, (byte)bytesToWrite.Length }.Concat(bytesToWrite)).ToArray();
  934. writeRawMessageToDevice(0xE1, bytesToWrite);
  935. return waitForMsg(new byte[] { 0xE2, 0x3C })[0];
  936. }
  937. #endregion
  938. #endregion Serial Commands
  939. }
  940. }