Linux C Serial Port Reading/Writing -
i'm trying send/receive data on usb port using ftdi, need handle serial communication using c/c++. i'm working on linux (ubuntu).
basically, connected device listening incoming commands. need send commands , read device's response. both commands , response ascii characters.
everything works fine using gtkterm but, when switch c programming, encounter problems.
here's code:
#include <stdio.h> // standard input / output functions #include <stdlib.h> #include <string.h> // string function definitions #include <unistd.h> // unix standard function definitions #include <fcntl.h> // file control definitions #include <errno.h> // error number definitions #include <termios.h> // posix terminal control definitions /* open file descriptor */ int usb = open( "/dev/ttyusb0", o_rdwr| o_nonblock | o_ndelay ); /* error handling */ if ( usb < 0 ) { cout << "error " << errno << " opening " << "/dev/ttyusb0" << ": " << strerror (errno) << endl; } /* *** configure port *** */ struct termios tty; memset (&tty, 0, sizeof tty); /* error handling */ if ( tcgetattr ( usb, &tty ) != 0 ) { cout << "error " << errno << " tcgetattr: " << strerror(errno) << endl; } /* set baud rate */ cfsetospeed (&tty, b9600); cfsetispeed (&tty, b9600); /* setting other port stuff */ tty.c_cflag &= ~parenb; // make 8n1 tty.c_cflag &= ~cstopb; tty.c_cflag &= ~csize; tty.c_cflag |= cs8; tty.c_cflag &= ~crtscts; // no flow control tty.c_lflag = 0; // no signaling chars, no echo, no canonical processing tty.c_oflag = 0; // no remapping, no delays tty.c_cc[vmin] = 0; // read doesn't block tty.c_cc[vtime] = 5; // 0.5 seconds read timeout tty.c_cflag |= cread | clocal; // turn on read & ignore ctrl lines tty.c_iflag &= ~(ixon | ixoff | ixany);// turn off s/w flow ctrl tty.c_lflag &= ~(icanon | echo | echoe | isig); // make raw tty.c_oflag &= ~opost; // make raw /* flush port, applies attributes */ tcflush( usb, tciflush ); if ( tcsetattr ( usb, tcsanow, &tty ) != 0) { cout << "error " << errno << " tcsetattr" << endl; } /* *** write *** */ unsigned char cmd[] = {'i', 'n', 'i', 't', ' ', '\r', '\0'}; int n_written = write( usb, cmd, sizeof(cmd) -1 ); /* allocate memory read buffer */ char buf [256]; memset (&buf, '\0', sizeof buf); /* *** read *** */ int n = read( usb, &buf , sizeof buf ); /* error handling */ if (n < 0) { cout << "error reading: " << strerror(errno) << endl; } /* print read... */ cout << "read: " << buf << endl; close(usb);
what happens read()
returns 0 (no bytes read @ all) or block until timeout (vtime
). i'm assuming happens because write()
not send anything. in case, device wouldn't receive command , cannot receive response. in fact, turning off device while program blocked on reading succeded in getting response (device sends while shutting down).
strange thing adding
cout << "i've written: " << n_written << "bytes" << endl;
right after write()
call, receive:
i've written 6 bytes
which expect. program doesn't work should, my device cannot receive i'm writing on port.
i've tried different things , solution, regarding data types (i've tried using std::string, such cmd = "init \r"
or const char
) nothing worked.
can tell me i'm wrong?
thank in advance.
edit: version of code used
unsigned char cmd[] = "init \n"
and cmd[] = "init \r\n"
. changed because command sintax device reported
<command><space><cr>
.
i've tried avoiding o_nonblock
flag on reading, block until forever. i've tried using select()
nothing happens. try, i've created waiting loop until data avaliable, code never exit loop. btw, waiting or usleep()
need avoid. reported 1 excerpt of code. complete code needs work in real-time environment (specifically orocos) don't want sleep-like function.
i've solved problems, post here correct code in case needs similar stuff.
open port
int usb = open( "/dev/ttyusb0", o_rdwr| o_noctty );
set parameters
struct termios tty; struct termios tty_old; memset (&tty, 0, sizeof tty); /* error handling */ if ( tcgetattr ( usb, &tty ) != 0 ) { std::cout << "error " << errno << " tcgetattr: " << strerror(errno) << std::endl; } /* save old tty parameters */ tty_old = tty; /* set baud rate */ cfsetospeed (&tty, (speed_t)b9600); cfsetispeed (&tty, (speed_t)b9600); /* setting other port stuff */ tty.c_cflag &= ~parenb; // make 8n1 tty.c_cflag &= ~cstopb; tty.c_cflag &= ~csize; tty.c_cflag |= cs8; tty.c_cflag &= ~crtscts; // no flow control tty.c_cc[vmin] = 1; // read doesn't block tty.c_cc[vtime] = 5; // 0.5 seconds read timeout tty.c_cflag |= cread | clocal; // turn on read & ignore ctrl lines /* make raw */ cfmakeraw(&tty); /* flush port, applies attributes */ tcflush( usb, tciflush ); if ( tcsetattr ( usb, tcsanow, &tty ) != 0) { std::cout << "error " << errno << " tcsetattr" << std::endl; }
write
unsigned char cmd[] = "init \r"; int n_written = 0, spot = 0; { n_written = write( usb, &cmd[spot], 1 ); spot += n_written; } while (cmd[spot-1] != '\r' && n_written > 0);
it not necessary write byte per byte, int n_written = write( usb, cmd, sizeof(cmd) -1)
worked fine.
at last, read:
int n = 0, spot = 0; char buf = '\0'; /* whole response*/ char response[1024]; memset(response, '\0', sizeof response); { n = read( usb, &buf, 1 ); sprintf( &response[spot], "%c", buf ); spot += n; } while( buf != '\r' && n > 0); if (n < 0) { std::cout << "error reading: " << strerror(errno) << std::endl; } else if (n == 0) { std::cout << "read nothing!" << std::endl; } else { std::cout << "response: " << response << std::endl; }
this 1 worked me. thank all!
Comments
Post a Comment