0

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;
}
Avihai Marchiano
  • 3,837
  • 3
  • 38
  • 55
  • Have you checked `port_settings` after setting it up? I notice it isn't initialized to zero ... – Useless Oct 29 '12 at 16:22
  • My first suggestion was going to be "try cu" (Linux) or "hyperterminal" (Windows). But you've done that - the RS232 connection is OK. Q: Have you tried initializing "port_settings" to zero? – paulsm4 Oct 29 '12 at 16:23
  • @paulsm4 i am new to this , can you please explain 'port_settings' to 0 ? – Avihai Marchiano Oct 29 '12 at 16:25
  • @Useless if you mean to add bzero(&port_settings, sizeof(port_settings)); than this cause to read hang . without it read failed – Avihai Marchiano Oct 29 '12 at 16:35
  • OK, so first: when read failed, what was the error? Second, if read hangs, presumably it's at least waiting successfully for data ... and I assume the correct line ending is definitely `\r`? You could `strace` both cu and your process, to compare _exactly_ what they're both writing to `/dev/ttyS0` ... – Useless Oct 29 '12 at 16:41

3 Answers3

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?

Andy Ross
  • 11,699
  • 1
  • 34
  • 31
  • I tried to zeroieng but than the read is hang. i copy my example from the internet. i also tried this example - http://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c , but read still hang – Avihai Marchiano Oct 29 '12 at 16:47
  • You can't find *any* working examples with your serial port? That seems very strange. Try running `stty < /dev/ttyS0` when minicom is running and when your (hanging) program is running and see what the difference is. Also: please prune your example program to the minimal subset. I see not reason to be clearing the file descriptor flags with `fcntl`, using non-blocking I/O or using NOCTTY for a process to be run interactively... – Andy Ross Oct 29 '12 at 16:53
0

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);
}
Avihai Marchiano
  • 3,837
  • 3
  • 38
  • 55
  • 1
    Relying on sleep or other delays to result in capturing a full reply is an unreliable implementation which could break if the connected devices replies more slowly some day. You want to read in a loop until you have received a full reply through the specified terminating character/condition, or use a read function which reads until such condition (or timeout or other fault). – Chris Stratton Nov 03 '12 at 17:46
  • @ChrisStratton can you give a reference to " read with timeout " – Avihai Marchiano Nov 03 '12 at 19:31
  • Look at select() or related syscalls as a means of implementing a data check with a timeout, and read only if they indicate data is available. Or you can put the port in non-blocking mode and poll it periodically (but beware that busy-waiting in a tight loop will hog a lot of CPU and reduce the performance of other tasks). You already seem to be setting up non-blocking I/O, so shortening the sleep and putting in a loop until a complete message is received would work - but beware of collecting the end of one message and the start of another in a single multi-byte read. – Chris Stratton Nov 03 '12 at 19:37
0

You should use SNMP to get interface status/statistics instead of connecting to serial console.

This is exact purpose what was SNMP designed for.

rkosegi
  • 14,165
  • 5
  • 50
  • 83