# serial programming problem



## j4ck (Apr 4, 2013)

Hi guys
I'm trying to connect to a CISCO router using termios. I solved most of the problems with your helps in this topic: http://forums.freebsd.org/showthread.php?t=38302
There is just one problem. This is whole code:


```
int mainfd=0;
char ch[2] = {NULL};

void *writeIn(void *)
{
    char temp;
    while(1)
    {
        temp = getchar();
        ch[0] = temp;   ch[1] = '\0';
        if(temp == '~')
        {
            printf("connection closed.\r\n");
            close(mainfd);
            pthread_exit(NULL);
        }
        check=write(mainfd, ch, 1);
        ch[0]='\0';
    }
}

void *readOut(void *)
{
    char outputbuffer[10000]= {0};
    while(1)
    {
                outputbuffer[0]='\0';
                int charnumber=read(mainfd, &outputbuffer, sizeof(outputbuffer));
                outputbuffer[charnumber] = '\0';
                printf("%s",outputbuffer);
                outputbuffer[0] = '\0';
    }
}

int main(int argc,char *argv[])
{
    //////////////////
    struct termios old = {0};
    if (tcgetattr(0, &old) < 0)
        perror("tcsetattr()");
    old.c_lflag &= ~ICANON;
    old.c_lflag &= ~ECHO;
    old.c_cc[VMIN] = 1;
    old.c_cc[VTIME] = 0;
    if (tcsetattr(0, TCSANOW, &old) < 0)
         perror("tcsetattr ICANON");
    //////////////////
    struct termios options;
    static int portnum=atoi(argv[1]);

    mainfd = open_port(portnum);

    fcntl(mainfd, F_SETFL, FNDELAY);  
    tcgetattr(mainfd, &options);
    cfsetspeed(&options, speed);
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~PARENB;
    options.c_cflag |= CSTOPB;

    options.c_cflag &= ~CSIZE;
    options.c_cflag |=  CS8;
    options.c_cflag &= ~CRTSCTS;
    options.c_iflag &= ~(ISTRIP|ICRNL);
    options.c_oflag &= ~OPOST;
    options.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
    options.c_cc[VMIN] = 1;
    options.c_cc[VTIME] = 0;
    //
    tcsetattr(mainfd, TCSAFLUSH, &options);
    pthread_t threads[2];
    pthread_create(&threads[0], NULL, writeIn, NULL);
    pthread_create(&threads[1], NULL, readOut, NULL);
    pthread_exit(NULL);
}
```
The problem is that I have to add 
	
	



```
usleep(70000)
```
 (at least) after 
	
	



```
check=write(mainfd, ch, 1);
```
 in readOut function otherwise the output would not be what I expect. Without this usleep command, every character I type, the output is shown with the next character.
Any suggestions?


----------



## nslay (Apr 6, 2013)

I don't know your exact problem since I can't compile or test your program. However, if your problems are thread related, you could always use select(2) to deal with both stdin and mainfd serially. This removes your use of threads completely.

I've modified your code as follows:

```
int mainfd=0;
char ch[2] = {'\0'};

void writeIn(void)
{
    char aBuff[1024], temp;
    size_t i, numRead;

    numRead = fread(aBuff, 1, sizeof(aBuff), stdin);

    for (i = 0; i < numRead; ++i)
    {
        temp = aBuff[i];
        ch[0] = temp;   ch[1] = '\0';
        if(temp == '~')
        {
            printf("connection closed.\r\n");
            close(mainfd);
            mainfd=-1;
            return;
        }
        check=write(mainfd, ch, 1);
        ch[0]='\0';
    }
}

void readOut(void)
{
    char outputbuffer[10000]= {0};
    //while(1)
    //{
                outputbuffer[0]='\0';
                int charnumber=read(mainfd, &outputbuffer, sizeof(outputbuffer)-1);
                outputbuffer[charnumber] = '\0';
                printf("%s",outputbuffer);
                outputbuffer[0] = '\0';
    //}
}

int main(int argc,char *argv[])
{
    //////////////////
    struct termios old = {0};
    if (tcgetattr(0, &old) < 0)
        perror("tcsetattr()");
    old.c_lflag &= ~ICANON;
    old.c_lflag &= ~ECHO;
    old.c_cc[VMIN] = 1;
    old.c_cc[VTIME] = 0;
    if (tcsetattr(0, TCSANOW, &old) < 0)
    old.c_cc[VTIME] = 0;
    if (tcsetattr(0, TCSANOW, &old) < 0)
         perror("tcsetattr ICANON");
    //////////////////
    struct termios options;
    static int portnum=atoi(argv[1]);

    mainfd = open_port(portnum);

    fcntl(mainfd, F_SETFL, FNDELAY);
    tcgetattr(mainfd, &options);
    cfsetspeed(&options, speed);
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~PARENB;
    options.c_cflag |= CSTOPB;

    options.c_cflag &= ~CSIZE;
    options.c_cflag |=  CS8;
    options.c_cflag &= ~CRTSCTS;
    options.c_iflag &= ~(ISTRIP|ICRNL);
    options.c_oflag &= ~OPOST;
    options.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
    options.c_cc[VMIN] = 1;
    options.c_cc[VTIME] = 0;
    //
    tcsetattr(mainfd, TCSAFLUSH, &options);
    /*pthread_t threads[2];
    pthread_create(&threads[0], NULL, writeIn, NULL);
    pthread_create(&threads[1], NULL, readOut, NULL);
    pthread_exit(NULL);*/

    do {
        fd_set readfds;

        FD_ZERO(&readfds);

        FD_SET(STDIN_FILENO, &readfds);
        FD_SET(mainfd, &readfds);

        if (select(mainfd+1, &readfds, NULL, NULL, NULL) == -1) {
            if (errno != EINTR) {
                // Bad, real bad!
                return -1;
            }
            continue;
        }

        if (FD_ISSET(STDIN_FILENO, &readfds))
            writeIn();

        if (FD_ISSET(mainfd, &readfds))
            readOut();

    } while(mainfd != -1);

    return 0;
}
```

I can't promise this will compile out of the box, but it should give you an idea.


----------



## j4ck (Apr 7, 2013)

Thanks. I changed the writeIn function like this:

```
void writeIn(void)
{
        char temp;
        char[2] = {NULL}
        temp = getchar();
        ch[0] = temp;   ch[1] = '\0';
        if(temp == '~')
        {
            printf("connection closed.\r\n");
            close(mainfd);
            mainfd=-1;
            return;
        }
        check=write(mainfd, ch, 1);
        ch[0]='\0';
}
```
But the problem still remains. This is the problem:

```
Router>
Router>abc // While I typed "abcd". If I continue with typing "e", then the output will be "abcd" and so on ...
```

Any ideas?


----------



## nslay (Apr 7, 2013)

j4ck said:
			
		

> Thanks. I changed the writeIn function like this:
> 
> ```
> void writeIn(void)
> ...



Maybe you can demonstrate the issue by using ffmpeg to capture an X11 terminal session. I created a script that you can use to easily capture a specific window and it can be found here. You may have to tweak it to output a video instead of a sequence of images. My post on the script also apparently mentions recordmydesktop which is in multimedia/recordmydesktop. The latter is probably easier to use.


Also, post the full source with headers included and all. I cannot easily compile and try your software as it is.


----------



## j4ck (Apr 15, 2013)

This is the whole code with headers plus open_port function:

```
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <iostream>
#include <signal.h>
#include <curses.h>
#include <sstream>

int mainfd=0;
char ch[2] = {NULL};

int open_port(int portnum)
{
    int fd;        /* File descriptor for the port */
    char portopen[1000];
    sprintf(portopen, "/dev/ttyu%d", portnum);
    fd = open(portopen, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);

    if (fd == -1)
    {
        /* Could not open the port */
        fprintf(stderr, "open_port: Unable to open /dev/ttyu0 - %s\r\n",
                strerror(errno));
    }
    else
    {
        printf("please enter ^ to close connection.\r\n");
    }
    return (fd);
}

void *writeIn(void *)
{
    char temp;
    int check;
    while(1)
    {
        temp = getchar();
        ch[0] = temp;   ch[1] = '\0';
        if(temp == '~')
        {
            printf("connection closed.\r\n");
            close(mainfd);
            pthread_exit(NULL);
        }
        check=write(mainfd, ch, 1);
        ch[0]='\0';
    }
}

void *readOut(void *)
{
    char outputbuffer[10000]= {0};
    while(1)
    {
                outputbuffer[0]='\0';
                int charnumber=read(mainfd, &outputbuffer, sizeof(outputbuffer));
                outputbuffer[charnumber] = '\0';
                printf("%s",outputbuffer);
                outputbuffer[0] = '\0';
    }
}

int main(int argc,char *argv[])
{
    //////////////////
    struct termios old = {0};
    if (tcgetattr(0, &old) < 0)
        perror("tcsetattr()");
    old.c_lflag &= ~ICANON;
    old.c_lflag &= ~ECHO;
    old.c_cc[VMIN] = 1;
    old.c_cc[VTIME] = 0;
    if (tcsetattr(0, TCSANOW, &old) < 0)
         perror("tcsetattr ICANON");
    //////////////////
    struct termios options;
    static int portnum=atoi(argv[1]);

    mainfd = open_port(portnum);

    fcntl(mainfd, F_SETFL, FNDELAY);
    tcgetattr(mainfd, &options);
    cfsetspeed(&options, 9600);
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~PARENB;
    options.c_cflag |= CSTOPB;

    options.c_cflag &= ~CSIZE;
    options.c_cflag |=  CS8;
    options.c_cflag &= ~CRTSCTS;
    options.c_iflag &= ~(ISTRIP|ICRNL);
    options.c_oflag &= ~OPOST;
    options.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
    options.c_cc[VMIN] = 1;
    options.c_cc[VTIME] = 0;
    //
    tcsetattr(mainfd, TCSAFLUSH, &options);
    pthread_t threads[2];
    pthread_create(&threads[0], NULL, writeIn, NULL);
    pthread_create(&threads[1], NULL, readOut, NULL);
    pthread_exit(NULL);
}
```
Another issue which may be helpful is the scenario I'm using, here it is:
mypc<---->mid-node<---->CISCO router
The executable file of my code is in mid-node which is a running a FreeBSD OS. I use putty to connect to the mid-node, then run the executable file with proper inputs to connect to the CISCO router.
Here are some screen shots of my problem:
http://www.overpic.net/viewer.php?file=xvt77oe16l6q8ionuut4.png
http://www.overpic.net/viewer.php?file=x4lk06m5j7s4bic5czpii.png
As you can see in the first photo, the prompt is not shown at last line. And in the second image, I typed abcd, while the output is abc


----------



## expl (Apr 15, 2013)

Try replacing this:


```
...
    old.c_lflag &= ~ICANON;
    old.c_lflag &= ~ECHO;
    old.c_cc[VMIN] = 1;
    old.c_cc[VTIME] = 0;
...
```

With:


```
cfmakeraw(&old);
```


----------



## nslay (Apr 17, 2013)

Try using fflush(3) like this:

```
printf("%s",outputbuffer);
fflush(stdout); // Add this
```

in your readOut() function.

Not sure if it will solve your problem. But the buffered I/O could be a problem.

Or use setbuf(3) to switch stdout to unbuffered I/O in your main() function:

```
setbuf(stdout, NULL);
```


----------



## j4ck (Apr 17, 2013)

nslay said:
			
		

> Try using fflush(3) like so ...
> 
> ```
> printf("%s",outputbuffer);
> ...


That's it! Thanks, it worked


----------

