litbaza книги онлайнРазная литератураИнтернет-журнал "Домашняя лаборатория", 2007 №8 - Журнал «Домашняя лаборатория»

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 324 325 326 327 328 329 330 331 332 ... 463
Перейти на страницу:
— Переполнение приемного буфера или принят символ после символа конца файла (EOF)

• CE_RXPARITY — Ошибка четности

• CE_TXFULL — Переполнение буфера передачи

∙ IpStat

Адрес структуры COMMSTAT. Должен быть указан, или адрес выделенного блока памяти, или NULL, если не требуется получать информацию о состоянии.

Структура COMMSTAT

Если с информацией об ошибке все ясно, то со структурой COMMSTAT мы еще не встречались. Вот она:

typedef struct _COMSTAT

    DWORD fCtsHold:1;

    DWORD fDsrHoldr:1;

    DWORD fRlsdHold:1;

    DWORD fXoffHold:1;

    DWORD fXoffSent:1;

    DWORD fEof:1;

    DWORD fTxim:1;

    DWORD fReserved:25;

    DWORD cblnQue;

    DWORD cbOutQue;

} COMSTAT, *LPCOMSTAT;

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

∙ fCtsHold

Передача приостановлена из-за сброса сигнала CSR.

∙ fDsrHold

Передача приостановлена из-за сброса сигнала DSR.

∙ fRlsdHold

Передача приостановлена из-за ожидания сигнала RLSD (receive-line-signal-detect). Более известное название данного сигнала — DCD (обнаружение несущей).

∙ fXoffHold

Передача приостановлена из-за приема символа XOFF.

∙ fXoffSent

Передача приостановлена из-за передачи символа XOFF. Следующий передаваемый символ обязательно должен быть XON, поэтому передача собственно данных тоже приостанавливается

∙ fEof

Принят символ конца файла (EOF).

∙ fTxim

В очередь, с помощью TransmitCommChar, поставлен символ для экстренной передачи.

∙ fReserved

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

∙ cblnQue

Число символов в приемном буфере. Эти символы приняты из линии но еще не считаны функцией ReadFile.

∙ cbOutQue

Число символов в передающем буфере. Эти символы ожидают передачи в линию. Для синхронных операций всегда 0.

Теперь Вы знаете почти все о работе с последовательными и параллельными портами в синхронном режиме. Особенности непосредственной работы с модемами я не буду рассматривать, так как существует большой набор высокоуровневых функций и протоколов, таких как TAPI, специально предназначенных для работы с модемами. Если Вас все же интересует эта тема, то почитайте описания функции GetCommModemStatus, и структур MODEMDEVCAPS и MODEMSETTINGS. В остальном работа с модемом ничем не отличается от работы с обычным портом.

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

Функция SetCommMask

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

BOOL SetCommMask(

    HANDLE hFile,

    DWORD dwEvtMask

);

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

• EV_BREAK — Состояние разрыва приемной линии

• EV_CTS — Изменение состояния линии CTS

• EV_DSR — Изменение состояния линии DSR

• EV_ERR — Ошибка обрамления, перебега или четности

• EV_RING — Входящий звонок на модем (сигнал на линии RI порта)

• EV_RLSD — Изменение состояния линии RLSD (DCD)

• EV_RXCHAR — Символ принят и помещен в приемный буфер

• EV_RXFLAG — Принят символ заданный полем EvtChar структуры DCB использованной для на стройки режимов работы порта

• EV_TXEMPTY — Из буфера передачи передан последний символ

Если dwEvtMask равно нулю, то отслеживание событий запрещается.

Функция GetCommMask

Разумеется, всегда можно получить текущую маску отслеживаемых событий с помощью функции

BOOL GetCommMask(

    HANDLE    hFile,

    LPDWORD IpEvtMask

);

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

• EV_EVENT1 — Устройство-зависимое событие

• EV_EVENT2 — Устройство-зависимое событие

• EV_PERR — Ошибка принтера

• EV_RX80FULL — Приемный буфер заполнен на 80 процентов

Эти дополнительные события используются внутри драйвера. Вы не должны переустанавливать состояние их отслеживания.

Функция WaitCommEvent

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

BOOL WaitCommEvent(

    HANDLE           hFile,

    LPDWORD        IpEvtMask,

    LPOVERLAPPED lpOverlapped,

);

Замечу, что в переменной, адресуемой вторым параметром, не будут устанавливаться внутренние события драйвера (перечислены в описании функции GetCommMask). В единичное состояние установятся только те биты, которые соответствуют реально произошедшим событиям.

Адрес структуры OVERLAPPED требуется для асинхронного ожидания (возможно и такое). Однако пока будем полагать, что порт открыт для синхронных операций, следовательно этот параметр должен быть NULL. Замечу только, что при асинхронном ожидании данная функция может завершиться с ошибкой, если в процессе этого ожидания будет вызвана функция SetCommMask для переустановки маски событий. Кроме того, связанное со структурой OVERLAPPED событие (объект создаваемый функцией CreateEvent, а не событие порта) должно быть с ручным сбросом. Вообще, поведение функции с ненулевым указателем на структуру OVERLAPPED аналогично поведению функций чтения и записи. Теперь коротенький пример:

#include <windows.h>

DCB dcb;

COMMTIMEOUTS ct;

HANDLE port;

DWORD mask;

DWORD bc;

char buf[101];

dcb.DCBlength=sizeof(DCB);

BuildCommDCB("baud=9600 parity=N data=8 stop=1",&dcb);

dсb.fNull=TRUE;

ct.ReadIntervalTimeout=10;

ct.ReadTotalTimeoutMultiplier=ct.ReadTotalTimeoutConstant=0;

ct.WriteTotalTimeoutMultiplier=ct.WriteTotalTimeoutConstant=0;

port=CreateFile("COM2",GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);

SetCommState(port,dcb);

SetCommTimeouts(port,&ct);

PurgeComm(port,PURGE_RXCLEAR);

SetCommMask(port,EV_RXCHAR);

WaitCommEvent(port,Smask,NULL);

ReadFile(port,buf,10 0,&bc,NULL);

CloseHandle(port);

В данном примере ожидается начало сообщения (первый полученный символ), после чего вызывается функция чтения. Освобождать процессор на время ожидания хорошо, но хотелось бы параллельно с вводом/выводом делать какую-либо полезную работу. Что бы это стало возможным, необходимо в качестве параметра dwFlagsAndAttributes вместо 0 указать FILE_FLAG_OVERLAPPED. Кроме того, для функций ReadFile, WriteFile и WaitCommEvent необходимо в качестве параметра lpOverlapped указывать адрес правильно инициализированной структуры OVERLAPPED.

Структура OVERLAPPED

Структура OVERLAPPED выглядит следующим образом:

typedef struct _OVERLAPPED {{

    DWORD Internal;

    DWORD InternalHigh;

    DWORD Offset;

    DWORD OffsetHigh;

    HANDLE hEvent;

} OVERLAPPED, *LPOVERLAPPED;

Подробно описывать поля этой структуры не буду, поскольку данная статья не о файловом вводе/выводе вообще, а о работе с портами. Для наших целей, за исключением WaitCommEvent, можно просто обнулить все поля этой структуры. Для WaitCommEvent поле hEvent должно содержать корректный описатель объекта "событие". Что бы все стало понятно, надо разобраться с таким обязательным

1 ... 324 325 326 327 328 329 330 331 332 ... 463
Перейти на страницу:

Комментарии
Минимальная длина комментария - 20 знаков. Уважайте себя и других!
Комментариев еще нет. Хотите быть первым?