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.

474 lines
11KB

  1. /*
  2. Serial interface for POSIX tty handling.
  3. Copyright (C) 2006 Robert Lipe, robertlipe+source@gpsbabel.org
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
  15. */
  16. #include "defs.h"
  17. #include "gbser.h"
  18. #include "gbser_private.h"
  19. #include <assert.h>
  20. #include <errno.h>
  21. #include <fcntl.h>
  22. #include <stdarg.h>
  23. #include <stdio.h>
  24. #include <sys/time.h>
  25. #include <termios.h>
  26. #include <unistd.h>
  27. typedef struct {
  28. struct termios old_tio;
  29. struct termios new_tio;
  30. int fd;
  31. unsigned vmin, vtime;
  32. unsigned long magic;
  33. unsigned char inbuf[BUFSIZE];
  34. unsigned inbuf_used;
  35. } gbser_handle;
  36. /* Wrapper to safely cast a void * into a gbser_handle */
  37. static gbser_handle* gbser__get_handle(void* p)
  38. {
  39. gbser_handle* h = (gbser_handle*) p;
  40. assert(h->magic == MYMAGIC);
  41. return h;
  42. }
  43. speed_t mkspeed(unsigned br)
  44. {
  45. switch (br) {
  46. case 1200:
  47. return B1200;
  48. case 2400:
  49. return B2400;
  50. case 4800:
  51. return B4800;
  52. case 9600:
  53. return B9600;
  54. case 19200:
  55. return B19200;
  56. case 38400:
  57. return B38400;
  58. #if defined B57600
  59. case 57600:
  60. return B57600;
  61. #endif
  62. #if defined B115200
  63. case 115200:
  64. return B115200;
  65. #endif
  66. #if defined B230400
  67. case 230400:
  68. return B230400;
  69. #endif
  70. default:
  71. fatal("Unsupported serial speed: %d\n", br);
  72. return 0; /* keep compiler happy */
  73. }
  74. }
  75. typedef struct timeval hp_time;
  76. static void get_time(hp_time* tv)
  77. {
  78. gettimeofday(tv, NULL);
  79. }
  80. static double elapsed(hp_time* tv)
  81. {
  82. hp_time now;
  83. double ot = (double) tv->tv_sec * 1000 +
  84. (double) tv->tv_usec / 1000;
  85. double nt;
  86. gettimeofday(&now, NULL);
  87. nt = (double) now.tv_sec * 1000 +
  88. (double) now.tv_usec / 1000;
  89. /*printf("elapsed -> %f\n", nt - ot);*/
  90. return nt - ot;
  91. }
  92. static int set_rx_timeout(gbser_handle* h, unsigned vmin, unsigned vtime)
  93. {
  94. if (vmin > 255) {
  95. vmin = 255;
  96. }
  97. if (vtime > 255) {
  98. vtime = 255;
  99. }
  100. if (vmin != h->vmin || vtime != h->vtime) {
  101. h->vmin = h->new_tio.c_cc[VMIN] = vmin;
  102. h->vtime = h->new_tio.c_cc[VTIME] = vtime;
  103. /*printf("VMIN=%d, VTIME=%d\n", h->vmin, h->vtime);*/
  104. return tcsetattr(h->fd, TCSANOW, &h->new_tio) ? gbser_ERROR : gbser_OK;
  105. } else {
  106. return 0;
  107. }
  108. }
  109. /* Open a serial port. |port_name| is the (platform specific) name
  110. * of the serial device to open. Under WIN32 familiar DOS port names
  111. * ('com1:') are translated into the equivalent name required by
  112. * WIN32
  113. */
  114. void* gbser_init(const char* port_name)
  115. {
  116. gbser_handle* h;
  117. gbser__db(4, "gbser_init(\"%s\")\n", port_name);
  118. h = (gbser_handle*) xcalloc(sizeof *h, 1);
  119. h->magic = MYMAGIC;
  120. h->vmin = h->vtime = 0;
  121. if (0 == strcmp(port_name, "-")) {
  122. h->fd = 0;
  123. return h;
  124. } else if (h->fd = open(port_name, O_RDWR | O_NOCTTY), h->fd == -1) {
  125. warning("Failed to open port (%s)\n", strerror(errno));
  126. goto failed;
  127. }
  128. if (!isatty(h->fd)) {
  129. warning("%s is not a TTY\n", port_name);
  130. goto failed;
  131. }
  132. if (gbser_set_port(h, 4800, 8, 0, 1)) {
  133. warning("gbser_set_port() failed\n");
  134. goto failed;
  135. }
  136. return h;
  137. failed:
  138. if (h->fd != -1) {
  139. close(h->fd);
  140. }
  141. xfree(h);
  142. return NULL;
  143. }
  144. /* Close a serial port
  145. */
  146. void gbser_deinit(void* handle)
  147. {
  148. gbser_handle* h = gbser__get_handle(handle);
  149. tcsetattr(h->fd, TCSAFLUSH, &h->old_tio);
  150. close(h->fd);
  151. xfree(h);
  152. }
  153. int gbser_set_port(void* handle, unsigned speed, unsigned bits, unsigned parity, unsigned stop)
  154. {
  155. gbser_handle* h = gbser__get_handle(handle);
  156. speed_t s;
  157. static unsigned bit_flags[] = {
  158. 0, 0, 0, 0, 0, CS5, CS6, CS7, CS8
  159. };
  160. if (bits < 5 || bits > 8) {
  161. fatal("Unsupported bits setting: %d\n", bits);
  162. }
  163. if (parity > 2) {
  164. fatal("Unsupported parity setting: %d\n", parity);
  165. }
  166. if (stop < 1 || stop > 2) {
  167. fatal("Unsupported stop setting: %d\n", stop);
  168. }
  169. s = mkspeed(speed);
  170. /* TODO: We don't /fully/ initialise the port's stat here... */
  171. tcgetattr(h->fd, &h->old_tio);
  172. h->new_tio = h->old_tio;
  173. /* clear bits */
  174. // cfmakeraw(&h->new_tio);
  175. h->new_tio.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
  176. |INLCR|IGNCR|ICRNL|IXON);
  177. h->new_tio.c_oflag &= ~OPOST;
  178. h->new_tio.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
  179. h->new_tio.c_cflag &= ~(CSIZE|PARENB);
  180. h->new_tio.c_cflag |= CS8;
  181. h->new_tio.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP |
  182. INLCR | IGNCR | IXON);
  183. h->new_tio.c_cflag &= ~(CSIZE | PARENB | PARODD | CSTOPB);
  184. /* set data bits, */
  185. h->new_tio.c_cflag |= bit_flags[bits];
  186. /* stop bits and... */
  187. if (stop == 2) {
  188. h->new_tio.c_cflag |= CSTOPB;
  189. }
  190. /* parity */
  191. if (parity != 0) {
  192. h->new_tio.c_cflag |= PARENB;
  193. if (parity == 1) {
  194. h->new_tio.c_cflag |= PARODD;
  195. }
  196. }
  197. h->new_tio.c_oflag = 0;
  198. h->new_tio.c_lflag = 0;
  199. h->new_tio.c_cc[VMIN] = h->vmin;
  200. h->new_tio.c_cc[VTIME] = h->vtime;
  201. cfsetospeed(&h->new_tio, s);
  202. cfsetispeed(&h->new_tio, s);
  203. return tcsetattr(h->fd, TCSADRAIN, &h->new_tio) ? gbser_ERROR : gbser_OK;
  204. }
  205. unsigned gbser__read_buffer(void* handle, void** buf, unsigned* len)
  206. {
  207. gbser_handle* h = gbser__get_handle(handle);
  208. unsigned count = *len;
  209. unsigned char* cp = (unsigned char*) *buf;
  210. if (count > h->inbuf_used) {
  211. count = h->inbuf_used;
  212. }
  213. memcpy(cp, h->inbuf, count);
  214. memmove(h->inbuf, h->inbuf + count,
  215. h->inbuf_used - count);
  216. h->inbuf_used -= count;
  217. *len -= count;
  218. cp += count;
  219. *buf = (void*) cp;
  220. return count;
  221. }
  222. /* Return when the input buffer contains at least |want| bytes or |*ms|
  223. * milliseconds have elapsed. |ms| may be NULL or |*ms| may be zero to
  224. * poll the port for available bytes and return immediately. |*ms| will
  225. * be updated to indicate the remaining time on exit.
  226. * Returns the number of bytes available (>=0) or an error code (<0).
  227. */
  228. int gbser__fill_buffer(void* handle, unsigned want, unsigned* ms)
  229. {
  230. int rc;
  231. gbser_handle* h = gbser__get_handle(handle);
  232. if (want > BUFSIZE) {
  233. want = BUFSIZE;
  234. }
  235. /* Already got enough bytes? */
  236. if (h->inbuf_used >= want) {
  237. return h->inbuf_used;
  238. }
  239. if (NULL == ms || 0 == *ms) {
  240. if ((rc = set_rx_timeout(h, 0, 0), rc < 0) ||
  241. (rc = read(h->fd, h->inbuf + h->inbuf_used,
  242. want - h->inbuf_used), rc < 0)) {
  243. return gbser_ERROR;
  244. }
  245. h->inbuf_used += rc;
  246. /*printf("Got %d bytes\n", rc);*/
  247. } else {
  248. double time_left = *ms;
  249. hp_time tv;
  250. get_time(&tv);
  251. for (;;) {
  252. fd_set rec;
  253. struct timeval t;
  254. time_left = *ms - elapsed(&tv);
  255. if (time_left <= 0 || h->inbuf_used >= want) {
  256. break;
  257. }
  258. FD_ZERO(&rec);
  259. FD_SET(h->fd, &rec);
  260. t.tv_sec = (time_t) time_left / 1000;
  261. t.tv_usec = ((unsigned) time_left % 1000) * 1000;
  262. if (select(h->fd + 1, &rec, NULL, NULL, &t) < 0) {
  263. return gbser_ERROR;
  264. }
  265. time_left = *ms - elapsed(&tv);
  266. if (FD_ISSET(h->fd, &rec)) {
  267. #if 0
  268. // See below comment.
  269. unsigned vmin = 0, vtime = 0;
  270. if (time_left >= 100) {
  271. vmin = want - h->inbuf_used;
  272. vtime = (unsigned) time_left / 100;
  273. }
  274. #endif
  275. // The commented out call to set_rx_timeout here is totally
  276. // legal by POSIX standards but does result in a flurry of
  277. // of tcsetattrs that slightly tweak VMIN/VTIME while there
  278. // is incoming data. This has been shown to trigger driver
  279. // bugs in the Prolific drivers for Mac and in certain Linux
  280. // kernels, thought the latter has since been fixed.
  281. // So althogh removing this means that the timeout behaviour
  282. // is actually different on POSIX and WIN32, it triggers
  283. // fewer buts this way. 2/12/2008 RJL
  284. if (/* (rc = set_rx_timeout(h, vmin, vtime), rc < 0) || */
  285. (rc = read(h->fd, h->inbuf + h->inbuf_used,
  286. want - h->inbuf_used), rc < 0)) {
  287. return gbser_ERROR;
  288. }
  289. h->inbuf_used += rc;
  290. /*printf("Got %d bytes\n", rc);*/
  291. }
  292. }
  293. *ms = (time_left < 0) ? 0 : time_left;
  294. }
  295. return h->inbuf_used;
  296. }
  297. /* Discard any pending input on the serial port.
  298. */
  299. int gbser_flush(void* handle)
  300. {
  301. gbser_handle* h = gbser__get_handle(handle);
  302. h->inbuf_used = 0;
  303. if (tcflush(h->fd, TCIFLUSH)) {
  304. return gbser_ERROR;
  305. }
  306. return gbser_OK;
  307. }
  308. /* Write |len| bytes from |buf| to the serial port.
  309. */
  310. int gbser_write(void* handle, const void* buf, unsigned len)
  311. {
  312. gbser_handle* h = gbser__get_handle(handle);
  313. const char* bp = (const char*) buf;
  314. int rc;
  315. while (len > 0) {
  316. /*printf("write(%d, %p, %d)\n", h->fd, bp, len);*/
  317. if (rc = write(h->fd, bp, len), rc < 0) {
  318. printf("rc = %d, errno = %d (%s)\n", rc, errno, strerror(errno));
  319. return gbser_ERROR;
  320. }
  321. len -= rc;
  322. bp += rc;
  323. }
  324. return gbser_OK;
  325. }
  326. /* Return true if a port name seems to refer to a serial port.
  327. * On Windows this tests the filename (against the regex
  328. * /^(\\\\\.\\\\)?com\d+:?$/i). On Posix it returns the value of
  329. * isatty()
  330. */
  331. int gbser_is_serial(const char* port_name)
  332. {
  333. int fd;
  334. int is_port = 0;
  335. if (fd = open(port_name, O_RDWR | O_NOCTTY), fd == -1) {
  336. gbser__db(1, "Failed to open port (%s) to check its type\n", strerror(errno));
  337. return 0;
  338. }
  339. is_port = isatty(fd);
  340. close(fd);
  341. return is_port;
  342. }
  343. /* This isn't part of the above abstraction; it's just a helper for
  344. * the other serial modules in the tree.
  345. *
  346. * Windows does a weird thing with serial ports.
  347. * COM ports 1 - 9 are "COM1:" through "COM9:"
  348. * The one after that is \\.\\com10 - this function tries to plaster over
  349. * that.
  350. * It returns a pointer to a staticly allocated buffer and is therefore not
  351. * thread safe. The buffer pointed to remains valid only until the next
  352. * call to this function.
  353. */
  354. const char* fix_win_serial_name_r(const char* comname, char* obuf, size_t len)
  355. {
  356. strncpy(obuf, comname, len);
  357. return obuf;
  358. }
  359. static char gb_com_buffer[100];
  360. const char* fix_win_serial_name(const char* comname)
  361. {
  362. return fix_win_serial_name_r(comname, gb_com_buffer, sizeof(gb_com_buffer));
  363. }
  364. /* Read from the serial port until the specified |eol| character is
  365. * found. Any character matching |discard| will be discarded. To
  366. * read lines terminated by 0x0A, 0x0D discarding linefeeds use
  367. * gbser_read_line(h, buf, len, 1000, 0x0D, 0x0A);
  368. * The terminating character and any discarded characters are not
  369. * stored in the buffer.
  370. */
  371. int gbser_read_line(void* handle, void* buf, unsigned len, unsigned ms, int eol, int discard)
  372. {
  373. char* bp = (char*) buf;
  374. unsigned pos = 0;
  375. hp_time tv;
  376. get_time(&tv);
  377. bp[pos] = '\0';
  378. for (;;) {
  379. signed time_left = ms - elapsed(&tv);
  380. int c;
  381. if (time_left <= 0) {
  382. return gbser_TIMEOUT;
  383. }
  384. c = gbser_readc_wait(handle, time_left);
  385. if (c == gbser_ERROR) {
  386. return c;
  387. } else if (c == eol) {
  388. return gbser_OK;
  389. }
  390. if (c != gbser_NOTHING && c != discard && pos < len - 1) {
  391. bp[pos++] = c;
  392. bp[pos] = '\0';
  393. }
  394. }
  395. }