2014-08-26 6 views
0

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

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

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

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

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

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

система: Язык: C++ Совет: BeagleBone Black

+0

Вы действительно не хотите этого делать в пользовательском пространстве. Если драйвер последовательного порта не поддерживает ** TIOCSRS485 ** ioctl, то улучшите этот драйвер, выполнив его. См. Http://stackoverflow.com/questions/25250731/automatically-changing-rts-for-rs-485-communication/25253003#25253003 – sawdust

ответ

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 нить, но я работаю на RS-485 с 16550-совместимый UART под Linux и найти

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^