прапорів PURGE_TXABORT, PURGE_RXABORT, PURGE_TXCLEAR, PURGE_RXCLEAR. br/>
Приклад на Delphi:
if not PurgeComm (hPort, PURGE_TXCLEAR or PURGE_RXCLEAR) then
raise Exception.Create ('Error purging port');
На цьому підготовча фаза закінчується, і можна приступати безпосередньо до прийому/передачі даних. Прийом даних у нас відбуватиметься за подієвої схемою; програма буде очікувати прийом одного або декількох символів (байт). Для перекладу порту в цей режим необхідно викликати функцію SetCommMask () з прапором EV_RXCHAR:
if not SetCommMask (hPort, EV_RXCHAR) then
raise Exception.Create ('Error setting port mask');
Прийом і передача даних виконується функціями ReadFile () і WriteFile (), тобто тими ж самими функціями, які використовуються для роботи з дисковими файлами. Ось їх опис:
BOOL ReadFile (
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);
BOOL WriteFile (
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
);
hFile - описувач відкритого порту. br/>
lpBuffer - адреса буфера. br/>
nNumberOfBytesToRead/nNumberOfBytesToWrite - Число очікуваних до прийому або призначених для передачі байт. br/>
lpNumberOfBytesRead/lpNumberOfBytesWritten - Число фактично прийнятих або переданих байт. br/>
lpOverlapped - адреса структури OVERLAPPED, використовуваної для асинхронних операцій. br/>
Передача даних є досить швидкої операцією, тому як правило її виконують з головного потоку додатку. На Delphi це виглядає так:
var
dwWrite: DWORD;
OverWrite: TOverlapped;
WriteBytes: array of Byte;
...
begin
OverWrite.hEvent: = CreateEvent (nil, True, False, nil);
if OverWrite.hEvent = Null then
raise Exception.Create ('Error creating write event');
...
if (not WriteFile (hPort, WriteBytes, SizeOf (WriteBytes),
dwWrite, @ OverWrite))
and (GetLastError <> ERROR_IO_PENDING) then
raise Exception.Create ('Error writing port');
end;
У даному прикладі функція WriteFile () виконує асинхронну запис масиву байтів WriteBytes в порт. Вона відразу повертає управління, і запис в порт відбувається паралельно з виконанням основного коду потоку. Якщо результат WriteFile () дорівнює False, то це означає, що на момент повернення управління передача масиву байтів ще закінчилася. Тому код помилки виконання WriteFile () у даному випадку повинен дорівнювати ERROR_IO_PENDING. Мінлива OverWrite - overlapped-структура, необхідна для асинхронних операцій. p> У принципі, вас не повинно хвилювати, коли закінчиться передача масиву байтів. Зате момент прийому одного або декількох символів дійсно важливий. Тому його можна розбити на дві частини: ініціювання прийому та визначення моменту прийому з подальшим читанням символів. Оскільки при цьому доводиться рахуватися з фактором очікування прийому символу, рекомендується функції прийому даних винести в окремий потік. Передавати дані можна і з основного потоку додатку, оскільки це відбувається досить швидко. А ось подія прийому символу будемо очікувати в окремому потоці. p> Розгляд роботи з потоками в Windows, зокрема того, як це реалізовано в Delphi, виходить за рамки цієї статті. Припускаю, що читач зустрічався або за Принаймні знайомий з цим. Скажу лише, що у будь-якого потоку є головна функція, яка починає виконуватися після його створення. У Delphi для потоків існує клас TThread, а його головна процедура називається TThread.Execute (). p> Ось так виглядає головна процедура окремого потоку, яка очікує поява одного або декількох символів і зчитує їх:
procedure TReadThread.Execute;
var
ComStat: TComStat;
dwMask, dwError: DWORD;
OverRead: TOverlapped;
Buf: array [0 .. $ FF] of Byte;
dwRead: DWORD;
begin
OverRead.hEvent: = CreateEvent (nil, True, False, nil);
if OverRead.hEvent = Null then
raise Exception.Create ('Error creating read event');
FreeOnTerminate: = True;
while not Terminated do
begin
if not WaitCommEvent (hPort, dwMask, @ OverRead) then
begin
if GetLastError = ERROR_IO_PENDING then
WaitForSingleObject (OverRead.hEvent, INFINITE)
else
raise Exception.Create ('Error waiting port event');
end;
if not ClearCommError (hPort, dwError, @ ComStat) then
raise Exception.Create ('Error clearing port');
dwRead: = ComStat.cbInQue;
if dwRead> 0 then
begin