serial.c 7.5 KB

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