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

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