Работа с коммуникационными портами (COM и LPT) в программах для Win32

Функция 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.



Содержание раздела