GPS GPRMC

GPS  简单实用-GPRMC

/*
 * GPS 模块使用相关说明
 * NMEA 0183是美国国家海洋电子协会(National Marine Electronics Association)为
 * 海用电子设备制定的标准格式。
 * 目前业已成了GPS导航设备统一的标准协议。
 * RTCM(Radio Technical Commission for Maritime services)
 * NMEA-0183协议采用ASCII码来传递GPS定位信息。
 * 帧格式形如:$aaccc,ddd,ddd,…,ddd*hh(CR)(LF)
 * 1、“$”:帧命令起始位
 * 2、aaccc:地址域,前两位为识别符(aa),后三位为语句名(ccc)
 * 3、ddd…ddd:数据
 * 4、“*”:校验和前缀(也可以作为语句数据结束的标志)
 * 5、hh:校验和(check  sum),$与*之间所有字符ASCII码的校验和
 *        (各字节做异或运算,得到校验和后,再转换16进制格式的ASCII字符)
 * 6、(CR)(LF):帧结束,回车和换行符
 *
 * $GPRMC(推荐定位信息,Recommended Minimum Specific GPS/Transit Data)
 * $GPRMC语句的基本格式如下:
 * $GPRMC,(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)*hh(CR)(LF)
 * (1)  UTC时间, hhmmss(时分秒)
 * (2)  定位状态, A=有效定位, V=无效定位
 * (3)  纬度ddmm.mmmm(度分)
 * (4)  纬度半球N(北半球)或S(南半球)
 * (5)  经度dddmm.mmmm(度分)
 * (6)  经度半球E(东经)或W(西经)
 * (7)  地面速率(000.0~999.9节)
 * (8)  地面航向(000.0~359.9度, 以真北方为参考基准)
 * (9)  UTC日期, ddmmyy(日月年)
 * (10) 磁偏角(000.0~180.0度, 前导位数不足则补0) empty
 * (11) 磁偏角方向,E(东)或W(西) empty
 * (12) 模式指示(A=自主定位, D=差分, E=估算, N=数据无效)
 * $GPRMC,082006.000,A,3852.9276,N,11527.4283,E,0.00,0.0,261009,,,A*38
 *
 * 1. 东经正数,西经负数(0-180), 经度的每一度被分为60分, 每一分被分为60秒
 * 2. 北纬正数,南纬负数(0- 90), 经度的每一度被分为60分, 每一分被分为60秒
 *
 */
#include 
#include 
#include 

#define GPS_RMC_TRACE 1
#if (GPS_RMC_TRACE == 1)
#define T_D(_fmt,...)                                                        \
    fprintf(stderr,  "%s/%d:"_fmt "\r\n", __func__, __LINE__, ##__VA_ARGS__);
#define __DEBUG_FUN   /* trace func section */
#else
#define T_D(_fmt,...)
#define __DEBUG_FUN
#endif


typedef struct {
	/* +1 for '\0', ez to snprintf */
	uint8_t utc_time[6+1];    /* hhmmss.xxx  but only xxx=000 */
	uint8_t status;           /* A/V         */
	uint8_t latitude[9+1];   /* ddmm.mmmm  */
	uint8_t NS;               /* N/S         */
	uint8_t logitude[10+1];   /* dddmm.mmmm */
	uint8_t EW;               /* E/W         */
	uint8_t speed[5+1];       /* 000.0~999.9 */
	uint8_t course[5+1];      /* 000.0~999.9 */
	uint8_t utc_date[6+1];    /* ddmmyy      */
    /* <10>: empty */
    /* <11>: empty */
	uint8_t  indicator;       /* A/D/E/N     */
} gps_rmc_t;


static char *box_strsep(char **stringp, const char *delim)
{
    char *s;
    const char *spanp;
    int c, sc;
    char *tok;
    if ((s = *stringp)== NULL)
        return (NULL);
    for (tok = s;;) {
        c = *s++;
        spanp = delim;
        do {
            if ((sc =*spanp++) == c) {
                if (c == 0)
                    s = NULL;
                else
                    s[-1] = 0;
                *stringp = s;
                return (tok);
            }
        } while (sc != 0);
    }
    /* NOTREACHED */
}


static char *box_next_token(char **p_cur)
{
    char *ret = NULL;

    if (*p_cur == NULL) {
        ret = NULL;
    } else {
        ret = box_strsep(p_cur, ",");
    }

    return ret;
}


static int box_token_has_more(char **p_cur)
{
    return ! (*p_cur == NULL || **p_cur == '\0');
}


__DEBUG_FUN void rmc_show(gps_rmc_t *gps_rmc)
{
	fprintf(stderr, "<1>utc_time  :%s\r\n", gps_rmc->utc_time);
	fprintf(stderr, "<2>status    :%c\r\n", gps_rmc->status);
	fprintf(stderr, "<3>latitude  :%s\r\n", gps_rmc->latitude);
	fprintf(stderr, "<4>NS        :%c\r\n", gps_rmc->NS);
	fprintf(stderr, "<5>logitude  :%s\r\n", gps_rmc->logitude);
	fprintf(stderr, "<6>EW        :%c\r\n", gps_rmc->EW);
	fprintf(stderr, "<7>speed     :%s\r\n", gps_rmc->speed);
	fprintf(stderr, "<8>course    :%s\r\n", gps_rmc->course);
	fprintf(stderr, "<9>utc_date  :%s\r\n", gps_rmc->utc_date);
	fprintf(stderr, "<12>indicator:%c\r\n", gps_rmc->indicator);
}


/*****************************************************************************
 * Name: gps_rmc_isvaild
 *
 * Description:
 *   GPS RMC Data is vaild and a tiny parser
 *
 * Input Parameters:
 *   data - string end with '\0'
 * Output Parameters:
 *   gps_rmc
 * Returned Value:
 *   1: vaild 0:unvaild
 ****************************************************************************/
uint8_t gps_rmc_isvaild(char *data, gps_rmc_t *gps_rmc)
{
	uint8_t i;
	char *str;
    if (!data)
        return 0;
	/* $GPRMC */
	if (!(str = box_next_token(&data))) {
        T_D("str null");
		return 0;
    } else if (strncmp(str, "$GPRMC", sizeof("$XXRMC")) &&
	           strncmp(str, "$GPRMC", sizeof("$XXRMC")) &&
		       strncmp(str, "$GPRMC", sizeof("$XXRMC"))) {
		return 0;
	}
    T_D("str:%s", str);
	/* (1)  UTC时间, hhmmss(时分秒) */
	if (!(str = box_next_token(&data))) {
        T_D("str null");
		return 0;
    }
    T_D("str:%s", str);
	strncpy(gps_rmc->utc_time, str, sizeof(gps_rmc->utc_time));
    gps_rmc->utc_time[sizeof(gps_rmc->utc_time) - 1] = '\0';
	/* (2)  定位状态, A=有效定位, V=无效定位 */
	if (!(str = box_next_token(&data))) {
        T_D("str null");
		return 0;
    } else if (strcmp(str, "A")) {
        T_D("Not 'A'");
		return 0;
    }
    T_D("str:%s", str);
	gps_rmc->status = str[0];
	/* (3)  纬度ddmm.mmmm(度分) */
	if (!(str = box_next_token(&data))) {
        T_D("str null");
		return 0;
    }
    T_D("str:%s", str);
	strncpy(gps_rmc->latitude, str, sizeof(gps_rmc->latitude));
	/* (4)  纬度半球N(北半球)或S(南半球) */
	if (!(str = box_next_token(&data))) {
        T_D("str null");
		return 0;
    }
    T_D("str:%s", str);
	gps_rmc->NS = str[0];
	/* (5)  经度dddmm.mmmm(度分) */
	if (!(str = box_next_token(&data))) {
        T_D("str null");
		return 0;
    }
    T_D("str:%s", str);
	strncpy(gps_rmc->logitude, str, sizeof(gps_rmc->logitude));
	/* (6)  经度半球E(东经)或W(西经) */
	if (!(str = box_next_token(&data))) {
        T_D("str null");
		return 0;
    }
    T_D("str:%s", str);
	gps_rmc->EW = str[0];
	/* (7)  地面速率(000.0~999.9节)  */
	if (!(str = box_next_token(&data))) {
        T_D("str null");
		return 0;
    }
    T_D("str:%s", str);
	strncpy(gps_rmc->speed, str, sizeof(gps_rmc->speed));
	/* (8)  地面航向(000.0~359.9度, 以真北方为参考基准) */
	if (!(str = box_next_token(&data))) {
        T_D("str null");
		return 0;
    }
    T_D("str:%s", str);
	strncpy(gps_rmc->course, str, sizeof(gps_rmc->course));
	/* (9)  UTC日期, ddmmyy(日月年) */
	if (!(str = box_next_token(&data))) {
        T_D("str null");
		return 0;
    }
    T_D("str:%s", str);
	strncpy(gps_rmc->utc_date, str, sizeof(gps_rmc->utc_date));
	/* (10) 磁偏角(000.0~180.0度, 前导位数不足则补0) */
	if (!(str = box_next_token(&data))) {
        T_D("str null");
		return 0;
    }
    T_D("str:%s", str);
	/* (11) 磁偏角方向,E(东)或W(西)  */
	if (!(str = box_next_token(&data))) {
        T_D("str null");
		return 0;
    }
    T_D("str:%s", str);
	/* (12) 模式指示(A=自主定位, D=差分, E=估算, N=数据无效)   */
	if (!(str = box_next_token(&data))) {
        T_D("str null");
		return 0;
    } else if (str[0] == 'N') {
		T_D("'N'");
		return 0;
	}
    T_D("str:%s", str);
	gps_rmc->indicator = str[0];
    /* last data has more token (12)*hh */
	if (box_token_has_more(&data)) {
        T_D("last data has more token (12)*hh");
		return 0;
    } 
	
    T_D("done");

	return  1;
}


int main(void)
{
    gps_rmc_t gps_rmc; 
    char gprmc_data[] = "$GNRMC,083505.000,A,3037.3890,N,10402.3510,E,0.32,163.24,250216,,,A*7F";

    if (gps_rmc_isvaild(gprmc_data, &gps_rmc)) {
        rmc_show(&gps_rmc);
    } else {
        fprintf(stderr, "%s: unvaild\r\n", gprmc_data);
    }

    return 0;
}











你可能感兴趣的:(嵌入式c)