Эта идиотская проблема отняла два дня моей жизни, так что оставлю это тут, для тех кто будет гуглить также как это делал я и ничего не найдет.
Ключевые слова для поиска:
- Задержки при чтении из ком порта и рс-232
- Низкая скорость обмена по ком порту и рс-232
- read delays com port RS-232
- winapi c# serialport port driver
- COMMPROP COMMTIMEOUTS FTDI Latency time
Суть проблемы - писал программу по общению железки с компьютером через виртуальный ком порт (FTDI). Общение - небольшими пактами по несколько байт. На прием каждого пакета уходило около 20 мс. При этом мне необходимо передавать около 200 пакетов в секунду, что значит, что задержка на один пакет не должна превышать 5мс, а лучше - меньше. Стал смотреть в чем дело - задержка возникала при чтении из ком порта с помощью стандартного класса serial port .NET Стал копаться дальше - стало понятно, что проблема с буферизацией и таймаутами. В драйвере есть некоторый софтверный буфер и о принятых байтах драйвер сообщает не сразу, а когда этот буфер заполняется или когда проходит таймаут после последнего принятого байта. Стал копать в сторону таймаутов. Функционал класса serialport далеко не безупречен и не позволяет полностью контролировать настройки драйвера, в то время как стандартные функции winapi позволяют. Стал копать в сторону реализации класса для работы с ком портом на основе импортированных из winapi функций. С учетом того что я на C#, да и вообще под винду на PC прогаю вторую неделю как - это было не очень просто для понимания. Нашел сторонний класс, прикрутил к своей программе и, ничего не изменилось. Стал смотреть дальше - в настройках ком порта, если нажать на кнопочку "дополнительно" то можно увидеть такое окошко:
Поначалу я больше обращал внимание на размер буфера, но потом увидел, что если поменять "Время ожидания" на 1мс, то передача становится практически мгновенной. Отлично, осталось найти, как это значение поменять из программы. написал импорт функций винапи, которые позволили загрузить и посмотреть все структуры для настройки ком порта. Посмотрел - нигде нет этих пресловутых 16мс. Стал гуглить на русском - ноль информации, кроме как советы снизить "время ожидания" вручную. Нашел как окошко выглядит на английском, поле называется Latency time. Это очень быстро привело к ответу на все вопросы. Оказывается это поле есть только у ком портов FTDI. Настроить ее через винапи и тем более класс serialport .NET нельзя!
Зато можно вот так:
В самом FTDI пишут:
http://www.ftdichip.com/Support/Knowledgebase/index.html?an232b_04adjlatency.htmFTDI's R, C and BM series chips allow the latency timer to be changed from 16 milliseconds to any value from 1 to 255 milliseconds, in 1 millisecond increments. When using the FTDI Virtual COM Port driver the latency timer can be set in the port properties page. In Windows, the port properties page is accessed via the Control Panel > System > Device Manager. For Windows 2000 and XP, the initial value of the latency timer can also be pre-configured in ftdiport.inf by changing the value of the last number in the following line:
[FtdiPort.NT.HW.AddReg]
HKR,,"LatencyTimer",0x00010001,16
where again, 16 milliseconds is the default value.
Есть ли такая радость у других преобразователей - не знаю, если кто проверит на CP2102 и прочих - скажу спасибо :)
Итого:
Плюсы:
-решил проблему;
-узнал много нового про то как работает винда, идет взаимодействие с драйверами и т.п.;
-немного поработал с winapi:
Минусы:
-чуть не сломал мозг;
-потратил на эту хрень два дня жизни.
П.С. Что интересно - если гуглить про задержки при работе с ком портом - можно найти несколько подобных проблем, возникавших у людей, причем практически все они без решения. Но нигде, нигде я не видел упоминаний про FTDI или про latency timer.
П.С.2 особенно доставили некоторые комментаторы, толком не разбирающиеся в вопросах, но пишущие на форумах что-то вроде "ком порт - очень медленное устройство, при работе с современными компьютерами проблем с задержками быть не может". Ха-ха. Компьютер конечно быстрее, но только сделано все слишком уж громоздко. МК отвечает на запрос компьютера за несколько десятков микросекунд максимум. Компьютер с виндой, которой до реального времени как до луны - отвечает в течение миллисекунд - минимум!
П.С.3 Попробуйте создать файл с именем com1.txt, на рабочем столе, например ;)
UPD: Грязный хак! Как гласит документация на FTDI - сигналом для отправки буфера кроме всего вышеописанного является изменение одной из хардверных линий - CTS/DSR/DCD/RI. Соответственно достаточно дергать одну из этих линий в конце каждого пакета или же, поступить еще брутальнее - просто закоротить эту линию с RX. Проверенно, работает :)