I have a device that sends information over USB to my computer. Arch Linux sets up this device by creating a file named ttyUSB0
in /dev/
. I have been using GTKterm
to receive this incoming information and display it in an emulated terminal window.
My question is, how exactly does GTKterm
read/write to this ttyUSB0
file, and where might I start learning how to implement similar functionality? That is, in the most basic form, how might I write a character to ttyUSB0
, or, in contrast, receive a byte and write it to a file?
Best Answer
TTYs are files that you can use just like any other. You can open them with the standard file-opening tools of your language and read or write from them. They have some special behaviour that's different to "ordinary" files, but the basics are the same. I'll cover some of the special cases at the end, but first, an experiment.
One interesting thing you can do straight from a regular terminal. Run
tty
and it will print a line like:That's the TTY device your terminal is running in. You can write something to that terminal:
You can even read from it:
(
read X
is sh's "read a line from standard input into variable X" command; the < is to use /dev/pts/2 as standard input for the read command; the first "hello" I typed, and the second was printed out).If you open up another shell, say by using
screen
orxterm
, you can run runecho spooky > /dev/pts/2
in that shell to make the text appear on your original terminal, and the same for the other commands. All of this is just your shell opening a file without knowing it's a TTY.Here is a very simple C program that does just what you asked, and writes a single character to /dev/pts/3, then reads a single byte back from it:
A real TTY device that's attached to a shell or terminal emulator will have interesting behaviour there, but you should get something back.
To access a terminal you need to have permission to use it. Those are just the standard file permissions you see with
ls -l
and set withchmod
: you need read permission to open the file and read it, and write permission to write into it. The TTYs that back your terminal will be owned by you, but another user's TTY won't, and TTYs for USB devices may or may not be, depending on your configuration. You can change the permissions in the same way as always.As far as writing a program to work with it goes, you don't need to do much special. You can see in the example that one thing you don't need to do is close the file every time to have your data read by the other end: the TTY files act like pipelines, just pushing data in both directions as it comes in. When I wrote text to the TTY it appeared immediately, and when I read from it afterwards there wasn't anything waiting for me already. It's not like writing to a regular file where the data gets saved on disk - it gets passed on immediately to the other side, or stored in memory until someone reads it.
You may want to use the select function so that you can do other things while you wait for the device to say something, but if you're happy to just wait for data to come through you can just use blocking reads and let the OS do the lifting.
One thing to keep in mind is that there is can be limited buffer size in the kernel, and if you write a lot of data at once you may end up blocking without meaning to. If that's likely to be a problem, use non-blocking IO with
open("/dev/...", O_RDWR | O_NONBLOCK)
. The principle will be the same either way.