title: Cause of serial port transmitting bad data and WriteFile return wrong number of bytes written?
body: <p>Bugfix update:
  As of Jun, 2013 FTDI did acknowledge to me that the bug was real. They have since released a new version of their driver (2.8.30.0, dated 2013-July-12) that fixes the problem. The driver made it through WHQL around the first of August, 2013 and is available via Windows Update at this time. </p>
  
  <p>I've re-tested running the same test code and am not able to reproduce the problem with the new driver, so at the moment the fix seems to be 'upgrade the driver'.</p>
  
  <p>The original question:
  I've got an 8 port USB-serial device (from VsCOM) that is based on the FTDI FT2232D chip. When I transmit at certain settings from one of the ports, AND I use the hardware handshaking to stop and start the data flow from the other end, I get two symptoms:</p>
  
  <p>1) The output data sometimes becomes garbage. There will be NUL characters, and pretty much any random thing you can think of.</p>
  
  <p>2) The WriteFile call will sometimes return a number of bytes <em>GREATER</em> than the number I asked it to write. That's not a typo. I ask for 30 bytes to be transmitted and the number of bytes sent comes back 8192 (and yes, I do clear the number sent to 0 before I make the call).</p>
  
  <p>Relevant facts:
  Using FTDI drivers 2.8.24.0, which is the latest as of today.
  Serial port settings are 19200, 7 data bits, odd parity, 1 stop bit.
  I get this same behavior with another FTDI based serial device, this time a single port one. 
  I get the same behavior with another 8 port device of the same type.
  I do NOT get this behavior when transmitting on the built-in serial ports (COM1). 
  I have a very simple 'Writer' program that just transmits continuously and a very simple 'Toggler' program that toggles RTS once per second. Together these seem to trigger the issue within 60 seconds.
  I have put an issue into the manufacturer of the device, but they've not yet had much time to respond.
  Compiler is mingw32, the one included with the Qt installer for Qt 4.8.1 (gcc 4.4.0) </p>
  
  <p>I'd like to know first off, if there's anything that anyone can think of that I could possibly do to trigger this behavior. I can't conceive of anything, but there's always things I don't know.</p>
  
  <p>Secondly, I've attached the Writer and Toggler test programs. If anyone can spot some issue that might trigger the program, I'd love to hear about it. I have a lot of trouble thinking that there is a driver bug (especially from something as mature as the FTDI chip), but the circumstances force me to think that there's at least SOME driver involvement. At the least, no matter what I do to it, it shouldn't be returning a number of bytes written greater than what I asked it to write.</p>
  
  <p>Writer program:</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;string&gt;
  
  using std::cerr;
  using std::endl;
  
  #include &lt;stdio.h&gt;
  #include &lt;windows.h&gt;
  
  
  
  int main(int argc, char **argv)
  {
      cerr &lt;&lt; "COM Writer, ctrl-c to end" &lt;&lt; endl;
  
      if (argc != 2) {
          cerr &lt;&lt; "Please specify a COM port for parameter 2";
          return 1;
      }
  
      char fixedbuf[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  
  
      std::string portName = "\\\\.\\";
      portName += argv[1];
  
      cerr &lt;&lt; "Transmitting on port " &lt;&lt; portName &lt;&lt; endl;
  
      HANDLE ph =  CreateFileA( portName.c_str(),
                                GENERIC_READ | GENERIC_WRITE,
                                0,      //  must be opened with exclusive-access
                                NULL,   //  default security attributes
                                OPEN_EXISTING, //  must use OPEN_EXISTING
                                0,      //  overlapped I/O
                                NULL ); //  hTemplate must be NULL for comm devices
  
      if (ph == INVALID_HANDLE_VALUE) {
          cerr &lt;&lt; "CreateFile " &lt;&lt; portName &lt;&lt;  " failed, error " &lt;&lt; GetLastError() &lt;&lt; endl;
          return 1;
      }
  
  
      COMMCONFIG  ccfg;
      DWORD ccfgSize = sizeof(COMMCONFIG);
      ccfg.dwSize = ccfgSize;
  
      GetCommConfig(ph, &amp;ccfg, &amp;ccfgSize);
      GetCommState(ph, &amp;(ccfg.dcb));
  
      ccfg.dcb.fBinary=TRUE;
      ccfg.dcb.fInX=FALSE;
      ccfg.dcb.fOutX=FALSE;
      ccfg.dcb.fAbortOnError=FALSE;
      ccfg.dcb.fNull=FALSE;
  
      // Camino is 19200 7-O-1
      ccfg.dcb.BaudRate = 19200;
      ccfg.dcb.Parity = ODDPARITY;
      ccfg.dcb.fParity = TRUE;
      ccfg.dcb.ByteSize = 7;
      ccfg.dcb.StopBits = ONESTOPBIT;
  
      // HW flow control
      ccfg.dcb.fOutxCtsFlow=TRUE;
      ccfg.dcb.fRtsControl=RTS_CONTROL_HANDSHAKE;
      ccfg.dcb.fInX=FALSE;
      ccfg.dcb.fOutX=FALSE;
  
      COMMTIMEOUTS ctimeout;
      DWORD tout = 10;// 10 ms
      ctimeout.ReadIntervalTimeout = tout;
      ctimeout.ReadTotalTimeoutConstant = tout;
      ctimeout.ReadTotalTimeoutMultiplier = 0;
      ctimeout.WriteTotalTimeoutMultiplier = tout;
      ctimeout.WriteTotalTimeoutConstant = 0;
  
  
      SetCommConfig(ph, &amp;ccfg, sizeof(COMMCONFIG));
      SetCommTimeouts(ph, &amp;ctimeout);
  
      DWORD nwrite = 1;
      for(;;) {
          nwrite++;
          if (nwrite &gt; 30) nwrite = 1;
  
          DWORD nwritten = 0;
          if (!WriteFile(ph, fixedbuf, nwrite, &amp;nwritten, NULL)) {
              cerr &lt;&lt; "f" &lt;&lt; endl;
          }
  
          if ((nwritten != 0) &amp;&amp; (nwritten != nwrite)) {
              cerr &lt;&lt; "nwrite: " &lt;&lt; nwrite &lt;&lt; " written: " &lt;&lt; nwritten &lt;&lt; endl;
          }
      }
  
  
      return 0;
  }
  </code></pre>
  
  <p>Toggler program:</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;string&gt;
  
  using std::cerr;
  using std::endl;
  
  #include &lt;stdio.h&gt;
  #include &lt;windows.h&gt;
  
  
  
  int main(int argc, char **argv)
  {
      cerr &lt;&lt; "COM Toggler, ctrl-c to end" &lt;&lt; endl;
      cerr &lt;&lt; "Flips the RTS line every second." &lt;&lt; endl;
  
      if (argc != 2) {
          cerr &lt;&lt; "Please specify a COM port for parameter 2";
          return 1;
      }
  
  
      std::string portName = "\\\\.\\";
      portName += argv[1];
  
      cerr &lt;&lt; "Toggling RTS on port " &lt;&lt; portName &lt;&lt; endl;
  
      HANDLE ph =  CreateFileA( portName.c_str(),
                                GENERIC_READ | GENERIC_WRITE,
                                0,      //  must be opened with exclusive-access
                                NULL,   //  default security attributes
                                OPEN_EXISTING, //  must use OPEN_EXISTING
                                0,      //  overlapped I/O
                                NULL ); //  hTemplate must be NULL for comm devices
  
      if (ph == INVALID_HANDLE_VALUE) {
          cerr &lt;&lt; "CreateFile " &lt;&lt; portName &lt;&lt;  " failed, error " &lt;&lt; GetLastError() &lt;&lt; endl;
          return 1;
      }
  
  
      COMMCONFIG  ccfg;
      DWORD ccfgSize = sizeof(COMMCONFIG);
      ccfg.dwSize = ccfgSize;
  
      GetCommConfig(ph, &amp;ccfg, &amp;ccfgSize);
      GetCommState(ph, &amp;(ccfg.dcb));
  
      ccfg.dcb.fBinary=TRUE;
      ccfg.dcb.fInX=FALSE;
      ccfg.dcb.fOutX=FALSE;
      ccfg.dcb.fAbortOnError=FALSE;
      ccfg.dcb.fNull=FALSE;
  
      // Camino is 19200 7-O-1
      ccfg.dcb.BaudRate = 19200;
      ccfg.dcb.Parity = ODDPARITY;
      ccfg.dcb.fParity = TRUE;
      ccfg.dcb.ByteSize = 7;
      ccfg.dcb.StopBits = ONESTOPBIT;
  
      // no flow control (so we can do manually)
      ccfg.dcb.fOutxCtsFlow=FALSE;
      ccfg.dcb.fRtsControl=RTS_CONTROL_DISABLE;
      ccfg.dcb.fInX=FALSE;
      ccfg.dcb.fOutX=FALSE;
  
      COMMTIMEOUTS ctimeout;
      DWORD tout = 10;// 10 ms
      ctimeout.ReadIntervalTimeout = tout;
      ctimeout.ReadTotalTimeoutConstant = tout;
      ctimeout.ReadTotalTimeoutMultiplier = 0;
      ctimeout.WriteTotalTimeoutMultiplier = tout;
      ctimeout.WriteTotalTimeoutConstant = 0;
  
  
      SetCommConfig(ph, &amp;ccfg, sizeof(COMMCONFIG));
      SetCommTimeouts(ph, &amp;ctimeout);
  
      bool rts = true;// true for set
      for(;;) {
          if (rts)
              EscapeCommFunction(ph, SETRTS);
          else
              EscapeCommFunction(ph, CLRRTS);
  
          rts = !rts;
          Sleep(1000);// 1 sec wait.
      }
  
  
      return 0;
  }
  </code></pre>