3

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 */
}

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.

Neuron
  • 5,141
  • 5
  • 38
  • 59
fedi
  • 368
  • 3
  • 7
  • 18
  • I can suggest you a good library, it is open source so you can also take inspiration from the code for your purposes: [library link](http://www.teuniz.net/RS-232/) – Niles Jun 21 '16 at 12:35
  • What is the **specific** problem? – too honest for this site Jun 21 '16 at 12:39
  • @Olaf the program is stucked in the read function, i send data via UART, but the program don't leave the read function – fedi Jun 21 '16 at 12:46
  • 1
    Please add such information and a question to the text! – too honest for this site Jun 21 '16 at 12:53
  • Open your file using `O_NONBLOCK`, then look for the return from the read function. If its a `-1`, then _[read here](http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html)_ about why – ryyker Jun 21 '16 at 13:01
  • You have `O_NDELAY` in your comments following the `open()` function, but do not use it in the argument list. Is this by design, or just an oversight? – ryyker Jun 21 '16 at 13:05
  • @ryyker, yes, the read function returns -1 – fedi Jun 21 '16 at 13:13
  • Read the links in both my comment (above) and in my answer (below). Both are at least relevant to the problem. I do not know enough about what you are seeing, or what kind of input you are providing to suggest any thing else. – ryyker Jun 21 '16 at 13:19
  • Does `/dev/ttyUSB0` represent an actual `UART` serial port, or a virtual serial port? The `USB` makes me wonder. – ryyker Jun 21 '16 at 13:24
  • yes this is the strange story, i used the same init function and then send data, data are sent succefully, however the read won't work, using printf("%s\n", strerror(errno)); i get Resource temporarily unavailable – fedi Jun 21 '16 at 13:28
  • @ryyker , what do you nmean by virtual serial port , i'am using a Virtual machine does that make a problem, if so why the send works – fedi Jun 21 '16 at 13:30
  • A USB device can use a kernel driver to _emulate_ UART functionality, making your OS think there is an actual UART (serial port). I am not sure what the impact would be between reading from an emulated UART as opposed to an actual UART. But in your reading, at least ask the question. _[Do you have your COM settings set appropriately in your virtual machine](https://www.vmware.com/support/ws3/doc/ws32_devices3.html)_? – ryyker Jun 21 '16 at 13:35
  • @ryyker ok you are right, COM port are enabled. "reading from an emulated UART " this question doesn't come to my mind since sending data works – fedi Jun 21 '16 at 13:45
  • The nature of your problem is difficult to troubleshoot without having the hardware setup in front of me. Beyond these comments, and the suggestions I made below, I am not sure how else I can help at this point. Good luck, I hope you figure it out. – ryyker Jun 21 '16 at 14:04
  • @ryyker, thanks a lot for your time. – fedi Jun 21 '16 at 14:15

3 Answers3

5

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;
sawdust
  • 16,103
  • 3
  • 40
  • 50
  • 1
    You're totally right, it seems that this is the source of the problem, i 'll try with this configuration, and update the status – fedi Jun 22 '16 at 14:56
  • what was the final solution>?can some one post? – Raulp May 12 '21 at 19:40
  • @Raulp -- For sample code using **cfmakeraw()** see https://stackoverflow.com/questions/12437593/how-to-read-a-binary-data-over-serial-terminal-in-c-program/12457195#12457195 – sawdust May 12 '21 at 20:56
1

There's an error in the read function

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

should be

bytes_read = read(fd,read_buffer,10); /* Read the data 
Illishar
  • 886
  • 1
  • 11
  • 24
  • @lllishar , i changed it but the problem still exist – fedi Jun 21 '16 at 12:47
  • @fedi - be specific about the problem. What error message, or what behavior are you seeing? – ryyker Jun 21 '16 at 12:51
  • @Illishar You are wrong here! `read_buffer` is an array, so it is also a pointer that points to the first member of the array. There is no need to preceede it with `&`. – 71GA Mar 25 '21 at 12:00
0

Your read() function may be blocked, for whatever reason. Here is a discussion on reading from a serial port, including code for blocked/unblocked settings.

It may also be possible that there is no data being transferred, leading to nothing being read. Without having access to the hardware setup, it is difficult to go further without very specific information about what you are seeing.

Also, in addition to passing the read_buffer correctly (another answer), there are at least two additional things that may improve:

1) check the return of read before using it:

bytes_read = read(fd,&read_buffer,10); /* Read the data*/
if(bytes_read > 0)
{
    ...
}

2) Change:

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

To:

//after successful read:
read_buffer[bytes_read]=0;//place null termination after last character read.
printf("%s",read_buffer);//note format specifier

This will print the number of characters read, without the loop.

Community
  • 1
  • 1
ryyker
  • 22,849
  • 3
  • 43
  • 87