L'ho scritto molto tempo fa ( dagli anni 1985-1992, con solo alcune modifiche da allora ), e ho semplicemente copiato e incollato i bit necessari in ogni progetto.
È necessario chiamare cfmakeraw
un tty
ottenuto da tcgetattr
. Non è possibile azzerare un struct termios
, configurarlo e quindi impostare il tty
con tcsetattr
. Se si utilizza il metodo zero-out, si verificheranno errori intermittenti inspiegabili, in particolare su BSD e OS X. Gli "errori intermittenti inspiegabili" includono l'aggancio read(3)
.
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int
set_interface_attribs (int fd, int speed, int parity)
{
struct termios tty;
if (tcgetattr (fd, &tty) != 0)
{
error_message ("error %d from tcgetattr", errno);
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
error_message ("error %d from tcsetattr", errno);
return -1;
}
return 0;
}
void
set_blocking (int fd, int should_block)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
error_message ("error %d from tggetattr", errno);
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
error_message ("error %d setting term attributes", errno);
}
...
char *portname = "/dev/ttyUSB1"
...
int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0)
{
error_message ("error %d opening %s: %s", errno, portname, strerror (errno));
return;
}
set_interface_attribs (fd, B115200, 0); // set speed to 115,200 bps, 8n1 (no parity)
set_blocking (fd, 0); // set no blocking
write (fd, "hello!\n", 7); // send 7 character greeting
usleep ((7 + 25) * 100); // sleep enough to transmit the 7 plus
// receive 25: approx 100 uS per char transmit
char buf [100];
int n = read (fd, buf, sizeof buf); // read up to 100 characters if ready to read
I valori per la velocità sono B115200
, B230400
, B9600
, B19200
, B38400
, B57600
, B1200
, B2400
, B4800
, ecc I valori di parità sono 0
(che significa nessuna parità), PARENB|PARODD
(consentire la parità e utilizzare dispari), PARENB
(consentire parità e usare anche), PARENB|PARODD|CMSPAR
(parità marchio), e PARENB|CMSPAR
( parità di spazio).
"Blocco" imposta se a read()
sulla porta attende l'arrivo del numero specificato di caratteri. L'impostazione di nessun blocco significa che un read()
ritorni comunque sono disponibili molti caratteri senza aspettare di più, fino al limite del buffer.
Addendum:
CMSPAR
è necessario solo per scegliere la parità del segno e dello spazio, il che è insolito. Per la maggior parte delle applicazioni, può essere omesso. Il mio file di intestazione /usr/include/bits/termios.h
abilita la definizione CMSPAR
solo se __USE_MISC
è definito il simbolo del preprocessore . Tale definizione si verifica (in features.h
) con
#if defined _BSD_SOURCE || defined _SVID_SOURCE
#define __USE_MISC 1
#endif
I commenti introduttivi di <features.h>
dice:
/* These are defined by the user (or the compiler)
to specify the desired environment:
...
_BSD_SOURCE ISO C, POSIX, and 4.3BSD things.
_SVID_SOURCE ISO C, POSIX, and SVID things.
...
*/