Не удается прочитать последовательные данные: read () ожидает неопределенно долго

#c #linux #serial-port

#c #linux #последовательный порт

Вопрос:

Я пытаюсь прочитать / записать последовательные данные в Linux, используя программирование на C. Я могу успешно открыть порт и установить атрибуты. Но когда я пытаюсь прочитать последовательные данные, read() системный вызов ожидает неопределенно долго. Не могу понять, почему это происходит.

Для тестирования последовательной связи я использую arduino с пропускной способностью 9600 бод и конфигурацией 8N1.

Вот мой код:

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>

int init(char *port);
void reads(int fd);

int main(int argc, char *argv[]){
    int fd;

    fd = init(argv[1]);

    fprintf(stdout, "nn####### DATA ########nn");
    reads(fd);

    close(fd);

    return EXIT_SUCCESS;
}

int init(char *port){
    int fd;
    struct termios topt;

    fd = open(port, O_RDWR | O_NONBLOCK);
    if(fd < 0){
        fprintf(stderr, "init error: can't open port %sn!", port);
        exit(1);
    }

    if(tcgetattr(fd, amp;topt) < 0){
        fprintf(stderr, "init error: can't get terios attributes!n");
        exit(1);
    }

    topt.c_cflag amp;= ~CRTSCTS;
    topt.c_cflag |= CREAD | CLOCAL;
    topt.c_cflag amp;= ~(IXON | IXOFF | IXANY);
    topt.c_cflag amp;= ~(ICANON | ECHO | ECHOE | ISIG);
    topt.c_cflag amp;= ~OPOST;

    cfsetispeed(amp;topt, B9600);
    cfsetospeed(amp;topt, B9600);

    topt.c_cflag amp;= ~PARENB;
    topt.c_cflag amp;= ~CSTOPB;
    topt.c_cflag amp;= ~CSIZE;
    topt.c_cflag |= CS8;

    topt.c_cc[VMIN] = 1;
    topt.c_cc[VTIME] = 0;

    tcsetattr(fd, TCSANOW, amp;topt);
    if(tcsetattr(fd, TCSAFLUSH, amp;topt) < 0){
        fprintf(stderr, "init error: can't set attributes!n");
        exit(1);
    }
}

void reads(int fd){
    char rdbuff[1];

    while(read(fd, rdbuff, 1) > 0){
        fprintf(stdout, "%c", rdbuff[0]);
    }
}
  

Спасибо!

Комментарии:

1. О, ваша init функция не возвращает файловый дескриптор! Ваш компилятор должен был предупредить вас об этом.

2. O_NONBLOCK означает неблокирующий режим. Если чтение или запись не могут быть выполнены немедленно (для read() нет последовательных данных или маленький последовательный аппаратный буфер заполнен write() ), они вернутся -1 с errno == EAGAIN или errno == EWOULDBLOCK . Он используется только тогда, когда вам нужно выполнить много действий, и вы хотите выполнить мультиплексирование между этими разными действиями, не будучи «заблокированным» в какой-то момент read() или write() просто потому, что они не могут быть выполнены прямо сейчас .

3. Кроме того, при использовании serial (или сетевого оборудования, если на то пошло) вы никогда не должны предполагать, что read(fd, data, n) or write(fd, data, n) возвращает либо ошибку, либо n ; они могут и часто будут возвращать некоторое положительное целое число, меньшее n (но не 0; в этом случае они возвращают -1 с errno==EINTR||errno==EAGAIN||errno==EWOULDBLOCK вместо этого). Это называется короткими отсчетами . При последовательном или сетевом чтении и записи вы всегда должны использовать цикл, который считывает / записывает остальные данные, если вызов возвращает короткое значение.

4. при компиляции. всегда включайте все предупреждения, затем исправляйте эти предупреждения. для gcc минимального использования: -Wall -Wextra -pedantic я также использую: -Wconversion -std=gnu99

5. @AshfaqurRahman: в неблокирующем режиме вы используете select() или poll() , чтобы определить, в каких дескрипторах есть данные для чтения или в которые они могут быть записаны без блокировки. Я думаю, я мог бы привести пример небольшой программы, которая делает это, записывая данные, считанные со стандартного ввода, в последовательный порт, а данные, считанные с последовательного порта, в стандартный вывод, с терминалом в режиме raw (каждое нажатие клавиши отправляется немедленно), если в этом есть интерес.