Changeset - 84e25f7efd5a
[Not reviewed]
default
0 1 0
ethanzonca@CL-ENS241-08.cedarville.edu - 12 years ago 2013-04-18 21:51:21
ethanzonca@CL-ENS241-08.cedarville.edu
Fixed issue where get_latitudeTrimmed() and get_latitudeLSBs() and associated longitude function returned the same results due to buffer sharing and compiler optimization.
1 file changed with 16 insertions and 14 deletions:
0 comments (0 inline, 0 general)
master/master/lib/gps.c
Show inline comments
 
/*
 
 * Master Firmware: NMEA Parser
 
 *
 
 * This file is part of OpenTrack.
 
 *
 
 * OpenTrack is free software: you can redistribute it and/or modify
 
 * it under the terms of the GNU Affero General Public License as published by
 
 * the Free Software Foundation, either version 3 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * OpenTrack is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU Affero General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU Affero General Public License
 
 * along with OpenTrack. If not, see <http://www.gnu.org/licenses/>.
 
 * 
 
 * Ethan Zonca
 
 * Matthew Kanning
 
 * Kyle Ripperger
 
 * Matthew Kroening
 
 *
 
 */
 

	
 
#include <stdbool.h>
 
#include <string.h>
 
#include <stdio.h>
 
#include <avr/io.h>
 
#include <avr/interrupt.h>
 
#include "gps.h"
 
#include "serial.h"
 
#include "../config.h"
 
#include "led.h"
 
#include "logger.h"
 

	
 
// Circular buffer for incoming data
 
uint8_t nmeaBuffer[NMEABUFFER_SIZE];
 

	
 
// Location of parser in the buffer
 
uint8_t nmeaBufferParsePosition = 0;
 

	
 
// Location of receive byte interrupt in the buffer
 
volatile uint16_t nmeaBufferDataPosition = 0;
 

	
 
// holds the byte ALREADY PARSED. includes starting character
 
int bytesReceived = 0;
 

	
 
//data (and checksum) of most recent transmission
 
char data[16];
 

	
 
//used to skip over bytes during parse
 
int skipBytes = 0;
 

	
 
//used to index data arrays during data collection
 
int numBytes = 0;
 

	
 
//variables to store data from transmission
 
//least significant digit is stored at location 0 of arrays
 
char tramsmissionType[7];
 

	
 
char timestamp[12];	//hhmmss.ss
 
char* get_timestamp() 
 
{
 
	return timestamp;
 
}
 
	
 
char latitude[14];	//lllll.lla
 
char latitudeTmp[8];
 
char latitudeTmpTRIM[8];
 
char latitudeTmpLSB[4];
 
char* get_latitudeTrimmed() 
 
{
 
	strncpy(latitudeTmp, &latitude[0], 7);
 
	latitudeTmp[7] = 0x00;
 
	return latitudeTmp;
 
	strncpy(latitudeTmpTRIM, &latitude[0], 7);
 
	latitudeTmpTRIM[7] = 0x00;
 
	return latitudeTmpTRIM;
 
}
 
char* get_latitudeLSBs()
 
{
 
	strncpy(latitudeTmp, &latitude[7], 3);
 
	latitudeTmp[3] = 0x00;
 
	return latitudeTmp;
 
	strncpy(latitudeTmpLSB, &latitude[7], 3);
 
	latitudeTmpLSB[3] = 0x00;
 
	return latitudeTmpLSB;
 
}
 

	
 
char longitude[14];	//yyyyy.yyb
 
char longitudeTmp[9];
 
char longitudeTmpTRIM[9];
 
char longitudeTmpLSB[4];
 

	
 
char* get_longitudeTrimmed() 
 
{
 
	strncpy(longitudeTmp, &longitude[0], 8);
 
	longitudeTmp[8] = 0x00;
 
	return longitudeTmp;
 
	strncpy(longitudeTmpTRIM, &longitude[0], 8);
 
	longitudeTmpTRIM[8] = 0x00;
 
	return longitudeTmpTRIM;
 
}
 
char* get_longitudeLSBs()
 
{
 
	strncpy(longitudeTmp, &longitude[8], 3);
 
	longitudeTmp[3] = 0x00;
 
	return longitudeTmp;
 
	strncpy(longitudeTmpLSB, &longitude[8], 3);
 
	longitudeTmpLSB[3] = 0x00;
 
	return longitudeTmpLSB;
 
}
 

	
 
char quality;		//quality for GGA and validity for RMC
 
char numSatellites[4];
 
char* get_sv() 
 
{
 
	return numSatellites;
 
}
 

	
 
char hdop[6];		//xx.x
 
char* get_hdop() 
 
{
 
	return hdop;
 
}
 

	
 
char altitude[10];	//xxxxxx.x
 
char* get_gpsaltitude()
 
{
 
	return altitude;
 
}
 

	
 
char wgs84Height[8];	//sxxx.x
 
char lastUpdated[8];	//blank - included for testing
 
char stationID[8];	//blank - included for testing
 
char checksum[3];	//xx
 

	
 
char knots[8];		//xxx.xx
 
char* get_speedKnots() 
 
{
 
	return knots;
 
}
 

	
 
char course[8];		//xxx.x
 
char* get_course() 
 
{
 
	return course;
 
}
 
	
 
char dayofmonth[9];	//ddmmyy
 
char* get_dayofmonth() 
 
{
 
	return dayofmonth;
 
}
 

	
 

	
 
bool gps_hadfix = false;
 

	
 
bool gps_hasfix() 
 
{
 
	bool hasFix = get_latitudeTrimmed()[0] != 0x00;
 
	
 
	if(hasFix && !gps_hadfix) {
 
		info_log_msg("Acquired GPS fix");
 
	}
 
	else if(!hasFix && gps_hadfix) {
 
		info_log_msg("Lost GPS fix");
 
	}
 
	
 
	gps_hadfix = hasFix;
 
	return hasFix;
 
}
 

	
 
char variation[9];	//xxx.xb
 
int calculatedChecksum;
 
int receivedChecksum;
 

	
 
// transmission state machine
 
enum decodeState {
 
	//shared fields
 
	INITIALIZE=0,
 
	GET_TYPE,
 
	GPS_CHECKSUM,	//XOR of all the bytes between the $ and the * (not including the delimiters themselves), written in hexadecimal
 
	//GGA data fields
 
	GGA_TIME,
 
	GGA_LATITUDE,
 
	GGA_LONGITUDE,
 
	GGA_QUALITY,
 
	GGA_SATELLITES,
 
	GGA_HDOP,
 
	GGA_ALTITUDE,
 
	GGA_WGS84,
 
	GGA_LAST_UPDATE,
 
	GGA_STATION_ID,
 
	//RMC data fields
 
	RMC_TIME,
 
	RMC_VALIDITY,
 
	RMC_LATITUDE,
 
	RMC_LONGITUDE,
 
	RMC_KNOTS,
 
	RMC_COURSE,
 
	RMC_DATE,
 
	RMC_MAG_VARIATION,
 
	
 
}decodeState;
 

	
 

	
 
ISR(USART1_RX_vect)
 
{
 
	nmeaBuffer[nmeaBufferDataPosition % NMEABUFFER_SIZE] = UDR1;
 
	nmeaBufferDataPosition = (nmeaBufferDataPosition + 1) % NMEABUFFER_SIZE;
 
}
 

	
 
void gps_setup() 
 
{
 
	timestamp[0] = 0x00;
 
	latitude[0] = 0x00;
 
	longitude[0] = 0x00;
 
	numSatellites[0] = 0x00;
 
	hdop[0] = 0x00;
 
	knots[0] = 0x00;
 
	course[0] = 0x00;
 
	dayofmonth[0] = 0x00;
 
}
 

	
 

	
 
// Could inline if program space available
 
static void setParserState(uint8_t state)
 
{
 
	decodeState = state;
 

	
 
	
 
	// If resetting, clear vars
 
	if(state == INITIALIZE)
 
	{
 
		calculatedChecksum = 0;
 
	}
 
	
 
	// Every time we change state, we have parsed a byte
 
	nmeaBufferParsePosition = (nmeaBufferParsePosition + 1) % NMEABUFFER_SIZE;
 
}
 

	
 

	
 

	
 
//// MKa GPS transmission parser START
 
void parse_gps_transmission(void){
 
	
 
	// Pull byte off of the buffer
 
	char byte;
 
	
 
	
 
	
 
	while(nmeaBufferDataPosition != nmeaBufferParsePosition) 
 
	{
 
		led_on(LED_ACTIVITY);
 
		
 
		byte = nmeaBuffer[nmeaBufferParsePosition];
 
		
 
		if(decodeState == INITIALIZE) //start of transmission sentence
 
		{
 
			if(byte == '$') 
 
			{
 
				#ifdef DEBUG_NMEA
 
				serial0_sendString("found $\r\n");
 
				#endif
 
				
 
				setParserState(GET_TYPE);
 
				numBytes = 0; //prep for next phases
 
				skipBytes = 0;
 
				calculatedChecksum = 0;
 
			}		
 
			
 
			else 
 
			{
 
				setParserState(INITIALIZE);
 
			}
 
		}
 
	
 
		//parse transmission type
 
		else if (decodeState == GET_TYPE)
 
		{
 
			tramsmissionType[numBytes] = byte;
 
			numBytes++;
 
			
 
			#ifdef DEBUG_NMEA
 
			serial0_sendString("stored a type byte\r\n");
 
			#endif
 
			
 
			if(byte == ',') //end of this data type
 
			{
 
				tramsmissionType[5] = 0x00;
 
				
 
				if (tramsmissionType[2] == 'G' &&
 
				tramsmissionType[3] == 'G' &&
 
				tramsmissionType[4] == 'A')
 
				{
 
					setParserState(GGA_TIME);
 
					numBytes = 0;
 
				}
 
				else if (tramsmissionType[2] == 'R' &&
 
				tramsmissionType[3] == 'M' &&
 
				tramsmissionType[4] == 'C')
 
				{
 
					setParserState(RMC_TIME);
 
					numBytes = 0;
 
				}
 
				else //this is an invalid transmission type
 
				{
 
					setParserState(INITIALIZE);
 
				}
 
			}
 
			else {
 
				// continue
 
				setParserState(GET_TYPE);
 
			}
 
			
 
		}
 
	
 
		///parses GGA transmissions START
 
		/// $--GGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*xx
 
		//timestamp
 
		else if (decodeState == GGA_TIME)
 
		{
 
			if (byte == ',') //end of this data type
 
			{
 
				timestamp[4] = 0x00; // Cut off at 4 (no seconds) for APRS
 
				setParserState(GGA_LATITUDE);
 
				skipBytes = 0; //prep for next phase of parse
 
				numBytes = 0;
 
			}
 
			else //store data
 
			{
 
				#ifdef DEBUG_NMEA
 
				serial0_sendString("found GGA time byte\r\n");
 
				#endif
 
				
 
				setParserState(GGA_TIME);
 
				timestamp[numBytes] = byte; //byte; //adjust number of bytes to fit array
 
				numBytes++;
 
			}
 
		}
 
	
 
		//latitude
 
		else if (decodeState == GGA_LATITUDE)
 
		{
 
			if (byte == ',' && skipBytes == 0) //discard this byte
 
			{
 
				#ifdef DEBUG_NMEA
 
				serial0_sendString("found lat skip byte\r\n");
 
				#endif
 
				
 
				skipBytes = 1;
 
				setParserState(GGA_LATITUDE);
 
			}
 
			else if (byte == ',') //end of this data type
 
			{
 
				
 
				latitude[numBytes] = 0x00; // null terminate
 
				
 
				setParserState(GGA_LONGITUDE);
 
				skipBytes = 0; //prep for next phase of parse
 
				numBytes = 0;
 
			}
 
			else //store data
 
			{
 
				#ifdef DEBUG_NMEA
 
				serial0_sendString("found lat byte\r\n");
 
				#endif
 
				
 
				latitude[numBytes] = byte; //adjust number of bytes to fit array
 
				numBytes++;
 
				setParserState(GGA_LATITUDE);
 
			}
 
		}
 
	
 
		//longitude
 
		else if (decodeState == GGA_LONGITUDE)
 
		{
 
			if (byte == ',' && skipBytes == 0) //discard this byte
 
			{
 
				#ifdef DEBUG_NMEA
 
				serial0_sendString("found long skip byte\r\n");
 
				#endif
 
				
 
				skipBytes = 1;
 
				setParserState(GGA_LONGITUDE);
 
			}
 
			else if (byte == ',') //end of this data type
 
			{
 
				longitude[numBytes] = 0x00;
 
				setParserState(GGA_QUALITY);
 
				numBytes = 0; //prep for next phase of parse
 
				skipBytes = 0;
 
			}
 
			else //store data
 
			{
 
				#ifdef DEBUG_NMEA
 
				serial0_sendString("found long byte\r\n");
 
				#endif
 
				
 
				longitude[numBytes] = byte; //adjust number of bytes to fit array
 
				numBytes++;
 
				setParserState(GGA_LONGITUDE);
 
			}
 
		}
 
	
 
		//GGA quality
 
		else if (decodeState == GGA_QUALITY)
 
		{
 
			if (byte == ',') //end of this data type
 
			{
 
				setParserState(GGA_SATELLITES);
 
				numBytes = 0; //prep for next phase of parse
 
			}
 
			else //store data
 
			{
 
				#ifdef DEBUG_NMEA
 
				serial0_sendString("found quality byte\r\n");
 
				#endif
 
				
 
				quality = byte; //maybe reset if invalid data ??
 
				setParserState(GGA_QUALITY);
 
			}
 
		}
 
	
 
		//number of satellites
 
		else if (decodeState == GGA_SATELLITES)
 
		{
 
			if (byte == ',') //end of this data type
 
			{
 
				numSatellites[numBytes] = 0x00;
 
				setParserState(GGA_HDOP);
 
				numBytes = 0; //prep for next phase of parse
 
			}
 
			else //store data
 
			{
 
				numSatellites[numBytes] = byte; //adjust number of bytes to fit array
 
				numBytes++;
 
				setParserState(GGA_SATELLITES);
 
			}
 
		}
 
	
 
		//HDOP
 
		else if (decodeState == GGA_HDOP)
 
		{
 
			if (byte == ',' ) //end of this data type
 
			{
 
				hdop[numBytes] = 0x00;
 
				setParserState(GGA_ALTITUDE);
 
				numBytes = 0; //prep for next phase of parse
 
				skipBytes = 0;
 
			}
 
			else //store data
 
			{
 
				hdop[numBytes] = byte; //adjust number of bytes to fit array
 
				numBytes++;
 
				setParserState(GGA_HDOP);
 
			}
 
		}
 
	
 
		//altitude
 
		else if (decodeState == GGA_ALTITUDE)
 
		{
 
			if (byte == ',' && skipBytes == 0) //discard this byte
 
			{
 
				altitude[numBytes] = 0x00;
 
				skipBytes = 1;
 
				setParserState(GGA_ALTITUDE);
 
			}
 
			else if(byte == ',') //end of this data type
 
			{
 
				// If we actually have an altitude
 
				if(numBytes>0) 
 
				{
 
					altitude[numBytes-1] = 0x00; // Cut off the "M" from the end of the altitude
 
				}
 
				else 
 
				{
 
					altitude[numBytes] = 0x00;
 
				}					
 
				setParserState(GGA_WGS84);
 
				numBytes = 0; //prep for next phase of parse
 
			}
 
			else //store data
 
			{
 
				altitude[numBytes] = byte; //adjust number of bytes to fit array
 
				numBytes++;
 
				setParserState(GGA_ALTITUDE);
 
			}
 
		}
 
	
 
		//WGS84 Height
 
		else if (decodeState == GGA_WGS84)
 
		{
 
			if (byte == ',' && skipBytes == 0) //discard this byte
0 comments (0 inline, 0 general)