Перейти к содержанию
    

Windows7: прием байтов через COM-порт без потерь

Здравствуйте!

Есть Windows7 Pro, 32-bit, компьютер- китайский одноплатник на Intel 1037U, 4GB RAM.

СОМ-порты- 4 штуки прямо на материнке.

И есть внешний передатчик, посылающий в COM-порт пакеты.

Скорость- 115200, стандартный формат 8N1.

Длина пакета- не более 255 байт, межпакетный интервал- не менее 4 байт, часто гораздо больше (десятки миллисекунд). Каждый пакет имеет контрольную сумму (crc16), по которой и принимается решение о валидности пакета. Общая загрузка канала где-то 5-8 килобайт в секунду, то есть до 80%. Загрузка CPU около 10-15%.

 

И есть самописная программа на С++Билдере (6), данный вариант делался по прерываниям, с несколькими потоками (базой был вот этот документ).

Есть поток, принимающий все байты по прерываниям и валящий в большой кольцевой буфер. И другой поток периодически выгребает байты из буфера и делит на пакеты для обработки, проверяет валидность.

 

Только прием, никаких переключений на передачу.

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

 

Обычно фактов потери байта где-то 10-20 в сутки. Корреляция с действиями Виндоуса пока не найдена, очень уж все случайно.

Потери именно в компьютере- подключенный прямо к этому же разъему логический анализатор исправно ловит все байты, никакого криминала или отклонений во времянке не обнаружено (по уровню тоже все без проблем)

 

 

Вопросов два:

1. Кто-то в подобных условиях добивался абсолютно безошибочного приема потока через COM-порт в Виндоус (7) на 115200?

2. куда копать? Сильно надеюсь что моя программа виновата. На другом железе пробовал- эффект тот же, то есть это не электроника глючит.

С приоритетами игрался, никакого эффекта.

 

Заранее спасибо за любые советы (по существу).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть поток, принимающий все байты по прерываниям и валящий в большой кольцевой буфер. И другой поток периодически выгребает байты из буфера и делит на пакеты для обработки, проверяет валидность.

Вот это место непонятно - для каждого порта свой буфер, или общий на все порты? выпадание байта определяете по сбою crc?

 

Что Вы называете "приемом по прерыванию"?

У выни свои прекрасные дрова для КОМ, и даже целый специальный апи в ядро встроен под устройства Comm - модемы проще. все известные мне либы в борланде являются прокладкой к этому стандартному АПИ. напрямую с прерыванием никто не работает.

проблем с потерями не было, хотя обмен бывал интенсивный - мегабод.

можно посоветовать покрутить :

1)объем буфферов кома (я делал 8кб)

2)приоритет нитки приемника сделать выше нормального

3)если у вас между пакетами есть пауза более 1мс, настроить ее в свойствах таймингов кома. в запросах асинхронного чтения возможно оно поможет АПИ возвращать целиком пакет а не куски случайно презанные.

4)какая может быть гарантия что порт вашего ПК видит ваш поток без потерь, даже если ваш снифер прекрасен? Вы в качестве снифера тот же самый ПК используете?

5) можно поставить прокси с журналированием на ком (я пользовал com0project, но их вроде множество разных), и уже к нему подключать вашу программу. в этом случае вы сможете сравнить поток принятый прокси с потоком принятым вашей софтиной.

6) вы журналировали поток считанный из порта, сравнить его с финальными нарезанными пакетами? точно эти байты не считываются из порта?

Изменено пользователем AlexRayne

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Начинать надо с того, что COM порт вообще и его реализация в Windows в частности, не гарантирует безошибочной передачи данных.

То есть рассчитывать на это нельзя, и контроль и/или обеспечение целостности данных надо реализовывать в протоколе обмена. Поврежненный пакед должен отбрасываться и если нужно передаваться повторно.

По возможным причинам. У стандартного аппаратного СОМ порта есть внутренний буфер, как правило размером 15 байт. Это не тот буфер, который задается в SetupComm. Если драйвер порта по каким-то причинам не успеет прочитать этот буфер, то принятые байты теряются, о чем извещают соответствующие флаги возвращаемые ClearCommError.

Приоритет пользовательского процесса не влиет на приоритет драйвера СОМ порта при обработке прерываний.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Начинать надо с того, что COM порт вообще и его реализация в Windows в частности, не гарантирует безошибочной передачи данных.

То есть рассчитывать на это нельзя, и контроль и/или обеспечение целостности данных надо реализовывать в протоколе обмена. Поврежненный пакед должен отбрасываться и если нужно передаваться повторно.

Парень сборется с другой проблемой - у него не пропадание сигнала на линии (этим он займется видимо позже, когда жареный петух клюнет), а пропадание байтов прямо на порте. можно это списать на особенности железа, но вероятность невелика

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

AlexRayne, большое спасибо за конструктивный ответ с кучей хороших идей!

Что именно Вы имеете в виде когда говорите про "прекрасные дрова для КОМ, и даже целый специальный апи в ядро встроен под устройства Comm"? Что именно советуете почитать-посмотреть, может даже применительно к простоте прикручивания в Билдер?

Я раньше работал по поллингу, и задачи другие были. А сейчас решил по прерываниям сделать, нашел понятное мне описание в интернете(ссылка в моем письме)- по нему и сделал.

 

Если уже есть компонент а или просто апишная функция "брать все байты из порта и кидать в большой пользовательский кольцевой буфер" - было бы замечательно. В пятом Билдере ставил пакет TurboPower Async Professional, но использовал по поллингу. Сейчас на новый (хихи) 6-й билдер перешел и думал без сторонних компонентов обойтись.

 

И это не железо, я пробовал на другом компьютере- эффект тоже имеет место быть.

И это действительно потеря в машине- прямо на порт включал независимый лог анализатор, и после сравнивал содержимое буферов его и моей программы.

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что Вы называете "приемом по прерыванию"?

У выни свои прекрасные дрова для КОМ, и даже целый специальный апи в ядро встроен под устройства Comm - модемы проще. все известные мне либы в борланде являются прокладкой к этому стандартному АПИ. напрямую с прерыванием никто не работает.

Нда, последнее сообщение автора прояснило что прерывание это не то прерывание о котором все подумали, а прерывание есть прерывание потока, по крайней мере так описано по ссылке :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Начинать надо с того, что COM порт вообще и его реализация в Windows в частности, не гарантирует безошибочной передачи данных.

То есть рассчитывать на это нельзя, и контроль и/или обеспечение целостности данных надо реализовывать в протоколе обмена. Поврежненный пакед должен отбрасываться и если нужно передаваться повторно.

По возможным причинам. У стандартного аппаратного СОМ порта есть внутренний буфер, как правило размером 15 байт. Это не тот буфер, который задается в SetupComm. Если драйвер порта по каким-то причинам не успеет прочитать этот буфер, то принятые байты теряются, о чем извещают соответствующие флаги возвращаемые ClearCommError.

Приоритет пользовательского процесса не влиет на приоритет драйвера СОМ порта при обработке прерываний.

Тоже думаю, что проблема просто в переполнении ФИФО аппаратного приёмника.

Потому, что винда тупо не успевает выгребать данные.

 

Но тогда надо проверить, флаг переполнения должен быть установлен.

 

Может, стоит попробовать адаптер COM->USB, там аппаратная буферизация может быть лучше, и ошибок не будет?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1. Дурацкий вопрос - а порты вообще с FIFO ? И оно включено ?

 

2. Как вариант, запустить какую-нибудь терминалку, залоггировать, а потом посмотреть - потери есть ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если Wind'а иногда не успевает выгребать данные из аппаратного буфера, может стоит подумать в сторону аппаратного управления потоком (RTS/CTS)?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 7 похоже, есть баг в COM драйвере. Многие программы, нормально работавшие с XP, глючат с ком-портами на 7. Единственное, что надежно под ней работает -USB-COM адаптер, причем с FTDI чипом.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я пересылал в комп пакеты данных на скорости 115200, сбоев не замечал. Формат был 8N2. Вот его и посоветую попробовать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я пересылал в комп пакеты данных на скорости 115200, сбоев не замечал. Формат был 8N2. Вот его и посоветую попробовать.

Да я тоже много чего пересылал, и на 480 кБод, и без сбоев. Насколько я понял, особенность проблем ТС в том, что данные идут постоянно, что в моей практике не встречается.

Хотя я Билдер не пользую, пишу в MSVC++ с отдельным потоком на прием и WaitCommEvent в том потоке с ивентом по каждому пришедшему байту...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Возможно, фантазирую, детально не вникал, полагаю, если стопов 2 или 1,5 то синхронизироваться по следующему старту можно точнее. Будет больше запаса на неравенство тактовых частот. А также увеличивается время для работы процессора.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

AlexRayne, большое спасибо за конструктивный ответ с кучей хороших идей!

Что именно Вы имеете в виде когда говорите про "прекрасные дрова для КОМ, и даже целый специальный апи в ядро встроен под устройства Comm"? Что именно советуете почитать-посмотреть, может даже применительно к простоте прикручивания в Билдер?

Вот это именно и имел ввиду - что вы путаете всех использованием слова "драйвер". В венде уже написаны дрова под множество материнок и уж тем более под известные стандартные контроллеры УАРТ. Вот они как раз напрямую с железом и прерыванием работают. писать их не требуется - они готовы и встроены в Ось. Овь прелагает довольно простое стандартное АПИ для работы с Сомм портами. Если вы поставили борланд - покурите их хелпы Win32 SDK или чтото вроде этого. Это огромный хелп по всем ресурсам венды. и в частности там описан и Comm интерфейс. Если вы полезете в изходники АсинкПро - то наглядно увидите как вендовые вызовы используются. АсинкПро - это обертка вендовых вызовов.

Когда я говорю "прекрасные" - значит они есть работают, отлажены, и проверены. (и удобны)

 

AlexRayne, большое спасибо за конструктивный ответ с кучей хороших идей!

 

Если уже есть компонент а или просто апишная функция "брать все байты из порта и кидать в большой пользовательский кольцевой буфер" - было бы замечательно. В пятом Билдере ставил пакет TurboPower Async Professional, но использовал по поллингу. Сейчас на новый (хихи) 6-й билдер перешел и думал без сторонних компонентов обойтись.

Большой буфер уже предоставляет Сомм интерфейс, размер его можно настраивать, по моей памяти он по умолчанию 4кБ делается. собственно из него и читается данные порта обычными файловыми чтениями.

По моему опыту - оказалось проще работать без оболочек, напрямую. это не требует стороннего кода и возни со сторонними пакетами.

требует освоения навыка работы с асинхронными вызовами венды чтения\записи файла - там их называют почемуто overlaped

 

AlexRayne, большое спасибо за конструктивный ответ с кучей хороших идей!

И это не железо, я пробовал на другом компьютере- эффект тоже имеет место быть.

И это действительно потеря в машине- прямо на порт включал независимый лог анализатор, и после сравнивал содержимое буферов его и моей программы.

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

 

Вам уже посоветовали использовать 1,5-2 стопбита. это хорошее предложение, если оно конечно возможно для ваших абонентов.

 

С адаптерами КОМ-УСБ советую не играться если есть нормальный порт на матери или PCI плате ввода вывода. Я встретил кривой адаптер от МОХи, народ жаловался на ФТДИ - у обоих проблемы с буфером приемника на больших трафиках.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кстати, о больших трафиках. Так ли они необходимы?

Очень много встречал профессиональных программистов, которые для своего личного удобства используют большие скорости и постоянно кидают в порт повторяющиеся данные (типа проверки связи и информации "я живой"). Причем в ситуациях, когда достаточно скорости 9600 и работы по принципу "запрос-ответ". А потом еще переносят эти принципы на радиоканал и забивают все вокруг.

Может, все-таки сначала подумать о минимизации трафика?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...