Devuan fork of gpsd
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.
 
 
 
 
 
 

410 lines
11 KiB

  1. /*
  2. * This file is Copyright (c) 2010 by the GPSD project
  3. * SPDX-License-Identifier: BSD-2-clause
  4. */
  5. #include <ctype.h>
  6. #include <fcntl.h>
  7. #include <stdarg.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <sys/types.h>
  12. #include <unistd.h>
  13. #include "../gpsd.h"
  14. static int verbose = 0;
  15. struct map
  16. {
  17. char *legend;
  18. unsigned char test[MAX_PACKET_LENGTH + 1];
  19. size_t testlen;
  20. int garbage_offset;
  21. int type;
  22. };
  23. /* *INDENT-OFF* */
  24. static struct map singletests[] = {
  25. /* NMEA tests */
  26. {
  27. .legend = "NMEA packet with checksum (1)",
  28. .test = "$GPVTG,308.74,T,,M,0.00,N,0.0,K*68\r\n",
  29. .testlen = 36,
  30. .garbage_offset = 0,
  31. NMEA_PACKET,
  32. },
  33. {
  34. .legend = "NMEA packet with checksum (2)",
  35. .test = "$GPGGA,110534.994,4002.1425,N,07531.2585,W,0,00,50.0,172.7,M,-33.8,M,0.0,0000*7A\r\n",
  36. .testlen = 82,
  37. .garbage_offset = 0,
  38. .type = NMEA_PACKET,
  39. },
  40. {
  41. .legend = "NMEA packet with checksum and 4 chars of leading garbage",
  42. .test = "\xff\xbf\x00\xbf$GPVTG,308.74,T,,M,0.00,N,0.0,K*68\r\n",
  43. .testlen = 40,
  44. .garbage_offset = 4,
  45. .type = NMEA_PACKET,
  46. },
  47. {
  48. .legend = "NMEA packet without checksum",
  49. .test = "$PSRF105,1\r\n",
  50. .testlen = 12,
  51. .garbage_offset = 0,
  52. .type = NMEA_PACKET,
  53. },
  54. {
  55. .legend = "NMEA packet with wrong checksum",
  56. .test = "$GPVTG,308.74,T,,M,0.00,N,0.0,K*28\r\n",
  57. .testlen = 36,
  58. .garbage_offset = 0,
  59. .type = BAD_PACKET,
  60. },
  61. {
  62. .legend = "NMEA interspersed packet",
  63. .test = "$GPZDA,112533.00,20,01,20$PTNTA,20000102173852,1,T4,,,6,1,0*32\r\n",
  64. .testlen = 64,
  65. .garbage_offset = 25,
  66. .type = NMEA_PACKET,
  67. },
  68. {
  69. .legend = "NMEA interrupted packet",
  70. .test = "$GPZDA,112533.00,20,01,2016,00,00*67\r\n$GPZDA,112533.00,20,01,20$PTNTA,20000102173852,1,T4,,,6,1,0*32\r\n16,00,00*67\r\n",
  71. .testlen = 115,
  72. .garbage_offset = 0,
  73. .type = NMEA_PACKET,
  74. },
  75. /* SiRF tests */
  76. {
  77. .legend = "SiRF WAAS version ID",
  78. .test = {
  79. 0xA0, 0xA2, 0x00, 0x15,
  80. 0x06, 0x06, 0x31, 0x2E, 0x32, 0x2E, 0x30, 0x44,
  81. 0x4B, 0x49, 0x54, 0x31, 0x31, 0x39, 0x20, 0x53,
  82. 0x4D, 0x00, 0x00, 0x00, 0x00,
  83. 0x03, 0x82, 0xB0, 0xB3},
  84. .testlen = 29,
  85. .garbage_offset = 0,
  86. .type = SIRF_PACKET,
  87. },
  88. {
  89. .legend = "SiRF WAAS version ID with 3 chars of leading garbage",
  90. .test = {
  91. 0xff, 0x00, 0xff,
  92. 0xA0, 0xA2, 0x00, 0x15,
  93. 0x06, 0x06, 0x31, 0x2E, 0x32, 0x2E, 0x30, 0x44,
  94. 0x4B, 0x49, 0x54, 0x31, 0x31, 0x39, 0x20, 0x53,
  95. 0x4D, 0x00, 0x00, 0x00, 0x00,
  96. 0x03, 0x82, 0xB0, 0xB3},
  97. .testlen = 32,
  98. .garbage_offset = 3,
  99. .type = SIRF_PACKET,
  100. },
  101. {
  102. .legend = "SiRF WAAS version ID with wrong checksum",
  103. .test = {
  104. 0xA0, 0xA2, 0x00, 0x15,
  105. 0x06, 0x06, 0x31, 0x2E, 0x32, 0x2E, 0x30, 0x44,
  106. 0x4B, 0x49, 0x54, 0x31, 0x31, 0x39, 0x20, 0x53,
  107. 0x4D, 0x00, 0x00, 0x00, 0x00,
  108. 0x03, 0x00, 0xB0, 0xB3},
  109. .testlen = 29,
  110. .garbage_offset = 0,
  111. .type = BAD_PACKET,
  112. },
  113. {
  114. .legend = "SiRF WAAS version ID with bad length",
  115. .test = {
  116. 0xA0, 0xA2, 0xff, 0x15,
  117. 0x06, 0x06, 0x31, 0x2E, 0x32, 0x2E, 0x30, 0x44,
  118. 0x4B, 0x49, 0x54, 0x31, 0x31, 0x39, 0x20, 0x53,
  119. 0x4D, 0x00, 0x00, 0x00, 0x00,
  120. 0x03, 0x82, 0xB0, 0xB3},
  121. .testlen = 29,
  122. .garbage_offset = 0,
  123. .type = BAD_PACKET,
  124. },
  125. /* Zodiac tests */
  126. {
  127. .legend = "Zodiac binary 1000 Geodetic Status Output Message",
  128. .test = {
  129. 0xff, 0x81, 0xe8, 0x03, 0x31, 0x00, 0x00, 0x00, 0xe8, 0x79,
  130. 0x74, 0x0e, 0x00, 0x00, 0x24, 0x00, 0x24, 0x00, 0x04, 0x00,
  131. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x03, 0x23, 0x00,
  132. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x06, 0x00,
  133. 0xcd, 0x07, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x7b, 0x0d,
  134. 0x00, 0x00, 0x12, 0x6b, 0xa7, 0x04, 0x41, 0x75, 0x32, 0xf8,
  135. 0x03, 0x1f, 0x00, 0x00, 0xe6, 0xf2, 0x00, 0x00, 0x00, 0x00,
  136. 0x00, 0x00, 0x11, 0xf6, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40,
  137. 0xd9, 0x12, 0x90, 0xd0, 0x03, 0x00, 0x00, 0xa3, 0xe1, 0x11,
  138. 0x10, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0xe1, 0x11,
  139. 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0x04, 0x00, 0x04, 0xaa},
  140. .testlen = 110,
  141. .garbage_offset = 0,
  142. .type = ZODIAC_PACKET,
  143. },
  144. /* EverMore tests */
  145. {
  146. .legend = "EverMore status packet 0x20",
  147. .test = {
  148. 0x10, 0x02, 0x0D, 0x20, 0xE1, 0x00, 0x00, 0x00,
  149. 0x0A, 0x00, 0x1E, 0x00, 0x32, 0x00, 0x5b, 0x10,
  150. 0x03},
  151. .testlen = 17,
  152. .garbage_offset = 0,
  153. .type = EVERMORE_PACKET,
  154. },
  155. {
  156. .legend = "EverMore packet 0x04 with 0x10 0x10 sequence",
  157. .test = {
  158. 0x10, 0x02, 0x0f, 0x04, 0x00, 0x00, 0x10, 0x10,
  159. 0xa7, 0x13, 0x03, 0x2c, 0x26, 0x24, 0x0a, 0x17,
  160. 0x00, 0x68, 0x10, 0x03},
  161. .testlen = 20,
  162. .garbage_offset = 0,
  163. .type = EVERMORE_PACKET,
  164. },
  165. {
  166. .legend = "EverMore packet 0x04 with 0x10 0x10 sequence, some noise before packet data",
  167. .test = {
  168. 0x10, 0x03, 0xff, 0x10, 0x02, 0x0f, 0x04, 0x00,
  169. 0x00, 0x10, 0x10, 0xa7, 0x13, 0x03, 0x2c, 0x26,
  170. 0x24, 0x0a, 0x17, 0x00, 0x68, 0x10, 0x03},
  171. .testlen = 23,
  172. .garbage_offset = 3,
  173. .type = EVERMORE_PACKET,
  174. },
  175. {
  176. .legend = "EverMore packet 0x04, 0x10 and some other data at the beginning",
  177. .test = {
  178. 0x10, 0x12, 0x10, 0x03, 0xff, 0x10, 0x02, 0x0f,
  179. 0x04, 0x00, 0x00, 0x10, 0x10, 0xa7, 0x13, 0x03,
  180. 0x2c, 0x26, 0x24, 0x0a, 0x17, 0x00, 0x68, 0x10,
  181. 0x03},
  182. .testlen = 25,
  183. .garbage_offset = 5,
  184. .type = EVERMORE_PACKET,
  185. },
  186. {
  187. .legend = "EverMore packet 0x04, 0x10 three times at the beginning",
  188. .test = {
  189. 0x10, 0x10, 0x10,
  190. 0x10, 0x02, 0x0f, 0x04, 0x00, 0x00, 0x10, 0x10,
  191. 0xa7, 0x13, 0x03, 0x2c, 0x26, 0x24, 0x0a, 0x17,
  192. 0x00, 0x68, 0x10, 0x03},
  193. .testlen = 23,
  194. .garbage_offset = 3,
  195. .type = EVERMORE_PACKET,
  196. },
  197. {
  198. /* from page 4-3 of RTCM 10403.1 */
  199. .legend = "RTCM104V3 type 1005 packet",
  200. /*
  201. * Reference Station Id = 2003
  202. * GPS Service supported, but not GLONASS or Galileo
  203. * ARP ECEF-X = 1114104.5999 meters
  204. * ARP ECEF-Y = -4850729.7108 meters
  205. * ARP ECEF-Z = 3975521.4643 meters
  206. */
  207. .test = {
  208. 0xD3, 0x00, 0x13, 0x3E, 0xD7, 0xD3, 0x02, 0x02,
  209. 0x98, 0x0E, 0xDE, 0xEF, 0x34, 0xB4, 0xBD, 0x62,
  210. 0xAC, 0x09, 0x41, 0x98, 0x6F, 0x33, 0x36, 0x0B,
  211. 0x98,
  212. },
  213. .testlen = 25,
  214. .garbage_offset = 0,
  215. .type = RTCM3_PACKET,
  216. },
  217. {
  218. .legend = "RTCM104V3 type 1005 packet with 4th byte garbled",
  219. .test = {
  220. 0xD3, 0x00, 0x13, 0x3F, 0xD7, 0xD3, 0x02, 0x02,
  221. 0x98, 0x0E, 0xDE, 0xEF, 0x34, 0xB4, 0xBD, 0x62,
  222. 0xAC, 0x09, 0x41, 0x98, 0x6F, 0x33, 0x36, 0x0B,
  223. 0x98,
  224. },
  225. .testlen = 25,
  226. .garbage_offset = 0,
  227. .type = BAD_PACKET,
  228. },
  229. {
  230. /* from page 3-71 of the RTCM 10403.1 */
  231. .legend = "RTCM104V3 type 1029 packet",
  232. .test = {
  233. 0xD3, 0x00, 0x27, 0x40, 0x50, 0x17, 0x00, 0x84,
  234. 0x73, 0x6E, 0x15, 0x1E, 0x55, 0x54, 0x46, 0x2D,
  235. 0x38, 0x20, 0xD0, 0xBF, 0xD1, 0x80, 0xD0, 0xBE,
  236. 0xD0, 0xB2, 0xD0, 0xB5, 0xD1, 0x80, 0xD0, 0xBA,
  237. 0xD0, 0xB0, 0x20, 0x77, 0xC3, 0xB6, 0x72, 0x74,
  238. 0x65, 0x72, 0xED, 0xA3, 0x3B
  239. },
  240. .testlen = 45,
  241. .garbage_offset = 0,
  242. .type = RTCM3_PACKET,
  243. },
  244. };
  245. /* *INDENT-ON* */
  246. /* *INDENT-OFF* */
  247. static struct map runontests[] = {
  248. /* NMEA tests */
  249. {
  250. .legend = "Double NMEA packet with checksum",
  251. .test = "$GPVTG,308.74,T,,M,0.00,N,0.0,K*68\r\n$GPGGA,110534.994,4002.1425,N,07531.2585,W,0,00,50.0,172.7,M,-33.8,M,0.0,0000*7A\r\n",
  252. .testlen = 118,
  253. 0,
  254. NMEA_PACKET,
  255. },
  256. };
  257. /* *INDENT-ON* */
  258. static int packet_test(struct map *mp)
  259. {
  260. struct gps_lexer_t lexer;
  261. int failure = 0;
  262. lexer_init(&lexer);
  263. lexer.errout.debug = verbose;
  264. memcpy(lexer.inbufptr = lexer.inbuffer, mp->test, mp->testlen);
  265. lexer.inbuflen = mp->testlen;
  266. packet_parse(&lexer);
  267. if (lexer.type != mp->type)
  268. printf("%2ti: %s test FAILED (packet type %d wrong).\n",
  269. mp - singletests + 1, mp->legend, lexer.type);
  270. else if (memcmp
  271. (mp->test + mp->garbage_offset, lexer.outbuffer,
  272. lexer.outbuflen)) {
  273. printf("%2ti: %s test FAILED (data garbled).\n", mp - singletests + 1,
  274. mp->legend);
  275. ++failure;
  276. } else
  277. printf("%2ti: %s test succeeded.\n", mp - singletests + 1,
  278. mp->legend);
  279. return failure;
  280. }
  281. static void runon_test(struct map *mp)
  282. {
  283. struct gps_lexer_t lexer;
  284. int nullfd = open("/dev/null", O_RDONLY);
  285. ssize_t st;
  286. lexer_init(&lexer);
  287. lexer.errout.debug = verbose;
  288. memcpy(lexer.inbufptr = lexer.inbuffer, mp->test, mp->testlen);
  289. lexer.inbuflen = mp->testlen;
  290. (void)fputs((char *)mp->test, stdout);
  291. do {
  292. st = packet_get(nullfd, &lexer);
  293. //printf("packet_parse() returned %zd\n", st);
  294. } while (st > 0);
  295. }
  296. static int property_check(void)
  297. {
  298. const struct gps_type_t **dp;
  299. int status;
  300. for (dp = gpsd_drivers; *dp; dp++) {
  301. if (*dp == NULL || (*dp)->packet_type == COMMENT_PACKET)
  302. continue;
  303. #ifdef RECONFIGURE_ENABLE
  304. if (CONTROLLABLE(*dp))
  305. (void)fputs("control\t", stdout);
  306. else
  307. (void)fputs(".\t", stdout);
  308. if ((*dp)->event_hook != NULL)
  309. (void)fputs("hook\t", stdout);
  310. else
  311. (void)fputs(".\t", stdout);
  312. #endif /* RECONFIGURE_ENABLE */
  313. if ((*dp)->trigger != NULL)
  314. (void)fputs("trigger\t", stdout);
  315. else if ((*dp)->probe_detect != NULL)
  316. (void)fputs("probe\t", stdout);
  317. else
  318. (void)fputs(".\t", stdout);
  319. #ifdef CONTROLSEND_ENABLE
  320. if ((*dp)->control_send != NULL)
  321. (void)fputs("send\t", stdout);
  322. else
  323. (void)fputs(".\t", stdout);
  324. #endif /* CONTROLSEND_ENABLE */
  325. if ((*dp)->packet_type > NMEA_PACKET)
  326. (void)fputs("binary\t", stdout);
  327. else
  328. (void)fputs("NMEA\t", stdout);
  329. #ifdef CONTROLSEND_ENABLE
  330. if (STICKY(*dp))
  331. (void)fputs("sticky\t", stdout);
  332. else
  333. (void)fputs(".\t", stdout);
  334. #endif /* CONTROLSEND_ENABLE */
  335. (void)puts((*dp)->type_name);
  336. }
  337. status = EXIT_SUCCESS;
  338. for (dp = gpsd_drivers; *dp; dp++) {
  339. if (*dp == NULL || (*dp)->packet_type == COMMENT_PACKET)
  340. continue;
  341. #if defined(CONTROLSEND_ENABLE) && defined(RECONFIGURE_ENABLE)
  342. if (CONTROLLABLE(*dp) && (*dp)->control_send == NULL) {
  343. (void)fprintf(stderr, "%s has control methods but no send\n",
  344. (*dp)->type_name);
  345. status = EXIT_FAILURE;
  346. }
  347. if ((*dp)->event_hook != NULL && (*dp)->control_send == NULL) {
  348. (void)fprintf(stderr, "%s has event hook but no send\n",
  349. (*dp)->type_name);
  350. status = EXIT_FAILURE;
  351. }
  352. #endif /* CONTROLSEND_ENABLE && RECONFIGURE_ENABLE*/
  353. }
  354. return status;
  355. }
  356. int main(int argc, char *argv[])
  357. {
  358. struct map *mp;
  359. int failcount = 0;
  360. int option, singletest = 0;
  361. verbose = 0;
  362. while ((option = getopt(argc, argv, "ce:t:v:")) != -1) {
  363. switch (option) {
  364. case 'c':
  365. exit(property_check());
  366. case 'e':
  367. mp = singletests + atoi(optarg) - 1;
  368. (void)fwrite(mp->test, mp->testlen, sizeof(char), stdout);
  369. (void)fflush(stdout);
  370. exit(EXIT_SUCCESS);
  371. case 't':
  372. singletest = atoi(optarg);
  373. break;
  374. case 'v':
  375. verbose = atoi(optarg);
  376. break;
  377. }
  378. }
  379. if (singletest)
  380. failcount += packet_test(singletests + singletest - 1);
  381. else {
  382. (void)fputs("=== Packet identification tests ===\n", stdout);
  383. for (mp = singletests;
  384. mp < singletests + sizeof(singletests) / sizeof(singletests[0]);
  385. mp++)
  386. failcount += packet_test(mp);
  387. (void)fputs("=== EOF with buffer nonempty test ===\n", stdout);
  388. runon_test(&runontests[0]);
  389. }
  390. exit(failcount > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
  391. }