No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DestijlCommandManager.cs 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. //
  2. // DestijlCommandManager.cs
  3. //
  4. // Author:
  5. // Di MERCURIO Sébastien <dimercur@insa-toulouse.fr>
  6. //
  7. // Copyright (c) 2018 INSA - DGEI
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU General Public License as published by
  11. // the Free Software Foundation, either version 3 of the License, or
  12. // (at your option) any later version.
  13. //
  14. // This program is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. // GNU General Public License for more details.
  18. //
  19. // You should have received a copy of the GNU General Public License
  20. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. using System;
  22. using System.Globalization;
  23. namespace monitor
  24. {
  25. /// <summary>
  26. /// Commands and options parameters used in Destijl project when communicating with server
  27. /// </summary>
  28. public static class DestijlCommandList
  29. {
  30. public const string ANSWER_ACK = "AACK";
  31. public const string ANSWER_NACK = "ANAK";
  32. public const string ANSWER_COM_ERROR = "ACER";
  33. public const string ANSWER_TIMEOUT = "ATIM";
  34. public const string ANSWER_CMD_REJECTED = "ACRJ";
  35. public const string MESSAGE = "MSSG";
  36. public const string CAMERA_OPEN = "COPN";
  37. public const string CAMERA_CLOSE = "CCLS";
  38. public const string CAMERA_IMAGE = "CIMG";
  39. public const string CAMERA_ARENA_ASK = "CASA";
  40. public const string CAMERA_ARENA_INFIRM = "CAIN";
  41. public const string CAMERA_ARENA_CONFIRM = "CACO";
  42. public const string CAMERA_POSITION_COMPUTE = "CPCO";
  43. public const string CAMERA_POSITION_STOP = "CPST";
  44. public const string CAMERA_POSITION = "CPOS";
  45. public const string ROBOT_COM_OPEN = "ROPN";
  46. public const string ROBOT_COM_CLOSE = "RCLS";
  47. public const string ROBOT_PING = "RPIN";
  48. public const string ROBOT_RESET = "RRST";
  49. public const string ROBOT_START_WITHOUT_WD = "RSOW";
  50. public const string ROBOT_START_WITH_WD = "RSWW";
  51. public const string ROBOT_RELOAD_WD = "RLDW";
  52. public const string ROBOT_MOVE = "RMOV";
  53. public const string ROBOT_TURN = "RTRN";
  54. public const string ROBOT_GO_FORWARD = "RGFW";
  55. public const string ROBOT_GO_BACKWARD = "RGBW";
  56. public const string ROBOT_GO_LEFT = "RGLF";
  57. public const string ROBOT_GO_RIGHT = "RGRI";
  58. public const string ROBOT_STOP = "RSTP";
  59. public const string ROBOT_POWEROFF = "RPOF";
  60. public const string ROBOT_BATTERY_LEVEL = "RBLV";
  61. public const string ROBOT_GET_BATTERY = "RGBT";
  62. public const string ROBOT_GET_STATE = "RGST";
  63. public const string ROBOT_CURRENT_STATE = "RCST";
  64. public const char SEPARATOR_CHAR = ':';
  65. //public const string HeaderMtsComDmb = "COM";
  66. //public const string HeaderMtsDmbOrder = "DMB";
  67. //public const string HeaderMtsCamera = "CAM";
  68. //public const string HeaderMtsMessage = "MSG";
  69. //public const string DataComOpen = "o";
  70. //public const string DataComClose = "C";
  71. //public const string DataCamOpen = "A";
  72. //public const string DataCamClose = "I";
  73. //public const string DataCamAskArena = "y";
  74. //public const string DataCamArenaConfirm = "x";
  75. //public const string DataCamInfirm = "z";
  76. //public const string DataCamComputePosition = "p";
  77. //public const string DataCamStopComputePosition = "s";
  78. //public const string HeaderStmAck = "ACK";
  79. //public const string HeaderStmNoAck = "NAK";
  80. //public const string HeaderStmLostDmb = "LCD";
  81. //public const string HeaderStmImage = "IMG";
  82. //public const string HeaderStmPos = "POS";
  83. //public const string HeaderStmMes = "MSG";
  84. //public const string HeaderStmBat = "BAT";
  85. }
  86. /// <summary>
  87. /// Commands used for robot messages
  88. /// </summary>
  89. //public static class RobotCommandList
  90. //{
  91. // public const string RobotPing = "p";
  92. // public const string RobotReset = "r";
  93. // public const string RobotStartWithoutWatchdog = "u";
  94. // public const string RobotStartWithWatchdog = "W";
  95. // public const string RobotGetBattery = "v";
  96. // public const string RobotGetBusyState = "b";
  97. // public const string RobotMove = "M";
  98. // public const string RobotTurn = "T";
  99. // public const string RobotGetVersion = "V";
  100. // public const string RobotPowerOff = "z";
  101. //}
  102. /// <summary>
  103. /// Specialization class for command manager, which implemnent destijl protocol between monitor and server
  104. /// </summary>
  105. public class DestijlCommandManager
  106. {
  107. /// <summary>
  108. /// Command Manager object
  109. /// </summary>
  110. private CommandManager commandManager = null;
  111. /// <summary>
  112. /// Part of received message corresponding to command header
  113. /// </summary>
  114. private string receivedHeader = null;
  115. /// <summary>
  116. /// Part of received message corresponding to command data
  117. /// </summary>
  118. private string receivedData = null;
  119. /// <summary>
  120. /// Callback for sending received data to application level
  121. /// </summary>
  122. public delegate void CommandReceivedEvent(string header, string data);
  123. public CommandReceivedEvent commandReceivedEvent = null;
  124. /// <summary>
  125. /// Timeout used for command with acknowledge
  126. /// </summary>
  127. public double timeout = 100;
  128. /// <summary>
  129. /// List of available return status
  130. /// </summary>
  131. public enum CommandStatus
  132. {
  133. Success,
  134. Rejected,
  135. InvalidAnswer,
  136. Busy,
  137. CommunicationLostWithRobot,
  138. CommunicationLostWithServer
  139. }
  140. public struct Point {
  141. public double x;
  142. public double y;
  143. }
  144. public class Position {
  145. public int robotID;
  146. public double angle;
  147. public Point centre;
  148. public Point direction;
  149. public Position() {
  150. robotID = 0;
  151. angle = 0.0;
  152. centre.x = 0.0;
  153. centre.y = 0.0;
  154. direction.x = 0.0;
  155. direction.y = 0.0;
  156. }
  157. public override string ToString() {
  158. string s = "ID: " + robotID + ", Angle: " + angle +
  159. ", Centre (x: " + centre.x + ", y: " + centre.y +
  160. "), Direction (x: " + direction.x + ", y: " + direction.y + ")";
  161. return s;
  162. }
  163. }
  164. /// <summary>
  165. /// Initializes a new instance of the <see cref="monitor.DestijlCommandManager"/> class.
  166. /// </summary>
  167. /// <param name="callback">Callback reference for reception of data</param>
  168. public DestijlCommandManager(CommandReceivedEvent callback)
  169. {
  170. commandManager = new CommandManager(OnCommandReceived);
  171. this.commandReceivedEvent += callback;
  172. }
  173. /// <summary>
  174. /// Releases unmanaged resources and performs other cleanup operations before the
  175. /// <see cref="monitor.DestijlCommandManager"/> is reclaimed by garbage collection.
  176. /// </summary>
  177. ~DestijlCommandManager()
  178. {
  179. if (commandManager != null) commandManager.Close();
  180. }
  181. /// <summary>
  182. /// Callback used for receiving data from lower layer (CommandManager class)
  183. /// </summary>
  184. /// <param name="msg">String containing received message</param>
  185. /// <param name="buffer">Raw buffer to be used when data are not in ascii format (image for example)</param>
  186. private void OnCommandReceived(string msg)
  187. {
  188. // Firstly, remove ending \n and everything after
  189. string[] msgsCarriageReturn = msg.Split('\n');
  190. // Second, split message in (at least) two part : header, and data
  191. string[] msgs = msgsCarriageReturn[0].Split(DestijlCommandList.SEPARATOR_CHAR);
  192. // If it exist at least on element in string array, it should be command header
  193. if (msgs.Length >= 1) receivedHeader = msgs[0];
  194. else receivedHeader = null;
  195. // if msgs array contains at least two elements, second element is normally data
  196. if (msgs.Length >= 2) receivedData = msgs[1];
  197. else receivedData = null;
  198. // when split is done, provide data to application
  199. this.commandReceivedEvent?.Invoke(receivedHeader, receivedData);
  200. }
  201. /// <summary>
  202. /// Open the specified hostname server, using default port number.
  203. /// </summary>
  204. /// <returns>true if connection succeded, false otherwise</returns>
  205. /// <param name="hostname">Hostname to connect to</param>
  206. public bool Open(string hostname)
  207. {
  208. return this.Open(hostname, Client.defaultPort);
  209. }
  210. /// <summary>
  211. /// Open connection to server "host", with port number "port"
  212. /// </summary>
  213. /// <returns>true if connection succeded, false otherwise</returns>
  214. /// <param name="hostname">Hostname to connect to</param>
  215. /// <param name="port">Port number for connection</param>
  216. public bool Open(string hostname, int port)
  217. {
  218. if (commandManager != null) return commandManager.Open(hostname, port);
  219. else return false;
  220. }
  221. /// <summary>
  222. /// Close connection to server
  223. /// </summary>
  224. public void Close()
  225. {
  226. if (commandManager != null) commandManager.Close();
  227. }
  228. /// <summary>
  229. /// Creates the command to send to server, based on header and data provided
  230. /// </summary>
  231. /// <returns>The command string</returns>
  232. /// <param name="header">Header part of the command</param>
  233. /// <param name="data">Data part of the command</param>
  234. private string CreateCommand(string header, string data)
  235. {
  236. return header + DestijlCommandList.SEPARATOR_CHAR + data+"\n";
  237. }
  238. /// <summary>
  239. /// Creates the command to send to server, based on header
  240. /// </summary>
  241. /// <returns>The command string</returns>
  242. /// <param name="header">Header part of the command</param>
  243. private string CreateCommand(string header)
  244. {
  245. return header + DestijlCommandList.SEPARATOR_CHAR+"\n";
  246. }
  247. /// <summary>
  248. /// Provide DestijlCommandManager.CommandStatus based on status received by CommandManager.SendCommand and answer string
  249. /// </summary>
  250. /// <returns>Status compatible with DestijlCommandManager.CommandStatus type</returns>
  251. /// <param name="localStatus">Status provided by CommandManager.SendCommand</param>
  252. /// <param name="answer">Answer provided by CommandManager.SendCommand</param>
  253. private CommandStatus DecodeStatus(CommandManager.CommandManagerStatus localStatus, string answer)
  254. {
  255. CommandStatus status = CommandStatus.Success;
  256. // if timeout occures, return CommandStatus.CommunicationLostWithServer
  257. if (localStatus == CommandManager.CommandManagerStatus.Timeout) status = CommandStatus.CommunicationLostWithServer;
  258. // if a command is currently processed, return Busy
  259. else if (localStatus == CommandManager.CommandManagerStatus.Busy) status = CommandStatus.Busy;
  260. else
  261. {
  262. if (answer != null)
  263. {
  264. // if command is not acknowledged, return Rejected
  265. if (answer.ToUpper().Contains(DestijlCommandList.ANSWER_NACK)) status = CommandStatus.Rejected;
  266. // if communication is lost with robot, return CommunicationLostWithRobot
  267. else if (answer.ToUpper().Contains(DestijlCommandList.ANSWER_TIMEOUT)) status = CommandStatus.CommunicationLostWithRobot;
  268. // if answer is empty, communication with robot is lost
  269. else if (answer.Length == 0) status = CommandStatus.CommunicationLostWithServer;
  270. //else status = CommandStatus.InvalidAnswer;
  271. }
  272. }
  273. return status;
  274. }
  275. /// <summary>
  276. /// Open communication with robot and wait acknowledge
  277. /// </summary>
  278. /// <returns>Command status (see DecodeStatus)</returns>
  279. public CommandStatus RobotOpenCom()
  280. {
  281. CommandManager.CommandManagerStatus localStatus;
  282. string answer;
  283. localStatus = commandManager.SendCommand(
  284. CreateCommand(DestijlCommandList.ROBOT_COM_OPEN),
  285. out answer,
  286. this.timeout);
  287. return DecodeStatus(localStatus, answer);
  288. }
  289. /// <summary>
  290. /// Close communication with robot and wait acknowledge
  291. /// </summary>
  292. /// <returns>Command status (see DecodeStatus)</returns>
  293. public CommandStatus RobotCloseCom()
  294. {
  295. CommandManager.CommandManagerStatus localStatus;
  296. string answer;
  297. localStatus = commandManager.SendCommand(
  298. CreateCommand(DestijlCommandList.ROBOT_COM_CLOSE),
  299. out answer,
  300. this.timeout);
  301. return DecodeStatus(localStatus, answer);
  302. }
  303. /// <summary>
  304. /// Ping the robot.
  305. /// </summary>
  306. /// <returns>Command status (see DecodeStatus)</returns>
  307. public CommandStatus RobotPing()
  308. {
  309. CommandManager.CommandManagerStatus localStatus;
  310. string answer;
  311. localStatus = commandManager.SendCommand(
  312. CreateCommand(DestijlCommandList.ROBOT_PING),
  313. out answer,
  314. this.timeout);
  315. return DecodeStatus(localStatus, answer);
  316. }
  317. /// <summary>
  318. /// Reset robot and let it in idle mode
  319. /// </summary>
  320. /// <returns>Command status (see DecodeStatus)</returns>
  321. public CommandStatus RobotReset()
  322. {
  323. CommandManager.CommandManagerStatus localStatus;
  324. string answer;
  325. localStatus = commandManager.SendCommand(
  326. CreateCommand(DestijlCommandList.ROBOT_RESET),
  327. out answer,
  328. 0);
  329. return DecodeStatus(localStatus, answer);
  330. }
  331. /// <summary>
  332. /// Start robot, enabling watchdog
  333. /// </summary>
  334. /// <returns>Command status (see DecodeStatus)</returns>
  335. public CommandStatus RobotStartWithWatchdog()
  336. {
  337. CommandManager.CommandManagerStatus localStatus;
  338. string answer;
  339. localStatus = commandManager.SendCommand(
  340. CreateCommand(DestijlCommandList.ROBOT_START_WITH_WD),
  341. out answer,
  342. this.timeout);
  343. return DecodeStatus(localStatus, answer);
  344. }
  345. /// <summary>
  346. /// Start robot, without enabling watchdog
  347. /// </summary>
  348. /// <returns>Command status (see DecodeStatus)</returns>
  349. public CommandStatus RobotStartWithoutWatchdog()
  350. {
  351. CommandManager.CommandManagerStatus localStatus;
  352. string answer;
  353. localStatus = commandManager.SendCommand(
  354. CreateCommand(DestijlCommandList.ROBOT_START_WITHOUT_WD),
  355. out answer,
  356. this.timeout);
  357. return DecodeStatus(localStatus, answer);
  358. }
  359. /// <summary>
  360. /// Move robot forward or backward, for a distance expressed in millimeter
  361. /// </summary>
  362. /// <returns>Command status (see DecodeStatus)</returns>
  363. /// <param name="distance">Distance of mouvment, in millimeter</param>
  364. public CommandStatus RobotMove(int distance)
  365. {
  366. CommandManager.CommandManagerStatus localStatus;
  367. string answer;
  368. localStatus = commandManager.SendCommand(
  369. CreateCommand(DestijlCommandList.ROBOT_MOVE, Convert.ToString(distance)),
  370. out answer,
  371. 0);
  372. return DecodeStatus(localStatus, answer);
  373. }
  374. /// <summary>
  375. /// Make robot turn left or right, for a given angle
  376. /// </summary>
  377. /// <returns>Command status (see DecodeStatus)</returns>
  378. /// <param name="angle">Angle of turn, in degree (negative for left, positive for right)</param>
  379. public CommandStatus RobotTurn(int angle)
  380. {
  381. CommandManager.CommandManagerStatus localStatus;
  382. string answer;
  383. localStatus = commandManager.SendCommand(
  384. CreateCommand(DestijlCommandList.ROBOT_TURN, Convert.ToString(angle)),
  385. out answer,
  386. 0);
  387. return DecodeStatus(localStatus, answer);
  388. }
  389. /// <summary>
  390. /// Request robot battery level
  391. /// </summary>
  392. /// <returns>Command status (see DecodeStatus)</returns>
  393. public CommandStatus RobotGetBattery()
  394. {
  395. CommandManager.CommandManagerStatus localStatus;
  396. string answer;
  397. localStatus = commandManager.SendCommand(
  398. CreateCommand(DestijlCommandList.ROBOT_GET_BATTERY),
  399. out answer,
  400. 0);
  401. return DecodeStatus(localStatus, answer);
  402. }
  403. /// <summary>
  404. /// Power off robot
  405. /// </summary>
  406. /// <returns>Command status (see DecodeStatus)</returns>
  407. public CommandStatus RobotPowerOff()
  408. {
  409. CommandManager.CommandManagerStatus localStatus;
  410. string answer;
  411. localStatus = commandManager.SendCommand(
  412. CreateCommand(DestijlCommandList.ROBOT_POWEROFF),
  413. out answer,
  414. 0);
  415. return DecodeStatus(localStatus, answer);
  416. }
  417. /// <summary>
  418. /// Open camera on remote device
  419. /// </summary>
  420. /// <returns>Command status (see DecodeStatus)</returns>
  421. public CommandStatus CameraOpen()
  422. {
  423. CommandManager.CommandManagerStatus localStatus;
  424. string answer;
  425. localStatus = commandManager.SendCommand(
  426. CreateCommand(DestijlCommandList.CAMERA_OPEN),
  427. out answer,
  428. this.timeout);
  429. return DecodeStatus(localStatus, answer);
  430. }
  431. /// <summary>
  432. /// Close camera on remote device
  433. /// </summary>
  434. /// <returns>Command status (see DecodeStatus)</returns>
  435. public CommandStatus CameraClose()
  436. {
  437. CommandManager.CommandManagerStatus localStatus;
  438. string answer;
  439. localStatus = commandManager.SendCommand(
  440. CreateCommand(DestijlCommandList.CAMERA_CLOSE),
  441. out answer,
  442. 0);
  443. return DecodeStatus(localStatus, answer);
  444. }
  445. /// <summary>
  446. /// Request still image of detected arena
  447. /// </summary>
  448. /// <returns>Command status (see DecodeStatus)</returns>
  449. public CommandStatus CameraAskArena()
  450. {
  451. CommandManager.CommandManagerStatus localStatus;
  452. string answer;
  453. localStatus = commandManager.SendCommand(
  454. CreateCommand(DestijlCommandList.CAMERA_ARENA_ASK),
  455. out answer,
  456. 0);
  457. return DecodeStatus(localStatus, answer);
  458. }
  459. /// <summary>
  460. /// Confirm arena detection (after requesting image of detected arena, using CameraAskArena
  461. /// </summary>
  462. /// <returns>Command status (see DecodeStatus)</returns>
  463. public CommandStatus CameraArenaConfirm()
  464. {
  465. CommandManager.CommandManagerStatus localStatus;
  466. string answer;
  467. localStatus = commandManager.SendCommand(
  468. CreateCommand(DestijlCommandList.CAMERA_ARENA_CONFIRM),
  469. out answer,
  470. 0);
  471. return DecodeStatus(localStatus, answer);
  472. }
  473. /// <summary>
  474. /// Reject arena detected (after requesting image of detected arena, using CameraAskArena
  475. /// </summary>
  476. /// <returns>Command status (see DecodeStatus)</returns>
  477. public CommandStatus CameraArenaInfirm()
  478. {
  479. CommandManager.CommandManagerStatus localStatus;
  480. string answer;
  481. localStatus = commandManager.SendCommand(
  482. CreateCommand(DestijlCommandList.CAMERA_ARENA_INFIRM),
  483. out answer,
  484. 0);
  485. return DecodeStatus(localStatus, answer);
  486. }
  487. /// <summary>
  488. /// Request robot position computing
  489. /// </summary>
  490. /// <returns>Command status (see DecodeStatus)</returns>
  491. public CommandStatus CameraComputePosition()
  492. {
  493. CommandManager.CommandManagerStatus localStatus;
  494. string answer;
  495. localStatus = commandManager.SendCommand(
  496. CreateCommand(DestijlCommandList.CAMERA_POSITION_COMPUTE),
  497. out answer,
  498. 0);
  499. return DecodeStatus(localStatus, answer);
  500. }
  501. /// <summary>
  502. /// Stop robot position computing
  503. /// </summary>
  504. /// <returns>Command status (see DecodeStatus)</returns>
  505. public CommandStatus CameraStopComputePosition()
  506. {
  507. CommandManager.CommandManagerStatus localStatus;
  508. string answer;
  509. localStatus = commandManager.SendCommand(
  510. CreateCommand(DestijlCommandList.CAMERA_POSITION_STOP),
  511. out answer,
  512. 0);
  513. return DecodeStatus(localStatus, answer);
  514. }
  515. public static Position DecodePosition(string data) {
  516. Position pos = new Position();
  517. pos.robotID = 0;
  518. pos.angle = 0.0;
  519. pos.centre.x = 0.0;
  520. pos.centre.y=0.0;
  521. pos.direction.x = 0.0;
  522. pos.direction.y = 0.0;
  523. string[] parts = data.Split(';');
  524. //for (int i = 0; i < parts.Length; i++) {
  525. // Console.WriteLine(parts[i]);
  526. //}
  527. NumberFormatInfo provider = new NumberFormatInfo();
  528. provider.NumberDecimalSeparator = ".";
  529. provider.NumberGroupSeparator = ",";
  530. provider.NumberGroupSizes = new int[] { 3 };
  531. if (parts.Length == 6) {
  532. pos.robotID = Convert.ToInt32(parts[0]);
  533. try
  534. {
  535. pos.angle = Convert.ToDouble(parts[1]);
  536. } catch (FormatException)
  537. {
  538. pos.angle = Convert.ToDouble(parts[1],provider);
  539. }
  540. try
  541. {
  542. pos.centre.x = Convert.ToDouble(parts[2]);
  543. } catch (FormatException)
  544. {
  545. pos.centre.x = Convert.ToDouble(parts[2], provider);
  546. }
  547. try
  548. {
  549. pos.centre.y = Convert.ToDouble(parts[3]);
  550. }
  551. catch (FormatException)
  552. {
  553. pos.centre.y = Convert.ToDouble(parts[3], provider);
  554. }
  555. try
  556. {
  557. pos.direction.x = Convert.ToDouble(parts[4]);
  558. }
  559. catch (FormatException)
  560. {
  561. pos.direction.x = Convert.ToDouble(parts[4], provider);
  562. }
  563. try
  564. {
  565. pos.direction.y = Convert.ToDouble(parts[5]);
  566. }
  567. catch (FormatException)
  568. {
  569. pos.direction.y = Convert.ToDouble(parts[5], provider);
  570. }
  571. } else {
  572. // misformatted data, return 0 filled position
  573. Console.WriteLine("Misformated position");
  574. }
  575. return pos;
  576. }
  577. }
  578. }