Выбрать главу

Параметры этой функции тоже достаточно очевидны. Установку тайм-аутов можно производить как до установки параметров порта, так и после. Последовательность вызова функций 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.

Исчерпывающая информация о возможностях коммуникационного устройства и драйвера содержится в структуре COMMPROP:

typedef struct _COMMPROP {

 WORD  wPacketLength;       // packet size, in bytes

 WORD  wPacketVersion;      // packet version

 DWORD dwServiceMask;       // services implemented

 DWORD dwReserved1;         // reserved

 DWORD dwMaxTxQueue;        // max Tx bufsize, in bytes

 DWORD dwMaxRxQueue;        // max Rx bufsize, in bytes

 DWORD dwMaxBaud;           // max baud rate, in bps

 DWORD dwProvSubType;       // specific provider type

 DWORD dwProvCapabilities;  // capabilities supported

 DWORD dwSettableParams;    // changable parameters

 DWORD dwSettableBaud;      // allowable baud rates

 WORD  wSettableData;       // allowable byte sizes

 WORD  wSettableStopParity; // stop bits/parity allowed

 DWORD dwCurrentTxQueue;    // Tx buffer size, in bytes

 DWORD dwCurrentRxQueue;    // Rx buffer size, in bytes

 DWORD dwProvSpec1;         // provider-specific data

 DWORD dwProvSpec2;         // provider-specific data

 WCHAR wcProvChar[1];       // provider-specific data

} COMMPROP;

Поля этой структуры описывают все возможности драйвера. Вы не можете выйти за пределы этих возможностей. Вот какое значение имеют поля:

wPacketLength

Задает размер, в байтах, структуры COMMPROP.

wPacketVersion

Номер версии структуры.

dwServiceMask

Битовая маска. Для коммуникационных устройств всегда SP_SERIALCOMM, включая модемы.

dwReserved1

Зарезервировано и не используется.

dwMaxTxQueue

Максимальный размер, в байтах, внутреннего буфера передачи драйвера. Нулевое значение свидетельствует об отсутствии ограничения.

dwMaxRxQueue

Максимальный размер, в байтах, внутреннего буфера приема драйвера. Нулевое значение свидетельствует об отсутствии ограничения.

dwMaxBaud

Максимально допустимая скорость обмена, в битах в секунду (бпс). Возможны следующие значения данного поля:

BAUD_075 75 бпс. BAUD_110 110 бпс. BAUD_134_5 134.5 бпс. BAUD_150 150 бпс. BAUD_300 300 бпс. BAUD_600 600 бпс. BAUD_1200 1200 бпс. BAUD_1800 1800 бпс. BAUD_2400 2400 бпс. BAUD_4800 4800 бпс BAUD_7200 7200 бпс. BAUD_9600 9600 бпс. BAUD_14400 14400 бпс. BAUD_19200 19200 бпс. BAUD_38400 38400 бпс. BAUD_56K 56K бпс. BAUD_57600 57600 бпс. BAUD_115200 115200 бпс. BAUD_128K 128K бпс. BAUD_USER Допускается программирование скорости обмена