37static const double PI = 3.1415926535897932;
38static const double D2R = 3.1415926535897932 / 180.0;
39static const double R2D = 180.0 / 3.1415926535897932;
41static const double FE_WGS84 = 1.0 / 298.257223563;
44#define MSG_DISCONN "$DISCONNECT"
47extern double dms2deg(
const double* dms);
48extern void deg2dms(
double deg,
double* dms,
int ndec);
49extern double norm(
const double* a,
int n);
50extern void covecef(
const double* pos,
const double* Q,
double* P);
51extern void enu2ecef(
const double* pos,
const double* e,
double* r);
53extern double geoidh(
const double* pos);
57#define SQR(x) ((x) < 0.0 ? -(x) * (x) : (x) * (x))
58#define SQRT(x) ((x) < 0.0 || (x) != (x) ? 0.0 : sqrt(x))
64#define KNOT2M 0.514444444
69 "GP",
"GL",
"GA",
"GB",
"GQ",
"GI",
""};
88 }
else if (!strcmp(opt->
sep,
"\\t")) {
94static int tonum(
char* buff,
const char* sep,
double* v) {
95 int n, len = (int)strlen(sep);
98 for (p = buff, n = 0; n <
MAXFIELD; p = q + len) {
99 if ((q = strstr(p, sep))) {
112static double sqvar(
double covar) {
return covar < 0.0 ? -sqrt(-covar) : sqrt(covar); }
114static double dmm2deg(
double dmm) {
return floor(dmm / 100.0) + fmod(dmm, 100.0) / 60.0; }
116static void septime(
double t,
double* t1,
double* t2,
double* t3) {
117 *t1 = floor(t / 10000.0);
119 *t2 = floor(t / 100.0);
120 *t3 = t - *t2 * 100.0;
127 P[1] = P[3] = sol->
qr[3];
128 P[5] = P[7] = sol->
qr[4];
129 P[2] = P[6] = sol->
qr[5];
133 sol->
qr[0] = (float)P[0];
134 sol->
qr[1] = (float)P[4];
135 sol->
qr[2] = (float)P[8];
136 sol->
qr[3] = (float)P[1];
137 sol->
qr[4] = (float)P[5];
138 sol->
qr[5] = (float)P[2];
145 P[1] = P[3] = sol->
qv[3];
146 P[5] = P[7] = sol->
qv[4];
147 P[2] = P[6] = sol->
qv[5];
151 sol->
qv[0] = (float)P[0];
152 sol->
qv[1] = (float)P[4];
153 sol->
qv[2] = (float)P[8];
154 sol->
qv[3] = (float)P[1];
155 sol->
qv[4] = (float)P[5];
156 sol->
qv[5] = (float)P[2];
160 double tod = 0.0, lat = 0.0, lon = 0.0, vel = 0.0, dir = 0.0, date = 0.0, ang = 0.0, ep[6];
162 char act =
' ', ns =
'N', ew =
'E', mew =
'E', mode =
'A';
165 trace(NULL, 4,
"decode_nmearmc: n=%d\n", n);
167 for (i = 0; i < n; i++) {
209 if ((act !=
'A' && act !=
'V') || (ns !=
'N' && ns !=
'S') || (ew !=
'E' && ew !=
'W')) {
210 trace(NULL, 3,
"invalid nmea rmc format\n");
213 pos[0] = (ns ==
'S' ? -1.0 : 1.0) *
dmm2deg(lat) *
D2R;
214 pos[1] = (ew ==
'W' ? -1.0 : 1.0) *
dmm2deg(lon) *
D2R;
215 septime(date, ep + 2, ep + 1, ep);
216 septime(tod, ep + 3, ep + 4, ep + 5);
217 ep[0] += ep[0] < 80.0 ? 2000.0 : 1900.0;
225 trace(NULL, 5,
"decode_nmearmc: %s rr=%.3f %.3f %.3f stat=%d ns=%d vel=%.2f dir=%.0f ang=%.0f mew=%c mode=%c\n",
226 time_str(sol->
time, 0), sol->
rr[0], sol->
rr[1], sol->
rr[2], sol->
stat, sol->
ns, vel, dir, ang, mew, mode);
232 double tod = 0.0, ep[6] = {0};
235 trace(NULL, 4,
"decode_nmeazda: n=%d\n", n);
237 for (i = 0; i < n; i++) {
243 ep[2] = atof(val[i]);
246 ep[1] = atof(val[i]);
249 ep[0] = atof(val[i]);
253 septime(tod, ep + 3, ep + 4, ep + 5);
264 double tod = 0.0, lat = 0.0, lon = 0.0, hdop = 0.0, alt = 0.0, msl = 0.0, ep[6], tt;
265 double pos[3] = {0}, age = 0.0;
266 char ns =
'N', ew =
'E', ua =
' ', um =
' ';
267 int i, solq = 0, nrcv = 0;
269 trace(NULL, 4,
"decode_nmeagga: n=%d\n", n);
271 for (i = 0; i < n; i++) {
314 if ((ns !=
'N' && ns !=
'S') || (ew !=
'E' && ew !=
'W')) {
315 trace(NULL, 3,
"invalid nmea gga format\n");
319 trace(NULL, 3,
"no date info for nmea gga\n");
322 pos[0] = (ns ==
'N' ? 1.0 : -1.0) *
dmm2deg(lat) *
D2R;
323 pos[1] = (ew ==
'E' ? 1.0 : -1.0) *
dmm2deg(lon) *
D2R;
327 septime(tod, ep + 3, ep + 4, ep + 5);
332 }
else if (tt > 43200.0) {
340 sol->
age = (float)age;
344 trace(NULL, 5,
"decode_nmeagga: %s rr=%.3f %.3f %.3f stat=%d ns=%d hdop=%.1f ua=%c um=%c\n",
time_str(sol->
time, 0),
345 sol->
rr[0], sol->
rr[1], sol->
rr[2], sol->
stat, sol->
ns, hdop, ua, um);
351 if (strlen(buff) < 6 || buff[0] !=
'$') {
354 return !strncmp(buff + 1,
"GP", 2) || !strncmp(buff + 1,
"GA", 2) ||
355 !strncmp(buff + 1,
"GL", 2) || !strncmp(buff + 1,
"GN", 2) || !strncmp(buff + 1,
"GB", 2) ||
356 !strncmp(buff + 1,
"GQ", 2) ||
357 !strncmp(buff + 1,
"GI", 2) || !strncmp(buff + 1,
"BD", 2) || !strncmp(buff + 1,
"QZ", 2);
361 if (strlen(buff) < 7 || buff[0] !=
'$') {
364 return !strncmp(buff + 1,
"POS", 3) || !strncmp(buff + 1,
"VELACC", 6) || !strncmp(buff + 1,
"CLK", 3) ||
365 !strncmp(buff + 1,
"ION", 3) || !strncmp(buff + 1,
"TROP", 4) || !strncmp(buff + 1,
"HWBIAS", 6) ||
366 !strncmp(buff + 1,
"TRPG", 4) || !strncmp(buff + 1,
"AMB", 3) || !strncmp(buff + 1,
"SAT", 3);
373 trace(NULL, 4,
"decode_nmea: buff=%s\n", buff);
376 for (p = buff; *p && n <
MAXFIELD; p = q + 1) {
377 if ((q = strchr(p,
',')) || (q = strchr(p,
'*'))) {
387 if (!strcmp(val[0] + 3,
"RMC")) {
389 }
else if (!strcmp(val[0] + 3,
"ZDA")) {
391 }
else if (!strcmp(val[0] + 3,
"GGA")) {
399 char *p, *q, s[64] =
" ";
402 trace(NULL, 4,
"decode_soltime:\n");
404 if (!strcmp(opt->
sep,
"\\t")) {
406 }
else if (*opt->
sep) {
409 len = (int)strlen(s);
415 if (sscanf(buff,
"%lf %lf %lf %lf:%lf:%lf", v, v + 1, v + 2, v + 3, v + 4, v + 5) < 6) {
419 if (!(p = strchr(buff,
':')) || !(p = strchr(p + 1,
':'))) {
422 for (p++; isdigit((
int)*p) || *p ==
'.';) {
428 if (sscanf(buff,
"%lf/%lf/%lf %lf:%lf:%lf", v, v + 1, v + 2, v + 3, v + 4, v + 5) >= 6) {
430 v[0] += v[0] < 80.0 ? 2000.0 : 1900.0;
438 if (!(p = strchr(buff,
':')) || !(p = strchr(p + 1,
':'))) {
441 for (p++; isdigit((
int)*p) || *p ==
'.';) {
446 for (p = buff, n = 0; n < 2; p = q + len) {
447 if ((q = strstr(p, s))) {
450 if (sscanf(p,
"%lf", v + n) == 1) {
457 if (n >= 2 && 0.0 <= v[0] && v[0] <= 3000.0 && 0.0 <= v[1] && v[1] < 604800.0) {
468 const char* sep =
opt2sep(opt);
470 trace(NULL, 4,
"decode_solxyz:\n");
472 if ((n =
tonum(buff, sep, val)) < 3) {
476 for (j = 0; j < 3; j++) {
477 sol->
rr[j] = val[i++];
480 sol->
stat = (uint8_t)val[i++];
483 sol->
ns = (uint8_t)val[i++];
493 P[1] = P[3] =
SQR(val[i]);
495 P[5] = P[7] =
SQR(val[i]);
497 P[2] = P[6] =
SQR(val[i]);
503 sol->
age = (float)val[i++];
506 sol->
ratio = (float)val[i++];
510 for (j = 0; j < 3; j++) {
511 sol->
rr[j + 3] = val[i++];
515 for (j = 0; j < 9; j++) {
525 P[1] = P[3] =
SQR(val[i]);
527 P[5] = P[7] =
SQR(val[i]);
529 P[2] = P[6] =
SQR(val[i]);
543 double val[
MAXFIELD], pos[3], vel[3], Q[9] = {0}, P[9];
545 const char* sep =
opt2sep(opt);
547 trace(NULL, 4,
"decode_solllh:\n");
549 n =
tonum(buff, sep, val);
555 pos[0] = val[i++] *
D2R;
556 pos[1] = val[i++] *
D2R;
569 sol->
stat = (uint8_t)val[i++];
572 sol->
ns = (uint8_t)val[i++];
582 Q[1] = Q[3] =
SQR(val[i]);
584 Q[2] = Q[6] =
SQR(val[i]);
586 Q[5] = Q[7] =
SQR(val[i]);
593 sol->
age = (float)val[i++];
596 sol->
ratio = (float)val[i++];
606 for (j = 0; j < 9; j++) {
616 Q[1] = Q[3] =
SQR(val[i]);
618 Q[2] = Q[6] =
SQR(val[i]);
620 Q[5] = Q[7] =
SQR(val[i]);
637 const char* sep =
opt2sep(opt);
639 trace(NULL, 4,
"decode_solenu:\n");
641 if ((n =
tonum(buff, sep, val)) < 3) {
645 for (j = 0; j < 3; j++) {
646 sol->
rr[j] = val[i++];
649 sol->
stat = (uint8_t)val[i++];
652 sol->
ns = (uint8_t)val[i++];
662 Q[1] = Q[3] =
SQR(val[i]);
664 Q[5] = Q[7] =
SQR(val[i]);
666 Q[2] = Q[6] =
SQR(val[i]);
672 sol->
age = (float)val[i++];
675 sol->
ratio = (float)val[i++];
687 double tow, pos[3], std[3] = {0};
690 trace(NULL, 4,
"decode_solsss:\n");
692 if (sscanf(buff,
"$POS,%d,%lf,%d,%lf,%lf,%lf,%lf,%lf,%lf", &week, &tow, &solq, pos, pos + 1, pos + 2, std, std + 1,
700 for (i = 0; i < 6; i++) {
701 sol->
rr[i] = i < 3 ? pos[i] : 0.0;
702 sol->
qr[i] = i < 3 ? (float)
SQR(std[i]) : 0.0f;
716 trace(NULL, 4,
"decode_solgsi:\n");
718 if (
tonum(buff,
" ", val) < 3) {
722 for (j = 0; j < 3; j++) {
723 sol->
rr[j] = val[i++];
733 trace(NULL, 4,
"decode_solpos: buff=%s\n", buff);
758 const char* sep =
opt2sep(opt);
760 trace(NULL, 3,
"decode_refpos: buff=%s\n", buff);
762 if ((n =
tonum(buff, sep, val)) < 3) {
767 for (i = 0; i < 3; i++) {
770 }
else if (opt->
degf == 0) {
771 pos[0] = val[0] *
D2R;
772 pos[1] = val[1] *
D2R;
775 }
else if (opt->
degf == 1 && n >= 7) {
786 trace(NULL, 4,
"decode_sol: buff=%s\n", buff);
794 if (!strstr(buff,
"ref pos") && !strstr(buff,
"slave pos")) {
797 if (!(p = strchr(buff,
':'))) {
810 trace(NULL, 4,
"decode_solhead: buff=%s\n", buff);
812 if (strncmp(buff,
COMMENTH, 1) && strncmp(buff,
"+", 1)) {
816 if (strstr(buff,
"GPST")) {
818 }
else if (strstr(buff,
"UTC")) {
820 }
else if (strstr(buff,
"JST")) {
824 if ((p = strstr(buff,
"x-ecef(m)"))) {
827 strncpy(opt->
sep, p + 9, 1);
829 }
else if ((p = strstr(buff,
"latitude(d'\")"))) {
832 strncpy(opt->
sep, p + 14, 1);
834 }
else if ((p = strstr(buff,
"latitude(deg)"))) {
837 strncpy(opt->
sep, p + 13, 1);
839 }
else if ((p = strstr(buff,
"e-baseline(m)"))) {
842 strncpy(opt->
sep, p + 13, 1);
844 }
else if ((p = strstr(buff,
"+SITE/INF"))) {
848 strcpy(opt->
sep,
" ");
856 trace(NULL, 3,
"readsolopt:\n");
858 for (i = 0; fgets(buff,
sizeof(buff), fp) && i < 100; i++) {
878 trace(NULL, 4,
"inputsol: data=0x%02x\n", data);
882 if (data ==
'$' || (!isprint(data) && data !=
'\r' && data !=
'\n')) {
885 if (data !=
'\r' && data !=
'\n') {
886 solbuf->
buff[solbuf->
nb++] = data;
892 solbuf->
buff[solbuf->
nb] =
'\0';
897 trace(NULL, 3,
"disconnect received\n");
910 if (stat != 1 || !
screent(sol.
time, ts, te, tint) || (qflag && sol.
stat != qflag)) {
914 return addsol(solbuf, &sol);
921 trace(NULL, 3,
"readsoldata:\n");
923 while ((c = fgetc(fp)) != EOF) {
925 inputsol((uint8_t)c, ts, te, tint, qflag, opt, solbuf);
927 return solbuf->
n > 0;
930static int cmpsol(
const void* p1,
const void* p2) {
933 return tt < -0.0 ? -1 : (tt > 0.0 ? 1 : 0);
940 trace(NULL, 4,
"sort_solbuf: n=%d\n", solbuf->
n);
942 if (solbuf->
n <= 0) {
946 if (!(solbuf_data = (
sol_t*)realloc(solbuf->
data,
sizeof(
sol_t) * solbuf->
n))) {
947 trace(NULL, 1,
"sort_solbuf: memory allocation error\n");
950 solbuf->
n = solbuf->
nmax = 0;
953 solbuf->
data = solbuf_data;
957 for (i = n = 0; i < solbuf->
n; i++) {
959 solbuf->
data[n++] = solbuf->
data[i];
964 solbuf->
end = solbuf->
n - 1;
983 trace(NULL, 3,
"readsolt: nfile=%d\n", nfile);
987 for (i = 0; i < nfile; i++) {
988 if (!(fp = fopen(files[i],
"rb"))) {
989 trace(NULL, 2,
"readsolt: file open error %s\n", files[i]);
997 if (!
readsoldata(fp, ts, te, tint, qflag, &opt, solbuf)) {
998 trace(NULL, 2,
"readsolt: no solution in %s\n", files[i]);
1007 trace(NULL, 3,
"readsol: nfile=%d\n", nfile);
1009 return readsolt(files, nfile, time, time, 0.0, 0, sol);
1020 trace(NULL, 4,
"addsol:\n");
1023 if (solbuf->
nmax <= 1) {
1026 solbuf->
data[solbuf->
end] = *sol;
1027 if (++solbuf->
end >= solbuf->
nmax) {
1030 if (solbuf->
start == solbuf->
end) {
1040 if (solbuf->
n >= solbuf->
nmax) {
1041 solbuf->
nmax = solbuf->
nmax == 0 ? 8192 : solbuf->
nmax * 2;
1043 trace(NULL, 1,
"addsol: memory allocation error\n");
1045 solbuf->
data = NULL;
1046 solbuf->
n = solbuf->
nmax = 0;
1049 solbuf->
data = solbuf_data;
1051 solbuf->
data[solbuf->
n++] = *sol;
1061 trace(NULL, 4,
"getsol: index=%d\n", index);
1063 if (index < 0 || solbuf->n <= index) {
1066 if ((index = solbuf->
start + index) >= solbuf->
nmax) {
1067 index -= solbuf->
nmax;
1069 return solbuf->
data + index;
1084 trace(NULL, 3,
"initsolbuf: cyclic=%d nmax=%d\n", cyclic, nmax);
1086 solbuf->
n = solbuf->
nmax = solbuf->
start = solbuf->
end = solbuf->
nb = 0;
1091 solbuf->
data = NULL;
1092 for (i = 0; i < 3; i++) {
1093 solbuf->
rb[i] = 0.0;
1100 trace(NULL, 1,
"initsolbuf: memory allocation error\n");
1103 solbuf->
nmax = nmax;
1114 trace(NULL, 3,
"freesolbuf: n=%d\n", solbuf->
n);
1117 solbuf->
n = solbuf->
nmax = solbuf->
start = solbuf->
end = solbuf->
nb = 0;
1118 solbuf->
data = NULL;
1119 for (i = 0; i < 3; i++) {
1120 solbuf->
rb[i] = 0.0;
1124 trace(NULL, 3,
"freesolstatbuf: n=%d\n", solstatbuf->
n);
1126 solstatbuf->
n = solstatbuf->
nmax = 0;
1128 solstatbuf->
data = NULL;
1134 return tt < -0.0 ? -1 : (tt > 0.0 ? 1 : 0);
1141 trace(NULL, 4,
"sort_solstat: n=%d\n", statbuf->
n);
1143 if (statbuf->
n <= 0) {
1147 if (!(statbuf_data = realloc(statbuf->
data,
sizeof(
solstat_t) * statbuf->
n))) {
1148 trace(NULL, 1,
"sort_solstat: memory allocation error\n");
1150 statbuf->
data = NULL;
1151 statbuf->
n = statbuf->
nmax = 0;
1154 statbuf->
data = statbuf_data;
1158 for (i = n = 0; i < statbuf->
n; i++) {
1160 statbuf->
data[n++] = statbuf->
data[i];
1169 double tow, az, el, resp, resc, snr;
1170 int n, week, sat, frq, vsat, fix, slip, lock, outc, slipc, rejc;
1171 char id[32] =
"", *p;
1173 trace(NULL, 4,
"decode_solstat: buff=%s\n", buff);
1175 if (strstr(buff,
"$SAT") != buff) {
1179 for (p = buff; *p; p++) {
1185 n = sscanf(buff,
"$SAT%d%lf%s%d%lf%lf%lf%lf%d%lf%d%d%d%d%d%d", &week, &tow,
id, &frq, &az, &el, &resp, &resc, &vsat,
1186 &snr, &fix, &slip, &lock, &outc, &slipc, &rejc);
1189 trace(NULL, 2,
"invalid format of solution status: %s\n", buff);
1193 trace(NULL, 2,
"invalid satellite in solution status: %s\n",
id);
1198 stat->
sat = (uint8_t)sat;
1199 stat->
frq = (uint8_t)frq;
1200 stat->
az = (float)(az *
D2R);
1201 stat->
el = (float)(el *
D2R);
1202 stat->
resp = (float)resp;
1203 stat->
resc = (float)resc;
1204 stat->
flag = (uint8_t)((vsat << 5) + (slip << 3) + fix);
1206 stat->
lock = (uint16_t)lock;
1207 stat->
outc = (uint16_t)outc;
1208 stat->
slipc = (uint16_t)slipc;
1209 stat->
rejc = (uint16_t)rejc;
1216 trace(NULL, 4,
"addsolstat:\n");
1218 if (statbuf->
n >= statbuf->
nmax) {
1219 statbuf->
nmax = statbuf->
nmax == 0 ? 8192 : statbuf->
nmax * 2;
1221 trace(NULL, 1,
"addsolstat: memory allocation error\n");
1223 statbuf->
data = NULL;
1224 statbuf->
n = statbuf->
nmax = 0;
1227 statbuf->
data = statbuf_data;
1229 statbuf->
data[statbuf->
n++] = *stat;
1236 trace(NULL, 3,
"readsolstatdata:\n");
1238 while (fgets(buff,
sizeof(buff), fp)) {
1249 return statbuf->
n > 0;
1263 char path[1024], *p;
1266 trace(NULL, 3,
"readsolstatt: nfile=%d\n", nfile);
1268 statbuf->
n = statbuf->
nmax = 0;
1269 statbuf->
data = NULL;
1271 for (i = 0; i < nfile; i++) {
1272 if ((p = strrchr(files[i],
'.')) && !strcmp(p,
".stat")) {
1273 sprintf(path,
"%s", files[i]);
1275 sprintf(path,
"%s.stat", files[i]);
1277 if (!(fp = fopen(path,
"r"))) {
1278 trace(NULL, 2,
"readsolstatt: file open error %s\n", path);
1283 trace(NULL, 2,
"readsolstatt: no solution in %s\n", path);
1296 trace(NULL, 3,
"readsolstat: nfile=%d\n", nfile);
1298 return readsolstatt(files, nfile, time, time, 0.0, statbuf);
1302 const char* sep =
opt2sep(opt);
1303 char* p = (
char*)buff;
1305 trace(NULL, 3,
"outecef:\n");
1308 "%s%s%14.4f%s%14.4f%s%14.4f%s%3d%s%3d%s%8.4f%s%8.4f%s%8.4f%s"
1309 "%8.4f%s%8.4f%s%8.4f%s%6.2f%s%6.1f",
1310 s, sep, sol->
rr[0], sep, sol->
rr[1], sep, sol->
rr[2], sep, sol->
stat, sep, sol->
ns, sep,
1316 "%s%10.5f%s%10.5f%s%10.5f%s%9.5f%s%8.5f%s%8.5f%s%8.5f%s"
1318 sep, sol->
rr[3], sep, sol->
rr[4], sep, sol->
rr[5], sep,
SQRT(sol->
qv[0]), sep,
SQRT(sol->
qv[1]),
1321 p += sprintf(p,
"\r\n");
1322 return p - (
char*)buff;
1326 double pos[3], vel[3], dms1[3], dms2[3], P[9], Q[9];
1327 const char* sep =
opt2sep(opt);
1328 char* p = (
char*)buff;
1330 trace(NULL, 3,
"outpos :\n");
1341 p += sprintf(p,
"%s%s%4.0f%s%02.0f%s%08.5f%s%4.0f%s%02.0f%s%08.5f", s, sep, dms1[0], sep, dms1[1], sep, dms1[2],
1342 sep, dms2[0], sep, dms2[1], sep, dms2[2]);
1344 p += sprintf(p,
"%s%s%14.9f%s%14.9f", s, sep, pos[0] *
R2D, sep, pos[1] *
R2D);
1347 "%s%10.4f%s%3d%s%3d%s%8.4f%s%8.4f%s%8.4f%s%8.4f%s%8.4f%s%8.4f"
1349 sep, pos[2], sep, sol->
stat, sep, sol->
ns, sep,
SQRT(Q[4]), sep,
SQRT(Q[0]), sep,
SQRT(Q[8]), sep,
1357 "%s%10.5f%s%10.5f%s%10.5f%s%9.5f%s%8.5f%s%8.5f%s%8.5f%s"
1359 sep, vel[1], sep, vel[0], sep, vel[2], sep,
SQRT(Q[4]), sep,
SQRT(Q[0]), sep,
SQRT(Q[8]), sep,
1362 p += sprintf(p,
"\r\n");
1363 return p - (
char*)buff;
1367 double pos[3], rr[3], enu[3], P[9], Q[9];
1369 const char* sep =
opt2sep(opt);
1370 char* p = (
char*)buff;
1372 trace(NULL, 3,
"outenu :\n");
1374 for (i = 0; i < 3; i++) {
1375 rr[i] = sol->
rr[i] - rb[i];
1382 "%s%s%14.4f%s%14.4f%s%14.4f%s%3d%s%3d%s%8.4f%s%8.4f%s%8.4f%s"
1383 "%8.4f%s%8.4f%s%8.4f%s%6.2f%s%6.1f\r\n",
1384 s, sep, enu[0], sep, enu[1], sep, enu[2], sep, sol->
stat, sep, sol->
ns, sep,
SQRT(Q[0]), sep,
1385 SQRT(Q[4]), sep,
SQRT(Q[8]), sep,
sqvar(Q[1]), sep,
sqvar(Q[5]), sep,
sqvar(Q[2]), sep, sol->
age, sep,
1387 return p - (
char*)buff;
1391 static double dirp = 0.0;
1393 double ep[6], pos[3], enuv[3], dms1[3], dms2[3], vel, dir, amag = 0.0;
1394 char *p = (
char*)buff, *q, sum;
1395 const char *emag =
"E", *mode =
"A", *status =
"V";
1397 trace(NULL, 3,
"outnmea_rmc:\n");
1400 p += sprintf(p,
"$%sRMC,,,,,,,,,,,,,",
NMEA_TID);
1401 for (q = (
char*)buff + 1, sum = 0; *q; q++) {
1404 p += sprintf(p,
"*%02X%c%c", sum, 0x0D, 0x0A);
1405 return p - (
char*)buff;
1408 if (time.
sec >= 0.995) {
1415 vel =
norm(enuv, 3);
1417 dir = atan2(enuv[0], enuv[1]) *
R2D;
1435 "$%sRMC,%02.0f%02.0f%05.2f,A,%02.0f%010.7f,%s,%03.0f%010.7f,"
1436 "%s,%4.2f,%4.2f,%02.0f%02.0f%02d,%.1f,%s,%s,%s",
1437 NMEA_TID, ep[3], ep[4], ep[5], dms1[0], dms1[1] + dms1[2] / 60.0, pos[0] >= 0 ?
"N" :
"S", dms2[0],
1438 dms2[1] + dms2[2] / 60.0, pos[1] >= 0 ?
"E" :
"W", vel /
KNOT2M, dir, ep[2], ep[1], (
int)ep[0] % 100,
1439 amag, emag, mode, status);
1440 for (q = (
char*)buff + 1, sum = 0; *q; q++) {
1443 p += sprintf(p,
"*%02X\r\n", sum);
1444 return p - (
char*)buff;
1449 double h, ep[6], pos[3], dms1[3], dms2[3], dop = 1.0;
1450 int solq, refid = 0;
1451 char *p = (
char*)buff, *q, sum;
1453 trace(NULL, 3,
"outnmea_gga:\n");
1456 p += sprintf(p,
"$%sGGA,,,,,,,,,,,,,,",
NMEA_TID);
1457 for (q = (
char*)buff + 1, sum = 0; *q; q++) {
1460 p += sprintf(p,
"*%02X%c%c", sum, 0x0D, 0x0A);
1461 return p - (
char*)buff;
1463 for (solq = 0; solq < 8; solq++) {
1472 if (time.
sec >= 0.995) {
1482 "$%sGGA,%02.0f%02.0f%05.2f,%02.0f%010.7f,%s,%03.0f%010.7f,%s,"
1483 "%d,%02d,%.1f,%.3f,M,%.3f,M,%.1f,%04d",
1484 NMEA_TID, ep[3], ep[4], ep[5], dms1[0], dms1[1] + dms1[2] / 60.0, pos[0] >= 0 ?
"N" :
"S", dms2[0],
1485 dms2[1] + dms2[2] / 60.0, pos[1] >= 0 ?
"E" :
"W", solq, sol->
ns, dop, pos[2] - h, h, sol->
age, refid);
1486 for (q = (
char*)buff + 1, sum = 0; *q; q++) {
1489 p += sprintf(p,
"*%02X\r\n", sum);
1490 return p - (
char*)buff;
1494 double azel[
MAXSAT * 2], dop[4];
1495 char *p = (
char*)buff, *q, *s, sum;
1496 int i, j, sys, prn, nsat, mask = 0, nsys = 0, sats[
MAXSAT];
1498 trace(NULL, 3,
"outnmea_gsa:\n");
1500 for (i = nsat = 0; i <
MAXSAT; i++) {
1504 sys =
satsys(i + 1, NULL);
1505 if (!(sys & mask)) {
1509 azel[2 * nsat] = ssat[i].
azel[0];
1510 azel[2 * nsat + 1] = ssat[i].
azel[1];
1511 sats[nsat++] = i + 1;
1513 dops(nsat, azel, 0.0, dop);
1516 for (j = nsat = 0; j <
MAXSAT && nsat < 12; j++) {
1521 sats[nsat++] = j + 1;
1526 p += sprintf(p,
"$%sGSA,A,%d", nsys > 1 ?
"GN" :
nmea_tid[i], sol->
stat ? 3 : 1);
1527 for (j = 0; j < 12; j++) {
1528 sys =
satsys(sats[j], &prn);
1537 p += sprintf(p,
",%02d", prn);
1539 p += sprintf(p,
",");
1542 p += sprintf(p,
",%3.1f,%3.1f,%3.1f,%d", dop[1], dop[2], dop[3],
nmea_sid[i]);
1543 for (q = s + 1, sum = 0; *q; q++) {
1546 p += sprintf(p,
"*%02X\r\n", sum);
1549 return p - (
char*)buff;
1554 int i, j, k, n, nsat, nmsg, prn, sys, sats[
MAXSAT];
1555 char *p = (
char*)buff, *q, *s, sum;
1557 trace(NULL, 3,
"outnmea_gsv:\n");
1560 for (j = nsat = 0; j <
MAXSAT && nsat < 36; j++) {
1564 if (ssat[j].azel[1] > 0.0) {
1565 sats[nsat++] = j + 1;
1568 nmsg = (nsat + 3) / 4;
1570 for (j = n = 0; j < nmsg; j++) {
1572 p += sprintf(p,
"$%sGSV,%d,%d,%02d",
nmea_tid[i], nmsg, j + 1, nsat);
1573 for (k = 0; k < 4; k++, n++) {
1575 sys =
satsys(sats[n], &prn);
1583 az = ssat[sats[n] - 1].
azel[0] *
R2D;
1587 el = ssat[sats[n] - 1].
azel[1] *
R2D;
1589 p += sprintf(p,
",%02d,%02.0f,%03.0f,%02.0f", prn, el, az, snr);
1591 p += sprintf(p,
",,,,");
1594 p += sprintf(p,
",0");
1595 for (q = s + 1, sum = 0; *q; q++) {
1598 p += sprintf(p,
"*%02X\r\n", sum);
1601 return p - (
char*)buff;
1611 const char* s1[] = {
1612 "Single",
"DGPS",
"Kinematic",
"Static",
"Moving-Base",
"Fixed",
"PPP Kinematic",
"PPP Static",
1613 "PPP Fixed",
"",
"",
""};
1614 const char* s2[] = {
"L1",
"L1+2",
"L1+2+3",
"L1+2+3+4",
"L1+2+3+4+5",
"L1+2+3+4+5+6",
"",
"",
""};
1615 const char* s3[] = {
"Forward",
"Backward",
"Combined",
"",
"",
""};
1616 const char* s4[] = {
"OFF",
"Broadcast",
"SBAS",
"Iono-Free LC",
"Estimate TEC",
"IONEX TEC",
"QZSS Broadcast",
"",
1618 const char* s5[] = {
"OFF",
"Saastamoinen",
"SBAS",
"Estimate ZTD",
"Estimate ZTD+Grad",
"",
"",
""};
1619 const char* s6[] = {
"Broadcast",
"Precise",
"Broadcast+SBAS",
"Broadcast+SSR APC",
"Broadcast+SSR CoM",
"",
"",
""};
1620 const char* s7[] = {
"GPS",
"GLONASS",
"Galileo",
"QZSS",
"BDS",
"NavIC",
"SBAS",
"",
"",
""};
1621 const char* s8[] = {
"OFF",
"Continuous",
"Instantaneous",
"Fix and Hold",
"",
"",
""};
1623 char* p = (
char*)buff;
1625 trace(NULL, 3,
"outprcopts:\n");
1627 p += sprintf(p,
"%s pos mode : %s\r\n",
COMMENTH, s1[opt->
mode]);
1630 p += sprintf(p,
"%s freqs : %s\r\n",
COMMENTH, s2[opt->
nf - 1]);
1635 p += sprintf(p,
"%s elev mask : %.1f deg\r\n",
COMMENTH, opt->
elmin *
R2D);
1637 p += sprintf(p,
"%s dynamics : %s\r\n",
COMMENTH, opt->
dynamics ?
"on" :
"off");
1638 p += sprintf(p,
"%s tidecorr : %s\r\n",
COMMENTH, opt->
tidecorr ?
"on" :
"off");
1644 p += sprintf(p,
"%s ephemeris : %s\r\n",
COMMENTH, s6[opt->
sateph]);
1645 p += sprintf(p,
"%s navi sys :",
COMMENTH);
1646 for (i = 0; sys[i]; i++) {
1647 if (opt->
navsys & sys[i]) {
1648 p += sprintf(p,
" %s", s7[i]);
1651 p += sprintf(p,
"\r\n");
1652 p += sprintf(p,
"%s ar sys :",
COMMENTH);
1653 for (i = 0; sys[i]; i++) {
1654 if (opt->
arsys & sys[i]) {
1655 p += sprintf(p,
" %s", s7[i]);
1658 p += sprintf(p,
"\r\n");
1660 p += sprintf(p,
"%s amb res : %s\r\n",
COMMENTH, s8[opt->
modear]);
1662 p += sprintf(p,
"%s val thres : %.1f\r\n",
COMMENTH, opt->
thresar[0]);
1668 for (i = 0; i < 2; i++) {
1672 p += sprintf(p,
"%s antenna%d : %-21s (%7.4f %7.4f %7.4f)\r\n",
COMMENTH, i + 1, opt->
anttype[i],
1675 return p - (
char*)buff;
1684 const char *s1[] = {
"WGS84",
"Tokyo"}, *s2[] = {
"ellipsoidal",
"geodetic"};
1685 const char *s3[] = {
"GPST",
"UTC ",
"JST "}, *sep =
opt2sep(opt);
1686 const char* leg1 =
"Q=1:fix,2:float,3:sbas,4:dgps,5:single,6:ppp";
1687 const char* leg2 =
"ns=# of satellites";
1688 char* p = (
char*)buff;
1691 trace(NULL, 3,
"outsolheads:\n");
1699 p += sprintf(p,
"x/y/z-ecef=WGS84");
1701 p += sprintf(p,
"e/n/u-baseline=WGS84");
1703 p += sprintf(p,
"lat/lon/height=%s/%s", s1[opt->
datum], s2[opt->
height]);
1705 p += sprintf(p,
",%s,%s)\r\n", leg1, leg2);
1707 p += sprintf(p,
"%s %-*s%s",
COMMENTH, (opt->
timef ? 16 : 8) + timeu + 1, s3[opt->
times], sep);
1712 "%16s%s%16s%s%10s%s%3s%s%3s%s%8s%s%8s%s%8s%s%8s%s%8s%s"
1714 "latitude(d'\")", sep,
"longitude(d'\")", sep,
"height(m)", sep,
"Q", sep,
"ns", sep,
"sdn(m)",
1715 sep,
"sde(m)", sep,
"sdu(m)", sep,
"sdne(m)", sep,
"sdeu(m)", sep,
"sdue(m)", sep,
"age(s)",
1719 "%14s%s%14s%s%10s%s%3s%s%3s%s%8s%s%8s%s%8s%s%8s%s%8s%s"
1721 "latitude(deg)", sep,
"longitude(deg)", sep,
"height(m)", sep,
"Q", sep,
"ns", sep,
"sdn(m)",
1722 sep,
"sde(m)", sep,
"sdu(m)", sep,
"sdne(m)", sep,
"sdeu(m)", sep,
"sdun(m)", sep,
"age(s)",
1726 p += sprintf(p,
"%s%10s%s%10s%s%10s%s%9s%s%8s%s%8s%s%8s%s%8s%s%8s", sep,
"vn(m/s)", sep,
"ve(m/s)", sep,
1727 "vu(m/s)", sep,
"sdvn", sep,
"sdve", sep,
"sdvu", sep,
"sdvne", sep,
"sdveu", sep,
"sdvun");
1731 "%14s%s%14s%s%14s%s%3s%s%3s%s%8s%s%8s%s%8s%s%8s%s%8s%s%8s"
1733 "x-ecef(m)", sep,
"y-ecef(m)", sep,
"z-ecef(m)", sep,
"Q", sep,
"ns", sep,
"sdx(m)", sep,
"sdy(m)",
1734 sep,
"sdz(m)", sep,
"sdxy(m)", sep,
"sdyz(m)", sep,
"sdzx(m)", sep,
"age(s)", sep,
"ratio");
1737 p += sprintf(p,
"%s%10s%s%10s%s%10s%s%9s%s%8s%s%8s%s%8s%s%8s%s%8s", sep,
"vx(m/s)", sep,
"vy(m/s)", sep,
1738 "vz(m/s)", sep,
"sdvx", sep,
"sdvy", sep,
"sdvz", sep,
"sdvxy", sep,
"sdvyz", sep,
"sdvzx");
1742 "%14s%s%14s%s%14s%s%3s%s%3s%s%8s%s%8s%s%8s%s%8s%s%8s%s%8s"
1744 "e-baseline(m)", sep,
"n-baseline(m)", sep,
"u-baseline(m)", sep,
"Q", sep,
"ns", sep,
"sde(m)",
1745 sep,
"sdn(m)", sep,
"sdu(m)", sep,
"sden(m)", sep,
"sdnu(m)", sep,
"sdue(m)", sep,
"age(s)", sep,
1748 p += sprintf(p,
"\r\n");
1749 return p - (
char*)buff;
1754 if (sol->
qr[0] > sol->
qr[1] && sol->
qr[0] > sol->
qr[2]) {
1757 if (sol->
qr[1] > sol->
qr[2]) {
1774 const char* sep =
opt2sep(opt);
1778 trace(NULL, 3,
"outsols :\n");
1802 time =
timeadd(time, 9 * 3600.0);
1809 if (86400 * 7 - gpst < 0.5 / pow(10.0, timeu)) {
1813 sprintf(s,
"%4d%.16s%*.*f", week, sep, 6 + (timeu <= 0 ? 0 : timeu + 1), timeu, gpst);
1815 switch (opt->
posf) {
1817 p +=
outpos(p, s, sol, opt);
1823 p +=
outenu(p, s, sol, rb, opt);
1845 trace(NULL, 3,
"outsolexs:\n");
1875 trace(NULL, 3,
"outprcopt:\n");
1878 fwrite(buff, n, 1, fp);
1891 trace(NULL, 3,
"outsolhead:\n");
1894 fwrite(buff, n, 1, fp);
1909 trace(NULL, 3,
"outsol :\n");
1911 if ((n =
outsols(buff, sol, rb, opt)) > 0) {
1912 fwrite(buff, n, 1, fp);
1928 trace(NULL, 3,
"outsolex:\n");
1930 if ((n =
outsolexs(buff, sol, ssat, opt)) > 0) {
1931 fwrite(buff, n, 1, fp);
int satid2no(const char *id)
void pos2ecef(const double *pos, double *r)
Transform geodetic position to ECEF position.
void covenu(const double *pos, const double *P, double *Q)
Transform ECEF covariance to local tangential coordinate.
void dops(int ns, const double *azel, double elmin, double *dop)
Compute DOP (dilution of precision).
void ecef2pos(const double *r, double *pos)
Transform ECEF position to geodetic position.
void ecef2enu(const double *pos, const double *r, double *e)
Transform ECEF vector to local tangential coordinate.
MRTKLIB Coordinates Module — Coordinate transformations and geometry.
int satsys(int sat, int *prn)
double norm(const double *a, int n)
Euclidean norm of vector.
int screent(gtime_t time, gtime_t ts, gtime_t te, double tint)
Screen data by time range and interval.
const solopt_t solopt_default
void freesolstatbuf(solstatbuf_t *solstatbuf)
Free solution status buffer memory.
static int decode_solxyz(char *buff, const solopt_t *opt, sol_t *sol)
static int decode_nmearmc(char **val, int n, sol_t *sol)
static double sol_std(const sol_t *sol)
int outprcopts(uint8_t *buff, const prcopt_t *opt)
Output processing options to buffer.
static char * decode_soltime(char *buff, const solopt_t *opt, gtime_t *time)
int readsolstat(char *files[], int nfile, solstatbuf_t *statbuf)
Read solution status from files.
void freesolbuf(solbuf_t *solbuf)
Free solution buffer memory.
int inputsol(uint8_t data, gtime_t ts, gtime_t te, double tint, int qflag, const solopt_t *opt, solbuf_t *solbuf)
Input solution data from stream.
void enu2ecef(const double *pos, const double *e, double *r)
static void covtosol_vel(const double *P, sol_t *sol)
int outsols(uint8_t *buff, const sol_t *sol, const double *rb, const solopt_t *opt)
Output solution to buffer.
static int test_solstat(const char *buff)
static const char * opt2sep(const solopt_t *opt)
int addsol(solbuf_t *solbuf, const sol_t *sol)
Add solution to buffer.
static const int nmea_sid[]
int readsolstatt(char *files[], int nfile, gtime_t ts, gtime_t te, double tint, solstatbuf_t *statbuf)
Read solution status from files with time filter.
static int tonum(char *buff, const char *sep, double *v)
void outprcopt(FILE *fp, const prcopt_t *opt)
Output processing options to file.
int outnmea_gsv(uint8_t *buff, const sol_t *sol, const ssat_t *ssat)
Output NMEA GSV sentence.
static void septime(double t, double *t1, double *t2, double *t3)
static const int nmea_sys[]
static int readsolstatdata(FILE *fp, gtime_t ts, gtime_t te, double tint, solstatbuf_t *statbuf)
static double dmm2deg(double dmm)
void outsolex(FILE *fp, const sol_t *sol, const ssat_t *ssat, const solopt_t *opt)
Output solution extended data to file.
static int decode_nmea(char *buff, sol_t *sol)
static int decode_solenu(char *buff, const solopt_t *opt, sol_t *sol)
static double sqvar(double covar)
static int outpos(uint8_t *buff, const char *s, const sol_t *sol, const solopt_t *opt)
void covecef(const double *pos, const double *Q, double *P)
gtime_t gpst2time(int week, double sec)
void initsolbuf(solbuf_t *solbuf, int cyclic, int nmax)
Initialize solution buffer.
int outsolexs(uint8_t *buff, const sol_t *sol, const ssat_t *ssat, const solopt_t *opt)
Output solution extended data to buffer.
static const char * nmea_tid[]
static int decode_solpos(char *buff, const solopt_t *opt, sol_t *sol)
static int cmpsol(const void *p1, const void *p2)
static const int nmea_solq[]
static int cmpsolstat(const void *p1, const void *p2)
static int decode_nmeazda(char **val, int n, sol_t *sol)
static int decode_solgsi(char *buff, const solopt_t *opt, sol_t *sol)
static int readsoldata(FILE *fp, gtime_t ts, gtime_t te, double tint, int qflag, const solopt_t *opt, solbuf_t *solbuf)
static int outecef(uint8_t *buff, const char *s, const sol_t *sol, const solopt_t *opt)
static int sort_solstat(solstatbuf_t *statbuf)
static void readsolopt(FILE *fp, solopt_t *opt)
static int decode_solstat(char *buff, solstat_t *stat)
static int decode_solllh(char *buff, const solopt_t *opt, sol_t *sol)
static void covtosol(const double *P, sol_t *sol)
static void decode_solopt(char *buff, solopt_t *opt)
int outnmea_rmc(uint8_t *buff, const sol_t *sol)
Output NMEA RMC sentence.
void outsolhead(FILE *fp, const solopt_t *opt)
Output solution header to file.
static int decode_solsss(char *buff, sol_t *sol)
static int outenu(uint8_t *buff, const char *s, const sol_t *sol, const double *rb, const solopt_t *opt)
int outnmea_gga(uint8_t *buff, const sol_t *sol)
Output NMEA GGA sentence.
double norm(const double *a, int n)
int outnmea_gsa(uint8_t *buff, const sol_t *sol, const ssat_t *ssat)
Output NMEA GSA sentence.
void outsol(FILE *fp, const sol_t *sol, const double *rb, const solopt_t *opt)
Output solution to file.
static void decode_refpos(char *buff, const solopt_t *opt, double *rb)
int readsolt(char *files[], int nfile, gtime_t ts, gtime_t te, double tint, int qflag, solbuf_t *solbuf)
Read solutions from files with time filter.
void deg2dms(double deg, double *dms, int ndec)
static int decode_nmeagga(char **val, int n, sol_t *sol)
static int decode_sol(char *buff, const solopt_t *opt, sol_t *sol, double *rb)
static int test_nmea(const char *buff)
int outsolheads(uint8_t *buff, const solopt_t *opt)
Output solution header to buffer.
static void soltocov_vel(const sol_t *sol, double *P)
static void soltocov(const sol_t *sol, double *P)
sol_t * getsol(solbuf_t *solbuf, int index)
Get solution from buffer.
double geoidh(const double *pos)
static int sort_solbuf(solbuf_t *solbuf)
int readsol(char *files[], int nfile, solbuf_t *sol)
Read solutions from files.
static void addsolstat(solstatbuf_t *statbuf, const solstat_t *stat)
double dms2deg(const double *dms)
MRTKLIB Solution Module — Solution data types and I/O functions.
MRTKLIB System Module — OS/filesystem utility functions.
gtime_t epoch2time(const double *ep)
Convert calendar day/time to gtime_t struct.
void time2epoch(gtime_t t, double *ep)
Convert gtime_t struct to calendar day/time.
void time2str(gtime_t t, char *s, int n)
Convert gtime_t struct to string.
gtime_t gpst2utc(gtime_t t)
Convert GPS time to UTC considering leap seconds.
double timediff(gtime_t t1, gtime_t t2)
Compute time difference (t1 - t2).
double time2gpst(gtime_t t, int *week)
Convert gtime_t to GPS week/tow.
gtime_t timeadd(gtime_t t, double sec)
Add seconds to gtime_t.
char * time_str(gtime_t t, int n)
Get time string (not reentrant).
gtime_t utc2gpst(gtime_t t)
Convert UTC to GPS time considering leap seconds.
void trace(mrtk_ctx_t *ctx, int level, const char *format,...)
Output trace message.
MRTKLIB Trace Module — debug trace and logging functions.
GNSS time representation.
uint8_t buff[MAXSOLMSG+1]