You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

521 lines
18KB

  1. /*
  2. * monitor_nmea0183.c - gpsmon support for NMEA devices.
  3. *
  4. * To do: Support for GPGLL, GPGBS, GPZDA, PASHR NMEA sentences.
  5. *
  6. * This file is Copyright (c) 2010-2018 by the GPSD project
  7. * SPDX-License-Identifier: BSD-2-clause
  8. */
  9. #include "gpsd_config.h" /* must be before all includes */
  10. #include <assert.h>
  11. #include <math.h>
  12. #include <stdarg.h>
  13. #include <stdio.h>
  14. #include <stdlib.h> /* for labs() */
  15. #include <string.h>
  16. #include <unistd.h>
  17. #include "gpsd.h"
  18. #include "gpsmon.h"
  19. #include "gpsdclient.h"
  20. #include "strfuncs.h"
  21. #ifdef NMEA0183_ENABLE
  22. extern const struct gps_type_t driver_nmea0183;
  23. static WINDOW *cookedwin, *nmeawin, *satwin, *gprmcwin;
  24. static WINDOW *gpggawin, *gpgsawin, *gpgstwin;
  25. static timespec_t last_tick, tick_interval;
  26. static char sentences[NMEA_MAX * 2];
  27. /*****************************************************************************
  28. *
  29. * NMEA0183 support
  30. *
  31. *****************************************************************************/
  32. #define SENTENCELINE 1 /* index of sentences line in the NMEA window */
  33. #define MAXSATS 12 /* max satellites we can display */
  34. static bool nmea_initialize(void)
  35. {
  36. cookedwin = derwin(devicewin, 3, 80, 0, 0);
  37. assert(cookedwin !=NULL);
  38. (void)wborder(cookedwin, 0, 0, 0, 0, 0, 0, 0, 0);
  39. (void)syncok(cookedwin, true);
  40. (void)wattrset(cookedwin, A_BOLD);
  41. (void)mvwaddstr(cookedwin, 1, 1, "Time: ");
  42. (void)mvwaddstr(cookedwin, 1, 32, "Lat: ");
  43. (void)mvwaddstr(cookedwin, 1, 55, "Lon: ");
  44. (void)mvwaddstr(cookedwin, 2, 34, " Cooked TPV ");
  45. (void)wattrset(cookedwin, A_NORMAL);
  46. nmeawin = derwin(devicewin, 3, 80, 3, 0);
  47. assert(nmeawin !=NULL);
  48. (void)wborder(nmeawin, 0, 0, 0, 0, 0, 0, 0, 0);
  49. (void)syncok(nmeawin, true);
  50. (void)wattrset(nmeawin, A_BOLD);
  51. (void)mvwaddstr(nmeawin, 2, 34, " Sentences ");
  52. (void)wattrset(nmeawin, A_NORMAL);
  53. satwin = derwin(devicewin, MAXSATS + 3, 20, 6, 0);
  54. assert(satwin !=NULL);
  55. (void)wborder(satwin, 0, 0, 0, 0, 0, 0, 0, 0), (void)syncok(satwin, true);
  56. (void)wattrset(satwin, A_BOLD);
  57. (void)mvwprintw(satwin, 1, 1, "PRN Az El S/N");
  58. (void)mvwprintw(satwin, 14, 7, " GSV ");
  59. (void)wattrset(satwin, A_NORMAL);
  60. gprmcwin = derwin(devicewin, 9, 30, 6, 20);
  61. assert(gprmcwin !=NULL);
  62. (void)wborder(gprmcwin, 0, 0, 0, 0, 0, 0, 0, 0),
  63. (void)syncok(gprmcwin, true);
  64. (void)wattrset(gprmcwin, A_BOLD);
  65. (void)mvwprintw(gprmcwin, 1, 1, "Time: ");
  66. (void)mvwprintw(gprmcwin, 2, 1, "Latitude: ");
  67. (void)mvwprintw(gprmcwin, 3, 1, "Longitude: ");
  68. (void)mvwprintw(gprmcwin, 4, 1, "Speed: ");
  69. (void)mvwprintw(gprmcwin, 5, 1, "Course: ");
  70. (void)mvwprintw(gprmcwin, 6, 1, "Status: FAA: ");
  71. (void)mvwprintw(gprmcwin, 7, 1, "MagVar: ");
  72. (void)mvwprintw(gprmcwin, 8, 12, " RMC ");
  73. (void)wattrset(gprmcwin, A_NORMAL);
  74. gpgsawin = derwin(devicewin, 6, 30, 15, 20);
  75. assert(gpgsawin !=NULL);
  76. (void)wborder(gpgsawin, 0, 0, 0, 0, 0, 0, 0, 0);
  77. (void)syncok(gpgsawin, true);
  78. (void)wattrset(gpgsawin, A_BOLD);
  79. #define MODE_LINE 1
  80. (void)mvwprintw(gpgsawin, MODE_LINE, 1, "Mode: ");
  81. #define SATS_LINE 1
  82. #define SATS_COL 10
  83. (void)mvwprintw(gpgsawin, SATS_LINE, SATS_COL, "Sats: ");
  84. #define DOP_LINE 2
  85. (void)mvwprintw(gpgsawin, DOP_LINE, 1, "DOP: H= V= P=");
  86. #define TOFF_LINE 3
  87. (void)mvwprintw(gpgsawin, TOFF_LINE, 1, "TOFF: ");
  88. (void)mvwaddstr(gpgsawin, TOFF_LINE, 7, "N/A");
  89. #define PPS_LINE 4
  90. (void)mvwprintw(gpgsawin, PPS_LINE, 1, "PPS: ");
  91. (void)mvwaddstr(gpgsawin, PPS_LINE, 6, "N/A");
  92. (void)mvwprintw(gpgsawin, 5, 9, " GSA + PPS ");
  93. (void)wattrset(gpgsawin, A_NORMAL);
  94. (void)syncok(gpgsawin, true);
  95. gpggawin = derwin(devicewin, 9, 30, 6, 50);
  96. assert(gpggawin !=NULL);
  97. (void)wborder(gpggawin, 0, 0, 0, 0, 0, 0, 0, 0);
  98. (void)syncok(gpggawin, true);
  99. (void)wattrset(gpggawin, A_BOLD);
  100. (void)mvwprintw(gpggawin, 1, 1, "Time: ");
  101. (void)mvwprintw(gpggawin, 2, 1, "Latitude: ");
  102. (void)mvwprintw(gpggawin, 3, 1, "Longitude: ");
  103. (void)mvwprintw(gpggawin, 4, 1, "Altitude: ");
  104. (void)mvwprintw(gpggawin, 5, 1, "Quality: Sats: ");
  105. (void)mvwprintw(gpggawin, 6, 1, "HDOP: ");
  106. (void)mvwprintw(gpggawin, 7, 1, "Geoid: ");
  107. (void)mvwprintw(gpggawin, 8, 12, " GGA ");
  108. (void)wattrset(gpggawin, A_NORMAL);
  109. gpgstwin = derwin(devicewin, 6, 30, 15, 50);
  110. assert(gpgstwin !=NULL);
  111. (void)wborder(gpgstwin, 0, 0, 0, 0, 0, 0, 0, 0);
  112. (void)syncok(gpgstwin, true);
  113. (void)wattrset(gpgstwin, A_BOLD);
  114. (void)mvwprintw(gpgstwin, 1, 1, "UTC: ");
  115. (void)mvwprintw(gpgstwin, 1, 16, "RMS: ");
  116. (void)mvwprintw(gpgstwin, 2, 1, "MAJ: ");
  117. (void)mvwprintw(gpgstwin, 2, 16, "MIN: ");
  118. (void)mvwprintw(gpgstwin, 3, 1, "ORI: ");
  119. (void)mvwprintw(gpgstwin, 3, 16, "LAT: ");
  120. (void)mvwprintw(gpgstwin, 4, 1, "LON: ");
  121. (void)mvwprintw(gpgstwin, 4, 16, "ALT: ");
  122. (void)mvwprintw(gpgstwin, 5, 12, " GST ");
  123. (void)wattrset(gpgstwin, A_NORMAL);
  124. (void)clock_gettime(CLOCK_REALTIME, &last_tick);
  125. sentences[0] = '\0';
  126. return (nmeawin != NULL);
  127. }
  128. static void cooked_pvt(void)
  129. {
  130. char scr[128];
  131. if (0 < session.gpsdata.fix.time.tv_sec) {
  132. (void)timespec_to_iso8601(session.gpsdata.fix.time, scr, sizeof(scr));
  133. } else
  134. (void)snprintf(scr, sizeof(scr), "n/a");
  135. (void)mvwprintw(cookedwin, 1, 7, "%-24s", scr);
  136. if (session.gpsdata.fix.mode >= MODE_2D) {
  137. deg_to_str2(deg_ddmm, session.gpsdata.fix.latitude,
  138. scr, sizeof(scr), " N", " S");
  139. } else
  140. (void)strncpy(scr, "n/a", sizeof(scr));
  141. (void)mvwprintw(cookedwin, 1, 37, "%-17s", scr);
  142. if (session.gpsdata.fix.mode >= MODE_2D) {
  143. deg_to_str2(deg_ddmm, session.gpsdata.fix.longitude,
  144. scr, sizeof(scr), " E", " W");
  145. } else
  146. (void)strncpy(scr, "n/a", sizeof(scr));
  147. (void)mvwprintw(cookedwin, 1, 60, "%-17s", scr);
  148. }
  149. static void monitor_satlist(WINDOW *win, int y, int x)
  150. /* display as much as we can of a satlist in a specified window */
  151. {
  152. int ymax, xmax;
  153. char scr[128];
  154. int i;
  155. assert(win != NULL);
  156. (void)wmove(win, y, x);
  157. (void)wclrtoeol(win);
  158. scr[0] = '\0';
  159. for (i = 0; i < MAXCHANNELS; i++) {
  160. if (session.gpsdata.skyview[i].used)
  161. str_appendf(scr, sizeof(scr),
  162. "%d ", session.gpsdata.skyview[i].PRN);
  163. }
  164. getmaxyx(win, ymax, xmax);
  165. assert(ymax != 0); /* suppress compiler warning */
  166. (void)mvwaddnstr(win, y, x, scr, xmax - 2 - x);
  167. if (strlen(scr) >= (size_t) (xmax - 2)) {
  168. (void)mvwaddch(win, y, xmax - 2 - x, (chtype) '.');
  169. (void)mvwaddch(win, y, xmax - 3 - x, (chtype) '.');
  170. (void)mvwaddch(win, y, xmax - 4 - x, (chtype) '.');
  171. }
  172. monitor_fixframe(win);
  173. }
  174. static void nmea_update(void)
  175. {
  176. char **fields;
  177. assert(cookedwin != NULL);
  178. assert(nmeawin != NULL);
  179. assert(gpgsawin != NULL);
  180. assert(gpggawin != NULL);
  181. assert(gprmcwin != NULL);
  182. assert(gpgstwin != NULL);
  183. /* can be NULL if packet was overlong */
  184. fields = session.nmea.field;
  185. if (session.lexer.outbuffer[0] == (unsigned char)'$'
  186. && fields != NULL && fields[0] != NULL) {
  187. int ymax, xmax;
  188. timespec_t now;
  189. timespec_t ts_diff;
  190. getmaxyx(nmeawin, ymax, xmax);
  191. assert(ymax > 0);
  192. if (strstr(sentences, fields[0]) == NULL) {
  193. char *s_end = sentences + strlen(sentences);
  194. if ((int)(strlen(sentences) + strlen(fields[0])) < xmax - 2) {
  195. *s_end++ = ' ';
  196. (void)strlcpy(s_end, fields[0], NMEA_MAX);
  197. } else {
  198. *--s_end = '.';
  199. *--s_end = '.';
  200. *--s_end = '.';
  201. }
  202. (void)mvwaddstr(nmeawin, SENTENCELINE, 1, sentences);
  203. }
  204. /*
  205. * If the interval between this and last update is
  206. * the longest we've seen yet, boldify the corresponding
  207. * tag.
  208. */
  209. (void)clock_gettime(CLOCK_REALTIME, &now);
  210. TS_SUB(&ts_diff, &now, &last_tick);
  211. if (TS_GZ(&ts_diff) && TS_GT(&ts_diff, &tick_interval)) {
  212. char *findme = strstr(sentences, fields[0]);
  213. tick_interval = ts_diff;
  214. if (findme != NULL) {
  215. (void)mvwchgat(nmeawin, SENTENCELINE, 1, xmax - 13, A_NORMAL, 0,
  216. NULL);
  217. (void)mvwchgat(nmeawin, SENTENCELINE, 1 + (findme - sentences),
  218. (int)strlen(fields[0]), A_BOLD, 0, NULL);
  219. }
  220. }
  221. last_tick = now;
  222. if (strcmp(fields[0], "GPGSV") == 0
  223. || strcmp(fields[0], "GNGSV") == 0
  224. || strcmp(fields[0], "GLGSV") == 0) {
  225. int i;
  226. int nsats =
  227. (session.gpsdata.satellites_visible <
  228. MAXSATS) ? session.gpsdata.satellites_visible : MAXSATS;
  229. for (i = 0; i < nsats; i++) {
  230. (void)wmove(satwin, i + 2, 1);
  231. (void)wprintw(satwin, "%3d %3d%3d %3.0f",
  232. session.gpsdata.skyview[i].PRN,
  233. (int)session.gpsdata.skyview[i].azimuth,
  234. (int)session.gpsdata.skyview[i].elevation,
  235. session.gpsdata.skyview[i].ss);
  236. }
  237. /* add overflow mark to the display */
  238. if (nsats <= MAXSATS)
  239. (void)mvwaddch(satwin, MAXSATS + 2, 18, ACS_HLINE);
  240. else
  241. (void)mvwaddch(satwin, MAXSATS + 2, 18, ACS_DARROW);
  242. }
  243. if (strcmp(fields[0], "GPRMC") == 0
  244. || strcmp(fields[0], "GNRMC") == 0
  245. || strcmp(fields[0], "GLRMC") == 0) {
  246. /* time, lat, lon, course, speed */
  247. (void)mvwaddstr(gprmcwin, 1, 12, fields[1]);
  248. (void)mvwprintw(gprmcwin, 2, 12, "%12s %s", fields[3], fields[4]);
  249. (void)mvwprintw(gprmcwin, 3, 12, "%12s %s", fields[5], fields[6]);
  250. (void)mvwaddstr(gprmcwin, 4, 12, fields[7]);
  251. (void)mvwaddstr(gprmcwin, 5, 12, fields[8]);
  252. /* the status field, FAA code, and magnetic variation */
  253. (void)mvwaddstr(gprmcwin, 6, 12, fields[2]);
  254. (void)mvwaddstr(gprmcwin, 6, 25, fields[12]);
  255. (void)mvwprintw(gprmcwin, 7, 12, "%-5s%s", fields[10],
  256. fields[11]);
  257. cooked_pvt(); /* cooked version of TPV */
  258. }
  259. if (strcmp(fields[0], "GPGSA") == 0
  260. || strcmp(fields[0], "GNGSA") == 0
  261. || strcmp(fields[0], "GLGSA") == 0) {
  262. (void)mvwprintw(gpgsawin, MODE_LINE, 7, "%1s%s", fields[1], fields[2]);
  263. monitor_satlist(gpgsawin, SATS_LINE, SATS_COL+6);
  264. (void)mvwprintw(gpgsawin, DOP_LINE, 8, "%-5s", fields[16]);
  265. (void)mvwprintw(gpgsawin, DOP_LINE, 16, "%-5s", fields[17]);
  266. (void)mvwprintw(gpgsawin, DOP_LINE, 24, "%-5s", fields[15]);
  267. monitor_fixframe(gpgsawin);
  268. }
  269. toff_update(gpgsawin, TOFF_LINE, 7);
  270. if (strcmp(fields[0], "GPGGA") == 0
  271. || strcmp(fields[0], "GNGGA") == 0
  272. || strcmp(fields[0], "GLGGA") == 0) {
  273. (void)mvwprintw(gpggawin, 1, 12, "%-17s", fields[1]);
  274. (void)mvwprintw(gpggawin, 2, 12, "%-17s", fields[2]);
  275. (void)mvwprintw(gpggawin, 3, 12, "%-17s", fields[4]);
  276. (void)mvwprintw(gpggawin, 4, 12, "%-17s", fields[9]);
  277. (void)mvwprintw(gpggawin, 5, 12, "%1.1s", fields[6]);
  278. (void)mvwprintw(gpggawin, 5, 22, "%2.2s", fields[7]);
  279. (void)mvwprintw(gpggawin, 6, 12, "%-5.5s", fields[8]);
  280. (void)mvwprintw(gpggawin, 7, 12, "%-5.5s", fields[11]);
  281. }
  282. if (strcmp(fields[0], "GPGST") == 0) {
  283. (void)mvwprintw(gpgstwin, 1, 6, "%-10s", fields[1]);
  284. (void)mvwprintw(gpgstwin, 1, 21, "%-8s", fields[2]);
  285. (void)mvwprintw(gpgstwin, 2, 6, "%-10s", fields[3]);
  286. (void)mvwprintw(gpgstwin, 2, 21, "%-8s", fields[4]);
  287. (void)mvwprintw(gpgstwin, 3, 6, "%-10s", fields[5]);
  288. (void)mvwprintw(gpgstwin, 3, 21, "%-8s", fields[6]);
  289. (void)mvwprintw(gpgstwin, 4, 6, "%-10s", fields[7]);
  290. (void)mvwprintw(gpgstwin, 4, 21, "%-8s", fields[8]);
  291. }
  292. }
  293. pps_update(gpgsawin, PPS_LINE, 6);
  294. }
  295. #undef SENTENCELINE
  296. static void nmea_wrap(void)
  297. {
  298. (void)delwin(nmeawin);
  299. (void)delwin(gpgsawin);
  300. (void)delwin(gpggawin);
  301. (void)delwin(gprmcwin);
  302. }
  303. const struct monitor_object_t nmea_mmt = {
  304. .initialize = nmea_initialize,
  305. .update = nmea_update,
  306. .command = NULL,
  307. .wrap = nmea_wrap,
  308. .min_y = 21,.min_x = 80,
  309. .driver = &driver_nmea0183,
  310. };
  311. /*****************************************************************************
  312. *
  313. * Extended NMEA support
  314. *
  315. *****************************************************************************/
  316. #if defined(CONTROLSEND_ENABLE) && defined(ASHTECH_ENABLE)
  317. static void monitor_nmea_send(const char *fmt, ...)
  318. {
  319. char buf[BUFSIZ];
  320. va_list ap;
  321. va_start(ap, fmt);
  322. (void)vsnprintf(buf, sizeof(buf) - 5, fmt, ap);
  323. va_end(ap);
  324. (void)monitor_control_send((unsigned char *)buf, strlen(buf));
  325. }
  326. #endif /* defined(CONTROLSEND_ENABLE) && defined(ASHTECH_ENABLE) */
  327. /*
  328. * Yes, it's OK for most of these to be clones of the generic NMEA monitor
  329. * object except for the pointer to the GPSD driver. That pointer makes
  330. * a difference, as it will automatically enable stuff like speed-switcher
  331. * and mode-switcher commands. It's really only necessary to write a
  332. * separate monitor object if you want to change the device-window
  333. * display or implement device-specific commands.
  334. */
  335. #if defined(GARMIN_ENABLE) && defined(NMEA0183_ENABLE)
  336. extern const struct gps_type_t driver_garmin;
  337. const struct monitor_object_t garmin_mmt = {
  338. .initialize = nmea_initialize,
  339. .update = nmea_update,
  340. .command = NULL,
  341. .wrap = nmea_wrap,
  342. .min_y = 21,.min_x = 80,
  343. .driver = &driver_garmin,
  344. };
  345. #endif /* GARMIN_ENABLE && NMEA0183_ENABLE */
  346. #ifdef ASHTECH_ENABLE
  347. extern const struct gps_type_t driver_ashtech;
  348. #define ASHTECH_SPEED_9600 5
  349. #define ASHTECH_SPEED_57600 8
  350. #ifdef CONTROLSEND_ENABLE
  351. static int ashtech_command(char line[])
  352. {
  353. switch (line[0]) {
  354. case 'N': /* normal = 9600, GGA+GSA+GSV+RMC+ZDA */
  355. monitor_nmea_send("$PASHS,NME,ALL,A,OFF"); /* silence outbound chatter */
  356. monitor_nmea_send("$PASHS,NME,ALL,B,OFF");
  357. monitor_nmea_send("$PASHS,NME,GGA,A,ON");
  358. monitor_nmea_send("$PASHS,NME,GSA,A,ON");
  359. monitor_nmea_send("$PASHS,NME,GSV,A,ON");
  360. monitor_nmea_send("$PASHS,NME,RMC,A,ON");
  361. monitor_nmea_send("$PASHS,NME,ZDA,A,ON");
  362. monitor_nmea_send("$PASHS,INI,%d,%d,,,0,",
  363. ASHTECH_SPEED_9600, ASHTECH_SPEED_9600);
  364. (void)sleep(6); /* it takes 4-6 sec for the receiver to reboot */
  365. monitor_nmea_send("$PASHS,WAS,ON"); /* enable WAAS */
  366. break;
  367. case 'R': /* raw = 57600, normal+XPG+POS+SAT+MCA+PBN+SNV */
  368. monitor_nmea_send("$PASHS,NME,ALL,A,OFF"); /* silence outbound chatter */
  369. monitor_nmea_send("$PASHS,NME,ALL,B,OFF");
  370. monitor_nmea_send("$PASHS,NME,GGA,A,ON");
  371. monitor_nmea_send("$PASHS,NME,GSA,A,ON");
  372. monitor_nmea_send("$PASHS,NME,GSV,A,ON");
  373. monitor_nmea_send("$PASHS,NME,RMC,A,ON");
  374. monitor_nmea_send("$PASHS,NME,ZDA,A,ON");
  375. monitor_nmea_send("$PASHS,INI,%d,%d,,,0,",
  376. ASHTECH_SPEED_57600, ASHTECH_SPEED_9600);
  377. (void)sleep(6); /* it takes 4-6 sec for the receiver to reboot */
  378. monitor_nmea_send("$PASHS,WAS,ON"); /* enable WAAS */
  379. monitor_nmea_send("$PASHS,NME,POS,A,ON"); /* Ashtech TPV solution */
  380. monitor_nmea_send("$PASHS,NME,SAT,A,ON"); /* Ashtech Satellite status */
  381. monitor_nmea_send("$PASHS,NME,MCA,A,ON"); /* MCA measurements */
  382. monitor_nmea_send("$PASHS,NME,PBN,A,ON"); /* ECEF TPV solution */
  383. monitor_nmea_send("$PASHS,NME,SNV,A,ON,10"); /* Almanac data */
  384. monitor_nmea_send("$PASHS,NME,XMG,A,ON"); /* exception messages */
  385. break;
  386. default:
  387. return COMMAND_UNKNOWN;
  388. }
  389. return COMMAND_UNKNOWN;
  390. }
  391. #endif /* CONTROLSEND_ENABLE */
  392. const struct monitor_object_t ashtech_mmt = {
  393. .initialize = nmea_initialize,
  394. .update = nmea_update,
  395. #ifdef CONTROLSEND_ENABLE
  396. .command = ashtech_command,
  397. #else
  398. .command = NULL,
  399. #endif /* CONTROLSEND_ENABLE */
  400. .wrap = nmea_wrap,
  401. .min_y = 21,.min_x = 80,
  402. .driver = &driver_ashtech,
  403. };
  404. #endif /* ASHTECH_ENABLE */
  405. #ifdef FV18_ENABLE
  406. extern const struct gps_type_t driver_fv18;
  407. const struct monitor_object_t fv18_mmt = {
  408. .initialize = nmea_initialize,
  409. .update = nmea_update,
  410. .command = NULL,
  411. .wrap = nmea_wrap,
  412. .min_y = 21,.min_x = 80,
  413. .driver = &driver_fv18,
  414. };
  415. #endif /* FV18_ENABLE */
  416. #ifdef GPSCLOCK_ENABLE
  417. extern const struct gps_type_t driver_gpsclock;
  418. const struct monitor_object_t gpsclock_mmt = {
  419. .initialize = nmea_initialize,
  420. .update = nmea_update,
  421. .command = NULL,
  422. .wrap = nmea_wrap,
  423. .min_y = 21,.min_x = 80,
  424. .driver = &driver_gpsclock,
  425. };
  426. #endif /* GPSCLOCK_ENABLE */
  427. #ifdef MTK3301_ENABLE
  428. extern const struct gps_type_t driver_mtk3301;
  429. const struct monitor_object_t mtk3301_mmt = {
  430. .initialize = nmea_initialize,
  431. .update = nmea_update,
  432. .command = NULL,
  433. .wrap = nmea_wrap,
  434. .min_y = 21,.min_x = 80,
  435. .driver = &driver_mtk3301,
  436. };
  437. #endif /* MTK3301_ENABLE */
  438. #ifdef AIVDM_ENABLE
  439. extern const struct gps_type_t driver_aivdm;
  440. const struct monitor_object_t aivdm_mmt = {
  441. .initialize = nmea_initialize,
  442. .update = nmea_update,
  443. .command = NULL,
  444. .wrap = nmea_wrap,
  445. .min_y = 21,.min_x = 80,
  446. .driver = &driver_aivdm,
  447. };
  448. #endif /* AIVDM_ENABLE */
  449. #endif /* NMEA0183_ENABLE */
  450. /* vim: set expandtab shiftwidth=4: */