Note that there are some explanatory texts on larger screens.

plurals
  1. POreading serial port blocks for unknown reason
    primarykey
    data
    text
    <p>I am trying to interface a contact-less smart card reader over UART (usbserial) using termios framework under Linux. The code works fine on the PC, but when I cross-compile and try it out on an ARM9 target, it is able to open the device and even writing the command to the device, but the read command blocks indefinitely. Here is the code snippet :</p> <pre><code>int mifare_rdr_init(struct mifare_1K * ptr, char *rdr_devnode) { bzero(ptr, sizeof(struct mifare_1K)); // zero the entire structure // open serial device int fd = open(rdr_devnode, O_RDWR|O_NOCTTY ); if (fd == -1) { perror("Failed to open serial device "); return 1; } ptr-&gt;serialfd = fd; // save file descriptor ptr-&gt;serialdev.c_iflag = 0; // no i/p flags ptr-&gt;serialdev.c_oflag = 0; // o/p flags ptr-&gt;serialdev.c_cflag = ( CS8 | CREAD | B38400 ); // 8 bits, receive enable, baud for rdr ptr-&gt;serialdev.c_lflag = ( ICANON ); // CANONICAL mode, means read till newline char '\n'. // control chars // commented below line as suggested by A.H below, since it's not needed in CANONICAL mode // ptr-&gt;serialdev.c_cc[VMIN] = 1; // read unblocks only after at least one received char. // flush all i/o garbage data if present tcflush(ptr-&gt;serialfd,TCIOFLUSH); int ret = 0; // apply settings ret = tcsetattr(ptr-&gt;serialfd,TCSANOW,&amp;ptr-&gt;serialdev); if (ret == -1) { perror("tcsetattr() failed "); return 2; } return 0; } int get_mifare_rdr_version(struct mifare_1K *ptr, char *data) { // flush all i/o garbage data if present tcflush(ptr-&gt;serialfd,TCIOFLUSH); int chars_written = write(ptr-&gt;serialfd,"$1V\n",4); if( chars_written &lt; 0 ) { perror("Failed to write serial device "); return 1; } printf("cmd sent, read version...\n"); // this prints, so I know cmd sent... int chars_read = read(ptr-&gt;serialfd,ptr-&gt;data_buf,14); if( chars_read &lt; 0 ) { perror("Failed to read serial device "); return 2; } // copy data to user buffer printf("reading done.\n"); // this doesn't print... return 0; } </code></pre> <p>The mifare_1K structure contains the file descriptor for serial device, termios structure, and various buffers I am using. The device as I mentioned is usb-to-serial ( module: ftdi_sio ) device. It's configured at 38400@8-N-1 in Canonical mode of termios.</p> <p>Canonical mode because the responses from the reader end in '\n', so its better handled in Canonical mode since it reads the device till '\n' is received (pls correct me if I'm wrong).</p> <p>First I call init() fn and then get_rdr_version(). The string "cmd sent, read version..." is printed so I know its able to write, but does not print string "reading done." after that.</p> <p>Another thing is that if I remove the card reader and connect that port to gtkterm (serial port terminal program) on another PC, I do not receive the "$1V\n" on that gtkterm ??!! . Then after a little RnD I found out that if I reboot the system on which the reader is connected reader then only I get that cmd "$1V\n" on the other Gtkterm. If I try again without a reboot, that cmd is not seen on that Gkterm...a clue, but havnt figured it out yet.</p> <p>Is it something like that the cmd is written to the device file, but not drained to the actual device ? Is there any way to chk this ?</p> <p>Any help is deeply appreciated since I've been stuck on this fr some time now....thnks.</p> <p>UPDATE :</p> <p>Ok, I have got it working by modifying the code a little as shown below.</p> <pre><code>// open serial device int fd = open(rdr_devnode, O_RDWR|O_NOCTTY|O_NDELAY ); // O_NDELAY ignores the status of DCD line, all read/write calls after this will be non-blocking fcntl(fd,F_SETFL,0); // restore read/write blocking behavior if (fd == -1) { perror("Failed to open serial device "); return 1; } </code></pre> <p>This is the modified section of the code which open the port in my init() function. Two changes : </p> <p>1) O_NDELAY is added to the flags in open() call, which ignores Data Carrier Detect (DCD) line to see if the other end is connected and ready for communication or not. This was used originally for MODEMs, which I did not need, in fact, I do not have it at all since I am using usbserial. But this flag also makes further calls to read() and write() as non-blocking. Point to note, I had thought this would be taken care of by adding CLOCAL to cflag of termios struct, which I had tried but did not work.</p> <p>2) fcntl(fd,F_SETFL,0) restores the blocking behaviour of further read() and write() calls.</p> <p>This combo is working perfectly for me. The <em>only</em> reason I am not posting this as an answer is that I do not yet understand why it worked on PC without this modification, since it was same hardware. In fact, I was able to read data from the smart card reader ON ARM9 TARGET using <strong>minicom</strong> , but not my program. I am going to check FT232BL docs to see if what is the status of DCD by default.</p> <p>Anyway, I found this bit of info on <a href="http://www.easysw.com/~mike/serial/serial.html" rel="nofollow">Serial programming Guide for POSIX operating systems</a> . Explanation anyone ??? Of course, I will post the answer when I find it out..</p> <p>Cheers :)</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload