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-16 15:53:00) [61]

А почему бы не воспользоваться ReadFileEx и колбэк-механизмом нотификации вместо овелэпа ?


REA   (2008-05-16 15:35:00) [62]

Ну значит я ставлю точку остановки в отладчике где ошибка и туда попадает, байтов на этот момент еще нет. А потом они в мониторе видны - значит не потерялись в проводах.


Сергей М.   (2008-05-16 15:29:00) [63]


> байтики эти приходят, но уже потом


Что значит "потом" ?


REA   (2008-05-16 15:22:00) [64]

ReadFile resets the event specified by the hEvent member of the OVERLAPPED structure to a nonsignaled state when it begins the I/O operation. Therefore, the caller does not need to do that.

Посмотрел COM монитором - байтики эти приходят, но уже потом, когда я решил, что это ошибка:
0.00000073 Geoscape.exe IOCTL_SERIAL_SET_WAIT_MASK Serial0 SUCCESS Mask: TXEMPTY  - ждать пока последний байт ушел
0.00000312 Geoscape.exe IOCTL_SERIAL_SET_DTR Serial0 SUCCESS  махнуть DTR
0.00001523 Geoscape.exe IRP_MJ_WRITE Serial0 SUCCESS Length 3: 51 00 4A  записать
0.00000152 Geoscape.exe IOCTL_SERIAL_WAIT_ON_MASK Serial0 SUCCESS  подождать
0.00000071 Geoscape.exe IOCTL_SERIAL_SET_WAIT_MASK Serial0 SUCCESS Mask:  сбросить маску
0.00000447 Geoscape.exe IOCTL_SERIAL_CLR_DTR Serial0 SUCCESS  снять DTR
0.00000279 Geoscape.exe IRP_MJ_READ Serial0 SUCCESS Length 2: 31 00  читать 2 байта
0.00000201 Geoscape.exe IRP_MJ_READ Serial0 SUCCESS Length 1: 52  читать все остальное - тут порядок
0.00000148 Geoscape.exe IOCTL_SERIAL_SET_WAIT_MASK

Serial0 SUCCESS Mask: TXEMPTY  далее по кргу
0.00000381 Geoscape.exe IOCTL_SERIAL_SET_DTR Serial0 SUCCESS  
0.00002319 Geoscape.exe IRP_MJ_WRITE Serial0 SUCCESS Length 3: 51 00 4A  
0.00000156 Geoscape.exe IOCTL_SERIAL_WAIT_ON_MASK Serial0 SUCCESS  
0.00000077 Geoscape.exe IOCTL_SERIAL_SET_WAIT_MASK Serial0 SUCCESS Mask:  
0.00000518 Geoscape.exe IOCTL_SERIAL_CLR_DTR Serial0 SUCCESS  
0.00000362 Geoscape.exe IRP_MJ_READ Serial0 SUCCESS Length 2: 31 00  
0.00000195 Geoscape.exe IRP_MJ_READ Serial0 SUCCESS Length 1: 52  
0.00000162 Geoscape.exe IOCTL_SERIAL_SET_WAIT_MASK Serial0 SUCCESS Mask: TXEMPTY  
0.00000386 Geoscape.exe IOCTL_SERIAL_SET_DTR Serial0 SUCCESS  
0.00002064 Geoscape.exe IRP_MJ_WRITE Serial0 SUCCESS Length 3: 51 00 4A  
0.00000173 Geoscape.exe IOCTL_SERIAL_WAIT_ON_MASK Serial0 SUCCESS  
0.00000069 Geoscape.exe IOCTL_SERIAL_SET_WAIT_MASK Serial0 SUCCESS Mask:  
0.00000441 Geoscape.exe IOCTL_SERIAL_CLR_DTR Serial0 SUCCESS  
181.90626013 Geoscape.exe IRP_MJ_READ Serial0 SUCCESS Length 2: 34 28  - а вот тут я не дождался
0.00000424 Geoscape.exe IOCTL_SERIAL_PURGE Serial0 SUCCESS Purge: RXCLEAR тут все забыть и по кругу


Сергей М.   (2008-05-16 14:58:00) [65]


> Т.е. проверяется на 0


А, да, вижу, есть такая проверка у тебя.

Что-то я не вижу про автосброс ивента ридфайлом ...
Ткни носом ?


REA   (2008-05-16 14:40:00) [66]

Не, там все как в исходниках написано. Т.е. проверяется на 0.
Таймаут там не возникает.
Event ручной, сбрасывается судя по MSDN сам при ReadFile.


Сергей М.   (2008-05-16 11:47:00) [67]

Кстати, а каково состояние ивента на момент перед вызовом ф-ции ожидания ?
Ты вообще как создавал ивент, с какими параметрами ?


Сергей М.   (2008-05-16 11:46:00) [68]


> Wait = True


Ф-ция ожидания вообще-то возвращает не булев результат, а код завершения.
Ты попросту не дожидаешься данных (о чем я тебе и сказал, спросив откуда взялось 500), потому как ф-ция вернула не нулевой результат, в то время как именно 0-й результат (см. константу WAIT_OBJECT_0) означает успешное завершение ожидания в течение указанного тобой периода таймаута.


REA   (2008-05-16 11:37:00) [69]

Проверил. Может и ни к чему, но ошибка видимо не в этом. ReadFile = False, Wait = True, Overlapped = True, 0 байт из ожидаемых 2х принятно.


Сергей М.   (2008-05-16 11:32:00) [70]


> Или GetOverlappedResult тоже в этом случае ни к чему?


Конечно ни к чему.
В этом и главная ошибка


REA   (2008-05-16 11:27:00) [71]

>Не надо делать никаких предположений

почему? за 500 мсек короткий кадр 102 процента должен дойти. А если не дошел, то транспортный протокол все восстановит (что он собственно и делает). INFINITE не люблю с детства.

>Зачем ожидание-то, если  ReadFile = True ?
А и нету ожидания. Если ReadFile = True, то Wait не вызывается. Или GetOverlappedResult тоже в этом случае ни к чему? Сейчас проверю.


Сергей М.   (2008-05-16 11:22:00) [72]


> Если ReadFile = True, то WaitForSingleObject как я понимаю
> уже ни к чему


Именно так.


> из файла читается, потом отрабатывает WaitForSingleObject


Зачем ожидание-то, если  ReadFile = True ?
Сразу забирай данные из буфера в кол-ве lpNumberOfBytesRead


> Должны быть практически сразу они


Не надо делать никаких предположений.

Поставь INFINITE, если ожидание у тебя не в гуёвом потоке - гарантированно дождешься данные.

Или вызывай ф-цию ожидания в цикле с фиксированным сравнительно небольшим таймаутом, пока ф-ция не вернет True.


REA   (2008-05-16 11:13:00) [73]

>А где обработка случая RdRes = True ?

Если ReadFile = True, то WaitForSingleObject как я понимаю уже ни к чему. Или нет?
Напоминаю, что ошибка замечена при RdRes = True. Т.е. из файла читается, потом отрабатывает WaitForSingleObject (таймаут не возникает) и GetOverlappedResult и считано 0 байт. Как будто какой то таймаут COM порта возник... При чем при синхронном чтении все работало достаточно стабильно.

>Откуда ты знаешь, что данные будут доступны не позднее пол-секунды ?
Должны быть практически сразу они. Там читается 2 байта на скорости 57600 и передатчик отвечает быстро.

>Может проще будет проверять сколько байт накопилось ?
Может... но и так работало в синхронном режиме


МистерТ   (2008-05-16 10:51:00) [74]

Может проще будет проверять сколько байт накопилось ?
Вот код (правда на С++)
       size_t byte_in_port()
       {
           if (!m_pSerialPort)
               return 0;
           DWORD   l_dwErrors;
           COMSTAT l_stStat;
           size_t Result;
           ::ClearCommError(m_pSerialPort->m_port,
                           &l_dwErrors,
                           &l_stStat);
           Result = static_cast (l_stStat.cbInQue) ;
           return Result;
       };

У меня это проверяется в цикле, и если за некоторое время ни чего не нападало - считаю, что передача закончена (не совсем правильно конечно).
А сам цикл, примерно такой:
...
           if (m_state == state::eWrite)
           {
               /* write */
               if (!byte_in_port())
               {
                   flush();
                   write_data();
                   if (m_pSerialPort->m_sending_messages.empty())
                       m_state = state::eRead;
                   next();
                   return;
               }
           };
           /* read */
           if (byte_in_port())
           {
               read_data();
           }
           else
               flush();
...


Сергей М.   (2008-05-16 10:50:00) [75]


>   RdRes := ReadFile(idComm, Buf[1], ToRead, Bytes, @IO);
>
>   If ( Not RdRes) And (GetLastError = ERROR_IO_PENDING) Then


А где обработка случая RdRes = True ?


> WaitForSingleObject(FIOEvent, 500)
> If (RdRes) Then


Почему 500 ? Откуда ты знаешь, что данные будут доступны не позднее пол-секунды ?
Где обработка случая RdRes = False ?


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

Наверх

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