Чтение с последовательного порта в многопоточной программе на Linux - PullRequest
1 голос
/ 14 марта 2011

Я пишу программу в linux для взаимодействия через последовательный интерфейс с частью аппаратного обеспечения.Устройство отправляет пакеты размером примерно 30-40 байтов на частоте около 10 Гц.Этот программный модуль будет взаимодействовать с другими и обмениваться данными через IPC, поэтому он должен выполнять определенный режим ожидания IPC, чтобы он мог получать сообщения, на которые он подписан, когда он не делает ничего полезного.

В настоящее время мой код выглядит примерно так:

while(1){
  IPC_sleep(some_time);
  read_serial();
  process_serial_data();
}

Проблема с этим заключается в том, что иногда чтение будет выполняться, пока на последовательном порту доступна только часть следующего пакета, чтоозначает, что не все прочитано до следующего цикла.Для конкретного приложения предпочтительно, чтобы данные читались, как только они были доступны, и чтобы программа не блокировала их во время чтения.

Какое решение этой проблемы является лучшим?

Ответы [ 4 ]

3 голосов
/ 14 марта 2011

Лучшее решение не спать!То, что я имею в виду, это хорошее решение, вероятно, смешать событие IPC и последовательное событие.выберите хороший инструмент для этого.Затем вы должны найти и механизм IPC, который выбирается совместимым.

  • IPC на основе сокета select() способен
  • IPC на основе канала select() способен
  • Вы также можете выбрать очередь сообщений posix

И тогда ваш цикл выглядит следующим образом:

while(1) {
    select(serial_fd | ipc_fd); //of course this is pseudo code
    if(FD_ISSET(fd_set, serial_fd)) {
        parse_serial(serial_fd, serial_context);
        if(complete_serial_message)
            process_serial_data(serial_context)
    }
    if(FD_ISSET(ipc_fd)) {
        do_ipc();
    }
}

read_serial заменяется на parse_serial, потому что, если вы тратите все свое время на ожиданиеполный последовательный пакет, тогда все преимущества выбора теряются.Но из вашего вопроса, кажется, вы уже делаете это, так как вы упоминаете получение последовательных данных в двух разных циклах.
С предложенной архитектурой у вас хорошая реактивность как на IPC, так и на последовательной стороне.Вы читаете последовательные данные, как только они становятся доступны, но без остановки обработки IPC.

Конечно, предполагается, что вы можете изменить механизм IPC.Если вы не можете, возможно, вы можете создать «процесс моста», который с одной стороны взаимодействует с любым IPC, с которым вы застряли, а с другой стороны использует select()able IPC для связи с вашим последовательным кодом.

3 голосов
/ 14 марта 2011

Храните то, что вы получили от сообщения, в каком-либо буфере.

Если вы не хотите блокировать во время ожидания новых данных, используйте что-то вроде select () дляпоследовательный порт для проверки доступности дополнительных данных.Если нет, вы можете продолжать выполнять некоторую обработку или все, что нужно сделать, вместо того, чтобы блокировать, пока не будут получены данные для извлечения.

Когда поступят остальные данные, добавьте в буфер и проверьте, достаточно лисоставляют полное сообщение.Если есть, обработайте его и удалите из буфера.

2 голосов
/ 14 марта 2011

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

Если он недействителен или не будет в приемлемые сроки, то вы бросаете его. В противном случае вы сохраните его и обработаете.

Обычно это называется реализацией синтаксического анализатора для протокола устройства.

0 голосов
/ 14 марта 2011

Необходим алгоритм (блокировка):

while(! complete_packet(p) &&  time_taken < timeout)
{
   p += reading_device.read(); //only blocks for t << 1sec. 

   time_taken.update();   
}
//now you have a complete packet or a timeout. 

При желании вы можете добавить обратный вызов или добавить соответствующие части в циклы обработки.

...