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.

808 lines
27KB

  1. /*
  2. * This file is Copyright (c) 2010-2018 by the GPSD project
  3. * SPDX-License-Identifier: BSD-2-clause
  4. */
  5. #include "gpsd_config.h" /* must be before all includes */
  6. #include <ctype.h> /* for isdigit() */
  7. #include <dirent.h> /* for DIR */
  8. #include <errno.h>
  9. #include <fcntl.h>
  10. #include <stdbool.h>
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <sys/ioctl.h>
  14. #include <sys/param.h> /* defines BSD */
  15. #include <sys/socket.h>
  16. #include <sys/stat.h>
  17. #include <sys/types.h>
  18. #include <unistd.h>
  19. #ifdef HAVE_SYS_SYSMACROS_H
  20. #include <sys/sysmacros.h> /* defines major() */
  21. #endif /* HAVE_SYS_SYSMACROS_H */
  22. #ifdef ENABLE_BLUEZ
  23. #include <bluetooth/bluetooth.h>
  24. #include <bluetooth/hci.h>
  25. #include <bluetooth/hci_lib.h>
  26. #include <bluetooth/rfcomm.h>
  27. #endif /* ENABLE_BLUEZ */
  28. #include "gpsd.h"
  29. /* Workaround for HP-UX 11.23, which is missing CRTSCTS */
  30. #ifndef CRTSCTS
  31. # ifdef CNEW_RTSCTS
  32. # define CRTSCTS CNEW_RTSCTS
  33. # else
  34. # define CRTSCTS 0
  35. # endif /* CNEW_RTSCTS */
  36. #endif /* !CRTSCTS */
  37. static sourcetype_t gpsd_classify(const char *path)
  38. /* figure out what kind of device we're looking at */
  39. {
  40. struct stat sb;
  41. if (stat(path, &sb) == -1)
  42. return source_unknown;
  43. else if (S_ISREG(sb.st_mode))
  44. return source_blockdev;
  45. /* this assumes we won't get UDP from a filesystem socket */
  46. else if (S_ISSOCK(sb.st_mode))
  47. return source_tcp;
  48. /* OS-independent check for ptys using Unix98 naming convention */
  49. else if (strncmp(path, "/dev/pts/", 9) == 0)
  50. return source_pty;
  51. else if (strncmp(path, "/dev/pps", 8) == 0)
  52. return source_pps;
  53. else if (S_ISFIFO(sb.st_mode))
  54. return source_pipe;
  55. else if (S_ISCHR(sb.st_mode)) {
  56. sourcetype_t devtype = source_rs232;
  57. #ifdef __linux__
  58. /* Linux major device numbers live here
  59. *
  60. * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/devices.txt
  61. *
  62. * Note: This code works because Linux major device numbers are
  63. * stable and architecture-independent. It is *not* a good model
  64. * for other Unixes where either or both assumptions may break.
  65. */
  66. int devmajor = major(sb.st_rdev);
  67. /* 207 are Freescale i.MX UARTs (ttymxc*) */
  68. if (devmajor == 4 || devmajor == 204 || devmajor == 207)
  69. devtype = source_rs232;
  70. else if (devmajor == 188 || devmajor == 166)
  71. devtype = source_usb;
  72. else if (devmajor == 216 || devmajor == 217)
  73. devtype = source_bluetooth;
  74. else if (devmajor == 3 || (devmajor >= 136 && devmajor <= 143))
  75. devtype = source_pty;
  76. #endif /* __linux__ */
  77. /*
  78. * See http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system
  79. * for discussion how this works. Key graphs:
  80. *
  81. * Compilers for the old BSD base for these distributions
  82. * defined the __bsdi__ macro, but none of these distributions
  83. * define it now. This leaves no generic "BSD" macro defined
  84. * by the compiler itself, but all UNIX-style OSes provide a
  85. * <sys/param.h> file. On BSD distributions, and only on BSD
  86. * distributions, this file defines a BSD macro that's set to
  87. * the OS version. Checking for this generic macro is more
  88. * robust than looking for known BSD distributions with
  89. * __DragonFly__, __FreeBSD__, __NetBSD__, and __OpenBSD__
  90. * macros.
  91. *
  92. * Apple's OSX for the Mac and iOS for iPhones and iPads are
  93. * based in part on a fork of FreeBSD distributed as
  94. * Darwin. As such, OSX and iOS also define the BSD macro
  95. * within <sys/param.h>. However, compilers for OSX, iOS, and
  96. * Darwin do not define __unix__. To detect all BSD OSes,
  97. * including OSX, iOS, and Darwin, use an #if/#endif that
  98. * checks for __unix__ along with __APPLE__ and __MACH__ (see
  99. * the later section on OSX and iOS).
  100. */
  101. #ifdef BSD
  102. /*
  103. * Hacky check for pty, which is what really matters for avoiding
  104. * adaptive delay.
  105. */
  106. if (strncmp(path, "/dev/ttyp", 9) == 0 ||
  107. strncmp(path, "/dev/ttyq", 9) == 0)
  108. devtype = source_pty;
  109. else if (strncmp(path, "/dev/ttyU", 9) == 0 ||
  110. strncmp(path, "/dev/dtyU", 9) == 0)
  111. devtype = source_usb;
  112. /* XXX bluetooth */
  113. #endif /* BSD */
  114. return devtype;
  115. } else
  116. return source_unknown;
  117. }
  118. #ifdef __linux__
  119. static int fusercount(const char *path)
  120. /* return true if any process has the specified path open */
  121. {
  122. DIR *procd, *fdd;
  123. struct dirent *procentry, *fdentry;
  124. char procpath[64], fdpath[64], linkpath[64];
  125. int cnt = 0;
  126. if ((procd = opendir("/proc")) == NULL)
  127. return -1;
  128. while ((procentry = readdir(procd)) != NULL) {
  129. if (isdigit(procentry->d_name[0])==0)
  130. continue;
  131. /* longest procentry->d_name I could find was 12 */
  132. (void)snprintf(procpath, sizeof(procpath),
  133. "/proc/%.20s/fd/", procentry->d_name);
  134. if ((fdd = opendir(procpath)) == NULL)
  135. continue;
  136. while ((fdentry = readdir(fdd)) != NULL) {
  137. (void)strlcpy(fdpath, procpath, sizeof(fdpath));
  138. (void)strlcat(fdpath, fdentry->d_name, sizeof(fdpath));
  139. (void)memset(linkpath, '\0', sizeof(linkpath));
  140. if (readlink(fdpath, linkpath, sizeof(linkpath)) == -1)
  141. continue;
  142. if (strcmp(linkpath, path) == 0) {
  143. ++cnt;
  144. }
  145. }
  146. (void)closedir(fdd);
  147. }
  148. (void)closedir(procd);
  149. return cnt;
  150. }
  151. #endif /* __linux__ */
  152. void gpsd_tty_init(struct gps_device_t *session)
  153. /* to be called on allocating a device */
  154. {
  155. /* mark GPS fd closed and its baud rate unknown */
  156. session->gpsdata.gps_fd = -1;
  157. session->saved_baud = -1;
  158. session->zerokill = false;
  159. session->reawake = (time_t)0;
  160. }
  161. #if !defined(HAVE_CFMAKERAW)
  162. /*
  163. * Local implementation of cfmakeraw (which is not specified by
  164. * POSIX; see matching declaration in gpsd.h).
  165. */
  166. /* Pasted from man page; added in serial.c arbitrarily */
  167. void cfmakeraw(struct termios *termios_p)
  168. {
  169. termios_p->c_iflag &=
  170. ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
  171. termios_p->c_oflag &= ~OPOST;
  172. termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
  173. termios_p->c_cflag &= ~(CSIZE | PARENB);
  174. termios_p->c_cflag |= CS8;
  175. }
  176. #endif /* !defined(HAVE_CFMAKERAW) */
  177. static speed_t gpsd_get_speed_termios(const struct termios *ttyctl)
  178. {
  179. speed_t code = cfgetospeed(ttyctl);
  180. switch (code) {
  181. case B300:
  182. return (300);
  183. case B1200:
  184. return (1200);
  185. case B2400:
  186. return (2400);
  187. case B4800:
  188. return (4800);
  189. case B9600:
  190. return (9600);
  191. case B19200:
  192. return (19200);
  193. case B38400:
  194. return (38400);
  195. case B57600:
  196. return (57600);
  197. case B115200:
  198. return (115200);
  199. case B230400:
  200. return (230400);
  201. default: /* B0 */
  202. return 0;
  203. }
  204. }
  205. speed_t gpsd_get_speed(const struct gps_device_t *dev)
  206. {
  207. return gpsd_get_speed_termios(&dev->ttyset);
  208. }
  209. speed_t gpsd_get_speed_old(const struct gps_device_t *dev)
  210. {
  211. return gpsd_get_speed_termios(&dev->ttyset_old);
  212. }
  213. char gpsd_get_parity(const struct gps_device_t *dev)
  214. {
  215. char parity = 'N';
  216. if ((dev->ttyset.c_cflag & (PARENB | PARODD)) == (PARENB | PARODD))
  217. parity = 'O';
  218. else if ((dev->ttyset.c_cflag & PARENB) == PARENB)
  219. parity = 'E';
  220. return parity;
  221. }
  222. int gpsd_get_stopbits(const struct gps_device_t *dev)
  223. {
  224. int stopbits = 0;
  225. if ((dev->ttyset.c_cflag & CS8) == CS8)
  226. stopbits = 1;
  227. else if ((dev->ttyset.c_cflag & (CS7 | CSTOPB)) == (CS7 | CSTOPB))
  228. stopbits = 2;
  229. return stopbits;
  230. }
  231. bool gpsd_set_raw(struct gps_device_t * session)
  232. {
  233. (void)cfmakeraw(&session->ttyset);
  234. if (-1 == tcsetattr(session->gpsdata.gps_fd, TCIOFLUSH, &session->ttyset)) {
  235. GPSD_LOG(LOG_ERROR, &session->context->errout,
  236. "SER: error changing port attributes: %s\n", strerror(errno));
  237. return false;
  238. }
  239. return true;
  240. }
  241. void gpsd_set_speed(struct gps_device_t *session,
  242. speed_t speed, char parity, unsigned int stopbits)
  243. {
  244. speed_t rate;
  245. struct timespec delay;
  246. if (0 < session->context->fixed_port_speed) {
  247. speed = session->context->fixed_port_speed;
  248. }
  249. if ('\0' != session->context->fixed_port_framing[0]) {
  250. // ignore length, stopbits=2 forces length 7.
  251. parity = session->context->fixed_port_framing[1];
  252. stopbits = session->context->fixed_port_framing[2] - '0';
  253. }
  254. /*
  255. * Yes, you can set speeds that aren't in the hunt loop. If you
  256. * do this, and you aren't on Linux where baud rate is preserved
  257. * across port closings, you've screwed yourself. Don't do that!
  258. */
  259. if (speed < 300)
  260. rate = B0;
  261. else if (speed < 1200)
  262. rate = B300;
  263. else if (speed < 2400)
  264. rate = B1200;
  265. else if (speed < 4800)
  266. rate = B2400;
  267. else if (speed < 9600)
  268. rate = B4800;
  269. else if (speed < 19200)
  270. rate = B9600;
  271. else if (speed < 38400)
  272. rate = B19200;
  273. else if (speed < 57600)
  274. rate = B38400;
  275. else if (speed < 115200)
  276. rate = B57600;
  277. else if (speed < 230400)
  278. rate = B115200;
  279. else
  280. rate = B230400;
  281. /* backward-compatibility hack */
  282. switch (parity) {
  283. case 'E':
  284. // FALLTHROUGH
  285. case (char)2:
  286. parity = 'E';
  287. break;
  288. case 'O':
  289. // FALLTHROUGH
  290. case (char)1:
  291. parity = 'O';
  292. break;
  293. case 'N':
  294. // FALLTHROUGH
  295. case (char)0:
  296. // FALLTHROUGH
  297. default:
  298. parity = 'N'; /* without this we might emit malformed JSON */
  299. break;
  300. }
  301. if (rate != cfgetispeed(&session->ttyset)
  302. || parity != session->gpsdata.dev.parity
  303. || stopbits != session->gpsdata.dev.stopbits) {
  304. /*
  305. * Don't mess with this conditional! Speed zero is supposed to mean
  306. * to leave the port speed at whatever it currently is. This leads
  307. * to excellent behavior on Linux, which preserves baudrate across
  308. * serial device closes - it means that if you've opened this
  309. * device before you typically don't have to hunt at all because
  310. * it's still at the same speed you left it - you'll typically
  311. * get packet lock within 1.5 seconds. Alas, the BSDs and OS X
  312. * aren't so nice.
  313. */
  314. if (rate != B0) {
  315. (void)cfsetispeed(&session->ttyset, rate);
  316. (void)cfsetospeed(&session->ttyset, rate);
  317. }
  318. session->ttyset.c_iflag &= ~(PARMRK | INPCK);
  319. session->ttyset.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
  320. session->ttyset.c_cflag |= (stopbits == 2 ? CS7 | CSTOPB : CS8);
  321. switch (parity) {
  322. case 'E':
  323. session->ttyset.c_iflag |= INPCK;
  324. session->ttyset.c_cflag |= PARENB;
  325. break;
  326. case 'O':
  327. session->ttyset.c_iflag |= INPCK;
  328. session->ttyset.c_cflag |= PARENB | PARODD;
  329. break;
  330. }
  331. if (0 != tcsetattr(session->gpsdata.gps_fd, TCSANOW,
  332. &session->ttyset)) {
  333. /* strangely this fails on non-serial ports, but if
  334. * we do not try, we get other failures.
  335. * so ignore for now, as we always have, until it can
  336. * be nailed down.
  337. *
  338. * GPSD_LOG(&session->context->errout, LOG_ERROR,
  339. * "SER: error setting port attributes: %s, sourcetype: %d\n",
  340. * strerror(errno), session->sourcetype);
  341. * return;
  342. */
  343. }
  344. /*
  345. * Serious black magic begins here. Getting this code wrong can cause
  346. * failures to lock to a correct speed, and not clean reproducible
  347. * failures but flukey hardware- and timing-dependent ones. So
  348. * be very sure you know what you're doing before hacking it, and
  349. * test thoroughly.
  350. *
  351. * The fundamental problem here is that serial devices take time
  352. * to settle into a new baud rate after tcsetattr() is issued. Until
  353. * they do so, input will be arbitarily garbled. Normally this
  354. * is not a big problem, but in our hunt loop the garbling can trash
  355. * a long enough prefix of each sample to prevent detection of a
  356. * packet header. We could address the symptom by making the sample
  357. * size enough larger that subtracting the maximum length of garble
  358. * would still leave a sample longer than the maximum packet size.
  359. * But it's better (and more efficient) to address the disease.
  360. *
  361. * In theory, one might think that not even a tcflush() call would
  362. * be needed, with tcsetattr() delaying its return until the device
  363. * is in a good state. For simple devices like a 14550 UART that
  364. * have fixed response timings this may even work, if the driver
  365. * writer was smart enough to delay the return by the right number
  366. * of milliseconds after poking the device port(s).
  367. *
  368. * Problems may arise if the driver's timings are off. Or we may
  369. * be talking to a USB device like the pl2303 commonly used in GPS
  370. * mice; on these, the change will not happen immediately because
  371. * it has to be sent as a message to the external processor that
  372. * has to act upon it, and that processor may still have buffered
  373. * data in its own FIFO. In this case the expected delay may be
  374. * too large and too variable (depending on the details of how the
  375. * USB device is integrated with its symbiont hardware) to be put
  376. * in the driver.
  377. *
  378. * So, somehow, we have to introduce a delay after tcsatattr()
  379. * returns sufficient to allow *any* device to settle. On the other
  380. * hand, a really long delay will make gpsd device registration
  381. * unpleasantly laggy.
  382. *
  383. * The classic way to address this is with a tcflush(), counting
  384. * on it to clear the device FIFO. But that call may clear only the
  385. * kernel buffers, not the device's hardware FIFO, so it may not
  386. * be sufficient by itself.
  387. *
  388. * flush followed by a 200-millisecond delay followed by flush has
  389. * been found to work reliably on the pl2303. It is also known
  390. * from testing that a 100-millisec delay is too short, allowing
  391. * occasional failure to lock.
  392. */
  393. (void)tcflush(session->gpsdata.gps_fd, TCIOFLUSH);
  394. /* wait 200,000 uSec */
  395. delay.tv_sec = 0;
  396. delay.tv_nsec = 200000000L;
  397. nanosleep(&delay, NULL);
  398. (void)tcflush(session->gpsdata.gps_fd, TCIOFLUSH);
  399. }
  400. GPSD_LOG(LOG_INF, &session->context->errout,
  401. "SER: speed %lu, %d%c%d\n",
  402. (unsigned long)gpsd_get_speed(session), 9 - stopbits, parity,
  403. stopbits);
  404. session->gpsdata.dev.baudrate = (unsigned int)speed;
  405. session->gpsdata.dev.parity = parity;
  406. session->gpsdata.dev.stopbits = stopbits;
  407. /*
  408. * The device might need a wakeup string before it will send data.
  409. * If we don't know the device type, ship it every driver's wakeup
  410. * in hopes it will respond. But not to USB or Bluetooth, because
  411. * shipping probe strings to unknown USB serial adaptors or
  412. * Bluetooth devices may spam devices that aren't GPSes at all and
  413. * could become confused.
  414. */
  415. if (!session->context->readonly
  416. && session->sourcetype != source_usb
  417. && session->sourcetype != source_bluetooth) {
  418. if (isatty(session->gpsdata.gps_fd) != 0
  419. && !session->context->readonly) {
  420. if (session->device_type == NULL) {
  421. const struct gps_type_t **dp;
  422. for (dp = gpsd_drivers; *dp; dp++)
  423. if ((*dp)->event_hook != NULL)
  424. (*dp)->event_hook(session, event_wakeup);
  425. } else if (session->device_type->event_hook != NULL)
  426. session->device_type->event_hook(session, event_wakeup);
  427. }
  428. }
  429. packet_reset(&session->lexer);
  430. }
  431. int gpsd_serial_open(struct gps_device_t *session)
  432. /* open a device for access to its data
  433. * return: the opened file descriptor
  434. * PLACEHOLDING_FD - for /dev/ppsX
  435. * UNALLOCATED_FD - for open failure
  436. */
  437. {
  438. mode_t mode = (mode_t) O_RDWR;
  439. session->sourcetype = gpsd_classify(session->gpsdata.dev.path);
  440. session->servicetype = service_sensor;
  441. /* we may need to hold on to this slot without opening the device */
  442. if (source_pps == session->sourcetype) {
  443. (void)gpsd_switch_driver(session, "PPS");
  444. return PLACEHOLDING_FD;
  445. }
  446. if (session->context->readonly
  447. || (session->sourcetype <= source_blockdev)) {
  448. mode = (mode_t) O_RDONLY;
  449. GPSD_LOG(LOG_INF, &session->context->errout,
  450. "SER: opening read-only GPS data source type %d and at '%s'\n",
  451. (int)session->sourcetype, session->gpsdata.dev.path);
  452. } else {
  453. GPSD_LOG(LOG_INF, &session->context->errout,
  454. "SER: opening GPS data source type %d at '%s'\n",
  455. (int)session->sourcetype, session->gpsdata.dev.path);
  456. }
  457. #ifdef ENABLE_BLUEZ
  458. if (bachk(session->gpsdata.dev.path) == 0) {
  459. struct sockaddr_rc addr = { 0, *BDADDR_ANY, 0};
  460. session->gpsdata.gps_fd = socket(AF_BLUETOOTH,
  461. SOCK_STREAM,
  462. BTPROTO_RFCOMM);
  463. addr.rc_family = AF_BLUETOOTH;
  464. addr.rc_channel = (uint8_t) 1;
  465. (void) str2ba(session->gpsdata.dev.path, &addr.rc_bdaddr);
  466. if (connect(session->gpsdata.gps_fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) {
  467. if (errno != EINPROGRESS && errno != EAGAIN) {
  468. (void)close(session->gpsdata.gps_fd);
  469. GPSD_LOG(LOG_ERROR, &session->context->errout,
  470. "SER: bluetooth socket connect failed: %s\n",
  471. strerror(errno));
  472. return UNALLOCATED_FD;
  473. }
  474. GPSD_LOG(LOG_ERROR, &session->context->errout,
  475. "SER: bluetooth socket connect in progress or again : %s\n",
  476. strerror(errno));
  477. }
  478. (void)fcntl(session->gpsdata.gps_fd, F_SETFL, (int)mode);
  479. GPSD_LOG(LOG_PROG, &session->context->errout,
  480. "SER: bluez device open success: %s %s\n",
  481. session->gpsdata.dev.path, strerror(errno));
  482. } else
  483. #endif /* BLUEZ */
  484. {
  485. /*
  486. * We open with O_NONBLOCK because we want to not get hung if
  487. * the CLOCAL flag is off. Need to keep O_NONBLOCK so the main
  488. * loop does not clock on an unresponsive read() from a receiver.
  489. */
  490. errno = 0;
  491. if ((session->gpsdata.gps_fd =
  492. open(session->gpsdata.dev.path,
  493. (int)(mode | O_NONBLOCK | O_NOCTTY))) == -1) {
  494. GPSD_LOG(LOG_ERROR, &session->context->errout,
  495. "SER: device open of %s failed: %s - "
  496. "retrying read-only\n",
  497. session->gpsdata.dev.path,
  498. strerror(errno));
  499. if ((session->gpsdata.gps_fd =
  500. open(session->gpsdata.dev.path,
  501. O_RDONLY | O_NONBLOCK | O_NOCTTY)) == -1) {
  502. GPSD_LOG(LOG_ERROR, &session->context->errout,
  503. "SER: read-only device open of %s failed: %s\n",
  504. session->gpsdata.dev.path,
  505. strerror(errno));
  506. return UNALLOCATED_FD;
  507. }
  508. GPSD_LOG(LOG_PROG, &session->context->errout,
  509. "SER: file device open of %s succeeded\n",
  510. session->gpsdata.dev.path);
  511. }
  512. }
  513. /*
  514. * Ideally we want to exclusion-lock the device before doing any reads.
  515. * It would have been best to do this at open(2) time, but O_EXCL
  516. * doesn't work without O_CREAT.
  517. *
  518. * We have to make an exception for ptys, which are intentionally
  519. * opened by another process on the master side, otherwise we'll
  520. * break all our regression tests.
  521. *
  522. * We also exclude bluetooth device because the bluetooth daemon opens them.
  523. */
  524. if (!(session->sourcetype == source_pty ||
  525. session->sourcetype == source_bluetooth)) {
  526. #ifdef TIOCEXCL
  527. /*
  528. * Try to block other processes from using this device while we
  529. * have it open (later opens should return EBUSY). Won't work
  530. * against anything with root privileges, alas.
  531. */
  532. (void)ioctl(session->gpsdata.gps_fd, (unsigned long)TIOCEXCL);
  533. #endif /* TIOCEXCL */
  534. #ifdef __linux__
  535. /*
  536. * Don't touch devices already opened by another process.
  537. */
  538. if (fusercount(session->gpsdata.dev.path) > 1) {
  539. GPSD_LOG(LOG_ERROR, &session->context->errout,
  540. "SER: %s already opened by another process\n",
  541. session->gpsdata.dev.path);
  542. (void)close(session->gpsdata.gps_fd);
  543. session->gpsdata.gps_fd = UNALLOCATED_FD;
  544. return UNALLOCATED_FD;
  545. }
  546. #endif /* __linux__ */
  547. }
  548. if (0 < session->context->fixed_port_speed) {
  549. session->saved_baud = session->context->fixed_port_speed;
  550. }
  551. if (session->saved_baud != -1) {
  552. (void)cfsetispeed(&session->ttyset, (speed_t)session->saved_baud);
  553. (void)cfsetospeed(&session->ttyset, (speed_t)session->saved_baud);
  554. if (0 != tcsetattr(session->gpsdata.gps_fd, TCSANOW,
  555. &session->ttyset)) {
  556. GPSD_LOG(LOG_ERROR, &session->context->errout,
  557. "SER: Error setting port attributes: %s\n",
  558. strerror(errno));
  559. }
  560. (void)tcflush(session->gpsdata.gps_fd, TCIOFLUSH);
  561. }
  562. session->lexer.type = BAD_PACKET;
  563. if ( 0 != isatty(session->gpsdata.gps_fd) ) {
  564. speed_t new_speed;
  565. char new_parity; // E, N, O
  566. unsigned int new_stop;
  567. /* Save original terminal parameters */
  568. if (tcgetattr(session->gpsdata.gps_fd, &session->ttyset_old) != 0)
  569. return UNALLOCATED_FD;
  570. session->ttyset = session->ttyset_old;
  571. /* twiddle the speed, parity, etc. but only on real serial ports */
  572. memset(session->ttyset.c_cc, 0, sizeof(session->ttyset.c_cc));
  573. //session->ttyset.c_cc[VTIME] = 1;
  574. /*
  575. * Tip from Chris Kuethe: the FIDI chip used in the Trip-Nav
  576. * 200 (and possibly other USB GPSes) gets completely hosed
  577. * in the presence of flow control. Thus, turn off CRTSCTS.
  578. *
  579. * This is not ideal. Setting no parity here will mean extra
  580. * initialization time for some devices, like certain Trimble
  581. * boards, that want 7O2 or other non-8N1 settings. But starting
  582. * the hunt loop at 8N1 will minimize the average sync time
  583. * over all devices.
  584. */
  585. session->ttyset.c_cflag &= ~(PARENB | PARODD | CRTSCTS | CSTOPB);
  586. session->ttyset.c_cflag |= CREAD | CLOCAL;
  587. session->ttyset.c_iflag = session->ttyset.c_oflag =
  588. session->ttyset.c_lflag = (tcflag_t) 0;
  589. session->baudindex = 0;
  590. if (0 < session->context->fixed_port_speed) {
  591. new_speed = session->context->fixed_port_speed;
  592. } else {
  593. new_speed = gpsd_get_speed_old(session);
  594. }
  595. if ('\0' == session->context->fixed_port_framing[0]) {
  596. new_parity = 'N';
  597. new_stop = 1;
  598. } else {
  599. // ignore length, stopbits=2 forces length 7.
  600. new_parity = session->context->fixed_port_framing[1];
  601. new_stop = session->context->fixed_port_framing[2] - '0';
  602. }
  603. gpsd_set_speed(session, new_speed, new_parity, new_stop);
  604. }
  605. /* Used to turn off O_NONBLOCK here, but best not to block trying
  606. * to read from an unresponsive receiver. */
  607. /* required so parity field won't be '\0' if saved speed matches */
  608. if (session->sourcetype <= source_blockdev) {
  609. session->gpsdata.dev.parity = 'N';
  610. session->gpsdata.dev.stopbits = 1;
  611. }
  612. GPSD_LOG(LOG_SPIN, &session->context->errout,
  613. "SER: open(%s) -> %d in gpsd_serial_open()\n",
  614. session->gpsdata.dev.path, session->gpsdata.gps_fd);
  615. return session->gpsdata.gps_fd;
  616. }
  617. ssize_t gpsd_serial_write(struct gps_device_t * session,
  618. const char *buf, const size_t len)
  619. {
  620. ssize_t status;
  621. bool ok;
  622. if (session == NULL ||
  623. session->context == NULL || session->context->readonly)
  624. return 0;
  625. status = write(session->gpsdata.gps_fd, buf, len);
  626. ok = (status == (ssize_t) len);
  627. (void)tcdrain(session->gpsdata.gps_fd);
  628. /* extra guard prevents expensive hexdump calls */
  629. if (session->context->errout.debug >= LOG_IO) {
  630. char scratchbuf[MAX_PACKET_LENGTH*2+1];
  631. GPSD_LOG(LOG_IO, &session->context->errout,
  632. "SER: => GPS: %s%s\n",
  633. gpsd_packetdump(scratchbuf, sizeof(scratchbuf),
  634. (char *)buf, len), ok ? "" : " FAILED");
  635. }
  636. return status;
  637. }
  638. /*
  639. * This constant controls how long the packet sniffer will spend looking
  640. * for a packet leader before it gives up. It *must* be larger than
  641. * MAX_PACKET_LENGTH or we risk never syncing up at all. Large values
  642. * will produce annoying startup lag.
  643. */
  644. #define SNIFF_RETRIES (MAX_PACKET_LENGTH + 128)
  645. /* advance to the next hunt setting */
  646. bool gpsd_next_hunt_setting(struct gps_device_t * session)
  647. {
  648. /* every rate we're likely to see on an old GPS */
  649. // FIXME add new rates
  650. static unsigned int rates[] =
  651. {0, 4800, 9600, 19200, 38400, 57600, 115200, 230400};
  652. char new_parity; // E, N, O
  653. unsigned int new_stop;
  654. /* don't waste time in the hunt loop if this is not actually a tty */
  655. if (0 == isatty(session->gpsdata.gps_fd))
  656. return false;
  657. /* ...or if it's nominally a tty but delivers only PPS and no data */
  658. if (session->sourcetype == source_pps)
  659. return false;
  660. if (session->lexer.retry_counter++ >= SNIFF_RETRIES) {
  661. if (0 < session->context->fixed_port_speed) {
  662. // fixed speed, don't hunt
  663. // this prevents framing hunt?
  664. return false;
  665. }
  666. if (session->baudindex++ >=
  667. (unsigned int)(sizeof(rates) / sizeof(rates[0])) - 1) {
  668. session->baudindex = 0;
  669. if ('\0' != session->context->fixed_port_framing[0]) {
  670. return false; /* hunt is over, no sync */
  671. }
  672. // More stop bits to try?
  673. if (session->gpsdata.dev.stopbits++ >= 2) {
  674. return false; /* hunt is over, no sync */
  675. }
  676. }
  677. if ('\0' == session->context->fixed_port_framing[0]) {
  678. new_parity = session->gpsdata.dev.parity;
  679. new_stop = session->gpsdata.dev.stopbits;
  680. } else {
  681. // ignore length, stopbits=2 forces length 7.
  682. new_parity = session->context->fixed_port_framing[1];
  683. new_stop = session->context->fixed_port_framing[2] - '0';
  684. }
  685. gpsd_set_speed(session, rates[session->baudindex], new_parity,
  686. new_stop);
  687. session->lexer.retry_counter = 0;
  688. }
  689. return true; /* keep hunting */
  690. }
  691. void gpsd_assert_sync(struct gps_device_t *session)
  692. /* to be called when we want to register that we've synced with a device */
  693. {
  694. /*
  695. * We've achieved first sync with the device. Remember the
  696. * baudrate so we can try it first next time this device
  697. * is opened.
  698. */
  699. if (session->saved_baud == -1)
  700. session->saved_baud = (int)cfgetispeed(&session->ttyset);
  701. }
  702. void gpsd_close(struct gps_device_t *session)
  703. {
  704. if (!BAD_SOCKET(session->gpsdata.gps_fd)) {
  705. #ifdef TIOCNXCL
  706. (void)ioctl(session->gpsdata.gps_fd, (unsigned long)TIOCNXCL);
  707. #endif /* TIOCNXCL */
  708. if (!session->context->readonly)
  709. (void)tcdrain(session->gpsdata.gps_fd);
  710. if (isatty(session->gpsdata.gps_fd) != 0) {
  711. /* force hangup on close on systems that don't do HUPCL properly */
  712. (void)cfsetispeed(&session->ttyset, (speed_t) B0);
  713. (void)cfsetospeed(&session->ttyset, (speed_t) B0);
  714. (void)tcsetattr(session->gpsdata.gps_fd, TCSANOW,
  715. &session->ttyset);
  716. }
  717. /* this is the clean way to do it */
  718. session->ttyset_old.c_cflag |= HUPCL;
  719. /*
  720. * Don't revert the serial parameters if we didn't have to mess with
  721. * them the first time. Economical, and avoids tripping over an
  722. * obscure Linux 2.6 kernel bug that disables threaded
  723. * ioctl(TIOCMWAIT) on a device after tcsetattr() is called.
  724. */
  725. if ((cfgetispeed(&session->ttyset_old) !=
  726. cfgetispeed(&session->ttyset)) ||
  727. ((session->ttyset_old.c_cflag & CSTOPB) !=
  728. (session->ttyset.c_cflag & CSTOPB))) {
  729. /*
  730. * If we revert, keep the most recent baud rate.
  731. * Cuts down on autobaud overhead the next time.
  732. */
  733. (void)cfsetispeed(&session->ttyset_old,
  734. (speed_t) session->gpsdata.dev.baudrate);
  735. (void)cfsetospeed(&session->ttyset_old,
  736. (speed_t) session->gpsdata.dev.baudrate);
  737. (void)tcsetattr(session->gpsdata.gps_fd, TCSANOW,
  738. &session->ttyset_old);
  739. }
  740. GPSD_LOG(LOG_SPIN, &session->context->errout,
  741. "SER: close(%d) in gpsd_close(%s)\n",
  742. session->gpsdata.gps_fd, session->gpsdata.dev.path);
  743. (void)close(session->gpsdata.gps_fd);
  744. session->gpsdata.gps_fd = -1;
  745. }
  746. }