0
votes

I trying to read serial raw bytes from using serial port "/dev/ttyS0".In my program, What i want to do is to press the letter and immediately see the the letter I introduced repeated without pressing ENTER. For example, if I press the letter 'a' I want to see an other 'a' next to it.

My code is here:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>

int main()
{
        int n = 0, fd = 0;

        struct termios term,trm;

        printf("%d\n",getpid());

        fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);

        if (fd == -1)
        {
                perror("open");
                return 1;
        }
        else
        {
                fcntl(fd, F_SETFL, 0);
                perror("Port");
        }

        if (n = tcgetattr(fd, &term) == -1)
        {
                perror("tcgetattr");
                return 1;
        }

        if (n = cfsetispeed(&term, B115200) == -1)
        {
                perror("cfsetispeed");
                return 1;
        }

        if (n = cfsetospeed(&term, B115200) == -1)
        {
                perror("cfsetospeed");
                return 1;
        }

        term.c_cflag |= (CLOCAL | CREAD);
        term.c_cflag &= ~PARENB;
        term.c_cflag &= ~CSTOPB;
        term.c_cflag &= ~CSIZE;
        term.c_cflag |= CS8;
        term.c_cflag &= ~CRTSCTS;
        term.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
        term.c_iflag &= ~(IXON | IXOFF | IXANY);
        term.c_iflag |= (INPCK | ISTRIP);
        term.c_oflag &= ~OPOST;

        unsigned char c,d;
        ssize_t s=0;

        tcflush(fd, TCIOFLUSH);

        system("/bin/stty raw");
        while((c=getchar()) != 'q')
        {
                write(fd, &c,1);

                term.c_cc[VMIN] = 1;
                term.c_cc[VTIME] = 0;

                tcsetattr(fd, TCSANOW, &term);

                if((s=read(fd, &d,1)) != -1)
                {
                        perror("read");
                        printf("%c",d);
                }
        }
        system("/bin/stty cooked");
        close(fd);
        return 0;
}
2
It is not necessary to integrate your port configuration into the while loop. Better to put them before the tcflush call. In addition, using system() to configure your port via stty is not necessary too, you are already configuring by using termios struct. - ogs
include fntl, stlib, stdio. termios and add return value. Please compile your code first, before you post it here - Gaurav Minocha
" What i want to do is to press the letter and immediately see the the letter I introduced repeated without pressing ENTER" -- This seems like a question only about stdin and stdout, and nothing to do with a serial port. - sawdust
Assuming you have properly configured the serial port using the termios, then a character sent to the serial port can be echoed (a) locally by enabling ECHO in c_lflag, and/or (b) remotely by the device on the other end of the serial link. Note that this means that you can get a single or double echo (or no echo at all) depending on how everything is setup. - sawdust

2 Answers

1
votes

I don't know if it is the solution you are looking for, but you must disable stdin buffering to make getchar exits each char user enter.

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>

int main()
{
        int n = 0, fd = 0;

        struct termios term, old_stdin, new_stdin;

        printf("%d\n",getpid());

        fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);

        if (fd == -1)
        {
                perror("open");
                return 1;
        }
        else
        {
                fcntl(fd, F_SETFL, 0);
                perror("Port");
        }

        if (n = tcgetattr(fd, &term) == -1)
        {
                perror("tcgetattr");
                return 1;
        }

        if (n = cfsetispeed(&term, B115200) == -1)
        {
                perror("cfsetispeed");
                return 1;
        }

        if (n = cfsetospeed(&term, B115200) == -1)
        {
                perror("cfsetospeed");
                return 1;
        }

        term.c_cflag |= (CLOCAL | CREAD);
        term.c_cflag &= ~PARENB;
        term.c_cflag &= ~CSTOPB;
        term.c_cflag &= ~CSIZE;
        term.c_cflag |= CS8;
        term.c_cflag &= ~CRTSCTS;
        term.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
        term.c_iflag &= ~(IXON | IXOFF | IXANY);
        term.c_iflag |= (INPCK | ISTRIP);
        term.c_oflag &= ~OPOST;

        unsigned char c,d;
        ssize_t s=0;

        tcflush(fd, TCIOFLUSH);
        term.c_cc[VMIN] = 1;
        term.c_cc[VTIME] = 0;

        tcsetattr(fd, TCSADRAIN, &term);

        // get the terminal settings for stdin 
        tcgetattr(STDIN_FILENO,&old_stdin);

        new_stdin = old_stdin;

        // disable canonical mode (buffered i/o) and local echo 
        new_stdin.c_lflag &=(~ICANON & ~ECHO);

        // set the new settings
        tcsetattr(STDIN_FILENO,TCSANOW,&new_stdin);

        while((c=getchar()) != 'q')
        {
            write(fd, &c,1);

            if((s=read(fd, &d,1)) != -1)
            {
                perror("read");
                printf("%c",d);
            }
        }
        close(fd);

        // Restore the old stdin setup
        tcsetattr(STDIN_FILENO,TCSANOW,&old_stdin);

        return 0;
}
0
votes

You should change the terminal device's mode to "raw", by using

tty.setraw(file_descriptor)