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

Я внедряю 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
Язык: с ++
Доска: BeagleBone Black

0

Решение

Я не думаю, что это возможно. Вам либо придется бежать 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;
}
}
}
1

Другие решения

Несвежий поток, но я работаю на RS-485 с 16550-совместимым UART под Linux и нахожу

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

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

0

По вопросам рекламы [email protected]