Здравствуйте, коллеги!
Проблема заключается в следующем: Есть устройство, работающее по Comm-порту, есть к нему утилита (написана на Borland Delphi или Builder), и есть протокол общения с этим устройством, который я реализовал в своей программе. Но есть одно, но, когда я пытаюсь загрузить данные, то это происходит с меньшей скоростью чем из родной утилиты (примерно в 2 раза). В снифере ком-порта видно, при работе родной утилиты идут сумасшедшие запросы IRP_MJ_DEVICECONTROL:IOCTL_SERIAL_GET_COMMSTATUS, а из моей IRP_MJ_WRITE.
Так вопрос собственно почему так происходит? И как можно настроить RS232, на максимальное быстродействие при заданных коммуникационных параметрах [38400, N, 8, 1]?
Здравствуйте, baxus, Вы писали:
B>когда я пытаюсь загрузить данные, то это происходит с меньшей скоростью чем из родной утилиты (примерно в 2 раза).
Навряд дело в настройках, я ставлю на реализацию алгоритма. Например, возможная причина — родная утилита при вызове ReadFile указывает точный размер блока(или читает побайтно), передаваемый устройством, А Вы — несколько больший. Считывается при этом все равно столько байт, сколько передавало ус-во, но чтение завершается по таймауту, увеличивая время операции на его величину. Способы борьбы — указывать точный размер блока, если он вам известен, а если нет, хотя бы поставить таймаут минимально допустимым.
Еще одна возможная причина — родная утилита начинает операцию записи не дожидаясь окончания предыдущего чтения, а Вы — дожидаетесь. Если протокол позволяет такое.
Здравствуйте, baxus, Вы писали:
B>Здравствуйте, коллеги!
Еще можно предположить, что Вы пишите/читаете синхронно, а утилита асинхронно. Не знаю правда насколько верно предположение.
Здравствуйте, baxus, Вы писали:
B>Здравствуйте, коллеги! B>Проблема заключается в следующем: Есть устройство, работающее по Comm-порту, есть к нему утилита (написана на Borland Delphi или Builder), и есть протокол общения с этим устройством, который я реализовал в своей программе. Но есть одно, но, когда я пытаюсь загрузить данные, то это происходит с меньшей скоростью чем из родной утилиты (примерно в 2 раза). В снифере ком-порта видно, при работе родной утилиты идут сумасшедшие запросы IRP_MJ_DEVICECONTROL:IOCTL_SERIAL_GET_COMMSTATUS, а из моей IRP_MJ_WRITE. B>Так вопрос собственно почему так происходит? И как можно настроить RS232, на максимальное быстродействие при заданных коммуникационных параметрах [38400, N, 8, 1]?
Стоит взглянуть, что показывает сниффер в момент настройки порта этой утилитой.
Судя по обилию IOCTL_SERIAL_GET_COMMSTATUS, родная утилита использует асиннхронный режим обмена, возможно с отключенными таймаутами. Вызывает WaitCommEvent + WaitForMultipleObjects (или MsgWaitForMultipleObjects), а по срабатыванию вызовом ClearCommError получает размер данных в буфере порта, поэтому ей вообще не приходится ждать лишнее время, хотя и чуть-чуть увеличивает загрузку процессора, но вряд-ли это можно заметить.
А вообще конечно оптимальный подход сильно зависит от прикладного протокола.
Здравствуйте, Tujh, Вы писали:
T>Здравствуйте, baxus, Вы писали:
B>>Здравствуйте, коллеги! T>Еще можно предположить, что Вы пишите/читаете синхронно, а утилита асинхронно. Не знаю правда насколько верно предположение.
Пробовал и асинхронно и синхронно, эффект один и тот же
Здравствуйте, Mizantrop, Вы писали:
M>Здравствуйте, baxus, Вы писали:
B>>Здравствуйте, коллеги! B>>Проблема заключается в следующем: Есть устройство, работающее по Comm-порту, есть к нему утилита (написана на Borland Delphi или Builder), и есть протокол общения с этим устройством, который я реализовал в своей программе. Но есть одно, но, когда я пытаюсь загрузить данные, то это происходит с меньшей скоростью чем из родной утилиты (примерно в 2 раза). В снифере ком-порта видно, при работе родной утилиты идут сумасшедшие запросы IRP_MJ_DEVICECONTROL:IOCTL_SERIAL_GET_COMMSTATUS, а из моей IRP_MJ_WRITE. B>>Так вопрос собственно почему так происходит? И как можно настроить RS232, на максимальное быстродействие при заданных коммуникационных параметрах [38400, N, 8, 1]?
M>Стоит взглянуть, что показывает сниффер в момент настройки порта этой утилитой. M>Судя по обилию IOCTL_SERIAL_GET_COMMSTATUS, родная утилита использует асиннхронный режим обмена, возможно с отключенными таймаутами. Вызывает WaitCommEvent + WaitForMultipleObjects (или MsgWaitForMultipleObjects), а по срабатыванию вызовом ClearCommError получает размер данных в буфере порта, поэтому ей вообще не приходится ждать лишнее время, хотя и чуть-чуть увеличивает загрузку процессора, но вряд-ли это можно заметить.
M>А вообще конечно оптимальный подход сильно зависит от прикладного протокола.
Нагрузка процессора около 50% при запуске утилиты.
Выяснил, что таймауты утилита выставляет следующие, а еще задает следующие значения:
Здравствуйте, sz36, Вы писали:
S>Здравствуйте, baxus, Вы писали:
B>>когда я пытаюсь загрузить данные, то это происходит с меньшей скоростью чем из родной утилиты (примерно в 2 раза). S> Навряд дело в настройках, я ставлю на реализацию алгоритма. Например, возможная причина — родная утилита при вызове ReadFile указывает точный размер блока(или читает побайтно), передаваемый устройством, А Вы — несколько больший. Считывается при этом все равно столько байт, сколько передавало ус-во, но чтение завершается по таймауту, увеличивая время операции на его величину. Способы борьбы — указывать точный размер блока, если он вам известен, а если нет, хотя бы поставить таймаут минимально допустимым.
Родная утилита шлет данные по одному байту, соответственно и я стал так делать, но это не помогло.
S> Еще одна возможная причина — родная утилита начинает операцию записи не дожидаясь окончания предыдущего чтения, а Вы — дожидаетесь. Если протокол позволяет такое.
Данные которые отсылаются делятся на пакет по 48 байт, после отправки которых приходит ответ из одного байта, так что я думаю пропуск чтения этого одного байта ничего не дает.
Таймауты тоже странноваты, похоже просто "для галочки".
B>Я просто думаю нет ли какого-нибудь способа писать в порт помимо метода WriteFile(), например с помощью управляющих кодов DeviceIOControl?
Это Вам ничего не даст, на скоростях работы СОМ-порта это сущие пустяки.
Конечно, надо-бы подробное описание протокола, но исходя из изложенного я бы сделал так:
Вся работа — в отдельном потоке с повышенным приоритетом. Ему передаётся весь объём данных одним буфером. Порт открывается в асинхронном режиме, таймауты отключаются. В цикле пишем в порт 48 байт, вызываем WaitCommEvent и начинаем ждать XXXWaitForXXX. Если EV_RXCHAR придёт раньше чем EV_TXEMPTY — явно ошибка. После получения EV_TXEMPTY либо ждём EV_RXCHAR с разумным таймаутом с учётом времени реакции устройства, либо сразу вызываем ReadFile. Получив EV_RXCHAR, считываем один байт и переходим в начало цикла, т.е. к отправке следующих 48-ми байт. При этом никакого копирования из одного буфера в другой, во WriteFile передаём указатель на данные в исходном буфере, сдвигая его после каждой отправки. Вряд-ли можно придумать что-то более быстрое.
Здравствуйте, baxus, Вы писали:
B>Здравствуйте, коллеги! B>Проблема заключается в следующем: Есть устройство, работающее по Comm-порту, есть к нему утилита (написана на Borland Delphi или Builder), и есть протокол общения с этим устройством, который я реализовал в своей программе. Но есть одно, но, когда я пытаюсь загрузить данные, то это происходит с меньшей скоростью чем из родной утилиты (примерно в 2 раза). В снифере ком-порта видно, при работе родной утилиты идут сумасшедшие запросы IRP_MJ_DEVICECONTROL:IOCTL_SERIAL_GET_COMMSTATUS, а из моей IRP_MJ_WRITE. B>Так вопрос собственно почему так происходит? И как можно настроить RS232, на максимальное быстродействие при заданных коммуникационных параметрах [38400, N, 8, 1]?
Спасибо всем кто как-то поучавствовал.
Проблема решилась откуда не ждали, просто устройство оказалось портозависимое. При подключении его к плате расширения COMM-портов все заработало