Чтение данных последовательного порта

Я пытаюсь прочитать данные последовательного порта на C в Mac OS. Конфигурация последовательного порта выполняется в отдельной Arduino IDE.

Я могу читать частичные данные, но затем напечатанные данные повторяются и начинают считывать нули, как показано ниже. Если удалить O_NONBLOCK, программа просто зависнет. Что я могу сделать, чтобы решить эту проблему? Во-вторых, учитывая, что я читаю данные в цикле for, как мне убедиться, что скорость чтения соответствует скорости передачи в бодах?

Просмотренных данных: 296310 0

320 295 311

320 295 311

9 296 311

320 295 311

320 295 311

9 296 311

...

0 0 0

0 0 0

0 0 0 и т. Д.

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

int buffer[300];

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

    // open serial port
    int port;
    port = open("/dev/tty.usbmodem1411", O_RDONLY | O_NONBLOCK);
    if (port == -1)
    {
        printf("Unable to open serial port.\n");
        return 1;
    }

    // instantiate file
    FILE* file = fdopen(port, "r");
    if (file == NULL)
    {
        printf("Unable to instantiate file.\n");
        close(port);
        return 2;
    }

    for (int j = 0; j < 200; j++)
    {

        fscanf(file, "%d %d %d", &buffer[3*i], &buffer[3*i+1], &buffer[3*i+2]);
        printf("%d %d %d\n", buffer[3*i], buffer[3*i+1], buffer[3*i+2]);

        i = (i + 1) % 100;

        usleep(10000);

    }

    fclose(file);
    close(port);

    return 0;

}

person Victor    schedule 04.12.2013    source источник
comment
1) Вероятно, вы получите лучшие результаты с устройствами /dev/cu.usbmodem####, чем с устройствами tty. 2) Убедитесь, что вы проверяете возвращаемое значение fscanf и обрабатываете данные только в случае успеха.   -  person Chris Stratton    schedule 04.12.2013
comment
По сути, я не верю, что fscanf будет перематывать входной поток, если он запускается, когда прибыло только частичное сообщение, поэтому вам может понадобиться что-то, что собирает полные сообщения, если вы не можете позволить себе отбрасывать данные, если вы вызываете fscanf только с получено частичное сообщение. Вместо этого рассмотрите блокирующую функцию fgets () для передачи всей строки в буфер, а затем sscanf () буфер для восстановления ваших полей.   -  person Chris Stratton    schedule 04.12.2013
comment
Под данными процесса вы имеете в виду хранение в имеющемся у меня буферном массиве? В этом случае должен ли я иметь дополнительный буферный массив, и если fscanf возвращает меньше трех, пропустить? Я бы предпочел полное сообщение, поэтому могу позволить себе пропустить частичное сообщение, если fscanf возвращает меньше трех.   -  person Victor    schedule 05.12.2013
comment
Нет, сохраняйте данные символьного массива (т. Е. Строковые) по мере их поступления, пока у вас не появится вся строка для анализа. В противном случае вы потеряете данные, если вызовете fscanf () с полученной неполной строкой. Или напишите синтаксический анализатор, который может обрабатывать символы, капающие по одному, и преобразовывать их в числа. Вы не учли, что при получении данных могут быть средние задержки, и что ваши текущие попытки проанализировать их полностью асинхронны, поэтому вы иногда будете пытаться сделать это в нерабочее время и потеряете данные.   -  person Chris Stratton    schedule 05.12.2013
comment
Вот что я придумал - как заставить fgets проверять частичные данные? Или это уже сделано с первым условием? if (fgets(temp, sizeof(temp), file) != NULL) { sscanf(temp, "%d %d %d\n", &buffer[3*i], &buffer[3*i+1], &buffer[3*i+2]); printf("%d %d %d\n", buffer[3*i], buffer[3*i+1], buffer[3*i+2]); }   -  person Victor    schedule 05.12.2013
comment
i объявление не отображается. Покажите, пожалуйста. Это инициализировано? В противном случае это является проблемой.   -  person chux - Reinstate Monica    schedule 06.12.2013
comment
Проверьте результат fscanf(), как в if (3 != fscanf(...)) Handle_error();   -  person chux - Reinstate Monica    schedule 06.12.2013


Ответы (1)


Для Криса Стрэттона:

if (fgets(temp, sizeof(temp), file) != NULL) 
{ 
     sscanf(temp, "%d %d %d\n", &buffer[3*i], &buffer[3*i+1], &buffer[3*i+2]); 
     printf("%d %d %d\n", buffer[3*i], buffer[3*i+1], buffer[3*i+2]); 
}

Однако, возвращаясь к моему первоначальному вопросу, даже если я использую fscanf и printf, я получаю данные, а затем бесконечно читаю только нули. Я думаю, это может быть больше проблема связи через последовательный порт?

person Victor    schedule 05.12.2013
comment
Вы все еще не проверяете значение возврата fscanf (), и на этом этапе было бы неплохо распечатать необработанные полученные буферы (перед синтаксическим анализом) для отладки. Кроме того, вам нужно использовать это блокирующим образом, поэтому избавьтесь от O_NONBLOCK. - person Chris Stratton; 05.12.2013
comment
Если я избавлюсь от O_NONBLOCK, программа, к сожалению, зависнет. - person Victor; 06.12.2013
comment
Да, должно, пока не увидит новую строку в конце строки данных. Если вы хотите работать в неблокирующем режиме, вам, вероятно, придется написать собственную логику для сбора и повторной сборки буферов и поиска новых строк, которые не находятся в конце буфера, если вы не читаете только один символ за раз в своем буфере. и остановитесь и проанализируйте, когда вы получите новую строку. Кроме того, вы еще не забыли переключиться с устройства tty на устройство cu? - person Chris Stratton; 06.12.2013
comment
Итак, если строка port = open (...) зависает, как это исправить? Кроме того, что касается вашего первого комментария к этому ответу, я больше не использую fscanf. Наконец, я попробовал устройство cu, и улучшений по сравнению с tty не было. - person Victor; 06.12.2013