Make TraceSource.GetSupportedAttributes() "protected internal".
[mono-project.git] / support / serial.c
blobdab4ccc3fe7e89cd3db7251e7c204be4d46b2162
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* serial port functions
5 * Author: Chris Toshok <toshok@ximian.com>
6 */
8 #include "map.h"
9 #include "mph.h"
11 #include <termios.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <string.h>
15 #include <errno.h>
16 #if defined(__APPLE__)
17 #include "fakepoll.h"
18 #elif defined(HAVE_POLL_H)
19 #include <poll.h>
20 #elif defined(HAVE_SYS_POLL_H)
21 #include <sys/poll.h>
22 #endif
23 #include <sys/ioctl.h>
25 #include <glib.h>
27 /* This is for FIONREAD on solaris */
28 #if defined(sun)
29 #include <sys/filio.h>
30 #endif
32 /* sys/time.h (for timeval) is required when using osx 10.3 (but not 10.4) */
33 #ifdef __APPLE__
34 #include <sys/time.h>
35 #endif
37 /* This is a copy of System.IO.Ports.Handshake */
38 typedef enum {
39 NoneHandshake = 0,
40 XOnXOff = 1,
41 RequestToSend = 2,
42 RequestToSendXOnXOff = 3
43 } MonoHandshake;
45 /* This is a copy of System.IO.Ports.Parity */
46 typedef enum {
47 NoneParity = 0,
48 Odd = 1,
49 Even = 2,
50 Mark = 3,
51 Space = 4
52 } MonoParity;
54 /* This is a copy of System.IO.Ports.StopBits */
55 typedef enum {
56 NoneStopBits = 0,
57 One = 1,
58 Two = 2,
59 OnePointFive = 3
60 } MonoStopBits;
62 /* This is a copy of System.IO.Ports.SerialSignal */
63 typedef enum {
64 NoneSignal,
65 Cd = 1, /* Carrier detect */
66 Cts = 2, /* Clear to send */
67 Dsr = 4, /* Data set ready */
68 Dtr = 8, /* Data terminal ready */
69 Rts = 16 /* Request to send */
70 } MonoSerialSignal;
73 * Silence the compiler, we do not need these prototypes to be public, since these are only
74 * used by P/Invoke
77 int open_serial (char *devfile);
78 int close_serial (int unix_fd);
79 guint32 read_serial (int fd, guchar *buffer, int offset, int count);
80 int write_serial (int fd, guchar *buffer, int offset, int count, int timeout);
81 int discard_buffer (int fd, gboolean input);
82 gint32 get_bytes_in_buffer (int fd, gboolean input);
83 gboolean is_baud_rate_legal (int baud_rate);
84 int setup_baud_rate (int baud_rate);
85 gboolean set_attributes (int fd, int baud_rate, MonoParity parity, int dataBits, MonoStopBits stopBits, MonoHandshake handshake);
86 MonoSerialSignal get_signals (int fd, gint32 *error);
87 gint32 set_signal (int fd, MonoSerialSignal signal, gboolean value);
88 int breakprop (int fd);
89 gboolean poll_serial (int fd, gint32 *error, int timeout);
90 void *list_serial_devices (void);
92 int
93 open_serial (char *devfile)
95 int fd;
96 fd = open (devfile, O_RDWR | O_NOCTTY | O_NONBLOCK);
98 return fd;
102 close_serial (int unix_fd)
104 // Linus writes: do not retry close after EINTR
105 return close (unix_fd);
108 guint32
109 read_serial (int fd, guchar *buffer, int offset, int count)
111 guint32 n;
113 n = read (fd, buffer + offset, count);
115 return (guint32) n;
119 write_serial (int fd, guchar *buffer, int offset, int count, int timeout)
121 struct pollfd pinfo;
122 guint32 n;
124 pinfo.fd = fd;
125 pinfo.events = POLLOUT;
126 pinfo.revents = POLLOUT;
128 n = count;
130 while (n > 0)
132 ssize_t t;
134 if (timeout != 0) {
135 int c;
137 while ((c = poll (&pinfo, 1, timeout)) == -1 && errno == EINTR)
139 if (c == -1)
140 return -1;
143 do {
144 t = write (fd, buffer + offset, n);
145 } while (t == -1 && errno == EINTR);
147 if (t < 0)
148 return -1;
150 offset += t;
151 n -= t;
154 return 0;
158 discard_buffer (int fd, gboolean input)
160 return tcflush(fd, input ? TCIFLUSH : TCOFLUSH);
163 gint32
164 get_bytes_in_buffer (int fd, gboolean input)
166 gint32 retval;
168 if (ioctl (fd, input ? FIONREAD : TIOCOUTQ, &retval) == -1) {
169 return -1;
172 return retval;
175 gboolean
176 is_baud_rate_legal (int baud_rate)
178 return setup_baud_rate (baud_rate) != -1;
182 setup_baud_rate (int baud_rate)
184 switch (baud_rate)
186 /*Some values are not defined on OSX and *BSD */
187 #if defined(B921600)
188 case 921600:
189 baud_rate = B921600;
190 break;
191 #endif
192 #if defined(B460800)
193 case 460800:
194 baud_rate = B460800;
195 break;
196 #endif
197 case 230400:
198 baud_rate = B230400;
199 break;
200 case 115200:
201 baud_rate = B115200;
202 break;
203 case 57600:
204 baud_rate = B57600;
205 break;
206 case 38400:
207 baud_rate = B38400;
208 break;
209 case 19200:
210 baud_rate = B19200;
211 break;
212 case 9600:
213 baud_rate = B9600;
214 break;
215 case 4800:
216 baud_rate = B4800;
217 break;
218 case 2400:
219 baud_rate = B2400;
220 break;
221 case 1800:
222 baud_rate = B1800;
223 break;
224 case 1200:
225 baud_rate = B1200;
226 break;
227 case 600:
228 baud_rate = B600;
229 break;
230 case 300:
231 baud_rate = B300;
232 break;
233 case 200:
234 baud_rate = B200;
235 break;
236 case 150:
237 baud_rate = B150;
238 break;
239 case 134:
240 baud_rate = B134;
241 break;
242 case 110:
243 baud_rate = B110;
244 break;
245 case 75:
246 baud_rate = B75;
247 break;
248 case 50:
249 case 0:
250 default:
251 baud_rate = -1;
252 break;
254 return baud_rate;
257 gboolean
258 set_attributes (int fd, int baud_rate, MonoParity parity, int dataBits, MonoStopBits stopBits, MonoHandshake handshake)
260 struct termios newtio;
262 if (tcgetattr (fd, &newtio) == -1)
263 return FALSE;
265 newtio.c_cflag |= (CLOCAL | CREAD);
266 newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG | IEXTEN );
267 newtio.c_oflag &= ~(OPOST);
268 newtio.c_iflag = IGNBRK;
270 /* setup baudrate */
271 baud_rate = setup_baud_rate (baud_rate);
273 /* char lenght */
274 newtio.c_cflag &= ~CSIZE;
275 switch (dataBits)
277 case 5:
278 newtio.c_cflag |= CS5;
279 break;
280 case 6:
281 newtio.c_cflag |= CS6;
282 break;
283 case 7:
284 newtio.c_cflag |= CS7;
285 break;
286 case 8:
287 default:
288 newtio.c_cflag |= CS8;
289 break;
292 /* stopbits */
293 switch (stopBits)
295 case NoneStopBits:
296 /* Unhandled */
297 break;
298 case One: /* One */
299 /* do nothing, the default is one stop bit */
300 newtio.c_cflag &= ~CSTOPB;
301 break;
302 case Two: /* Two */
303 newtio.c_cflag |= CSTOPB;
304 break;
305 case OnePointFive: /* OnePointFive */
306 /* XXX unhandled */
307 break;
310 /* parity */
311 newtio.c_iflag &= ~(INPCK | ISTRIP );
313 switch (parity)
315 case NoneParity: /* None */
316 newtio.c_cflag &= ~(PARENB | PARODD);
317 break;
319 case Odd: /* Odd */
320 newtio.c_cflag |= PARENB | PARODD;
321 break;
323 case Even: /* Even */
324 newtio.c_cflag &= ~(PARODD);
325 newtio.c_cflag |= (PARENB);
326 break;
328 case Mark: /* Mark */
329 /* XXX unhandled */
330 break;
331 case Space: /* Space */
332 /* XXX unhandled */
333 break;
336 newtio.c_iflag &= ~(IXOFF | IXON);
337 #ifdef CRTSCTS
338 newtio.c_cflag &= ~CRTSCTS;
339 #endif /* def CRTSCTS */
341 switch (handshake)
343 case NoneHandshake: /* None */
344 /* do nothing */
345 break;
346 case RequestToSend: /* RequestToSend (RTS) */
347 #ifdef CRTSCTS
348 newtio.c_cflag |= CRTSCTS;
349 #endif /* def CRTSCTS */
350 break;
351 case RequestToSendXOnXOff: /* RequestToSendXOnXOff (RTS + XON/XOFF) */
352 #ifdef CRTSCTS
353 newtio.c_cflag |= CRTSCTS;
354 #endif /* def CRTSCTS */
355 /* fall through */
356 case XOnXOff: /* XOnXOff */
357 newtio.c_iflag |= IXOFF | IXON;
358 break;
361 if (cfsetospeed (&newtio, baud_rate) < 0 || cfsetispeed (&newtio, baud_rate) < 0 ||
362 tcsetattr (fd, TCSANOW, &newtio) < 0)
364 return FALSE;
366 else
368 return TRUE;
373 static gint32
374 get_signal_code (MonoSerialSignal signal)
376 switch (signal) {
377 case Cd:
378 return TIOCM_CAR;
379 case Cts:
380 return TIOCM_CTS;
381 case Dsr:
382 return TIOCM_DSR;
383 case Dtr:
384 return TIOCM_DTR;
385 case Rts:
386 return TIOCM_RTS;
387 default:
388 return 0;
391 /* Not reached */
392 return 0;
395 static MonoSerialSignal
396 get_mono_signal_codes (int signals)
398 MonoSerialSignal retval = NoneSignal;
400 if ((signals & TIOCM_CAR) != 0)
401 retval |= Cd;
402 if ((signals & TIOCM_CTS) != 0)
403 retval |= Cts;
404 if ((signals & TIOCM_DSR) != 0)
405 retval |= Dsr;
406 if ((signals & TIOCM_DTR) != 0)
407 retval |= Dtr;
408 if ((signals & TIOCM_RTS) != 0)
409 retval |= Rts;
411 return retval;
414 MonoSerialSignal
415 get_signals (int fd, gint32 *error)
417 int signals;
419 *error = 0;
421 if (ioctl (fd, TIOCMGET, &signals) == -1) {
422 *error = -1;
423 return NoneSignal;
426 return get_mono_signal_codes (signals);
429 gint32
430 set_signal (int fd, MonoSerialSignal signal, gboolean value)
432 int signals, expected, activated;
434 expected = get_signal_code (signal);
435 if (ioctl (fd, TIOCMGET, &signals) == -1)
436 return -1;
438 activated = (signals & expected) != 0;
439 if (activated == value) /* Already set */
440 return 1;
442 if (value)
443 signals |= expected;
444 else
445 signals &= ~expected;
447 if (ioctl (fd, TIOCMSET, &signals) == -1)
448 return -1;
450 return 1;
454 breakprop (int fd)
456 return tcsendbreak (fd, 0);
459 gboolean
460 poll_serial (int fd, gint32 *error, int timeout)
462 struct pollfd pinfo;
464 *error = 0;
466 pinfo.fd = fd;
467 pinfo.events = POLLIN;
468 pinfo.revents = 0;
470 while (poll (&pinfo, 1, timeout) == -1 && errno == EINTR) {
471 /* EINTR is an OK condition, we should not throw in the upper layer an IOException */
472 if (errno != EINTR){
473 *error = -1;
474 return FALSE;
478 return (pinfo.revents & POLLIN) != 0 ? 1 : 0;
482 * mono internals should not be used here.
483 * this serial stuff needs to be implemented with icalls.
484 * make this at least compile until the code is moved elsewhere
485 * defined(linux) is wrong, too
487 void*
488 list_serial_devices (void)
490 return NULL;
493 #if 0
494 MonoArray *
495 list_serial_devices (void)
497 MonoArray *array;
498 #if defined(linux)
499 /* Linux serial files are of the form ttyS[0-9]+ */
500 GSList *l, *list = NULL;
501 GDir* dir = g_dir_open ("/dev", 0, NULL);
502 const char *filename;
503 int i = 0;
505 while ((filename = g_dir_read_name (dir))) {
506 if (filename) {
507 if (!strncmp (filename, "ttyS", 4))
508 list = g_slist_append (list, g_strconcat ("/dev/", filename, NULL));
512 g_dir_close (dir);
514 array = mono_array_new (mono_domain_get (), mono_get_string_class (), g_slist_length (list));
515 for (l = list; l; l = l->next) {
516 mono_array_set (array, gpointer, i++, mono_string_new (mono_domain_get (), (char*)l->data));
517 g_free (l->data);
520 g_slist_free (list);
522 #else
523 #warning "list_serial_devices isn't ported to this OS"
524 #endif
526 return array;
528 #endif