Linux Reading Data from UART

fedi  picture fedi · Jun 21, 2016 · Viewed 9k times · Source

I want to read data from UART, i followed this tutorial, the write function works as expected, however i'am getting problem with the read function :

This is the uart_init function:

void uart_init()
{
 printf("\n +----------------------------------+");
 printf("\n |        Serial Port Write         |");
 printf("\n +----------------------------------+");

/*------------------------------- Opening the Serial Port -------------------------------*/

  fd = open("/dev/ttyUSB0",O_RDWR | O_NOCTTY| O_SYNC);      /* !!blocks the read  */
                                                            /* O_RDWR Read/Write access to serial port           */
                                                            /* O_NOCTTY - No terminal will control the process   */
                                                            /* O_NDELAY -Non Blocking Mode,Does not care about-  */
                                                            /* -the status of DCD line,Open() returns immediatly */                                        

 if(fd == -1)                                               /* Error Checking */
  printf("\n  Error! in Opening ttyUSB0  ");
 else
  printf("\n  ttyUSB0 Opened Successfully ");


 /*---------- Setting the Attributes of the serial port using termios structure --------- */

struct termios SerialPortSettings;          /* Create the structure                          */

tcgetattr(fd, &SerialPortSettings);         /* Get the current attributes of the Serial port */

cfsetispeed(&SerialPortSettings,B19200);        /* Set Read  Speed as 19200                       */
cfsetospeed(&SerialPortSettings,B19200);        /* Set Write Speed as 19200                       */

SerialPortSettings.c_cflag &= ~PARENB;          /* Disables the Parity   Enable bit(PARENB),So No Parity   */
SerialPortSettings.c_cflag &= ~CSTOPB;          /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
SerialPortSettings.c_cflag &= ~CSIZE;           /* Clears the mask for setting the data size             */
SerialPortSettings.c_cflag |=  CS8;             /* Set the data bits = 8                                 */

SerialPortSettings.c_cflag &= ~CRTSCTS;         /* No Hardware flow Control                         */
SerialPortSettings.c_cflag |= CREAD | CLOCAL;   /* Enable receiver,Ignore Modem Control lines       */ 


SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);          /* Disable XON/XOFF flow control both i/p and o/p */
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);  /* Non Cannonical mode                            */

SerialPortSettings.c_oflag &= ~OPOST;/*No Output Processing*/

/* Setting Time outs */
SerialPortSettings.c_cc[VMIN] = 10; /* Read at least 10 characters */
SerialPortSettings.c_cc[VTIME] = 0; /* Wait indefinetly   */

if((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0) /* Set the attributes to the termios structure*/
 printf("\n  ERROR ! in Setting attributes");
else
 printf("\n  BaudRate = 19200 \n  StopBits = 1 \n  Parity   = none");

}

the receive function :

void uart_receive()
{
 char read_buffer[32];   /* Buffer to store the data received              */
 int  bytes_read = 0;    /* Number of bytes read by the read() system call */
 int i = 0;

 bytes_read = read(fd,&read_buffer,10); /* Read the data                   */

 printf("\n\n  Bytes Rxed %d", bytes_read); /* Print the number of bytes read */
 printf("\n\n  ");

 for(i=0;i<bytes_read;i++)   /*printing only the received characters*/
 printf("%c",read_buffer[i]);

 printf("\n +----------------------------------+\n\n\n");
}

the main function :

void main(void)
{ 
  uart_init();
  /*------------------------------- Write data to serial port -----------------------------*/
  //uart_write_commande(write_buffer); //Write function works well
  uart_receive();

  close(fd);/* Close the Serial port */
}

EDIT

I execute the program and wait for data bytes to be received in UART, i send data using UART but the read function keeps blocked.

I'am using a Virtual machine with Ubunutu 14.04 on it, and i'am not sure that using an emulated UART can cause problems during reception.

Answer

sawdust picture sawdust · Jun 22, 2016

Your program is hanging in the read() syscall because it is blocked waiting for a line-termination character.
You tried to configure the port for non-canonical mode with the statement

SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);  /* Non Cannonical mode  

but that operation is on the wrong termios element.
The ICANON attribute is part of the lflag element (and not the iflag). (This error originates from the tutorial you referenced!)
Therefore your program is performing blocking canonical reads.

There's a convenient termios function for configuring non-canonical mode:

   cfmakeraw()  sets the terminal to something like the "raw" mode of the old 
   Version 7 terminal driver: input is available character by
   character, echoing is disabled, and all special processing of  
   terminal  input  and  output  characters  is  disabled.   The  terminal
   attributes are set as follows:

       termios_p->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
                       | INLCR | IGNCR | ICRNL | IXON);
       termios_p->c_oflag &= ~OPOST;
       termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
       termios_p->c_cflag &= ~(CSIZE | PARENB);
       termios_p->c_cflag |= CS8;