Последовательный ввод / вывод в C с помощью termios: ненадежная капитализация выхода
У меня есть очень маленькая программа на C, которая отправляет и получает строки ASCII с символом окончания строки в последовательное устройство. Он подключен к моему компьютеру с помощью USB-адаптера, на /dev/ttyUSB0
,
Большую часть времени он отправляет команды только находят, но иногда он будет использовать заглавные буквы в верхнем регистре. Он оставляет все специальные символы в покое.
Я отправляю строку /home\n
, Примерно 1 из каждых пяти раз я запускаю программу (просто запустив ./a.out
без перекомпиляции), понятное для устройства отправленное сообщение /HOME\n
,
Вот мой исходный код:
#include <stdio.h>
#include <stdlib.h>
#include "zserial.h"
int main() {
char buf[256];
int fd = connect("/dev/ttyUSB0");
char *cmd = "/home\n";
send(fd, cmd);
receive(fd, buf, 256);
puts(buf);
exit(0);
}
И zserial.c:
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "zserial.h"
int send(int fd, char *buf) {
int len = strlen(buf);
int nb = write(fd, buf, len);
if (len != nb || nb < 1)
perror("Error: wrote no bytes!");
tcdrain(fd);
return nb;
}
int receive(int fd, char *dst, int nbytes) {
int i;
char c;
for(i = 0; i < nbytes;) {
int r = read(fd, &c, 1);
/* printf("Read %d bytes\n", r); */
if (r > 0) {
dst[i++] = c;
if (c == '\n') break;
}
}
dst[i] = 0; /* null-terminate the string */
return i;
}
int connect(char *portname) {
int fd;
struct termios tio;
fd = open(portname, O_RDWR | O_NOCTTY | O_NONBLOCK);
tio.c_cflag = CS8|CREAD|CLOCAL;
if ((cfsetospeed(&tio, B115200) & cfsetispeed(&tio, B115200)) < 0) {
perror("invalid baud rate");
exit(-1);
}
tcsetattr(fd, TCSANOW, &tio);
return fd;
}
Что я делаю неправильно? Есть ли какой-нибудь флаг termios, который изменяет вывод на последовательный порт?
1 ответ
c_oflag & OLCUC
включает отображение строчных и прописных букв на выходе. Так как вы никогда не инициализировали tio
Не удивительно, что у вас есть несколько случайных флагов.
У вас есть два варианта:
tcgetattr
текущие настройки вtermios
struct, чтобы инициализировать его, затем изменить те, которые вас интересуют, а затем записать их обратноtcsetattr
инициализировать все поля termios известными значениями, а не только
c_cflag
и поля скорости.