|
|
|
сниффер ком порта |
|
|
|
Sep 6 2016, 13:56
|
Группа: Участник
Сообщений: 14
Регистрация: 8-08-15
Пользователь №: 87 893
|
Всем доброго дня. Есть сеть устройств, работающих по протоколу модбас через RS485. Необходимо написать перехватчик сообщений для ком порта, способный ловить паузы между сообщениями. Вот как поймать паузы, пока не соображу. Драйвер возвращает пачки по несколько байт, но поймать получается только длинные паузы (между запросами), а вот разделить запрос-ответ пока не могу. Есть программы снифферы, которые как-то реализуют такую возможность. Надо написать свою, в которой данные преобразовать в удобоваримый вид, удобный для отладки работы сети устройств. В винде это наверное тяжело будет сделать, но может есть способ, о котором я пока не знаю.
|
|
|
|
|
Sep 6 2016, 14:24
|
Участник
Группа: Участник
Сообщений: 25
Регистрация: 14-08-16
Пользователь №: 92 949
|
Можно принимать байты по одному с таймаутом, т.е. таймаут только на приём одного байта. Пока синхронизация приёма пакетов не нарушилась работаем только с crc, если нарушилась, то устанавливаем таймаут равный времени приёма одного байта + небольшой запас (не помню интервал тишины в modbus, вроде три байта). Если передача идёт по стандарту modbus, то таймаут на два-три байта тишины должен помочь
|
|
|
|
|
Sep 6 2016, 14:39
|
Группа: Участник
Сообщений: 14
Регистрация: 8-08-15
Пользователь №: 87 893
|
Такой вариант я рассматривал, но здесь ключевая фраза, если принята без ошибок. Самый надёжный способ - именно ловить паузы.
Эксперименты с таймаутом особо не помогают. При скорости 115200 время передачи байта составляет 95мкс, а таймауты устанавливаются в миллисекундах. Основную проблему я вижу в том, что драйвер подбирает у системы данные с некоторым периодом. Программа у драйвера запрашивает данные тоже с каким-то периодом. За это время фактически драйвер может взять у системы несколько байт. Причём может схватить хвост запроса и начало ответа. Отсюда и лезут проблемы.
|
|
|
|
|
Sep 6 2016, 15:06
|
Участник
Группа: Участник
Сообщений: 25
Регистрация: 14-08-16
Пользователь №: 92 949
|
т.е. вы подключаетесь к какой либо паре устройств работающих по modbus (запросы отправляете не вы) и задача стоит разобрать протокол (синхронизироваться)? если да, то можно со сдвигом принятых данных считать crc и где crc верна, там и есть начало пакета. Определить "запрос" или "ответ" можно уже по протоколу.
|
|
|
|
|
Sep 6 2016, 18:08
|
Знающий
Группа: Участник
Сообщений: 745
Регистрация: 28-12-06
Пользователь №: 23 960
|
Цитата(Alex_2015 @ Sep 6 2016, 17:39) Основную проблему я вижу в том, что драйвер подбирает у системы данные с некоторым периодом. Программа у драйвера запрашивает данные тоже с каким-то периодом. За это время фактически драйвер может взять у системы несколько байт. Причём может схватить хвост запроса и начало ответа. Отсюда и лезут проблемы. Вы все правильно понимаете. Вывод из этого простой : стандартные ОС со стандартными компортами (обычно 16550-compatible) ловить таймауты modbus-rtu неспособны. Ставьте конвертор на МК.
|
|
|
|
|
Sep 7 2016, 06:47
|
Профессионал
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848
|
Если пишете сами, попробуйте использовать таймауты драйвера см. тутПисать надо на достаточно низком, в хорошем смысле, уровне. С, CPP PAS, с событиями-потоками. Win32API, ReadFileEx() etc. Для модбаса надо отлавливать паузы 3.5 байта.
|
|
|
|
|
Sep 7 2016, 12:42
|
Группа: Участник
Сообщений: 14
Регистрация: 8-08-15
Пользователь №: 87 893
|
На тему конвертора мысли были. Но только на самый крайний случай. Сейчас пока используется модифицированный модбас, в котором есть признаки, позволяющие однозначно определять начало и конец посылок. Есть потребность перейти к стандартному модбасу и будет нужна прога, которая позволит в реальном времени отслеживать обмен между устройствами в целях отладки. Сегодня перечитывал старую информацию, которую использовал при освоении программирования ком порта и нашёл то, что пропустил. Есть в структуре DCB символ XOFCHAR, который позволяет определить конец посылки. Осталось непонятным, его записывает драйвер в массив приёма или этот символ должен быть записан передатчиком в конец сообщения. Интернет по этому поводу подробностей пока не дал. Буду пробовать экспериментально. Была ещё мысль отслеживать событие DCD data carrier detect, но боюсь оно ожидаемого результата не даст. Была мысль алгоритмически ловить конец посылки через подсчёт CRC, но вариант не самый красивый. Хотя должен привести к результату.
|
|
|
|
|
Sep 7 2016, 18:22
|
Гуру
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713
|
Цитата(DASM @ Sep 6 2016, 21:56) честно говоря я бы такую задачу решал иначе. А именно - сниффер пишется на МК, и отдает пакеты в комп приплюсовывая к ним time stamp Я бы тоже решал по-другому. А именно: с открытия MSDN и прочтения всего, что касается работы с COM-портом. Чего автор как видно не сделал. Иначе он знал бы о функции SetCommTimeouts() WinAPI и многих других полезных. А не строил пустые предположения. Далее: установил-бы ReadIntervalTimeout and ReadTotalTimeoutMultiplier to MAXDWORD and sets ReadTotalTimeoutConstant to a value greater than zero and less than MAXDWORDкак советует MSDN, повысил приоритет принимающего потока, а также прочитал в MSDN про семейство функций QueryPerformanceFrequency()/QueryPerformanceCounter() и понял бы, что даже 95мкс - не есть проблема. Другое дело что всё это лучше делать на железном RS-232 компа, а не USB-COM переходнике, времянки которого сомнительны. Даже и с железным COM-портом и приоритетом потока ==REALTIME возможно будут проблемы из-за работы других драйверов винды (винта, видео и т.п.). Так что возможно лучше вынести такую работу на уровень драйверов. Цитата(Alex_2015 @ Sep 7 2016, 18:42) Есть в структуре DCB символ XOFCHAR, который позволяет определить конец посылки. Это вообще из другой оперы. Это для software flowcontrol. Цитата(Alex_2015 @ Sep 7 2016, 18:42) Была мысль алгоритмически ловить конец посылки через подсчёт CRC, но вариант не самый красивый. Хотя должен привести к результату. Лучше откройте наконец-то MSDN, а не занимайтесь ерундой.
|
|
|
|
|
Sep 8 2016, 01:23
|
Группа: Участник
Сообщений: 14
Регистрация: 8-08-15
Пользователь №: 87 893
|
Читал я MSDN в своё время, когда осваивал программирование ком порта. Но это ни чего не даёт. Когда драйвер захочет вернуть данные пользовательской программе, тогда и вернёт. И совсем не в режиме реального времени. А с таймоутами я экспериментировал, результат далёк от желаемого.
|
|
|
|
|
Sep 8 2016, 03:53
|
Гуру
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713
|
Цитата(zltigo @ Sep 8 2016, 03:06) К чему опрос счетчиков хоть с тактовой процессора, если их НЕЛЬЗЯ со сколь-нибудь детерминированной точностью привязать к событиям UART. ТСу нужно не опрашивать счётчики, а вести лог обмена по каналу UART. Причём с таймштампами точностью до десятков мкс. Ну или хотя-бы видеть, что между двумя соседними байтами X1 и X2 была хоть какая-то пауза, обнаруженная драйвером канала или её не было. Аппаратура UART 16550 позволяет определять наличие паузы, значит и драйвер это должен видеть. А функция SetCommTimeouts(), как следует из её описания, должна позволить получить эту инфу юзеру. Цитата(Alex_2015 @ Sep 8 2016, 07:23) Читал я MSDN в своё время, когда осваивал программирование ком порта. Но это ни чего не даёт. Когда драйвер захочет вернуть данные пользовательской программе, тогда и вернёт. И совсем не в режиме реального времени. Т.е. - Вы утверждаете что MSDN врёт, говоря, что: Код If an application sets ReadIntervalTimeout and ReadTotalTimeoutMultiplier to MAXDWORD and sets ReadTotalTimeoutConstant to a value greater than zero and less than MAXDWORD, one of the following occurs when the ReadFile function is called: If there are any bytes in the input buffer, ReadFile returns immediately with the bytes in the buffer. If there are no bytes in the input buffer, ReadFile waits until a byte arrives and then returns immediately. Читаем первую строку с "if" и вторую, видим там слово "immediately", думаем. Я почти уверен, что если приоритет вызывающего потока будет ==THREAD_PRIORITY_TIME_CRITICAL, а приоритет процесса ==REALTIME_PRIORITY_CLASS, то как только аппаратура UART зафиксирует, что в FIFO есть символы и с момента приёма последнего из них прошло более 3.5 символьных интервала, так сразу и вернёт управление вызывающему потоку. Возможно даже хватит меньших приоритетов у процесса/потока, главное - превысить приоритеты всех других работающих в системе потоков. И всё конечно зависит ещё от драйвера. Стандартный виндовый драйвер для UART 16550 на сис. шине должен соответствовать требованиям MSDN. Про сторонние драйвера UART, тем более для USB-UART речи нет - они могут только примерно соответствовать MSDN. Но думаю, если устройство, реализующее CDC-класс USB, при отправке данных, выделяет разные кадры ModBus в отдельные пакеты по USB, то и драйвер CDC-класса под виндой также сможет выполнить требования SetCommTimeouts().
|
|
|
|
|
|
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|