/elekIOaux/shipdata.c

http://github.com/Yniold/liftsrc · C · 509 lines · 340 code · 79 blank · 90 comment · 57 complexity · 811a24c5c5b5ffbbcf244e2a87e9c74d MD5 · raw file

  1. // ============================================
  2. // shipdata.c
  3. // ShipData Control Thread
  4. // ============================================
  5. //
  6. // $RCSfile: shipdata.c,v $ last changed on $Date: 2007/07/12 17:18:44 $ by $Author: rudolf $
  7. //
  8. // History:
  9. //
  10. // $Log: shipdata.c,v $
  11. // Revision 1.7 2007/07/12 17:18:44 rudolf
  12. // corrected include file order
  13. //
  14. // Revision 1.6 2007-03-10 18:09:30 rudolf
  15. // fixed lat and longitude swapped
  16. //
  17. // Revision 1.5 2007-03-08 18:53:23 rudolf
  18. // made fields flash green if new data received, cosmetics
  19. //
  20. // Revision 1.4 2007-03-08 14:01:22 rudolf
  21. // cleaned up unused ports
  22. //
  23. // Revision 1.3 2007-03-07 18:11:28 rudolf
  24. // fixed nasty locking bug
  25. //
  26. // Revision 1.2 2007-03-07 17:14:04 rudolf
  27. // more work on parser
  28. //
  29. // Revision 1.1 2007-03-05 20:48:09 rudolf
  30. // added thread for collecting ship's data, more work on parser
  31. //
  32. //
  33. //
  34. //
  35. //
  36. //#define DEBUG_MUTEX
  37. //#define DEBUG
  38. //#define DEBUG_SETPOS
  39. #undef DEBUG
  40. #undef DEBUG_SETPOS
  41. #undef DEBUG_MUTEX
  42. #include <stdint.h>
  43. #include <pthread.h>
  44. #include <sys/socket.h>
  45. #include <sys/types.h>
  46. #include <errno.h>
  47. #include <signal.h>
  48. #include <ncurses.h>
  49. #include "../include/elekGeneral.h"
  50. #include "../include/elekIO.h"
  51. #include "../include/elekIOPorts.h"
  52. #include "../commTools/udptools.h"
  53. #include "shipdata.h"
  54. extern bool bEnableGUI;
  55. extern WINDOW* pStatusWin;
  56. extern struct MessagePortType MessageOutPortList[];
  57. typedef void Sigfunc (int);
  58. static void dummy_handler(int signo)
  59. {
  60. return;
  61. };
  62. enum OutPortListEnum
  63. {
  64. // this list has to be coherent with MessageOutPortList
  65. ELEK_DEBUG_OUT, // port for outgoing messages to debug
  66. ELEK_MANUAL_OUT, // reverse port for answers to eCmd
  67. ELEK_ELEKIO_AUX_MASTER_OUT, // port for outgoing data packets from elekAux to master
  68. MAX_MESSAGE_OUTPORTS
  69. };
  70. // Variables
  71. //
  72. //typedef void Sigfunc (int);
  73. // the thread works on this structure
  74. //
  75. struct sShipDataType sShipDataThread =
  76. {
  77. .iFD = -1, /* socket FD */
  78. };
  79. pthread_mutex_t mShipDataMutex;
  80. // bind to socket and create the parser thread
  81. //
  82. int ShipDataInit(void)
  83. {
  84. int iRetCode;
  85. pthread_t ptShipDataThread;
  86. // init mutex before creating thread
  87. pthread_mutex_init(&mShipDataMutex,NULL);
  88. iRetCode = pthread_create(&ptShipDataThread, NULL, (void*)&ShipDataThreadFunc,(void*) &sShipDataThread);
  89. if(iRetCode > 0)
  90. {
  91. extern struct MessagePortType MessageOutPortList[];
  92. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],"elekIOaux : thread create failed");
  93. printf("In ShipDataInit(): pthread_create failed!\n\r");
  94. return (1);
  95. };
  96. signal(SIGALRM, dummy_handler);
  97. return(0);
  98. };
  99. // thread code
  100. //
  101. void ShipDataThreadFunc(void* pArgument)
  102. {
  103. // buffer for one line
  104. char aUDPBuffer[1024];
  105. extern struct MessagePortType MessageOutPortList[];
  106. int iRetVal;
  107. char cTheChar;
  108. char *pTheBuffer = aUDPBuffer;
  109. int iNumChars;
  110. // socket structure
  111. struct sockaddr_in ServerAddress;
  112. // shared structure
  113. struct sShipDataType *sStructure = (struct sShipDataType *) pArgument;
  114. while(1)
  115. {
  116. // try to connect till success
  117. while(1)
  118. {
  119. // create SocketFD
  120. sStructure->iFD = socket(AF_INET, SOCK_DGRAM, 0);
  121. memset(&ServerAddress,0, sizeof(ServerAddress));
  122. // fill out structure for connection to XPORT
  123. ServerAddress.sin_family = AF_INET;
  124. ServerAddress.sin_port = htons(3040);
  125. ServerAddress.sin_addr.s_addr = htonl(INADDR_ANY);
  126. // try connection to XPORT using a timeout
  127. if((iRetVal = bind(sStructure->iFD, (const struct sockaddr*)&ServerAddress, sizeof(ServerAddress))) < 0)
  128. {
  129. close(sStructure->iFD);
  130. if(errno == EINTR)
  131. errno = ETIMEDOUT;
  132. }
  133. else
  134. {
  135. break;
  136. };
  137. };
  138. if(iRetVal < 0)
  139. printf("%s\r\n",strerror(errno));
  140. else
  141. {
  142. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],"elekIOaux : bound to ship's broadcast data");
  143. if(bEnableGUI)
  144. {
  145. wprintw(pStatusWin,"Bound to ship's broadcast data\n");
  146. wrefresh(pStatusWin);
  147. }
  148. else
  149. printf("elekIOaux : bound to ship's broadcast data\r\n");
  150. };
  151. while(true)
  152. {
  153. // clear buffer
  154. memset(aUDPBuffer,0,1023);
  155. if( (iRetVal = recvfrom(sStructure->iFD,aUDPBuffer,1023,0,NULL,NULL)) < 0)
  156. {
  157. if(errno == EINTR)
  158. printf("elekIOaux : socket timeout\r\n");
  159. else
  160. printf("recvfrom() error\r\n");
  161. }
  162. // we got data in time
  163. else
  164. {
  165. // strncmp may fail with shorter strings
  166. if(iRetVal > 5)
  167. {
  168. if(strncmp(aUDPBuffer,"@GPS1",5) == 0)
  169. {
  170. ShipDataParseGPSBuffer(aUDPBuffer,iRetVal,sStructure);
  171. };
  172. if(strncmp(aUDPBuffer,"@MTS1",5) == 0)
  173. {
  174. ShipDataParseWaterBuffer(aUDPBuffer,iRetVal,sStructure);
  175. };
  176. if(strncmp(aUDPBuffer,"@ESFB",5) == 0)
  177. {
  178. ShipDataParseSonarBuffer(aUDPBuffer,iRetVal,sStructure);
  179. };
  180. if(strncmp(aUDPBuffer,"@GYR1",5) == 0)
  181. {
  182. ShipDataParseGyroBuffer(aUDPBuffer,iRetVal,sStructure);
  183. };
  184. if(strncmp(aUDPBuffer,"@GIL1",5) == 0)
  185. {
  186. ShipDataParseAnemoBuffer(aUDPBuffer,iRetVal,sStructure);
  187. };
  188. };
  189. // printf("%s\r\n",aUDPBuffer);
  190. };
  191. };
  192. };
  193. printf("Trying to reconnect!\r\n");
  194. close(sStructure->iFD);
  195. };
  196. void ShipDataParseGPSBuffer(char* pBuffer, int iBuffLen, struct sShipDataType* sDataStructure)
  197. {
  198. char* pRetVal;
  199. int iTokenNumber=0;
  200. char* pContext;
  201. // use thread safe version here...
  202. pRetVal = strtok_r(pBuffer,",",&pContext);
  203. //write(2,"ShipDataParseGPSBuffer: before lock\n\r",sizeof("ShipDataParseGPSBuffer: before lock\n\r"));
  204. pthread_mutex_lock(&mShipDataMutex);
  205. //write(2,"ShipDataParseGPSBuffer: after lock\n\r",sizeof("ShipDataParseGPSBuffer: after lock\n\r"));
  206. while(true)
  207. {
  208. if(pRetVal != NULL)
  209. {
  210. iTokenNumber++;
  211. switch(iTokenNumber)
  212. {
  213. case 3:
  214. {
  215. unsigned int uiTime = atoi(pRetVal);
  216. sDataStructure->ucUTCHours = uiTime / 10000;
  217. sDataStructure->ucUTCMins = (uiTime - (sDataStructure->ucUTCHours * 10000)) / 100;
  218. sDataStructure->ucUTCSeconds = (uiTime -(sDataStructure->ucUTCHours * 10000)-(sDataStructure->ucUTCMins*100));
  219. }
  220. case 4:
  221. sDataStructure->ucUTCDay = atoi(pRetVal);
  222. case 5:
  223. sDataStructure->ucUTCMonth = atoi(pRetVal);
  224. case 6:
  225. sDataStructure->uiUTCYear = atoi(pRetVal);
  226. case 7:
  227. sDataStructure->dLatitude= strtod(pRetVal,NULL);
  228. case 8:
  229. if(pRetVal[0] == 'S')
  230. sDataStructure->dLatitude= -sDataStructure->dLatitude;
  231. case 9:
  232. sDataStructure->dLongitude= strtod(pRetVal,NULL);
  233. case 10:
  234. if(pRetVal[0] == 'W')
  235. sDataStructure->dLongitude = -sDataStructure->dLongitude;
  236. case 11:
  237. sDataStructure->dCourseOverGround= strtod(pRetVal,NULL);
  238. case 12:
  239. sDataStructure->dGroundSpeed= strtod(pRetVal,NULL);
  240. default:
  241. break;
  242. };
  243. pRetVal=strtok_r(NULL,",",&pContext);
  244. }
  245. else
  246. break;
  247. };
  248. sDataStructure->Valid.Field.ShipGPSDataValid = 1;
  249. //write(2,"ShipDataParseGPSBuffer: before unlock\n\r",sizeof("ShipDataParseGPSBuffer: before unlock\n\r"));
  250. pthread_mutex_unlock(&mShipDataMutex);
  251. //write(2,"ShipDataParseGPSBuffer: after unlock\n\r",sizeof("ShipDataParseGPSBuffer: after unlock\n\r"));
  252. if(gPlotData)
  253. {
  254. printf("GPS Time:(UTC) %02d:%02d:%02d\r\n",sDataStructure->ucUTCHours,sDataStructure->ucUTCMins,sDataStructure->ucUTCSeconds);
  255. printf("GPS Date: %02d.%02d.%04d\r\n",sDataStructure->ucUTCDay,sDataStructure->ucUTCMonth,sDataStructure->uiUTCYear);
  256. printf("GPS Longitude: %09.6f\r\n",sDataStructure->dLongitude);
  257. printf("GPS Latitude: %09.6f\r\n",sDataStructure->dLatitude);
  258. printf("GPS Course: %04.2f\r\n",sDataStructure->dCourseOverGround);
  259. printf("GPS Speed: %04.2f\r\n\r\n",sDataStructure->dGroundSpeed);
  260. };
  261. };
  262. void ShipDataParseWaterBuffer(char* pBuffer, int iBuffLen, struct sShipDataType* sDataStructure)
  263. {
  264. char* pRetVal;
  265. int iTokenNumber=0;
  266. char* pContext;
  267. // use thread safe version here...
  268. pRetVal = strtok_r(pBuffer,",",&pContext);
  269. //write(2,"ShipDataParseWaterBuffer: before lock\n\r",sizeof("ShipDataParseWaterBuffer: before lock\n\r"));
  270. pthread_mutex_lock(&mShipDataMutex);
  271. //write(2,"ShipDataParseWaterBuffer: after lock\n\r",sizeof("ShipDataParseWaterBuffer: after lock\n\r"));
  272. while(true)
  273. {
  274. if(pRetVal != NULL)
  275. {
  276. iTokenNumber++;
  277. switch(iTokenNumber)
  278. {
  279. case 2:
  280. if(pRetVal[0] == 'P')
  281. {
  282. //write(2,"ShipDataParseWaterBuffer: before unlock (return)\n\r",sizeof("ShipDataParseWaterBuffer: before unlock (return)\n\r"));
  283. pthread_mutex_unlock(&mShipDataMutex);
  284. //write(2,"ShipDataParseWaterBuffer: after unlock (return)\n\r",sizeof("ShipDataParseWaterBuffer: after unlock (return)\n\r"));
  285. return;
  286. };
  287. case 3:
  288. sDataStructure->dWaterTemp = strtod(pRetVal,NULL);
  289. case 5:
  290. sDataStructure->dSalinity = strtod(pRetVal,NULL);
  291. default:
  292. break;
  293. };
  294. pRetVal=strtok_r(NULL,",",&pContext);
  295. }
  296. else
  297. break;
  298. };
  299. sDataStructure->Valid.Field.ShipWaterDataValid = 1;
  300. //write(2,"ShipDataParseWaterBuffer: before unlock\n\r",sizeof("ShipDataParseWaterBuffer: before unlock\n\r"));
  301. pthread_mutex_unlock(&mShipDataMutex);
  302. //write(2,"ShipDataParseWaterBuffer: after unlock\n\r",sizeof("ShipDataParseWaterBuffer: after unlock\n\r"));
  303. if(gPlotData)
  304. {
  305. printf("Water Temperature: %04.2f\r\n",sDataStructure->dWaterTemp);
  306. printf("Water Salinity: %04.2f\r\n\r\n",sDataStructure->dSalinity);
  307. };
  308. };
  309. void ShipDataParseSonarBuffer(char* pBuffer, int iBuffLen, struct sShipDataType* sDataStructure)
  310. {
  311. char* pRetVal;
  312. int iTokenNumber=0;
  313. char* pContext;
  314. //thread safe version here...
  315. pRetVal = strtok_r(pBuffer,",",&pContext);
  316. //write(2,"ShipDataParseSonarBuffer: before lock\n\r",sizeof("ShipDataParseSonarBuffer: before lock\n\r"));
  317. pthread_mutex_lock(&mShipDataMutex);
  318. //write(2,"ShipDataParseSonarBuffer: after lock\n\r",sizeof("ShipDataParseSonarBuffer: after lock\n\r"));
  319. while(true)
  320. {
  321. if(pRetVal != NULL)
  322. {
  323. iTokenNumber++;
  324. switch(iTokenNumber)
  325. {
  326. case 3:
  327. if(strncmp(pRetVal, "#SF11SBP",8) != 0)
  328. {
  329. //write(2,"ShipDataParseSonarBuffer: before unlock (return)\n\r",sizeof("ShipDataParseSonarBuffer: before unlock (return)\n\r"));
  330. pthread_mutex_unlock(&mShipDataMutex);
  331. //write(2,"ShipDataParseSonarBuffer: after unlock (return)\n\r",sizeof("ShipDataParseSonarBuffer: after unlock (return)\n\r"));
  332. return;
  333. };
  334. case 8:
  335. sDataStructure->dFrequency = strtod(pRetVal,NULL);
  336. case 10:
  337. sDataStructure->dWaterDepth = strtod(pRetVal,NULL);
  338. default:
  339. break;
  340. };
  341. pRetVal=strtok_r(NULL,",",&pContext);
  342. }
  343. else
  344. break;
  345. };
  346. sDataStructure->Valid.Field.ShipSonarDataValid = 1;
  347. //write(2,"ShipDataParseSonarBuffer: before unlock\n\r",sizeof("ShipDataParseSonarBuffer: before unlock\n\r"));
  348. pthread_mutex_unlock(&mShipDataMutex);
  349. //write(2,"ShipDataParseSonarBuffer: after unlock\n\r",sizeof("ShipDataParseSonarBuffer: after unlock\n\r"));
  350. if(gPlotData)
  351. {
  352. printf("Water Depth: %06.2f\r\n\r\n",sDataStructure->dWaterDepth);
  353. };
  354. };
  355. void ShipDataParseGyroBuffer(char* pBuffer, int iBuffLen, struct sShipDataType* sDataStructure)
  356. {
  357. char* pRetVal;
  358. int iTokenNumber=0;
  359. char* pContext;
  360. // use thread safe version here...
  361. pRetVal = strtok_r(pBuffer,",",&pContext);
  362. //write(2,"ShipDataParseGyroBuffer: before lock\n\r",sizeof("ShipDataParseGyroBuffer: before lock\n\r"));
  363. pthread_mutex_lock(&mShipDataMutex);
  364. //write(2,"ShipDataParseGyroBuffer: after lock\n\r",sizeof("ShipDataParseGyroBuffer: after lock\n\r"));
  365. while(true)
  366. {
  367. if(pRetVal != NULL)
  368. {
  369. iTokenNumber++;
  370. //printf("Token %02d is '%s'\r\n",iTokenNumber,pRetVal);
  371. switch(iTokenNumber)
  372. {
  373. case 3:
  374. sDataStructure->dDirection = strtod(pRetVal,NULL);
  375. default:
  376. break;
  377. };
  378. pRetVal=strtok_r(NULL,",",&pContext);
  379. }
  380. else
  381. break;
  382. };
  383. sDataStructure->Valid.Field.ShipGyroDataValid = 1;
  384. //write(2,"ShipDataParseGyroBuffer: before unlock\n\r",sizeof("ShipDataParseGyroBuffer: before unlock\n\r"));
  385. pthread_mutex_unlock(&mShipDataMutex);
  386. //write(2,"ShipDataParseGyroBuffer: after unlock\n\r",sizeof("ShipDataParseGyroBuffer: after unlock\n\r"));
  387. if(gPlotData)
  388. {
  389. printf("Gyro Heading: %06.2f\r\n\r\n",sDataStructure->dDirection);
  390. };
  391. };
  392. void ShipDataParseAnemoBuffer(char* pBuffer, int iBuffLen, struct sShipDataType* sDataStructure)
  393. {
  394. char* pRetVal;
  395. int iTokenNumber=0;
  396. char* pContext;
  397. // use thread safe version here...
  398. pRetVal = strtok_r(pBuffer,",",&pContext);
  399. //write(2,"ShipDataParseAnemoBuffer: before lock\n\r",sizeof("ShipDataParseAnemoBuffer: before lock\n\r"));
  400. pthread_mutex_lock(&mShipDataMutex);
  401. //write(2,"ShipDataParseAnemoBuffer: after lock\n\r",sizeof("ShipDataParseAnemoBuffer: after lock\n\r"));
  402. while(true)
  403. {
  404. if(pRetVal != NULL)
  405. {
  406. iTokenNumber++;
  407. switch(iTokenNumber)
  408. {
  409. case 3:
  410. sDataStructure->dWindDirection = strtod(pRetVal,NULL);
  411. case 4:
  412. sDataStructure->dWindSpeed = strtod(pRetVal,NULL);
  413. default:
  414. break;
  415. };
  416. pRetVal=strtok_r(NULL,",",&pContext);
  417. }
  418. else
  419. break;
  420. };
  421. sDataStructure->Valid.Field.ShipMeteoDataValid = 1;
  422. //write(2,"ShipDataParseAnemoBuffer: before unlock\n\r",sizeof("ShipDataParseAnemoBuffer: before unlock\n\r"));
  423. pthread_mutex_unlock(&mShipDataMutex);
  424. //write(2,"ShipDataParseAnemoBuffer: after unlock\n\r",sizeof("ShipDataParseAnemoBuffer: after unlock\n\r"));
  425. if(gPlotData)
  426. {
  427. printf("Wind Direction: %06.2f\r\n",sDataStructure->dWindDirection);
  428. printf("Wind Speed: %06.2f\r\n\r\n",sDataStructure->dWindSpeed);
  429. };
  430. };