IMU_DUAL/nmea/nmea_zjut.c
2022-12-06 17:34:02 +08:00

399 lines
8.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "main.h"
#include "time.h"
#include "rtklib.h"
/* 在rtklib 中定义结构体 */
#define MAXFIELD 64 /* max number of fields in a record */
typedef enum fsm_err
{
FSM_EOK = 0,
FSM_ERROR,
FSM_EINVAL,
} fsm_err_t;
enum
{
FSM_STATE_INIT = 0,
FSM_STATE_ABORT,
FSM_STATE_COMPLETE,
FSM_STATE_NAME_RECV,
FSM_STATE_ARGS_RECV,
FSM_STATE_CSUM_RECV,
FSM_STATE_CRLF_RECV,
FSM_STATE_MAX,
};
typedef enum
{
FSM_EVENT_DOLLAR_CHAR = 0,
FSM_EVENT_ORDINARY_CHAR,
FSM_EVENT_COMMA_CHAR,
FSM_EVENT_ASTERISK_CHAR,
FSM_EVENT_CR_CHAR,
FSM_EVENT_LF_CHAR,
FSM_EVENT_NUL_CHAR,
FSM_EVENT_MAX,
FSM_EVENT_G_CHAR,
FSM_EVENT_DATA,
FSM_EVENT_CHEAK1,
FSM_EVENT_CHEAK2,
FSM_EVENT_FINISH,
FSM_EVENT_IDLE,
} fsm_event_t;
enum
{
FSM_ERROR_DOLLAR_REPEAT = 1,
FSM_ERROR_ORDINARY_EARLY,
FSM_ERROR_ORDINARY_REPEAT,
FSM_ERROR_COMMA_EARLY,
FSM_ERROR_COMMA_REPEAT,
FSM_ERROR_ASTERISK_EARLY,
FSM_ERROR_ASTERISK_REPEAT,
FSM_ERROR_CR_EARLY,
FSM_ERROR_CR_REPEAT,
FSM_ERROR_LF_EARLY,
FSM_ERROR_LF_REPEAT,
FSM_ERROR_NUL_EARLY,
};
static int nmea_xor(uint8_t *buff, int len)
{
int i = 0;
int result = buff[1];
int ans = 0;
for (i = 2; buff[i] != '*' && i < len - 2; i++)
{
result ^= buff[i];
}
if (buff[++i] > '9')
{
ans += 10 + buff[i] - 'A';
}
else
{
ans += buff[i] - '0';
}
ans *= 16;
if (buff[++i] > '9')
{
ans += 10 + buff[i] - 'A';
}
else
{
ans += buff[i] - '0';
}
if (ans == result)
return 1;
else
return 0;
}
/* convert calendar day/time to time -------------------------------------------
* convert calendar day/time to gtime_t struct
* args : double *ep I day/time {year,month,day,hour,min,sec}
* return : gtime_t struct
* notes : proper in 1970-2037 or 1970-2099 (64bit time_t)
*-----------------------------------------------------------------------------*/
extern gtime_t epoch2time(const double *ep)
{
const int doy[]={1,32,60,91,121,152,182,213,244,274,305,335};
gtime_t time={0};
int days,sec,year=(int)ep[0],mon=(int)ep[1],day=(int)ep[2];
if (year<1970||2099<year||mon<1||12<mon) return time;
/* leap year if year%4==0 in 1901-2099 */
days=(year-1970)*365+(year-1969)/4+doy[mon-1]+day-2+(year%4==0&&mon>=3?1:0);
sec=(int)floor(ep[5]);
time.time=(time_t)days*86400+(int)ep[3]*3600+(int)ep[4]*60+sec;
time.sec=ep[5]-sec;
return time;
}
/* convert time in nmea format to time ---------------------------------------*/
static void septime(double t, double *t1, double *t2, double *t3)
{
*t1 = floor(t / 10000.0);
t -= *t1 * 10000.0;
*t2 = floor(t / 100.0);
*t3 = t - *t2 * 100.0;
}
/* convert ddmm.mm in nmea format to deg -------------------------------------*/
static double dmm2deg(double dmm)
{
return floor(dmm / 100.0) + fmod(dmm, 100.0) / 60.0;
}
/* decode NMEA RMC (Recommended Minumum Specific GNSS Data) sentence ---------*/
static int decode_nmearmc(char **val, int n, sol_t *sol)
{
double tod = 0.0, lat = 0.0, lon = 0.0, vel = 0.0, dir = 0.0, date = 0.0, ang = 0.0, ep[6];
double pos[3] = {0};
char act = ' ', ns = 'N', ew = 'E', mew = 'E', mode = 'A';
int i;
// trace(4, "decode_nmearmc: n=%d\n", n);
for (i = 0; i < n; i++)
{
switch (i)
{
case 0:
tod = atof(val[i]);
break; /* time in utc (hhmmss) */
case 1:
act = *val[i];
break; /* A=active,V=void */
case 2:
lat = atof(val[i]);
break; /* latitude (ddmm.mmm) */
case 3:
ns = *val[i];
break; /* N=north,S=south */
case 4:
lon = atof(val[i]);
break; /* longitude (dddmm.mmm) */
case 5:
ew = *val[i];
break; /* E=east,W=west */
case 6:
vel = atof(val[i]);
break; /* speed (knots) */
case 7:
dir = atof(val[i]);
break; /* track angle (deg) */
case 8:
date = atof(val[i]);
break; /* date (ddmmyy) */
case 9:
ang = atof(val[i]);
break; /* magnetic variation */
case 10:
mew = *val[i];
break; /* E=east,W=west */
case 11:
mode = *val[i];
break; /* mode indicator (>nmea 2) */
/* A=autonomous,D=differential */
/* E=estimated,N=not valid,S=simulator */
}
}
if ((act != 'A' && act != 'V') || (ns != 'N' && ns != 'S') || (ew != 'E' && ew != 'W'))
{
// trace(3, "invalid nmea rmc format\n");
return 0;
}
pos[0] = (ns == 'S' ? -1.0 : 1.0) * dmm2deg(lat) * D2R;
pos[1] = (ew == 'W' ? -1.0 : 1.0) * dmm2deg(lon) * D2R;
septime(date, ep + 2, ep + 1, ep);
septime(tod, ep + 3, ep + 4, ep + 5);
ep[0] += ep[0] < 80.0 ? 2000.0 : 1900.0;
sol->utctime=epoch2time(ep);
sol->time = utc2gpst(sol->utctime);
pos2ecef(pos, sol->rr);
sol->stat = mode == 'D' ? SOLQ_DGPS : SOLQ_SINGLE;
sol->ns = 0;
sol->type = 0; /* postion type = xyz */
// trace(1, "decode_nmearmc: %s rr=%.3f %.3f %.3f stat=%d ns=%d vel=%.2f dir=%.0f ang=%.0f mew=%c mode=%c \r\n",
// time_str(sol->time, 0), sol->rr[0], sol->rr[1], sol->rr[2], sol->stat, sol->ns,
// vel, dir, ang, mew, mode);
// trace(3, "decode_nmearmc: %s rr=%.3f %.3f %.3f stat=%d ns=%d \r\n",
// time_str(sol->time, 0), sol->rr[0], sol->rr[1], sol->rr[2], sol->stat, sol->ns);
return 2; /* update time */
}
static int decode_nmea(char *buff, sol_t *sol)
{
char *p, *q, *val[MAXFIELD];
int n = 0;
// trace(4, "decode_nmea: buff=%s\n", buff);
/* parse fields */
for (p = buff; *p && n < MAXFIELD; p = q + 1)
{
if ((q = strchr(p, ',')) || (q = strchr(p, '*')))
{
val[n++] = p;
*q = '\0';
}
else
break;
}
if (n < 1)
{
return 0;
}
if (!strcmp(val[0] + 3, "RMC"))
{ /* $xxRMC */
return decode_nmearmc(val + 1, n - 1, sol);
}
// else if (!strcmp(val[0] + 3, "ZDA"))
//{ /* $xxZDA */
// return decode_nmeazda(val + 1, n - 1, sol);
// }
// else if (!strcmp(val[0] + 3, "GGA"))
//{ /* $xxGGA */
// return decode_nmeagga(val + 1, n - 1, sol);
// }
return 0;
}
// extern int input_nmea(nmea_t *nmea, uint8_t data)
// {
// static uint8_t state = 0;
// int8_t ans = 0;
// trace(5, "input_nmea: data=%02x\n", data);
// if (nmea->nbyte == 0 && data == '$')
// {
// state = 1;
// }
// else if (nmea->nbyte != 0 && data == '*')
// {
// state = 2;
// }
// else if (nmea->len != 0)
// {
// state = 3;
// }
// if (state == 1)
// {
// nmea->buff[nmea->nbyte++] = data;
// if(nmea->nbyte == 2 && nmea->buff[1] != 'G')
// {
// ans = -1;
// }
// }
// else if (state == 2)
// {
// nmea->buff[nmea->nbyte++] = data;
// nmea->len = nmea->nbyte + 2;
// }
// else if (state == 3)
// {
// nmea->buff[nmea->nbyte++] = data;
// if (nmea->nbyte == nmea->len) /* <20><><EFBFBD><EFBFBD><EFBFBD>ռ<EFBFBD><D5BC><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>У<EFBFBD><D0A3> */
// {
// if (0 == nmea_xor(nmea->buff, nmea->len))
// {
// trace(1, "nmea parity error: len=%d \n", nmea->len);
// ans = -1;
// }
// else
// {
// ans = 1;
// }
// }
// }
// if (ans == 1)
// {
// return decode_nmea((char *)nmea->buff, &(nmea->sol));
// }
// if(nmea->nbyte >=255) /* Խ<><D4BD> */
// {
// ans = -1;
// }
// if (ans != 0)
// {
// nmea->len = 0;
// nmea->nbyte = 0;
// state = 0;
// }
// return ans;
// }
extern int input_nmea(nmea_t *nmea, const uint8_t data)
{
static fsm_event_t event = 0;
int8_t ans = 0;
// trace(5, "input_nmea: data=%02x\n", data);
switch (data)
{
case '$':
event = FSM_EVENT_DOLLAR_CHAR;
break;
case '*':
if(event == FSM_EVENT_DATA)
event = FSM_EVENT_ASTERISK_CHAR;
else
event = FSM_EVENT_IDLE;
break;
default:
break;
}
switch (event)
{
case FSM_EVENT_DOLLAR_CHAR:
nmea->nbyte = 0;
nmea->len = 0;
nmea->buff[nmea->nbyte++] = data;
event = FSM_EVENT_G_CHAR;
break;
case FSM_EVENT_G_CHAR:
if (data == 'G')
{
nmea->buff[nmea->nbyte++] = data;
event = FSM_EVENT_DATA;
}
else
{
event = FSM_EVENT_IDLE;
}
break;
case FSM_EVENT_DATA:
if (nmea->nbyte > 168)
{
event = FSM_EVENT_IDLE;
}
else
{
nmea->buff[nmea->nbyte++] = data;
}
break;
case FSM_EVENT_ASTERISK_CHAR:
nmea->buff[nmea->nbyte++] = data;
nmea->len = nmea->nbyte + 2;
event = FSM_EVENT_CHEAK1;
break;
case FSM_EVENT_CHEAK1:
nmea->buff[nmea->nbyte++] = data;
event = FSM_EVENT_CHEAK2;
break;
case FSM_EVENT_CHEAK2:
nmea->buff[nmea->nbyte++] = data;
event = FSM_EVENT_FINISH;
break;
default:
break;
}
if (event == FSM_EVENT_FINISH)
{
event = FSM_EVENT_IDLE;
if (0 == nmea_xor(nmea->buff, nmea->len))
{
// trace(3, "nmea parity error: len=%d \r\n", nmea->len);
ans = -1;
}
else
{
ans = 1;
return decode_nmea((char *)nmea->buff, &(nmea->sol));
}
}
return ans;
}