MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_streamsvr.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_streamsvr.c : stream server functions
3 *
4 * Copyright (C) 2026 H.SHIONO (MRTKLIB Project)
5 * Copyright (C) 2010-2020 T.TAKASU
6 *
7 * SPDX-License-Identifier: BSD-2-Clause
8 *----------------------------------------------------------------------------*/
9/**
10 * @file mrtk_streamsvr.c
11 * @brief Stream server functions for data relay and format conversion.
12 *
13 * version : $Revision:$ $Date:$
14 * history : 2010/07/18 1.0 moved from stream.c
15 * 2011/01/18 1.1 change api strsvrstart()
16 * 2012/12/04 1.2 add stream conversion function
17 * 2012/12/25 1.3 fix bug on cyclic navigation data output
18 * suppress warnings
19 * 2013/05/08 1.4 fix bug on 1 s offset for javad -> rtcm conversion
20 * 2014/10/16 1.5 support input from stdout
21 * 2015/12/05 1.6 support rtcm 3 mt 63 beidou ephemeris
22 * 2016/07/23 1.7 change api strsvrstart(),strsvrstop()
23 * support command for output streams
24 * 2016/08/20 1.8 support api change of sendnmea()
25 * 2016/09/03 1.9 support ntrip caster function
26 * 2016/09/06 1.10 add api strsvrsetsrctbl()
27 * 2016/09/17 1.11 add relay back function of output stream
28 * fix bug on rtcm cyclic output of beidou ephemeris
29 * 2016/10/01 1.12 change api startstrserver()
30 * 2017/04/11 1.13 fix bug on search of next satellite in nextsat()
31 * 2018/11/05 1.14 update message type of beidou ephemeirs
32 * support multiple msm messages if nsat x nsig > 64
33 * 2020/11/30 1.15 support RTCM MT1131-1137,1041 (NavIC/IRNSS)
34 * add log paths in API strsvrstart()
35 * add log status in API strsvrstat()
36 * support multiple ephemeris sets (e.g. I/NAV-F/NAV)
37 * delete API strsvrsetsrctbl()
38 * use integer types in stdint.h
39 */
40#include "mrtklib/rtklib.h"
41
42/* test observation data message ---------------------------------------------*/
43static int is_obsmsg(int msg) {
44 return (1001 <= msg && msg <= 1004) || (1009 <= msg && msg <= 1012) || (1071 <= msg && msg <= 1077) ||
45 (1081 <= msg && msg <= 1087) || (1091 <= msg && msg <= 1097) || (1101 <= msg && msg <= 1107) ||
46 (1111 <= msg && msg <= 1117) || (1121 <= msg && msg <= 1127) || (1131 <= msg && msg <= 1137);
47}
48/* test navigation data message ----------------------------------------------*/
49static int is_navmsg(int msg) {
50 return msg == 1019 || msg == 1020 || msg == 1044 || msg == 1045 || msg == 1046 || msg == 1042 || msg == 63 ||
51 msg == 1041;
52}
53/* test station info message -------------------------------------------------*/
54static int is_stamsg(int msg) {
55 return msg == 1005 || msg == 1006 || msg == 1007 || msg == 1008 || msg == 1033 || msg == 1230;
56}
57/* test time interval --------------------------------------------------------*/
58static int is_tint(gtime_t time, double tint) {
59 if (tint <= 0.0) return 1;
60 return fmod(time2gpst(time, NULL) + DTTOL, tint) <= 2.0 * DTTOL;
61}
62/* new stream converter --------------------------------------------------------
63 * generate new stream converter
64 * args : int itype I input stream type (STRFMT_???)
65 * int otype I output stream type (STRFMT_???)
66 * char *msgs I output message type and interval (, separated)
67 * int staid I station id
68 * int stasel I station info selection (0:remote,1:local)
69 * char *opt I rtcm or receiver raw options
70 * return : stream generator (NULL:error)
71 *-----------------------------------------------------------------------------*/
72extern strconv_t* strconvnew(int itype, int otype, const char* msgs, int staid, int stasel, const char* opt) {
73 strconv_t* conv;
74 double tint;
75 char buff[1024], *p;
76 int msg;
77
78 /* zero-init is required by the rtcm_t.lclblk ownership contract */
79 if (!(conv = (strconv_t*)calloc(1, sizeof(strconv_t)))) return NULL;
80
81 conv->nmsg = 0;
82 if (!msgs || strlen(msgs) >= sizeof(buff)) {
83 free(conv);
84 return NULL;
85 }
86 snprintf(buff, sizeof(buff), "%s", msgs);
87 for (p = strtok(buff, ","); p; p = strtok(NULL, ",")) {
88 tint = 0.0;
89 if (sscanf(p, "%d(%lf)", &msg, &tint) < 1) continue;
90 conv->msgs[conv->nmsg] = msg;
91 conv->tint[conv->nmsg] = tint;
92 conv->tick[conv->nmsg] = tickget();
93 conv->ephsat[conv->nmsg++] = 0;
94 if (conv->nmsg >= 32) break;
95 }
96 if (conv->nmsg <= 0) {
97 free(conv);
98 return NULL;
99 }
100 conv->itype = itype;
101 conv->otype = otype;
102 conv->stasel = stasel;
103 if (!init_rtcm(&conv->rtcm) || !init_rtcm(&conv->out)) {
104 free(conv);
105 return NULL;
106 }
107 if (!init_raw(&conv->raw, itype)) {
108 free_rtcm(&conv->rtcm);
109 free_rtcm(&conv->out);
110 free(conv);
111 return NULL;
112 }
113 if (stasel) conv->out.staid = staid;
114 snprintf(conv->rtcm.opt, sizeof(conv->rtcm.opt), "-EPHALL %s", opt);
115 snprintf(conv->raw.opt, sizeof(conv->raw.opt), "-EPHALL %s", opt);
116 return conv;
117}
118/* free stream converter -------------------------------------------------------
119 * free stream converter
120 * args : strconv_t *conv IO stream converter
121 * return : none
122 *-----------------------------------------------------------------------------*/
123extern void strconvfree(strconv_t* conv) {
124 if (!conv) return;
125 free_rtcm(&conv->rtcm);
126 free_rtcm(&conv->out);
127 free_raw(&conv->raw);
128 free(conv);
129}
130/* copy received data from receiver raw to rtcm ------------------------------*/
131static void raw2rtcm(rtcm_t* out, const raw_t* raw, int ret) {
132 int i, sat, set, sys, prn;
133
134 out->time = raw->time;
135
136 if (ret == 1) {
137 for (i = 0; i < raw->obs.n; i++) {
138 out->time = raw->obs.data[i].time;
139 out->obs.data[i] = raw->obs.data[i];
140
141 sys = satsys(raw->obs.data[i].sat, &prn);
142 if (sys == SYS_GLO && raw->nav.glo_fcn[prn - 1]) {
143 out->nav.glo_fcn[prn - 1] = raw->nav.glo_fcn[prn - 1];
144 }
145 }
146 out->obs.n = raw->obs.n;
147 } else if (ret == 2) {
148 sat = raw->ephsat;
149 set = raw->ephset;
150 sys = satsys(sat, &prn);
151 if (sys == SYS_GLO) {
152 out->nav.geph[prn - 1] = raw->nav.geph[prn - 1];
153 out->ephsat = sat;
154 out->ephset = set;
155 } else if (sys == SYS_GPS || sys == SYS_GAL || sys == SYS_QZS || sys == SYS_CMP || sys == SYS_IRN) {
156 out->nav.eph[sat - 1 + MAXSAT * set] = raw->nav.eph[sat - 1 + MAXSAT * set];
157 out->ephsat = sat;
158 out->ephset = set;
159 }
160 } else if (ret == 5) {
161 out->sta = raw->sta;
162 } else if (ret == 9) {
163 matcpy(out->nav.utc_gps, raw->nav.utc_gps, 8, 1);
164 matcpy(out->nav.utc_glo, raw->nav.utc_glo, 8, 1);
165 matcpy(out->nav.utc_gal, raw->nav.utc_gal, 8, 1);
166 matcpy(out->nav.utc_qzs, raw->nav.utc_qzs, 8, 1);
167 matcpy(out->nav.utc_cmp, raw->nav.utc_cmp, 8, 1);
168 matcpy(out->nav.utc_irn, raw->nav.utc_irn, 9, 1);
169 matcpy(out->nav.utc_sbs, raw->nav.utc_sbs, 4, 1);
170 matcpy(out->nav.ion_gps, raw->nav.ion_gps, 8, 1);
171 matcpy(out->nav.ion_gal, raw->nav.ion_gal, 4, 1);
172 matcpy(out->nav.ion_qzs, raw->nav.ion_qzs, 8, 1);
173 matcpy(out->nav.ion_cmp, raw->nav.ion_cmp, 8, 1);
174 matcpy(out->nav.ion_irn, raw->nav.ion_irn, 8, 1);
175 }
176}
177/* copy received data from receiver rtcm to rtcm -----------------------------*/
178static void rtcm2rtcm(rtcm_t* out, const rtcm_t* rtcm, int ret, int stasel) {
179 int i, sat, set, sys, prn;
180
181 out->time = rtcm->time;
182
183 if (!stasel) out->staid = rtcm->staid;
184
185 if (ret == 1) {
186 for (i = 0; i < rtcm->obs.n; i++) {
187 out->obs.data[i] = rtcm->obs.data[i];
188
189 sys = satsys(rtcm->obs.data[i].sat, &prn);
190 if (sys == SYS_GLO && rtcm->nav.glo_fcn[prn - 1]) {
191 out->nav.glo_fcn[prn - 1] = rtcm->nav.glo_fcn[prn - 1];
192 }
193 }
194 out->obs.n = rtcm->obs.n;
195 } else if (ret == 2) {
196 sat = rtcm->ephsat;
197 set = rtcm->ephset;
198 sys = satsys(sat, &prn);
199 if (sys == SYS_GLO) {
200 out->nav.geph[prn - 1] = rtcm->nav.geph[prn - 1];
201 out->ephsat = sat;
202 out->ephset = set;
203 } else if (sys == SYS_GPS || sys == SYS_GAL || sys == SYS_QZS || sys == SYS_CMP || sys == SYS_IRN) {
204 out->nav.eph[sat - 1 + MAXSAT * set] = rtcm->nav.eph[sat - 1 + MAXSAT * set];
205 out->ephsat = sat;
206 out->ephset = set;
207 }
208 } else if (ret == 5) {
209 if (!stasel) out->sta = rtcm->sta;
210 }
211}
212/* write rtcm3 msm to stream -------------------------------------------------*/
213static void write_rtcm3_msm(stream_t* str, rtcm_t* out, int msg, int sync) {
214 obsd_t *data, buff[MAXOBS];
215 int i, j, n, ns, sys, nobs, code, nsat = 0, nsig = 0, nmsg, mask[MAXCODE] = {0};
216
217 if (1071 <= msg && msg <= 1077)
218 sys = SYS_GPS;
219 else if (1081 <= msg && msg <= 1087)
220 sys = SYS_GLO;
221 else if (1091 <= msg && msg <= 1097)
222 sys = SYS_GAL;
223 else if (1101 <= msg && msg <= 1107)
224 sys = SYS_SBS;
225 else if (1111 <= msg && msg <= 1117)
226 sys = SYS_QZS;
227 else if (1121 <= msg && msg <= 1127)
228 sys = SYS_CMP;
229 else if (1131 <= msg && msg <= 1137)
230 sys = SYS_IRN;
231 else
232 return;
233
234 data = out->obs.data;
235 nobs = out->obs.n;
236
237 /* count number of satellites and signals */
238 for (i = 0; i < nobs && i < MAXOBS; i++) {
239 if (satsys(data[i].sat, NULL) != sys) continue;
240 nsat++;
241 for (j = 0; j < NFREQ + NEXOBS; j++) {
242 if (!(code = data[i].code[j]) || mask[code - 1]) continue;
243 mask[code - 1] = 1;
244 nsig++;
245 }
246 }
247 if (nsig > 64) return;
248
249 /* pack data to multiple messages if nsat x nsig > 64 */
250 if (nsig > 0) {
251 ns = 64 / nsig; /* max number of sats in a message */
252 nmsg = (nsat - 1) / ns + 1; /* number of messages */
253 } else {
254 ns = 0;
255 nmsg = 1;
256 }
257 out->obs.data = buff;
258
259 for (i = j = 0; i < nmsg; i++) {
260 for (n = 0; n < ns && j < nobs && j < MAXOBS; j++) {
261 if (satsys(data[j].sat, NULL) != sys) continue;
262 out->obs.data[n++] = data[j];
263 }
264 out->obs.n = n;
265
266 if (gen_rtcm3(out, msg, 0, i < nmsg - 1 ? 1 : sync)) {
267 strwrite(str, out->buff, out->nbyte);
268 }
269 }
270 out->obs.data = data;
271 out->obs.n = nobs;
272}
273/* write obs data messages ---------------------------------------------------*/
274static void write_obs(gtime_t time, stream_t* str, strconv_t* conv) {
275 int i, j = 0;
276
277 for (i = 0; i < conv->nmsg; i++) {
278 if (!is_obsmsg(conv->msgs[i]) || !is_tint(time, conv->tint[i])) continue;
279
280 j = i; /* index of last message */
281 }
282 for (i = 0; i < conv->nmsg; i++) {
283 if (!is_obsmsg(conv->msgs[i]) || !is_tint(time, conv->tint[i])) continue;
284
285 /* generate messages */
286 if (conv->otype == STRFMT_RTCM2) {
287 if (!gen_rtcm2(&conv->out, conv->msgs[i], i != j)) continue;
288
289 /* write messages to stream */
290 strwrite(str, conv->out.buff, conv->out.nbyte);
291 } else if (conv->otype == STRFMT_RTCM3) {
292 if (conv->msgs[i] <= 1012) {
293 if (!gen_rtcm3(&conv->out, conv->msgs[i], 0, i != j)) continue;
294 strwrite(str, conv->out.buff, conv->out.nbyte);
295 } else { /* write rtcm3 msm to stream */
296 write_rtcm3_msm(str, &conv->out, conv->msgs[i], i != j);
297 }
298 }
299 }
300}
301/* write nav data messages ---------------------------------------------------*/
302static void write_nav(gtime_t time, stream_t* str, strconv_t* conv) {
303 int i;
304
305 for (i = 0; i < conv->nmsg; i++) {
306 if (!is_navmsg(conv->msgs[i]) || conv->tint[i] > 0.0) continue;
307
308 /* generate messages */
309 if (conv->otype == STRFMT_RTCM2) {
310 if (!gen_rtcm2(&conv->out, conv->msgs[i], 0)) continue;
311 } else if (conv->otype == STRFMT_RTCM3) {
312 if (!gen_rtcm3(&conv->out, conv->msgs[i], 0, 0)) continue;
313 } else
314 continue;
315
316 /* write messages to stream */
317 strwrite(str, conv->out.buff, conv->out.nbyte);
318 }
319}
320/* next ephemeris satellite --------------------------------------------------*/
321static int nextsat(nav_t* nav, int sat, int msg) {
322 int sys, set, p, p0, p1, p2;
323
324 switch (msg) {
325 case 1019:
326 sys = SYS_GPS;
327 set = 0;
328 p1 = MINPRNGPS;
329 p2 = MAXPRNGPS;
330 break;
331 case 1020:
332 sys = SYS_GLO;
333 set = 0;
334 p1 = MINPRNGLO;
335 p2 = MAXPRNGLO;
336 break;
337 case 1044:
338 sys = SYS_QZS;
339 set = 0;
340 p1 = MINPRNQZS;
341 p2 = MAXPRNQZS;
342 break;
343 case 1045:
344 sys = SYS_GAL;
345 set = 1;
346 p1 = MINPRNGAL;
347 p2 = MAXPRNGAL;
348 break;
349 case 1046:
350 sys = SYS_GAL;
351 set = 0;
352 p1 = MINPRNGAL;
353 p2 = MAXPRNGAL;
354 break;
355 case 63:
356 case 1042:
357 sys = SYS_CMP;
358 set = 0;
359 p1 = MINPRNCMP;
360 p2 = MAXPRNCMP;
361 break;
362 case 1041:
363 sys = SYS_IRN;
364 set = 0;
365 p1 = MINPRNIRN;
366 p2 = MAXPRNIRN;
367 break;
368 default:
369 return 0;
370 }
371 if (satsys(sat, &p0) != sys) return satno(sys, p1);
372
373 /* search next valid ephemeris */
374 for (p = p0 >= p2 ? p1 : p0 + 1; p != p0; p = p >= p2 ? p1 : p + 1) {
375 if (sys == SYS_GLO) {
376 sat = satno(sys, p);
377 if (nav->geph[p - 1].sat == sat) return sat;
378 } else {
379 sat = satno(sys, p);
380 if (nav->eph[sat - 1 + MAXSAT * set].sat == sat) return sat;
381 }
382 }
383 return 0;
384}
385/* write cyclic nav data messages --------------------------------------------*/
386static void write_nav_cycle(stream_t* str, strconv_t* conv) {
387 uint32_t tick = tickget();
388 int i, sat, tint;
389
390 for (i = 0; i < conv->nmsg; i++) {
391 if (!is_navmsg(conv->msgs[i]) || conv->tint[i] <= 0.0) continue;
392
393 /* output cycle */
394 tint = (int)(conv->tint[i] * 1000.0);
395 if ((int)(tick - conv->tick[i]) < tint) continue;
396 conv->tick[i] = tick;
397
398 /* next satellite */
399 if (!(sat = nextsat(&conv->out.nav, conv->ephsat[i], conv->msgs[i]))) {
400 continue;
401 }
402 conv->out.ephsat = conv->ephsat[i] = sat;
403
404 /* generate messages */
405 if (conv->otype == STRFMT_RTCM2) {
406 if (!gen_rtcm2(&conv->out, conv->msgs[i], 0)) continue;
407 } else if (conv->otype == STRFMT_RTCM3) {
408 if (!gen_rtcm3(&conv->out, conv->msgs[i], 0, 0)) continue;
409 } else
410 continue;
411
412 /* write messages to stream */
413 strwrite(str, conv->out.buff, conv->out.nbyte);
414 }
415}
416/* write cyclic station info messages ----------------------------------------*/
417static void write_sta_cycle(stream_t* str, strconv_t* conv) {
418 uint32_t tick = tickget();
419 int i, tint;
420
421 for (i = 0; i < conv->nmsg; i++) {
422 if (!is_stamsg(conv->msgs[i])) continue;
423
424 /* output cycle */
425 tint = conv->tint[i] == 0.0 ? 30000 : (int)(conv->tint[i] * 1000.0);
426 if ((int)(tick - conv->tick[i]) < tint) continue;
427 conv->tick[i] = tick;
428
429 /* generate messages */
430 if (conv->otype == STRFMT_RTCM2) {
431 if (!gen_rtcm2(&conv->out, conv->msgs[i], 0)) continue;
432 } else if (conv->otype == STRFMT_RTCM3) {
433 if (!gen_rtcm3(&conv->out, conv->msgs[i], 0, 0)) continue;
434 } else
435 continue;
436
437 /* write messages to stream */
438 strwrite(str, conv->out.buff, conv->out.nbyte);
439 }
440}
441/* convert stream ------------------------------------------------------------*/
442static void strconv(stream_t* str, strconv_t* conv, uint8_t* buff, int n) {
443 int i, ret;
444
445 for (i = 0; i < n; i++) {
446 /* input rtcm 2 messages */
447 if (conv->itype == STRFMT_RTCM2) {
448 ret = input_rtcm2(&conv->rtcm, buff[i]);
449 rtcm2rtcm(&conv->out, &conv->rtcm, ret, conv->stasel);
450 }
451 /* input rtcm 3 messages */
452 else if (conv->itype == STRFMT_RTCM3) {
453 ret = input_rtcm3(&conv->rtcm, buff[i]);
454 rtcm2rtcm(&conv->out, &conv->rtcm, ret, conv->stasel);
455 }
456 /* input receiver raw messages */
457 else {
458 ret = input_raw(&conv->raw, &conv->rtcm, conv->itype, buff[i]);
459 raw2rtcm(&conv->out, &conv->raw, ret);
460 }
461 /* write obs and nav data messages to stream */
462 switch (ret) {
463 case 1:
464 write_obs(conv->out.time, str, conv);
465 break;
466 case 2:
467 write_nav(conv->out.time, str, conv);
468 break;
469 }
470 }
471 /* write cyclic nav data and station info messages to stream */
472 write_nav_cycle(str, conv);
473 write_sta_cycle(str, conv);
474}
475/* periodic command ----------------------------------------------------------*/
476static void periodic_cmd(int cycle, const char* cmd, stream_t* stream) {
477 const char *p = cmd, *q;
478 char msg[1024], *r;
479 int n, period;
480
481 for (p = cmd;; p = q + 1) {
482 for (q = p;; q++)
483 if (*q == '\r' || *q == '\n' || *q == '\0') break;
484 n = (int)(q - p);
485 if (n >= (int)sizeof(msg)) {
486 n = (int)sizeof(msg) - 1;
487 }
488 strncpy(msg, p, n);
489 msg[n] = '\0';
490
491 period = 0;
492 if ((r = strrchr(msg, '#'))) {
493 sscanf(r, "# %d", &period);
494 *r = '\0';
495 /* delete tail spaces safely without underflowing msg buffer */
496 while (r > msg && *(r - 1) == ' ') {
497 --r;
498 *r = '\0';
499 }
500 }
501 if (period <= 0) period = 1000;
502 if (*msg && cycle % period == 0) {
503 strsendcmd(stream, msg);
504 }
505 if (!*q) break;
506 }
507}
508/* stream server thread ------------------------------------------------------*/
509static void* strsvrthread(void* arg) {
510 strsvr_t* svr = (strsvr_t*)arg;
511 sol_t sol_nmea = {{0}};
512 uint32_t tick, tick_nmea;
513 uint8_t buff[1024];
514 int i, n, cyc;
515
516 tracet(NULL, 3, "strsvrthread:\n");
517
518 svr->tick = tickget();
519 tick_nmea = svr->tick - 1000;
520
521 for (cyc = 0; svr->state; cyc++) {
522 tick = tickget();
523
524 /* read data from input stream */
525 while ((n = strread(svr->stream, svr->buff, svr->buffsize)) > 0 && svr->state) {
526 /* write data to output streams */
527 for (i = 1; i < svr->nstr; i++) {
528 if (svr->conv[i - 1]) {
529 strconv(svr->stream + i, svr->conv[i - 1], svr->buff, n);
530 } else {
531 strwrite(svr->stream + i, svr->buff, n);
532 }
533 }
534 /* write data to log stream */
535 strwrite(svr->strlog, svr->buff, n);
536
537 rtk_lock(&svr->lock);
538 for (i = 0; i < n && svr->npb < svr->buffsize; i++) {
539 svr->pbuf[svr->npb++] = svr->buff[i];
540 }
541 rtk_unlock(&svr->lock);
542 }
543 for (i = 1; i < svr->nstr; i++) {
544 /* read message from output stream */
545 while ((n = strread(svr->stream + i, buff, sizeof(buff))) > 0) {
546 /* relay back message from output stream to input stream */
547 if (i == svr->relayback) {
548 strwrite(svr->stream, buff, n);
549 }
550 /* write data to log stream */
551 strwrite(svr->strlog + i, buff, n);
552 }
553 }
554 /* write periodic command to input stream */
555 for (i = 0; i < svr->nstr; i++) {
556 periodic_cmd(cyc * svr->cycle, svr->cmds_periodic[i], svr->stream + i);
557 }
558 /* write nmea messages to input stream */
559 if (svr->nmeacycle > 0 && (int)(tick - tick_nmea) >= svr->nmeacycle) {
560 sol_nmea.stat = SOLQ_SINGLE;
561 sol_nmea.time = utc2gpst(timeget());
562 matcpy(sol_nmea.rr, svr->nmeapos, 3, 1);
563 strsendnmea(svr->stream, &sol_nmea);
564 tick_nmea = tick;
565 }
566 sleepms(svr->cycle - (int)(tickget() - tick));
567 }
568 for (i = 0; i < svr->nstr; i++) strclose(svr->stream + i);
569 for (i = 0; i < svr->nstr; i++) strclose(svr->strlog + i);
570 svr->npb = 0;
571 free(svr->buff);
572 svr->buff = NULL;
573 free(svr->pbuf);
574 svr->pbuf = NULL;
575
576 return 0;
577}
578/* initialize stream server ----------------------------------------------------
579 * initialize stream server
580 * args : strsvr_t *svr IO stream sever struct
581 * int nout I number of output streams
582 * return : none
583 *-----------------------------------------------------------------------------*/
584extern void strsvrinit(strsvr_t* svr, int nout) {
585 int i;
586
587 tracet(NULL, 3, "strsvrinit: nout=%d\n", nout);
588
589 svr->state = 0;
590 svr->cycle = 0;
591 svr->buffsize = 0;
592 svr->nmeacycle = 0;
593 svr->relayback = 0;
594 svr->npb = 0;
595 for (i = 0; i < 16; i++) *svr->cmds_periodic[i] = '\0';
596 for (i = 0; i < 3; i++) svr->nmeapos[i] = 0.0;
597 svr->buff = svr->pbuf = NULL;
598 svr->tick = 0;
599 for (i = 0; i < nout + 1 && i < 16; i++) strinit(svr->stream + i);
600 for (i = 0; i < nout + 1 && i < 16; i++) strinit(svr->strlog + i);
601 svr->nstr = i;
602 for (i = 0; i < 16; i++) svr->conv[i] = NULL;
603 svr->thread = 0;
604 rtk_initlock(&svr->lock);
605}
606/* start stream server ---------------------------------------------------------
607 * start stream server
608 * args : strsvr_t *svr IO stream sever struct
609 * int *opts I stream options
610 * opts[0]= inactive timeout (ms)
611 * opts[1]= interval to reconnect (ms)
612 * opts[2]= averaging time of data rate (ms)
613 * opts[3]= receive/send buffer size (bytes);
614 * opts[4]= server cycle (ms)
615 * opts[5]= nmea request cycle (ms) (0:no)
616 * opts[6]= file swap margin (s)
617 * opts[7]= relay back of output stream (0:no)
618 * int *strs I stream types (STR_???)
619 * strs[0]= input stream
620 * strs[1]= output stream 1
621 * strs[2]= output stream 2
622 * strs[3]= output stream 3
623 * ...
624 * char **paths I stream paths
625 * paths[0]= input stream
626 * paths[1]= output stream 1
627 * paths[2]= output stream 2
628 * paths[3]= output stream 3
629 * ...
630 * char **logs I log paths
631 * logs[0]= input log path
632 * logs[1]= output stream 1 return log path
633 * logs[2]= output stream 2 retrun log path
634 * logs[3]= output stream 2 retrun log path
635 * ...
636 * strconv_t **conv I stream converter
637 * conv[0]= output stream 1 converter
638 * conv[1]= output stream 2 converter
639 * conv[2]= output stream 3 converter
640 * ...
641 * char **cmds I start/stop commands (NULL: no cmd)
642 * cmds[0]= input stream command
643 * cmds[1]= output stream 1 command
644 * cmds[2]= output stream 2 command
645 * cmds[3]= output stream 3 command
646 * ...
647 * char **cmds_periodic I periodic commands (NULL: no cmd)
648 * cmds[0]= input stream command
649 * cmds[1]= output stream 1 command
650 * cmds[2]= output stream 2 command
651 * cmds[3]= output stream 3 command
652 * ...
653 * double *nmeapos I nmea request position (ecef) (m) (NULL: no)
654 * return : status (0:error,1:ok)
655 *-----------------------------------------------------------------------------*/
656extern int strsvrstart(strsvr_t* svr, int* opts, int* strs, char** paths, char** logs, strconv_t** conv, char** cmds,
657 char** cmds_periodic, const double* nmeapos) {
658 int i, rw, stropt[5] = {0};
659 char file1[MAXSTRPATH], file2[MAXSTRPATH], *p;
660
661 tracet(NULL, 3, "strsvrstart:\n");
662
663 if (svr->state) return 0;
664
665 strinitcom();
666
667 for (i = 0; i < 4; i++) stropt[i] = opts[i];
668 stropt[4] = opts[6];
669 strsetopt(stropt);
670 svr->cycle = opts[4];
671 svr->buffsize = opts[3] < 4096 ? 4096 : opts[3]; /* >=4096byte */
672 svr->nmeacycle = 0 < opts[5] && opts[5] < 1000 ? 1000 : opts[5]; /* >=1s */
673 svr->relayback = opts[7];
674 for (i = 0; i < 3; i++) svr->nmeapos[i] = nmeapos ? nmeapos[i] : 0.0;
675 for (i = 0; i < svr->nstr; i++) {
676 strcpy(svr->cmds_periodic[i], !cmds_periodic[i] ? "" : cmds_periodic[i]);
677 }
678 for (i = 0; i < svr->nstr - 1; i++) svr->conv[i] = conv[i];
679
680 if (!(svr->buff = (uint8_t*)malloc(svr->buffsize)) || !(svr->pbuf = (uint8_t*)malloc(svr->buffsize))) {
681 free(svr->buff);
682 free(svr->pbuf);
683 return 0;
684 }
685 /* open streams */
686 for (i = 0; i < svr->nstr; i++) {
687 strcpy(file1, paths[0]);
688 if ((p = strstr(file1, "::"))) *p = '\0';
689 strcpy(file2, paths[i]);
690 if ((p = strstr(file2, "::"))) *p = '\0';
691 if (i > 0 && *file1 && !strcmp(file1, file2)) {
692 sprintf(svr->stream[i].msg, "output path error: %-512.512s", file2);
693 for (i--; i >= 0; i--) strclose(svr->stream + i);
694 return 0;
695 }
696 if (strs[i] == STR_FILE) {
697 rw = i == 0 ? STR_MODE_R : STR_MODE_W;
698 } else {
699 rw = STR_MODE_RW;
700 }
701 if (stropen(svr->stream + i, strs[i], rw, paths[i])) continue;
702 for (i--; i >= 0; i--) strclose(svr->stream + i);
703 return 0;
704 }
705 /* open log streams */
706 for (i = 0; i < svr->nstr; i++) {
707 if (strs[i] == STR_NONE || strs[i] == STR_FILE || !*logs[i]) continue;
708 stropen(svr->strlog + i, STR_FILE, STR_MODE_W, logs[i]);
709 }
710 /* write start commands to input/output streams */
711 for (i = 0; i < svr->nstr; i++) {
712 if (!cmds[i]) continue;
713 strwrite(svr->stream + i, (uint8_t*)"", 0); /* for connect */
714 sleepms(100);
715 strsendcmd(svr->stream + i, cmds[i]);
716 }
717 svr->state = 1;
718
719 /* create stream server thread */
720 if (pthread_create(&svr->thread, NULL, strsvrthread, svr)) {
721 for (i = 0; i < svr->nstr; i++) strclose(svr->stream + i);
722 svr->state = 0;
723 return 0;
724 }
725 return 1;
726}
727/* stop stream server ----------------------------------------------------------
728 * start stream server
729 * args : strsvr_t *svr IO stream server struct
730 * char **cmds I stop commands (NULL: no cmd)
731 * cmds[0]= input stream command
732 * cmds[1]= output stream 1 command
733 * cmds[2]= output stream 2 command
734 * cmds[3]= output stream 3 command
735 * ...
736 * return : none
737 *-----------------------------------------------------------------------------*/
738extern void strsvrstop(strsvr_t* svr, char** cmds) {
739 int i;
740
741 tracet(NULL, 3, "strsvrstop:\n");
742
743 for (i = 0; i < svr->nstr; i++) {
744 if (cmds[i]) strsendcmd(svr->stream + i, cmds[i]);
745 }
746 svr->state = 0;
747
748 pthread_join(svr->thread, NULL);
749}
750/* get stream server status ----------------------------------------------------
751 * get status of stream server
752 * args : strsvr_t *svr IO stream sever struct
753 * int *stat O stream status
754 * int *log_stat O log status
755 * uint64_t *byte O bytes received/sent
756 * int *bps O bitrate received/sent
757 * char *msg O messages
758 * return : none
759 *-----------------------------------------------------------------------------*/
760extern void strsvrstat(strsvr_t* svr, int* stat, int* log_stat, uint64_t* byte, int* bps, char* msg) {
761 char s[MAXSTRMSG] = "", *p = msg;
762 int i, bps_in;
763
764 tracet(NULL, 4, "strsvrstat:\n");
765
766 for (i = 0; i < svr->nstr; i++) {
767 if (i == 0) {
768 strsum(svr->stream, byte, bps, NULL, NULL);
769 } else {
770 strsum(svr->stream + i, NULL, &bps_in, byte + i, bps + i);
771 }
772 stat[i] = strstat(svr->stream + i, s);
773 if (*s) p += sprintf(p, "(%d) %s ", i, s);
774 log_stat[i] = strstat(svr->strlog + i, s);
775 }
776}
777/* peek input/output stream ----------------------------------------------------
778 * peek input/output stream of stream server
779 * args : strsvr_t *svr IO stream sever struct
780 * uint8_t *buff O stream buff
781 * int nmax I buffer size (bytes)
782 * return : stream size (bytes)
783 *-----------------------------------------------------------------------------*/
784extern int strsvrpeek(strsvr_t* svr, uint8_t* buff, int nmax) {
785 int n;
786
787 if (!svr->state) return 0;
788
789 rtk_lock(&svr->lock);
790 n = svr->npb < nmax ? svr->npb : nmax;
791 if (n > 0) {
792 memcpy(buff, svr->pbuf, n);
793 }
794 if (n < svr->npb) {
795 memmove(svr->pbuf, svr->pbuf + n, svr->npb - n);
796 }
797 svr->npb -= n;
798 rtk_unlock(&svr->lock);
799 return n;
800}
#define MAXSAT
Definition mrtk_coords.c:45
int satsys(int sat, int *prn)
Definition mrtk_nav.c:117
#define SYS_GPS
Definition mrtk_eph.c:65
#define SYS_SBS
Definition mrtk_eph.c:66
#define SYS_QZS
Definition mrtk_eph.c:69
#define SYS_IRN
Definition mrtk_eph.c:71
#define SYS_CMP
Definition mrtk_eph.c:70
#define SYS_GAL
Definition mrtk_eph.c:68
#define SYS_GLO
Definition mrtk_eph.c:67
struct nav_s nav_t
Definition mrtk_eph.h:40
#define MAXSTRPATH
#define MINPRNIRN
#define MINPRNCMP
#define MAXOBS
#define MINPRNQZS
#define MAXCODE
#define MAXPRNQZS
#define rtk_unlock(f)
#define DTTOL
#define MAXPRNIRN
#define rtk_initlock(f)
#define MAXPRNGAL
#define MAXSTRMSG
#define MINPRNGAL
#define MINPRNGLO
#define rtk_lock(f)
#define MAXPRNCMP
#define MAXPRNGLO
int strwrite(struct stream_tag *stream, uint8_t *buff, int n)
void matcpy(double *A, const double *B, int n, int m)
Copy matrix.
Definition mrtk_mat.c:205
int satno(int sys, int prn)
Convert satellite system+prn/slot number to satellite number.
Definition mrtk_nav.c:58
#define SOLQ_SINGLE
Definition mrtk_opt.h:75
static rtcm_t * rtcm
#define MINPRNGPS
#define MAXPRNGPS
void free_raw(raw_t *raw)
Free receiver raw data control struct.
int input_raw(raw_t *raw, rtcm_t *rtcm, int format, uint8_t data)
Input receiver raw data from stream (byte-by-byte).
int init_raw(raw_t *raw, int format)
Initialize receiver raw data control struct.
#define STRFMT_RTCM3
Definition mrtk_rcvraw.h:50
#define STRFMT_RTCM2
Definition mrtk_rcvraw.h:49
int gen_rtcm2(rtcm_t *rtcm, int type, int sync)
Generate RTCM 2 message.
Definition mrtk_rtcm.c:369
void free_rtcm(rtcm_t *rtcm)
Free RTCM control struct.
Definition mrtk_rtcm.c:118
int init_rtcm(rtcm_t *rtcm)
Initialize RTCM control struct.
Definition mrtk_rtcm.c:37
int gen_rtcm3(rtcm_t *rtcm, int type, int subtype, int sync)
Generate RTCM 3 message.
Definition mrtk_rtcm.c:392
int input_rtcm2(rtcm_t *rtcm, uint8_t data)
Input RTCM 2 message from stream (byte-by-byte).
Definition mrtk_rtcm.c:159
int input_rtcm3(rtcm_t *rtcm, uint8_t data)
Input RTCM 3 message from stream (byte-by-byte).
Definition mrtk_rtcm.c:289
void strinit(stream_t *stream)
Initialize stream structure.
int strstat(stream_t *stream, char *msg)
Get stream status.
int strread(stream_t *stream, uint8_t *buff, int n)
Read data from stream.
void strsendnmea(stream_t *stream, const sol_t *sol)
Send NMEA request to stream.
void strsetopt(const int *opt)
Set stream options.
void strinitcom(void)
Initialize stream communication system.
void strclose(stream_t *stream)
Close stream.
int stropen(stream_t *stream, int type, int mode, const char *path)
Open stream.
void strsum(stream_t *stream, uint64_t *inb, int *inr, uint64_t *outb, int *outr)
Get stream statistics summary.
void strsendcmd(stream_t *str, const char *cmd)
Send receiver command to stream.
#define STR_FILE
Definition mrtk_stream.h:45
#define STR_MODE_W
Definition mrtk_stream.h:60
#define STR_MODE_R
Definition mrtk_stream.h:59
#define STR_MODE_RW
Definition mrtk_stream.h:61
struct stream_tag stream_t
#define STR_NONE
Definition mrtk_stream.h:43
static int nextsat(nav_t *nav, int sat, int msg)
void strsvrinit(strsvr_t *svr, int nout)
static void write_rtcm3_msm(stream_t *str, rtcm_t *out, int msg, int sync)
static void write_obs(gtime_t time, stream_t *str, strconv_t *conv)
static int is_navmsg(int msg)
static void * strsvrthread(void *arg)
void strsvrstat(strsvr_t *svr, int *stat, int *log_stat, uint64_t *byte, int *bps, char *msg)
Get stream server status.
static int is_obsmsg(int msg)
static void rtcm2rtcm(rtcm_t *out, const rtcm_t *rtcm, int ret, int stasel)
static void write_nav_cycle(stream_t *str, strconv_t *conv)
void strsvrstop(strsvr_t *svr, char **cmds)
strconv_t * strconvnew(int itype, int otype, const char *msgs, int staid, int stasel, const char *opt)
static void periodic_cmd(int cycle, const char *cmd, stream_t *stream)
static void strconv(stream_t *str, strconv_t *conv, uint8_t *buff, int n)
int strsvrstart(strsvr_t *svr, int *opts, int *strs, char **paths, char **logs, strconv_t **conv, char **cmds, char **cmds_periodic, const double *nmeapos)
static void write_nav(gtime_t time, stream_t *str, strconv_t *conv)
void strconvfree(strconv_t *conv)
static void write_sta_cycle(stream_t *str, strconv_t *conv)
static int is_tint(gtime_t time, double tint)
static void raw2rtcm(rtcm_t *out, const raw_t *raw, int ret)
static int is_stamsg(int msg)
int strsvrpeek(strsvr_t *svr, uint8_t *buff, int nmax)
void sleepms(int ms)
Sleep for specified milliseconds.
Definition mrtk_time.c:588
double time2gpst(gtime_t t, int *week)
Convert gtime_t to GPS week/tow.
Definition mrtk_time.c:181
gtime_t utc2gpst(gtime_t t)
Convert UTC to GPS time considering leap seconds.
Definition mrtk_time.c:440
gtime_t timeget(void)
Get current time in UTC.
Definition mrtk_time.c:289
uint32_t tickget(void)
Get current tick in milliseconds.
Definition mrtk_time.c:566
void tracet(mrtk_ctx_t *ctx, int level, const char *format,...)
Output trace message with elapsed time.
Definition mrtk_trace.c:91
int sat
Definition mrtk_eph.h:78
int sat
Definition mrtk_eph.h:112
GNSS time representation.
Definition mrtk_time.h:49
int glo_fcn[32]
Definition mrtk_nav.h:426
double utc_glo[8]
Definition mrtk_nav.h:415
double utc_qzs[8]
Definition mrtk_nav.h:417
double ion_irn[8]
Definition mrtk_nav.h:425
double utc_gal[8]
Definition mrtk_nav.h:416
double utc_gps[8]
Definition mrtk_nav.h:414
geph_t * geph
Definition mrtk_nav.h:407
double utc_cmp[8]
Definition mrtk_nav.h:418
double utc_sbs[4]
Definition mrtk_nav.h:420
double ion_cmp[8]
Definition mrtk_nav.h:424
double ion_gal[4]
Definition mrtk_nav.h:422
double utc_irn[9]
Definition mrtk_nav.h:419
eph_t * eph
Definition mrtk_nav.h:400
double ion_gps[8]
Definition mrtk_nav.h:421
double ion_qzs[8]
Definition mrtk_nav.h:423
obsd_t * data
Definition mrtk_obs.h:61
int n
Definition mrtk_obs.h:60
Observation data record.
Definition mrtk_obs.h:44
gtime_t time
Definition mrtk_obs.h:45
uint8_t sat
Definition mrtk_obs.h:46
Receiver raw data control type.
Definition mrtk_rcvraw.h:78
nav_t nav
Definition mrtk_rcvraw.h:83
int ephset
Definition mrtk_rcvraw.h:86
obs_t obs
Definition mrtk_rcvraw.h:81
char opt[256]
sta_t sta
Definition mrtk_rcvraw.h:84
int ephsat
Definition mrtk_rcvraw.h:85
gtime_t time
Definition mrtk_rcvraw.h:79
RTCM control struct type.
Definition mrtk_rtcm.h:50
obs_t obs
Definition mrtk_rtcm.h:57
gtime_t time
Definition mrtk_rtcm.h:55
nav_t nav
Definition mrtk_rtcm.h:58
uint8_t buff[1200]
Definition mrtk_rtcm.h:75
int staid
Definition mrtk_rtcm.h:51
int ephset
Definition mrtk_rtcm.h:67
char opt[256]
Definition mrtk_rtcm.h:79
int ephsat
Definition mrtk_rtcm.h:66
sta_t sta
Definition mrtk_rtcm.h:59
int nbyte
Definition mrtk_rtcm.h:72
double rr[6]
Definition mrtk_sol.h:46
uint8_t stat
Definition mrtk_sol.h:54
gtime_t time
Definition mrtk_sol.h:45
uint32_t tick[32]
Definition mrtk_stream.h:92
int ephsat[32]
Definition mrtk_stream.h:93
int msgs[32]
Definition mrtk_stream.h:90
double tint[32]
Definition mrtk_stream.h:91
rtcm_t rtcm
Definition mrtk_stream.h:95
rtcm_t out
Definition mrtk_stream.h:97
raw_t raw
Definition mrtk_stream.h:96
char msg[MAXSTRMSG]
Definition mrtk_stream.h:84
double nmeapos[3]
strconv_t * conv[16]
uint32_t tick
stream_t stream[16]
rtk_thread_t thread
stream_t strlog[16]
uint8_t * pbuf
int relayback
char cmds_periodic[16][MAXRCVCMD]
uint8_t * buff
int nmeacycle
rtk_lock_t lock
#define malloc(x)
Definition toml.c:52
#define calloc(x, y)
Definition toml.c:54
#define free(x)
Definition toml.c:53