-
Помогите с вопросом. Уже мозг сломал. Сделал чтение 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. Что я неправильно делаю?
-
> 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 ?
-
Может проще будет проверять сколько байт накопилось ? Вот код (правда на С++) size_t byte_in_port()
; У меня это проверяется в цикле, и если за некоторое время ни чего не нападало - считаю, что передача закончена (не совсем правильно конечно). А сам цикл, примерно такой: ...
if (m_state == state::eWrite)
};
/* read */
if (byte_in_port())
else
flush();
...
-
>А где обработка случая RdRes = True ?
Если ReadFile = True, то WaitForSingleObject как я понимаю уже ни к чему. Или нет? Напоминаю, что ошибка замечена при RdRes = True. Т.е. из файла читается, потом отрабатывает WaitForSingleObject (таймаут не возникает) и GetOverlappedResult и считано 0 байт. Как будто какой то таймаут COM порта возник... При чем при синхронном чтении все работало достаточно стабильно.
>Откуда ты знаешь, что данные будут доступны не позднее пол-секунды ? Должны быть практически сразу они. Там читается 2 байта на скорости 57600 и передатчик отвечает быстро.
>Может проще будет проверять сколько байт накопилось ? Может... но и так работало в синхронном режиме
-
> Если ReadFile = True, то WaitForSingleObject как я понимаю > уже ни к чему
Именно так.
> из файла читается, потом отрабатывает WaitForSingleObject
Зачем ожидание-то, если ReadFile = True ? Сразу забирай данные из буфера в кол-ве lpNumberOfBytesRead
> Должны быть практически сразу они
Не надо делать никаких предположений.
Поставь INFINITE, если ожидание у тебя не в гуёвом потоке - гарантированно дождешься данные.
Или вызывай ф-цию ожидания в цикле с фиксированным сравнительно небольшим таймаутом, пока ф-ция не вернет True.
-
>Не надо делать никаких предположений
почему? за 500 мсек короткий кадр 102 процента должен дойти. А если не дошел, то транспортный протокол все восстановит (что он собственно и делает). INFINITE не люблю с детства.
>Зачем ожидание-то, если ReadFile = True ? А и нету ожидания. Если ReadFile = True, то Wait не вызывается. Или GetOverlappedResult тоже в этом случае ни к чему? Сейчас проверю.
-
> Или GetOverlappedResult тоже в этом случае ни к чему?
Конечно ни к чему. В этом и главная ошибка
-
Проверил. Может и ни к чему, но ошибка видимо не в этом. ReadFile = False, Wait = True, Overlapped = True, 0 байт из ожидаемых 2х принятно.
-
> Wait = True
Ф-ция ожидания вообще-то возвращает не булев результат, а код завершения. Ты попросту не дожидаешься данных (о чем я тебе и сказал, спросив откуда взялось 500), потому как ф-ция вернула не нулевой результат, в то время как именно 0-й результат (см. константу WAIT_OBJECT_0) означает успешное завершение ожидания в течение указанного тобой периода таймаута.
-
Кстати, а каково состояние ивента на момент перед вызовом ф-ции ожидания ? Ты вообще как создавал ивент, с какими параметрами ?
-
Не, там все как в исходниках написано. Т.е. проверяется на 0. Таймаут там не возникает. Event ручной, сбрасывается судя по MSDN сам при ReadFile.
-
> Т.е. проверяется на 0
А, да, вижу, есть такая проверка у тебя.
Что-то я не вижу про автосброс ивента ридфайлом ... Ткни носом ?
-
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 тут все забыть и по кругу
-
> байтики эти приходят, но уже потом
Что значит "потом" ?
-
Ну значит я ставлю точку остановки в отладчике где ошибка и туда попадает, байтов на этот момент еще нет. А потом они в мониторе видны - значит не потерялись в проводах.
-
А почему бы не воспользоваться ReadFileEx и колбэк-механизмом нотификации вместо овелэпа ?
-
Если не разберусь, то буду пытаться этот механизм задействовать. Что то мне подсказывает, что это не проще :) Изменил код на такой: 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: Протекает наложенное событие ввода/вывода
и кто бы сомневался, что оно протекает... только почему то не вытекает
-
ПРобуй так:
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
-
Оно еще может возвратить WAIT_TIMEOUT, но мысль я понял. Тоже хотел так попробовать.
-
> Оно еще может возвратить WAIT_TIMEOUT
Может. Но выход из цикла только по WAIT_OBJECT_0
|