Thread: Serial port programming in Linux

  1. #1
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476

    Serial port programming in Linux

    Hi, currently I'm working on a device that was attached to a serial port (ttyS0). The device can be used as I/O to and from the computer. The input is in a form of buttons while the output is in a form of LEDs. Currently I'm still working on the output.

    I added SDL as a event handler so every time I clicked a mouse, it will blink if it was turned off or vice versa. The blinking was done by sending "fls 1 1 1\r" to the device, and turned off by sending "turnoff 1\r". The funny thing was I have to click numerous time until the mode toggle itself. For example:

    State 1: LED turned off
    > Mouse click --> mode = 1, sent "fls 1 1 1\r" to device, still in state 1
    > Mouse click --> mode = 0, sent "turnoff 1\r" to device, still in state 1
    > Mouse click --> mode = 1, sent "fls 1 1 1\r" to device, change to state 2
    State 2: LED blinked
    > Mouse click --> mode = 0, sent "turnoff 1\r" to device, still in state 2
    > Mouse click --> mode = 1, sent "fls 1 1 1\r" to device, still in state 2
    > Mouse click --> mode = 0, sent "turnoff 1\r" to device, still in state 2
    > Mouse click --> mode = 1, sent "fls 1 1 1\r" to device, still in state 2
    > Mouse click --> mode = 0, sent "turnoff 1\r" to device, change to state 1
    State 1: LED turned off
    ...
    The behaviour is not always like that. Sometimes I have to click multiple times to change the state, but sometimes one click is just what it needed. Why is this happening? BTW, my initialization step is:

    Code:
        #define BAUDRATE B4800
        #define STOPBITS	0
        #define PARITY	0
        #define PARITYON	0
    
        int fd,c, res;
        struct termios oldtio,newtio;
        struct sigaction saio;           /* definition of signal action */
        char buf[255];
    
        fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY ); 
        if (fd <0) 
        {
    	perror("/dev/ttyS0"); 
    	exit(-1); 
        }
            
    
        saio.sa_handler = signal_handler_IO;
        sigemptyset(&saio.sa_mask);  //saio.sa_mask = 0;
        saio.sa_flags = 0;
        saio.sa_restorer = NULL;
        sigaction(SIGIO,&saio,NULL);
    
        fcntl(fd, F_SETOWN, getpid());
    
        fcntl(fd, F_SETFL, FASYNC);
    
        tcgetattr(fd,&oldtio); /* save current serial port settings */
        bzero(&newtio, sizeof(newtio)); /* clear struct for new port settings */
        
        newtio.c_cflag = BAUDRATE | CS8 | STOPBITS| PARITY |PARITYON | CLOCAL | CREAD ;
    
        newtio.c_iflag = IGNPAR | ICRNL;
             
        //newtio.c_oflag = 0;
        newtio.c_oflag = OPOST|ONLCR;
    
        newtio.c_lflag = ICANON;// | ECHO | ECHOE;
            
        tcflush(fd, TCIFLUSH);
        tcsetattr(fd,TCSANOW,&newtio);

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Post your code which sends the messages.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    Here you go:

    Code:
    void Flash(bool mod, int fd)
    {
      int n;
      if (mod) // Blink
      {
    	n=write(fd,"fls 1 1 1\r",10);
             tcdrain(fd);
        	if (n < 0)
          		fputs("write() of 10 bytes failed!\n", stderr);
    
      }
      else // Turn off
      {
    	n=write(fd,"turn off 1\r",11);
             tcdrain(fd);
        	if (n < 0)
          		fputs("write() of 11 bytes failed!\n", stderr);
    
     }

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Mmm, what value does tcdrain() return?

    Also, are you also writing the code on the device at the other end, which toggles the LED in response to those messages on the serial line?

    Is your serial cable wired with CTS/RTS for hardware flow control?
    Is XON/XOFF software flow control enabled / implemented at both ends?

    Does a slower baud rate make it work more reliably?

    If the receiving module receives a garbled command, how does it recover?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    >>Mmm, what value does tcdrain() return?

    tcdrain() returned 0 so it worked

    >>Also, are you also writing the code on the device at the other end, which toggles the LED in response to those messages on the serial line?

    Yes. Not just for the LED, but for the button too for input

    >>Is your serial cable wired with CTS/RTS for hardware flow control?
    >>Is XON/XOFF software flow control enabled / implemented at both ends?

    Can't say for sure because the one who make the device wasn't me. But I think both the hardware and software flow control was disabled because it's only a NULL modem device.

    >>Does a slower baud rate make it work more reliably?

    Hasn't tested it yet

    >>If the receiving module receives a garbled command, how does it recover?

    It sends a 5 byte message containing the string "ERROR". Sadly I haven't been able to catch it too. Because the input also didn't work.

    BTW, when I tried it in minicom, it worked just fine. If I typed "fls 1 1 1" and hit enter the LED is blinking without too many tries. Also the button input works too.

    This is the minicom's settings:
    Code:
     Serial Device : /dev/ttyS0
    Lock Location : /var/lock
    Callin Program :
    Callout Program :
    Bps / Par / Bits : 4800 8N1
    Hardware Flow Control : No
    Software Flow Control : No

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Sounds to me like you're losing data.
    Typing 1 or 2 chars / sec works fine.
    Sending all 11 at program speed loses something unless you're lucky.

    Which means you need to investigate the various flow control options
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    Maybe you should check the actual number of bytes written - and retry with the rest of the buffer if it is only partyally written?

  8. #8
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    Quote Originally Posted by vart
    Maybe you should check the actual number of bytes written - and retry with the rest of the buffer if it is only partyally written?
    Sorry for the long reply. Been away for a week. How do I do that?

  9. #9
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    Quote Originally Posted by Salem
    Sounds to me like you're losing data.
    Typing 1 or 2 chars / sec works fine.
    Sending all 11 at program speed loses something unless you're lucky.

    Which means you need to investigate the various flow control options
    So, I should've sent the data with Non-Canonical Input, right?

  10. #10
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    Quote Originally Posted by g4j31a5
    How do I do that?
    Code:
    unsigned char buffer[MAX_LENGTH];
    long len = 0;
    long written = 0;
    unsigned char* ptr = buffer;
    int counter = 0;
    FILE* f = NULL;
    //here we fill buffer and initialize its len
    
    //suppose all is ready
    for(counter = 0; counter < 10; counter++)//ten retries
    {
       written = fwrite(ptr,1,len,f);
       if (written > 0)
       {
        ptr += written;
        len -= written;
        if (len <= 0)
        {
         //all is done!!
         break;
        }
        //something left
        continue;
       }
       //error?
    }
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  11. #11
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    Quote Originally Posted by vart
    Code:
    unsigned char buffer[MAX_LENGTH];
    long len = 0;
    long written = 0;
    unsigned char* ptr = buffer;
    int counter = 0;
    FILE* f = NULL;
    //here we fill buffer and initialize its len
    
    //suppose all is ready
    for(counter = 0; counter < 10; counter++)//ten retries
    {
       written = fwrite(ptr,1,len,f);
       if (written > 0)
       {
        ptr += written;
        len -= written;
        if (len <= 0)
        {
         //all is done!!
         break;
        }
        //something left
        continue;
       }
       //error?
    }

    Ok, I get it. But I think it won't work because the "write" function returned 11 (indicating all of the characters were sent successfully).

  12. #12
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > (indicating all of the characters were sent successfully).
    Well that depends, it may mean
    - sent to the driver OK
    - sent along the wire OK.

    But if the other end can't keep up and it loses characters, then it most definitely doesn't mean 11 characters received at the other end OK.

    The first thing I would put on the other end is a "loopback" mode which simply sends back to you everything it received. Until you have the loopback working correctly (you get back everything you send), figuring everything else out is a waste of time.

    > n=write(fd,"turn off 1\r",11);
    Try sending them one char at a time, with a delay between each character.

    You've already said that this works "at typing speed".

    It all points to lack of flow control IMO.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  13. #13
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    Quote Originally Posted by Salem
    > (indicating all of the characters were sent successfully).
    Well that depends, it may mean
    - sent to the driver OK
    - sent along the wire OK.

    But if the other end can't keep up and it loses characters, then it most definitely doesn't mean 11 characters received at the other end OK.

    The first thing I would put on the other end is a "loopback" mode which simply sends back to you everything it received. Until you have the loopback working correctly (you get back everything you send), figuring everything else out is a waste of time.

    > n=write(fd,"turn off 1\r",11);
    Try sending them one char at a time, with a delay between each character.

    You've already said that this works "at typing speed".

    It all points to lack of flow control IMO.
    So, non-canon it is. Ok, I'll give it a try.

  14. #14
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    canonical mode has NOTHING to do with flow control - are you even listening?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  15. #15
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    Quote Originally Posted by Salem
    canonical mode has NOTHING to do with flow control - are you even listening?
    Sory bout that. My last encounter with serial prot programming was ages ago. And that was in DOS with Turbo C. So practically I started from scratch again. And when you said about "sending them one char after another", I assumed you are talking about non-canonical input. And I don't even know how to set the flow control.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. serial port to poll on request
    By infineonintern in forum C++ Programming
    Replies: 2
    Last Post: 06-11-2009, 06:52 AM
  2. Linux serial port interrupts
    By danga1993 in forum Linux Programming
    Replies: 1
    Last Post: 04-28-2007, 11:15 AM
  3. Serial port programming in Linux
    By g4j31a5 in forum C++ Programming
    Replies: 1
    Last Post: 09-28-2006, 08:24 PM
  4. need guidance to connect to serial port
    By gnychis in forum Linux Programming
    Replies: 1
    Last Post: 06-02-2005, 10:10 AM
  5. DOS, Serial, and Touch Screen
    By jon_nc17 in forum A Brief History of Cprogramming.com
    Replies: 0
    Last Post: 01-08-2003, 04:59 PM