March Madness - GPS Satellites

This reads in data from a GPS, parses the GPS satellite position and draws them on a graphics LCD display

This is a continuation of yesterday's program.

This image shows you at the center and the location of the satellites with respect to you.
North is of course, 12:00. The outside circle is the horizon.

This is what it looks like after 12 hours. Note the "hole" at 12:00. There is very liitle coverage around the north pole.
So next time you are trecking across the artic, you will know not to rely on your GPS.


//************************************************************************
//*	GPS Almanac display
//*		by Mark Sproul
//*		March 7, 2010
//************************************************************************

#include	
#include	
#include	
#include	
#include	"WConstants.h"

#include	"wiring.h"

#ifdef __MWERKS__
	int	atoi(...);
	int	sprintf(...);
#endif

#define	_T6963_GRAPHICS_
//#define		_MEGA_


#ifdef _T6963_GRAPHICS_
	#include	
//	T6963 LCD(160,128,6,32);
	T6963 LCD(160,128,8,64);
	#define	kScreen_Width	160
	#define	kScreen_Height	128
#endif

#include	"HardwareSerial.h"
//#include	
#include	



#ifdef _T6963_GRAPHICS_
	#define	kTX_Pin		10
	#define	kRX_Pin		11
	#define	kPOWER_Pin	12

	#define	kLED1_PIN	13
//	#define	kLED2_PIN	13
#elif defined(_MEGA_)
	#define	kTX_Pin		10
	#define	kRX_Pin		11
	#define	kPOWER_Pin	12

	#define	kLED1_PIN	13
//	#define	kLED2_PIN	13
#else
	#define	kTX_Pin		4
	#define	kRX_Pin		5
	#define	kPOWER_Pin	6

	#define	kLED1_PIN	7
	#define	kLED2_PIN	8
#endif

#define kGPSRATE	 4800


typedef struct 
{
	unsigned int	elevation;
	unsigned int	snr;		//*	signal to noise ration
	unsigned int	asimuth;
} SAT_DATA;

//AFSoftSerial gpsSerial		=	AFSoftSerial(kTX_Pin, kRX_Pin);
SoftwareSerial gpsSerial		=	SoftwareSerial(kTX_Pin, kRX_Pin);


#define	kNMEAbuffSize	80		//	plenty big
char		gNMEAbuffer[kNMEAbuffSize];
char		gNMEAbuffidx;
int			gNMEAhour;
int			gNMEAminute;
int			gNMEAsecond;
int			gNMEAsatCount;

#define	kSatMaxCount	32
SAT_DATA	gNMEAsatData[kSatMaxCount];

//#define _OUTPUT_TO_CONSOLE_

//************************************************************************
void setup()
{
int	ii;

	Serial.begin(115200);
	Serial.println();
	Serial.println("GPS Clock");

	pinMode(kLED1_PIN, OUTPUT);
	pinMode(kLED1_PIN, OUTPUT);

	//*	turn on the GPS
	pinMode(kPOWER_Pin, OUTPUT);
	digitalWrite(kPOWER_Pin, LOW);		 // pull low to turn on!
	gpsSerial.begin(kGPSRATE);	//*	open GPS port
//	Serial.println("GPS Power turned on");
	
	gNMEAbuffidx	=	0;
	gNMEAsatCount	=	0;
	
	for (ii=0; ii 0) || (gNMEAsatData[ii].asimuth > 0))
		{
			azm		=	ReturnCompAngFromMapAng(gNMEAsatData[ii].asimuth);
			relv	=	(1.0 * gNMEAsatData[ii].elevation) / kDeg2Rad;
			razm	=	(1.0 * azm) / kDeg2Rad;

			dhy		=	cos(relv) * (circleRadius - 3);
			daj		=	cos(razm) * dhy;
			dop		=	sin(razm) * dhy;

			satCenterX	=	xCenter + daj;
			satCenterY	=	yCenter - dop;

			LCD.createLine(satCenterX - 2,	satCenterY,		satCenterX + 2,	satCenterY);
			LCD.createLine(satCenterX,		satCenterY - 2,	satCenterX,		satCenterY + 2);

		//	LCD.createCircle(satCenterX, satCenterY, 2);
		}
	}
	
	
#elif defined(foobar)
char	myString[32];
int		ii;
int		yy;

	sprintf(myString, "Sat cnt=%d", gNMEAsatCount);
	LCD.TextGoTo(0, 1);
	LCD.WriteString(myString);
	yy	=	2;
	for (ii=0; ii 0) || (gNMEAsatData[ii].asimuth > 0))
		{
			sprintf(myString, "%2d %2d %3d %2d",	ii,
													gNMEAsatData[ii].elevation,
													gNMEAsatData[ii].asimuth,
													gNMEAsatData[ii].snr);
			LCD.TextGoTo(0, yy);
			LCD.WriteString(myString);
		//	Serial.println(myString);
			
			yy++;
		}
	}

#endif
}



//************************************************************************
//*	GPS Clock
//*	$PSRFTXT,Version:GSW3.2.4_3.1.00.12-SDK003P1.00a 
//*	$PSRFTXT,Version2:F-GPS-03-0701301
//*	$PSRFTXT,WAAS Enable
//*	$PSRFTXT,TOW:  0
//*	$PSRFTXT,WK:   1399
//*	$PSRFTXT,POS:  6378137 0 0
//*	$PSRFTXT,CLK:  96250
//*	$PSRFTXT,CHNL: 12
//*	$PSRFTXT,Baud rate: 4800 
//*	$GPGGA,235947.031,,,,,0,00,,,M,0.0,M,,0000*5A
//*	$GPGSA,A,1,,,,,,,,,,,,,,,*1E
//*	$GPRMC,235947.031,V,,,,,,,281006,,*2E
//*	$GPGGA,235948.039,,,,,0,00,,,M,0.0,M,,0000*5D
//*	$GPGSA,A,1,,,,,,,,,,,,,,,*1E
//*	$GPRMC,235948.039,V,,,,,,,281006,,*29
//*	$GPGGA,235949.030,,,,,0,00,,,M,0.0,M,,0000*55
//*	$GPGSA,A,1,,,,,,,,,,,,,,,*1E
//*	$GPRMC,235949.030,V,,,,,,,281006,,*21
//*	$GPGGA,235950.030,,,,,0,00,,,M,0.0,M,,0000*5D
//*	$GPGSA,A,1,,,,,,,,,,,,,,,*1E
//*	$GPRMC,235950.030,V,,,,,,,281006,,*29
//*	$GPGGA,235951.038,,,,,0,00,,,M,0.0,M,,0000*54
//*	
//*	$GPGGA,003509.000,4027.4299,N,07430.2057,W,1,04,2.0,40.9,M,-34.1,M,,0000*56
//*	$GPGSA,A,3,32,14,31,30,,,,,,,,,4.0,2.0,3.5*37
//*	$GPRMC,003509.000,A,4027.4299,N,07430.2057,W,0.48,346.15,070310,,*15
//*	$GPGGA,003510.000,4027.4297,N,07430.2055,W,1,04,2.0,40.9,M,-34.1,M,,0000*52
//*	$GPGSA,A,3,32,14,31,30,,,,,,,,,4.0,2.0,3.5*37
//*	$GPGSV,3,1,12,25,70,326,,31,70,008,28,32,51,276,35,01,48,314,26*77
//*	$GPGSV,3,2,12,05,42,054,,14,40,112,22,16,37,195,23,20,28,304,28*70
//*	$GPGSV,3,3,12,30,23,045,28,06,18,074,,07,16,062,,22,09,168,*7D
//*	$GPRMC,003510.000,A,4027.4297,N,07430.2055,W,0.35,144.00,070310,,*1F
//*	$GPGGA,003511.000,4027.4291,N,07430.2051,W,1,04,2.0,40.8,M,-34.1,M,,0000*50
//*	$GPGSA,A,3,32,14,31,30,,,,,,,,,4.0,2.0,3.5*37
//*	$GPRMC,003511.000,A,4027.4291,N,07430.2051,W,1.38,153
//************************************************************************
void ProcessNMEA(char *nmeaBuffer)
{
long	nmeaSentanceType;
char	hourString[4];
char	minString[4];
char	secString[4];
char	myString[32];
int		ii;
int		cc;
int		comaCount;
int		parsedNum;
int		satEntryIndex;
int		satData[16];
int		gsvEntryCount;
int		gsvEntryNumber;
boolean	keepGoing;

	if ((nmeaBuffer[0] == '$') && (nmeaBuffer[1] == 'G'))
	{
		nmeaSentanceType	=	0;
		for (ii = 0; ii < 4; ii++)
		{
			nmeaSentanceType	=	nmeaSentanceType <<	8;
			nmeaSentanceType	+=	nmeaBuffer[2 + ii];
		}
		switch(nmeaSentanceType)
		{
		//*	Global Positioning System Fix Data
		//*	$GPGGA,003509.000,4027.4299,N,07430.2057,W,1,04,2.0,40.9,M,-34.1,M,,0000*56
		//	case 'PGGA':
			case 0x50474741:
		//		Serial.println(nmeaBuffer);
				ii				=	7;
				hourString[0]	=	nmeaBuffer[ii++];
				hourString[1]	=	nmeaBuffer[ii++];
				hourString[2]	=	0;

				minString[0]	=	nmeaBuffer[ii++];
				minString[1]	=	nmeaBuffer[ii++];
				minString[2]	=	0;

				secString[0]	=	nmeaBuffer[ii++];
				secString[1]	=	nmeaBuffer[ii++];
				secString[2]	=	0;
			//	Serial.print("\x0c");
				
				strcpy(myString,	hourString);
				strcat(myString,	":");
				strcat(myString,	minString);
				strcat(myString,	":");
				strcat(myString,	secString);
				strcat(myString,	" Z");
				
			#ifdef _T6963_GRAPHICS_
				LCD.TextGoTo(0,0);
				LCD.WriteString(myString);
			#else
			//	Serial.println(myString);
			#endif
				
				gNMEAhour		=	atoi(hourString);
				gNMEAminute		=	atoi(minString);
				gNMEAsecond		=	atoi(secString);
				if (gNMEAsecond == 0)
				{
			//		Serial.print("\x07");	//*	send a bell
				}
				
				gNMEAhour		+=	19;		//*	adjust to local time



				digitalWrite(kLED1_PIN, HIGH);		//*	turn on LED
				break;
			
			//*	GPS Satellites in view 
			//*	$GPGSV,3,1,12,25,70,326,,31,70,008,28,32,51,276,35,01,48,314,26*77
			//*	$GPGSV,3,2,12,05,42,054,,14,40,112,22,16,37,195,23,20,28,304,28*70
			//*	$GPGSV,3,3,12,30,23,045,28,06,18,074,,07,16,062,,22,09,168,*7D
			//	case 'PGSV':
			case 0x50475356:
			//	Serial.println(nmeaBuffer);
				for (ii=0; ii<16; ii++)
				{
					satData[ii]	=	0;;
				}
				digitalWrite(kLED1_PIN, LOW);		//*	turn on LED
				gsvEntryCount	=	0;
				gsvEntryNumber	=	0;
				ii				=	0;
				cc				=	0;
				comaCount		=	0;
				keepGoing		=	true;
				while ((nmeaBuffer[ii] != 0) && keepGoing)
				{
					if (nmeaBuffer[ii] == '*')
					{
						keepGoing	=	false;
					}
					if ((nmeaBuffer[ii] == ',') || (nmeaBuffer[ii] == '*'))
					{
						//*	time to do something with the string
						myString[cc++]	=	0;
						parsedNum		=	atoi(myString);
						
						if (comaCount == 1)
						{
							gsvEntryCount	=	parsedNum;
						}
						if (comaCount == 2)
						{
							gsvEntryNumber	=	parsedNum;
						}
						if (comaCount == 3)
						{
							gNMEAsatCount	=	parsedNum;
						}
						else if ((comaCount >= 4) && (comaCount <= 19))
						{
							satData[comaCount - 4]	=	parsedNum;
						}
						comaCount++;
						
						cc	=	0;
					}
					else
					{
						myString[cc++]	=	nmeaBuffer[ii];
					}
					
					ii++;
				}
				
				//*	go through the 4 entries
				for (ii=0; ii<4; ii++)
				{
					satEntryIndex	=	satData[(ii * 4)];
					if ((satEntryIndex > 0) && (satEntryIndex < 32))
					{
						gNMEAsatData[satEntryIndex].elevation	=	satData[(ii * 4) + 1];
						gNMEAsatData[satEntryIndex].asimuth		=	satData[(ii * 4) + 2];
						gNMEAsatData[satEntryIndex].snr			=	satData[(ii * 4) + 3];
					}
				}
				if ((gsvEntryCount > 0) && (gsvEntryNumber == gsvEntryCount))
				{
					DisplayGPSalmanac();
				}
				break;
		}
	}
}


//************************************************************************
void loop()
{
char	gpsChar;

	gpsChar	=	gpsSerial.read();
#ifdef _OUTPUT_TO_CONSOLE_
	Serial.write(gpsChar);
#endif
	if (gpsChar == 0x0d)
	{
		//*	if its a CR, process the line
		gNMEAbuffer[gNMEAbuffidx++]	=	0;
		ProcessNMEA(gNMEAbuffer);
		gNMEAbuffidx	=	0;
	}
	else if ((gpsChar >= 0x20) && (gNMEAbuffidx < kNMEAbuffSize))
	{
		//*	valid char store it
		gNMEAbuffer[gNMEAbuffidx++]	=	gpsChar;
		
		//*	first char MUST be '$'
		if (gNMEAbuffer[0] != '$')
		{
			gNMEAbuffidx	=	0;
		}
	}

}