/*************************** (C) COPYRIGHT 2017 CXHY ****************************
 * 文件名  ：gps.c
 * 描  述  ：GPS驱动代码     
 * 版  本  ：V1.0
 * 作  者  ：XuZhongPing
 * 日  期  ：2017/03/05 
*********************************************************************************/
#include "gps.h" 
#include "delay.h" 							   
#include "usart4.h" 								   
#include "stdio.h"	 
#include "stdarg.h"	 
#include "string.h"	 
#include "math.h"

nmea_msg gpsx; 											//GPS信息
__align(4) u8 dtbuf[50];   					//打印缓存器
      
/*
***********************************************************************
*	函 数 名: NMEA_Comma_Pos
*	功能说明: 从buf里面得到第cx个逗号所在的位置
*	形    参: buf,数据缓存
*						cx,第几个逗号所在的位置
*	返 回 值: 0~0XFE,代表逗号所在位置的偏移
*						0XFF,代表不存在第cx个逗号		
***********************************************************************
*/					  
u8 NMEA_Comma_Pos(u8 *buf, u8 cx)
{	 		    
	u8 *p = buf;
	while(cx)
	{		 
		if((*buf == '*') || (*buf < ' ') || (*buf > 'z')) return 0XFF;	//遇到'*'或者非法字符,则不存在第cx个逗号
		if(*buf == ',') cx--;
		buf++;
	}
	return buf - p;	 
}

/*
***********************************************************************
*	函 数 名: NMEA_Pow
*	功能说明: m^n函数
*	形    参: m,底数
*						n,指数
*	返 回 值: 运算后的结果
***********************************************************************
*/	
u32 NMEA_Pow(u8 m, u8 n)
{
	u32 result = 1;	 
	while(n--)result *= m;    
	return result;
}

/*
***********************************************************************
*	函 数 名: NMEA_Str2num
*	功能说明: str转换为数字,以','或者'*'结束
*	形    参: buf:数字存储区
*						dx:小数点位数,返回给调用函数
*	返 回 值: 转换后的结果
***********************************************************************
*/
int NMEA_Str2num(u8 *buf, u8 *dx)
{
	u8 *p = buf;
	u32 ires = 0, fres = 0;
	u8 ilen = 0, flen = 0, i;
	u8 mask = 0;
	int res;
	while(1) //得到整数和小数的长度
	{
		if(*p == '-'){mask |= 0X02; p++;}//是负数
		if(*p == ',' || (*p == '*'))break;//遇到结束了
		if(*p == '.'){mask |= 0X01; p++;}//遇到小数点了
		else if((*p > '9') || (*p < '0'))	//有非法字符
		{	
			ilen = 0;
			flen = 0;
			break;
		}	
		if(mask & 0X01)flen++;
		else ilen++;
		p++;
	}
	if(mask & 0X02)buf++;			//去掉负号
	for(i = 0; i<ilen; i++)		//得到整数部分数据
	{  
		ires += NMEA_Pow(10, ilen-1-i) * (buf[i]-'0');
	}
	if(flen > 5)flen = 5;			//最多取5位小数
	*dx = flen;	 							//小数点位数
	for(i = 0; i<flen; i++)		//得到小数部分数据
	{  
		fres += NMEA_Pow(10, flen-1-i) * (buf[ilen+1+i] - '0');
	} 
	res = ires * NMEA_Pow(10, flen) + fres;
	if(mask & 0X02)res=-res;		   
	return res;
}	

/*
***********************************************************************
*	函 数 名: gps_control
*	功能说明: 分析GPGGA信息（GPS定位信息）
*	形    参: *gpsx:nmea信息结构体（输出的全局变量）
*						*buf:接收到的GPS数据缓冲区首地址
*	返 回 值: 无
***********************************************************************
*/
void gps_control(void)
{
 
 GPIO_InitTypeDef  GPIO_InitStructure;
 	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);	 	//使能PB端口时钟
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;				 				
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 		//推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 		//IO口速度为50MHz
 GPIO_Init(GPIOA, &GPIO_InitStructure);					 					//根据设定参数初始化
	
 GPIO_SetBits(GPIOA, GPIO_Pin_4);
}

void open_gps(void)
{
	 GPIO_SetBits(GPIOA, GPIO_Pin_4);
}

void close_gps(void)
{
	 GPIO_ResetBits(GPIOA, GPIO_Pin_4);
}


  							 
/*
***********************************************************************
*	函 数 名: NMEA_GPGGA_Analysis
*	功能说明: 分析GPGGA信息（GPS定位信息）
*	形    参: *gpsx:nmea信息结构体（输出的全局变量）
*						*buf:接收到的GPS数据缓冲区首地址
*	返 回 值: 无
***********************************************************************
*/
void NMEA_GPGGA_Analysis(nmea_msg *gpsx, u8 *buf)
{
	u8 *p1, dx;			 
	u8 posx;    
	p1 = (u8*)strstr((const char *)buf, "$GPGGA");
	
	posx = NMEA_Comma_Pos(p1, 6);								//得到GPS状态
	if(posx != 0XFF)gpsx->gpssta = NMEA_Str2num(p1+posx, &dx);	
	
	posx = NMEA_Comma_Pos(p1, 7);								//得到用于定位的卫星数
	if(posx != 0XFF)gpsx->posslnum = NMEA_Str2num(p1+posx, &dx); 
	
	posx = NMEA_Comma_Pos(p1, 9);								//得到海拔高度
	if(posx != 0XFF)gpsx->altitude = NMEA_Str2num(p1+posx, &dx);  
	gpsx->altitude *= 1000;
}


/*
***********************************************************************
*	函 数 名: NMEA_GPRMC_Analysis
*	功能说明: 分析GPRMC信息（GPS推荐定位信息）
*	形    参: *gpsx:nmea信息结构体（输出的全局变量）
*						*buf:接收到的GPS数据缓冲区首地址
*	返 回 值: 无
***********************************************************************
*/
void NMEA_GPRMC_Analysis(nmea_msg *gpsx, u8 *buf)
{
	u8 *p1,dx;			 
	u8 posx;     
	u32 temp;	   
	float rs;  
	p1 = (u8*)strstr((const char *)buf, "$GPRMC");
	posx = NMEA_Comma_Pos(p1, 1);								//得到UTC时间
	if(posx != 0XFF)
	{
		temp = NMEA_Str2num(p1+posx, &dx)/NMEA_Pow(10,dx);	 	//得到UTC时间,去掉ms
		gpsx->utc.hour = temp/10000;
		gpsx->utc.min = (temp/100)%100;
		gpsx->utc.sec = temp%100;	 	 
	}
	
	posx = NMEA_Comma_Pos(p1,3);								//得到纬度
	if(posx != 0XFF)
	{
		temp = NMEA_Str2num(p1+posx, &dx);		 	 
		gpsx->latitude = temp/NMEA_Pow(10, dx+2);	//得到°
		rs = temp%NMEA_Pow(10, dx+2);							//得到'		 
		gpsx->latitude = gpsx->latitude*NMEA_Pow(10, 5)+(rs*NMEA_Pow(10, 5-dx))/60;//转换为° 
		gpsx->latitude /= 10;			//缩小10倍便于传输，最终放大10000倍
	}
	
	posx = NMEA_Comma_Pos(p1, 4);								//南纬还是北纬 
	if(posx != 0XFF)gpsx->nshemi = *(p1 + posx);
	
 	posx = NMEA_Comma_Pos(p1, 5);								//得到经度
	if(posx != 0XFF)
	{												  
		temp = NMEA_Str2num(p1+posx, &dx);		 	 
		gpsx->longitude = temp/NMEA_Pow(10, dx+2);	//得到°
		rs = temp%NMEA_Pow(10, dx+2);								//得到'		 
		gpsx->longitude = gpsx->longitude * NMEA_Pow(10, 5)+(rs * NMEA_Pow(10, 5-dx))/60;//转换为° 
		gpsx->longitude /= 10;		//缩小10倍便于传输，最终放大10000倍
	}
	
	posx = NMEA_Comma_Pos(p1, 6);									//东经还是西经
	if(posx != 0XFF)gpsx->ewhemi = *(p1 + posx);
	
	posx = NMEA_Comma_Pos(p1, 9);									//得到UTC日期
	if(posx != 0XFF)
	{
		temp = NMEA_Str2num(p1+posx, &dx);		 			//得到UTC日期
		gpsx->utc.date = temp/10000;
		gpsx->utc.month = (temp/100)%100;
		gpsx->utc.year = 2000 + temp%100;	 	 
	} 
}
  
/*
***********************************************************************
*	函 数 名: GPS_Analysis
*	功能说明: 提取NMEA-0183信息
*	形    参: *gpsx:nmea信息结构体（输出的全局变量）
*						*buf:接收到的GPS数据缓冲区首地址
*	返 回 值: 无
***********************************************************************
*/
void GPS_Analysis(nmea_msg *gpsx, u8 *buf)
{
	NMEA_GPGGA_Analysis(gpsx, buf);	//GPGGA解析 	
	NMEA_GPRMC_Analysis(gpsx, buf);	//GPRMC解析
}

void PrinterfGpsInfo(void)
{
	float tp;		   
	
	printf("\r\n定位状态：%d\r\n", gpsx.gpssta);
	if(gpsx.gpssta == 1)
	{
		printf("\r\n已定位\r\n");
		
		tp = gpsx.longitude;	   
		printf("\r\n经度：%.4f %1c\r\n", tp/=10000, gpsx.ewhemi);	//得到经度字符串
			 
		tp = gpsx.latitude;	   
		printf("\r\n纬度：%.4f %1c\r\n", tp/=10000, gpsx.nshemi);		//得到纬度字符串
		
		tp = gpsx.altitude;	   
		printf("\r\n高度：%.4f\r\n", tp/=10000);		//得到纬度字符串
	}else{
		printf("\r\n未定位\r\n");
	}
}

/******************** (C) COPYRIGHT 2014 CHY *****END OF FILE*******************/
