Что вызывает спорадическую ошибку в SerialPort.Write под Mono?
Я использую USB-соединение (FTDI) от Linux к Arduino Nano под Mono. Это в основном работает, но через некоторое время я получаю, по-видимому, случайное время, TimeoutException, пытаясь записать в SerialPort. Очевидно (см. FIXME и соответствующий отчет об ошибке), любая ошибка в Write приведет к возникновению TimeoutException, и нет задержки по времени, поэтому я думаю, что будет справедливо предположить, что это на самом деле не тайм-аут, а просто ошибка,
Моно код:
// FIXME: this reports every write error as timeout
if (write_serial (fd, buffer, offset, count, write_timeout) < 0)
throw new TimeoutException("The operation has timed-out");
Здесь (смотрите write_serial) - вызываемая оболочка Mono, которая, по-видимому, превращает любой результат ошибки из "poll" или "write" в простой результат ошибки -1.
Mono Helper:
int
write_serial (int fd, guchar *buffer, int offset, int count, int timeout)
{
struct pollfd pinfo;
guint32 n;
pinfo.fd = fd;
pinfo.events = POLLOUT;
pinfo.revents = POLLOUT;
n = count;
while (n > 0)
{
ssize_t t;
if (timeout != 0) {
int c;
while ((c = poll (&pinfo, 1, timeout)) == -1 && errno == EINTR)
;
if (c == -1)
return -1;
}
do {
t = write (fd, buffer + offset, n);
} while (t == -1 && errno == EINTR);
if (t < 0)
return -1;
offset += t;
n -= t;
}
return 0;
}
У меня не было проблем с подключением из Windows/.NET к тому же устройству и с использованием того же кода записи (вы увидите ниже).
Это оставляет меня в растерянности относительно того, как даже диагностировать это без написания каких-либо обширных C-тестов, которые, я надеюсь, будут воспроизводить те же шаблоны ввода-вывода и синхронизацию, что и мой текущий код. Есть снифферы портов, но это будет просто захватывать данные, а не диагностировать и выдавать ошибку. Возможно, есть способ отловить и записать ошибки ввода-вывода в ядре Linux?
Мой код довольно прост. Вот соответствующий фрагмент:
_port = new SerialPort(portName, Configuration.BaudRate);
_port.NewLine = "\n";
_port.ReadTimeout = Configuration.StartupCommandTimeout; // 7000ms
_port.WriteTimeout = Configuration.StartupCommandTimeout;
_port.Open();
_port.WriteLine(command);
Это всегда происходит вне основного потока, хотя не всегда может происходить в том же потоке, из которого был построен порт, из которого считаны данные и каким-либо другим образом записаны.
Использование Mono версии 3.2.8, хотя приведенный ниже код взят от Master, так как не изменился. Я использую Ubuntu 15.10 на ARM.
1 ответ
В моей системе управления у меня много потоков, выполняющихся одновременно. Давая повышенный приоритет потока (ThreadPriority.AboveNormal) субъекту (по существу, потоку), который обслуживает последовательный порт, я, кажется, минимизировал или, возможно, устранил проблему. Возможно, Linux более чувствителен к проблемам с нехваткой службы последовательного порта, чем Windows, или это различное оборудование.