/*********************************************************************
 *                    Flowcode GPS Component Code
 *
 * File: PIC_GPS.c
 *
 * (c) 2009 Matrix Multimedia Ltd.
 * http://www.matrixmultimedia.com
 *
 * Software License Agreement
 *
 * The software supplied herewith by Matrix Multimedia Ltd (the
 * “Company”) for its Flowcode graphical programming language is
 * intended and supplied to you, the Company’s customer, for use
 * solely and exclusively on the Company's products. The software
 * is owned by the Company, and is protected under applicable
 * copyright laws. All rights are reserved. Any use in violation
 * of the foregoing restrictions may subject the user to criminal
 * sanctions under applicable laws, as well as to civil liability
 * for the breach of the terms and conditions of this licence.
 *
 * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 *
 * Changelog:
 *
 *  date  | by | description
 * -------+----+-----------------------------------------------------
 * 180309 | BR | Created
 * 080409 | BR | RS232 definition changes
 * 150409 | BR | Added functions for valid data and fixed bug with GPS module
 * 130509 | BR | Added % definitions to DefinesCode section
 * 100909 | BR | Added HiTECH Defines
 * 240210 | BR | Reduced work processed by the interrupt to reduce overall stack corruption and RAM usage
 * 120410 | BR | Removed all fixed locations from the process string function to improve reliability of the GPS parser
 * 120410 | BR | Added functionality for Error Detection, Auto Echo, UART Selection, Buffer Size and Ability to Select Which Data to Record
 * 190410 | BR | Added Course over ground recording
 * 310111 | BR | Fixed a bug when using the GPS with an 18F device TX needs to be enabled
 * 230311 | BR | Changed code to work for hitech and boostc without ifdefs
 ********************************************************************/

/*********************************************************************

 Return & parameter types:
   void
   char
   short
   char*
   float

 Pin directions:
   0 = OUTPUT
   2 = INPUT
   3 = BIDIRECTIONAL

**********************************************************************

[Settings]
CLSID={}
IsAnalogue=0
MultipleAllowed=0
Description=GPS Flowcode Component

**********************************************************************

[Port]
DesiredPort=0
PortMandatory=0
SamePortAsID=0

[Pins]
Count=0

[PinPort]
# PORTA = 0
# PORTB = 1
# PORTC = 2
# PORTD = 3
# PORTE = 4

[PinDesiredBit]

[PinDirection]
# DIR_INPUT = 2
# DIR_OUTPUT = 0
# DIR_BIDIRECTIONAL = 3

[PinMustUsePort]
# boolean

[SamePortAsPinX]
# -1 = any pin
# otherwise, the pin number

[PinMustUsePin]
# boolean

[PinValue]
# boolean (0 = off, 1 = on)

**********************************************************************

[MacroNames]
Count=17
1=GPS_Send_Char
2=GPS_Receive_Char
3=GPS_Process_String
4=Is_Data_Valid
5=Read_Longitude
6=Read_Latitude
7=Read_Altitude
8=Read_GroundSpeed
9=Read_Course_Over_Ground
10=Read_NumberOfSatellites
11=Read_UTC_Time
12=Read_UTC_Date
13=SkipToDataSection
14=CheckBufferOverflow
15=Read_DilutionOfPrecision
16=Read_HorizontalDilutionOfPrecision
17=Read_VerticalDilutionOfPrecision

[MacroReturns]
1=void
2=char
3=void
4=char
5=float
6=float
7=float
8=float
9=float
10=char
11=char
12=char
13=char
14=char
15=float
16=float
17=float


[MacroIsPrivate]
1=1
2=1
3=1
4=0
5=0
6=0
7=0
8=0
9=0
10=0
11=0
12=0
13=1
14=0
15=0
16=0
17=0


[MacroParameters_GetDefines]
Count=0

[MacroParamTypes_GetDefines]


[MacroParameters_GPS_Send_Char]
Count=1
1=nChar

[MacroParamTypes_GPS_Send_Char]
1=char

[MacroParameters_GPS_Receive_Char]
Count=0

[MacroParamTypes_GPS_Receive_Char]

[MacroParameters_GPS_Process_String]
Count=1
1=mx_in_length

[MacroParamTypes_GPS_Process_String]
1=char

[MacroParameters_Is_Data_Valid]
Count=0

[MacroParamTypes_Is_Data_Valid]


[MacroParameters_Read_Longitude]
Count=0

[MacroParamTypes_Read_Longitude]


[MacroParameters_Read_Latitude]
Count=0

[MacroParamTypes_Read_Latitude]


[MacroParameters_Read_Altitude]
Count=0

[MacroParamTypes_Read_Altitude]


[MacroParameters_Read_GroundSpeed]
Count=0

[MacroParamTypes_Read_GroundSpeed]


[MacroParameters_Read_Course_Over_Ground]
Count=0

[MacroParamTypes_Read_Course_Over_Ground]


[MacroParameters_Read_NumberOfSatellites]
Count=0

[MacroParamTypes_Read_NumberOfSatellites]


[MacroParameters_Read_UTC_Time]
Count=1
1=unit

[MacroParamTypes_Read_UTC_Time]
1=char


[MacroParameters_Read_UTC_Date]
Count=1
1=unit

[MacroParamTypes_Read_UTC_Date]
1=char


[MacroParameters_SkipToDataSection]
Count=1
1=numtoskip

[MacroParamTypes_SkipToDataSection]
1=char


[MacroParameters_CheckBufferOverflow]
Count=0

[MacroParamTypes_CheckBufferOverflow]


[MacroParameters_Read_DilutionOfPrecision]
Count=0

[MacroParamTypes_Read_DilutionOfPrecision]


[MacroParameters_Read_HorizontalDilutionOfPrecision]
Count=0

[MacroParamTypes_Read_HorizontalDilutionOfPrecision]


[MacroParameters_Read_VerticalDilutionOfPrecision]
Count=0

[MacroParamTypes_Read_VerticalDilutionOfPrecision]



 ********************************************************************/

/********************************************************************
 * ADDITIONAL CODE
 ********************************************************************/

/*DefinesCode_Start*/

/**** Macro Substitutions ****
%a = UART TXSTA Initialize Value
%b = UART SPBRG Initialize Value
%c = Amount of RAM memory to reserve for a GPS msg $GP"XXXx...x". (largest processed message "RMCx...x" ~58 bytes?)
%d = 0: No Echo, 	1: Auto Echo On Tx Pin Enabled
%e = 1: UART1, 	2: UART2
%f = Latitude Recording Control 			Mem Reqs - 	10 bytes RAM 	ROM function 	FloatLib
%g = Longitude Recording Control 			Mem Reqs - 	11 bytes RAM 	ROM function 	FloatLib
%h = Time Recording Control 				Mem Reqs - 	3 bytes RAM 	ROM function
%i = Date Recording Control 				Mem Reqs - 	3 bytes RAM 	ROM function
%j = Ground Speed Recording Control 		Mem Reqs - 	8 bytes RAM		ROM function 	FloatLib
%k = Altitude Recording Control 			Mem Reqs - 	8 bytes RAM 	ROM function 	FloatLib	GGA MSG Parse
%l = Satellite Count Recording Control 		Mem Reqs - 	1 byte RAM 		ROM function				GSV MSG Parse
%m = Buffer Overflow Detection				Mem Reqs - 	1 byte RAM 		ROM function
%n = Course Over Ground Recording Control	Mem Reqs - 	8 bytes RAM 	ROM function 	FloatLib
%o = Dilution Of Precision Control			Mem Reqs - 	8 bytes RAM 	ROM function 	FloatLib
%p = Horizontal DOP							Mem Reqs - 	8 bytes RAM 	ROM function 	FloatLib
%q = Vertical DOP							Mem Reqs - 	8 bytes RAM 	ROM function 	FloatLib
******************************/

#ifndef MX_MIAC_SYSTEM
	#define MX_GPS_TXSTA		%a			//Baud Rate Defines, EB045 - 4800bps, EB056 - 9600bps
	#define MX_GPS_SPBRG		%b
#endif

	//Following Defines Control GPS Connectivity and functionality
	//**********************************************************//

	#define MX_GPS_BUFFER_SIZE  80		//%c			//GPS Message RAM Size Control
	#define MX_GPS_ECHO			0		//%d			//Echo Control
	#define MX_GPS_UART			1		//%e			//UART Control
	#define MX_GPS_EN_LAT		1		//%f			//Latitude Recording Control
	#define MX_GPS_EN_LON		1		//%g			//Longitude Recording Control
	#define MX_GPS_EN_TIME		1		//%h			//Time Recording Control
	#define MX_GPS_EN_DATE		1		//%i			//Date Recording Control
	#define MX_GPS_EN_SPD		1		//%j			//Ground Speed Recording Control
	#define MX_GPS_EN_ALT		1		//%k			//Altitude Recording Control
	#define MX_GPS_EN_CNT		1		//%l			//Satellite Count Recording Control
	#define MX_GPS_BUFFER_OV	1		//%m			//Buffer Overflow Detection
	#define MX_GPS_EN_COG		1		//%n			//Course over ground Recording Control
	#define MX_GPS_EN_DOP		1		//%o
	#define MX_GPS_EN_HDOP		1		//%o
	#define MX_GPS_EN_VDOP		1		//%o
	//**********************************************************//

#ifndef MX_MIAC_SYSTEM
	//UART data variables
	char mx_incoming[MX_GPS_BUFFER_SIZE];
	char mx_in_len       = 0;
	char mx_in_status    = 0;

	//GPS Data Recording Variables
	#if (MX_GPS_EN_LON == 1)
		char mx_lon_mins[7];
		char mx_lon_deg[3];
		char mx_lon_d;
	#endif

	#if (MX_GPS_EN_LAT == 1)
		char mx_lat_mins[7];
		char mx_lat_deg[2];
		char mx_lat_d;
	#endif

	#if (MX_GPS_EN_SPD == 1)
		char mx_gspeed[8];
	#endif

	#if (MX_GPS_EN_ALT == 1)
		char mx_altitude[8];
	#endif

	#if (MX_GPS_EN_CNT == 1)
		char  mx_satcnt  = 0;
	#endif

	#if (MX_GPS_EN_COG == 1)
		char mx_cog[8];
	#endif

	#if (MX_GPS_EN_DOP == 1)
		char mx_dop[8];
	#endif

	#if (MX_GPS_EN_HDOP == 1)
		char mx_hdop[8];
	#endif

	#if (MX_GPS_EN_VDOP == 1)
		char mx_vdop[8];
	#endif

	#if (MX_GPS_EN_TIME == 1)
		char  mx_utc_hour  = 0;
		char  mx_utc_min   = 0;
		char  mx_utc_sec   = 0;
	#endif

	#if (MX_GPS_EN_DATE == 1)
		char  mx_utc_day	= 0;
		char  mx_utc_month = 0;
		char  mx_utc_year  = 0;
	#endif

	#if (MX_GPS_BUFFER_OV == 1)

		#define MX_GPS_ERR_BUFFER_FULL			1
		#define MX_GPS_ERR_SECTION_NOT_FOUND	2

		char mx_buff_overflow = 0;

	#endif

	char  mx_data_validity = 0;
#endif
/*DefinesCode_End*/

/*InitialisationCode_Start*/

#ifdef MX_MIAC_SYSTEM
	#define MOD_ID	(((%a & 0x0300) << 1) + ((%a & 0x001f) << 4)) << 5

	MIAC_CAN_TX[0] = %b;
	MIAC_Module_WR(MOD_ID, 704, 1,1,0);
	MIAC_Module_GetAck(MOD_ID + 32, 704, 20);

	#undef MOD_ID
#else
  #ifndef MX_UART
	#error "The target microcontroller does not have a UART"
  #endif

	#if (MX_GPS_UART == 1)
		txsta = MX_GPS_TXSTA;   				// 8-bit, async, low speed, off
		spbrg = MX_GPS_SPBRG;   				// set the baud rate 4800
		rcsta = 0;                    			// 8-bit, disabled
		st_bit(rcsta, SPEN);         			// turn on serial interface
	#endif

	#if (MX_GPS_UART == 2)
		txsta2 = MX_GPS_TXSTA;   				// 8-bit, async, low speed, off
		spbrg2 = MX_GPS_SPBRG;   				// set the baud rate 4800
		rcsta2 = 0;                    			// 8-bit, disabled
		st_bit(rcsta2, SPEN);         			// turn on serial interface
	#endif

	cr_bit (intcon, GIE);						// Disable Global interrupts to ensure no stack corruption

	FCD_GPS0_GPS_Receive_Char();				// Dummy reads to clear any errors on bus
	FCD_GPS0_GPS_Receive_Char();

	#if (MX_GPS_UART == 1)
		st_bit(txsta, TXEN);      					// Enable Transmitter - Fixes a bug on 18F devices.
		st_bit (pie1, RCIE);					// Enable UART receive interrupts
	#endif

	#if (MX_GPS_UART == 2)
		st_bit(txsta2, TXEN);      					// Enable Transmitter - Fixes a bug on 18F devices.
		st_bit (pie4, RC2IE);					// Enable UART receive interrupts
	#endif

	st_bit (intcon, PEIE);						// Enable peripheral interrupts
	st_bit (intcon, GIE);						// Enable Global interrupts
#endif
/*InitialisationCode_End*/

/*InterruptCode_Start*/

#ifndef MX_MIAC_SYSTEM
	char tst = 0;

	//Test for GPS UART receive interrupt
	#if (MX_GPS_UART == 1)
		tst = ts_bit(pir1, RCIF) && ts_bit(pie1, RCIE);
	#endif

	#if (MX_GPS_UART == 2)
		tst = ts_bit(pir4, RC2IF) && ts_bit(pie4, RC2IE);
	#endif

	if (tst)										// Interrupt detected?
	{
		char in;

		#if (MX_GPS_UART == 1)
			cr_bit (pie1, RCIE);					// Disable UART receive interrupts
		#endif

		#if (MX_GPS_UART == 2)
			cr_bit (pie4, RC2IE);					// Disable UART receive interrupts
		#endif

		in = FCD_GPS0_GPS_Receive_Char();
		switch (mx_in_status)
		{
			case 1:
				if (in == 'G')						// G = Second character of command
					mx_in_status = 2;
				else mx_in_status = 0;
				break;
			case 2:
				if (in == 'P')						// P = Third character of command
					mx_in_status = 3;
				else mx_in_status = 0;
				break;
			case 3:
				if (in == 0x0D)						// Carrage return signifies end of command
				{
					mx_in_status = 0;

					FCD_GPS0_GPS_Process_String(mx_in_len);
					mx_in_len = 0;
				}
				else if (in < 255)					// Valid Character
				{
					if (mx_in_len < MX_GPS_BUFFER_SIZE)		// If available room in buffer
					{
						mx_incoming[mx_in_len] = in;		// Add data to buffer
						mx_in_len = mx_in_len + 1;			// Increment size of message
					}
					else
					{
						mx_in_status = 0;

						#if (MX_GPS_BUFFER_OV == 1)					//If we get to here then the buffer has run out before the NMEA message has finished
							mx_buff_overflow = MX_GPS_ERR_BUFFER_FULL;
						#endif

						FCD_GPS0_GPS_Process_String(mx_in_len);		// No space left in the buffer, send string to be processed
						mx_in_len = 0;
					}
				}
				else
				{
					mx_in_status = 0;
					mx_in_len = 0;
				}
				break;
			default:
				if (in == 36)							// $ = First character of command
					mx_in_status = 1;
				break;
		}

		#if (MX_GPS_UART == 1)
			st_bit (pie1, RCIE);						// Enable UART receive interrupts
			cr_bit (pir1, RCIF);						// Clear interrupt
		#endif

		#if (MX_GPS_UART == 2)
			st_bit (pie4, RC2IE);						// Enable UART receive interrupts
			cr_bit (pir4, RC2IF);						// Clear interrupt
		#endif
	}
#endif

/*InterruptCode_End*/

/********************************************************************
 * FUNCTIONS
 ********************************************************************/



void GPS_Send_Char(char nChar)
{
/*Macro_GPS_Send_Char_Start*/

	#if (MX_GPS_UART == 1)

		st_bit(txsta, TXEN);
		while (ts_bit(pir1, TXIF) == 0);
		txreg = nChar;

	#endif

	#if (MX_GPS_UART == 2)

		st_bit(txsta2, TXEN);
		while (ts_bit(pir4, TX2IF) == 0);
		txreg2 = nChar;

	#endif

/*Macro_GPS_Send_Char_End*/
}



char GPS_Receive_Char()
{
/*Macro_GPS_Receive_Char_Start*/
	char delay1 = 0;
	char dummy = 0;
	char retVal = 255;

	#if (MX_GPS_UART == 1)						//UART1

		st_bit(rcsta, CREN);

		if (ts_bit(pir1, RCIF) != 0)
		{
			if (ts_bit(rcsta, FERR) != 0)		//received a Char
				dummy = rcreg;      			//need to read the rcreg to clear FERR
			else
			{
				if (ts_bit(rcsta, OERR) != 0)
				{
					cr_bit(rcsta, CREN);		//disable receiver
					st_bit(rcsta, CREN);		//enable receiver
					dummy = rcreg;				//finally, read the rcreg to clear error
				}
				else
					retVal = rcreg; 			//no error, so rx byte is valid
			}
		}

	#endif

	#if (MX_GPS_UART == 2)						//UART2

		st_bit(rcsta2, CREN);

		if (ts_bit(pir4, RC2IF) != 0)
		{
			if (ts_bit(rcsta2, FERR) != 0)		//received a Char
				dummy = rcreg2;      			//need to read the rcreg to clear FERR
			else
			{
				if (ts_bit(rcsta2, OERR) != 0)
				{
					cr_bit(rcsta2, CREN);		//disable receiver
					st_bit(rcsta2, CREN);		//enable receiver
					dummy = rcreg2;				//finally, read the rcreg to clear error
				}
				else
					retVal = rcreg2; 			//no error, so rx byte is valid
			}
		}

	#endif

	#if (MX_GPS_ECHO == 1)
		GPS_Send_Char(retVal);
	#endif

	return (retVal);
/*Macro_GPS_Receive_Char_End*/
}



void GPS_Process_String(char mx_in_length)
{
/*Macro_GPS_Process_String_Start*/

#ifndef MX_MIAC_SYSTEM
	char command = 0;
	char idx, idxoffset;
	char tmp;

	#if (MX_GPS_EN_ALT == 1)
		if(mx_incoming[0] == 'G' && ( mx_incoming[1] == 'G' && mx_incoming[2] == 'A' ))		// $GPGGA - GPS Altitude Data
			command = 1;
	#endif

	#if (MX_GPS_EN_CNT == 1)
		if(mx_incoming[0] == 'G' && ( mx_incoming[1] == 'S' && mx_incoming[2] == 'V' ))		// $GPGSV - GPS Satellites in View
			command = 2;
	#endif

	if(mx_incoming[0] == 'R' && ( mx_incoming[1] == 'M' && mx_incoming[2] == 'C' ))			// $GPRMC - Recommended Minimum Specific Data
		command = 3;

	if(mx_incoming[0] == 'G' && ( mx_incoming[1] == 'S' && mx_incoming[2] == 'A' ))		// $GPGSA - DOP and Active Satellites
		command = 4;

	switch (command)
	{
		case 1:

			//Altitude
			#if (MX_GPS_EN_ALT == 1)
				idxoffset = SkipToDataSection (9);							//Move to mx_altitude
				if (idxoffset)												//If position found in string
				{
					for (idx = idxoffset; mx_incoming[idx] != ','; idx++)	//Collect Altitude
					{
						tmp = idx - idxoffset;
						mx_altitude[tmp] = mx_incoming[idx];
					}

					tmp = idx - idxoffset;

					if (tmp < 8)
						mx_altitude[tmp] = 0;								//Terminate String
				}
			#endif

			break;

		case 2:

			//Satellite Count
			#if (MX_GPS_EN_CNT == 1)
				mx_satcnt = 0;												//Initialise count

				idxoffset = SkipToDataSection (3);							//Move to Satellite Count
				if (idxoffset)												//If position found in string
				{
					for (idx = idxoffset; mx_incoming[idx] != ','; idx++)	//Collect Satellite count
					{
						mx_satcnt = mx_satcnt * 10;
						mx_satcnt = mx_satcnt + (mx_incoming[idx] - '0');
					}
				}
			#endif

			break;

		case 3:

			idxoffset = SkipToDataSection (2);								//Read Data Validity position

			//UTC Time stamp is at start of message - fixed string locations should be ok and removes the need for extra commands
			#if (MX_GPS_EN_TIME == 1)
				if (idxoffset > 10)											//Test timestamp data is there
				{
					mx_utc_hour = (mx_incoming[4] - '0') * 10;				//Collect UTC Hour
					mx_utc_hour = mx_utc_hour + (mx_incoming[5] - '0');
					mx_utc_min = (mx_incoming[6] - '0') * 10;				//Collect UTC Min
					mx_utc_min = mx_utc_min + (mx_incoming[7] - '0');
					mx_utc_sec = (mx_incoming[8] - '0') * 10;				//Collect UTC Sec
					mx_utc_sec = mx_utc_sec + (mx_incoming[9] - '0');
				}
			#endif

			//Data Vailidity
			if (mx_incoming[idxoffset] == 'A')
				mx_data_validity = 1;										//Data is valid
			else
				mx_data_validity = 0;										//Data is not valid

			//Lattitude
			#if (MX_GPS_EN_LAT == 1)
				idxoffset = SkipToDataSection (3);							//move to start of Lattitude
				mx_lat_deg[0] = mx_incoming[idxoffset];						//Collect latitude degree
				idxoffset = idxoffset + 1;
				mx_lat_deg[1] = mx_incoming[idxoffset];
				idxoffset = idxoffset + 1;
				for (idx = idxoffset; mx_incoming[idx] != ','; idx++)		//Collect latitude minutes
				{
					tmp = idx - idxoffset;
					mx_lat_mins[tmp] = mx_incoming[idx];
				}
				tmp = idx - idxoffset;
				if(tmp < 7)
					mx_lat_mins[tmp] = 0;									//Terminate Latitude minutes string

				idxoffset = SkipToDataSection (4);							//move to start of Lattitude Direction
				mx_lat_d = mx_incoming[idxoffset];
			#endif

			//Longitude
			#if (MX_GPS_EN_LON == 1)
				idxoffset = SkipToDataSection (5);							//move to start of Longitude
				mx_lon_deg[0] = mx_incoming[idxoffset];						//Collect longitude degree
				idxoffset = idxoffset + 1;
				mx_lon_deg[1] = mx_incoming[idxoffset];
				idxoffset = idxoffset + 1;
				mx_lon_deg[2] = mx_incoming[idxoffset];
				idxoffset = idxoffset + 1;
				for (idx = idxoffset; mx_incoming[idx] != ','; idx++)		//Collect longitude minutes
				{
					tmp = idx - idxoffset;
					mx_lon_mins[tmp] = mx_incoming[idx];
				}
				tmp = idx - idxoffset;
				if(tmp < 7)
					mx_lon_mins[tmp] = 0;									//Terminate Longitude minutes string

				idxoffset = SkipToDataSection (6);							//move to start of Longitude Direction
				mx_lon_d = mx_incoming[idxoffset];
			#endif

			//Ground Speed
			#if (MX_GPS_EN_SPD == 1)
				idxoffset = SkipToDataSection (7);							//move to start of Ground speed
				for (idx = idxoffset; mx_incoming[idx] != ','; idx++)		//Collect ground speed
				{
					tmp = idx - idxoffset;
					mx_gspeed[tmp] = mx_incoming[idx];
				}

				tmp = idx - idxoffset;
				if(tmp < 8)
					mx_gspeed[tmp] = 0;										//Terminate speed string
			#endif

			//Course Over Ground
			#if (MX_GPS_EN_COG == 1)
				idxoffset = SkipToDataSection (8);							//move to start of course angle
				for (idx = idxoffset; mx_incoming[idx] != ','; idx++)		//Collect course angle
				{
					tmp = idx - idxoffset;
					mx_cog[tmp] = mx_incoming[idx];
				}

				tmp = idx - idxoffset;
				if(tmp < 8)
					mx_cog[tmp] = 0;										//Terminate speed string
			#endif

			//UTC Date
			#if (MX_GPS_EN_DATE == 1)
				idx = SkipToDataSection (9);								//move to start of UTC date
				idxoffset = SkipToDataSection (10);							//move to end of UTC date
				if((idxoffset - idx) > 6)									//If the UTC date data is present
				{
					mx_utc_day = (mx_incoming[idx] - '0') * 10;				//Collect UTC Day
					idx = idx + 1;
					mx_utc_day = mx_utc_day + (mx_incoming[idx] - '0');

					idx = idx + 1;
					mx_utc_month = (mx_incoming[idx] - '0') * 10;			//Collect UTC Month
					idx = idx + 1;
					mx_utc_month = mx_utc_month + (mx_incoming[idx] - '0');

					idx = idx + 1;
					mx_utc_year = (mx_incoming[idx] - '0') * 10;			//Collect UTC Year
					idx = idx + 1;
					mx_utc_year = mx_utc_year + (mx_incoming[idx] - '0');
				}
			#endif
			break;

		case 4:

			//DOP
			#if (MX_GPS_EN_DOP == 1)
				idxoffset = SkipToDataSection (15);							//Move to mx_dop
				if (idxoffset)												//If position found in string
				{
					for (idx = idxoffset; mx_incoming[idx] != ','; idx++)	//Collect Altitude
					{
						tmp = idx - idxoffset;
						mx_dop[tmp] = mx_incoming[idx];
					}

					tmp = idx - idxoffset;

					if (tmp < 8)
						mx_dop[tmp] = 0;									//Terminate String
				}
			#endif

			#if (MX_GPS_EN_HDOP == 1)
				idxoffset = SkipToDataSection (16);							//Move to mx_dop
				if (idxoffset)												//If position found in string
				{
					for (idx = idxoffset; mx_incoming[idx] != ','; idx++)	//Collect Altitude
					{
						tmp = idx - idxoffset;
						mx_hdop[tmp] = mx_incoming[idx];
					}

					tmp = idx - idxoffset;

					if (tmp < 8)
						mx_hdop[tmp] = 0;									//Terminate String
				}
			#endif

			#if (MX_GPS_EN_VDOP == 1)
				idxoffset = SkipToDataSection (17);							//Move to mx_dop
				if (idxoffset)												//If position found in string
				{
					for (idx = idxoffset; mx_incoming[idx] != ','; idx++)	//Collect Altitude
					{
						tmp = idx - idxoffset;
						mx_vdop[tmp] = mx_incoming[idx];
					}

					tmp = idx - idxoffset;

					if (tmp < 8)
						mx_vdop[tmp] = 0;									//Terminate String
				}
			#endif

			break;

		default:
			break;
	}
#endif
/*Macro_GPS_Process_String_End*/
}


char Is_Data_Valid()
{
/*Macro_Is_Data_Valid_Start*/
#ifdef MX_MIAC_SYSTEM
	unsigned int ModID = (((%a & 0x0300) << 1) + ((%a & 0x001f) << 4)) << 5;

	MIAC_Module_WR(ModID, 705, 0,1,0);
	MIAC_Module_GetAck(ModID + 32, 705, 200);
	return MIAC_CAN_RX[0];
#else
	return mx_data_validity;
#endif
/*Macro_Is_Data_Valid_End*/
}


float Read_Longitude()
{
/*Macro_Read_Longitude_Start*/

	#if (MX_GPS_EN_LON == 1)
		#ifdef MX_MIAC_SYSTEM
			unsigned int ModID = (((%a & 0x0300) << 1) + ((%a & 0x001f) << 4)) << 5;

			MIAC_Module_WR(ModID, 706, 0,1,0);
			MIAC_Module_GetAck(ModID + 32, 706, 200);

			FloatConv.ByteArray[0] = MIAC_CAN_RX[0];
			FloatConv.ByteArray[1] = MIAC_CAN_RX[1];
			FloatConv.ByteArray[2] = MIAC_CAN_RX[2];
			FloatConv.ByteArray[3] = MIAC_CAN_RX[3];

			return FloatConv.FloatVal;
		#else
			char Degree;
			float Minute;
			float RetVal;

			Degree = FCI_STRING_TO_INT(mx_lon_deg, 3);
			Minute = FCI_STRING_TO_FLOAT(mx_lon_mins, 7);

			Minute = float32_div(Minute, 60);			//Convert minute to fraction of a degree
			RetVal = float32_from_int32(Degree);
			RetVal = float32_add(Minute, RetVal);		//Calculate position using BoostC float functions

			if (mx_lon_d == 'W')							//West is negative longitude
			{
				RetVal = float32_sub(0, RetVal);
			}

			return RetVal;
		#endif
	#else
		return 0;
	#endif

/*Macro_Read_Longitude_End*/
}


float Read_Latitude()
{
/*Macro_Read_Latitude_Start*/

	#if (MX_GPS_EN_LAT == 1)
		#ifdef MX_MIAC_SYSTEM
			unsigned int ModID = (((%a & 0x0300) << 1) + ((%a & 0x001f) << 4)) << 5;

			MIAC_Module_WR(ModID, 707, 0,1,0);
			MIAC_Module_GetAck(ModID + 32, 707, 200);

			FloatConv.ByteArray[0] = MIAC_CAN_RX[0];
			FloatConv.ByteArray[1] = MIAC_CAN_RX[1];
			FloatConv.ByteArray[2] = MIAC_CAN_RX[2];
			FloatConv.ByteArray[3] = MIAC_CAN_RX[3];

			return FloatConv.FloatVal;
		#else
			char Degree;
			float Minute;
			float RetVal;

			Degree = FCI_STRING_TO_INT(mx_lat_deg, 2);
			Minute = FCI_STRING_TO_FLOAT(mx_lat_mins, 7);

			Minute = float32_div(Minute, 60);			//Convert minute to fraction of a degree
			RetVal = float32_from_int32(Degree);
			RetVal = float32_add(Minute, RetVal);		//Calculate position using BoostC float functions

			if (mx_lat_d == 'S')							//Southern hemisphere is negative latitude
			{
				RetVal = float32_sub(0, RetVal);
			}

			return RetVal;
		#endif
	#else
		return 0;
	#endif

/*Macro_Read_Latitude_End*/
}


float Read_Altitude()
{
/*Macro_Read_Altitude_Start*/

	#if (MX_GPS_EN_ALT == 1)
		#ifdef MX_MIAC_SYSTEM
			unsigned int ModID = (((%a & 0x0300) << 1) + ((%a & 0x001f) << 4)) << 5;

			MIAC_Module_WR(ModID, 708, 0,1,0);
			MIAC_Module_GetAck(ModID + 32, 708, 200);

			FloatConv.ByteArray[0] = MIAC_CAN_RX[0];
			FloatConv.ByteArray[1] = MIAC_CAN_RX[1];
			FloatConv.ByteArray[2] = MIAC_CAN_RX[2];
			FloatConv.ByteArray[3] = MIAC_CAN_RX[3];

			return FloatConv.FloatVal;
		#else
			return FCI_STRING_TO_FLOAT(mx_altitude, 8);
		#endif
	#else
		return 0;
	#endif

/*Macro_Read_Altitude_End*/
}


float Read_GroundSpeed()
{
/*Macro_Read_GroundSpeed_Start*/
	#if (MX_GPS_EN_SPD == 1)
		#ifdef MX_MIAC_SYSTEM
			unsigned int ModID = (((%a & 0x0300) << 1) + ((%a & 0x001f) << 4)) << 5;

			MIAC_Module_WR(ModID, 709, 0,1,0);
			MIAC_Module_GetAck(ModID + 32, 709, 200);

			FloatConv.ByteArray[0] = MIAC_CAN_RX[0];
			FloatConv.ByteArray[1] = MIAC_CAN_RX[1];
			FloatConv.ByteArray[2] = MIAC_CAN_RX[2];
			FloatConv.ByteArray[3] = MIAC_CAN_RX[3];

			return FloatConv.FloatVal;
		#else
			return FCI_STRING_TO_FLOAT(mx_gspeed, 8);
		#endif
	#else
		return 0;
	#endif

/*Macro_Read_GroundSpeed_End*/
}


float Read_Course_Over_Ground()
{
/*Macro_Read_Course_Over_Ground_Start*/
	#if (MX_GPS_EN_COG == 1)
		#ifdef MX_MIAC_SYSTEM
			unsigned int ModID = (((%a & 0x0300) << 1) + ((%a & 0x001f) << 4)) << 5;

			MIAC_Module_WR(ModID, 710, 0,1,0);
			MIAC_Module_GetAck(ModID + 32, 710, 200);

			FloatConv.ByteArray[0] = MIAC_CAN_RX[0];
			FloatConv.ByteArray[1] = MIAC_CAN_RX[1];
			FloatConv.ByteArray[2] = MIAC_CAN_RX[2];
			FloatConv.ByteArray[3] = MIAC_CAN_RX[3];

			return FloatConv.FloatVal;
		#else
			return FCI_STRING_TO_FLOAT(mx_cog, 8);
		#endif
	#else
		return 0;
	#endif
/*Macro_Read_Course_Over_Ground_End*/
}


char Read_NumberOfSatellites()
{
/*Macro_Read_NumberOfSatellites_Start*/

	#if (MX_GPS_EN_CNT == 1)
		#ifdef MX_MIAC_SYSTEM
			unsigned int ModID = (((%a & 0x0300) << 1) + ((%a & 0x001f) << 4)) << 5;

			MIAC_Module_WR(ModID, 711, 0,1,0);
			MIAC_Module_GetAck(ModID + 32, 711, 200);

			return(MIAC_CAN_RX[0]);
		#else
			return mx_satcnt;
		#endif
	#else
		return 0;
	#endif
/*Macro_Read_NumberOfSatellites_End*/
}


char Read_UTC_Time(char unit)
{
/*Macro_Read_UTC_Time_Start*/
	#if (MX_GPS_EN_TIME == 1)
		#ifdef MX_MIAC_SYSTEM
			unsigned int ModID = (((%a & 0x0300) << 1) + ((%a & 0x001f) << 4)) << 5;

			MIAC_Module_WR(ModID, 712, 0,1,0);
			MIAC_Module_GetAck(ModID + 32, 712, 200);

			return(MIAC_CAN_RX[0]);
		#else
			switch(unit)
			{
				case 0:
				case 'S':
				case 's':
					return mx_utc_sec;

				case 1:
				case 'M':
				case 'm':
					return mx_utc_min;

				case 2:
				case 'H':
				case 'h':
					return mx_utc_hour;
			}
		#endif
	#endif
	return 0;
/*Macro_Read_UTC_Time_End*/
}


char Read_UTC_Date(char unit)
{
/*Macro_Read_UTC_Date_Start*/
	#if (MX_GPS_EN_DATE == 1)
		#ifdef MX_MIAC_SYSTEM
			unsigned int ModID = (((%a & 0x0300) << 1) + ((%a & 0x001f) << 4)) << 5;

			MIAC_Module_WR(ModID, 713, 0,1,0);
			MIAC_Module_GetAck(ModID + 32, 713, 200);

			return(MIAC_CAN_RX[0]);
		#else
			switch(unit)
			{
				case 0:
				case 'D':
				case 'd':
					return mx_utc_day;

				case 1:
				case 'M':
				case 'm':
					return mx_utc_month;

				case 2:
				case 'Y':
				case 'y':
					return mx_utc_year;
			}
		#endif
	#endif
	return 0;
/*Macro_Read_UTC_Date_End*/
}



char SkipToDataSection (char numtoskip)
{
/*Macro_SkipToDataSection_Start*/

#ifndef MX_MIAC_SYSTEM
	char iteration;
	char idx = 0;

	for (iteration=0; iteration<numtoskip; iteration++)				//Number of commas to find
	{
		while (mx_incoming[idx] != ',' && idx < MX_GPS_BUFFER_SIZE) //While searching for next comma
		{
			idx = idx + 1;   										//Move to next location
		}
		idx = idx + 1;												//Move to first location after comma
	}

	if (idx < MX_GPS_BUFFER_SIZE)
		return idx;													//Valid position marker

	#if (MX_GPS_BUFFER_OV == 1)										//If we get to here then the section was not found in the string
		mx_buff_overflow = MX_GPS_ERR_SECTION_NOT_FOUND;
	#endif

	return 0;														//Position marker not found - NMEA error or GPS_Buffer too small
#endif
/*Macro_SkipToDataSection_End*/
}



char CheckBufferOverflow ()
{
/*Macro_CheckBufferOverflow_Start*/

#ifdef MX_MIAC_SYSTEM
	return 0;
#else
	#if (MX_GPS_BUFFER_OV == 1)
		return mx_buff_overflow;
	#else
		return 0;
	#endif
#endif
/*Macro_CheckBufferOverflow_End*/
}


float Read_DilutionOfPrecision()
{
/*Macro_Read_DilutionOfPrecision_Start*/
	#if (MX_GPS_EN_DOP == 1)
		return FCI_STRING_TO_FLOAT(mx_dop, 8);
	#else
		return 0;
	#endif

/*Macro_Read_DilutionOfPrecision_End*/
}


float Read_HorizontalDilutionOfPrecision()
{
/*Macro_Read_HorizontalDilutionOfPrecision_Start*/
	#if (MX_GPS_EN_HDOP == 1)
		return FCI_STRING_TO_FLOAT(mx_hdop, 8);
	#else
		return 0;
	#endif

/*Macro_Read_HorizontalDilutionOfPrecision_End*/
}


float Read_VerticalDilutionOfPrecision()
{
/*Macro_Read_VerticalDilutionOfPrecision_Start*/
	#if (MX_GPS_EN_VDOP == 1)
		return FCI_STRING_TO_FLOAT(mx_vdop, 8);
	#else
		return 0;
	#endif

/*Macro_Read_VerticalDilutionOfPrecision_End*/
}
