![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Асинхронная работа с Com портом. [D7, WinXP]
Kolan © (2006-01-27 20:31:00)Здравствуйте,
Помогите понять эту тему.
Сделал тестовый проект по этой статье:
http://articles.org.ru/cfaq/index.php?qid=1185
Сделали мне заглушку в Com порт. Те что послал то и принял.
Она 100% работает, проверил на своих проектах...
Чтение выполняется в отдельном потоке. Вот его код полнистью:
unit KAsyncComPortThread;
interface
uses
Windows, Classes, KAsyncComPortRoutines, Variants;
type
TReadThread = class(TThread)
private
{ Private declarations }
FBuffer: array[0..$FF] of Byte;
FPortHandle: THandle;
FOverRead: TOverlapped;
FReadCount: DWORD;
FReadEvent: TReadEvent;
procedure DoRead;
protected
procedure Execute; override;
public
constructor Create(PortHandle: THandle; ReadEvent: TReadEvent);
destructor Destroy; override;
end;
implementation
{ Important: Methods and properties of objects in visual components can only be
used in a method called using Synchronize, for example,
Synchronize(UpdateCaption);
and UpdateCaption could look like,
procedure TReadThread.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }
{ TReadThread }
constructor TReadThread.Create(PortHandle: THandle; ReadEvent: TReadEvent);
var
{//}Err: Boolean;
begin
FReadEvent := nil;
FPortHandle := PortHandle;
FReadEvent := ReadEvent;
ZeroMemory(@FOverRead, SizeOf(@FOverRead));
FOverRead.hEvent := CreateEvent(nil, True, False, nil);
if FOverRead.hEvent = Null then
{//}Err := True;
inherited Create(False);
end;
destructor TReadThread.Destroy;
begin
CloseHandle(FOverRead.hEvent);
inherited;
end;
procedure TReadThread.DoRead;
var
Answer: TByteArray;
I: Integer;
begin
if Assigned(FReadEvent) then
begin
SetLength(Answer, FReadCount);
for I := Low(Answer) to High(Answer) do
Answer[I] := FBuffer[I];
FReadEvent(Self, Answer);
SetLength(Answer, 0);
end;
end;
procedure TReadThread.Execute;
var
ComStat: TComStat;
dwMask, dwError: DWORD;
{//}Err: Boolean;
I: LongBool;
begin
{ Place thread code here }
FreeOnTerminate := True;
while not Terminated do
begin
//I := WaitCommEvent(FPortHandle, dwMask, @FOverRead);
if not WaitCommEvent(FPortHandle, dwMask, @FOverRead) then
begin
if GetLastError = ERROR_IO_PENDING then
WaitForSingleObject(FOverRead.hEvent, INFINITE)
else
{//}Err := True;
end;
if not Terminated then
if not ClearCommError(FPortHandle, dwError, @ComStat) then
{//}Err := True;
FReadCount := ComStat.cbInQue;
if FreadCount > 0 then
begin
if not ReadFile(FPortHandle, FBuffer, FReadCount, FReadCount, @FOverRead) then
{//}Err := True;
Synchronize(DoRead);
end;
end;
end;
end.
Вроде я разобрался в том как это все должно работать.
Проблема заключается в том, что какое бы кол-во байт я не пошлю приходит всегда 4(а должно быть как-бы эхо).
Причем 2 последних всегда одинаковые.
Ума не приложу с чем это может быть связано...
Проверил действительно в этой строке:
FReadCount := ComStat.cbInQue;
cbInQue = 4
tesseract (2006-01-28 11:25:00) [21]Kolan не парься. К этому классу я шёл года 3.
В конечном итоге и поддержка масок и ThreadSafe и дружбу с классом для Tcp/IP соединений реализовать таки удалось :-)
Вышли конечно. А в Win98 непойдет?
Пойдёт но только через winapi. И номер порта не может быть больше 9.
Kolan (2006-01-28 11:11:00) [22]Вышли конечно. А в Win98 непойдет?
А что насчет моего проекта...
PS
Когдаже осушествится моя мечта и я напишу класс для работы с портом, котроый будет все правильно читать, не подвисать при чтении, самое главное работать с таймаутом, вообшем такой чтобы я забыл о этой проблемме..... уже год парюсь все неразберусь.
tesseract (2006-01-28 10:58:00) [23]Сказал бы сразу что надо. Выслать мой класс для прямого общения с драйвером порта (Win2k+) ?
Kolan (2006-01-28 00:17:00) [24]Чуть чуть не понял.
1. Что такоеSize, а точнее где его взять. Желательно чтобы приемник незнал сколько надо читать. Сколько пришло- столько пришло...
2. Блин что делает этаClearCommErrorникак непойму?
3. Дело в том что скорее всего мне придется кождую секунду принимать массив в 512 остчетов(что-то вроде графика). Каждый остчет- 2 числа, каждое число наверно по 4 байта..... Вообшем довольно много...
tesseract (2006-01-27 23:54:00) [25]А так?
for count:=1 to 5 do
begin
ClearCommError(hCom, ErrCode, @hCurState);
if hCurState.cbInQue>=Size then
begin
result:=true;
exit;
end;
sleep(50);
end;
Kolan (2006-01-27 23:46:00) [26]
Sleep(100);
if not ClearCommError(FPortHandle, dwError, @ComStat) then
{//}Err := True;
FReadCount := ComStat.cbInQue;
if FreadCount > 0 then
Так? - Непомогло
tesseract (2006-01-27 23:38:00) [27]Не парься. Всё ок. Правда с RS-484 я работал только с конвертерами. Для особо одарённых случаев приходилось отключать WaitCommMask и работать именно таким способом.
Kolan (2006-01-27 23:24:00) [28]Шас попробую с задержкой. Ненравится мне этот вариант тк у меня будет RS-485.
Не уверен что получится
Если вас незатруднит обясните мне глубокий смысл ф-цииClearCommError.
Из справки я понял что: Функция извлекает инф. о ошибках связи и сообщ текущее состояние устр-ва связи (это Com порт как я понял). Функция вызывается при возникновении ошибки, и отчишает флаг ошибки устр-ва ч тобы включить дополнительные операции ввода/вывода.
Вот это я не очень понял...
tesseract (2006-01-27 23:08:00) [29]
>Просто засыпть? - это решение мне ненравится...
Зря. Если используешь поток - нормально, на загрузке проца не скажется.
ClearCommError можно вызывать десяток раз, через некоторые промежутки времени Ж-)
Kolan (2006-01-27 23:05:00) [30]Непойму как это сделать?
Просто засыпть? - это решение мне ненравится...
tesseract (2006-01-27 22:27:00) [31]Винда использует буфер.
подожди побольше - придёт побольше байтов.