![]() |
| ||
|
|
Новости |
Поиск |
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-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 ?