Serial programming using termios

Hi guys
I'm trying to connect to CISCO router using termios. So I decided to have two threads one for reading data and the other one for writing data.
And here's my code :

int mainfd=0;
char ch[2] = {NULL};
 
void *write(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 *read(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, write, NULL);
    pthread_create(&threads[1], NULL, read, NULL);
    pthread_exit(NULL);
}

The problem is that I have to add sleep(2) (at least 2s) after write user input to the port (line 17 I think) otherwise the output would not be what I expect. Without this sleep command, every character I type, the output is shown with next character not at time :

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

How can I fix this?

First off, consider compiling with all warnings enabled. Example: void *read will trigger lots of problems. read, write are standard names for UNIX syscalls.

Next -

    pthread_create(&threads[0], NULL, write, NULL);
    pthread_create(&threads[1], NULL, read, NULL);
    pthread_exit(NULL);

means that as soon as the two threads are created (assuming they were since you do not check return codes), ALL threads will exit - when you call pthread_exit() from main() it shuts down everything. So if and why your code runs - I cannot see? check out pthread_join().

There are many other issues with your code. There is a concept in programming: 'not even wrong'. Code can be wrong for lots of reasons. But when code goes off into undefined behavior - which yours is doing - it then does not have actual meaning. No offense. Your write function is doing reads -getchar() is a read.

First step: turn on compiler warnings, example:

gcc -Wall myfile.c

Fix your code until there are ZERO warnings.

Check and obey your return codes.

After you get that organized, please come back with more questions.

Thanks for your answer.
I changed names to readinput (ex read function) and serial (ex write function), sorry about wrong names.
In readinput function, I get the user input (getchar()) and then write it to the port. And in serial function I read the port and print it.
I fixed my code, and now there are no warnings. But still the problem remains!
Let me ask my question from an upper point of view. How can I read the port immediately after writing data? Without the need of using sleep command after writing data to the port?

Thanks

One way is to synchronize with a select (or poll) and set the fd's to non-blocking.

Once the read gets a \n or a write sends an \n - leave the function - I would not use threads. Unless this is a school assignment.

Use select or poll on both. Never block on a read or a write like you are currently doing.
select() will block for you until one fd (ex, read or write) becomes ready for i/o.

pseudocode: use 3 fd's

while true
do
  set up FD_SET for select to wait on both fd's
  call select  this will block if nothing is coming or going
  the FD_SET will tell you how to branch  but only branch to 2 when you have a buffer to send.
  either
    1 - read from CISCO until you get a zero return (file closed) or you get a \n character
  or
    2 - write to CISCO until EOF or a \n  (after you got a \n from 3)
         empty your buffer used for -2 and -3
  or
    3-  read a single char from keyboard  - this is called a typeahead buffer
end while

If you get a file closed return it means some happened - user quit with ctrl/D or CISCO went South.