Support for sending serial breaks, in both the Windows and Unix
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Tue, 29 Aug 2006 18:20:57 +0000 (18:20 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Tue, 29 Aug 2006 18:20:57 +0000 (18:20 +0000)
serial backends.

git-svn-id: svn://svn.tartarus.org/sgt/putty@6832 cda61777-01e9-0310-a592-d414129be87e

unix/uxser.c
windows/winser.c

index 85e9618..db98dd8 100644 (file)
@@ -2,12 +2,6 @@
  * Serial back end (Unix-specific).
  */
 
-/*
- * TODO:
- * 
- *  - send break.
- */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
@@ -260,6 +254,11 @@ static const char *serial_init(void *frontend_handle, void **backend_handle,
 
     serial_uxsel_setup(serial);
 
+    /*
+     * Specials are always available.
+     */
+    update_specials_menu(serial->frontend);
+
     return NULL;
 }
 
@@ -418,9 +417,13 @@ static void serial_size(void *handle, int width, int height)
  */
 static void serial_special(void *handle, Telnet_Special code)
 {
-    /*
-     * FIXME: serial break? XON? XOFF?
-     */
+    Serial serial = (Serial) handle;
+
+    if (serial->fd >= 0 && code == TS_BRK) {
+       tcsendbreak(serial->fd, 0);
+       logevent(serial->frontend, "Sending serial break at user request");
+    }
+
     return;
 }
 
@@ -430,10 +433,11 @@ static void serial_special(void *handle, Telnet_Special code)
  */
 static const struct telnet_special *serial_get_specials(void *handle)
 {
-    /*
-     * FIXME: serial break? XON? XOFF?
-     */
-    return NULL;
+    static const struct telnet_special specials[] = {
+       {"Break", TS_BRK},
+       {NULL, TS_EXITMENU}
+    };
+    return specials;
 }
 
 static int serial_connected(void *handle)
index 21ff9a2..1213d4a 100644 (file)
@@ -2,17 +2,6 @@
  * Serial back end (Windows-specific).
  */
 
-/*
- * TODO:
- * 
- *  - sending breaks?
- *     + looks as if you do this by calling SetCommBreak(handle),
- *      then waiting a bit, then doing ClearCommBreak(handle). A
- *      small job for timing.c, methinks.
- *
- *  - why are we dropping data when talking to judicator?
- */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <limits.h>
@@ -26,6 +15,8 @@ typedef struct serial_backend_data {
     struct handle *out, *in;
     void *frontend;
     int bufsize;
+    long clearbreak_time;
+    int break_in_progress;
 } *Serial;
 
 static void serial_terminate(Serial serial)
@@ -39,6 +30,8 @@ static void serial_terminate(Serial serial)
        serial->in = NULL;
     }
     if (serial->port) {
+       if (serial->break_in_progress)
+           ClearCommBreak(serial->port);
        CloseHandle(serial->port);
        serial->port = NULL;
     }
@@ -218,6 +211,7 @@ static const char *serial_init(void *frontend_handle, void **backend_handle,
     serial->port = NULL;
     serial->out = serial->in = NULL;
     serial->bufsize = 0;
+    serial->break_in_progress = FALSE;
     *backend_handle = serial;
 
     serial->frontend = frontend_handle;
@@ -246,6 +240,11 @@ static const char *serial_init(void *frontend_handle, void **backend_handle,
 
     *realhost = dupstr(cfg->serline);
 
+    /*
+     * Specials are always available.
+     */
+    update_specials_menu(serial->frontend);
+
     return NULL;
 }
 
@@ -254,6 +253,7 @@ static void serial_free(void *handle)
     Serial serial = (Serial) handle;
 
     serial_terminate(serial);
+    expire_timer_context(serial);
     sfree(serial);
 }
 
@@ -301,14 +301,42 @@ static void serial_size(void *handle, int width, int height)
     return;
 }
 
+static void serbreak_timer(void *ctx, long now)
+{
+    Serial serial = (Serial)ctx;
+
+    if (now >= serial->clearbreak_time && serial->port) {
+       ClearCommBreak(serial->port);
+       serial->break_in_progress = FALSE;
+       logevent(serial->frontend, "Finished serial break");
+    }
+}
+
 /*
  * Send serial special codes.
  */
 static void serial_special(void *handle, Telnet_Special code)
 {
-    /*
-     * FIXME: serial break? XON? XOFF?
-     */
+    Serial serial = (Serial) handle;
+
+    if (serial->port && code == TS_BRK) {
+       logevent(serial->frontend, "Starting serial break at user request");
+       SetCommBreak(serial->port);
+       /*
+        * To send a serial break on Windows, we call SetCommBreak
+        * to begin the break, then wait a bit, and then call
+        * ClearCommBreak to finish it. Hence, I must use timing.c
+        * to arrange a callback when it's time to do the latter.
+        * 
+        * SUS says that a default break length must be between 1/4
+        * and 1/2 second. FreeBSD apparently goes with 2/5 second,
+        * and so will I. 
+        */
+       serial->clearbreak_time =
+           schedule_timer(TICKSPERSEC * 2 / 5, serbreak_timer, serial);
+       serial->break_in_progress = TRUE;
+    }
+
     return;
 }
 
@@ -318,10 +346,11 @@ static void serial_special(void *handle, Telnet_Special code)
  */
 static const struct telnet_special *serial_get_specials(void *handle)
 {
-    /*
-     * FIXME: serial break? XON? XOFF?
-     */
-    return NULL;
+    static const struct telnet_special specials[] = {
+       {"Break", TS_BRK},
+       {NULL, TS_EXITMENU}
+    };
+    return specials;
 }
 
 static int serial_connected(void *handle)