1 /*
2 * SiRF object for the GPS packet monitor.
3 *
4 * This file is Copyright (c) 2010-2018 by the GPSD project
5 * SPDX-License-Identifier: BSD-2-clause
6 *
7 */
8
9 #include "gpsd_config.h" /* must be before all includes */
10
11 #include <stdlib.h>
12 #include <stdbool.h>
13 #include <string.h>
14 #include <math.h>
15 #include <stdlib.h> /* for labs() */
16 #include <assert.h>
17 #include <time.h>
18 #include <sys/time.h>
19
20 #include "gpsd.h"
21 #include "bits.h"
22 #include "gpsmon.h"
23 #include "strfuncs.h"
24
25 #if defined(SIRF_ENABLE) && defined(BINARY_ENABLE)
26 extern const struct gps_type_t driver_sirf;
27
28 static WINDOW *mid2win, *mid4win, *mid6win, *mid7win, *mid9win, *mid13win;
29 static WINDOW *mid19win, *mid27win;
30 static bool dispmode = false, subframe_enabled = false, ppstime_enabled = false;
31 static int leapseconds;
32
33 static char *verbpat[] = {
34 "#Time:",
35 "@R Time:",
36 "CSTD: New almanac for",
37 "NOTICE: DOP Q Boost",
38 "RTC not set",
39 "numOfSVs = 0",
40 "rtcaj tow ",
41 NULL
42 };
43
44
45 static char *dgpsvec[] = {
46 "None",
47 "SBAS",
48 "Serial",
49 "Beacon",
50 "Software",
51 };
52
53 /* check range of an unsigned quantity */
54 #define CHECK_RANGE(vec, i) ((i) < sizeof(vec)/sizeof(vec[0]))
55
56 /*****************************************************************************
57 *
58 * SiRF packet-decoding routines
59 *
60 *****************************************************************************/
61
62 #define display (void)mvwprintw
63
64 #define SIRF_CHANNELS 12 /* max channels allowed in SiRF format */
65
sirf_initialize(void)66 static bool sirf_initialize(void)
67 {
68 unsigned int i;
69
70 mid2win = subwin(devicewin, 6, 80, 1, 0);
71 mid4win = subwin(devicewin, SIRF_CHANNELS + 3, 30, 7, 0);
72 mid6win = subwin(devicewin, 3, 50, 7, 30);
73 mid7win = subwin(devicewin, 4, 50, 13, 30);
74 mid9win = subwin(devicewin, 3, 50, 10, 30);
75 mid13win = subwin(devicewin, 3, 50, 17, 30);
76 mid19win = newwin(16, 50, 7, 30);
77 mid27win = subwin(devicewin, 3, 50, 20, 30);
78 if (mid2win == NULL || mid4win == NULL || mid6win == NULL
79 || mid9win == NULL || mid13win == NULL || mid19win == NULL
80 || mid27win == NULL)
81 return false;
82
83 (void)syncok(mid2win, true);
84 (void)syncok(mid4win, true);
85 (void)syncok(mid6win, true);
86 (void)syncok(mid7win, true);
87 (void)syncok(mid9win, true);
88 (void)syncok(mid13win, true);
89 (void)syncok(mid27win, true);
90
91 (void)wborder(mid2win, 0, 0, 0, 0, 0, 0, 0, 0),
92 (void)wattrset(mid2win, A_BOLD);
93 (void)wmove(mid2win, 0, 1);
94 display(mid2win, 0, 12, " X ");
95 display(mid2win, 0, 21, " Y ");
96 display(mid2win, 0, 30, " Z ");
97 display(mid2win, 0, 43, " North ");
98 display(mid2win, 0, 54, " East ");
99 display(mid2win, 0, 65, " Alt ");
100
101 (void)wmove(mid2win, 1, 1);
102 (void)wprintw(mid2win,
103 "Pos: m m");
104 (void)wmove(mid2win, 2, 1);
105 (void)wprintw(mid2win,
106 "Vel: m/s climb m/s");
107 (void)wmove(mid2win, 3, 1);
108 (void)wprintw(mid2win,
109 "Time: Leap: Heading: speed m/s");
110 (void)wmove(mid2win, 4, 1);
111 (void)wprintw(mid2win,
112 "Fix: HDOP: M1: M2: ");
113 display(mid2win, 5, 24, " Packet type 2 (0x02) ");
114 (void)wattrset(mid2win, A_NORMAL);
115
116 (void)wborder(mid4win, 0, 0, 0, 0, 0, 0, 0, 0),
117 (void)wattrset(mid4win, A_BOLD);
118 display(mid4win, 1, 1, "Ch PRN Az El Stat C/N ? SF");
119 for (i = 0; i < SIRF_CHANNELS; i++) {
120 display(mid4win, (int)(i + 2), 1, "%2d", i);
121 }
122 display(mid4win, 0, 1, " Measured Tracker ");
123 display(mid4win, 14, 4, " Packet Type 4 (0x04) ");
124 (void)wattrset(mid4win, A_NORMAL);
125
126 (void)wborder(mid19win, 0, 0, 0, 0, 0, 0, 0, 0),
127 (void)wattrset(mid19win, A_BOLD);
128 display(mid19win, 1, 1, "Alt. hold mode:");
129 display(mid19win, 2, 1, "Alt. hold source:");
130 display(mid19win, 3, 1, "Alt. source input:");
131 display(mid19win, 4, 1, "Degraded timeout:");
132 display(mid19win, 5, 1, "DR timeout:");
133 display(mid19win, 6, 1, "Track smooth mode:");
134 display(mid19win, 7, 1, "Static Navigation:");
135 display(mid19win, 8, 1, "3SV Least Squares:");
136 display(mid19win, 9, 1, "DOP Mask mode:");
137 display(mid19win, 10, 1, "Nav. Elev. mask:");
138 display(mid19win, 11, 1, "Nav. Power mask:");
139 display(mid19win, 12, 1, "DGPS Source:");
140 display(mid19win, 13, 1, "DGPS Mode:");
141 display(mid19win, 14, 1, "DGPS Timeout:");
142 display(mid19win, 1, 26, "LP Push-to-Fix:");
143 display(mid19win, 2, 26, "LP On Time:");
144 display(mid19win, 3, 26, "LP Interval:");
145 display(mid19win, 4, 26, "U. Tasks Enab.:");
146 display(mid19win, 5, 26, "U. Task Inter.:");
147 display(mid19win, 6, 26, "LP Pwr Cyc En:");
148 display(mid19win, 7, 26, "LP Max Acq Srch:");
149 display(mid19win, 8, 26, "LP Max Off Time:");
150 display(mid19win, 9, 26, "APM enabled:");
151 display(mid19win, 10, 26, "# of Fixes:");
152 display(mid19win, 11, 26, "Time btw Fixes:");
153 display(mid19win, 12, 26, "H/V Error Max:");
154 display(mid19win, 13, 26, "Rsp Time Max:");
155 display(mid19win, 14, 26, "Time/Accu:");
156
157 display(mid19win, 15, 8, " Packet type 19 (0x13) ");
158 (void)wattrset(mid19win, A_NORMAL);
159
160 (void)wborder(mid6win, 0, 0, 0, 0, 0, 0, 0, 0),
161 (void)wattrset(mid6win, A_BOLD);
162 display(mid6win, 0, 1, " Firmware Version ");
163 display(mid6win, 2, 8, " Packet Type 6 (0x06) ");
164 (void)wattrset(mid6win, A_NORMAL);
165
166 (void)wborder(mid7win, 0, 0, 0, 0, 0, 0, 0, 0),
167 (void)wattrset(mid7win, A_BOLD);
168 display(mid7win, 0, 1, " Clock Status ");
169 display(mid7win, 1, 1, "SVs: ");
170 display(mid7win, 1, 9, "Drift: ");
171 display(mid7win, 1, 23, "Bias: ");
172 display(mid7win, 2, 1, "GPS Time: ");
173 display(mid7win, 2, 23, "PPS: ");
174 (void)syncok(mid7win, true);
175 (void)mvwaddstr(mid7win, 2, 40, "N/A");
176 display(mid7win, 3, 8, " Packet type 7 (0x07) ");
177 (void)wattrset(mid7win, A_NORMAL);
178
179 (void)wborder(mid9win, 0, 0, 0, 0, 0, 0, 0, 0),
180 (void)wattrset(mid9win, A_BOLD);
181 display(mid9win, 0, 1, " CPU Throughput ");
182 display(mid9win, 1, 1, "Max: ");
183 display(mid9win, 1, 13, "Lat: ");
184 display(mid9win, 1, 25, "Time: ");
185 display(mid9win, 1, 39, "MS: ");
186 display(mid9win, 2, 8, " Packet type 9 (0x09) ");
187 (void)wattrset(mid9win, A_NORMAL);
188
189 (void)wborder(mid13win, 0, 0, 0, 0, 0, 0, 0, 0),
190 (void)wattrset(mid13win, A_BOLD);
191 display(mid13win, 0, 1, " Visible List ");
192 display(mid13win, 2, 8, " Packet type 13 (0x0D) ");
193 (void)wattrset(mid13win, A_NORMAL);
194
195 (void)wborder(mid27win, 0, 0, 0, 0, 0, 0, 0, 0),
196 (void)wattrset(mid27win, A_BOLD);
197 display(mid27win, 0, 1, " DGPS Status ");
198 display(mid27win, 2, 8, " Packet type 27 (0x1B) ");
199 (void)wattrset(mid27win, A_NORMAL);
200
201 #ifdef CONTROLSEND_ENABLE
202 /* probe for version */
203 (void)monitor_control_send((unsigned char *)"\x84\x00", 2);
204 #endif /* CONTROLSEND_ENABLE */
205
206 /* initialize the GPS context's time fields */
207 gpsd_time_init(session.context, time(NULL));
208
209 return true;
210 }
211
decode_ecef(double x,double y,double z,double vx,double vy,double vz)212 static void decode_ecef(double x, double y, double z,
213 double vx, double vy, double vz)
214 {
215 const double a = WGS84A;
216 const double b = WGS84B;
217 const double e2 = (a * a - b * b) / (a * a);
218 const double e_2 = (a * a - b * b) / (b * b);
219 double lambda, p, theta, phi, n, h, vnorth, veast, vup, speed, heading;
220
221 lambda = atan2(y, x);
222 p = sqrt(pow(x, 2) + pow(y, 2));
223 theta = atan2(z * a, p * b);
224 phi =
225 atan2(z + e_2 * b * pow(sin(theta), 3),
226 p - e2 * a * pow(cos(theta), 3));
227 n = a / sqrt(1.0 - e2 * pow(sin(phi), 2));
228 h = p / cos(phi) - n;
229 h -= wgs84_separation((double)(RAD_2_DEG * phi),
230 (double)(RAD_2_DEG * lambda));
231 vnorth =
232 -vx * sin(phi) * cos(lambda) - vy * sin(phi) * sin(lambda) +
233 vz * cos(phi);
234 veast = -vx * sin(lambda) + vy * cos(lambda);
235 vup =
236 vx * cos(phi) * cos(lambda) + vy * cos(phi) * sin(lambda) +
237 vz * sin(phi);
238 speed = sqrt(pow(vnorth, 2) + pow(veast, 2));
239 heading = atan2(veast, vnorth);
240 if (heading < 0)
241 heading += 2 * GPS_PI;
242
243 /* North and East position fields */
244 (void)wattrset(mid2win, A_UNDERLINE);
245 (void)wmove(mid2win, 1, 40);
246 (void)wprintw(mid2win, "%9.5f %9.5f %9d",
247 (double)(RAD_2_DEG * phi),
248 (double)(RAD_2_DEG * lambda),
249 (int)h);
250 (void)mvwaddch(mid2win, 1, 49, ACS_DEGREE);
251 (void)mvwaddch(mid2win, 1, 59, ACS_DEGREE);
252
253 /* North and East velocity fields */
254 (void)wmove(mid2win, 2, 40);
255 (void)wprintw(mid2win, "%9.1f %9.1f %9.1f", vnorth, veast, vup);
256
257 /* heading and speed fields */
258 (void)wmove(mid2win, 3, 54);
259 (void)wprintw(mid2win, "%5.1f %9.1f", (double)(RAD_2_DEG * heading), speed);
260 (void)mvwaddch(mid2win, 3, 59, ACS_DEGREE);
261 (void)wattrset(mid2win, A_NORMAL);
262 }
263
sirf_update(void)264 static void sirf_update(void)
265 {
266 int i, j, ch, sv;
267 unsigned char *buf;
268 size_t len;
269 uint8_t dgps;
270 char tbuf[JSON_DATE_MAX+1];
271
272 buf = session.lexer.outbuffer + 4;
273 len = session.lexer.outbuflen - 8;
274 switch (buf[0]) {
275 case 0x02: /* Measured Navigation Data */
276 (void)wmove(mid2win, 1, 6); /* ECEF position */
277 (void)wprintw(mid2win, "%8d %8d %8d", getbes32(buf, 1),
278 getbes32(buf, 5), getbes32(buf, 9));
279 (void)wmove(mid2win, 2, 6); /* ECEF velocity */
280 (void)wprintw(mid2win, "%8.1f %8.1f %8.1f",
281 (double)getbes16(buf, 13) / 8, (double)getbes16(buf,
282 15) / 8,
283 (double)getbes16(buf, 17) / 8);
284 decode_ecef((double)getbes32(buf, 1), (double)getbes32(buf, 5),
285 (double)getbes32(buf, 9), (double)getbes16(buf, 13) / 8,
286 (double)getbes16(buf, 15) / 8, (double)getbes16(buf,
287 17) / 8);
288 /* line 3 */
289 (void)wmove(mid2win, 3, 7);
290 if (0 < session.gpsdata.fix.time.tv_sec) {
291 (void)wprintw(mid2win, "%-24s",
292 timespec_to_iso8601(session.gpsdata.fix.time, tbuf,
293 sizeof(tbuf)));
294 }
295 (void)wmove(mid2win, 3, 38);
296 (void)wattrset(mid2win, A_UNDERLINE);
297 if (ppstime_enabled)
298 (void)wprintw(mid2win, "%02d", leapseconds);
299 else
300 (void)wprintw(mid2win, "??");
301 (void)wattrset(mid2win, A_NORMAL);
302 /* line 4 */
303 /* HDOP */
304 (void)wmove(mid2win, 4, 59);
305 (void)wprintw(mid2win, "%4.1f", (double)getub(buf, 20) / 5);
306 /* Mode 1 */
307 (void)wmove(mid2win, 4, 69);
308 (void)wprintw(mid2win, "%02x", getub(buf, 19));
309 /* Mode 2 */
310 (void)wmove(mid2win, 4, 77);
311 (void)wprintw(mid2win, "%02x", getub(buf, 21));
312 /* SVs in fix */
313 (void)wmove(mid2win, 4, 6);
314 (void)wprintw(mid2win, "%2d = ",
315 (int)getub(buf, 28));
316 /* SV list */
317 (void)wmove(mid2win, 4, 10);
318 /* coverity_submit[tainted_data] */
319 for (i = 0; i < (int)getub(buf, 28); i++)
320 (void)wprintw(mid2win, " %2d", (int)getub(buf, 29 + i));
321 monitor_log("MND 0x02=");
322 break;
323
324 case 0x04: /* Measured Tracking Data */
325 ch = (int)getub(buf, 7);
326 for (i = 0; i < ch; i++) {
327 int az, el, state, off;
328 double cn;
329
330 off = 8 + 15 * i;
331 (void)wmove(mid4win, i + 2, 3);
332
333 sv = (int)getub(buf, off);
334 az = (int)getub(buf, off + 1) * 3 / 2;
335 el = (int)getub(buf, off + 2) / 2;
336 state = (int)getbeu16(buf, off + 3);
337 cn = 0;
338 for (j = 0; j < 10; j++)
339 cn += (int)getub(buf, off + 5 + j);
340 cn /= 10;
341
342 (void)wprintw(mid4win, " %3d %3d %2d %04x %4.1f %c",
343 sv, az, el, state, cn, state == 0xbf ? 'T' : ' ');
344 }
345 monitor_log("MTD 0x04=");
346 break;
347
348 #ifdef __UNUSED__
349 case 0x05: /* raw track data */
350 for (off = 1; off < len; off += 51) {
351 ch = getbeu32(buf, off);
352 (void)wmove(mid4win, ch + 2, 19);
353 cn = 0;
354
355 for (j = 0; j < 10; j++)
356 cn += getub(buf, off + 34 + j);
357
358 printw("%5.1f", (double)cn / 10);
359
360 printw("%9d%3d%5d", getbeu32(buf, off + 8),
361 (int)getbeu16(buf, off + 12), (int)getbeu16(buf, off + 14));
362 printw("%8.5f %10.5f", (double)getbeu32(buf, off + 16) / 65536,
363 (double)getbeu32(buf, off + 20) / 1024);
364 }
365 monitor_log("RTD 0x05=");
366 break;
367 #endif /* __UNUSED */
368
369 case 0x06: /* firmware version */
370 display(mid6win, 1, 1, "%s", buf + 1);
371 monitor_log("FV 0x06=");
372 break;
373
374 case 0x07: /* Response - Clock Status Data */
375 display(mid7win, 1, 5, "%2d", getub(buf, 7)); /* SVs */
376 /* Clock ppstimes */
377 display(mid7win, 1, 16, "%lu", (unsigned long)getbeu32(buf, 8));
378 display(mid7win, 1, 29, "%lu", (unsigned long)getbeu32(buf, 12));
379 /* Clock Bias */
380 display(mid7win, 2, 11, "%lu", (unsigned long)getbeu32(buf, 16));
381 /* Estimated Time */
382 monitor_log("CSD 0x07=");
383 break;
384
385 case 0x08: /* 50 BPS data */
386 ch = (int)getub(buf, 1);
387 sv = (int)getub(buf, 2);
388 display(mid4win, ch + 2, 27, "%2d", sv);
389 subframe_enabled = true;
390 monitor_log("50B 0x08=");
391 break;
392
393 case 0x09: /* Throughput */
394 display(mid9win, 1, 6, "%.3f", (double)getbeu16(buf, 1) / 186); /*SegStatMax */
395 display(mid9win, 1, 18, "%.3f", (double)getbeu16(buf, 3) / 186); /*SegStatLat */
396 display(mid9win, 1, 31, "%.3f", (double)getbeu16(buf, 5) / 186); /*SegStatTime */
397 display(mid9win, 1, 42, "%3d", (int)getbeu16(buf, 7)); /* Last Millisecond */
398 monitor_log("THR 0x09=");
399 break;
400
401 case 0x0b: /* Command Acknowledgement */
402 monitor_log("ACK 0x0b=");
403 break;
404
405 case 0x0c: /* Command NAcknowledgement */
406 monitor_log("NAK 0x0c=");
407 break;
408
409 case 0x0d: /* Visible List */
410 display(mid13win, 1, 1, "%02d = ",
411 getub(buf, 1));
412 (void)wmove(mid13win, 1, 5);
413 for (i = 0; i < (int)getub(buf, 1); i++)
414 (void)wprintw(mid13win, " %d", getub(buf, 2 + 5 * i));
415 monitor_log("VL 0x0d=");
416 break;
417
418 case 0x13:
419 #define YESNO(n) (((int)getub(buf, n) != 0)?'Y':'N')
420 display(mid19win, 1, 20, "%d", getub(buf, 5)); /* Alt. hold mode */
421 display(mid19win, 2, 20, "%d", getub(buf, 6)); /* Alt. hold source */
422 display(mid19win, 3, 20, "%dm", (int)getbeu16(buf, 7)); /* Alt. source input */
423 if (getub(buf, 9) != (uint8_t) '\0')
424 display(mid19win, 4, 20, "%dsec", getub(buf, 10)); /* Degraded timeout */
425 else
426 display(mid19win, 4, 20, "N/A ");
427 display(mid19win, 5, 20, "%dsec", getub(buf, 11)); /* DR timeout */
428 display(mid19win, 6, 20, "%c", YESNO(12)); /* Track smooth mode */
429 display(mid19win, 7, 20, "%c", YESNO(13)); /* Static Nav. */
430 display(mid19win, 8, 20, "0x%x", getub(buf, 14)); /* 3SV Least Squares */
431 display(mid19win, 9, 20, "0x%x", getub(buf, 19)); /* DOP Mask mode */
432 display(mid19win, 10, 20, "0x%x", (int)getbeu16(buf, 20)); /* Nav. Elev. mask */
433 display(mid19win, 11, 20, "0x%x", getub(buf, 22)); /* Nav. Power mask */
434 display(mid19win, 12, 20, "0x%x", getub(buf, 27)); /* DGPS Source */
435 display(mid19win, 13, 20, "0x%x", getub(buf, 28)); /* DGPS Mode */
436 display(mid19win, 14, 20, "%dsec", getub(buf, 29)); /* DGPS Timeout */
437 display(mid19win, 1, 42, "%c", YESNO(34)); /* LP Push-to-Fix */
438 display(mid19win, 2, 42, "%dms", getbeu32(buf, 35)); /* LP On Time */
439 display(mid19win, 3, 42, "%d", getbeu32(buf, 39)); /* LP Interval */
440 display(mid19win, 4, 42, "%c", YESNO(43)); /* User Tasks enabled */
441 display(mid19win, 5, 42, "%d", getbeu32(buf, 44)); /* User Task Interval */
442 display(mid19win, 6, 42, "%c", YESNO(48)); /* LP Power Cycling Enabled */
443 display(mid19win, 7, 42, "%d", getbeu32(buf, 49)); /* LP Max Acq Search Time */
444 display(mid19win, 8, 42, "%d", getbeu32(buf, 53)); /* LP Max Off Time */
445 display(mid19win, 9, 42, "%c", YESNO(57)); /* APM Enabled */
446 display(mid19win, 10, 42, "%d", (int)getbeu16(buf, 58)); /* # of fixes */
447 display(mid19win, 11, 42, "%d", (int)getbeu16(buf, 60)); /* Time Between fixes */
448 display(mid19win, 12, 42, "%d", getub(buf, 62)); /* H/V Error Max */
449 display(mid19win, 13, 42, "%d", getub(buf, 63)); /* Response Time Max */
450 display(mid19win, 14, 42, "%d", getub(buf, 64)); /* Time/Accu & Duty Cycle Priority */
451 #undef YESNO
452 monitor_log("NP 0x13=");
453 break;
454
455 case 0x1b:
456 /******************************************************************
457 Not actually documented in any published materials before the
458 1.6 version of the SiRF binary protocol manual.
459 Here is what Chris Kuethe got from the SiRF folks,
460 (plus some corrections from the GpsPaSsion forums):
461
462 Start of message
463 ----------------
464 Message ID 1 byte 27
465 Correction Source 1 byte 0=None, 1=SBAS, 2=Serial, 3=Beacon,
466 4=Software
467
468 total: 2 bytes
469
470 Middle part of message varies if using beacon or other:
471 -------------------------------------------------------
472 If Beacon:
473 Receiver Freq Hz 4 bytes
474 Bit rate BPS 1 byte
475 Status bit map 1 byte 01=Signal Valid,
476 02=Auto frequency detect
477 04=Auto bit rate detect
478 Signal Magnitude 4 bytes Note: in internal units
479 Signal Strength dB 2 bytes derived from Signal Magnitude
480 SNR dB 2 bytes
481
482 total: 14 bytes
483
484 If Not Beacon:
485 Correction Age[12] 1 byte x 12 Age in seconds in same order as follows
486 Reserved 2 bytes
487
488 total: 14 bytes
489
490 End of Message
491 --------------
492 Repeated 12 times (pad with 0 if less than 12 SV corrections):
493 SVID 1 byte
494 Correction (cm) 2 bytes (signed short)
495
496 total 3 x 12 = 36 bytes
497 ******************************************************************/
498 dgps = getub(buf, 1);
499 display(mid27win, 1, 1, "%8s = ",
500 (CHECK_RANGE(dgpsvec, dgps) ? dgpsvec[dgps] : "???"));
501 (void)wmove(mid27win, 1, 11);
502 for (ch = 0; ch < SIRF_CHANNELS; ch++)
503 if (getub(buf, 16 + 3 * ch) != '\0')
504 (void)wprintw(mid27win, " %d", getub(buf, 16 + 3 * ch));
505 monitor_log("DST 0x1b=");
506 break;
507
508 case 0x1c: /* NL Measurement Data */
509 case 0x1d: /* NL DGPS Data */
510 case 0x1e: /* NL SV State Data */
511 case 0x1f: /* NL Initialized Data */
512 subframe_enabled = true;
513 monitor_log("NL 0x%02x=", buf[0]);
514 break;
515
516 case 0x29: /* Geodetic Navigation Data */
517 monitor_log("GND 0x29=");
518 break;
519
520 case 0x32: /* SBAS Parameters */
521 monitor_log("SBP 0x32=");
522 break;
523
524 case 0x34: /* PPS Time */
525 ppstime_enabled = true;
526 leapseconds = (int)getbeu16(buf, 8);
527 monitor_log("PPS 0x34=");
528 break;
529
530 case 0xff: /* Development Data */
531 while (len > 0 && buf[len - 1] == '\n')
532 len--;
533 while (len > 0 && buf[len - 1] == ' ')
534 len--;
535 buf[len] = '\0';
536 j = 1;
537 for (i = 0; verbpat[i] != NULL; i++)
538 if (str_starts_with((char *)(buf + 1), verbpat[i])) {
539 j = 0;
540 break;
541 }
542 if (j != 0)
543 monitor_log("%s\n", buf + 1);
544 monitor_log("DD 0xff=");
545 break;
546
547 default:
548 monitor_log("UNK 0x%02x=", buf[0]);
549 break;
550 }
551
552 #ifdef CONTROLSEND_ENABLE
553 /* elicit navigation parameters */
554 if (dispmode && (time(NULL) % 10 == 0)) {
555 (void)monitor_control_send((unsigned char *)"\x98\x00", 2);
556 }
557 #endif /* CONTROLSEND_ENABLE */
558
559 /* clear the 50bps data field every 6 seconds */
560 if (subframe_enabled && (time(NULL) % 6 == 0)) {
561 for (ch = 0; ch < SIRF_CHANNELS; ch++)
562 display(mid4win, ch + 2, 27, " ");
563 }
564
565 if (dispmode) {
566 (void)touchwin(mid19win);
567 (void)wnoutrefresh(mid19win);
568 }
569
570 pps_update(mid7win, 2, 32);
571 }
572
573 #ifdef CONTROLSEND_ENABLE
sirf_command(char line[])574 static int sirf_command(char line[])
575 {
576 unsigned char buf[BUFSIZ];
577 int v;
578
579 switch (line[0]) {
580 case 'A': /* toggle 50bps subframe data */
581 (void)memset(buf, '\0', sizeof(buf));
582 putbyte(buf, 0, 0x80);
583 putbyte(buf, 23, 0x0c);
584 putbyte(buf, 24, subframe_enabled ? 0x00 : 0x10);
585 (void)monitor_control_send(buf, 25);
586 /*
587 * The subframe_enabled off because we're counting on receipt of
588 * a subframe packet to turn it on if the command succeeds.
589 */
590 subframe_enabled = false;
591 return COMMAND_MATCH;
592
593 case 'M': /* static navigation */
594 putbyte(buf, 0, 0x8f); /* id */
595 putbyte(buf, 1, atoi(line + 1));
596 (void)monitor_control_send(buf, 2);
597 return COMMAND_MATCH;
598
599 case 'D': /* MID 4 rate change (undocumented) */
600 v = atoi(line + 1);
601 if (v > 30)
602 return COMMAND_MATCH;
603 putbyte(buf, 0, 0xa6);
604 putbyte(buf, 1, 0);
605 putbyte(buf, 2, 4); /* satellite picture */
606 putbyte(buf, 3, v);
607 putbyte(buf, 4, 0);
608 putbyte(buf, 5, 0);
609 putbyte(buf, 6, 0);
610 putbyte(buf, 7, 0);
611 (void)monitor_control_send(buf, 8);
612 return COMMAND_MATCH;
613
614 case 'P': /* poll navigation params */
615 dispmode = !dispmode;
616 if (dispmode) {
617 (void)syncok(mid6win, false);
618 (void)syncok(mid7win, false);
619 (void)syncok(mid9win, false);
620 (void)syncok(mid13win, false);
621 (void)syncok(mid27win, false);
622 } else {
623 (void)syncok(mid6win, true);
624 (void)wsyncup(mid6win);
625 (void)syncok(mid7win, true);
626 (void)wsyncup(mid7win);
627 (void)syncok(mid9win, true);
628 (void)wsyncup(mid9win);
629 (void)syncok(mid13win, true);
630 (void)wsyncup(mid13win);
631 (void)syncok(mid27win, true);
632 (void)wsyncup(mid27win);
633 }
634 return COMMAND_MATCH;
635 }
636
637 return COMMAND_UNKNOWN; /* no match */
638 }
639 #endif /* CONTROLSEND_ENABLE */
640
sirf_wrap(void)641 static void sirf_wrap(void)
642 {
643 (void)delwin(mid2win);
644 (void)delwin(mid4win);
645 (void)delwin(mid6win);
646 (void)delwin(mid7win);
647 (void)delwin(mid9win);
648 (void)delwin(mid13win);
649 (void)delwin(mid19win);
650 (void)delwin(mid27win);
651 }
652
653 const struct monitor_object_t sirf_mmt = {
654 .initialize = sirf_initialize,
655 .update = sirf_update,
656 #ifdef CONTROLSEND_ENABLE
657 .command = sirf_command,
658 #else
659 .command = NULL,
660 #endif /* CONTROLSEND_ENABLE */
661 .wrap = sirf_wrap,
662 .min_y = 22,.min_x = 80,
663 .driver = &driver_sirf,
664 };
665 #endif /* defined(SIRF_ENABLE) && defined(BINARY_ENABLE) */
666
667 /* sirfmon.c ends here */
668