![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
COM порт, асинхронные чтение запись
REA © (2008-05-16 10:41:00)Помогите с вопросом. Уже мозг сломал.
Сделал чтение COM порта и периодически теряются байтики. В результате получился такой код:
FillChar(IO, SizeOf(IO), 0);
IO.hEvent := FIOEvent; // Overlapped
ToRead := 2; // Допустим 2
RdRes := ReadFile(idComm, Buf[1], ToRead, Bytes, @IO);
If (Not RdRes) And (GetLastError = ERROR_IO_PENDING) Then
RdRes := WaitForSingleObject(FIOEvent, 500) = 0; // Limit frame reading by 500 msec
If (RdRes) Then
RdRes := GetOverlappedResult(idComm, IO, Bytes, False);
If RdRes And (Bytes = ToRead) Then
и вот тут при RdRes = True число байт (Bytes) = 0.
Что я неправильно делаю?
Сергей М. (2008-05-19 12:02:00) [41]
> там это и так в доп. потоке
А зачем тогда асинхронка ? Или этот доп.поток у тебя кроме собственно транспорта еще чем-то важным озадачен ?
> Насчет ThreadAffinitiMask это как то совсем уж сурово
Ну а как ты хотел ?
На то и AffinitiMask, чтобы явно ткнуть систему носом в упомянутый запрет
REA (2008-05-19 11:57:00) [42]>Работай с портом проверенным тобой способом, т.е. в синхронном блок-режиме, но в доп.потоке, если это непозволительно для основного
там это и так в доп. потоке
>Работай в оверлэпе (или с колбэками)
пробую с колбэками. Насчет ThreadAffinitiMask это как то совсем уж сурово.
да в принципе оно и так работает - протокол кадры перезапрашивает, но не люблю такие фокусы - не известно как оно себя поведет на других компьютерах
Сергей М. (2008-05-19 11:34:00) [43]Думаю, у тебя как минимум 2 верных варианта избавления от геморроя:
1. Работай с портом проверенным тобой способом, т.е. в синхронном блок-режиме, но в доп.потоке, если это непозволительно для основного.
2. Работай в оверлэпе (или с колбэками), но исключи возможность выполнения неконтролируемых тобой потоков своего процесса разными ядрами (см. SetProcess/ThreadAffinitiMask)
REA (2008-05-19 11:25:00) [44]>А так ли уж необходим асинхронный оверлэп-режим ?
Дело в следующем: мне нужно дождаться ухода последнего байта, чтобы махнуть по протоколу DTR. Это можно сделать при помощи WaitCommEvent, но сама по себе эта функция таймаута не имеет и может зависнуть, если вызвать ее тогда, когда последний байт уже ушел. Что на многоядерных компьютерах и происходит. В Overlapped режиме можно результат проверить позже с таймаутом. Запись в порт в таком виде вроде работает.
Сергей М. (2008-05-19 10:53:00) [45]А так ли уж необходим асинхронный оверлэп-режим ?
REA (2008-05-19 10:44:00) [46]Поиграл с настройками порта - действительно при одних значениях таймаутов порта возникает именно таймаут при WaitForSingleObject, а при других таймаут не возникает, но число байт = 0
Сейчас сделал чтобы возникал таймаут (все таймауты порта установлены в 0, кроме межбайтового на чтение = 4мс). Ищем дальше...
REA (2008-05-19 10:26:00) [47]>Германн
Спасибо!
REA (2008-05-19 10:25:00) [48]>6 байт - это отнюдь не "пустой кадр".
С точки зрения протокола кадрового уровня я имел ввиду. Поэтому в кавычках.
В синхронном режиме все работало. С появлением многоядерных компьютеров работать перестало (связано с записью и маханием DTR).
Ну может и неправильно инициализирую. Хотя 12 лет отработало уже...
Все равно непонятно где байты пропадают.
Сергей М. (2008-05-19 10:04:00) [49]
> пустой это байт 6, а длинный может 10 и более
6 байт - это отнюдь не "пустой кадр".
Даже 1 байт, посланный дивайсом по прикл.протоколу, уже не есть "пустой кадр".
Может ты порт не должным образом инициализируешь ?
Германн (2008-05-18 15:00:00) [50]
> REA (17.05.08 20:06) [25]
Выслал.
REA (2008-05-17 20:06:00) [51]>Дай определение "пустого" и "длинного" информационного кадра ..
ну пустой это байт 6, а длинный может 10 и более, но тоже не больше 16 наверно. Точнее не помню, но думаю это и не нужно.
>Могу переслать тебе книгу Павла Агурова. Самое, имхо лучшее пособие по работе с СОМ-портом. Скажи только куда.
Было бы здорово. Шлите на rea999<>hotmail.com
Только мне уже самому можно скоро будет книгу писать :)
Германн (2008-05-17 01:20:00) [52]
> REA (16.05.08 10:41)
Могу переслать тебе книгу Павла Агурова. Самое, имхо лучшее пособие по работе с СОМ-портом. Скажи только куда.
Сергей М. (2008-05-16 19:30:00) [53]Дай определение "пустого" и "длинного" информационного кадра ..
REA (2008-05-16 18:08:00) [54]Все страньше и страньше. Таймаут теперь не возникает, но зато все как сначала: все отрабатывает Ok, но число байт = 0
Интересно еще вот что, если программа обменивается "пустыми" кадрами (там только заголовки без информации), то ошибок не возникает. Как только идет обмен "длинными" информационными кадрами возникает ошибка.
REA (2008-05-16 17:38:00) [55]А нет, все на месте :)
Если заменить
RdRes := GetOverlappedResult(idComm, IO, Bytes, True); на False, то выдает вот что:
ODS: Wait bug: Наложенное событие ввода/вывода не находится в сигнальном состоянии
Будем ломать дальше...
REA (2008-05-16 17:28:00) [56]Выяснил что это все таки таймаут, но таймаут вне зависимости от его размера - т.е. хоть 20 секунд поставь. Переписал так:
If (GetLastError = ERROR_IO_PENDING) Then
Begin
RdRes := GetOverlappedResult(idComm, IO, Bytes, True); // А вдруг уже все?
If Not RdRes Then
Begin
WaitRes := WaitForSingleObject(IO.hEvent, 200);
RdRes := WaitRes = 0;
If (RdRes) Then
RdRes := GetOverlappedResult(idComm, IO, Bytes, True)
Else
Begin
OutputDebugString(PChar('Wait bug: ' + SysErrorMessage(GetLastError)));
End
End Else OutputDebugString('Wow');
End Else OutputDebugString(PChar('ReadFile bug'));
ээфект от этого заклинания получился странный: ошибок кажется не возникает, но и сообщение 'Wow' не выводит... Теперь придется проверить на одноядерных процессорах и на Win98 - сдается мне, что там оно себя может вести иначе...
Сергей М. (2008-05-16 17:08:00) [57]
> Оно еще может возвратить WAIT_TIMEOUT
Может. Но выход из цикла только по WAIT_OBJECT_0
REA (2008-05-16 17:04:00) [58]Оно еще может возвратить WAIT_TIMEOUT, но мысль я понял. Тоже хотел так попробовать.
Сергей М. (2008-05-16 16:57:00) [59]ПРобуй так:
RdRes := ReadFile(idComm, Buf[1], ToRead, Bytes, @IO);
If not RdRes Then
Begin
If GetLastError = ERROR_IO_PENDING Then
Begin
while not (WaitForSingleObject(FIOEvent, 500) = WAIT_OBJECT_0) do Sleep(0);
Win32Check(GetOverlappedResult(idComm, IO, Bytes, False));
End Else
RaiseLastWin32Error;
End
REA (2008-05-16 16:10:00) [60]Если не разберусь, то буду пытаться этот механизм задействовать. Что то мне подсказывает, что это не проще :)
Изменил код на такой:
RdRes := ReadFile(idComm, Buf[1], ToRead, Bytes, @IO);
If (Not RdRes) Then
Begin
If (GetLastError = ERROR_IO_PENDING) Then
Begin
RdRes := WaitForSingleObject(FIOEvent, 800) = 0;
If (RdRes) Then
RdRes := GetOverlappedResult(idComm, IO, Bytes, False)
Else
Begin
OutputDebugString(PChar('Wait bug: ' + SysErrorMessage(GetLastError)));
End;
End Else OutputDebugString(PChar('ReadFile bug'));
End;
и выдает он чаще всего вот что:
ODS: Wait bug: Протекает наложенное событие ввода/вывода
и кто бы сомневался, что оно протекает... только почему то не вытекает