#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <ncurses.h>
#include <panel.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <math.h>
#include "aprstlm.h"

   int argp;

   int quit=0;

   char mycall[10];

   char hdr_gen_txt[80];
   char satname[26];
   char satcall[26];
   char satcallb[26];
   int selsat;

   int pcsatside=0;
   int foundpkt=0;

   extern char *tzname[2];
   struct timeval epochtime;
   struct timezone epochtz;
   struct tm tmzulu;
   struct tm tmlocal;
   time_t epochbird;		
   double birdmet;	    	/* In Seconds!! */	
   long metdays;		/* Complete Days in Orbit */
   long methours;		/* Extra Hours in Orbit */
   long metmins;		/* Extra Minutes in Orbit */
   long metsecs;		/* Extra Seconds in Orbit */

   char predhost[256];		/* Predict Host */
   char predbuf[MAX_UDP_BUF];	/* Predict Buffer */
   int predport;		/* Predict Port */

   int preden=0;		/* Predict Enabled ? */
   int predsock,predbind;	/* Predict Sockets */
   int predstat;		/* Predict Remote Status */
   int addrlen;			/* Address Length */

   char predsat[10];		/* Satellite name Recieved from Predict */
   char birdns,birdew;		/* Satellite N/S and E/W decision */
   float birdlong,birdlat;	/* Satellite Long and Lat */
   float birdaz,birdel;		/* Satellite Az and El */
   float birdaos,birdfoot;	/* Satellite AOS/LOS and  Footprint (Unused) */
   float birdrange,birdalt;	/* Satellite Range And Altitude */
   float birdvel,birdorbit;	/* Satellite Velocity, and Orbit Number */
   float birdvis,birdphase;	/* Satellite Visibility and Orbit Phase */
   float birdeclipse,birdsquint;	/* Satellite Eclipse and Squint */

   struct hostent *predhostent;		/* Hostent for Predict Host */
   struct sockaddr_in predaddr;		/* Predict Address Structure */
   struct sockaddr_in locladdr;		/* Local Addr Structure for Predict */

   int aprssock;			/* APRS Socket */
   int aprsstat;			/* APRS Remote Status */
   struct sockaddr_in aprsaddr;		/* APRS Address Structure */
   struct hostent *aprshostent; 	/* APRS Hostent Structure */
   struct pollfd aprspoll;		/* APRS Poll Structure */
   char aprsbuf[MAX_TCP_BUF];		/* APRS Buffer */
   char aprsout[MAX_TCP_BUF];		/* Outbound APRS Buffer */
   char aprschar;
   char aprshost[256];
   char aprsport[6];

   int aprscount;

   char tlmpkt[43];			/* Tlm Packet */
   char aprstlmstart;			/* Start of TLM */
   int tlmpktdtd;			/* Tlm Packet Detected */
   int k;				/* Tlm for counter */
   int tlmcount;

   char discard01, discard02,discard03;	/* Discard these chars in tlm stream */
   char discard04, discard05,discard06; /* Discard these chars in tlm stream */
   char discard07;			/* Discard these chars in tlm stream */
   char discard10, discard11;		/* Discard these chars in tlm stream */
   char discard13, discard14;

   char rawtlmno[3];			/* Telemetry Counter */
   char rawtlmstr[5][3];		/* String Raw Telemetry Values */
   int rawtlmint[4][5];			/* Integer Raw Telemetry Values */
   float tlmval[4][5];			/* Floating TLM Values, Post Decode */
   float ref5v;				/* Floating 5V Ref for PCSAT */
   char sbits[2];			/* Spare/Experiment Bits */
   char rawcmdbits[8];			/* Cmd Bits */
   char rawarmbit;			/* Arm Bit */
   int tlmarmbit[4];			/* Arm Bit as Int */
   char rawfrnum[2];			/* Tlm Frame Number */
   int tlmframe;			/* Decimal TLM Frame */
   char tmptlmstr[4];
   char tmptlmnum[4];
   int elptlmno[4];
   int lasttlmnum;
   int currtlmnum;

   int l;				/* atoin Counter */
   struct timeval frametime[4];		/* Last TLM Recieve Time */
   struct timeval frametimeb[4];	/* Last TLM Recieve Time */
   struct timezone framezone[4];	/* Unused in the end */
   struct timezone framezoneb[4];	/* Unused in the end */
   int framestatic[4];			/* Is This Static Data ? */
   int framestaticb[4];			/* Is This Static Data ? */
   int allframestatic;			/* All TLM is Old! */
   int allframestaticb;			/* All TLM is Old! */

   int z;				/* Counter */
   double tmpdifftime;
   double statictime=300.00;
   int a;				/* Zero-Out Counter */
   int c;
   int d;
   int e;
   int bin1,bin2;			/* Binary Frame For Elapsed Time */

   double framemet[4];			/* Frame Recieved at MET */
   double framemetb[4];			/* Frame Recieved at MET */
   long framedays[4];			/* Frame Received Days*/
   long framedaysb[4];			/* Frame Received Days*/
   long framehours[4];			/* Frame Received Hours */
   long framehoursb[4];			/* Frame Received Hours */
   long framemins[4];			/* Frame Received Mins */
   long frameminsb[4];			/* Frame Received Mins */
   long framesecs[4];			/* Frame Received Seconds */
   long framesecsb[4];			/* Frame Received Seconds */
   char cmdstrings[8][CMD_STR_LEN+1];	/* Textual Command Strings - Per Bird */
   int x;				/* cmd_win counter */
   int numcmdstr;			/* number of active cmd strings */

   double elapsedtime;
   double elapsedtimeb;
   long elapseddays[4];
   long elapseddaysb[4];
   long elapsedhours[4];
   long elapsedhoursb[4];
   long elapsedmins[4];
   long elapsedminsb[4];
   long elapsedsecs[4];
   long elapsedsecsb[4];

   char tlmlbl[24][15];			/* Telemetry Labels */
   char tlmlblb[24][15];		/* Telemetry Labels (B Screen) */

   int numtlmlbl;			/* Number of TLM Labels */
   int numtlmlblb;			/* Number of TLM Labels */

   int lbly;				/* Which Label Col Do We Display */

   int anytlmrx=0;			/* Have we had *any* tlm yet */
   int anytlmrxb=0;			/* Have we had *any* tlm yet */
   int frtlmrx[4];			/* Have we had each frame yet */
   int frtlmrxb[4];			/* Have we had each frame yet */

   struct tm tmframe[4][2];		/* First Digit Frame, Second tz */
   struct tm tmframeb[4][2];		/* First Digit Frame, Second tz */

   int keypress;			/* Key Pressed */

   int numtlmviews;			/* How Many TLM Views do we have */
   int numtlmframes=3;			/* How Many TLM Frames for this bird */
                                        /* minus one. Default to 3 (4 frames)*/
   int numdatewins=3;
                                        /* RAFT will need numtlmframes=0 */
   int norad;				/* NORAD Number for Satellite */
   char noradstr[6];			/* String Equivalent of NORAD no */

   WINDOW *header_win;
   WINDOW *clocks_win;
   WINDOW *qth_win;
   WINDOW *tlm_win;
   WINDOW *tlmb_win;
   WINDOW *raw_win;
   WINDOW *rawb_win;
   WINDOW *cmd_win;
   WINDOW *arm_win;
   WINDOW *timer_win;

   WINDOW *tlmdateutc_win;
   WINDOW *tlmdatelcl_win;
   WINDOW *tlmdatemet_win;
   WINDOW *tlmdateelp_win;

   WINDOW *tlmdateutcb_win;
   WINDOW *tlmdatelclb_win;
   WINDOW *tlmdatemetb_win;
   WINDOW *tlmdateelpb_win;

   PANEL *tlm_pan,*tlmb_pan;
   PANEL *raw_pan,*rawb_pan;
   PANEL *tlmdateutc_pan;
   PANEL *tlmdatelcl_pan;
   PANEL *tlmdatemet_pan;
   PANEL *tlmdateelp_pan;
   PANEL *tlmdateutcb_pan;
   PANEL *tlmdatelclb_pan;
   PANEL *tlmdatemetb_pan;
   PANEL *tlmdateelpb_pan;

   PANEL *tlmpanptr[4];
   PANEL *tlmdatepanptr[8];
   int cur_tlm_ptr=0;
   int cur_tlmdate_ptr=0;


int main(int argc, char **argv)
{
   strcpy(mycall,"NOCALL");

   /* Parse Command Line Arguments */

   for (argp=0; argp<argc; argp++)
   {

      /* Show Version */
      if (strcmp(argv[argp],"-v")==0)
      {
         fprintf(stdout,"aprstlm version :%s\n",APRSTLMVER);
         exit(0);
      }

      /* Satellite To Show */
      if (strcmp(argv[argp],"-sat")==0)
      {
         argp++;
         strcpy(satname,argv[argp]);
      
         if (strcmp(satname,"PCSAT")==0)
         {
            selsat=SAT_PCSAT;
            sprintf(satcall,"W3ADO");
            sprintf(satcallb,"PCSAT-");
            numdatewins=7;
         } 
         if (strcmp(satname,"PCSAT2")==0)
         {
            selsat=SAT_PCSAT2;
            sprintf(satcall,"PCSAT2");
            sprintf(satcallb,"PCSAT2");
            numdatewins=3;
         }
      }
      
      /* Predict Host */
      if (strcmp(argv[argp],"-pred")==0)
      {
         argp++;
         strcpy(predhost,argv[argp]);
         argp++;
         predport=atoi(argv[argp]);
         preden=1;
      }

      /* APRS-IS Host */
      if (strcmp(argv[argp],"-aprs")==0)
      {
         argp++;
         strcpy(aprshost,argv[argp]);
         argp++;
         strcpy(aprsport,argv[argp]);
      }

      /* My Call */
      if (strcmp(argv[argp],"-mycall")==0)
      {
         argp++;
         strcpy(mycall,argv[argp]);
      }
   }

   /* Setup ncurses stuff */

   initscr();
   curs_set(0);					/* Turn the Cursor Off */
   cbreak();					/* Raw, Immediate Input */
   noecho();					/* Don't Do Any Echoing */
   nodelay(stdscr,TRUE);			/* No Delays! */

   if(has_colors() == TRUE)
   {
      start_color();
      init_pair(1, COLOR_YELLOW, COLOR_BLACK); 	/* MCC Header, Warn Values */
      init_pair(2, COLOR_RED, COLOR_BLACK);	/* Clocks and QTH, Red Values */
      init_pair(3, COLOR_WHITE, COLOR_BLACK);	/* Nominal Values */
      init_pair(4, COLOR_BLACK, COLOR_CYAN);	/* Static Values (NASA Mode)*/
      init_pair(5, COLOR_BLUE, COLOR_BLACK);	/* Labels (cmd_win )*/
      init_pair(6, COLOR_BLACK, COLOR_BLACK);	/* Invisible Hack */   
   }

   /* Create The Header Windows And Borders*/

   header_win=newwin(5,25,0,28);
   clocks_win=newwin(5,29,0,0);
   qth_win=newwin(5,28,0,52);
   tlm_win=newwin(8,80,5,0);
   raw_win=newwin(8,80,5,0);

   cmd_win=newwin(7,40,13,0);

   tlmdateutc_win=newwin(7,40,13,40);
   tlmdatelcl_win=newwin(7,40,13,40);
   tlmdatemet_win=newwin(7,40,13,40);
   tlmdateelp_win=newwin(7,40,13,40);

   tlm_pan=new_panel(tlm_win);
   raw_pan=new_panel(raw_win);

   tlmpanptr[0]=tlm_pan;
   tlmpanptr[1]=raw_pan;

   tlmdateutc_pan=new_panel(tlmdateutc_win);
   tlmdatelcl_pan=new_panel(tlmdatelcl_win);
   tlmdatemet_pan=new_panel(tlmdatemet_win);
   tlmdateelp_pan=new_panel(tlmdateelp_win);

   tlmdatepanptr[0]=tlmdateutc_pan;
   tlmdatepanptr[1]=tlmdatelcl_pan;
   tlmdatepanptr[2]=tlmdatemet_pan;
   tlmdatepanptr[3]=tlmdateelp_pan;

   if (selsat==SAT_PCSAT)
   {
      tlmdateutcb_win=newwin(7,40,13,40);
      tlmdatelclb_win=newwin(7,40,13,40);
      tlmdatemetb_win=newwin(7,40,13,40);
      tlmdateelpb_win=newwin(7,40,13,40);

      tlmdateutcb_pan=new_panel(tlmdateutcb_win);
      tlmdatelclb_pan=new_panel(tlmdatelclb_win);
      tlmdatemetb_pan=new_panel(tlmdatemetb_win);
      tlmdateelpb_pan=new_panel(tlmdateelpb_win);

      tlmdatepanptr[4]=tlmdateutcb_pan;
      tlmdatepanptr[5]=tlmdatelclb_pan;
      tlmdatepanptr[6]=tlmdatemetb_pan;
      tlmdatepanptr[7]=tlmdateelpb_pan;
   }

   wborder(header_win,0,0,0,0,ACS_TTEE,ACS_TTEE,ACS_BTEE,ACS_BTEE);
   wborder(clocks_win,0,0,0,0,0,ACS_TTEE,ACS_LTEE,ACS_BTEE);
   wborder(qth_win,0,0,0,0,ACS_TTEE,0,ACS_BTEE,ACS_RTEE);
   wborder(tlm_win,ACS_VLINE,ACS_VLINE,' ',ACS_HLINE,ACS_VLINE,ACS_VLINE,ACS_LTEE,ACS_RTEE);
   wborder(raw_win,ACS_VLINE,ACS_VLINE,' ',ACS_HLINE,ACS_VLINE,ACS_VLINE,ACS_LTEE,ACS_RTEE);
   wborder(cmd_win,ACS_VLINE,' ',' ',ACS_HLINE,ACS_VLINE,' ',ACS_LTEE,ACS_HLINE);
   wborder(tlmdateutc_win,ACS_VLINE,ACS_VLINE,' ',ACS_HLINE,ACS_VLINE,ACS_VLINE,ACS_PLUS,ACS_RTEE);
   wborder(tlmdatelcl_win,ACS_VLINE,ACS_VLINE,' ',ACS_HLINE,ACS_VLINE,ACS_VLINE,ACS_PLUS,ACS_RTEE);
   wborder(tlmdatemet_win,ACS_VLINE,ACS_VLINE,' ',ACS_HLINE,ACS_VLINE,ACS_VLINE,ACS_PLUS,ACS_RTEE);
   wborder(tlmdateelp_win,ACS_VLINE,ACS_VLINE,' ',ACS_HLINE,ACS_VLINE,ACS_VLINE,ACS_PLUS,ACS_RTEE);
  
   if (selsat==SAT_PCSAT)
   {
      wborder(tlmdateutcb_win,ACS_VLINE,ACS_VLINE,' ',ACS_HLINE,ACS_VLINE,ACS_VLINE,ACS_PLUS,ACS_RTEE);
      wborder(tlmdatelclb_win,ACS_VLINE,ACS_VLINE,' ',ACS_HLINE,ACS_VLINE,ACS_VLINE,ACS_PLUS,ACS_RTEE);
      wborder(tlmdatemetb_win,ACS_VLINE,ACS_VLINE,' ',ACS_HLINE,ACS_VLINE,ACS_VLINE,ACS_PLUS,ACS_RTEE);
      wborder(tlmdateelpb_win,ACS_VLINE,ACS_VLINE,' ',ACS_HLINE,ACS_VLINE,ACS_VLINE,ACS_PLUS,ACS_RTEE);
   }
   mvwaddch(tlm_win,7,40,ACS_TTEE);
   mvwaddch(raw_win,7,40,ACS_TTEE);

   mvwaddch(cmd_win,7,40,ACS_PLUS);

   switch (selsat)
   {
      case SAT_PCSAT:
         pcsat_setup();
         break;
      case SAT_PCSAT2:
         pcsat2_setup();
         break;
   }

   for (c=0; c<=3; c++)
   {
      mvwprintw(tlmdateutc_win,2+c,38,"S");
      mvwprintw(tlmdatelcl_win,2+c,38,"S");
      mvwprintw(tlmdatemet_win,2+c,38,"S");
      mvwprintw(tlmdateelp_win,2+c,38,"S");
      mvwchgat(tlmdateutc_win,2+c,38,1,A_NORMAL,6,NULL);
      mvwchgat(tlmdatelcl_win,2+c,38,1,A_NORMAL,6,NULL);
      mvwchgat(tlmdatemet_win,2+c,38,1,A_NORMAL,6,NULL);
      mvwchgat(tlmdateelp_win,2+c,38,1,A_NORMAL,6,NULL);

      if (selsat==SAT_PCSAT)
      {
         mvwprintw(tlmdateutcb_win,2+c,38,"S");
         mvwprintw(tlmdatelclb_win,2+c,38,"S");
         mvwprintw(tlmdatemetb_win,2+c,38,"S");
         mvwprintw(tlmdateelpb_win,2+c,38,"S");
         mvwchgat(tlmdateutcb_win,2+c,38,1,A_NORMAL,6,NULL);
         mvwchgat(tlmdatelclb_win,2+c,38,1,A_NORMAL,6,NULL);
         mvwchgat(tlmdatemetb_win,2+c,38,1,A_NORMAL,6,NULL);
         mvwchgat(tlmdateelpb_win,2+c,38,1,A_NORMAL,6,NULL);
      }
   }

   touchwin(tlmdateutc_win);
   touchwin(tlmdatelcl_win);
   touchwin(tlmdatemet_win);
   touchwin(tlmdateelp_win);

   for (x=0; x<=(numcmdstr/2); x++)
   {
      
      mvwprintw(cmd_win,2+x,2,cmdstrings[x]);
      mvwprintw(cmd_win,2+x,19,"S");
      mvwchgat(cmd_win,2+x,2,CMD_STR_LEN,A_NORMAL,6,NULL);
      mvwchgat(cmd_win,2+x,19,1,A_NORMAL,6,NULL);
      mvwprintw(cmd_win,2+x,22,cmdstrings[x+4]);
      mvwprintw(cmd_win,2+x,38,"S");
      mvwchgat(cmd_win,2+x,22,CMD_STR_LEN,A_NORMAL,6,NULL);
      mvwchgat(cmd_win,2+x,38,1,A_NORMAL,6,NULL);
   }

   if (has_colors() == TRUE)
   {
      wattrset(header_win,COLOR_PAIR(COLOUR_HEADER));
      wattrset(clocks_win,COLOR_PAIR(COLOUR_CLOCKS));
      wattrset(qth_win,COLOR_PAIR(COLOUR_QTH));
   }

   if (selsat==SAT_PCSAT)
   {
      mvwprintw(tlmdateutc_win,0,5,"LAST TLM RECEIVE DATE (A-SIDE)");
      mvwprintw(tlmdatelcl_win,0,5,"LAST TLM RECEIVE DATE (A-SIDE)");
      mvwprintw(tlmdatemet_win,0,5,"LAST TLM RECEIVE DATE (A-SIDE)");
      mvwprintw(tlmdateelp_win,0,5,"LAST TLM RECEIVE DATE (A-SIDE)");
      mvwprintw(tlmdateutcb_win,0,5,"LAST TLM RECEIVE DATE (B-SIDE)");
      mvwprintw(tlmdatelclb_win,0,5,"LAST TLM RECEIVE DATE (B-SIDE)");
      mvwprintw(tlmdatemetb_win,0,5,"LAST TLM RECEIVE DATE (B-SIDE)");
      mvwprintw(tlmdateelpb_win,0,5,"LAST TLM RECEIVE DATE (B-SIDE)");
   }
   else
   {
      mvwprintw(tlmdateutc_win,0,9,"LAST TLM RECEIVE DATE");
      mvwprintw(tlmdatelcl_win,0,9,"LAST TLM RECEIVE DATE");
      mvwprintw(tlmdatemet_win,0,9,"LAST TLM RECEIVE DATE");
      mvwprintw(tlmdateelp_win,0,9,"LAST TLM RECEIVE DATE");
   }

   
   strcpy(hdr_gen_txt,"APRS TELEMETRY VIEWER");

   mvwprintw(header_win,2,((25-strlen(hdr_gen_txt))/2),hdr_gen_txt);
   mvwprintw(header_win,1,((25-strlen(satname))/2),satname);
   mvwprintw(cmd_win,0,10,"BINARY COMMAND BITS");

      touchwin(tlm_win);
      touchwin(raw_win);
      touchwin(tlmb_win);
      touchwin(rawb_win);
      touchwin(cmd_win);
      touchwin(arm_win);
      touchwin(timer_win);
      touchwin(tlmdateutc_win);
      touchwin(tlmdatelcl_win);
      touchwin(tlmdatemet_win);
      touchwin(tlmdateelp_win);
      touchwin(tlmdateutcb_win);
      touchwin(tlmdatelclb_win);
      touchwin(tlmdatemetb_win);
      touchwin(tlmdateelpb_win);
      touchwin(header_win);

      wrefresh(clocks_win);
      wrefresh(header_win);
      wrefresh(qth_win);
      wrefresh(cmd_win);
      wrefresh(arm_win);
      wrefresh(timer_win);
     

      update_panels();
      doupdate();         

   /* Zero Out frlmrx, and framestatic */

   for (a=0; a<=3; a++)
   {
      frtlmrx[a]=0;
      framestatic[a]=0;
      framestaticb[a]=0;
   }

   /* Setup Predict Socket if enabled */

   if (preden==1)
   {
      predsock=socket(AF_INET, SOCK_DGRAM, 0);
      if (predsock==-1)
      {
         preden=0;
      }
      else
      {
         locladdr.sin_family = AF_INET;
         locladdr.sin_addr.s_addr = INADDR_ANY;
         locladdr.sin_port = 0;

         predbind = bind(predsock, (struct sockaddr*)&locladdr, sizeof(locladdr));
         if (predbind==-1)
         {
            preden=0;
         }
         else
         {
            predaddr.sin_family = AF_INET;
            if ((predhostent=gethostbyname(predhost)))
            {
                bcopy(predhostent->h_addr,(char *)&predaddr.sin_addr,predhostent->h_length);

            }
            else if ((predaddr.sin_addr.s_addr=inet_addr(predhost))==INADDR_NONE)
            {
               preden=0;
            }
            predaddr.sin_port = htons(predport);
         }
      }
   }

   aprssock=socket(AF_INET, SOCK_STREAM, 0);
   if ((aprssock)==-1)
   {
      endwin();
      fprintf(stderr,"Couldn't Create Socket For APRS Feed. Aborting\n");
      exit(1);
   }

/* This section commented out so we can be dual IPv4/IPv6 stacked */
/* Credit to John Ronan for showing me how easy this hack was to do */

/*   aprshostent=gethostbyname(aprshost);
   if ((aprshostent)==NULL)
   {
      endwin();
      fprintf(stderr,"Unknown Host for APRS Feed. Aborting\n");
      exit(1);
   }

   bzero((char *) &aprsaddr, sizeof(aprsaddr));
   aprsaddr.sin_family = AF_INET;
   bcopy((char *)aprshostent->h_addr, (char *)&aprsaddr.sin_addr.s_addr,
      aprshostent->h_length);
   aprsaddr.sin_port = htons(aprsport);

   if (connect(aprssock,&aprsaddr,sizeof(aprsaddr)) < 0) 
*/

/* END of IPv4 only obsolete code */
   aprssock= connect_client(aprshost,aprsport,AF_UNSPEC, SOCK_STREAM);
   if (aprssock<0)
   {
      endwin();
      fprintf(stderr,"Cant Connect to APRS Feed. Aborting\n");
      fprintf(stderr,"%s:%d\n",aprshost,aprsport);
      exit(1);
   }

   aprspoll.fd=aprssock;
   aprspoll.events=POLLIN;

   /* Construct Outbound Registration/Filter Message */

   strcpy(aprsout,"USER ");
   strcat(aprsout,mycall);
   strcat(aprsout," PASS -1 vers aprstlm v");
   strcat(aprsout,APRSTLMVER);
   strcat(aprsout," filter p/w3ado/pcsat\n");

   write(aprssock,aprsout,strlen(aprsout));

   /* Setup Date Window */
   keypress=getch();
   while((keypress!='q') && (keypress!='Q'))
   {
      /* Read From TCP Stream */

      aprscount=0;
      aprsstat=read(aprssock,&aprschar,1);

      do
      {
         if (aprschar!=10)
         {
            aprsbuf[aprscount]=aprschar;
            aprscount++;
         }
         if (poll(&aprspoll,1,100)>=1)
         {
            aprsstat=read(aprssock,&aprschar,1);
         }
         gettimeofday(&epochtime,&epochtz);
         gmtime_r(&epochtime.tv_sec,&tmzulu); 
         localtime_r(&epochtime.tv_sec,&tmlocal);

         /* Handle Most of Mission Elapsed Time (Orbit number is provided */
         /* by predict later ) */

         birdmet=difftime(epochtime.tv_sec,epochbird);
         metdays=birdmet/86400.0;

         birdmet=birdmet-(metdays*86400.0);
         methours=birdmet/3600.0;

         birdmet=birdmet-(methours*3600.0);
         metmins=birdmet/60.0;

         birdmet=birdmet-(metmins*60);
         metsecs=birdmet;

         if (preden==0)
         {
             mvwprintw(qth_win,2,1,"PREDICT SERVER UNAVAILABLE");
         }
         else
         { 
            strcpy(predbuf,"GET_SAT ");
            strcat(predbuf,noradstr);
            strcat(predbuf,"\n");
   
            predstat =  sendto(predsock,predbuf,strlen(predbuf)+1, 0,
                    (struct sockaddr*)&predaddr, sizeof(predaddr));

            if (predstat == -1)
            {
               mvwprintw(qth_win,2,1,"PREDICT SERVER UNAVAILABLE");
               preden=0;
            }
            else
            {
                addrlen=sizeof(predhost);
                predstat = recvfrom(predsock,predbuf, MAX_UDP_BUF,0,
                        (struct sockaddr*)&predhost, &addrlen);

                if (predstat == -1)
                {
                   mvwprintw(qth_win,2,1,"PREDICT SERVER UNAVAILABLE");
                   preden=0;
                }
                else
                {
                   predbuf[predstat] = 0;
                   sscanf(predbuf,"%s%f%f%f%f%f%f%f%f%f%f%f%f%f%f",predsat,&birdlong,&birdlat,&birdaz,&birdel,&birdaos,&birdfoot,&birdrange,&birdalt,&birdvel,&birdorbit,&birdvis,&birdphase,&birdeclipse,&birdsquint);

                   birdew='W';
                   if (birdlong<180.0) 
                   {
                      birdew='E';
                      birdlong=-birdlong;
                      birdlong=birdlong*(-1);
                   }
                   else if (birdlong>180.0)
                   {
                      birdlong=360.0-birdlong;
                   }

                   birdns='N';
                   if (birdlat<0.0) 
                   {
                      birdns='S';
                      birdlat=birdlat*(-1);
                   }
                }
            }
         }

         /* Check For any Frames That Have Gone Static */
         for (z=0; z<=3; z++)
         {
            if (frtlmrx[z]==1)
            {
               framestatic[z]=0;
               tmpdifftime=difftime(epochtime.tv_sec,frametime[z].tv_sec);
               if (tmpdifftime>statictime)
               {
                  framestatic[z]=1;
               }
               else
               {
                  framestatic[z]=0;
               }
            }
            if (frtlmrxb[z]==1)
            {
               framestaticb[z]=0;
               tmpdifftime=difftime(epochtime.tv_sec,frametimeb[z].tv_sec);
               if (tmpdifftime>statictime)
               {
                  framestaticb[z]=1;
               }
               else
               {
                  framestaticb[z]=0;
               }
            }
         }

         if ((framestatic[0]==1) && (framestatic[1]==1) && (framestatic[2]==1)
            && (framestatic[3]==1))
         {
            allframestatic=1;
         }
         else
         {
            allframestatic=0;
         }
         if ((framestaticb[0]==1) && (framestaticb[1]==1) && (framestaticb[2]==1) && (framestaticb[3]==1))
         {
            allframestaticb=1;
         }
         else
         {
            allframestaticb=0;
         }

         /* Handle Elapsed Time Counters */
         for (e=0; e<=3; e++)
         {
            if (frtlmrx[e]==1)
            {
               elapsedtime=difftime(epochtime.tv_sec,frametime[e].tv_sec);
               elapseddays[e]=elapsedtime/86400.0;

               elapsedtime=elapsedtime-(elapseddays[e]*86400.0);
               elapsedhours[e]=elapsedtime/3600.0;
   
               elapsedtime=elapsedtime-(elapsedhours[e]*3600.0);
               elapsedmins[e]=elapsedtime/60.0;

               elapsedtime=elapsedtime-(elapsedmins[e]*60.0);
               elapsedsecs[e]=elapsedtime;
   
               bin2=0;
               if (e>=2)
               {
                  bin2=1;
                  bin1=e-2;
               }
               else
               {
                  bin1=e;
               }

               if (selsat==SAT_PCSAT)
               {
                  mvwprintw(tlmdateelp_win,2+e,2,"A-%d%d T#%03d T+%d Days %02d:%02d:%02d",bin2,bin1,elptlmno[e],(int)elapseddays[e],(int)elapsedhours[e],(int)elapsedmins[e],(int)elapsedsecs[e]);
               }
               else
               {
                  mvwprintw(tlmdateelp_win,2+e,2,"F-%d%d T#%03d T+%d Days %02d:%02d:%02d",bin2,bin1,elptlmno[e],(int)elapseddays[e],(int)elapsedhours[e],(int)elapsedmins[e],(int)elapsedsecs[e]);
               }
            }
            if ((frtlmrxb[e]==1) && (selsat==SAT_PCSAT))
            {
               elapsedtimeb=difftime(epochtime.tv_sec,frametimeb[e].tv_sec);
               elapseddaysb[e]=elapsedtimeb/86400.0;

               elapsedtimeb=elapsedtimeb-(elapseddaysb[e]*86400.0);
               elapsedhoursb[e]=elapsedtimeb/3600.0;
   
               elapsedtimeb=elapsedtimeb-(elapsedhoursb[e]*3600.0);
               elapsedminsb[e]=elapsedtimeb/60.0;

               elapsedtimeb=elapsedtimeb-(elapsedminsb[e]*60.0);
               elapsedsecsb[e]=elapsedtimeb;
   
               bin2=0;
               if (e>=2)
               {
                  bin2=1;
                  bin1=e-2;
               }
               else
               {
                  bin1=e;
               }

               mvwprintw(tlmdateelpb_win,2+e,2,"B-%d%d T#%03d T+%d Days %02d:%02d:%02d",bin2,bin1,elptlmno[e],(int)elapseddaysb[e],(int)elapsedhoursb[e],(int)elapsedminsb[e],(int)elapsedsecsb[e]);
            }
         }

         /* UTC and LCL Clocks Update */

         mvwprintw(clocks_win,1,3,"%4d/%02d/%02d %02d:%02d:%02d UTC",(tmzulu.tm_year+1900),(tmzulu.tm_mon+1),tmzulu.tm_mday,tmzulu.tm_hour,tmzulu.tm_min,tmzulu.tm_sec);
         mvwprintw(clocks_win,2,3,"%4d/%02d/%02d %02d:%02d:%02d %s",(tmlocal.tm_year+1900),(tmlocal.tm_mon+1),tmlocal.tm_mday,tmlocal.tm_hour,tmlocal.tm_min,tmlocal.tm_sec,tzname[0]);
   
      /* Predict Window Update */

         if (preden==1)
         {
            mvwprintw(qth_win,1,2,"                        ");
            mvwprintw(qth_win,3,2,"                        ");
            mvwprintw(qth_win,1,3,"Long %2.2f%c  Lat %2.2f%c",birdlong,birdew,birdlat,birdns);
            mvwprintw(qth_win,3,3,"Range %5.0fkm Ecl %2.2f",birdrange,birdeclipse);
            mvwprintw(clocks_win,3,3,"%05d/%04d %02d:%02d:%02d MET",(int)birdorbit,(int)metdays,(int)methours,(int)metmins,(int)metsecs);
         }

        if (anytlmrx==1)
        {
           switch (selsat)
           {
              case SAT_PCSAT:
                 pcsat_static();
                 break;
              case SAT_PCSAT2:
                 pcsat2_static();
                 break;
           }
        }

        touchwin(clocks_win);
        touchwin(header_win);
        touchwin(qth_win);
        touchwin(tlm_win);
        touchwin(raw_win);
        touchwin(cmd_win);
        touchwin(arm_win);
        touchwin(timer_win);

        if (selsat==SAT_PCSAT)
        {
           touchwin(tlmb_win);
           touchwin(rawb_win);
           touchwin(tlmdateutcb_win);
           touchwin(tlmdatelclb_win);
           touchwin(tlmdatemetb_win);
           touchwin(tlmdateelpb_win);
        }

        touchwin(tlmdateutc_win);
        touchwin(tlmdatelcl_win);
        touchwin(tlmdatemet_win);
        touchwin(tlmdateelp_win);

        wrefresh(clocks_win);
        wrefresh(qth_win);
        wrefresh(header_win);
        wrefresh(cmd_win);
        wrefresh(arm_win);
        wrefresh(timer_win);

        keypress=getch();
        if (keypress=='\t')
        {
           show_panel(tlmpanptr[cur_tlm_ptr]);
           cur_tlm_ptr++;
           if (cur_tlm_ptr>=numtlmviews)
              cur_tlm_ptr=0;
        }

        if ((keypress=='t') || (keypress=='T'))
        {
           show_panel(tlmdatepanptr[cur_tlmdate_ptr]);
           cur_tlmdate_ptr++;
           if (cur_tlmdate_ptr>numdatewins)
              cur_tlmdate_ptr=0;
        }

        if ((keypress=='q') || (keypress=='Q'))
            quit=1;
  
        update_panels();
        doupdate();         
     } while ((aprschar!=13) && (quit!=1)); 

   if (quit!=1)
   {
      foundpkt=0;		/* Assume its not a tlm pkt */
      pcsatside=0;		/* Assume we have the A side of PCSAT */

      if (strncmp(aprsbuf,satcall,strlen(satcall))==0)
         foundpkt=1;
      if (((strncmp(aprsbuf,satcallb,strlen(satcallb))==0) && (selsat==SAT_PCSAT)))
      {
         foundpkt=1;
         pcsatside=1;
      }

      if (foundpkt==1)
      {
         /* Detect Start of telemetry bits */

         tlmcount=0;
         tlmpktdtd=0;
         aprstlmstart=aprsbuf[tlmcount];
         do
         {
            if (aprstlmstart==':')
            {
               /* Found our pkt */

               tlmcount++;
               if (aprsbuf[tlmcount]=='T')
               {
                  /* TLM Packet Detected. Copy and Decode */
                  tlmpktdtd=1;
                  if (pcsatside==0)
                  {
                     anytlmrx=1;
                     allframestatic=0;
                  }
                  else
                  {
                     anytlmrxb=1;
                     allframestaticb=0;
                  }

                  for (k=0; k<=41; k++)
                  {
                     tlmpkt[k]=aprsbuf[(tlmcount+k)];
                  }

                  /* Copy TLM Packet into Raw Array */
                  sscanf(tlmpkt,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",&discard01,&discard02,&rawtlmno[0],&rawtlmno[1],&rawtlmno[2],&discard03,&rawtlmstr[0][0],&rawtlmstr[0][1],&rawtlmstr[0][2],&discard04,&rawtlmstr[1][0],&rawtlmstr[1][1],&rawtlmstr[1][2],&discard05,&rawtlmstr[2][0],&rawtlmstr[2][1],&rawtlmstr[2][2],&discard06,&rawtlmstr[3][0],&rawtlmstr[3][1],&rawtlmstr[3][2],&discard14,&rawtlmstr[4][0],&rawtlmstr[4][1],&rawtlmstr[4][2],&discard07,&rawcmdbits[0],&rawcmdbits[1],&rawcmdbits[2],&rawcmdbits[3],&rawcmdbits[4],&rawcmdbits[5],&rawcmdbits[6],&rawcmdbits[7],&discard10,&sbits[0],&sbits[1],&rawfrnum[0],&rawfrnum[1],&discard11,&rawarmbit,&discard13);

                  /* Get Frame Number, and Update last rx date */

                  tlmframe=((rawfrnum[0]-48)*2);
                  tlmframe=tlmframe+(rawfrnum[1]-48);

                  if (pcsatside==0)
                  {
                     frtlmrx[tlmframe]=1;
                     gettimeofday(&frametime[tlmframe],&framezone[tlmframe]);
                     gmtime_r(&frametime[tlmframe].tv_sec,&tmframe[tlmframe][0]);
                     localtime_r(&frametime[tlmframe].tv_sec,&tmframe[tlmframe][1]);

                     framemet[tlmframe]=difftime(frametime[tlmframe].tv_sec,epochbird);
                     framedays[tlmframe]=framemet[tlmframe]/86400.0;
                     framemet[tlmframe]=framemet[tlmframe]-(framedays[tlmframe]*86400.0);

                     framehours[tlmframe]=framemet[tlmframe]/3600.0;
                     framemet[tlmframe]=framemet[tlmframe]-(framehours[tlmframe]*3600.0);

                     framemins[tlmframe]=framemet[tlmframe]/60;
                     framemet[tlmframe]=framemet[tlmframe]-(framemins[tlmframe]*60.0);
                     framesecs[tlmframe]=framemet[tlmframe];
                  }
                  else
                  {
                     frtlmrxb[tlmframe]=1;

                     gettimeofday(&frametimeb[tlmframe],&framezoneb[tlmframe]);
                     gmtime_r(&frametimeb[tlmframe].tv_sec,&tmframeb[tlmframe][0]);
                     localtime_r(&frametimeb[tlmframe].tv_sec,&tmframeb[tlmframe][1]);
   
                     framemetb[tlmframe]=difftime(frametimeb[tlmframe].tv_sec,epochbird);
                     framedaysb[tlmframe]=framemetb[tlmframe]/86400.0;
                     framemetb[tlmframe]=framemetb[tlmframe]-(framedaysb[tlmframe]*86400.0);

                     framehoursb[tlmframe]=framemetb[tlmframe]/3600.0;
                     framemetb[tlmframe]=framemetb[tlmframe]-(framehoursb[tlmframe]*3600.0);

                     frameminsb[tlmframe]=framemetb[tlmframe]/60;
                     framemetb[tlmframe]=framemetb[tlmframe]-(frameminsb[tlmframe]*60.0);
                     framesecsb[tlmframe]=framemetb[tlmframe];
                  }
                  /* Convert to ints ready for decode() */

                  for (l=0; l<=4; l++)
                  {
                     strncpy(tmptlmstr,rawtlmstr[l],3);
                     rawtlmint[tlmframe][l]=atoi(tmptlmstr);
                  }

                  strncpy(tmptlmnum,rawtlmno,3);
                  elptlmno[tlmframe]=atoi(tmptlmnum);

                  lasttlmnum=currtlmnum;
                  currtlmnum=atoi(tmptlmnum);

                  tlmarmbit[tlmframe]=(rawarmbit-48);

               }
           }
           tlmcount++;
           aprstlmstart=aprsbuf[tlmcount];
        } while ((tlmpktdtd!=1) && (tlmcount<strlen(aprsbuf)));

         switch (selsat)
         {
            case SAT_PCSAT:
               if (pcsatside==0)
               {
                  pcsat_a_decode();
                  pcsat_a_display();
               }
               else
               {
                  pcsat_b_decode();
                  pcsat_b_display();
               }
               break;
            case SAT_PCSAT2:
               pcsat2_decode();
               pcsat2_display();
               break;
         }
      }         
    } /* END QUIT IF */
  }
  endwin();

  return(0);
}

