Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

COM порт, асинхронные чтение запись


Страницы:   1 2 3 4

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: Протекает наложенное событие ввода/вывода

и кто бы сомневался, что оно протекает... только почему то не вытекает


Страницы:   1 2 3 4

Наверх

Титульная страница Поиск, карта сайта Написать письмо