So I have USB port and converter cable on one side, and RS232 cable on other side.
I am trying to open COM port using CreateFile() API, and so far I managed to do this:
HANDLE dev = CreateFile(devicePath, (GENERIC_READ | GENERIC_WRITE), 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
ShowError("connectCOM()");
if (dev == INVALID_HANDLE_VALUE)
{
return false;
}
But I get AccessDenied error. I am now stuck because I am new to C programming and device communication.
What is the necessary step before calling CreateFile API in case of virtual COM port?
The first way could be like this, assuming your Serial USB convertor creates /dev/ttyUSB0, it also involves system call to set up the port :
int usbdev;
char command[10];
char response[10];
system("stty -F /dev/ttyUSB0 115200 cs8 -cstopb -parity -icanon min 1 time 1");
usbdev = open("/dev/ttyUSB0", O_RDWR);
write(usbdev, command, 2);
read(usbdev, response, 1);
close(usbdev);
Another way to implement it,
#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
int main()
{
/* Open File Descriptor */
int USB = open( "/dev/ttyUSB0", O_RDWR | O_NDELAY );
/* Error Handling */
if ( USB < 0 )
{
//cout << "Error " << errno << " opening " << "/dev/ttyUSB0" << ": " << strerror (errno) << endl;
perror("USB ");
}
/* *** Configure Port *** */
struct termios tty;
memset (&tty, 0, sizeof tty);
/* Error Handling */
if ( tcgetattr ( USB, &tty ) != 0 )
{
//cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << endl;
perror("tcgerattr ");
}
/* 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, then applies attributes */
tcflush( USB, TCIFLUSH );
if ( tcsetattr ( USB, TCSANOW, &tty ) != 0)
{
//cout << "Error " << errno << " from tcsetattr" << endl;
}
/* *** WRITE *** */
unsigned char cmd[] = {'I', 'N', 'I', 'T', ' ', '\r', '\0'};
//int n_written = write( USB, cmd, sizeof(cmd) -1 );
/* Allocate memory for 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;
perror("read error ");
}
/* Print what I read... */
//cout << "Read: " << buf << endl;
printf("%s",buf);;
close(USB);
}
My USB serial converter is in my office, not with me at the moment, so I will able to check it tomorrow,
Related
I'm using a Raspberry Pi Zero in device mode and a Raspberry Pi B in host mode. I'm connecting the two with a USB cable. My goal right now is just to send simple, arbitrary data back and forth between the two Pi's.
The problem is whichever Pi writes to the serial port first ends up reading what it wrote. The program I've written has the device send d\n and the host send h\n. So, if the device writes first, the the host reads correctly the d\n, then writes h\n to the serial port. But the device ends up reading d\n! The problem persists if I switch it so that the host writes first.
I've tried adding various tcflush calls to the program after writing but before reading, but it doesn't work. I've also tried sleeping for various amounts of time. I've read waiting 100 microseconds for each character written and I've slept for several seconds.
My setup requires me to not have a constant connection between both Pi's at the same time because of the Pi Zero's single data-capable usb port. So, to test, I'm actually plugging in a keyboard and running the program, then plugging in the proper cable to transfer data. I can transfer data, but not after writing because the program simply reads back what it wrote.
I'm starting to think I've fallen into a noob trap that I can't fathom. Here is the code I'm using:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
/*
* gcc -o device_rw -DDEVICE serial_rw.c
* gcc -o host_rw serial_rw.c
*/
#define SERIAL_DEVICE "/dev/ttyGS0"
#define SERIAL_HOST "/dev/ttyACM0"
#ifdef DEVICE
#define _TTY SERIAL_DEVICE
#else
#define _TTY SERIAL_HOST
#endif
int
set_interface_attribs(int fd, int speed)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
tty.c_iflag |= IGNPAR | IGNCR;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_iflag |= ICANON;
tty.c_iflag &= ~OPOST;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
return 0;
}
void
write_serial (int fd, const char *buf, int len)
{
printf("WRITE: %s\n", buf);
write(fd, buf, len);
}
void
read_serial (int fd, char *buf, int len)
{
ssize_t nread = read(fd, buf, len);
if (nread > 0 && nread <= len) {
buf[nread] = 0;
printf(" READ: %s\n", buf);
}
}
int
main (int argc, char **argv)
{
char buf[80];
int fd = open(_TTY, O_RDWR | O_NOCTTY);
if (fd < 0) {
fprintf(stderr, "Can't open %s: %s\n", _TTY, strerror(errno));
goto exit;
}
if (set_interface_attribs(fd, B115200) < 0) {
goto exit;
}
#ifdef DEVICE
printf("device: %s\n", _TTY);
write_serial(fd, "d\n", 2);
usleep((2 + 25) * 100);
read_serial(fd, buf, 2);
#else
printf("host: %s\n", _TTY);
read_serial(fd, buf, 2);
//usleep((2 + 25) * 100);
write_serial(fd, "h\n", 2);
#endif
close(fd);
exit:
return 0;
}
Beside not disabling the ECHO attributes (as #MarkPlotnick commented), you have two misapplied assignments:
tty.c_iflag |= ICANON;
ICANON belongs to the lflag member, and
tty.c_iflag &= ~OPOST;
OPOST belongs to the oflag member.
Considering these errors, did you properly apply #MarkPlotnick's suggestion?
See Working with linux serial port in C, Not able to get full data for a working canonical setup.
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag |= CLOCAL | CREAD;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
tty.c_lflag |= ICANON | ISIG; /* canonical input */
tty.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN);
tty.c_iflag &= ~INPCK;
tty.c_iflag |= IGNCR;
tty.c_iflag &= ~(INLCR | ICRNL | IUCLC | IMAXBEL);
tty.c_iflag &= ~(IXON | IXOFF | IXANY); /* no SW flowcontrol */
tty.c_oflag &= ~OPOST;
Note that it is also possible to have echo enabled on the far end.
To determine if the echo is generated locally or from the far end, simply disconnect the remote device (assuming you're using UARTs and/or USB-to-serial adapters), and transmit.
If you still get echo, then it's generated locally, which is controlled by the termios ECHO attributes.
If you no longer get an echo, then it's the remote unit that is repeating its input back to the sender.
BTW Your program as posted does not compile cleanly.
It's missing #include <string.h>
The termios initialization routine that you copied (but then incorrectly modified) has proper checking of return values, but your read and write routines do not check for errors.
I learned a lot from everyone's answers and am grateful for them because I will need them as I move on with this project. For this particular case, however, the issue ended up being permissions. Yep, file permissions on ttyGSO.
I completely expected a permission denied error from open and never got one, so I never considered the possibility. Especially since I opened the files in RDWR mode, I could write to the serial file, and it appeared I was reading data (although the same data) it never dawned on me that perhaps I didn't have read permissions.
Dear Colleagues.
I'm trying write C program for Linux to write serial port (Arduino) and wait for answer. I know, there was many Q about it on forum, but all I tried have the same problem - successfully write - but not read answer. For example, here and here.
I have found two separate files for write and for read.
I'm compile and run read file in one terminal window, and write file in other. Works great. But I can't merge them in one file to write and then wait for answer. The same problem - write, but not read.
Here is like I tried:
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
void main(void)
{
int fd;
fd = open("/dev/ttyS0",O_RDWR | O_NOCTTY | O_SYNC);
if(fd == -1)
printf("\n Error! in Opening ttyUSB0 ");
else
printf("\n ttyS0 Opened Successfully ");
struct termios SerialPortSettings;
tcgetattr(fd, &SerialPortSettings);
cfsetispeed(&SerialPortSettings,B9600);
cfsetospeed(&SerialPortSettings,B9600);
/* 8N1 Mode */
SerialPortSettings.c_cflag &= ~PARENB;
SerialPortSettings.c_cflag &= ~CSTOPB;
SerialPortSettings.c_cflag &= ~CSIZE;
SerialPortSettings.c_cflag |= CS8;
SerialPortSettings.c_cflag &= ~CRTSCTS;
SerialPortSettings.c_cflag |= CREAD | CLOCAL;
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
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)
printf("\n ERROR ! in Setting attributes");
else
printf("\n BaudRate = 9600 \n StopBits = 1 \n Parity = none");
char write_buffer[] = "Hello/n";
int bytes_written = 0;
printf("\n %s written to ttyUSB0",write_buffer);
printf("\n %d Bytes written to ttyUSB0", bytes_written);
printf("\n +----------------------------------+\n\n");
//tcflush(fd, TCIFLUSH); /* Discards old data in the rx buffer */
char read_buffer[32];
int bytes_read = 0;
int i = 0;
write(fd,write_buffer,sizeof(write_buffer));/* use write() to send data to port */
usleep ((8 + 25) * 100); /* Delay */
read(fd,&read_buffer,32); /* 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");
close(fd); /* Close the serial port */
}
Thanks for your help, Have a nice day.
You have a variable called bytes_read that is initialized to 0. Nothing in the code changes that value.
– user3386109
The statement read(fd,&read_buffer,32) should be corrected to bytes_read = read(fd, read_buffer, 32) …
– sawdust
My C code is sending data to Uart perfectly but while receiving it gives error.
Here is my 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>
void main()
{
int USB = open( "/dev/ttyUSB0", O_RDWR| O_NONBLOCK | O_NDELAY );
struct termios tty;
struct termios tty_old;
memset (&tty, 0, sizeof tty);
/* Error Handling */
if ( USB < 0 )
{
printf( "Error %d form tcgetattr : %s /n", errno, strerror( errno ) );
}
/* 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, then applies attributes */
tcflush( USB, TCIFLUSH );
if ( tcsetattr ( USB, TCSANOW, &tty ) != 0)
{
printf("Error %d from tcsetattr /n",errno);
// std::cout << "Error " << errno << " from tcsetattr" << std::endl;
}
/* WRITE */
unsigned char cmd[] = "YES this program is writing \r";
int n_written = 0,spot = 0;
do {
n_written = write( USB, &cmd[spot], 1 );
spot += n_written;
} while (cmd[spot-1] != '\r' && n_written > 0);
/* READ */
int n = 0,spot_r =0;
char buf = '\0';
/* Whole response*/
char response[1024];
memset(response, '\0', sizeof response);
do {
n = read( USB, &buf, 1 );
sprintf( &response[spot_r], "%c", buf );
spot_r += n;
} while( buf != '\r' && n > 0);
if (n < 0) {
printf("Error reading %s",strerror(errno));
}
else if (n==0) {
printf("read nothing");
}
else {
printf("Response %s",response);
}
}
Error Message
Error reading Resource temporarily unavailable
It is sending data to UART perfectly.
But at reception side it gives error of resource temporary unavailable.
Should i put delay in-between?
Or any other function that could help me out.
Thank you.
Abhi
I'm trying to send/receive data over an USB Port using FTDI, so I need to handle serial communication using C/C++. I'm working on Linux (Ubuntu).
Basically, I am connected to a device which is listening for incoming commands. I need to send those commands and read device's response. Both commands and response are ASCII characters.
Everything works fine using GtkTerm but, when I switch to C programming, I encounter problems.
Here's my 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 << " from 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, then applies attributes */
tcflush( USB, TCIFLUSH );
if ( tcsetattr ( USB, TCSANOW, &tty ) != 0)
{
cout << "Error " << errno << " from tcsetattr" << endl;
}
/* *** WRITE *** */
unsigned char cmd[] = {'I', 'N', 'I', 'T', ' ', '\r', '\0'};
int n_written = write( USB, cmd, sizeof(cmd) -1 );
/* Allocate memory for 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 what I read... */
cout << "Read: " << buf << endl;
close(USB);
What happens is that read() returns 0 (no bytes read at all) or block until timeout (VTIME). I'm assuming this happens because write() does not send anything. In that case, device wouldn't receive command and I cannot receive response. In fact, turning off the device while my program is blocked on reading actually succeded in getting a response (device sends something while shutting down).
Strange thing is that adding this
cout << "I've written: " << n_written << "bytes" << endl;
right after write() call, I receive:
I've written 6 bytes
which is exactly what I expect. Only my program doesn't work as it should, like my device cannot receive what I'm actually writing on port.
I've tried different things and solution, also regarding data types (I've tried using std::string, such as cmd = "INIT \r" or const char) but nothing really worked.
Can someone tell me where I'm wrong?
Thank you in advance.
EDIT:
Previously version of this code used
unsigned char cmd[] = "INIT \n"
and also cmd[] = "INIT \r\n". I changed it because command sintax for my device is reported as
<command><SPACE><CR>.
I've also tried avoiding the O_NONBLOCK flag on reading, but then I only block until forever. I've tried using select() but nothing happens. Just for a try, I've created a waiting loop until data is avaliable, but my code never exit the loop. Btw, waiting or usleep() is something I need to avoid. Reported one is only an excerpt of my code. Complete code needs to work in a real-time environment (specifically OROCOS) so I don't really want sleep-like function.
I've solved my problems, so I post here the correct code in case someone 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 << " from 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, then applies attributes */
tcflush( USB, TCIFLUSH );
if ( tcsetattr ( USB, TCSANOW, &tty ) != 0) {
std::cout << "Error " << errno << " from tcsetattr" << std::endl;
}
Write
unsigned char cmd[] = "INIT \r";
int n_written = 0,
spot = 0;
do {
n_written = write( USB, &cmd[spot], 1 );
spot += n_written;
} while (cmd[spot-1] != '\r' && n_written > 0);
It was definitely not necessary to write byte per byte, also 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);
do {
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 one worked for me. Thank you all!
Some receivers expect EOL sequence, which is typically two characters \r\n, so try in your code replace the line
unsigned char cmd[] = {'I', 'N', 'I', 'T', ' ', '\r', '\0'};
with
unsigned char cmd[] = "INIT\r\n";
BTW, the above way is probably more efficient. There is no need to quote every character.
1) I'd add a /n after init. i.e. write( USB, "init\n", 5);
2) Double check the serial port configuration. Odds are something is incorrect in there. Just because you don't use ^Q/^S or hardware flow control doesn't mean the other side isn't expecting it.
3) Most likely: Add a "usleep(100000); after the write(). The file-descriptor is set not to block or wait, right? How long does it take to get a response back before you can call read? (It has to be received and buffered by the kernel, through system hardware interrupts, before you can read() it.) Have you considered using select() to wait for something to read()? Perhaps with a timeout?
Edited to Add:
Do you need the DTR/RTS lines? Hardware flow control that tells the other side to send the computer data? e.g.
int tmp, serialLines;
cout << "Dropping Reading DTR and RTS\n";
ioctl ( readFd, TIOCMGET, & serialLines );
serialLines &= ~TIOCM_DTR;
serialLines &= ~TIOCM_RTS;
ioctl ( readFd, TIOCMSET, & serialLines );
usleep(100000);
ioctl ( readFd, TIOCMGET, & tmp );
cout << "Reading DTR status: " << (tmp & TIOCM_DTR) << endl;
sleep (2);
cout << "Setting Reading DTR and RTS\n";
serialLines |= TIOCM_DTR;
serialLines |= TIOCM_RTS;
ioctl ( readFd, TIOCMSET, & serialLines );
ioctl ( readFd, TIOCMGET, & tmp );
cout << "Reading DTR status: " << (tmp & TIOCM_DTR) << endl;
I want to connect to Cisco router from my c++ application.
Need it in order to get interface status.
My linux station (Ubuntu) and the router connected via serial interface.
connected from puty or minicom or Console Connections work.
for example:
root#test:/etc/minicom# cu -l /dev/ttyS0 -s 9600
Connected.
Router#show int summary
*: interface is up
IHQ: pkts in input hold queue IQD: pkts dropped from input queue
OHQ: pkts in output hold queue OQD: pkts dropped from output queue
RXBS: rx rate (bits/sec) RXPS: rx rate (pkts/sec)
TXBS: tx rate (bits/sec) TXPS: tx rate (pkts/sec)
TRTL: throttle count
Now i tried to do the same with C++ (or C) , but read hang.
My c code:
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <iostream>
#include<stdio.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<fcntl.h>
using namespace std;
int fd1;
int fd2;
char *buff, *buffer, *bufptr;
int wr, rd, nbytes, tries;
int configure_port(int fd) // configure the port
{
struct termios port_settings; // structure to store the port settings in
bzero(&port_settings, sizeof(port_settings));
cfsetispeed(&port_settings, B9600); // set baud rates
cfsetospeed(&port_settings, B9600);
port_settings.c_cflag &= ~PARENB; // set no parity, stop bits, data bits
port_settings.c_cflag &= ~CSTOPB;
port_settings.c_cflag &= ~CSIZE;
port_settings.c_cflag |= CS8;
tcsetattr(fd, TCSANOW, &port_settings); // apply the settings to the port
return (fd);
}
int main() {
fd1 = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd1 == -1) {
perror("open_port: Unable to open /dev/ttyS0 – ");
} else {
fcntl(fd1, F_SETFL, 0);
}
printf("Port 1 has been sucessfully opened and %d is the file description\n",fd1);
configure_port(fd1);
wr = write(fd1, "\r", 1);
cout << " wr status " << wr << endl;
wr = write(fd1, "\r", 1);
cout << " wr status " << wr << endl;
wr = write(fd1, "ena\r", 4);
cout << " wr status " << wr << endl;
wr = write(fd1, "show int sum\r", 13);
cout << " wr status " << wr << endl;
rd = read(fd1, buff, 50);
cout << " rd status " << rd << endl;
cout << rd << endl;
return 0;
}
You aren't zeroing your port_settings struct first before modifying it. That's surely a bug, though it may not be the source of your problems. Have you tried building one of the dozens of "termios sample programs" available on the intnernet for comparison?
This work - probably sleep was missing.
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <iostream>
#include<stdio.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<fcntl.h>
using namespace std;
int set_interface_attribs(int fd, int speed, int parity) {
struct termios tty;
memset(&tty, 0, sizeof tty);
if (tcgetattr(fd, &tty) != 0) {
printf("err");//error_message("error %d from tcgetattr", errno);
return -1;
}
cfsetospeed(&tty, speed);
cfsetispeed(&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // ignore break signal
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_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("err");//error_message("error %d from tcsetattr", errno);
return -1;
}
return 0;
}
void set_blocking(int fd, int should_block) {
struct termios tty;
memset(&tty, 0, sizeof tty);
if (tcgetattr(fd, &tty) != 0) {
printf("err");//error_message("error %d from tggetattr", errno);
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr(fd, TCSANOW, &tty) != 0)
printf("err");//error_message("error %d setting term attributes", errno);
}
int main(int argc, char **argv) {
char *portname = "/dev/ttyS0";
int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
printf("err");//error_message("error %d opening %s: %s", errno, portname,strerror(errno));
return -1;
}
set_interface_attribs(fd, B9600, 0); // set speed to 115,200 bps, 8n1 (no parity)
set_blocking(fd, 0); // set no blocking
write(fd, "\r", 1); // send 7 character greeting
write(fd, "\r", 1);
usleep(100000);
char buf[1000];
write(fd, "ena\r", 4);
memset(&buf, 0, sizeof buf);
usleep(100000);
write(fd, "show int sum\r", 15);
sleep(1);
memset(&buf, 0, sizeof buf);
int n = read(fd, buf, sizeof buf); // read up to 100 characters if ready to read
cout << " n " << n << endl;
cout << " buf " << buf << endl;
close(fd);
}
You should use SNMP to get interface status/statistics instead of connecting to serial console.
This is exact purpose what was SNMP designed for.