diff packages/io/serial/current/src/common/serial.c @ 1214:349e2eadf98d

* src/common/serial.c: Fixed bug for XON/XOFF flow control that would cause multiple XON (or XOFF) characters to be sent for a single flow control state transition. Fixed bug in serial_write() that would cause output data to be discarded if using polled mode with flow control, and output was blocked due to flow control. Fixed bug in serial_data_xmt_req() that would not stop sending data when output was flow controlled off (hardware flow control).
author jlarmour
date Fri, 12 Sep 2003 15:32:49 +0000
parents d53522870fc0
children b300f8978722
line wrap: on
line diff
--- a/packages/io/serial/current/src/common/serial.c
+++ b/packages/io/serial/current/src/common/serial.c
@@ -164,11 +164,17 @@ static __inline__ void
 throttle_rx( serial_channel *chan, cyg_bool force )
 {
     serial_funs *funs = chan->funs;
+#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
+    cyg_uint32 prev_flags = chan->flow_desc.flags;
+#endif
 
     chan->flow_desc.flags |= CYG_SERIAL_FLOW_IN_THROTTLED;
 #ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
-    // send an xoff
-    if ( force || chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_RX ) {
+    // send an xoff if not already done (throttled)
+    if ( force ||
+        ((chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_RX) &&
+         (0==(prev_flags & CYG_SERIAL_FLOW_IN_THROTTLED))) ) {
+        CYG_ASSERT(force||(chan->flow_desc.xchar=='\0')||(chan->flow_desc.xchar==CYGDAT_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR), "xchar already set (XOFF)");
         chan->flow_desc.xchar = CYGDAT_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR;
         // Make sure xmit is running so we can send it
         (funs->start_xmit)(chan); 
@@ -193,11 +199,17 @@ static __inline__ void
 restart_rx( serial_channel *chan, cyg_bool force )
 {
     serial_funs *funs = chan->funs;
+#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
+    cyg_uint32 prev_flags = chan->flow_desc.flags;
+#endif
 
     chan->flow_desc.flags &= ~CYG_SERIAL_FLOW_IN_THROTTLED;
 #ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
-    // send an xon
-    if ( force || chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_RX ) {
+    // send an xon, if we haven't already
+    if ( force ||
+        ((chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_RX) &&
+         (prev_flags & CYG_SERIAL_FLOW_IN_THROTTLED)) ) {
+        CYG_ASSERT(force||(chan->flow_desc.xchar=='\0')||(chan->flow_desc.xchar==CYGDAT_IO_SERIAL_FLOW_CONTROL_XON_CHAR), "xchar already set (XON)");
         chan->flow_desc.xchar = CYGDAT_IO_SERIAL_FLOW_CONTROL_XON_CHAR;
         (funs->start_xmit)(chan);  // Make sure xmit is running so we can send it
     }
@@ -265,7 +277,7 @@ serial_init(serial_channel *chan)
         // But make sure it is at least 35 below buffer size, to allow
         // for 16 byte fifos, twice, plus some latency before s/w flow
         // control can kick in. This doesn't apply to h/w flow control
-        // as it is near-instaneous
+        // as it is near-instantaneous
         if ( (cbuf->len - cbuf->high_water) < 35 )
             cbuf->high_water = cbuf->len - 35;
         // and just in case...
@@ -312,7 +324,7 @@ serial_write(cyg_io_handle_t handle, con
         // Non interrupt driven (i.e. polled) operation
         while (size-- > 0) {
 #ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
-            while ( ( 0 == (chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED) ) &&
+            while ( ( 0 != (chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED) ) ||
                     ((funs->putc)(chan, *buf) == false) ) 
                 ;  // Ignore full, keep trying
 #else
@@ -1113,6 +1125,14 @@ serial_data_xmt_req(serial_channel *chan
     CYG_ASSERT(false == cbuf->block_mode_xfer_running,
                "Attempting new block transfer while another is running");
 
+#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
+    // if we're meant to be throttled, just stop and leave
+    if ( chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED ) {
+        (chan->funs->stop_xmit)(chan);  // Stop transmitting for now
+        return CYG_XMT_EMPTY;
+    }
+#endif
+
     // Available data (G = get, P = put, x = data, . = empty)
     //  0:        no data
     //  negative: xxxxP.....Gxxx        [offer last chunk only]