Дорогие посетители нашего сайта! Если
у вас есть какие то вопросы, или замечания, идеи или предложения, то
просьба ПОСТИТЬ в Форуме (это же так просто кликнуть по ссылке
"Форум" :)). Давайте же общаться ! Короче форум открыт
для всех. Добро пожаловать!
PsychoZ 2004-07-27 11:38:12
У меня вопрос ко всем...Чего вы такие
стеснительные?ВВы знанийсвоих боитесь что
ли?ПОСТИТЕ,ПОСТИТЕ,ПОСТИТЕ.На одних админах портал не вытянуть,да и
вы разве не стремитесь к новым знаниям?а?
YuGi 2004-07-26 19:50:34
Я вернулся !! Усем привет.Кстати как
я понял Валера на нас батон крошит.Если честно я на вашем месте на
таких ламеров даже и внимания не обращал.Как в народе говорится
топик килл автор бан, Ж)
Программирование 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()
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;
// 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 );
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( 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"\
// устанавливаем события, о
появлении которых мы хотим узнать: // (будем мониторить
все события)
// теперь создадим 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сек
// надеюсь тут все понятно, поразрядным & мы
проверяем что у нас в 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() //че-то
делаем... а потом проверяем состояние
// как вы уже догадались - 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)