...Мыши плакали, кололись, но пpодолжали жpать кактус...
  Главная
  Статьи
     ICQ
     Всё про IP
     Юмор
      Логи
     Кардинг
     Как работает Интернет
     Windows
     *NIX
     Взлом
     Западло в сети
     Программирование
      PHP
      C/C++
      Delphi/Pascal
     Разное
  Download
     Все
     Атака
     Разное
     Программирование
     Сканнеры
     Снифферы
     Pass crk
     WarDialers
     Должно быть у всех
  Регистрация
  Гостевая
  Форум
  Эксплоиты
     Windows
     Linux
     BSD

     Локальные
     Удалённые
  Уязвимости
  Новости

Вы не авторизованы



Зачем мне регистрироваться?
Голосование
какая операционка вам больше по душе
Windows
Linux
BSD
Novel netware
Solaris
BeOs
Lindows
Результаты
Дорогие посетители нашего сайта! Если у вас есть какие то вопросы, или замечания, идеи или предложения, то просьба ПОСТИТЬ в Форуме (это же так просто кликнуть по ссылке "Форум" :)). Давайте же общаться ! Короче форум открыт для всех. Добро пожаловать!
PsychoZ
2004-07-27 11:38:12
У меня вопрос ко всем...Чего вы такие стеснительные?ВВы знанийсвоих боитесь что ли?ПОСТИТЕ,ПОСТИТЕ,ПОСТИТЕ.На одних админах портал не вытянуть,да и вы разве не стремитесь к новым знаниям?а?
YuGi
2004-07-26 19:50:34
Я вернулся !! Усем привет.Кстати как я понял Валера на нас батон крошит.Если честно я на вашем месте на таких ламеров даже и внимания не обращал.Как в народе говорится топик килл автор бан, Ж)
YuGi
2004-07-23 16:02:47
Гостевая




Rambler's Top100

ByHiT ГеоСАР
Хак TOP-100
NSD.ru - Безопасность в сети! Все о Хакерстве. Анонимность. Защита. Противстояние...


#xak для винды
#xak для юникса


Ruskod Team
Acolytez Team
Wahack.Org.ru
FrikZona.org
StinSoft
Всё об ICQ
InAttack.ru

DrCyrix
Di Monstr
PsychoZ
DrFaust
YuGi
Создателем этого проекта является DrCyrix©
ICQ: 3539968
mailto:chalex@onego.ru
Обзор статей
Поиск статей
Начало > Программирование > Delphi/Pascal
Программирование COM - порта с использованием WinApi и Assemblera
В данной статье я поведаю основы и тонкости программирования интерфейса RS-232,
в народе известного как последовательный COM-порт персонального компутера, с использованием
системных функций win32api и assembler'а.
В статье будет выложена информация и куски кода, которые являются результатами
бессонных ночей, моего пота и крови, которые были пролиты на msdn, разные доки и факи с
целью детального изучения всех моментов и хинтов работы с данным портом 8)



*** Содержание ***



[1] вступление
[2] немного об интерфейсе RS-232
[3] низкоуровневый доступ к портам. функции BIOS
[4] структуры для работы с com-портом, доступные на уровне win32API
[5] win32API функции для работы с com-портом
[6] тонкости работы с последовательным com-портом. (+пример)




*** Вступление ***



Данная статья посвящена теме программирования последовательного порта ПК.
Данный интерфейс до сих пор очень широко используется, начиная от подключения мышки к
компу и заканчивая мощнейшими приборами, которые взаимодействуют с компутером.
Данный интерфейс позволяет производить ввод/вывод данных, очень гибкую настройку режима
передачи, и хороший контроль состояния порта и ошибок, которые возникают. Поэтому то, как
и для чего вы будете использовать данный интерфейс зависит большей частью от вашей фантазии,
мне, к примеру, доводилось писать много разных тулз, которые работали с данным интерфейсом.
Это: программа для управление ПК посредством инфракрасного сигнала, передаваемого с пульта
ДУ на комп. К компу подключается простенькая схемка с инфракрасным приемником и программа
уже обрабатывает сигналы, которые поступают на порт с прибора. Также разные тулзы для обработки
сигналов с разных приборов.
Что еще интеретного бывает, так это чаты, которые работают через com-порты компутеров,
соединенных между собой. В общем кто как может так и пользует этот интерфейс 8)

ps модемы, кстати, тоже на этот порт вешаются, так что разобравшись с командами вашего
модема вы сможете закодить свою програму для работы с модемом 8)




*** Немного об интерфейсе RS-232 ***



Интерфейс RS-232-C разработан ассоциацией электронной промышленности (Electronic
Industries Association - EIA) как стандарт для соединения компьютеров и различных
последовательных периферийных устройств.
Данный интерфейс является асинхронным. Тоесть позволяет одновременное выполнение нескольких
операция ввода/вывода. Соответственно средства кодинга порта учитывают это и работа с портом
является оч удобной и логичной.
В основе порта лежит микросхема Intel 8250 или ее современные аналоги -
Intel 16450, 16550, 16550A. Эта микросхема является универсальным асинхронным
приемопередатчиком (UART - Universal Asynchronous Receiver Transmitter).
В данной микрухе имеются сдвиговый и буферный регистры приемника.
Программа имеет доступ только к буферным регистрам, копирование информации в
сдвиговые регистры и процесс сдвига выполняется микросхемой UART автоматически.



*** Низкоуровневый доступ к портам. Функции BIOS ***



те, кто кодируют на асме знают что взаимодействие с различными аппаратным средствам
ПК осуществляется посредством вызова соответствующего прерывания или функции BIOS.
Так вот, наш интерфейс RS-232 (com-порт) тоже может вырабатывать прерывания:

COM1, COM3 - IRQ4 (соответствует INT 0Ch)
COM2, COM4 - IRQ3 (соответствует INT 0Bh)

COM1 имеет базовый адрес 3F8h и занимает диапазон адресов от 3F8h до 3FFh
COM2 имеет базовый адрес 2F8h и занимает адреса 2F8h...2FFh
COM3 имеет базовый адрес 3E8h и занимает диапазон адресов от 3E8h до 3EFh
COM4 имеет базовый адрес 2E8h и занимает адреса 2E8h...2EFh

Рассмотрим функции, которые нам доступны для работы с портом:

AH=00h - Инициализация порта


AL: смотрите в таблице
DX: номер порта(0-3; 0 equ. 0x3f8, 1 equ. 0x2f8, и т.д.)
Bit 7 Bit 6 Bit 5 Rate [bps] Bit 4 Bit 3 Parity
1 1 1 9600 0 0 none
1 1 0 4800 1 0 none
1 0 1 2400 0 1 odd
1 0 0 1200 1 1 even
0 1 1 600
0 1 0 300 Bit 1 Bit 0 Data bits
0 0 1 150 0 0 5
0 0 0 110 0 1 6
1 0 7
Bit 2 0 -> 1 stop bit, 1 -> 2 stop bits 1 1 8

(!)Возвращаемые значения:
AH: RS-232C бит статуса линии
Бит
0: RBF - данные доступны в буфере
1: OE - данные утеряны
5: THRE - room is available in output buffer
6: TEMT - буфер пустой
AL: биты статуса модема
3: всегда 1
7: DCD - несущая

AH=01h - Записать байт


AL: символ для посылки в порт
DX: порт
(!)Возвращаемые значения:
AH: 7-й бит сброшен - все ок, установлен - возникла ошибка.
Биты 0-6 смотрите INT 14h AH=03h

AH=02h - Прочитать байт


(!)Возвращаемые значения:
AH: Состояние линии (смотрите AH=03h)
AL: принятый символ (если 7-й бит AH не установлен)

AH=03h - получить информацию о статусе порта



DX: Порт
(!)Возвращаемые значения:
AH: статус линии
Bit 7: Timeout
Bit 6: TEMT Transmitter empty
Bit 5: THRE Transmitter Holding Register Empty
Bit 4: Break (broken line detected)
Bit 3: FE Framing error
Bit 2: PE Parity error
Bit 1: OE Overrun error
Bit 0: RDF Receiver buffer full (data available)
AL: Modem Status
Bit 7: DCD Carrier detect
Bit 6: RI Ring indicator
Bit 5: DSR Data set ready
Bit 4: CTS Clear to send
Bit 3: DDCD Delta carrier detect
Bit 2: TERI Trailing edge of ring indicator
Bit 1: DDSR Delta data set ready
Bit 0: DCTS Delta Clear to send



*** структуры для работы с com-портом, доступные на уровне win32API ***



win32api предоставляют нам пять структур для работы с com-портом.
структуры для работы с com-портом объявлены в заголовочном файле winbase.h


COMMCONFIG - предоставляет информацию о конфигурации комуникационного устройства

члены структуры:


DWORD dwSize; /* Size of the entire struct */
WORD wVersion; /* version of the structure */
WORD wReserved; /* alignment */
DCB dcb; /* device control block */
DWORD dwProviderSubType; /* ordinal value for identifying provider-defined data structure format*/
DWORD dwProviderOffset; /* Specifies the offset of provider specific data field in bytes from the start */
DWORD dwProviderSize; /* size of the provider-specific data field */
WCHAR wcProviderData[1]; /* provider-specific data */


COMMPROP - структура, заполняемая при вызове GetCommProperties (), предоставляет информацию
о комуникацонном драйвере

члены структуры:


WORD wPacketLength;
WORD wPacketVersion;
DWORD dwServiceMask;
DWORD dwReserved1;
DWORD dwMaxTxQueue;
DWORD dwMaxRxQueue;
DWORD dwMaxBaud;
DWORD dwProvSubType;
DWORD dwProvCapabilities;
DWORD dwSettableParams;
DWORD dwSettableBaud;
WORD wSettableData;
WORD wSettableStopParity;
DWORD dwCurrentTxQueue;
DWORD dwCurrentRxQueue;
DWORD dwProvSpec1;
DWORD dwProvSpec2;
WCHAR wcProvChar[1];


COMMTIMEOUTS - определяет значения таймаутов для операций ввода/вывода. используются функции
SetCommTimeouts() и GetCommTimeouts()

члены структуры:


DWORD ReadIntervalTimeout; /* Maximum time between read chars. */
DWORD ReadTotalTimeoutMultiplier; /* Multiplier of characters. */
DWORD ReadTotalTimeoutConstant; /* Constant in milliseconds. */
DWORD WriteTotalTimeoutMultiplier; /* Multiplier of characters. */
DWORD WriteTotalTimeoutConstant; /* Constant in milliseconds. */


COMSTAT - возвращает информацию о текущем состоянии последовательного порта, заполняется
при вызове функции ClearCommError()

члены структуры:


DWORD fCtsHold : 1;
DWORD fDsrHold : 1;
DWORD fRlsdHold : 1;
DWORD fXoffHold : 1;
DWORD fXoffSent : 1;
DWORD fEof : 1;
DWORD fTxim : 1;
DWORD fReserved : 25;
DWORD cbInQue;
DWORD cbOutQue;


DCB - содержит основные установки комуникационного устройства. для получения структуры используйте
функцию GetCommState()

члены структуры:


DWORD DCBlength; /* sizeof(DCB) */
DWORD BaudRate; /* Baudrate at which running */
DWORD fBinary: 1; /* Binary Mode (skip EOF check) */
DWORD fParity: 1; /* Enable parity checking */
DWORD fOutxCtsFlow:1; /* CTS handshaking on output */
DWORD fOutxDsrFlow:1; /* DSR handshaking on output */
DWORD fDtrControl:2; /* DTR Flow control */
DWORD fDsrSensitivity:1; /* DSR Sensitivity */
DWORD fTXContinueOnXoff: 1; /* Continue TX when Xoff sent */
DWORD fOutX: 1; /* Enable output X-ON/X-OFF */
DWORD fInX: 1; /* Enable input X-ON/X-OFF */
DWORD fErrorChar: 1; /* Enable Err Replacement */
DWORD fNull: 1; /* Enable Null stripping */
DWORD fRtsControl:2; /* Rts Flow control */
DWORD fAbortOnError:1; /* Abort all reads and writes on Error */
DWORD fDummy2:17; /* Reserved */
WORD wReserved; /* Not currently used */
WORD XonLim; /* Transmit X-ON threshold */
WORD XoffLim; /* Transmit X-OFF threshold */
BYTE ByteSize; /* Number of bits/byte, 4-8 */
BYTE Parity; /* 0-4=None,Odd,Even,Mark,Space */
BYTE StopBits; /* 0,1,2 = 1, 1.5, 2 */
char XonChar; /* Tx and Rx X-ON character */
char XoffChar; /* Tx and Rx X-OFF character */
char ErrorChar; /* Error replacement char */
char EofChar; /* End of Input character */
char EvtChar; /* Received Event character */
WORD wReserved1; /* Fill for now. */



ну и можно добавить две структуры для работы с модемами, которые объявлены в mcx.h:

MODEMDEVCAPS - структура содержит информацию об аппаратных возможностях модема

члены структуры:


DWORD dwActualSize;
DWORD dwRequiredSize;
DWORD dwDevSpecificOffset;
DWORD dwDevSpecificSize;

// product and version identification
DWORD dwModemProviderVersion;
DWORD dwModemManufacturerOffset;
DWORD dwModemManufacturerSize;
DWORD dwModemModelOffset;
DWORD dwModemModelSize;
DWORD dwModemVersionOffset;
DWORD dwModemVersionSize;

// local option capabilities
DWORD dwDialOptions; // bitmap of supported values
DWORD dwCallSetupFailTimer; // maximum in seconds
DWORD dwInactivityTimeout; // maximum in seconds
DWORD dwSpeakerVolume; // bitmap of supported values
DWORD dwSpeakerMode; // bitmap of supported values
DWORD dwModemOptions; // bitmap of supported values
DWORD dwMaxDTERate; // maximum value in bit/s
DWORD dwMaxDCERate; // maximum value in bit/s

// Variable portion for proprietary expansion
BYTE abVariablePortion [1];


MODEMSETTINGS - информация об настройках и установках модема

члены структуры:


DWORD dwActualSize;
DWORD dwRequiredSize;
DWORD dwDevSpecificOffset;
DWORD dwDevSpecificSize;

// static local options (read/write)
DWORD dwCallSetupFailTimer; // seconds
DWORD dwInactivityTimeout; // seconds
DWORD dwSpeakerVolume; // level
DWORD dwSpeakerMode; // mode
DWORD dwPreferredModemOptions; // bitmap

// negotiated options (read only) for current or last call
DWORD dwNegotiatedModemOptions; // bitmap
DWORD dwNegotiatedDCERate; // bit/s

// Variable portion for proprietary expansion
BYTE abVariablePortion [1];





*** win32API функции для работы с com-портом ***



win32api предоставляет множество функций для работы с устройствами связи и последовательными портами ввода вывода.
благодарю такому набору средств можно писать очень эфективные програмы для работы с портами, етц.
далее я приведу перечень все функция с описание функции, также укажу параметры функции и их типы. более детальную информацию
о параметрах функций и самих функциях вы можете найти в MSDN'е (http://msdn.microsoft.com) или же в других источниках
информации. если я стану описывать все нюансы касательно каждой функции и ее аргумента - статья превратится в настоящую книгу
объемом порядка сотни страниц. да и имена параметров достаточно понятны чтобы описывать каждый отдельно ;)

BuildCommDCB - Заполняет указанную структуру блока описания устройств значениями, указанными в строке управления устройства.
BOOL BuildCommDCB(
LPCTSTR lpDef,
LPDCB lpDCB
);


BuildCommDCBAndTimeouts - Переводит строку определения устройства в соответствующие коды управляющего блока устройства и
размещает их в управляющий блок устройства.
BOOL BuildCommDCBAndTimeouts(
LPCTSTR lpDef,
LPDCB lpDCB,
LPCOMMTIMEOUTS lpCommTimeouts
);


ClearCommBreak - Передача символа восстановлений для указанного устройства связи. Сбрасывает значения ошибок и заполняет
структуру COMSTAT.
BOOL ClearCommBreak(
HANDLE hFile
);


ClearCommError - Вовращает информацию об ошибках связи и сообщает о текущем состоянии устройства связи.
BOOL ClearCommError(
HANDLE hFile,
LPDWORD lpErrors,
LPCOMSTAT lpStat
);


CommConfigDialog - Отображает снабженное драйвером диалоговое окно конфигурации.
BOOL CommConfigDialog(
LPCTSTR lpszName,
HWND hWnd,
LPCOMMCONFIG lpCC
);


EscapeCommFunction - Указывает указанному устройство связи, что необходимо выполнить расширенную функцию.
BOOL EscapeCommFunction(
HANDLE hFile,
DWORD dwFunc
);


GetCommConfig - Возвращает текущую конфигурацию устройства связи
BOOL GetCommConfig(
HANDLE hCommDev,
LPCOMMCONFIG lpCC,
LPDWORD lpdwSize
);


GetCommMask - Возвращает значение маски события для указанного устройства связи.
BOOL GetCommMask(
HANDLE hFile,
LPDWORD lpEvtMask
);


GetCommModemStatus - Возвращает модемные значения регистра управления.
BOOL GetCommModemStatus(
HANDLE hFile,
LPDWORD lpModemStat
);


GetCommProperties - Возвращает информацию о свойствах связи для указанного устройства связи.
BOOL GetCommProperties(
HANDLE hFile,
LPCOMMPROP lpCommProp
);


GetCommState - Возвращает текущие параметры настройки управления для указанного устройства связи.
BOOL GetCommState(
HANDLE hFile,
LPDCB lpDCB
);


GetCommTimeout - Возвращает параметры блокировки времени для всего чтения и операций записи на указанном устройстве связи.
BOOL GetCommTimeouts(
HANDLE hFile,
LPCOMMTIMEOUTS lpCommTimeouts
);


GetDefaultCommConfig - Возвращает заданную по умолчанию конфигурацию для указанного устройства связи.
BOOL GetDefaultCommConfig(
LPCTSTR lpszName,
LPCOMMCONFIG lpCC,
LPDWORD lpdwSize
);


PurgeComm - Сбрасывает все символы вывода или входного буфера указанного ресурса связи.
BOOL PurgeComm(
HANDLE hFile,
DWORD dwFlags
);


SetCommBreak - Передача символа Suspends для указанного устройства связи и установка состояния break до вызова ф-ции
ClearCommBreak()
BOOL SetCommBreak(
HANDLE hFile
);


SetCommConfig - Устанавливает текущую конфигурацию устройства связи.
BOOL SetCommConfig(
HANDLE hCommDev,
LPCOMMCONFIG lpCC,
DWORD dwSize
);


SetCommMask - Определяет набор событий, которые будут зафиксированы для устройства связи.
BOOL SetCommMask(
HANDLE hFile,
DWORD dwEvtMask
);


SetCommState - Конфигурирует устройство связи согласно спецификациям в управляющем блоке устройства.
BOOL SetCommState(
HANDLE hFile,
LPDCB lpDCB
);


SetCommTimeouts - Устанавливает параметры блокировки времени для всего чтения и операций записи на указанном
устройстве связи.
BOOL SetCommTimeouts(
HANDLE hFile,
LPCOMMTIMEOUTS lpCommTimeouts
);


SetDefaultCommConfig - Устанавливает заданную по умолчанию конфигурацию для устройства связи.
BOOL SetDefaultCommConfig(
LPCTSTR lpszName,
LPCOMMCONFIG lpCC,
DWORD dwSize
);


SetupComm - Инициализирует параметры связи для указанного устройства связи.
BOOL SetupComm(
HANDLE hFile,
DWORD dwInQueue,
DWORD dwOutQueue
);


TransmitCommChar - Передает указанный символ перед любыми операциями ожидания данных в буфере вывода указанного
устройства связи.
BOOL TransmitCommChar(
HANDLE hFile,
char cChar
);


WaitCommEvent - Ожидает события, которые установлены с помощью SetCommMask()
BOOL WaitCommEvent(
HANDLE hFile,
LPDWORD lpEvtMask,
LPOVERLAPPED lpOverlapped
);




*** тонкости работы с последовательным com-портом ***



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

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

для чтения и записи в порт в асме есть две простые команды:

in аккумулятор, номер_порта ; ввод аккумулятора из порта с номером номер_порта
out порт, аккумулятор ; вывод содержимого аккумулятора в порт с номером номер_порта

тут все просто как двери. загнали в регистры нужные значения, вызвали функцию, потом прерывание
и вперед - анализируем значения, которые устанавливаются после выполнения определенной функции.
это все было описано выше. так как основное внимание в данной статье уделено кодингу с
использованием win32api функций - на асме останавливаться не будем, так как на нем это
все делается гораздо проще нежели многие думают, там нет пары десятков функций и структур,
асм прост, как говорят - все гениальное просто. так и асм. ну да ладно, если кто считает,
что кодинг на асме это изврат пускай и дальше заблуждается и верит в свое ограничивающее
убеждение ;))

итак. с асмом все понятно 8) а как быть с api функциями?
с ними тоже все просто, нужно одинраз разобраться и все станет понятно.

для начала необходимо проинициализировать порт, для этого используется функция CreateFile()

char *port_ptr = "COM1";
HANDLE hCom = CreateFile(port_ptr, // init port
GENERIC_READ | GENERIC_WRITE, // read/write access
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,// default security attribute
OPEN_EXISTING, //COM's must exist 8-)
FILE_FLAG_OVERLAPPED, //use for overlapped i/o.
0
);
единственное что стоит сказать относителньо использования этой функции для инициализации
порта - не игнорируйте шестой параметр и устанавливайте его FILE_FLAG_OVERLAPPED. это укажет
функции, что необходимо инициализировать порт в режиме асинхронного ввода/вывода.
что это значит? к примеру вы написали програмку, которая читает данные из порта, анализирует
их. что-то еще делает, с окошками, менюшками, разными фичами. так вот. если работать
с портом в режиме синхронного ввода/вывода - поток, в котором происходит обращение к ресурсам
порта блокируется до появления событий порта, а в режиме асинхронного вв/в - операция ожидания
переводится в фоновый режим выплнения и вы можете в том же потоке делать что вам необходимо
тем самым не мешая программе ожидать событий от порта...

// итак, инициализируем порт, проверяем результат выполнения функции:

if( hCom != INVALID_HANDLE_VALUE )
printf("(+) %s initialized\n", port_ptr);
else
printf("(-) %s initialization failed\n", port_ptr);


// теперь нужно сбросить значения буферов порта и регистров:

int retcode
=
PurgeComm(hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);

// retcode будет содержать код возврата

if( retcode==NULL )
printf("(-) PurgeComm() failed\n");
else
printf("(+) Discarded all characters from the output and input buffer\n");

retcode = ClearCommBreak(hCom);
if( retcode==NULL ){
printf("(-) ClearCommBreak() failed\n");
PrintLastError();
}else
printf("(+) Restored character transmission and placed the transmission line in a nonbreak state\n");


// далее подготовим структуру DCB для того чтобы внести некоторые изменения в параметрах порта:

DCB dcb;

retcode = GetCommState(hCom,&dcb);
if( retcode==NULL )
printf("(-) GetCommState() failed\n");
else
printf("(+) Retrieved the current control settings for %s\n", port_ptr);

// изменяем только то что нам нужно:
dcb.BaudRate = CBR_9600; // set the baud rate
dcb.ByteSize = 8; // data size, xmit, and rcv
dcb.Parity = NOPARITY; // no parity bit
dcb.StopBits = ONESTOPBIT; // one stop bit

// и устанавливаем новый опции порта:

retcode = SetCommState(hCom, &dcb);

// и опять проверяем код возврата, на всякий случай... надеюсь я вас научу это всегда делать,
// это является правилом хорошего тона. с таким подходом никогда не затеряетесь в своем коде
// и легконайдете причину возникновения ошибок, если таковые будут

if( retcode==NULL )
printf("(-) SetCommState() failed\n");
else
printf("(+) Reinitialized all hardware and control settings \n"\


// устанавливаем события, о появлении которых мы хотим узнать:
// (будем мониторить все события)

DWORD CommEventMask = EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING |
EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY;

retcode = SetCommMask(hCom,CommEventMask);
if( retcode==NULL ){
printf("(-) SetCommMask() failed\n");
PrintLastError();
}else
printf("(+) Events to be monitored -> BREAK, CTS, DSR, ERR, RING, RLSD, RXCHAR, RXFLAG, TXEMPTY\n");



// теперь создадим event, который нам сообшит о проишедшем событии:

OVERLAPPED OL;
// эта структура требуется в многих функциях при асинхронном вв/в
// как не сложно заметить, она содержит в себе параметр типа HANDLE, который и будет нашим
// event'ом

OL.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD EventMask = 0; //сюда будет записан тип события

do{
// обрабатываем события в цикле, дабы программа не закончилась после обработки одного события
// если этого непосредственно не нужно

retcode = WaitCommEvent(hCom, &EventMask, &OL);
if ( ( !retcode ) && (GetLastError()==ERROR_IO_PENDING) ){
printf("(!) Waiting for event\n");
WaitForSingleObject(OL.hEvent, INFINITE);
}

// поясняю этот код:
// WaitCommEvent() ожидает событий от com-порта, тип событий ранее мы "привязали" к хэндлу порта
// с помощью SetCommEvent()
// retcode сообщает о результате выполнения функции. retcode должен быть NULL и
// GetLastError() должна возвратать нам 997 (ERROR_IO_PENDING), что означает
// "Overlapped I/O operation is in progress", тоесть функция успешно выполнилась и перевела
// операцию ожидания событий в фоновый процесс, о чем мы и говорили раньше - при асинхронном
// вв/в операции с портом не блокируют поток, в котором они выполняются.
// далее при помощи WaitForSingleObject() ожидаем события, INFINITE - это константа, которая
// задает интервал времени для ожидания в милисекундах, в даном случае INFINITE привыкли
// считать как вечное ожидание, на самом деле это не так, это максимальное 32-х разрядное
// число 0xFFFFFFFF, если подсчитать получается интервал ожидания больше чем год, думаю вам этого хватит 8))
// тоесть задав вместо INFINITE 1000 вы указываете ждать 1сек

// далее анализируем чтоже произошло:

if(EventMask & EV_BREAK) printf("(i) EV_BREAK\n");
if(EventMask & EV_RLSD) printf("(i) EV_RLSD\n");
if(EventMask & EV_CTS) printf("(i) EV_CTS\n");
if(EventMask & EV_DSR) printf("(i) EV_DSR\n");
if(EventMask & EV_ERR) printf("(i) EV_ERR\n");
if(EventMask & EV_RING) printf("(i) EV_RING\n");
if(EventMask & EV_RXCHAR) printf("(i) EV_RXCHAR\n");
if(EventMask & EV_RXFLAG) printf("(i) EV_RXFLAG\n");
if(EventMask & EV_TXEMPTY) printf("(i) EV_TXEMPTY\n");

// надеюсь тут все понятно, поразрядным & мы проверяем что у нас в EventMask
// ну и далее в зависимости от события вы работаете с портом дальше, рассмотрим случай с
// чтением данных из порта. в таком случае должно возникнуть событие EV_RXCHAR
// итак, если у нас возникает EV_RXCHAR - в буфере порта нас ожидает сюрприз, а именно
// какие-то данные. как же их поглядеть, а? 8) как как - считать в память и вывести на stdout 8)
// для начала определим размер входящих данных. для этого нужно поглядеть на член структуры
// COMSTAT - cbInQue
// выше я писал, что для загрузки значений в COMSTAT пользуется функция ClearCommError()

DWORD ErrorMask = 0; // сюда будет занесен код ошибки порта, если таковая была

COMSTAT CStat;

ClearCommError(hCom, &ErrorMask, &CStat);

DWORD quelen = CStat.cbInQue;

// все. тепереь quelen содержит количество байт в буфере порта.

// выделяем память под буфер

char *lpInBuffer = new char[ (int)quelen+1 ];
memset(&lpInBuffer, '\0', (int)quelen);

DWORD dwReaded = 0;
// эта переменная после вызова ReadFile будет содержать количество число, которое покажет
// сколько байт было реально прочитано. как вы уже догадались, анализируя это значение можно
// судить об успешности выполнения операции чтения. если у нас в буфере было 512байт, а
// прочитали 0 или того меньше - чето не так, GetLastError() вам подскажет то именно 8))

retcode = ReadFile(com->hCom, lpInBuffer, quelen, &dwReaded, &OL);
// опять же передаем структуру OL


if( dwReaded == 0 && GetLastError() == ERROR_IO_PENDING ) {
// если ничего не прочитано и GetLastError() возвратила ERROR_IO_PENDING
// операция не успела за установленный в COMMTIMEOUTS
// период времени выполниться и выполняется в фоне, тоесть вы можете спокойно чето делать
// в этом болке кода а после проанализировать результат выполнения

// DoSomeThing() //че-то делаем... а потом проверяем состояние

retcode = GetOverlappedResult(hCom, &OL, &dwreaded, FALSE) ;

// как вы уже догадались - dwreaded содержит кол-во прочитаных байт

}else{ //если что-то прочитали или возникла ошибка

if (dwReaded>0) //если прочитали данные
printf("(+) %d bytes received (%s)\n", dwReaded, lpInBuffer);
// по выводу вы увидете сколько байт прочитали и что именно
else
printf("(-) ReadFile() failed. errno %d\n", GetLastError());

}


// теперь нужно сбросить значения буферов порта и регистров:
if( PurgeComm(com->hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR) == NULL ){
printf("(-) PurgeComm() failed\n");
PrintLastError();
}else
printf("(+) Discarded all characters from the output and input buffer\n");



EventMask=0;
ResetEvent(OL.hEvent);

// сбрасываем значения нашего event'а перед ожиданием следующего события
//
}
}while(1);


выше могли заметить некую функцию PrintLastError(), это моя функция для вывода сообщения о последней
ошибке, вот вам в качестве бонуса 8)

void PrintLastError(void){

int ercode = GetLastError();
printf("(-) GetLastError() return %i ", ercode );
switch( ercode ){
case 2: printf("(The system cannot find the file specified)\n"); break;
case 5: printf("(Access is denied)\n"); break;
case 29: printf("(The system cannot write to the specified device)\n"); break;
case 87: printf("(The parameter is incorrect)\n"); break;
case 998: printf("(Invalid access to memory location)\n"); break;

// тут описания для самых распространенных ошибок, остальные пару сотен добавите сами 8)

default: printf("\n");
}

}



ну а как писать в порт? вместо ReadFile() пользуйте WriteFile()



напоследок советую всем обзавестить MSDN, где все оч оч подробно описано 8)
главное, что необходимо запомнить - всегда проверяйте коды возврата и если вы работаете
в асинхронном режиме с портом - проверяйте на наличие ERROR_IO_PENDING, что будет свидетельствовать
о том что операция выполняется в фоне и не стоит преждевременно суетиться и искать ошибки, которых
нет 8)


взята из http://www.nteam.ru/articles.php?id_tn=34)
Кто прислал: 12a
Комментариев нет
Просмотреть все комментарии (0 всего) :: Оставить комментарий
Сайт создан в системе uCoz