Добавить в цитаты Настройки чтения

Страница 308 из 436



Обычно функция BuldCommDCB изменяет только явно перечисленные в строке lpDef поля. Однако существуют два исключения из этого правила:

• При задании скорости обмена 110 бит в секунду автоматически устанавливается формат обмена с двумя стоповыми битами. Это сделано для совместимости с командой mode из MS-DOS или Windows NT.

• По умолчанию запрещается программное (XON/XOFF) и аппаратное управление потоком. Вы должны вручную заполнить требуемые поля DCB если требуется управление потоком.

Функция BuilCommDCB поддерживает как новый, так и старый форматы командной строки mode. Однако, Вы не можете смешивать эти форматы в одной строке.

Новый формат строки позволяет явно задавать значения для полей DCB отвечающих за управление потоком. При использовании старого формата существуют следующие соглашения:

— Для строк вида 9600,n,8,1 (не заканчивающихся символами х или р):

• flnX, fOutX,fOutXDsrFlow, fOutXCtsFlow устанавливаются в FALSE

• fDtrControl устанавливается в DTR_CONTROL_ENABLE

• fRtsControl устанавливается в RTS_CONTROL_ENABLE

— Для строк вида 9600,n,8,1,х (заканчивающихся символом х):

• flnX, fOutX устанавливаются в TRUE

• fOutXDsrFlow,fOutXCtsFlow устанавливаются в FALSE

• fDtrControl устанавливается в DTR_CONTROL_ENABLE

• fRtsControl устанавливается в RTS_CONTROL_ENABLE

— Для строк вида 9600,n,8,1,р (заканчивающихся символом р):

• flnX, fOutX устанавливаются в FALSE

• fOutXDsrFlow,fOutXCtsFlow устанавливаются TRUE

• fDtrControl устанавливается в DTR_CONTROL_HANDSHAKE

• fRtsControl устанавливается в RTS_CONTROL_HANDSHAKE

Следует заметить, что функция BuildCommDCB только заполняет поля DCB указанными значениями. Это подготовительный шаг к конфигурированию порта, но не само конфигурирование, которое выполняется рассматриваемыми далее функциями. Поэтому Вы можете вызвать BuildCommDCB для общего заполнения структуры DCB, затем изменить значения не устраивающих Вас полей, и после этого вызывать функцию конфигурирования порта.

Функция GetCommState

Заполнить DCB можно еще одним способом. Вызовом функции GetCommState. Эта функция заполняет DCB информацией о текущем состоянии устройства, точнее о его настройках. Вот как она выглядит:

BOOL GetCommState(

      HANDLE hFile,

      LPDCB lpDCB

);

Функция очень проста и имеет всего два параметра:

∙ hFile

Описатель открытого файла коммуникационного порта. Этот описатель возвращается функцией CreateFile. Следовательно, прежде чем получить параметры порта, Вы должны его открыть. Для функции BuildCommDCB это не требовалось.

∙ lpDCB

Указатель на DCB. Для DCB должен быть выделен блок памяти.

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





Функция SetCommState

Заполнив DCB можно приступать к собственно конфигурированию порта. Это делается с помощью функции SetCommState:

BOOL SetCommState(

      HANDLE hFile,

      LPDCB lpDCB

);

Эта функция имеет точно такие же параметры, как GetCommState. Различается только направление передачи информации. GetCommState считывает информацию из внутренних управляющих структур и регистров порта, а SetCommState наоборот заносит ее. Следует быть осторожным при вызове функции SetCommState, поскольку она изменит параметры даже в том случае, если очереди приема/передачи не пусты, что может вызвать искажение потока передаваемых или принимаемых данных.

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

Как всегда, в случае успешного завершения возвращается отличное от нуля значение, а в случае ошибки — нуль.

Структура COMMTIMEOUTS

Следующей важной управляющей структурой является COMMTIMEOUTS. Она определяет параметры временных задержек при приеме и передаче. Значения, задаваемые полями этой структуры, оказывают большое влияние на работу функций чтения/записи.

typedef struct _COMMTIMEOUTS {{

     DWORD ReadlntervalTimeout;

     DWORD ReadTotalTimeoutMultiplier;

     DWORD ReadTotalTimeoutConstant;

     DWORD WriteTotalTimeoutMultiplier;

     DWORD WriteTotalTimeoutConstant;

} COMMTIMEOUTS,*LPCOMMTIMEOUTS;

Поля структуры COMMTIMEOUTS имеют следующие значения:

∙ ReadlntervalTimeout

Максимальное время, в миллисекундах, допустимое между двумя последовательными символами, считываемыми с коммуникационной линии. Во время операции чтения временной период начинает отсчитываться с момента приема первого символа. Если интервал между двумя последовательными символами превысит заданное значение, операция чтения завершается и все данные, накопленные в буфере, передаются в программу. Нулевое значение данного поля означает, что данный тайм-аут не используется. Значение MAXDWORD, вместе с нулевыми значениями полей ReadTotalTimeoutConstant и ReadTotalTimeoutMultiplier, означает немедленный возврат из операции чтения с передачей уже принятого символа, даже если ни одного символа не было получено из линии.

∙ ReadTotalTimeoutMultiplier

Задает множитель, в миллисекундах, используемый для вычисления общего тайм-аута операции чтения. Для каждой операции чтения данное значение умножается на количество запрошенных для чтения символов.

∙ ReadTotalTimeoutConstant

Задает константу, в миллисекундах, используемую для вычисления общего тайм-аута операции чтения. Для каждой операции чтения данное значение прибавляется к результату умножения ReadTotalTimeoutMultiplier на количество запрошенных для чтения символов. Нулевое значение полей ReadTotalTimeoutMultiplier и ReadTotalTimeoutConstant означает, что общий тайм-аут для операции чтения не используется.

∙ WriteTotalTimeoutMuItiplier

Задает множитель, в миллисекундах, используемый для вычисления общего тайм-аута операции записи. Для каждой операции записи данное значение умножается на количество записываемых символов.

∙ WriteTotalTimeoutConstant

Задает константу, в миллисекундах, используемую для вычисления общего тайм-аута операции записи. Для каждой операции записи данное значение прибавляется к результату умножения WriteTotalTimeoutMultiplier на количество записываемых символов. Нулевое значение полей WriteTotalTimeoutMultiplier и WriteTotalTimeoutConstant означает, что общий тайм-аут для операции записи не используется.

По тайм-аутам обычно возникает много вопросов. Поэтому попробую объяснить подробнее. Пусть мы считываем 50 символов из порта со скоростью 9600. При этом используется 8 бит на символ, дополнение до четности и один стоповый бит. Таким образом на один символ в физической линии приходится 11 бит (включая стартовый бит). 50 символов на скорости 9600 будут приниматься 50 * 11 / 9600 = 0.0572916 секунд, или примерно 57.3 миллисекунды, при условии ну левого интервала между приемом последовательных символов. Если интервал между символами составляет примерно половину времени передачи одного символа, т. е. 0.5 миллисекунд, то время приема будет 50 * 11 / 9600 + 49 * 0.0005 = 0.0817916 секунд, или примерно 82 миллисекунды. Если в процессе чтения прошло более 82 миллисекунд, то мы вправе предположить, что произошла ошибка в работе внешнего устройства и прекратить считывание, избежав тем самым зависания программы. Это и есть общий тайм-аут операции чтения. Аналогично существует и общий там-аут операции записи.