a leitura da porta serial em c divide as linhas
Estou tentando escrever um pequeno programa em C que lerá da porta serial usando o comando select para que bloqueie e aguarde a entrada. Está funcionando, exceto que continua quebrando linhas e não faço ideia do porquê. O dispositivo está programado para não quebrar as linhas e funciona bem com os programas de terminal reais. Eu nunca fiz comunicação serial em C antes, e estou em um Mac, então é tudo novo para mim. Eu realmente não tenho idéia de onde procurar o que está errado.
Eu tenho algum código que encontra e lista portas seriais. Vou deixar isso de fora por simplicidade, portanto, se houver uma variável que não faça sentido, talvez seja por isso. Aqui está o código que abre a porta, define atributos e tenta ler a partir dela, com comentários copiados do site da Apple (desculpe):
/* this is based on a combination of http://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
* and https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/WorkingWSerial/WWSerial_SerialDevs/SerialDevices.html
*/
static int OpenSerialPort(const char *deviceFilePath, int speed)
{
int fileDescriptor = -1;
struct termios options;
memset(&options, 0, sizeof(options)); // init it
// Open the serial port read/write, with no controlling terminal,
// and don't wait for a connection.
// The O_NONBLOCK flag also causes subsequent I/O on the device to
// be non-blocking.
// See open(2) ("man 2 open") for details.
fileDescriptor = open(deviceFilePath, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fileDescriptor == -1)
{
printf("Error opening serial port %s - %s(%d).\n", deviceFilePath, strerror(errno), errno);
goto error;
}
// Note that open() follows POSIX semantics: multiple open() calls to
// the same file will succeed unless the TIOCEXCL ioctl is issued.
// This will prevent additional opens except by root-owned processes.
// See options(4) ("man 4 options") and ioctl(2) ("man 2 ioctl") for details.
if (ioctl(fileDescriptor, TIOCEXCL) == kMyErrReturn)
{
printf("Error setting TIOCEXCL on %s - %s(%d).\n", deviceFilePath, strerror(errno), errno);
goto error;
}
// Set raw input (non-canonical) mode, with reads blocking until either
// a single character has been received or a one second timeout expires.
// See tcsetattr(4) ("man 4 tcsetattr") and termios(4) ("man 4 termios")
// for details.
cfmakeraw(&options);
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 5;
// The baud rate, word length, and handshake options can be set as follows:
cfsetspeed(&options, speed); // Set 19200 baud
options.c_cflag = (options.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
options.c_iflag &= ~IGNBRK; // disable break processing
options.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
options.c_oflag = 0; // no remapping, no delays
options.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
options.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
options.c_cflag &= ~(PARENB | PARODD); // shut off parity
options.c_cflag |= false;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CRTSCTS;
// Cause the new options to take effect immediately.
if (tcsetattr(fileDescriptor, TCSANOW, &options) == kMyErrReturn)
{
printf("Error setting options attributes %s - %s(%d).\n", deviceFilePath, strerror(errno), errno);
goto error;
}
// turn on blocking
if (fcntl(fileDescriptor, F_SETFL, 0) == kMyErrReturn)
{
printf("Error clearing O_NONBLOCK %s - %s(%d).\n", deviceFilePath, strerror(errno), errno);
goto error;
}
// Success:
return fileDescriptor;
// Failure:
error:
if (fileDescriptor != kMyErrReturn)
{
close(fileDescriptor);
}
return -1;
}
int main(void)
{
int fileDescriptor;
kern_return_t kernResult; // these are Apple-specific
io_iterator_t serialPortIterator; // Apple
char deviceFilePath[MAXPATHLEN];
fd_set fdset; // make a file descriptor set
FD_ZERO (&fdset); // init it
char buf[1000]; // some strings are big
kernResult = GetDevices(&serialPortIterator);
printf("Devices on this system:\n");
kernResult = ListDevicePaths(serialPortIterator, deviceFilePath, sizeof(deviceFilePath));
IOObjectRelease(serialPortIterator); // Release the iterator.
// Open the modem port, initialize the modem, then close it.
if (!deviceFilePath[0])
{
printf("No modem port found.\n");
return EX_UNAVAILABLE;
}
fileDescriptor = OpenSerialPort("/dev/cu.usbmodem1d1111", B230400);
FD_SET (fileDescriptor, &fdset); // add to file descriptor set
// now we're going to use select to only read from the file handle when there's data available
while (1)
{
if (select (FD_SETSIZE, &fdset, NULL, NULL, NULL) < 0) // this will block the program until something is on the line
{
printf("select error\n");
}
read(fileDescriptor, buf, 1000);
printf("%s\n", buf);
memset(buf, '\0', 1000);
}
// let's try to read from the serial port
/* for (int i = 0; i <= 10; i++)
{
char buf [100];
int n = read(fileDescriptor, buf, sizeof buf);
printf("%s\n", buf);
//usleep ((7 + 25) * 100);
}*/
close(fileDescriptor);
printf("Modem port closed.\n");
return EX_OK;
}
Saída esperada:
This is sample output.
Hello.
O que realmente recebo no programa acima:
Thi
s is sam
ple output.
Hel
lo.
Ou algo assim. É diferente a cada vez. Às vezes funciona bem. Parece ser aleatório.
Então, minhas perguntas são: O que estou fazendo de errado? Em que código eu preciso trabalhar além de apenas um cobertor "tudo isso?" O que não estou entendendo? Admito que realmente não entendo exatamente como essas bibliotecas funcionam. Estou assumindo (eu sei, eu sei) que eles cuidam do controle de fluxo e erros e assim por diante. Mas, novamente, os exemplos dos quais copiei não explicam exatamente isso, então eu não sei. Eu realmente não sei o que está acontecendo.