serial.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
  2. /* serial port functions
  3. *
  4. * Author: Chris Toshok <[email protected]>
  5. */
  6. #include <termios.h>
  7. #include <unistd.h>
  8. #include <fcntl.h>
  9. #include <string.h>
  10. #include <sys/poll.h>
  11. #include <sys/ioctl.h>
  12. #include <errno.h>
  13. #include <glib.h>
  14. /* This is for FIONREAD on solaris */
  15. #if defined(sun)
  16. #include <sys/filio.h>
  17. #endif
  18. /* sys/time.h (for timeval) is required when using osx 10.3 (but not 10.4) */
  19. #ifdef __APPLE__
  20. #include <sys/time.h>
  21. #endif
  22. /* This is a copy of System.IO.Ports.Handshake */
  23. typedef enum {
  24. NoneHandshake = 0,
  25. XOnXOff = 1,
  26. RequestToSend = 2,
  27. RequestToSendXOnXOff = 3
  28. } MonoHandshake;
  29. /* This is a copy of System.IO.Ports.Parity */
  30. typedef enum {
  31. NoneParity = 0,
  32. Odd = 1,
  33. Even = 2,
  34. Mark = 3,
  35. Space = 4
  36. } MonoParity;
  37. /* This is a copy of System.IO.Ports.StopBits */
  38. typedef enum {
  39. NoneStopBits = 0,
  40. One = 1,
  41. Two = 2,
  42. OnePointFive = 3
  43. } MonoStopBits;
  44. /* This is a copy of System.IO.Ports.SerialSignal */
  45. typedef enum {
  46. NoneSignal,
  47. Cd = 1, /* Carrier detect */
  48. Cts = 2, /* Clear to send */
  49. Dsr = 4, /* Data set ready */
  50. Dtr = 8, /* Data terminal ready */
  51. Rts = 16 /* Request to send */
  52. } MonoSerialSignal;
  53. int
  54. open_serial (char* devfile)
  55. {
  56. int fd;
  57. fd = open (devfile, O_RDWR | O_NOCTTY | O_NONBLOCK);
  58. if (fd == -1)
  59. return -1;
  60. return fd;
  61. }
  62. void
  63. close_serial (int unix_fd)
  64. {
  65. close (unix_fd);
  66. }
  67. guint32
  68. read_serial (int fd, guchar *buffer, int offset, int count)
  69. {
  70. guint32 n;
  71. n = read (fd, buffer + offset, count);
  72. return (guint32) n;
  73. }
  74. int
  75. write_serial (int fd, guchar *buffer, int offset, int count, int timeout)
  76. {
  77. struct pollfd pinfo;
  78. guint32 n;
  79. pinfo.fd = fd;
  80. pinfo.events = POLLOUT;
  81. pinfo.revents = POLLOUT;
  82. n = count;
  83. while (n > 0)
  84. {
  85. size_t t;
  86. if (timeout > 0) {
  87. int c;
  88. while ((c = poll (&pinfo, 1, timeout)) == -1 && errno == EINTR)
  89. ;
  90. if (c == -1)
  91. return -1;
  92. }
  93. do {
  94. t = write (fd, buffer + offset, n);
  95. } while (t == -1 && errno == EINTR);
  96. if (t < 0)
  97. return -1;
  98. offset += t;
  99. n -= t;
  100. }
  101. return 0;
  102. }
  103. void
  104. discard_buffer (int fd, gboolean input)
  105. {
  106. tcflush(fd, input ? TCIFLUSH : TCOFLUSH);
  107. }
  108. gint32
  109. get_bytes_in_buffer (int fd, gboolean input)
  110. {
  111. gint32 retval;
  112. if (ioctl (fd, input ? FIONREAD : TIOCOUTQ, &retval) == -1) {
  113. return -1;
  114. }
  115. return retval;
  116. }
  117. gboolean
  118. set_attributes (int fd, int baud_rate, MonoParity parity, int dataBits, MonoStopBits stopBits, MonoHandshake handshake)
  119. {
  120. struct termios newtio;
  121. tcgetattr (fd, &newtio);
  122. newtio.c_cflag |= (CLOCAL | CREAD);
  123. newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG | IEXTEN );
  124. newtio.c_oflag &= ~(OPOST);
  125. newtio.c_iflag = IGNBRK;
  126. /* setup baudrate */
  127. switch (baud_rate)
  128. {
  129. case 230400:
  130. baud_rate = B230400;
  131. break;
  132. case 115200:
  133. baud_rate = B115200;
  134. break;
  135. case 57600:
  136. baud_rate = B57600;
  137. break;
  138. case 38400:
  139. baud_rate = B38400;
  140. break;
  141. case 19200:
  142. baud_rate = B19200;
  143. break;
  144. case 9600:
  145. baud_rate = B9600;
  146. break;
  147. case 4800:
  148. baud_rate = B4800;
  149. break;
  150. case 2400:
  151. baud_rate = B2400;
  152. break;
  153. case 1800:
  154. baud_rate = B1800;
  155. break;
  156. case 1200:
  157. baud_rate = B1200;
  158. break;
  159. case 600:
  160. baud_rate = B600;
  161. break;
  162. case 300:
  163. baud_rate = B300;
  164. break;
  165. case 200:
  166. baud_rate = B200;
  167. break;
  168. case 150:
  169. baud_rate = B150;
  170. break;
  171. case 134:
  172. baud_rate = B134;
  173. break;
  174. case 110:
  175. baud_rate = B110;
  176. break;
  177. case 75:
  178. baud_rate = B75;
  179. break;
  180. case 50:
  181. case 0:
  182. default:
  183. baud_rate = B9600;
  184. break;
  185. }
  186. /* char lenght */
  187. newtio.c_cflag &= ~CSIZE;
  188. switch (dataBits)
  189. {
  190. case 5:
  191. newtio.c_cflag |= CS5;
  192. break;
  193. case 6:
  194. newtio.c_cflag |= CS6;
  195. break;
  196. case 7:
  197. newtio.c_cflag |= CS7;
  198. break;
  199. case 8:
  200. default:
  201. newtio.c_cflag |= CS8;
  202. break;
  203. }
  204. /* stopbits */
  205. switch (stopBits)
  206. {
  207. case NoneStopBits:
  208. /* Unhandled */
  209. break;
  210. case One: /* One */
  211. /* do nothing, the default is one stop bit */
  212. newtio.c_cflag &= ~CSTOPB;
  213. break;
  214. case Two: /* Two */
  215. newtio.c_cflag |= CSTOPB;
  216. break;
  217. case OnePointFive: /* OnePointFive */
  218. /* XXX unhandled */
  219. break;
  220. }
  221. /* parity */
  222. newtio.c_iflag &= ~(INPCK | ISTRIP );
  223. switch (parity)
  224. {
  225. case NoneParity: /* None */
  226. newtio.c_cflag &= ~(PARENB | PARODD);
  227. break;
  228. case Odd: /* Odd */
  229. newtio.c_cflag |= PARENB | PARODD;
  230. break;
  231. case Even: /* Even */
  232. newtio.c_cflag &= ~(PARODD);
  233. newtio.c_cflag |= (PARENB);
  234. break;
  235. case Mark: /* Mark */
  236. /* XXX unhandled */
  237. break;
  238. case Space: /* Space */
  239. /* XXX unhandled */
  240. break;
  241. }
  242. newtio.c_iflag &= ~(IXOFF | IXON);
  243. #ifdef CRTSCTS
  244. newtio.c_cflag &= ~CRTSCTS;
  245. #endif /* def CRTSCTS */
  246. switch (handshake)
  247. {
  248. case NoneHandshake: /* None */
  249. /* do nothing */
  250. break;
  251. case RequestToSend: /* RequestToSend (RTS) */
  252. #ifdef CRTSCTS
  253. newtio.c_cflag |= CRTSCTS;
  254. #endif /* def CRTSCTS */
  255. break;
  256. case RequestToSendXOnXOff: /* RequestToSendXOnXOff (RTS + XON/XOFF) */
  257. #ifdef CRTSCTS
  258. newtio.c_cflag |= CRTSCTS;
  259. #endif /* def CRTSCTS */
  260. /* fall through */
  261. case XOnXOff: /* XOnXOff */
  262. newtio.c_iflag |= IXOFF | IXON;
  263. break;
  264. }
  265. if (cfsetospeed (&newtio, baud_rate) < 0 || cfsetispeed (&newtio, baud_rate) < 0 ||
  266. tcsetattr (fd, TCSANOW, &newtio) < 0)
  267. {
  268. return FALSE;
  269. }
  270. else
  271. {
  272. return TRUE;
  273. }
  274. }
  275. static gint32
  276. get_signal_code (MonoSerialSignal signal)
  277. {
  278. switch (signal) {
  279. case Cd:
  280. return TIOCM_CAR;
  281. case Cts:
  282. return TIOCM_CTS;
  283. case Dsr:
  284. return TIOCM_DSR;
  285. case Dtr:
  286. return TIOCM_DTR;
  287. case Rts:
  288. return TIOCM_RTS;
  289. default:
  290. return 0;
  291. }
  292. /* Not reached */
  293. return 0;
  294. }
  295. static MonoSerialSignal
  296. get_mono_signal_codes (int signals)
  297. {
  298. MonoSerialSignal retval = NoneSignal;
  299. if ((signals & TIOCM_CAR) != 0)
  300. retval |= Cd;
  301. if ((signals & TIOCM_CTS) != 0)
  302. retval |= Cts;
  303. if ((signals & TIOCM_DSR) != 0)
  304. retval |= Dsr;
  305. if ((signals & TIOCM_DTR) != 0)
  306. retval |= Dtr;
  307. if ((signals & TIOCM_RTS) != 0)
  308. retval |= Rts;
  309. return retval;
  310. }
  311. MonoSerialSignal
  312. get_signals (int fd, gint32 *error)
  313. {
  314. int signals;
  315. *error = 0;
  316. if (ioctl (fd, TIOCMGET, &signals) == -1) {
  317. *error = -1;
  318. return NoneSignal;
  319. }
  320. return get_mono_signal_codes (signals);
  321. }
  322. gint32
  323. set_signal (int fd, MonoSerialSignal signal, gboolean value)
  324. {
  325. int signals, expected, activated;
  326. expected = get_signal_code (signal);
  327. if (ioctl (fd, TIOCMGET, &signals) == -1)
  328. return -1;
  329. activated = (signals & expected) != 0;
  330. if (activated == value) /* Already set */
  331. return 1;
  332. if (value)
  333. signals |= expected;
  334. else
  335. signals &= ~expected;
  336. if (ioctl (fd, TIOCMSET, &signals) == -1)
  337. return -1;
  338. return 1;
  339. }
  340. void
  341. breakprop (int fd)
  342. {
  343. tcsendbreak (fd, 0);
  344. }
  345. gboolean
  346. poll_serial (int fd, gint32 *error, int timeout)
  347. {
  348. struct pollfd pinfo;
  349. *error = 0;
  350. pinfo.fd = fd;
  351. pinfo.events = POLLIN;
  352. pinfo.revents = 0;
  353. while (poll (&pinfo, 1, timeout) == -1 && errno == EINTR) {
  354. /* EINTR is an OK condition, we should not throw in the upper layer an IOException */
  355. if (errno != EINTR){
  356. *error = -1;
  357. return FALSE;
  358. }
  359. }
  360. return (pinfo.revents & POLLIN) != 0 ? 1 : 0;
  361. }
  362. /*
  363. * mono internals should not be used here.
  364. * this serial stuff needs to be implemented with icalls.
  365. * make this at least compile until the code is moved elsewhere
  366. * defined(linux) is wrong, too
  367. */
  368. void*
  369. list_serial_devices (void)
  370. {
  371. return NULL;
  372. }
  373. #if 0
  374. MonoArray *
  375. list_serial_devices (void)
  376. {
  377. MonoArray *array;
  378. #if defined(linux)
  379. /* Linux serial files are of the form ttyS[0-9]+ */
  380. GSList *l, *list = NULL;
  381. GDir* dir = g_dir_open ("/dev", 0, NULL);
  382. const char *filename;
  383. int i = 0;
  384. while ((filename = g_dir_read_name (dir))) {
  385. if (filename) {
  386. if (!strncmp (filename, "ttyS", 4))
  387. list = g_slist_append (list, g_strconcat ("/dev/", filename, NULL));
  388. }
  389. }
  390. g_dir_close (dir);
  391. array = mono_array_new (mono_domain_get (), mono_get_string_class (), g_slist_length (list));
  392. for (l = list; l; l = l->next) {
  393. mono_array_set (array, gpointer, i++, mono_string_new (mono_domain_get (), (char*)l->data));
  394. g_free (l->data);
  395. }
  396. g_slist_free (list);
  397. #else
  398. #warning "list_serial_devices isn't ported to this OS"
  399. #endif
  400. return array;
  401. }
  402. #endif