Úloha 5 |
Napište program, teletype. Tento program otevře sériový port a vyšle na něj každý z klávesnice zapsaný znak a vypíše každý jednotlivý znak ze sériové linky přijatý. Pomocí sériového kabelu propojte COM1 a COM2 a spusťte 2 instance programu teletype. Který COM se bude používat specifikujte z příkazové řádky při spouštění programu.
Princip sériové komunikaci spočívá ve vysílání jednotlivých bitů přenášeného slova postupně. To má výhodu v tom, že ušetříme výstupy a dráty.
PC architektura používá pro sériovou komunikaci standardně rozhraní RS232 obsluhované řadičem 8250 zvaným UART.
Na fyzické vrstvě odpovídá logické 1 hodnota napětí -25V až -3V, logické 0 hodnota napětí +3V až +25V.
Konektor (Canon 9) pro RS232. | Zapojení nulového modemu pro propojení dvou PC. |
V Unixu byl sériový terminál prvním a základním způsobem, jak se připojit k operačnímu systému. Zkratka TTI pochází ze slova teletype. Jak se Unix rozvíjel vznikly i jiné terminály, než sériový (např. konzole, xterm), avšak k terminálu a k sériovému portu se z programů přistupuje stále stejně. Terminály se však liší jmény odpovídajících zařízení.
Typ terminálu, kterým jsme připojeni zjistíme příkazem tty
Pro nastavení a zjišťování parametrů terminálu slouží příkaz stty. Např. stty -F /dev/ttyS0 -a vypíše nastavení parametrů portu COM1.
[fanda@lab3-2 examples]$ stty -F /dev/ttyS0 -a speed 9600 baud; rows 0; columns 0; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; -parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke [fanda@lab3-2 examples]$ |
Vidíme, že je toho opravdu hodně, co se dá nastavit, naštěstí se nenastavuje všechno. Zejména je nutné si rozmyslet, zda chceme náš terminál (sériový port) provozovat v kanonickém nebo nekanonickém režimu.
V kanonickém režimu (ten je implicitní) se data z terminálu odesílají až po ukončení řádku. To nám dává možnost je editovat.
V nekanonickém režimu (nutno nastavit parametrem -icanon) se data z terminálu odesílají okamžitě jak se objeví (objevit se mohou z klávesnice v případě terminálu, nebo jsou přijata v případě sériové linky). To nám dává možnost je editovat.
Nejjednodušší způsob jak vysílat znaky na sériovou linku je cat > /dev/ttyS0.
A nejjednodušší způsob jak číst znaky ze sériové linky je cat /dev/ttyS0.
Pokud si to vyzkoušíte uvidíte, že to nefunguje, tak jak očekáváte. Zjistíte, že přenesená zpráva je donekonečna opakována, je to proto, že /dev/ttyS0 i /dev/ttyS1 mají nastaven flag echo a s posílanou zprávou si hrají ping-pong.
Přítrž tomuto chování uděláte příkazem stty -F /dev/ttyS0 -echo.
Chcete-li, aby byly znaky kopírovány po jednotlivých písmenkách, je třeba vysílací terminál a přijímající COM přepnout do nekanonického režimu.
stty -icanon
stty -F /dev/ttyS1 -icanon
Struktura termios zachycuje chování terminálu a slouží i pro jeho nastavování.
typedef unsigned char cc_t; typedef unsigned int speed_t; typedef unsigned int tcflag_t; struct termios { tcflag_t c_iflag; /* input mode flags */ tcflag_t c_oflag; /* output mode flags */ tcflag_t c_cflag; /* control mode flags */ tcflag_t c_lflag; /* local mode flags */ cc_t c_line; /* line discipline */ cc_t c_cc[NCCS]; /* control characters */ speed_t c_ispeed; /* input speed (new interface)*/ speed_t c_ospeed; /* output speed (new interface)*/ #define _HAVE_STRUCT_TERMIOS_C_ISPEED 1 #define _HAVE_STRUCT_TERMIOS_C_OSPEED 1 };
Tyto funkce se používají strukturu termios pro čtení a nastavení parametrů terminálu.
int tcgetattr(int fildes, struct termios *termios_p); int tcsetattr(int fildes, int optional_actions, conststruct termios *termios_p);
Nastavení parametrů terminálu ukazuje příklad 2.
Starší implementace používali k nastavení rychlosti c_cflag, novější používají c_ispeed, c_ospeed. Abychom nemuseli řešit tyto implementační závislosti, nastavujeme rychlost terminálu pomocí čtveřice funkcí viz. příklad použití.
speed_t cfgetispeed(const struct termios *termios_p); speed_t cfgetospeed(const struct termios *termios_p); int cfsetispeed(struct termios *termios_p, speed_t speed); int cfsetospeed(struct termios *termios_p, speed_t speed);
Tyto funkce nepotřebují strukturu termios a pracují přímo s filedescriptorem terminálu.
int isatty(int fildes); int tcdrain(int fildes); int tcflush(int fildes, int queue_selector); int tcflow(int fildes, intaction);
1. Čtení sériového portu.
2. Přepnutí terminálu do nekanonického režimu.
3. Příklad knihovny pro konfiguraci a použití sériového portu. zdroják, header