Linux-опрос о завершении последовательной передачи

0

Я реализую RS485 на платформе разработки рук, используя последовательный порт и gpio для включения данных.

Я устанавливаю разрешение данных на высокий уровень перед отправкой, и я хочу, чтобы он был установлен на низком уровне после завершения передачи.

Это можно просто сделать, написав:

//fd = open("/dev/ttyO2", ...);
DataEnable.Set(true);
write(fd, data, datalen);
tcdrain(fd); //Wait until all data is sent
DataEnable.Set(false);

Я хотел перейти из режима блокировки в неблокирующий и использовать опрос с помощью fd. Но я не вижу никакого события опроса, соответствующего "полной передаче".

Как я могу получить уведомление, когда все данные были отправлены?

Система: linux Язык интерфейса: c++ Board: BeagleBone Black

  • 0
    Вы действительно не хотите делать это в пространстве пользователя. Если драйвер последовательного порта не поддерживает ioctl TIOCSRS485 , улучшите этот драйвер, внедрив его. См. Stackoverflow.com/questions/25250731/…
Теги:
rs485
polling
uart

2 ответа

1

Я не думаю, что это возможно. Вам придется либо запустить tcdrain в другом потоке, либо уведомить об этом основной поток, либо использовать тайм-аут в poll и опросе, чтобы узнать, был ли выход изъят.

Вы можете использовать TIOCOUTQ ioctl для получения количества байтов в выходном буфере и настройки таймаута в соответствии со скоростью передачи. Это должно уменьшить количество опросов, которые вам нужно сделать всего один или два раза. Что-то вроде:

 enum { writing, draining, idle } write_state;
 while(1) {
     int write_event, timeout = -1;
     ...
     if (write_state == writing) {
         poll_fds[poll_len].fd = write_fd;
         poll_fds[poll_len].event = POLLOUT;
         write_event = poll_len++
     } else if (write == draining) {
         int outq;
         ioctl(write_fd, TIOCOUTQ, &outq);
         if (outq == 0) {
             DataEnable.Set(false);
             write_state = idle;
         } else {
             // 10 bits per byte, 1000 millisecond in a second
             timeout = outq * 10 * 1000 / baud_rate; 
             if (timeout < 1) {
                 timeout = 1;
             }
         }
     }
     int r = poll(poll_fds, poll_len, timeout);
     ...
     if (write_state == writing && r > 0 && (poll_fds[write_event].revent & POLLOUT)) {
         DataEnable.Set(true); // Gets set even if already set. 
         int n = write(write_fd, write_data, write_datalen);
         write_data += n;
         write_datalen -= n;
         if (write_datalen == 0) {
             state = draining;
         }
     }
 }
0

Stale thread, но я работал над RS-485 с 16500-совместимым UART под Linux и нашел

  • tcdrain работает, но добавляет задержку от 10 до 20 мс. Кажется, будет опрошено
  • Значение, возвращаемое TIOCOUTQ, похоже, подсчитывает байты в буфере ОС, но НЕ байты в UIF FIFO, поэтому он может недооценивать задержку, требуемую, если передача уже началась.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню