title: Serial programming RS485
body: <p>I have been tasked with the implementation of the ModBus protocol over a RS485 2-wire system. (Actually it's three wires, A/B and GND).
  ModBus is not the point though, but the step before that...simple I/O over the interface.</p>
  
  <p>I am using the FTDI USB-RS485 converter to connect a Linux host (not interchangeable) to a Windows host (interchangeable with another Linux host, though I'd like to avoid that)</p>
  
  <p>The encoding is supposed to be 19200, 8, n, 1.
  But it just doesn't seem to work.</p>
  
  <p>I don't have the exact code handy, but on Linux I am doing this:</p>
  
  <pre><code> int fd = open("/dev/ttyS3", O_RDWR | O_CTTY);
   if(fd == -1) return "Error while opening the port";
  </code></pre>
  
  <p>Next, I configure the port.</p>
  
  <pre><code>struct termios tty;
  
  tcgetattr(fd, &amp;tty);
  
  cfsetispeed(&amp;tty, B19200);
  cfsetospeed(&amp;tty, B19200);
  
  tty.c_cflag  = CS8;              //Empties the cflags and sets the character width.
  tty.c_cflag |= (CLOCAL | CREAD); //Sets 'recommended' options.
  
  tty.c_lflag  = 0;
  tty.c_iflag  = 0;
  tty.c_oflag  = 0;
  
  tcgetattr(fd, TCSANOW, &amp;tty);
  </code></pre>
  
  <p>Parity and Flow Control are currently not planned, since the final result will connect to a low level board, where I need to take care of the signals myself. Furthermore there aren't any wires, which would allow 'unfettered communication'. (After all I don't want an XON/XOFF character to limit the byte range I can transmit)</p>
  
  <p>All of these function go through properly and the data is set.</p>
  
  <p>On Windows, I open the serial port like this:</p>
  
  <pre><code>DCB SP;
  HANDLE hSerial = CreateFile("COM6", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
  if(hSerial == INVALID_HANDLE_VALUE) return "Error while opening the port";
  GetCommState(hSerial, &amp;SP);
  </code></pre>
  
  <p>Parity is disabled, as well as flow control. Byte size is set to 8.</p>
  
  <p>Edit:
  Since it has been asked, here is my code for the baudrate on Windows (from memory)
      SP.DCBlength= sizeof(SP);
      SP.BaudRate = 19200;
      SP.Parity   = NOPARITY;
      SP.StopBits = ONESTOPBIT;
      SetCommState(hSerial, &amp;SP);</p>
  
  <p>Again, all of these functions run flawlessly.</p>
  
  <p>Now, for the test case that's giving me a major headache.</p>
  
  <p>On the Linux host, I create a byte buffer of 256 bytes size.
  This buffer is filled with the character values from 0-255...and then sent over the wire with write.
  At the same time, the other side is waiting with 'ReadFile' for data to arrive.</p>
  
  <p>With this configuration, for both the 'other Linux host', as well as for the Windows host, 256 Bytes arrive...however it's NOT the numbers from 0-255, but something 00 06 etc.</p>
  
  <p>I can get the Linuxhost to work, when I'm setting all members of the termios structure to 0 before setting the options I actually want. I'm guessing, it's because of the control characters...however if I do that, the Windows host either receives only 4 of 256 bytes.</p>
  
  <p>As I said, unfortunately I don't have the code handy. If anyone has any idea from what point I could tackle this, I'd be very grateful. I will post more code, once I have access to it again.</p>
  
  <p>How I'm implementing the read operation:</p>
  
  <pre><code>DWORD nBytes = 0;
  char Buffer[256], *ptr = Buffer;
  int Rem = 256;
  
  while(Rem) {
      ReadFile(hSerial, ptr, Rem, &amp;nBytes, 0);
      Rem -= nBytes;
      ptr += nBytes;
  }
  
  //Evaluate Buffer
  </code></pre>
  
  <p>To be noted, I did set the timeouts, but can't remember the exact values.</p>
  
  <p>Edit: Since I now have access to my work place again, here's the actual (current) code.</p>
  
  <pre><code>const char *InitCOM(const char *TTY) {
      struct termios tty;
      hSerial = open(TTY, O_RDWR | O_NOCTTY | O_NDELAY);
      if(hSerial == -1) return "Opening of the port failed";
      fcntl(hSerial, F_SETFL, 0);
      if(tcgetattr(hSerial, &amp;tty) != 0) return "Getting the parameters failed.";
      if(cfsetispeed(&amp;tty, B19200) != 0 || cfsetospeed(&amp;tty, B19200) != 0) return "Setting the baud rate failed.";
  
  
      //CFlags
      //Note: I am full aware, that there's an '=', and that it makes the '&amp;=' obsolete, but they're in there for the sake of completeness.
      tty.c_cflag  = (tty.c_cflag &amp; ~CSIZE) | CS8;    //8-bit characters
      tty.c_cflag |= (CLOCAL | CREAD);und erlaubt 'Lesen'.
      tty.c_cflag &amp;= ~(PARENB | PARODD);          
      tty.c_cflag &amp;= ~CSTOPB;
      tty.c_cflag &amp;= ~CRTSCTS;                    
  
      //Input Flags
      tty.c_iflag     &amp;= ~IGNBRK;             
      tty.c_iflag &amp;= ~(IXON | IXOFF | IXANY);         
  
      //Local Flags
      tty.c_lflag  = 0;                   
  
      //Output Flags
      tty.c_oflag  = 0;
  
      //Control-Characters
      tty.c_cc[VMIN]   = 0;
      tty.c_cc[VTIME]  = 5;
      if(tcsetattr(hSerial, TCSAFLUSH, &amp;tty) != 0) return "Setting the new parameters failed";
  return NULL;
  </code></pre>
  
  <p>}</p>
  
  <p>As for the actual sending/receiving code: </p>
  
  <pre><code>int main(int argc, char* argv[]) {
      #if defined FOR_PC
          const char *err = InitCOM("/dev/ttyUSB0");
      #else
          const char *err = InitCOM("/dev/ttyS3");
      #endif
  
      if(err) printf("Error while initalizing: %s ErrNum: %d\n", err, errno);
      else {
      /*unsigned char C[256];    //Original code with the array
      int nBytes;
      #ifdef FOR_PC
          int Rem = 256, ReqCount = 0;
          unsigned char *ptr = C;
          while(Rem &gt; 0) {    
              fd_set fds;
              FD_ZERO(&amp;fds);
              FD_SET(hSerial, &amp;fds);
              select(hSerial+1, &amp;fds, NULL, NULL, NULL);
              nBytes = read(hSerial, ptr, Rem);
              if(nBytes &gt; 0) {
                  Rem -= nBytes;
                  ptr += nBytes;
                  ++ReqCount;
              }
          }
          printf("Number of received Bytes: %d in %d sends.\n\n", 256 - Rem, ReqCount);
          for(int i = 0; i &lt; 256; ++i) {
              printf("%02X ", C[i]);
              if((i%32) == 31) printf("\n");
          }
      #else
          for(int i = 0; i &lt; 256; ++i) C[i] = i;
          nBytes = write(hSerial, C, 256);
          printf("\nWritten Bytes: %d\n", nBytes);
      #endif*/
  
      //Single-Byte Code
      unsigned char C = 0x55;
      #ifdef FOR_PC
          while(true) {   //Keeps listening
              fd_set fds;
              FD_ZERO(&amp;fds);
              FD_SET(hSerial, &amp;fds);
              select(hSerial+1, &amp;fds, NULL, NULL, NULL);
              read(hSerial, &amp;C, 1);
              printf("Received value 0x%02X\n", C);
          }
      #else
          write(hSerial, &amp;C, 1);  //Sends one byte
      #endif
      close(hSerial);
  }
  return 0;
  </code></pre>
  
  <p>}</p>
  
  <p>As for the Oscilloscope: I've tested both directions with sending. Both did their job quite admirably.</p>
  
  <p>The signal of 0x55 is a constant Up/Down at the length of 50 microseconds (as it should, so setting the baud rate is no problem either).</p>
  
  <p>So is there anything in my 'receive' code I'm doing wrong? Is the 'select' wrong?</p>