/elekIOaux/elekIOaux.c

http://github.com/Yniold/liftsrc · C · 1075 lines · 703 code · 190 blank · 182 comment · 50 complexity · 2c7d02ee4583b668df60b844faa32e64 MD5 · raw file

  1. /*
  2. * $RCSfile: elekIOaux.c,v $ last changed on $Date: 2007/03/11 11:17:36 $ by $Author: rudolf $
  3. *
  4. * $Log: elekIOaux.c,v $
  5. * Revision 1.9 2007/03/11 11:17:36 rudolf
  6. * put timestamp to structure
  7. *
  8. * Revision 1.8 2007-03-10 14:34:49 rudolf
  9. * broadcasting data on Port 1180
  10. *
  11. * Revision 1.7 2007-03-08 18:53:23 rudolf
  12. * made fields flash green if new data received, cosmetics
  13. *
  14. * Revision 1.6 2007-03-08 14:01:22 rudolf
  15. * cleaned up unused ports
  16. *
  17. * Revision 1.5 2007-03-07 21:13:54 rudolf
  18. * startet work on ncurses based GUI
  19. *
  20. * Revision 1.4 2007-03-07 18:11:28 rudolf
  21. * fixed nasty locking bug
  22. *
  23. * Revision 1.3 2007-03-05 20:48:09 rudolf
  24. * added thread for collecting ship's data, more work on parser
  25. *
  26. * Revision 1.2 2007-03-04 19:28:41 rudolf
  27. * added parsing for data into the right structure elements
  28. *
  29. * Revision 1.1 2007-03-04 13:41:59 rudolf
  30. * created new server for auxilliary data like weather data, ships GPS etc
  31. *
  32. *
  33. *
  34. */
  35. #define VERSION 0.1
  36. #define POSIX_SOURCE 1
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <unistd.h>
  40. #include <time.h>
  41. #include <string.h>
  42. #include <sys/types.h>
  43. #include <sys/socket.h>
  44. #include <sys/time.h>
  45. #include <sys/select.h>
  46. #include <netinet/in.h>
  47. #include <arpa/inet.h>
  48. #include <netdb.h>
  49. #include <ctype.h> /*for NAN*/
  50. #include <stdlib.h>
  51. #include <math.h>
  52. #include <signal.h>
  53. #include <errno.h>
  54. #include <sched.h>
  55. #include <pthread.h>
  56. #include <ncurses.h> /* ncurses.h includes stdio.h */
  57. #include "../include/elekGeneral.h"
  58. #include "../include/elekIO.h"
  59. #include "../include/elekIOPorts.h"
  60. #include "elekIOaux.h"
  61. #include "meteobox.h"
  62. #include "shipdata.h"
  63. #define STATUS_INTERVAL 200
  64. #define DEBUGLEVEL 0
  65. #undef DEBUG_TIMER
  66. #define CPUCLOCK 500000000UL // CPU clock of Markus' Athlon XP
  67. // #define DEBUG_STRUCTUREPASSING
  68. //
  69. char gPlotData = 0; // this is not a define, it's meant to be replaced by a commandline arg in the future
  70. enum InPortListEnum
  71. {
  72. // this list has to be coherent with MessageInPortList
  73. ELEK_MANUAL_IN, // port for incoming commands from eCmd
  74. MAX_MESSAGE_INPORTS
  75. };
  76. enum OutPortListEnum
  77. {
  78. // this list has to be coherent with MessageOutPortList
  79. ELEK_DEBUG_OUT, // port for outgoing messages to debug
  80. ELEK_MANUAL_OUT, // reverse port for answers to eCmd
  81. ELEK_ELEKIO_AUX_MASTER_OUT, // port for outgoing data packets from elekAux to master
  82. MAX_MESSAGE_OUTPORTS
  83. };
  84. struct MessagePortType MessageInPortList[MAX_MESSAGE_INPORTS]=
  85. {
  86. // order in list defines sequence of polling
  87. /* Name , PortNo , ReversePort , IPAddr , fdSocket, MaxMsg, Direction */
  88. {"Manual" , UDP_ELEK_MANUAL_INPORT , ELEK_MANUAL_OUT, IP_LOCALHOST, -1, 1, UDP_IN_PORT}
  89. };
  90. struct MessagePortType MessageOutPortList[MAX_MESSAGE_OUTPORTS]=
  91. {
  92. // order in list defines sequence of polling
  93. /* Name ,PortNo , ReversePort , IPAddr , fdSocket, MaxMsg, Direction */
  94. {"DebugPort" ,UDP_ELEK_DEBUG_OUTPORT , -1 , IP_DEBUG_CLIENT , -1 , 0 , UDP_OUT_PORT},
  95. {"Manual" ,UDP_ELEK_MANUAL_OUTPORT , ELEK_MANUAL_IN , IP_LOCALHOST , -1 , 0 , UDP_OUT_PORT},
  96. {"ElekIOauxOut" ,UDP_ELEK_AUX_INPORT , -1 , "255.255.255.255", -1 , 0 , UDP_OUT_PORT}
  97. };
  98. struct TaskListType TasktoWakeList[MAX_TASKS_TO_WAKE]=
  99. {
  100. // order defines sequence of wake up after timer
  101. /* TaskName TaskConn TaskWantStatusOnPort */
  102. { "", -1, -1},
  103. { "", -1, -1},
  104. { "", -1, -1}
  105. };
  106. /**********************************************************************************************************/
  107. /* NCURSES STUFF */
  108. /**********************************************************************************************************/
  109. bool bEnableGUI;
  110. WINDOW* pGPSWin;
  111. WINDOW* pMeteoBoxWin;
  112. WINDOW* pWaterWin;
  113. WINDOW* pSonarWin;
  114. WINDOW* pGyroWin;
  115. WINDOW* pAnemoWin;
  116. WINDOW* pStatusBorderWin; // we create a dummy window just containing the border, so we can use wprintw
  117. // without needing to set the x position to 1 each time
  118. WINDOW* pStatusWin;
  119. /**********************************************************************************************************/
  120. /* Signal Handler */
  121. /**********************************************************************************************************/
  122. static int StatusFlag=0;
  123. static enum TimerSignalStateEnum TimerState=TIMER_SIGNAL_STATE_INITIAL;
  124. /* Signalhandler */
  125. void signalstatus(int signo)
  126. {
  127. /* locale variables for Timer*/
  128. extern int StatusFlag;
  129. extern enum TimerSignalStateEnum TimerState;
  130. char buf[GENERIC_BUF_LEN];
  131. ++StatusFlag;
  132. TimerState=(TimerState+1) % TIMER_SIGNAL_STATE_MAX;
  133. }
  134. //
  135. /**********************************************************************************************************/
  136. /* Load Module Config */
  137. /**********************************************************************************************************/
  138. /* function to load the config settings for all modules */
  139. void LoadModulesConfig(struct auxStatusType *ptrAuxStatus)
  140. {
  141. extern struct MessagePortType MessageInPortList[];
  142. extern struct MessagePortType MessageOutPortList[];
  143. int i;
  144. int Channel;
  145. int Card;
  146. char buf[GENERIC_BUF_LEN];
  147. // set all data to invalid
  148. ptrAuxStatus->Status.Status.Word = 0;
  149. };
  150. /**********************************************************************************************************/
  151. /* Init METEOBOX */
  152. /**********************************************************************************************************/
  153. int InitMeteoBox(struct auxStatusType *ptrAuxStatus)
  154. {
  155. extern struct MessagePortType MessageInPortList[];
  156. extern struct MessagePortType MessageOutPortList[];
  157. char debugbuf[GENERIC_BUF_LEN];
  158. int ret;
  159. // create butterfly thread
  160. ret = MeteoBoxInit();
  161. if(ret == 1)
  162. {
  163. sprintf(debugbuf,"elekIOaux : Can't create MeteoBox Thread!\n\r");
  164. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],debugbuf);
  165. return (INIT_MODULE_FAILED);
  166. };
  167. // success
  168. sprintf(debugbuf,"elekIOaux: MeteoBox Thread running!\n\r");
  169. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],debugbuf);
  170. return (INIT_MODULE_SUCCESS);
  171. }
  172. /* Init MeteoBox */
  173. /**********************************************************************************************************/
  174. /* Init ShipData */
  175. /**********************************************************************************************************/
  176. int InitShipData(struct auxStatusType *ptrAuxStatus)
  177. {
  178. extern struct MessagePortType MessageInPortList[];
  179. extern struct MessagePortType MessageOutPortList[];
  180. char debugbuf[GENERIC_BUF_LEN];
  181. int ret;
  182. // create ShipData thread
  183. ret = ShipDataInit();
  184. if(ret == 1)
  185. {
  186. sprintf(debugbuf,"elekIOaux : Can't create ShipData Thread!\n\r");
  187. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],debugbuf);
  188. return (INIT_MODULE_FAILED);
  189. };
  190. // success
  191. sprintf(debugbuf,"elekIOaux : ShipData Thread running!\n\r");
  192. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],debugbuf);
  193. return (INIT_MODULE_SUCCESS);
  194. }
  195. /* InitShipData */
  196. /**********************************************************************************************************/
  197. /* Init Modules */
  198. /**********************************************************************************************************/
  199. /* function to initialize all Modules */
  200. void InitModules(struct auxStatusType *ptrAuxStatus)
  201. {
  202. extern struct MessagePortType MessageInPortList[];
  203. extern struct MessagePortType MessageOutPortList[];
  204. int ret;
  205. char buf[GENERIC_BUF_LEN];
  206. LoadModulesConfig(ptrAuxStatus);
  207. if (INIT_MODULE_SUCCESS == (ret=InitMeteoBox(ptrAuxStatus)))
  208. {
  209. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],"elekIOaux : init MeteoBox successfull");
  210. }
  211. else
  212. {
  213. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],"elekIOaux : init MeteoBox failed !!");
  214. }
  215. if (INIT_MODULE_SUCCESS == (ret=InitShipData(ptrAuxStatus)))
  216. {
  217. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],"elekIOaux : init ShipData successfull");
  218. }
  219. else
  220. {
  221. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],"elekIOaux : init ShipData failed !!");
  222. }
  223. }
  224. /* InitModules */
  225. /**********************************************************************************************************/
  226. /* GetMeteoBoxData */
  227. /**********************************************************************************************************/
  228. void GetMeteoBoxData ( struct auxStatusType *ptrAuxStatus)
  229. {
  230. extern struct MessagePortType MessageInPortList[];
  231. extern struct MessagePortType MessageOutPortList[];
  232. extern pthread_mutex_t mMeteoBoxMutex;
  233. extern struct sMeteoType sMeteoThread;
  234. uint16_t ret;
  235. uint16_t Control;
  236. char buf[GENERIC_BUF_LEN];
  237. {
  238. //write(2,"GetMeteo: before lock\n\r",sizeof("GetMeteo: before lock\n\r"));
  239. pthread_mutex_lock(&mMeteoBoxMutex);
  240. //write(2,"GetMeteo: after lock\n\r",sizeof("GetMeteo: after lock\n\r"));
  241. // pthread_mutex_lock(&mMeteoBoxMutex);
  242. ptrAuxStatus->Status.Status.Word = ptrAuxStatus->Status.Status.Word | sMeteoBoxThread.Valid.Word; /* will copy only bits set to one*/
  243. sMeteoBoxThread.Valid.Word = 0;
  244. ptrAuxStatus->MeteoBox.dWindSpeed = sMeteoBoxThread.dWindSpeed; /* Windspeed in m/s */
  245. ptrAuxStatus->MeteoBox.uiWindDirection = sMeteoBoxThread.uiWindDirection; /* 45° resolution */
  246. ptrAuxStatus->MeteoBox.dRelHum = sMeteoBoxThread.dRelHum; /* 000.0 - 100.0 % */
  247. ptrAuxStatus->MeteoBox.dAirTemp = sMeteoBoxThread.dAirTemp; /* Temperature in degree celsius */
  248. ptrAuxStatus->MeteoBox.dGasSensorVoltage = sMeteoBoxThread.dGasSensorVoltage; /* dirt sensor */
  249. //write(2,"GetMeteo: before unlock\n\r",sizeof("GetMeteo: before unlock\n\r"));
  250. pthread_mutex_unlock(&mMeteoBoxMutex);
  251. //write(2,"GetMeteo: after unlock\n\r",sizeof("GetMeteo: after unlock\n\r"));
  252. // pthread_mutex_unlock(&mMeteoBoxMutex);
  253. #ifdef DEBUG_STRUCTUREPASSING
  254. printf("ptrAuxStatus->MeteoBox.dWindSpeed: %04.2f\n\r",ptrAuxStatus->MeteoBox.dWindSpeed);
  255. printf("ptrAuxStatus->MeteoBox.uiWindDirection: %03d\n\r",ptrAuxStatus->MeteoBox.uiWindDirection);
  256. printf("ptrAuxStatus->MeteoBox.dRelHum: %04.2f\n\r",ptrAuxStatus->MeteoBox.dRelHum);
  257. printf("ptrAuxStatus->MeteoBox.dAirTemp: %+04.2f\n\r",ptrAuxStatus->MeteoBox.dAirTemp);
  258. printf("ptrAuxStatus->MeteoBox.dGasSensorVoltage: %05.3f\n\r",ptrAuxStatus->MeteoBox.dGasSensorVoltage);
  259. #endif
  260. }
  261. }
  262. /* GetMeteoBoxData */
  263. /**********************************************************************************************************/
  264. /* GetShipData */
  265. /**********************************************************************************************************/
  266. void GetShipData ( struct auxStatusType *ptrAuxStatus)
  267. {
  268. extern struct MessagePortType MessageInPortList[];
  269. extern struct MessagePortType MessageOutPortList[];
  270. extern pthread_mutex_t mShipDataMutex;
  271. extern struct sShipDataType sShipDataThread;
  272. uint16_t ret;
  273. uint16_t Control;
  274. char buf[GENERIC_BUF_LEN];
  275. {
  276. // pthread_mutex_lock(&mShipDataMutex);
  277. //write(2,"GetShip: before lock\n\r",sizeof("GetShip: before lock\n\r"));
  278. pthread_mutex_lock(&mShipDataMutex);
  279. //write(2,"GetShip: after lock\n\r",sizeof("GetShip: after lock\n\r"));
  280. ptrAuxStatus->Status.Status.Word = ptrAuxStatus->Status.Status.Word | sShipDataThread.Valid.Word; /* will copy only bits set to one*/
  281. sShipDataThread.Valid.Word = 0;
  282. ptrAuxStatus->ShipGPS.ucUTCHours = sShipDataThread.ucUTCHours; /* binary, not BCD coded (!) 0 - 23 decimal*/
  283. ptrAuxStatus->ShipGPS.ucUTCMins = sShipDataThread.ucUTCMins; /* binary, 0-59 decimal */
  284. ptrAuxStatus->ShipGPS.ucUTCSeconds = sShipDataThread.ucUTCSeconds; /* binary 0-59 decimal */
  285. ptrAuxStatus->ShipGPS.ucUTCDay = sShipDataThread.ucUTCDay; /* day 1-31 */
  286. ptrAuxStatus->ShipGPS.ucUTCMonth = sShipDataThread.ucUTCMonth; /* month 1-12 */
  287. ptrAuxStatus->ShipGPS.uiUTCYear = sShipDataThread.uiUTCYear; /* year 4 digits */
  288. ptrAuxStatus->ShipGPS.dLongitude = sShipDataThread.dLongitude; /* "Laengengrad" I always mix it up...
  289. * signed notation,
  290. * negative values mean "W - west of Greenwich"
  291. * positive values mean "E - east of Greenwich" */
  292. ptrAuxStatus->ShipGPS.dLatitude = sShipDataThread.dLatitude; /* "Breitengrad" I always mix it up...
  293. * signed notation,
  294. * negative values mean "S - south of the equator"
  295. * positive values mean "N - north of the equator*/
  296. ptrAuxStatus->ShipGPS.dGroundSpeed = sShipDataThread.dGroundSpeed; /* speed in knots above ground */
  297. ptrAuxStatus->ShipGPS.dCourseOverGround = sShipDataThread.dCourseOverGround; /* heading in degrees */
  298. ptrAuxStatus->ShipWater.dSalinity = sShipDataThread.dSalinity; /* gramms per litre */
  299. ptrAuxStatus->ShipWater.dWaterTemp = sShipDataThread.dWaterTemp; /* water temp in degrees celsius */
  300. ptrAuxStatus->ShipMeteo.dWindSpeed = sShipDataThread.dWindSpeed; /* m/s */
  301. ptrAuxStatus->ShipMeteo.dWindDirection = sShipDataThread.dWindDirection; /* in degrees relative to ship ??? */
  302. ptrAuxStatus->ShipSonar.dFrequency = sShipDataThread.dFrequency; /* Khz */
  303. ptrAuxStatus->ShipSonar.dWaterDepth = sShipDataThread.dWaterDepth; /* m */
  304. ptrAuxStatus->ShipGyro.dDirection = sShipDataThread.dDirection; /* degrees */
  305. //write(2,"GetShip: before unlock\n\r",sizeof("GetShip: before unlock\n\r"));
  306. pthread_mutex_unlock(&mShipDataMutex);
  307. //write(2,"GetShip: after unlock\n\r",sizeof("GetShip: after unlock\n\r"));
  308. // pthread_mutex_unlock(&mShipDataMutex);
  309. #ifdef DEBUG_STRUCTUREPASSING
  310. printf("ptrAuxStatus->ShipGPS.ucUTCHours: %02d\n\r",ptrAuxStatus->ShipGPS.ucUTCHours);
  311. printf("ptrAuxStatus->ShipGPS.ucUTCMins: %02d\n\r",ptrAuxStatus->ShipGPS.ucUTCMins);
  312. printf("ptrAuxStatus->ShipGPS.ucUTCSeconds: %02d\n\r",ptrAuxStatus->ShipGPS.ucUTCSeconds);
  313. printf("ptrAuxStatus->ShipGPS.ucUTCDay: %02d\n\r",ptrAuxStatus->ShipGPS.ucUTCDay);
  314. printf("ptrAuxStatus->ShipGPS.ucUTCMonth: %02d\n\r",ptrAuxStatus->ShipGPS.ucUTCMonth);
  315. printf("ptrAuxStatus->ShipGPS.uiUTCYear: %04d\n\r",ptrAuxStatus->ShipGPS.uiUTCYear);
  316. printf("ptrAuxStatus->ShipGPS.dLongitude: %+06.4f\n\r",ptrAuxStatus->ShipGPS.dLongitude);
  317. printf("ptrAuxStatus->ShipGPS.dLatitude: %+06.4f\n\r",ptrAuxStatus->ShipGPS.dLatitude);
  318. printf("ptrAuxStatus->ShipGPS.dGroundSpeed: %-5.2f\n\r",ptrAuxStatus->ShipGPS.dGroundSpeed);
  319. printf("ptrAuxStatus->ShipGPS.dCourseOverGround: %-6.2f\n\r",ptrAuxStatus->ShipGPS.dCourseOverGround);
  320. printf("ptrAuxStatus->ShipWater.dSalinity: %04.2f\n\r",ptrAuxStatus->ShipWater.dSalinity);
  321. printf("ptrAuxStatus->ShipWater.dWaterTemp: %04.2f\n\r",ptrAuxStatus->ShipWater.dWaterTemp);
  322. printf("ptrAuxStatus->Status.Status.Word: %04x\n\r",ptrAuxStatus->Status.Status.Word);
  323. ptrAuxStatus->Status.Status.Word = 0;
  324. #endif
  325. }
  326. }
  327. /* GetShipData */
  328. /**********************************************************************************************************/
  329. /* GetAuxStatus */
  330. /**********************************************************************************************************/
  331. /* function to retrieve Statusinformation */
  332. void GetAuxStatus ( struct auxStatusType *ptrAuxStatus, int IsMaster)
  333. {
  334. gettimeofday(&(ptrAuxStatus->TimeOfDayAux), NULL);
  335. // get values from MeteoBox
  336. GetMeteoBoxData (ptrAuxStatus);
  337. GetShipData (ptrAuxStatus);
  338. }
  339. /* GetAuxStatus */
  340. /**********************************************************************************************************/
  341. /* Init UDP Ports */
  342. /**********************************************************************************************************/
  343. int InitUDPPorts(fd_set *pFDsMaster, int *fdMax)
  344. {
  345. extern struct MessagePortType MessageInPortList[];
  346. extern struct MessagePortType MessageOutPortList[];
  347. int MessagePort;
  348. // init inports
  349. for (MessagePort=0; MessagePort<MAX_MESSAGE_INPORTS;MessagePort++)
  350. {
  351. printf("opening IN Port %s on Port %d Socket:",
  352. MessageInPortList[MessagePort].PortName,
  353. MessageInPortList[MessagePort].PortNumber);
  354. MessageInPortList[MessagePort].fdSocket=InitUDPInSocket(MessageInPortList[MessagePort].PortNumber);
  355. FD_SET(MessageInPortList[MessagePort].fdSocket, pFDsMaster); // add the manual port to the master set
  356. printf("%08x\n",MessageInPortList[MessagePort].fdSocket);
  357. (*fdMax)=MessageInPortList[MessagePort].fdSocket; // the last one will give the max number
  358. }
  359. /* for MessageInPort */
  360. // init outports
  361. for (MessagePort=0; MessagePort<MAX_MESSAGE_OUTPORTS;MessagePort++)
  362. {
  363. printf("opening OUT Port %s on Port %d, Destination IP: %s\n",
  364. MessageOutPortList[MessagePort].PortName,
  365. MessageOutPortList[MessagePort].PortNumber,
  366. MessageOutPortList[MessagePort].IPAddr);
  367. MessageOutPortList[MessagePort].fdSocket=InitUDPOutSocket(MessageOutPortList[MessagePort].PortNumber);
  368. }
  369. /* for MessageOutPort */
  370. return(1);
  371. }
  372. /*InitUDPPorts*/
  373. /**********************************************************************************************************/
  374. /* Change Priority */
  375. /**********************************************************************************************************/
  376. int ChangePriority()
  377. {
  378. struct sched_param param;
  379. int scheduler;
  380. int prio;
  381. struct timespec tp;
  382. int ret;
  383. int min,max;
  384. sched_getparam(0,&param);
  385. printf("sched prio %d\n",param.sched_priority);
  386. printf("min max prio %d %d\n",sched_get_priority_min(SCHED_RR),sched_get_priority_max(SCHED_RR));
  387. sched_rr_get_interval(0, &tp);
  388. printf("RR Quantum : %f\n",tp.tv_nsec*1e-9);
  389. max=sched_get_priority_max(SCHED_RR);
  390. min=sched_get_priority_max(SCHED_RR);
  391. param.sched_priority= (int)((max-min)/2);
  392. if (-1==(ret=sched_setscheduler(0,SCHED_RR, &param)))
  393. {
  394. char aBuffer[1024];
  395. printf("kann scheduler nicht wechseln: %s\r\n",strerror(errno));
  396. }
  397. return (ret);
  398. }
  399. /* ChangePriority */
  400. /**********************************************************************************************************/
  401. /* MAIN */
  402. /**********************************************************************************************************/
  403. int main(int argc, char *argv[])
  404. {
  405. extern int errno;
  406. extern int StatusFlag;
  407. extern enum TimerSignalStateEnum TimerState;
  408. int IsMaster = 1;
  409. extern struct MessagePortType MessageInPortList[];
  410. extern struct MessagePortType MessageOutPortList[];
  411. uint64_t ulCpuClock = CPUCLOCK;
  412. int nLostPackets = 0; // counter for lost packets from slave
  413. int fdMax; // max fd for select
  414. int i; // loop counter
  415. int fdNum; // fd number in loop
  416. fd_set fdsMaster; // master file descriptor list
  417. fd_set fdsSelect; // temp file descriptor list for select()
  418. int ret;
  419. uint64_t ProcessTick;
  420. uint64_t TSC,TSCin;
  421. uint64_t TSCsentPacket;
  422. uint64_t MinTimeDiff=1e6;
  423. uint64_t MaxTimeDiff=0;
  424. struct timeval StartAction;
  425. struct timeval StopAction;
  426. struct timeval LastAction;
  427. struct timeval GetStatusStartTime;
  428. struct timeval GetStatusStopTime;
  429. float ProcessTime;
  430. struct tm tmZeit;
  431. struct sigaction SignalAction;
  432. struct sigevent SignalEvent;
  433. sigset_t SignalMask;
  434. struct itimerspec StatusTimer;
  435. timer_t StatusTimer_id;
  436. clock_t clock = CLOCK_REALTIME;
  437. int StatusInterval=STATUS_INTERVAL;
  438. struct timespec pselect_timeout;
  439. struct timespec RealTime; // Real time clock
  440. struct sockaddr_in my_addr; // my address information
  441. struct sockaddr_in their_addr; // connector's address information
  442. int numbytes;
  443. socklen_t addr_len;
  444. char buf[GENERIC_BUF_LEN];
  445. bool EndOfSession;
  446. int MessagePort;
  447. int MessageNumber;
  448. struct ElekMessageType Message;
  449. int SlaveNum;
  450. int Task;
  451. int Channel;
  452. int MaskAddr;
  453. struct SyncFlagType SyncFlag;
  454. int RequestDataFlag;
  455. if (elkInit())
  456. {
  457. printf("Error: failed to grant IO access rights\n");
  458. exit(EXIT_FAILURE);
  459. };
  460. // setup master fd
  461. FD_ZERO(&fdsMaster); // clear the master and temp sets
  462. FD_ZERO(&fdsSelect);
  463. InitUDPPorts(&fdsMaster,&fdMax); // Setup UDP in and out Ports
  464. // change scheduler and set priority
  465. if (-1==(ret=ChangePriority()))
  466. {
  467. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],"elekIOaux : cannot set Priority");
  468. }
  469. if (argc==2)
  470. {
  471. // Check if we should display a summary of received data on screen
  472. if ((argv[1][0] == 's') || (argv[1][0] == 'S'))
  473. {
  474. bEnableGUI = true;
  475. InitNcursesWindows();
  476. }
  477. else
  478. bEnableGUI = false;
  479. };
  480. addr_len = sizeof(struct sockaddr);
  481. // output version info on debugMon and Console
  482. //
  483. #ifdef RUNONPC
  484. if(bEnableGUI)
  485. {
  486. wprintw(pStatusWin,"elekIOaux I386(CVS: $Id: elekIOaux.c,v 1.9 2007/03/11 11:17:36 rudolf Exp $)\n");
  487. sprintf(buf, "This is elekIOaux Version %3.2f (CVS: $Id: elekIOaux.c,v 1.9 2007/03/11 11:17:36 rudolf Exp $) for I386\n",VERSION);
  488. wrefresh(pStatusWin);
  489. }
  490. else
  491. {
  492. printf("This is elekIOaux Version %3.2f (CVS: $Id: elekIOaux.c,v 1.9 2007/03/11 11:17:36 rudolf Exp $) for I386\n",VERSION);
  493. sprintf(buf, "This is elekIOaux Version %3.2f (CVS: $Id: elekIOaux.c,v 1.9 2007/03/11 11:17:36 rudolf Exp $) for I386\n",VERSION);
  494. };
  495. #else
  496. printf("This is elekIOaux Version %3.2f (CVS: $Id: elekIOaux.c,v 1.9 2007/03/11 11:17:36 rudolf Exp $) for ARM\n",VERSION);
  497. sprintf(buf, "This is elekIOaux Version %3.2f (CVS: $Id: elekIOaux.c,v 1.9 2007/03/11 11:17:36 rudolf Exp $) for ARM\n",VERSION);
  498. #endif
  499. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],buf);
  500. if(bEnableGUI)
  501. {
  502. wprintw(pStatusWin,"Structure size of 'AuxStatus' in bytes is: %d\n",sizeof(AuxStatus));
  503. wrefresh(pStatusWin);
  504. }
  505. else
  506. printf("Structure size of 'AuxStatus' in bytes is: %05d\r\n", sizeof(AuxStatus));
  507. sprintf(buf, "elekIOaux : Structure size of 'AuxStatus' in bytes is: %d", sizeof(AuxStatus));
  508. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],buf);
  509. wrefresh(pStatusWin);
  510. refresh();
  511. /* init all modules */
  512. InitModules(&AuxStatus);
  513. /* set up signal handler */
  514. sigfillset(&SignalAction.sa_mask);
  515. SignalAction.sa_flags = 0;
  516. SignalAction.sa_handler = signalstatus;
  517. sigaction(SIGNAL_STATUS, &SignalAction, NULL);
  518. /* Set up timer: */
  519. memset(&SignalEvent, 0, sizeof(SignalEvent));
  520. SignalEvent.sigev_notify = SIGEV_SIGNAL;
  521. SignalEvent.sigev_signo = SIGNAL_STATUS;
  522. SignalEvent.sigev_value.sival_int = 0;
  523. ret= timer_create(clock, &SignalEvent, &StatusTimer_id);
  524. if (ret < 0)
  525. {
  526. perror("timer_create");
  527. return EXIT_FAILURE;
  528. }
  529. /* Start timer: */
  530. StatusTimer.it_interval.tv_sec = StatusInterval / 1000;
  531. StatusTimer.it_interval.tv_nsec = (StatusInterval % 1000) * 1000000;
  532. StatusTimer.it_value = StatusTimer.it_interval;
  533. ret = timer_settime(StatusTimer_id, 0, &StatusTimer, NULL);
  534. if (ret < 0)
  535. {
  536. perror("timer_settime");
  537. return EXIT_FAILURE;
  538. }
  539. sigemptyset(&SignalMask);
  540. // sigsuspend(&SignalMask);
  541. //
  542. gettimeofday(&LastAction, NULL);
  543. EndOfSession=FALSE;
  544. RequestDataFlag=FALSE;
  545. while (!EndOfSession)
  546. {
  547. /* if(bEnableGUI)
  548. {
  549. wprintw(pStatusWin,"Wait for data..\n");
  550. wrefresh(pStatusWin);
  551. }
  552. else
  553. write(2,"Wait for data..\r",16);
  554. */
  555. fdsSelect=fdsMaster;
  556. pselect_timeout.tv_sec= UDP_SERVER_TIMEOUT;
  557. pselect_timeout.tv_nsec=0;
  558. ret=pselect(fdMax+1, &fdsSelect, NULL, NULL, &pselect_timeout, &SignalMask); // wait until incoming udp or Signal
  559. gettimeofday(&StartAction, NULL);
  560. #ifdef DEBUG_TIMER
  561. printf("Time:");
  562. localtime_r(&StartAction.tv_sec,&tmZeit);
  563. printf("%02d:%02d:%02d.%03d :%d\n", tmZeit.tm_hour, tmZeit.tm_min,
  564. tmZeit.tm_sec, StartAction.tv_usec/1000,TimerState);
  565. printf("ret %d StatusFlag %d\n",ret,StatusFlag);
  566. #endif
  567. if (ret ==-1 )
  568. {
  569. // select error
  570. //
  571. if (errno==EINTR)
  572. {
  573. gettimeofday(&GetStatusStartTime, NULL);
  574. GetAuxStatus(&AuxStatus,IsMaster);
  575. gettimeofday(&GetStatusStopTime, NULL);
  576. AuxStatus.TimeOfDayAux = GetStatusStartTime;
  577. // Send Status to Status process
  578. SendUDPData(&MessageOutPortList[ELEK_ELEKIO_AUX_MASTER_OUT],sizeof(struct auxStatusType), &AuxStatus);
  579. UpdateWindows((struct auxStatusType*)&AuxStatus);
  580. AuxStatus.Status.Status.Word = 0; // mark data invalid
  581. }
  582. else
  583. {
  584. // if(errno==EINTR) so was not the Timer, it was a UDP Packet that caused err
  585. perror("select");
  586. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],"elekIOaux: Problem with select");
  587. }
  588. // if errno
  589. }
  590. else if (ret>0)
  591. {
  592. // printf("woke up...");
  593. write(2,"incoming Call..\r",16);
  594. for (MessagePort=0; MessagePort<MAX_MESSAGE_INPORTS;MessagePort++)
  595. {
  596. if (FD_ISSET(MessageInPortList[MessagePort].fdSocket,&fdsSelect))
  597. {
  598. // new msg on fdNum. socket ...
  599. // printf("fdsSelect: %016lx\n\r",fdsSelect);
  600. // fdElekManual=MessagePortList[MessagePort].fdSocket;
  601. // fdElekManual=MessagePortList[0].fdSocket;
  602. switch (MessagePort)
  603. {
  604. case ELEK_MANUAL_IN: // port for incoming commands from eCmd
  605. if ((numbytes=recvfrom(MessageInPortList[MessagePort].fdSocket,
  606. &Message,sizeof(struct ElekMessageType) , 0,
  607. (struct sockaddr *)&their_addr, &addr_len)) == -1)
  608. {
  609. perror("recvfrom");
  610. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],"elekIOaux: Problem with receive");
  611. }
  612. switch (Message.MsgType)
  613. {
  614. case MSG_TYPE_FETCH_DATA: // Master want data
  615. gettimeofday(&GetStatusStartTime, NULL);
  616. GetAuxStatus(&AuxStatus,IsMaster);
  617. gettimeofday(&GetStatusStopTime, NULL);
  618. // send this debugmessage message to debugmon
  619. sprintf(buf,"elekIOaux : FETCH_DATA from Port: %05d",
  620. MessageInPortList[MessagePort].PortNumber,
  621. Message.Addr,Message.Value,Message.Value);
  622. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],buf);
  623. // send requested data, don't send any acknowledges
  624. SendUDPData(&MessageOutPortList[ELEK_ELEKIO_AUX_MASTER_OUT],
  625. sizeof(struct auxStatusType), &AuxStatus); // send data packet
  626. break;
  627. case MSG_TYPE_READ_DATA:
  628. // printf("elekIOaux: manual read from Address %04x\n", Message.Addr);
  629. Message.Value=elkReadData(Message.Addr);
  630. Message.MsgType=MSG_TYPE_ACK;
  631. sprintf(buf,"elekIOaux : ReadCmd from %05d Port %04x Value %d (%04x)",
  632. MessageInPortList[MessagePort].PortNumber,
  633. Message.Addr,Message.Value,Message.Value);
  634. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],buf);
  635. sprintf(buf,"%d",MessageInPortList[MessagePort].RevMessagePort);
  636. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],buf);
  637. SendUDPDataToIP(&MessageOutPortList[MessageInPortList[MessagePort].RevMessagePort],
  638. inet_ntoa(their_addr.sin_addr),
  639. sizeof(struct ElekMessageType), &Message);
  640. break;
  641. case MSG_TYPE_WRITE_DATA:
  642. sprintf(buf,"elekIOaux : WriteCmd from %05d Port %04x Value %d (%04x)",
  643. MessageInPortList[MessagePort].PortNumber,
  644. Message.Addr,Message.Value,Message.Value);
  645. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],buf);
  646. Message.Status=elkWriteData(Message.Addr,Message.Value);
  647. Message.MsgType=MSG_TYPE_ACK;
  648. SendUDPDataToIP(&MessageOutPortList[MessageInPortList[MessagePort].RevMessagePort],
  649. inet_ntoa(their_addr.sin_addr),
  650. sizeof(struct ElekMessageType), &Message);
  651. break;
  652. }
  653. /* switch MsgType */
  654. break;
  655. default:
  656. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],"elekIOaux: unknown Port Type");
  657. break;
  658. }
  659. // switch MessagePort
  660. // printf("%lld got Message on Port %d from %s\n",TSC,inet_ntoa(their_addr.sin_addr));
  661. // printf("packet is %d bytes long\n",numbytes);
  662. TSCin=Message.MsgTime;
  663. MaxTimeDiff= MaxTimeDiff<TSC-TSCin ? TSC-TSCin : MaxTimeDiff;
  664. MinTimeDiff= MinTimeDiff>TSC-TSCin ? TSC-TSCin : MinTimeDiff;
  665. // printf("diff : %9lld Max: %9lld Min: %9lld\n",TSC-TSCin,MaxTimeDiff,MinTimeDiff);
  666. // printf("%9lld\n",TSC-TSCin);
  667. // check for end signature
  668. EndOfSession=(bool)(strstr(buf,"ende")!=NULL);
  669. // printf("found %u\n",EndOfSession);
  670. }
  671. /* if fd_isset */
  672. }
  673. /* for MessagePort */
  674. }
  675. else
  676. {
  677. /* ret==0*/
  678. // printf("timeout...\n");
  679. write(2,"timeout........\r",16);
  680. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],"elekIOaux : TimeOut");
  681. }
  682. #ifdef RUNONPC
  683. if (timer_getoverrun(StatusTimer_id)>0)
  684. {
  685. printf("OVERRUN\n\r");
  686. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],"elekIOaux : Overrun");
  687. }
  688. /* if overrun */
  689. #endif
  690. gettimeofday(&StopAction, NULL);
  691. #ifdef DEBUG_TIME_TASK
  692. sprintf(buf,"elekIOaux: %ld RT: %ld DT: %ld",StartAction.tv_usec/1000,
  693. StopAction.tv_usec-StartAction.tv_usec, (StartAction.tv_usec-LastAction.tv_usec)/1000);
  694. SendUDPMsg(&MessageOutPortList[ELEK_DEBUG_OUT],buf);
  695. #endif
  696. LastAction=StartAction;
  697. }
  698. /* while */
  699. #ifdef RUNONPC
  700. /* delete timer */
  701. timer_delete(StatusTimer_id);
  702. #endif
  703. // close all in bound sockets
  704. for (MessagePort=0; MessagePort<MAX_MESSAGE_INPORTS;MessagePort++)
  705. {
  706. close(MessageInPortList[MessagePort].fdSocket);
  707. }
  708. /*for MessagePort */
  709. // close all out bound sockets
  710. for (MessagePort=0; MessagePort<MAX_MESSAGE_OUTPORTS;MessagePort++)
  711. {
  712. close(MessageOutPortList[MessagePort].fdSocket);
  713. }
  714. /*for MessagePort */
  715. if (elkExit())
  716. {
  717. // release IO access
  718. printf("Error: failed to release IO access rights\n");
  719. exit(EXIT_FAILURE);
  720. }
  721. exit(EXIT_SUCCESS);
  722. }
  723. void InitNcursesWindows(void)
  724. {
  725. initscr(); /* Start curses mode */
  726. cbreak(); /* Line buffering disabled, Pass on*/
  727. refresh();
  728. curs_set(0);
  729. start_color(); /* Start color */
  730. init_pair(1, COLOR_YELLOW, COLOR_BLACK);
  731. init_pair(2, COLOR_WHITE, COLOR_BLACK);
  732. init_pair(3, COLOR_GREEN, COLOR_BLACK);
  733. attron(COLOR_PAIR(2));
  734. pGPSWin = newwin(8, 30, 0, 0);
  735. wattron(pGPSWin,COLOR_PAIR(1));
  736. box(pGPSWin,0,0);
  737. mvwprintw(pGPSWin,0,1,"GPS Ship");
  738. wrefresh(pGPSWin);
  739. pMeteoBoxWin = newwin(8, 26, 00, 30);
  740. wattron(pMeteoBoxWin,COLOR_PAIR(1));
  741. box(pMeteoBoxWin,0,0);
  742. mvwprintw(pMeteoBoxWin,0,1,"MeteoBox");
  743. wrefresh(pMeteoBoxWin);
  744. pWaterWin = newwin(4, 24, 00, 56);
  745. wattron(pWaterWin,COLOR_PAIR(1));
  746. box(pWaterWin,0,0);
  747. mvwprintw(pWaterWin,0,1,"Water Ship");
  748. wrefresh(pWaterWin);
  749. pAnemoWin = newwin(4, 24, 04, 56);
  750. wattron(pAnemoWin,COLOR_PAIR(1));
  751. box(pAnemoWin,0,0);
  752. mvwprintw(pAnemoWin,0,1,"Anemometer Ship");
  753. wrefresh(pAnemoWin);
  754. pSonarWin = newwin(4, 30, 8, 0);
  755. wattron(pSonarWin,COLOR_PAIR(1));
  756. box(pSonarWin,0,0);
  757. mvwprintw(pSonarWin,0,1,"Sonar Ship");
  758. wrefresh(pSonarWin);
  759. pGyroWin = newwin(4, 26, 8, 30);
  760. wattron(pGyroWin,COLOR_PAIR(1));
  761. box(pGyroWin,0,0);
  762. mvwprintw(pGyroWin,0,1,"Gyro Ship");
  763. wrefresh(pGyroWin);
  764. pStatusBorderWin = newwin(12, 80, 12, 0);
  765. wattron(pStatusBorderWin,COLOR_PAIR(1));
  766. box(pStatusBorderWin,0,0);
  767. mvwprintw(pStatusBorderWin,0,36,"Messages");
  768. wrefresh(pStatusBorderWin);
  769. pStatusWin = newwin(10, 78, 13, 1);
  770. wrefresh(pStatusWin);
  771. }
  772. void UpdateWindows(struct auxStatusType *ptrAuxStatus)
  773. {
  774. if(bEnableGUI)
  775. {
  776. // GPS
  777. //
  778. if(ptrAuxStatus->Status.Status.Field.ShipGPSDataValid == 1)
  779. {
  780. wattroff(pGPSWin,COLOR_PAIR(1));
  781. wattroff(pGPSWin,COLOR_PAIR(2));
  782. wattron(pGPSWin,COLOR_PAIR(3));
  783. }
  784. else
  785. {
  786. wattroff(pGPSWin,COLOR_PAIR(1));
  787. wattroff(pGPSWin,COLOR_PAIR(3));
  788. wattron(pGPSWin,COLOR_PAIR(2));
  789. };
  790. mvwprintw(pGPSWin,1,2,"Time (UTC): %02d:%02d:%02d",ptrAuxStatus->ShipGPS.ucUTCHours\
  791. ,ptrAuxStatus->ShipGPS.ucUTCMins\
  792. ,ptrAuxStatus->ShipGPS.ucUTCSeconds);
  793. mvwprintw(pGPSWin,2,2,"Date: %02d.%02d.%04d",ptrAuxStatus->ShipGPS.ucUTCDay\
  794. ,ptrAuxStatus->ShipGPS.ucUTCMonth\
  795. ,ptrAuxStatus->ShipGPS.uiUTCYear);
  796. mvwprintw(pGPSWin,3,2,"Longitude: %+06.4f °",ptrAuxStatus->ShipGPS.dLongitude);
  797. mvwprintw(pGPSWin,4,2,"Latitude: %+06.4f °",ptrAuxStatus->ShipGPS.dLatitude);
  798. mvwprintw(pGPSWin,5,2,"COG: %-6.2f °",ptrAuxStatus->ShipGPS.dCourseOverGround);
  799. mvwprintw(pGPSWin,6,2,"Ground Speed: %-5.2f knots",ptrAuxStatus->ShipGPS.dGroundSpeed);
  800. wrefresh(pGPSWin);
  801. // Water Ship
  802. if(ptrAuxStatus->Status.Status.Field.ShipWaterDataValid == 1)
  803. {
  804. wattroff(pWaterWin,COLOR_PAIR(1));
  805. wattroff(pWaterWin,COLOR_PAIR(2));
  806. wattron(pWaterWin,COLOR_PAIR(3));
  807. }
  808. else
  809. {
  810. wattroff(pWaterWin,COLOR_PAIR(1));
  811. wattroff(pWaterWin,COLOR_PAIR(3));
  812. wattron(pWaterWin,COLOR_PAIR(2));
  813. };
  814. mvwprintw(pWaterWin,1,2,"Temp.: %+5.2f °C",ptrAuxStatus->ShipWater.dWaterTemp);
  815. mvwprintw(pWaterWin,2,2,"Salinity: %-6.2f g/l",ptrAuxStatus->ShipWater.dSalinity);
  816. wrefresh(pWaterWin);
  817. // Anemo Ship
  818. if(ptrAuxStatus->Status.Status.Field.ShipMeteoDataValid == 1)
  819. {
  820. wattroff(pAnemoWin,COLOR_PAIR(1));
  821. wattroff(pAnemoWin,COLOR_PAIR(2));
  822. wattron(pAnemoWin,COLOR_PAIR(3));
  823. }
  824. else
  825. {
  826. wattroff(pAnemoWin,COLOR_PAIR(1));
  827. wattroff(pAnemoWin,COLOR_PAIR(3));
  828. wattron(pAnemoWin,COLOR_PAIR(2));
  829. };
  830. mvwprintw(pAnemoWin,1,2,"Direction: %-6.2f °",ptrAuxStatus->ShipMeteo.dWindDirection);
  831. mvwprintw(pAnemoWin,2,2,"Speed: %-2.0f m/s",ptrAuxStatus->ShipMeteo.dWindSpeed);
  832. wrefresh(pAnemoWin);
  833. // Sonar Ship
  834. if(ptrAuxStatus->Status.Status.Field.ShipSonarDataValid == 1)
  835. {
  836. wattroff(pSonarWin,COLOR_PAIR(1));
  837. wattroff(pSonarWin,COLOR_PAIR(2));
  838. wattron(pSonarWin,COLOR_PAIR(3));
  839. }
  840. else
  841. {
  842. wattroff(pSonarWin,COLOR_PAIR(1));
  843. wattroff(pSonarWin,COLOR_PAIR(3));
  844. wattron(pSonarWin,COLOR_PAIR(2));
  845. };
  846. mvwprintw(pSonarWin,1,2,"Frequency: %-6.4f Khz",ptrAuxStatus->ShipSonar.dFrequency);
  847. mvwprintw(pSonarWin,2,2,"Waterdepth: %-8.2f m",ptrAuxStatus->ShipSonar.dWaterDepth);
  848. wrefresh(pSonarWin);
  849. // Gyro Ship
  850. if(ptrAuxStatus->Status.Status.Field.ShipGyroDataValid == 1)
  851. {
  852. wattroff(pGyroWin,COLOR_PAIR(1));
  853. wattroff(pGyroWin,COLOR_PAIR(2));
  854. wattron(pGyroWin,COLOR_PAIR(3));
  855. }
  856. else
  857. {
  858. wattroff(pGyroWin,COLOR_PAIR(1));
  859. wattroff(pGyroWin,COLOR_PAIR(3));
  860. wattron(pGyroWin,COLOR_PAIR(2));
  861. };
  862. mvwprintw(pGyroWin,1,2,"Heading: %03.0f °",ptrAuxStatus->ShipGyro.dDirection);
  863. wrefresh(pGyroWin);
  864. // MeteoBox
  865. if(ptrAuxStatus->Status.Status.Field.MeteoBoxDataValid == 1)
  866. {
  867. wattroff(pMeteoBoxWin,COLOR_PAIR(1));
  868. wattroff(pMeteoBoxWin,COLOR_PAIR(2));
  869. wattron(pMeteoBoxWin,COLOR_PAIR(3));
  870. }
  871. else
  872. {
  873. wattroff(pMeteoBoxWin,COLOR_PAIR(1));
  874. wattroff(pMeteoBoxWin,COLOR_PAIR(3));
  875. wattron(pMeteoBoxWin,COLOR_PAIR(2));
  876. };
  877. mvwprintw(pMeteoBoxWin,1,2,"Windspeed: %-6.2f m/s",ptrAuxStatus->MeteoBox.dWindSpeed);
  878. mvwprintw(pMeteoBoxWin,2,2,"Windspeed: %-6.2f km/h",ptrAuxStatus->MeteoBox.dWindSpeed*3.6f);
  879. mvwprintw(pMeteoBoxWin,3,2,"Wind Dir: %-3d °",ptrAuxStatus->MeteoBox.uiWindDirection);
  880. mvwprintw(pMeteoBoxWin,4,2,"Rel. Humid: %-5.2f %",ptrAuxStatus->MeteoBox.dRelHum);
  881. mvwprintw(pMeteoBoxWin,5,2,"Air Temp: %+05.2f °C",ptrAuxStatus->MeteoBox.dAirTemp);
  882. mvwprintw(pMeteoBoxWin,6,2,"Gas Sensor: %-5.3f V",ptrAuxStatus->MeteoBox.dGasSensorVoltage);
  883. wrefresh(pMeteoBoxWin);
  884. };
  885. };