Reputation: 11489
I am new to the linux programming. I followed example on the web to read/write to console e.g., "/dev/ttyS0". Each time I run the code, it exits without prompting user to write the input. It also distorts the terminal prompt (newline) and I am unable to see what I am typing... Here is the code I am using :
int main(int argc, char** argv)
{
struct termios tio;
struct termios stdio;
int tty_fd;
/* fd_set rdset; */
printf("Please start with %s /dev/ttyS0 (for example)\n",argv[0]);
unsigned char mesg='D';
memset(&stdio,0,sizeof(stdio));
stdio.c_iflag=0;
stdio.c_oflag=0;
stdio.c_cflag=0;
stdio.c_lflag=0;
stdio.c_cc[VMIN]=1;
stdio.c_cc[VTIME]=0;
tcsetattr(STDOUT_FILENO,TCSANOW,&stdio);
tcsetattr(STDOUT_FILENO,TCSAFLUSH,&stdio);
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); // make the reads non-blocking
memset(&tio,0,sizeof(tio));
tio.c_iflag=0;
tio.c_oflag=0;
tio.c_cflag=CS8|CREAD|CLOCAL; // 8n1, see termios.h for more information
tio.c_lflag=0;
tio.c_cc[VMIN]=1;
tio.c_cc[VTIME]=5;
tty_fd=open(argv[1], O_RDWR | O_NONBLOCK | O_NOCTTY);
cfsetospeed(&tio,B115200); // 115200 baud
cfsetispeed(&tio,B115200); // 115200 baud
tcsetattr(tty_fd,TCSANOW,&tio);
while (mesg != 'q') {
if (read(tty_fd,&mesg,1)>0) write(STDOUT_FILENO,&mesg,1); // if new data is available on the serial port, print it out
if (read(STDIN_FILENO,&mesg,1)>0) write(tty_fd,&mesg,1); // if new data is available on the console, send it to the serial port
}
close(tty_fd);
return(0);
}
Upvotes: 1
Views: 852
Reputation: 58627
When you're experimenting with code that changes tty parameters, you should wrap your invocations of the test program with a script which saves and restores the parameters, in case your program neglects to do so.
This can be done like this:
$ SAVED_TTY=$(stty -g) # save the good settings once
$ ./a.out ; stty $SAVED_TTY # restore than after each run of the program
The -g
option of stty
causes it to output all of the tty settings "pickled" into a character string, which is acceptable as an argument to a future invocation of stty
to restore the same settings.
(Properly written tty-manipulating programs take care to restore the terminal settings when they exit, and even if they exit abruptly by receiving any fatal signal that can be handled.)
As for the question of how to loop back what is written to the tty device, there is no general functionality for this in the tty subsystem itself. The standard tty line discipline module can echo incoming characters back to the output, so that when users use line-oriented programs, they can see their own typing, but there is no software loopback whereby a tty device pretends to receive some characters that it has just sent.
However, some serial hardware is capable of hardware loopback: essentially tying the UART TX line to the RX line for the purpose of testing.
The Linux tty's support a modem control ioctl which can be used to turn this on and off, if the hardware supports it. This takes the form of TIOCMGET
and TIOCMSET
ioctls. These ioctls work with a value that is a logical OR of various masks, one of which is TIOCM_LOOP
.
So, I believe that setting up hardware loopback goes something like this:
unsigned int modem_control_bits;
result = ioctl(tty_descriptor, TIOCMGET, &modem_control_bits);
/* check result for error, of course */
modem_control_bits |= TIOCM_LOOP; /* request loopback from serial port */
result = ioctl(tty_descriptor, TIOCMSET, &modem_control_bits);
/* check result for error */
It's not clear whether every serial driver will report an error if it is asked to set TIOCM_LOOP
, but the hardware does not support it. (I don't think that just because the result is zero, it necessarily worked).
There are other TIOCM_*
bits, so you can do standard things like turn on and off DTR, or detect whether the ring indicator is on and whatnot.
Upvotes: 1