/******************************************************************************
 *
 *	SEESATS.C	- Allows user to "see" where the satellites
 *			are currently located.
 *
 *	Translated from W0SL's ORBITS2.BAS (BASIC) by:
 *
 *		(c) Copyright
 *		November 1985
 *		Rich Bono - NM1D
 *		7 Redfield Circle
 *		Derry, New Hampshire 03038
 *		(603) 432-9002
 *
 *		**** Wild Mean Bits ****
 *
 *	This program in its entirety, or in its parts, is NOT in the public
 *	domain.  My Name/call/copyright must remain in both the source, and
 *	any executable produced from this source or any derivitive of it.
 *	Of course, if you make additions, you may add your name to the end
 *	of the copyright messages.
 *	This source is being made available to others to foster the goodwill
 *	and development of Amateur Radio satelellite operators.  If you make
 *	any changes to this code, either for to port this to another machine
 *	or architechture, you must send me the source for archival reasons,
 *	and so that I can incorporate improvements into the reference copy.
 *
 *
 *
 *	Note:	This program is in such poor shape because it is a
 *		(almost) a direct translation from a BASIC source!  I did all
 *		I could to disolve the spagetti sauce.  With more time, and
 *		revisions, the code will improve....
 *
 *	Revisions:
 *	Ver 1.0		25-Oct-88	localtime() was returning month as
 *					 base 0, needed base 1
 *
 *	Ver 0.9		19-Oct-88	Changed dos ints to calls to time(),
 *					 and localtime()
 *					 also changed for UNIX portability
 *
 *	Ver 0.8		16-Feb-88	Fixed sat loop, so not to repeat
 *					 selected bird
 *
 *	Ver 0.7		13-Feb-88	Changes to read data file routine
 *
 *	Ver 0.6		28-Dec-87	Fixed bug caused by MSC V4.0 float
 *					 logic
 *
 *	Ver 0.5		30-Sep-87	Added paged output mode logic,
 *					 changed abs() to fabs()
 *
 *			22-May-87	Added argument driven loops
 *			20-May-87	Added satelite data display
 *			15-May-87	Changed menu operation to toggle.
 *
 *			06-May-87	Added Version display & concatenated
 *					 data files to use SEESATS.DAT
 *
 *			13-Apr-87	Added prediction algorithms
 *			28-Sep-86	Worked on variable names
 *
 *	Hope to add/change:
 *
 *		Doppler correction, outputs to drive az-el antenna control.
 *		Make bird data into structure.
 *		Get RID of all these *GLOBALS*!!
 *
 *	Notes:
 *
 *	This code was kept as generic as possible, that is, NO terminal
 *	control features were used to allow this to be fairly portable.
 *
 *	Currently compiles with Microsoft-C, see GetAKeyNoEcho() for
 *	possible non-portable code.
 *
 *	Set the FORMSDOS or FORUNIX flag as appropriate
 *
 *	This has been tested under MS-DOS and OS/2
 */

#define	VERSION	"1.0"		/* Version as displayed by program	*/

#include	<stdio.h>
#include	<math.h>
#include	<time.h>
#include	<ctype.h>

#define	FORMSDOS	1	/* 1 = for MSDOS or OS/2	*/
#define	FORUNIX		0	/* 1 = for UNIX			*/

/* #define	fopen	fpopen	/* open files with aid of MS-DOS PATH */

#define	DATAFILE	"seesats.dat"	/* file that contains station &	*/
					/* bird information		*/

#define	bool		int
#define	ESC		27		/* Escape key	*/
#define	TRUE		(1)
#define	FALSE		(0)
#define abs(a)		(((a) < 0) ? -(a) : (a))
#define	MAXTRACKED	20	/* maximum number of satellites	*/

/************ GLOBALs ****************/

double	pi		= 3.1415926535;	/* P1 value of PI		*/
double	pi_2;				/* P2 PI squared		*/
double	pi_180;				/* P0 PI/180			*/

double	one3rd		= 1.0/3.0;	/* one third			*/

double	e_radius	= 6378.16;	/* R0 Earth's radius		*/
double	e_flat		= 298.16;	/* F  1/Earth flattening	*/
					/*		 coeficient	*/
double	e_gm		=75369793000000.0;/* G0 GM of Earth in 		*/
					/*	(Orbits/day)^2/km^3	*/

double	stn_latitude;			/* L9 station latitude		*/
double	stn_longitude;			/* W9 station longitude		*/
double	stn_height;			/* H9 station altitude		*/
char	stn_call[8+1];			/* C$ station call sign		*/
int	stn_utc;			/* Number of hours to change to	*/
					/*  UTC from local time		*/

int	s_year1[20+1];			/* Y1 siderial year info	*/
int	s_year2;			/* X2				*/
double	s_year3[20+1];			/* G3				*/
double	s_ratio	= 1.0027379093;		/* G1 Sidereal/Solar time	*/
					/*		rate ratio	*/

char	sat_name[MAXTRACKED+1][10];	/* I$ sat name			*/
double	beacon_freq[MAXTRACKED+1];	/* F1				*/
double	epoch_orbit[MAXTRACKED+1];	/* K0				*/
int	epoch_yr[MAXTRACKED+1];		/* Y3				*/
double	epoch_day[MAXTRACKED+1];	/* T0				*/
double	raan[MAXTRACKED+1];		/* O0				*/
double	inclination[MAXTRACKED+1];	/* I0				*/
double	eccentricity[MAXTRACKED+1];	/* E0				*/
double	arg_of_perigee[MAXTRACKED+1];	/* W0				*/
double	mean_anomoly[MAXTRACKED+1];	/* M0				*/
double	mean_motion[MAXTRACKED+1];	/* N0				*/
double	decay_rate[MAXTRACKED+1];	/* N1				*/


double	eccent,
	realtime,
	sat_orbit,
	orbit_pi2,
	sat_height,
	this_orbit,
	cos_eccent,
	sin_eccent,
	sat_latitude,
	sat_range,
	sat_longitude,
	cos_s_lon,
	s_lat_pi180,
	sin_s_lon,
	sat_azimuth,
	sin_s_lat,
	sat_elevation,
	s_h_radis,
	cos_s_lat,
	sat_phase,
	stn_x,
	stn_y,
	stn_z;

int	max_sats;
int	sider_cnt;

struct	{
		int	hour;
		int	minute;
		int	second;
		int	tenth;
	} static_time;

struct	{
		int	year;
		int	month;
		int	day;
	} static_date;

int	dos_time	= TRUE;	/* when true read dos clock, else increment	*/
				/* clock by min_inc				*/
int	min_inc		= 10;	/* number of minutes to increment clock by	*/

int	in_view		= FALSE;/* when TRUE, only print data is sat is in view	*/
int	aos_los		= FALSE;/* when TRUE, only print data at (near) AOS/LOS	*/
int	sel_bird	= 0;	/* when not 0, only use selected satelite	*/
int	page_mode	= TRUE;	/* when TRUE, give user a page at a time	*/

/*****************************************************************************
 *
 *	GetAKeyNoEcho() - read one key without echo
 *
 *		if no input available return (0)
 *
 *              else return key
 *
 *     Note: this will not allow the NUL (CTRL-@) character to be input
 *
 */

int GetAKeyNoEcho()
{
#if	FORMSDOS
	if(kbhit())
	{
		return(getch());	/* read key without echo */
	}
	else
	{
		return(0);		/* no key to read */
	}

#endif	/* FORMSDOS */

#if	FORUNIX
#include	<termio.h>

struct	termio	tty, savetty;
int	stat;
char	keyin;

	if(isatty(fileno(stdin)))
	{
	    ioctl(fileno(stdin), TCGETA, &tty); /* read current settings */

	    savetty = tty;			/* save current settings */

	    tty.c_lflag &= ~ (ICANON|ECHO);	/* allow read of char without echo */
	    tty.c_cc[VMIN] = 0;			/* allow read without blocking */
	    tty.c_cc[VTIME] = 0;		/* no input timer */

	    ioctl(fileno(stdin), TCSETA, &tty); /* set new parameters */
	}

	stat = read(fileno(stdin), &keyin, 1); /* read one character */

	if(isatty(fileno(stdin)))
	{
	    ioctl(fileno(stdin), TCSETA, &savetty); /* restore previous settings */
	}

	return(stat ? ((int) keyin) : 0);	/* return key read if any, else return 0 */

#endif	/* FORUNIX */

} /* end of GetAKeyNoEcho() */

/****************************************************************************/
main(argc, argv)
int	argc;
char	*argv[];
{

FILE		*fp, *fopen();
int		hour(), minute(), second(), day(), month(), year();
int		status;
int		loops;			/* number of loops to perform	*/
int		forever;		/* flag, is loops decremented?	*/
char		*date();
char		buffer[132];
register	sat_number;

	printf("\nSeesats  version %s - (c) Copyright 1985 - By Rich Bono, NM1D.\n\n", VERSION);


	/*********************************/
	/* read earth station parameters */
	/*********************************/

	fp = fopen(DATAFILE,"r");

	if(!fp)
	 {
	 	fprintf(stderr, "\nFile %s missing!\n\n", DATAFILE);
	 	exit(1);
	 }

	do	/* eat any comment lines, output note lines */
	{
	 	fgets(buffer, sizeof(buffer), fp);

		if(buffer[0] == '|')	/* output lines that begin with | */
		{			/* to stdout			  */
			printf("%s", &buffer[1]);
		}

	} while (buffer[0] == ';' || buffer[0] == '|');

	if( 5 != sscanf(buffer, "%lf %lf %lf %s %d",
				&stn_latitude, &stn_longitude, &stn_height,
				stn_call, &stn_utc)
	  )
	 {
	 	fprintf(stderr,"\nError reading file %s for earth station information!\n\n", DATAFILE);

		fprintf(stderr,"Should be latitude longitude height station ID and UTC correction\n");
		fprintf(stderr,"%lf %lf %lf %s %d\n",
			&stn_latitude, &stn_longitude, &stn_height,stn_call, stn_utc);


		fclose(fp);
	 	exit(1);
	 }

	fprintf(stderr,"Earth location data entered for '%s'.\n\n", stn_call);

	/************************/
	/* initialize constants	*/
	/************************/

	pi_2		= 2.0 * pi;
	pi_180		= pi / 180.0;
	e_flat		= 1.0 / e_flat;
	s_lat_pi180	= stn_latitude * pi_180;
	sin_s_lat	= sin(s_lat_pi180);
	cos_s_lat	= cos(s_lat_pi180);
	sin_s_lon	= sin( -stn_longitude * pi_180);
	cos_s_lon	= cos(stn_longitude * pi_180);
	s_h_radis	= e_radius * ( 1.0 - (e_flat / 2.0) + (e_flat / 2.0) * cos(2.0 * s_lat_pi180)) + stn_height / 1000.0;
	s_lat_pi180	= atan( ((1.0 - e_flat)*(1.0 - e_flat)) * sin_s_lat / cos_s_lat);
	stn_z		= s_h_radis * sin(s_lat_pi180);
	stn_x		= s_h_radis * cos(s_lat_pi180) * cos_s_lon;
	stn_y		= s_h_radis * cos(s_lat_pi180) * sin_s_lon;

	dos_time = TRUE;

	settime();	/* initialize time and date structures	*/

	/**********************************/
	/* Initialize Sidereal time table */
	/**********************************/

	for(sider_cnt=1; sider_cnt<20; sider_cnt++)
	 {
		s_year1[sider_cnt] = sider_cnt + 1980;

		s_year2 = floor( (s_year1[sider_cnt] - 1.0) / 100.0);

		s_year3[sider_cnt] = 2.0 - s_year2 + floor(s_year2 / 4.0) +
				floor(365.25 * (s_year1[sider_cnt]-1.0)) +
				floor(30.6001 * 14);

		s_year3[sider_cnt] = (s_year3[sider_cnt] - 730550.5) / 36525;

		s_year3[sider_cnt] = (s_year3[sider_cnt] * (s_year3[sider_cnt] * (s_year3[sider_cnt] *
				(-7.1759593E-11) + .00000107759259) +
				100.002139)) + .279057273;

		s_year3[sider_cnt] = s_year3[sider_cnt] - floor(s_year3[sider_cnt]);

		s_year1[sider_cnt] = s_year1[sider_cnt] - 1900;
	 }


	/*******************************/
	/* initialize satellite matrix */
	/*******************************/

	for(max_sats=1; max_sats<=MAXTRACKED; )
	 {
	 	fgets(buffer, sizeof(buffer), fp);

		/* skip lines that begin with a ';' or '|' */
		/* output lines that begin with a '|; to stdout */
	 	if(buffer[0] == ';' || buffer[0] == '|')
	 	  {
	 	  	if(buffer[0] == '|')
	 	  	{
	 	  		printf("%s",&buffer[1]);
	 	  	}
			continue;
		  }

 		status = sscanf(buffer,"%s %d %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf",
 			sat_name[max_sats],
 			&epoch_yr[max_sats],
 			&epoch_day[max_sats],
 			&inclination[max_sats],
 			&raan[max_sats],
 			&eccentricity[max_sats],
 			&arg_of_perigee[max_sats],
 			&mean_anomoly[max_sats],
 			&mean_motion[max_sats],
 			&decay_rate[max_sats],
 			&epoch_orbit[max_sats],
 			&beacon_freq[max_sats]
 			    );

	  	if(feof(fp) || (status != 12))
	  	 {
	  	 	break;
	  	 }

 	 	fprintf(stderr,"Data for %2d satellite%s read.\r",max_sats,(max_sats==1?" ":"s"));


/*
 * 		printf("%s %d %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n",
 * 			sat_name[max_sats],
 * 			epoch_yr[max_sats],
 * 			epoch_day[max_sats],
 * 			inclination[max_sats],
 * 			raan[max_sats],
 * 			eccentricity[max_sats],
 * 			arg_of_perigee[max_sats],
 * 			mean_anomoly[max_sats],
 * 			mean_motion[max_sats],
 * 			decay_rate[max_sats],
 * 			epoch_orbit[max_sats],
 * 			beacon_freq[max_sats]
 *		    );
 */


		if(!((epoch_yr[max_sats] == year()) || (epoch_yr[max_sats] == year()-1)))
		 {
		 	fprintf(stderr, "\nThe elements for satellite #%d (%s) is not from the\n", max_sats, sat_name[max_sats]);
		 	fprintf(stderr, " current or preceding year.  The current date is %s. Set the\n",date());
		 	fprintf(stderr, " system date or update the satellite orbital elements.\n");
			exit(1); /* back to menu if any */
		 }

		max_sats++;

	 } /* end of for(max_sats=1; max_sats<=MAXTRACKED;) */

	if(!page_mode)
	{
		fprintf(stderr, "\n\n Press [ENTER] for menu . . .\n");
	}
	else
	{
		printf("\n");
	}

	/********************************/
	/*	Orbit calculation loop	*/
	/********************************/

	switch(argc)
	{
		default:
		case 1:		/* no command line, set up to run forever */
			dos_time = TRUE;
			loops	= 1;
			forever	= TRUE;
			break;

		case 2:
			loops = atoi(argv[1]);	/* get number of loops	*/

			if(loops > 0)		/* if legal number	*/
			{
				forever = FALSE; /* won't be running long*/
			}
			else
			{
				forever = TRUE;	/* will never end	*/
			}

			dos_time = TRUE;	/* be in realtime mode	*/

			break;

	} /* end of switch(argc) */

	while(loops)
	 {
	 	if(!dos_time)	/* if not in realtime */
	 	{
	 		settime();	/* calculate date & time here */
	 	}

		if(sel_bird)			/* if one bird */
		{
			if(GetAKeyNoEcho())
		 	{
	 	 		do_command();		/* give menu commands	*/
		 	}

			calc_orbit(sel_bird);	/* calculate orbital data */

			show_data(sel_bird);	/* show current data	*/
		}
		else				/* do all birds	*/
		{
			for(sat_number=1;sat_number < max_sats; sat_number++)
			 {
				if(GetAKeyNoEcho())
			 	{
			 	 	do_command();		/* give menu commands	*/
			 	}

				calc_orbit(sat_number);	/* calculate orbital data */

				show_data(sat_number);	/* show current data	*/

			 } /* end for(sat_number=1;sat_number < max_sats; sat_number++) */
		}

		if(!forever)		/* if not running forever	*/
		{
			loops--;	/* count this loop		*/
		}

	 } /* end while(loops) */

}	/* end of main()	*/

/*****************************************************************************
 *
 *	calc_orbit() - calculate orbital data
 *
 */
calc_orbit(sat_number)
register sat_number;
{
register	loop_cnt;
bool	calc;
int	hour(), minute(), second(), day(), month(), year();
char	*date();
double	c[3+1][2+1];
double	xx,
	yy,
	zz,
	a0,
	c0,
	m0,
	n0,
	o0,
	q0,
	s0,
	w0,
	x_0,
	y_0,
	c1,
	e1,
	m1,
	s1,
	x1,
	y_1,
	z1,
	c2,
	e2,
	g2,
	k2,
	s2,
	r3,
	b5,
	c5,
	m5,
	s5,
	x5,
	y5,
	z5,
	c7,
	g7,
	s7,
	x8,
	y8,
	z8;

double	temp;

 	n0 = mean_motion[sat_number] + 2.0 * (realtime - epoch_day[sat_number]) * decay_rate[sat_number];
 	a0 = pow((e_gm / (n0 * n0)), one3rd);
	e2 = 1.0 - eccentricity[sat_number] * eccentricity[sat_number];
	e1 = sqrt(e2);
	q0 = mean_anomoly[sat_number] / 360.0 + epoch_orbit[sat_number];

	k2 = 9.95 * pow((e_radius / a0), 3.5) / (e2 * e2);
	s1 = sin(inclination[sat_number] * pi_180);
	c1 = cos(inclination[sat_number] * pi_180);

	calc_time(sat_number);	/* update realtime for this bird	*/

	o0 = raan[sat_number] - (realtime - epoch_day[sat_number]) * k2 * c1;
	s0 = sin(o0 * pi_180);
	c0 = cos(o0 * pi_180);
	w0 = arg_of_perigee[sat_number] + ( realtime - epoch_day[sat_number]) * k2 *
		(2.5 * (c1 * c1) - .5);
	s2 = sin(w0 * pi_180);
	c2 = cos(w0 * pi_180);
	c[1][1] = /*+*/(c2 * c0) - (s2 * s0 * c1);
	c[1][2] = -(s2 * c0) - (c2 * s0 * c1);
	c[2][1] = /*+*/(c2 * s0) + (s2 * c0 * c1);
	c[2][2] = -(s2 * s0) + (c2 * c0 * c1);
	c[3][1] = /*+*/(s2 * s1);
	c[3][2] = /*+*/(c2 * s1);
	this_orbit = (mean_motion[sat_number] + decay_rate[sat_number] * (realtime - epoch_day[sat_number])) *
		(realtime - epoch_day[sat_number]) + q0;

	sat_orbit = floor(this_orbit);
	sat_phase = floor((this_orbit-sat_orbit) * 256.0);
	orbit_pi2 = (this_orbit - sat_orbit) * pi_2;
	eccent = orbit_pi2 + eccentricity[sat_number] * sin(orbit_pi2) + .5 *
		(eccentricity[sat_number] * eccentricity[sat_number]) * sin(2.0 * orbit_pi2);

	calc = TRUE;

	while(calc)	/* calculating */
	 {
		sin_eccent = sin(eccent);
		cos_eccent = cos(eccent);
		r3 = 1.0 - eccentricity[sat_number] * cos_eccent;
		m1 = eccent - eccentricity[sat_number] * sin_eccent;
		m5 = m1 - orbit_pi2;

		if( fabs(m5) < .000001)
		 {
			calc = FALSE;
		 }
		else
		 {
			eccent = eccent - m5 / r3;
		 }

	 } /* end while(TRUE) calc */

	x_0 = a0 * (cos_eccent - eccentricity[sat_number]);
	y_0 = a0 * e1 * sin_eccent;
	sat_height = a0 * r3;
	x1 = x_0 * c[1][1] + y_0 * c[1][2];

	y_1 = x_0 * c[2][1] + y_0 * c[2][2];
	z1 = x_0 * c[3][1] + y_0 * c[3][2];

	for(loop_cnt = 1; loop_cnt != sider_cnt; loop_cnt++)
	 {
		if(epoch_yr[sat_number] == s_year1[loop_cnt])
		 {
		 	g2 = s_year3[loop_cnt];
		 }
	 }
	g7 = realtime * s_ratio + g2;
	temp = g7;			/* this is to force FWAIT by MSC V4.0! */
	g7 = (g7 - floor(g7)) * pi_2;
	s7 = -sin(g7);
	c7 = cos(g7);
	xx = /*+*/(x1 * c7) - (y_1 * s7);
	yy = /*+*/(x1 * s7) + (y_1 * c7);
	zz = z1;
	x5 = (xx - stn_x);
	y5 = (yy - stn_y);
	z5 = (zz - stn_z);
	sat_range = sqrt(x5 * x5 + y5 * y5 + z5 * z5);
	z8 = /*+*/(x5 * cos_s_lon * cos_s_lat) + (y5 * sin_s_lon * cos_s_lat) + (z5 * sin_s_lat);
	x8 = -(x5 * cos_s_lon * sin_s_lat) - (y5 * sin_s_lon * sin_s_lat) + (z5 * cos_s_lat);
	y8 = /*+*/(y5 * cos_s_lon) - (x5 * sin_s_lon);
	s5 = z8/sat_range;
	c5 = sqrt(1.0 - s5 * s5);
	sat_elevation = atan(s5 / c5) / pi_180;

	if(x8 < 0.0)
	 {
	 	sat_azimuth = pi + atan(y8 / x8);
	 }
	else
	 {
	 	if(x8 > 0.0 && y8 >= 0.0)
	 	 {
	 	 	sat_azimuth = atan(y8/x8);
	 	 }
	 	else
	 	 {
	 	 	if(x8 > 0.0)
	 	 	 {
	 	 		sat_azimuth = pi_2 + atan(y8/x8);
	 	 	 }
	 	 	else
	 	 	 {
	 	 	 	if(y8 < 0.0)
	 	 	 	 {
	 	 	 	 	sat_azimuth = 3.0 * pi / 2.0;
	 	 	 	 }
	 	 	 	else
	 	 	 	 {
	 	 	 	 	sat_azimuth = pi / 2.0;
	 	 	 	 }
	 	 	 }
		 }
	 }
	sat_azimuth = sat_azimuth / pi_180;
	if(xx < 0.0)
	 {
	 	sat_longitude = pi + atan(yy/xx);
	 }
	else
	 {
	 	if(xx > 0.0 && yy >= 0.0)
	 	 {
	 	 	sat_longitude = atan(yy/xx);
	 	 }
	 	else
	 	 {
	 	 	if(xx > 0.0)
	 	 	 {
	 	 	 	sat_longitude = pi_2 + atan(yy / xx);
	 	 	 }
	 	 	else
	 	 	 {
	 	 	 	if(yy < 0.0)
	 	 	 	 {
	 	 	 	 	sat_longitude = 3.0 * pi/2.0;
				 }
				else
				 {
				 	sat_longitude = pi / 2.0;
				 }
			 }
		 }
	 }
	sat_longitude = 360.0 - sat_longitude / pi_180;
	b5 = zz / sat_height;
	sat_latitude = atan(b5 / (sqrt(1 - (b5 * b5)))) / pi_180;

} /* end of calc_obit() */

 
/****************************************************************************
 *
 *	show_data() - show current calculated data
 *
 *	output a header line for each new day, and for each 'page'
 */

show_data(sat_number)
register sat_number;
{
char	*stime(), *date();
char	buffer[80];
static	line = 0;
static	oldday = 0;

	if(
	   (in_view && (sat_elevation < 0.0))
	  )
	 {
	 	return;
	 }
	 
	if((line-- <= 0) || (oldday != day()))
	 {
	 	oldday = day();

	 	line = MAXTRACKED-1;

	 	if(page_mode)
	 	{
	 		fprintf(stderr, "\n-- [ENTER] to continue, M for menu -- ");
			fgets(buffer, sizeof(buffer), stdin);

			if(tolower(buffer[0])=='m')	/* if user wants back to menu */
			{
				do_command();		/* handle command	*/
				return;
			}
	 	}

		printf("\nFor %8s, at %7.3f Latitude, %7.3f Longitude, %7.2f M Altitude",
			 stn_call,
			 stn_latitude,
			 stn_longitude,
			 stn_height
			 );

		printf("\nSatellite   Az  El RngKm AltKm   Lat  Long  Orbit   Ph  Beacon %s\n",date());
	 }

	printf("%-10s %3.0f %3.0f %5.0f %5.0f %5.1f %5.1f %6.0f %4.0f %7.3f  %s\n",
			 sat_name[sat_number],		/* Name		*/
			 sat_azimuth,			/* Azimuth	*/
			 sat_elevation,			/* Elevation	*/
			 sat_range,			/* Range_Km	*/
			 (sat_height - e_radius),	/* Height_Km	*/
			 sat_latitude,			/* Latitude	*/
			 sat_longitude,			/* Longitude	*/
			 sat_orbit,			/* Orbit	*/
			 sat_phase,			/* Phase	*/
			 beacon_freq[sat_number],	/* Freq (someday doppler corrected)*/
			 stime()
		);

} /* end of show_data() */
/*******************************************************************************
 *
 *	show_elements(sat) - display current element data for sat.
 *
 *
 */

show_elements(sat)
int	sat;
{

	printf("\n");
	printf("Name                : %9s\n",		sat_name[sat]);
	printf("Epoch year          : %9d\n",
		(epoch_yr[sat]<1900 ? epoch_yr[sat] + 1900 : epoch_yr[sat]));
	printf("Epoch day           : %20.10lf\n",	epoch_day[sat]);
	printf("Epoch orbit         : %20.10lf\n",	epoch_orbit[sat]);
	printf("Inclination         : %20.10lf\n",	inclination[sat]);
	printf("RAAN                : %20.10lf\n",	raan[sat]);
	printf("Eccentricity        : %20.10lf\n",	eccentricity[sat]);
	printf("Argument of perigee : %20.10lf\n",	arg_of_perigee[sat]);
	printf("Mean anomoly        : %20.10lf\n",	mean_anomoly[sat]);
	printf("Mean motion         : %20.10lf\n",	mean_motion[sat]);
	printf("Decay rate          : %20.10lf\n",	decay_rate[sat]);
	printf("Beacon frequency    : %20.10lf\n",	beacon_freq[sat]);
	printf("\n");

} /* end of show_elements() */

/*******************************************************************************
 *
 *	do_command() - Handle any keyboard entries
 *			Present menu.
 *
 */

do_command()
{
int	index;
int	cmd_loop;
char	buffer[85];

	cmd_loop = TRUE;	/* keep looping until user is done	*/
				/*  with menu				*/
	do
	{

		fprintf(stderr, "\n\n\t\t\t Current selections:\n");

/* the 3 fields for the following are : 10 chars for description, 16 chars data... */

		fprintf(stderr,"\nMode is...%-16s  Print...%-16s  Select..%-16s\n",
			(dos_time ? "realtime" : "prediction"),
			(in_view ? "when in view" : "all calculations"),
			(sel_bird ? sat_name[sel_bird] : "all satelites")
			);
		fprintf(stderr,  "Output is.%-16s\n",
			(page_mode ? "paged" : "continuous")
			);

		fprintf(stderr, "\n\n\t\t\tSeesats menu -\n\n");
		fprintf(stderr,   "\t\t1   - Mode to %s\n", (dos_time ? "prediction":"realtime"));
		fprintf(stderr,   "\t\t2   - Print %s\n",(in_view ? "all calculations" : "when in view"));
		fprintf(stderr,   "\t\t3   - Select %s\n",(sel_bird ? "all satelites" : "satelite of interest"));
		fprintf(stderr,   "\t\t4   - Print current element data for satelites\n");
		fprintf(stderr,   "\t\t5   - Change output mode to %s\n", (page_mode ? "continuous" : "paged"));

		fprintf(stderr, "\n\t\t0 - Quit.\n\n");

		fprintf(stderr, "Enter number for desired function ([ENTER] to continue) : ");

		fgets(buffer, sizeof(buffer), stdin);

	 	switch(buffer[0])
	 	 {
		 	case '1':	/* select either realtime or predictions	*/

		 		dos_time = !dos_time;	/* toggle mode	*/

				if(dos_time)
				{
			 		fprintf(stderr,"\n\nRunning in realtime . . .\n");
			 		settime();
			 	}
			 	else
			 	{
					fprintf(stderr, "\n\n\nEnter start day, month & year [ENTER = %02d/%02d/%02d ] (dd/mm/yy) : ", 
						static_date.day, static_date.month, static_date.year-1900);
						fgets(buffer, sizeof(buffer), stdin);
					if(strlen(buffer))
					{
						sscanf(buffer, "%d/%d/%4d",&static_date.day, &static_date.month, &static_date.year);
					}

					if(static_date.year < 1900)
					{
						static_date.year += 1900;
					}

					fprintf(stderr, "\nEnter start hour & minute      [ENTER = %02d:%02d ]      (hh:mm) : ",
						static_time.hour, static_time.minute);
						static_time.second = 0;
						static_time.tenth = 0;

					fgets(buffer, sizeof(buffer), stdin);
					if(strlen(buffer))
					{
						sscanf(buffer, "%d:%d", &static_time.hour, &static_time.minute);
					}

					fprintf(stderr, "\nEnter number of minutes to increment  [ENTER = %3d ]         : ", min_inc);

					fgets(buffer, sizeof(buffer), stdin);
					if(strlen(buffer))
					{
						sscanf(buffer, "%d",&min_inc);
					}


				} /* end of if(dos_time) */

				break;

			case '2':	/* select only in view or all calculations	*/

				in_view = !in_view;
				if(in_view)
				{
					fprintf(stderr,"\n\nWill show data for satelites only when in view . . .\n");
				}
				else
				{
					fprintf(stderr,"\n\nWill show all calculated data.\n");
				}
				break;

			case '3':	/* select bird of interest	*/

				if(sel_bird)
				{
					sel_bird = 0;
					fprintf(stderr,"\n\nShow data for all satelites.\n");

				}
				else
				{
					fprintf(stderr, "\n\nSelect from the following list :\n\n");

					do
					{
						fprintf(stderr, "\t\t 0 = All the following\n");

						for(index=1; index < max_sats; index++)
						{

							fprintf(stderr, "\t\t%2d = %s\n",index, sat_name[index]);
						}

						fprintf(stderr, "\n\n\t\tSelect satelite by number [ENTER = %d] : ", sel_bird);

						fgets(buffer, sizeof(buffer), stdin);
						if(strlen(buffer))
						{
							sscanf(buffer, "%d",&sel_bird);
						}

					} while ((sel_bird >= max_sats) || (sel_bird < 0));

				} /* end of if(sel_bird) */

				break;

			case '4':	/* display element data for bird(s)	*/

				fprintf(stderr, "\n\nSelect from the following list to display current element data:\n\n");

				do
				{
					fprintf(stderr, "\t\t 0 = All the following\n");	
					for(index=1; index < max_sats; index++)
					{

						fprintf(stderr, "\t\t%2d = %s\n",index, sat_name[index]);
					}

					fprintf(stderr, "\n\n\t\tSelect satelite by number [ENTER = %d] : ", 0);

					fgets(buffer, sizeof(buffer), stdin);
					if(strlen(buffer))
					{
						index=0;
						sscanf(buffer, "%d",&index);
					}
					else
					{
						index = 0;
					}

				} while ((index >= max_sats) || (index < 0));


				if(index)
				{
					show_elements(index);	/* show current data for selected bird */
				}				else
				{
					for(index=1; index<max_sats; index++)
					{
						show_elements(index);	/* show current data for all birds */
					}
				}

				fprintf(stderr, "\n\n\tHit [ENTER] to continue : ");
				fgets(buffer, sizeof(buffer), stdin);

				break;

			case '5':	/* select paged or continuous output mode	*/

				page_mode = !page_mode;
				if(page_mode)
				{
					fprintf(stderr,"\n\nOutput mode changed to continuous output\n");
				}
				else
				{
					fprintf(stderr,"\n\nOutput mode changed to paged output\n");
				}
				break;

			case '0':
				fprintf(stderr, "\n\nSeeSats: done.\n\n");
				exit(0);
				break;

		 	default:
		 		cmd_loop = FALSE;
		 		break;

	 	 } /* end of switch(buffer[0]) */


	} while (cmd_loop); /* until done with command loop */

	if(in_view)	/* if in_view mode, machine may appear dead, tell user	*/
	{
		fprintf(stderr, "\nNOTE: There will be NOTHING displayed when none are in view!\n");
	}

	fprintf(stderr, "\n\n");


} /* end of do_command() */

/*********************************************
 *
 *	Real time functions
 *
 */
settime()	/* set the static_time structure to the current time	*/
{
long	l_systemtime;
struct	tm *st_systemtime;

extern struct static_time;

register int	carry;
static int days_in_mnth[13] =
			{
			0,
			31,
			28,
			31,
			30,
			30,
			30,
			31,
			31,
			30,
			31,
			30,
			31
			};

	if(dos_time)	/* read DOS clock */
	 {
	 	time(&l_systemtime);	/* read the current system time */
		st_systemtime = localtime(&l_systemtime); /* convert to parts */


		static_time.hour	= st_systemtime->tm_hour;
		/* add UTC offset	*/
		static_time.hour	+= stn_utc;

		static_time.minute	= st_systemtime->tm_min;
		static_time.second	= st_systemtime->tm_sec;
		static_time.tenth	= 0;

		/* year should include century, ie: 1988 not 88 */
		static_date.year	= st_systemtime->tm_year + 1900;

		/* month should be 1 through 12, 1 = January */
		static_date.month	= st_systemtime->tm_mon + 1;

		/* day is day of the month, 1 - 31 */
		static_date.day		= st_systemtime->tm_mday;


	 }
	else		/* increment time/date by min_inc */
	 {

		if((static_date.year % 4) == 0)
		 {
		 	days_in_mnth[2] = 29;
		 }
		else
		 {
		 	days_in_mnth[2] = 28;
		 }

	 	static_time.tenth	= 0;
	 	static_time.second	= 0;
	 	static_time.minute	+= min_inc;
	 }

	/* adjust rollover of time if needed */

 	carry			= static_time.minute/60;
 	static_time.minute	%= 60;
 	static_time.hour	+= carry;
 	carry			= static_time.hour/24;
 	static_time.hour	%= 24;
 	static_date.day		+= carry;
 	carry			= static_date.day/(days_in_mnth[static_date.month]+1);
 	static_date.day		%= (days_in_mnth[static_date.month]+1);
 	if(static_date.day == 0)
 	 {
 	 	static_date.day = 1;
 	 }
 	static_date.month	+= carry;
 	carry			= static_date.month/13;
 	static_date.month	%= 13;
 	if(static_date.month == 0)
 	 {
 	 	static_date.month = 1;
 	 }
 	static_date.year	+= carry;

} /* end of settime() */


int second()	/* return seconds part of clock	*/
{
extern struct static_time;

	return(static_time.second);
}

int minute()	/* return minutes part of clock	*/
{
extern struct static_time;

	return(static_time.minute);
}

int hour()	/* return hours part of clock */
{
extern struct static_time;

	return(static_time.hour);
}

int day()	/* return day of month	*/
{
extern struct static_date;

	return(static_date.day);
}

int month()	/* return month of year	*/
{
extern struct static_date;

	return(static_date.month);
}

int year()	/* return year		*/
{
extern struct static_date;

	return(static_date.year - 1900);
}

char *date()	/*return date in string format (ie: 23-Feb-86) */
{

static	char	date[20];
static	char	*mnth[13] = {	"***",
				"Jan",
				"Feb",
				"Mar",
				"Apr",
				"May",
				"Jun",
				"Jul",
				"Aug",
				"Sep",
				"Oct",
				"Nov",
				"Dec"
			 };
					

	sprintf(date,"%02d-%s-%02d",day(),mnth[month()],year());

	return(date);}

char *stime()	/*return time in string format (ie: 09:28:32) */
{

static	char	time[20];

	sprintf(time,"%02d:%02d:%02d",hour(),minute(),second());

	return(time);
}

calc_time(sat_number)	/* calculate the new realtime	*/
register sat_number;
{

	if(dos_time)	/* if in realtime, update time/date now */
	{
		settime();
	}


	realtime = floor(30.55 * (((double)month())+2.0)) - 2.0 * ( floor(.1 * (((double)month())+7.0))) - 91.0;
	if(month() > 2)
	 {
	 	if((((double)year())/4.0) == floor(((double)year())/4.0))
	 	 {
	 	 	realtime += 1.0;
	 	 }
	 }
	if(epoch_yr[sat_number] == year() - 1)
	 {
	 	realtime += 365.0;
	 	if(epoch_yr[sat_number]/4.0 == floor(epoch_yr[sat_number] / 4.0))
	 	 {
	 	 	realtime += 1.0;
	 	 }
	 }



	realtime = realtime + ((double)day()) + (((double)hour())/24.0) + (((double)minute())/1440.0) + (((double)second())/86400.0);

}

/* end of seesats.c	*/
