Я пытаюсь читать данные с устройства UART в среде Linux с помощью программы на языке C, но получаю разные результаты в отношении связи с UART с помощью экрана.
Код C, который я использую для проверки связи UART, следующий:
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <getopt.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <signal.h>
#include <ctype.h>
bool loop;
void sigHandler(int32_t sig)
{
if (sig == SIGINT)
{
printf("Catched SIGINT");
loop = false;
}
}
int main(int argc, char *argv[])
{
char *devname = argv[1];
int fd = -1;
int nread = -1;
int nwrite = -1;
int ret;
struct termios t_new = {0};
struct termios t_old = {0};
signal(SIGINT, sigHandler);
fd = open(devname, O_RDWR | O_NOCTTY |O_NONBLOCK);
if (fd > 0)
{
printf("TTY open ! Configuring TTY");
}
else
{
fd = -1;
return 1;
}
ret = tcgetattr(fd, &t_old);
if (ret < 0)
{
perror("tcgetattr ");
close(fd);
fd = -1;
return 1;
}
t_new = t_old;
t_new.c_cflag = (B9600 | CS8 | CREAD );
t_new.c_oflag = 0;
t_new.c_iflag = 0;
t_new.c_lflag = 0;
ret = tcsetattr(fd, TCSANOW, &t_new);
loop = true;
while(loop)
{
char s[] = "at+gmi=?\r\n";
nwrite = write(fd, s, strlen(s));
if (nwrite == strlen(s))
{
fd_set rfd;
struct timeval tm = {.tv_sec = 0, .tv_usec = 500000};
FD_ZERO(&rfd);
FD_SET(fd, &rfd);
char buffer[64] = {0};
if (select(fd + 1, &rfd, NULL, NULL, &tm) > 0)
nread = read(fd, buffer, sizeof(buffer));
if (nread > 0)
printf("Reply is: %s\n", buffer);
}
usleep(500000);
}
}
Но когда я читаю ответ, он всегда включает в себя отправленную мной строку.
У меня не возникает этой проблемы с screen
.
Как лучше всего читать с UART на C с помощью Linux?
Может ли мультиплексный способ (с использованием select
) вызвать проблемы?
РЕДАКТИРОВАТЬ Для полноты вывод:
Reply is: at+gmi=?
OK
Кроме того, иногда я ничего не читаю.
да. Но ECHO отключен, по крайней мере, в моем коде. Я не знаю настройки внешнего устройства UART.
Возможный дубликат Как открывать, читать и писать из последовательного порта в C?
But when I read the reply, it always includes the string I have sent.
Поскольку ваша конфигурация termios уничтожила локальные атрибуты эха, и вы отправляете команду AT-модема, вам следует попробовать отправить команду ATE0
, чтобы отключить эхо модема.
I don't experience this problem using screen.
Это наблюдение подтверждает, что у подключенного модема включено эхо.
Команда AT отображается эхом (модемом) по мере ввода, но вы не возражаете против этих полученных данных в этой ситуации (потому что вы хотите видеть, что вы вводите) .
Если бы у модема не было включено эхо, вы бы жаловались, что то, что вы вводите в экран, не было видно.
Эхо IOW желательно при использовании программы эмулятора терминала (такой как экран), но эхо необходимо отключить при отправке данных программой.
What is the best way to read from an UART in C using Linux ?
(Технически вы читаете не из "UART", а из последовательного терминала, который полностью буферизует весь ввод и вывод.)
Код, соответствующий стандарту POSIX, как описано в Правильная установка режимов терминала
и Руководство по последовательному программированию для операционных систем POSIX было бы намного лучше, чем то, что у вас есть сейчас.
Я удивлен, что он вообще работает (например, CREAD не включен).
Could the multiplexed way (using select) causing the problems ?
Не эхо "проблема" .
Ваша программа не делает ничего, что требует использования Выбрать() и неблокирующего режима.
Also, sometimes I don't read anything.
Когда вы пишете код, не совместимый с POSIX, не следует ожидать надежного поведения программы.
Да, это моя вина. На устройстве было включено эхо, и я запутался в выводе с экрана ...
Похоже, это просто терминальное эхо. Ваш ввод определенно возвращается от UART?