Как правильно настроить RS232
От: baxus  
Дата: 03.09.09 16:32
Оценка:
Здравствуйте, коллеги!
Проблема заключается в следующем: Есть устройство, работающее по Comm-порту, есть к нему утилита (написана на Borland Delphi или Builder), и есть протокол общения с этим устройством, который я реализовал в своей программе. Но есть одно, но, когда я пытаюсь загрузить данные, то это происходит с меньшей скоростью чем из родной утилиты (примерно в 2 раза). В снифере ком-порта видно, при работе родной утилиты идут сумасшедшие запросы IRP_MJ_DEVICECONTROL:IOCTL_SERIAL_GET_COMMSTATUS, а из моей IRP_MJ_WRITE.
Так вопрос собственно почему так происходит? И как можно настроить RS232, на максимальное быстродействие при заданных коммуникационных параметрах [38400, N, 8, 1]?
Re: Как правильно настроить RS232
От: sz36 Россия  
Дата: 03.09.09 21:22
Оценка:
Здравствуйте, baxus, Вы писали:

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

Навряд дело в настройках, я ставлю на реализацию алгоритма. Например, возможная причина — родная утилита при вызове ReadFile указывает точный размер блока(или читает побайтно), передаваемый устройством, А Вы — несколько больший. Считывается при этом все равно столько байт, сколько передавало ус-во, но чтение завершается по таймауту, увеличивая время операции на его величину. Способы борьбы — указывать точный размер блока, если он вам известен, а если нет, хотя бы поставить таймаут минимально допустимым.
Еще одна возможная причина — родная утилита начинает операцию записи не дожидаясь окончания предыдущего чтения, а Вы — дожидаетесь. Если протокол позволяет такое.
Re: Как правильно настроить RS232
От: Tujh Голландия  
Дата: 04.09.09 04:09
Оценка:
Здравствуйте, baxus, Вы писали:

B>Здравствуйте, коллеги!

Еще можно предположить, что Вы пишите/читаете синхронно, а утилита асинхронно. Не знаю правда насколько верно предположение.
Re: Как правильно настроить RS232
От: Mizantrop  
Дата: 04.09.09 05:07
Оценка:
Здравствуйте, 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 получает размер данных в буфере порта, поэтому ей вообще не приходится ждать лишнее время, хотя и чуть-чуть увеличивает загрузку процессора, но вряд-ли это можно заметить.

А вообще конечно оптимальный подход сильно зависит от прикладного протокола.
"Нормальные герои всегда идут в обход!"
Re[2]: Как правильно настроить RS232
От: baxus  
Дата: 04.09.09 07:09
Оценка:
Здравствуйте, Tujh, Вы писали:

T>Здравствуйте, baxus, Вы писали:


B>>Здравствуйте, коллеги!

T>Еще можно предположить, что Вы пишите/читаете синхронно, а утилита асинхронно. Не знаю правда насколько верно предположение.

Пробовал и асинхронно и синхронно, эффект один и тот же
Re[2]: Как правильно настроить RS232
От: baxus  
Дата: 04.09.09 07:26
Оценка:
Здравствуйте, 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% при запуске утилиты.
Выяснил, что таймауты утилита выставляет следующие, а еще задает следующие значения:
DCB dcb;
//...
dcb.XonLim = 2048;
dcb.XoffLim = 512

COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = 50; 
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 30000;


Я просто думаю нет ли какого-нибудь способа писать в порт помимо метода WriteFile(), например с помощью управляющих кодов DeviceIOControl?
Re[2]: Как правильно настроить RS232
От: baxus  
Дата: 04.09.09 07:31
Оценка:
Здравствуйте, sz36, Вы писали:

S>Здравствуйте, baxus, Вы писали:


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

S> Навряд дело в настройках, я ставлю на реализацию алгоритма. Например, возможная причина — родная утилита при вызове ReadFile указывает точный размер блока(или читает побайтно), передаваемый устройством, А Вы — несколько больший. Считывается при этом все равно столько байт, сколько передавало ус-во, но чтение завершается по таймауту, увеличивая время операции на его величину. Способы борьбы — указывать точный размер блока, если он вам известен, а если нет, хотя бы поставить таймаут минимально допустимым.

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

S> Еще одна возможная причина — родная утилита начинает операцию записи не дожидаясь окончания предыдущего чтения, а Вы — дожидаетесь. Если протокол позволяет такое.


Данные которые отсылаются делятся на пакет по 48 байт, после отправки которых приходит ответ из одного байта, так что я думаю пропуск чтения этого одного байта ничего не дает.
Re[3]: Как правильно настроить RS232
От: Mizantrop  
Дата: 04.09.09 08:46
Оценка: 1 (1)
Здравствуйте, baxus, Вы писали:

B>Нагрузка процессора около 50% при запуске утилиты.


Что-то многовато, похоже на банальный поллинг.

B>COMMTIMEOUTS timeouts;

B>timeouts.ReadIntervalTimeout = 50;
B>timeouts.ReadTotalTimeoutMultiplier = 0;
B>timeouts.ReadTotalTimeoutConstant = 0;
B>timeouts.WriteTotalTimeoutMultiplier = 0;
B>timeouts.WriteTotalTimeoutConstant = 30000;

Таймауты тоже странноваты, похоже просто "для галочки".

B>Я просто думаю нет ли какого-нибудь способа писать в порт помимо метода WriteFile(), например с помощью управляющих кодов DeviceIOControl?


Это Вам ничего не даст, на скоростях работы СОМ-порта это сущие пустяки.

Конечно, надо-бы подробное описание протокола, но исходя из изложенного я бы сделал так:

Вся работа — в отдельном потоке с повышенным приоритетом. Ему передаётся весь объём данных одним буфером. Порт открывается в асинхронном режиме, таймауты отключаются. В цикле пишем в порт 48 байт, вызываем WaitCommEvent и начинаем ждать XXXWaitForXXX. Если EV_RXCHAR придёт раньше чем EV_TXEMPTY — явно ошибка. После получения EV_TXEMPTY либо ждём EV_RXCHAR с разумным таймаутом с учётом времени реакции устройства, либо сразу вызываем ReadFile. Получив EV_RXCHAR, считываем один байт и переходим в начало цикла, т.е. к отправке следующих 48-ми байт. При этом никакого копирования из одного буфера в другой, во WriteFile передаём указатель на данные в исходном буфере, сдвигая его после каждой отправки. Вряд-ли можно придумать что-то более быстрое.
"Нормальные герои всегда идут в обход!"
Re: Проблема решена
От: baxus  
Дата: 07.09.09 14:25
Оценка:
Здравствуйте, 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-портов все заработало
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.