diff src/sysdep.c @ 95884:d6a4488883dc

Daniel Engeler <engeler at gmail.com> These changes add serial port access. * process.c: Add HAVE_SERIAL. (Fdelete_process, Fprocess_status, Fset_process_buffer) (Fset_process_filter, Fset_process_sentinel, Fprocess_contact) (list_processes_1, select_wrapper, Fstop_process) (Fcontinue_process, Fprocess_send_eof, kill_buffer_processes) (status_notify): Modify to handle serial processes. [HAVE_SERIAL] (Fserial_process_configure) [HAVE_SERIAL] (make_serial_process_unwind, Fmake_serial_process): New functions. * process.h (struct Lisp_Process): Add `type'. * sysdep.c [HAVE_TERMIOS] (serial_open, serial_configure): New functions. * w32.c (_sys_read_ahead, sys_read, sys_write): Modify to handle serial ports. (serial_open, serial_configure) New functions. * w32.h: Add FILE_SERIAL. (struct _child_process): Add ovl_read, ovl_write.
author Glenn Morris <rgm@gnu.org>
date Fri, 13 Jun 2008 08:08:20 +0000
parents b309a7cbf6e1
children c46e112bded0
line wrap: on
line diff
--- a/src/sysdep.c	Fri Jun 13 08:07:04 2008 +0000
+++ b/src/sysdep.c	Fri Jun 13 08:08:20 2008 +0000
@@ -166,6 +166,11 @@
 #include "process.h"
 #include "cm.h"  /* for reset_sys_modes */
 
+/* For serial_configure() and serial_open()  */
+extern Lisp_Object QCport, QCspeed, QCprocess;
+extern Lisp_Object QCbytesize, QCstopbits, QCparity, Qodd, Qeven;
+extern Lisp_Object QCflowcontrol, Qhw, Qsw, QCsummary;
+
 #ifdef WINDOWSNT
 #include <direct.h>
 /* In process.h which conflicts with the local copy.  */
@@ -5379,6 +5384,200 @@
   return signame;
 }
 #endif /* HAVE_STRSIGNAL */
+
+#ifdef HAVE_TERMIOS
+/* For make-serial-process  */
+int serial_open (char *port)
+{
+  int fd = -1;
+
+  fd = emacs_open ((char*) port,
+		   O_RDWR
+#ifdef O_NONBLOCK
+		   | O_NONBLOCK
+#else
+		   | O_NDELAY
+#endif
+#ifdef O_NOCTTY
+		   | O_NOCTTY
+#endif
+		   , 0);
+  if (fd < 0)
+    {
+      error ("Could not open %s: %s",
+	     port, emacs_strerror (errno));
+    }
+#ifdef TIOCEXCL
+  ioctl (fd, TIOCEXCL, (char *) 0);
+#endif
+
+  return fd;
+}
+#endif /* TERMIOS  */
+
+#ifdef HAVE_TERMIOS
+/* For serial-process-configure  */
+void
+serial_configure (struct Lisp_Process *p,
+		      Lisp_Object contact)
+{
+  Lisp_Object childp2 = Qnil;
+  Lisp_Object tem = Qnil;
+  struct termios attr;
+  int err = -1;
+  char summary[4] = "???"; /* This usually becomes "8N1".  */
+
+  childp2 = Fcopy_sequence (p->childp);
+
+  /* Read port attributes and prepare default configuration.  */
+  err = tcgetattr (p->outfd, &attr);
+  if (err != 0)
+    error ("tcgetattr() failed: %s", emacs_strerror (errno));
+  cfmakeraw (&attr);
+#if defined (CLOCAL)
+  attr.c_cflag |= CLOCAL;
+#endif
+#if defined (CREAD)
+  attr.c_cflag | CREAD;
+#endif
+
+  /* Configure speed.  */
+  if (!NILP (Fplist_member (contact, QCspeed)))
+    tem = Fplist_get (contact, QCspeed);
+  else
+    tem = Fplist_get (p->childp, QCspeed);
+  CHECK_NUMBER (tem);
+  err = cfsetspeed (&attr, XINT (tem));
+  if (err != 0)
+    error ("cfsetspeed(%d) failed: %s", XINT (tem), emacs_strerror (errno));
+  childp2 = Fplist_put (childp2, QCspeed, tem);
+
+  /* Configure bytesize.  */
+  if (!NILP (Fplist_member (contact, QCbytesize)))
+    tem = Fplist_get (contact, QCbytesize);
+  else
+    tem = Fplist_get (p->childp, QCbytesize);
+  if (NILP (tem))
+    tem = make_number (8);
+  CHECK_NUMBER (tem);
+  if (XINT (tem) != 7 && XINT (tem) != 8)
+    error (":bytesize must be nil (8), 7, or 8");
+  summary[0] = XINT(tem) + '0';
+#if defined (CSIZE) && defined (CS7) && defined (CS8)
+  attr.c_cflag &= ~CSIZE;
+  attr.c_cflag |= ((XINT (tem) == 7) ? CS7 : CS8);
+#else
+  /* Don't error on bytesize 8, which should be set by cfmakeraw().  */
+  if (XINT (tem) != 8)
+    error ("Bytesize cannot be changed");
+#endif
+  childp2 = Fplist_put (childp2, QCbytesize, tem);
+
+  /* Configure parity.  */
+  if (!NILP (Fplist_member (contact, QCparity)))
+    tem = Fplist_get (contact, QCparity);
+  else
+    tem = Fplist_get (p->childp, QCparity);
+  if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
+    error (":parity must be nil (no parity), `even', or `odd'");
+#if defined (PARENB) && defined (PARODD) && defined (IGNPAR) && defined (INPCK)
+  attr.c_cflag &= ~(PARENB | PARODD);
+  attr.c_iflag &= ~(IGNPAR | INPCK);
+  if (NILP (tem))
+    {
+      summary[1] = 'N';
+    }
+  else if (EQ (tem, Qeven))
+    {
+      summary[1] = 'E';
+      attr.c_cflag |= PARENB;
+      attr.c_iflag |= (IGNPAR | INPCK);
+    }
+  else if (EQ (tem, Qodd))
+    {
+      summary[1] = 'O';
+      attr.c_cflag |= (PARENB | PARODD);
+      attr.c_iflag |= (IGNPAR | INPCK);
+    }
+#else
+  /* Don't error on no parity, which should be set by cfmakeraw().  */
+  if (!NILP (tem))
+    error ("Parity cannot be configured");
+#endif
+  childp2 = Fplist_put (childp2, QCparity, tem);
+
+  /* Configure stopbits.  */
+  if (!NILP (Fplist_member (contact, QCstopbits)))
+    tem = Fplist_get (contact, QCstopbits);
+  else
+    tem = Fplist_get (p->childp, QCstopbits);
+  if (NILP (tem))
+    tem = make_number (1);
+  CHECK_NUMBER (tem);
+  if (XINT (tem) != 1 && XINT (tem) != 2)
+    error (":stopbits must be nil (1 stopbit), 1, or 2");
+  summary[2] = XINT (tem) + '0';
+#if defined (CSTOPB)
+  attr.c_cflag &= ~CSTOPB;
+  if (XINT (tem) == 2)
+    attr.c_cflag |= CSTOPB;
+#else
+  /* Don't error on 1 stopbit, which should be set by cfmakeraw().  */
+  if (XINT (tem) != 1)
+    error ("Stopbits cannot be configured");
+#endif
+  childp2 = Fplist_put (childp2, QCstopbits, tem);
+
+  /* Configure flowcontrol.  */
+  if (!NILP (Fplist_member (contact, QCflowcontrol)))
+    tem = Fplist_get (contact, QCflowcontrol);
+  else
+    tem = Fplist_get (p->childp, QCflowcontrol);
+  if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
+    error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
+#if defined (CRTSCTS)
+  attr.c_cflag &= ~CRTSCTS;
+#endif
+#if defined (CNEW_RTSCTS)
+  attr.c_cflag &= ~CNEW_RTSCTS;
+#endif
+#if defined (IXON) && defined (IXOFF)
+  attr.c_iflag &= ~(IXON | IXOFF);
+#endif
+  if (NILP (tem))
+    {
+      /* Already configured.  */
+    }
+  else if (EQ (tem, Qhw))
+    {
+#if defined (CRTSCTS)
+      attr.c_cflag |= CRTSCTS;
+#elif defined (CNEW_RTSCTS)
+      attr.c_cflag |= CNEW_RTSCTS;
+#else
+      error ("Hardware flowcontrol (RTS/CTS) not supported");
+#endif
+    }
+  else if (EQ (tem, Qsw))
+    {
+#if defined (IXON) && defined (IXOFF)
+      attr.c_iflag |= (IXON | IXOFF);
+#else
+      error ("Software flowcontrol (XON/XOFF) not supported");
+#endif
+    }
+  childp2 = Fplist_put (childp2, QCflowcontrol, tem);
+
+  /* Activate configuration.  */
+  err = tcsetattr (p->outfd, TCSANOW, &attr);
+  if (err != 0)
+    error ("tcsetattr() failed: %s", emacs_strerror (errno));
+
+  childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
+  p->childp = childp2;
+
+}
+#endif /* TERMIOS  */
 
 /* arch-tag: edb43589-4e09-4544-b325-978b5b121dcf
    (do not change this comment) */