PageRenderTime 104ms CodeModel.GetById 17ms app.highlight 79ms RepoModel.GetById 1ms app.codeStats 1ms

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