
- •Работа с коммуникационными портами (com и lpt) в программах для Win32. Автор: Титов Олег
- •Функция CreateFile
- •LpFileName
- •DwDesiredAccess
- •Структура dcb
- •DcBlength
- •BaudRate
- •FBinary
- •FAbortOnError
- •Функция GetCommState
- •Функция SetCommState
- •Структура commtimeouts
- •ReadIntervalTimeout
- •ReadTotalTimeoutMultiplier
- •ReadTotalTimeoutConstant
- •WriteTotalTimeoutMultiplier
- •WriteTotalTimeoutConstant
- •Функция BuildCommDcbAndTimeouts
- •Функция GetCommTimeouts
- •ФункцияSetCommTimeouts
- •Структура commprop
- •WPacketLength
- •DwProvSubType
- •DwProvCapabilities
- •DwSettableParams
- •Структура commconfig
- •Функция CommConfigDialog
- •LpszName
- •Функция SetCommConfig
- •Функции GetDefaultCommConfig и SetDegaultCommConfig
- •Функция SetupComm
- •Функцити ReadFile и WriteFile
- •Функция PurgeComm
- •Функция FlushFileBuffers
- •Функция TransmitCommChar
- •Функции SetCommBreak и ClearCommBreak
- •Функция EscapeCommFunction
- •Функция ClearCommError
- •LpErrors
- •Функция SetCommMask
- •Функция GetCommMask
- •Функция WaitCommEvent
- •Структура overlapped
- •Продолжение следует ...
Функция BuildCommDcbAndTimeouts
Функция BuildCommDCBAndTimeoutsпозволяет заполнить не только структуруDCB, но и структуруCOMMTIMEOUTS. Вот как выглядит ее прототип:
BOOL BuildCommDCBAndTimeouts(
LPCTSTR lpDef,
LPDCB lpDCB,
LPCOMMTIMEOUTS lpCommTimeouts
);
Как видно, у этой функции, по сравнению с BuildCommDCB, появился третий параметр. Это указатель на структуруCOMMTIMEOUTS. Конфигурационная строка при вызове этой функции должна задаваться в новом формате. Если эта строка содержит подстроку "TO=ON", то устанавливаются общие тайм-ауты для операций чтения и записи. Это значения устанавливаются на основе информации о скорости передачи и формате посылки. Если конфигурационная строка содержит подстроку "TO=OFF", то устанавливается режим работы без тайм-аутов. Если конфигурационная строка не содержит подстроки "TO=xxx" или эта подстрока имеет неверное значение, то указатель на структуруCOMMTIMEOUTSпросто игнорируется. При этом функцияBuilCommDCBAndTimeoutsоказывается идентичной функцииBuildCommDCB.
Параметр lpCommTimeoutsдолжен указывать на распределенную область памяти, причем корректность этой области не проверяется. Передача нулевого указателя приводит к ошибке.
Функция GetCommTimeouts
Как и для заполнения структуры DCB, дляCOMMTIMEOUTSсуществует функция считывания установленных в системе значений. Это функцияGetCommTimeouts:
BOOL GetCommTimeouts(
HANDLE hFile,
LPCOMMTIMEOUTS lpCommTimeouts
);
Не буду подробно останавливаться на описании параметров этой функции, они достаточно очевидны, как и возвращаемые функцией значения. Скажу только, что под структуру, адресуемую lpCommTimeouts, должна быть выделена память.
ФункцияSetCommTimeouts
Заполнив структуру COMMTIMEOUTSможно вызывать функцию установки тайм-аутов порта. Это функция называетсяSetCommTimeouts:
BOOL SetCommTimeouts(
HANDLE hFile,
LPCOMMTIMEOUTS lpCommTimeouts
);
Параметры этой функции тоже достаточно очевидны. Установку тайм-аутов можно производить как до установки параметров порта, так и после. Последовательность вызова функций SetCommStateиSetCommTimeoutsне имеет никакого значения. Главное, что бы все настройки были завершены до начала ввода/вывода информации.
Теперь приведу пример настройки порта:
#include <windows.h>
. . .
DCB *dcb;
COMMTIMEOUTS ct;
HANDLE port;
. . .
dcb=(DCB*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DCB));
dcb->DCBlength=sizeof(DCB);
BuildCommDCB("baud=9600 parity=N data=8 stop=1",dcb);
dcb->fNull=TRUE;
ct.ReadIntervalTimeout=10;
ct.ReadTotalTimeoutMultiplier=ct.ReadTotalTimeoutConstant=0;
ct.WriteTotalTimeoutMultiplier=ct.WriteTotalTimeoutConstant=0;
port=CreateFile("COM2",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
SetCommState(port,dcb);
SetCommTimeouts(port,&ct);
HeapFree(GetProcessHeap(),0,dcb);
. . .
CloseHandle(port);
В этом примере полностью убрана обработка ошибок. Обрабатывать ошибки необходимо, но сейчас главное разобраться в работе с портом, а обработка ошибок уменьшает наглядность.
Первым делом, с помощью функции HeapAlloc, выделяется и заполняется нулями область памяти для DCB. Затем в полеDCBlengthзаносится размер структурыDCBв байтах. Зачем это нужно обсуждалось выше, при описании данного поля. Для общего (и наглядного) заполненияDCBиспользована функцияBuildCommDCB. Будем считать, что нас устраивает информация занесеная вDCB, но требуется игнорировать нулевые байты при приеме. Так какBuildCommDCBне выполняет требуемых действий мы вручную изменяем соответсвующее поле. Далее мы заполняем информацию о тайм-аутах. Общие тайм-ауты операций чтения и записи не используются, конец сообщения определяется по тайм-ауту между двумя последовательными символами большему 10 миллисекунд. Теперь можно открыть порт, что делается функциейCreateFile, и выполнить его настройку вызвав функцииSetCommStateиSetCommTimeots. После установки параметров порта структураDCBстановится не нужной, поэтому можно освободить занимаемую ей память. СтруктураCOMMTIMEOUTSв примере размещена статически, поэтому выделять под нее память и освобждать ее не требуется. Наконец, мы закрываем порт перед завершением.
Функции HeapAllocиHeapFreeзанимаются выделением и освобождением памяти из куч, которых в программе может быть несколько. Вместо этих функций можно использоватьmalloc(calloc) иfree. Однако использование функций предоставляемых Win32 API позволяет сократить размер программы, что может быть не маловажно, если работа с портами ведется из DLL (например Вы пишете своеобразный псевдодрайвер для своего устройства). Есть и другие аргументы в пользу этой точки зрения, которую я Вам, впрочем, не навязываю.
Рассмотренные структуры и функции позволяют программировать порт на достаточно низком уровне. Их, в большинстве случаев, более чем достаточно даже для тонкой настройки порта. Однако бывают и исключения. Например, под именем COM1 может скрываться вовсе не привычный порт RS-232, а какая-нибудь экзотика. Или порт может не позволять задавать скорость более 9600.