Люди!!!! Помогите!! Уже сутки практически не могу побороть глюк...
Была поставлена задача общения с устройством по COM-порту. Почитал форумы, накропал тестовый код в не-overlapped.
Все круто , работает... Ловлю когда нужно EV_TXEMPTY, когда нужно — EV_RXCHAR... короче все ровно. Переделал все в overlapped. Начались глюки: получаю только EV_TXEMPTY, даже когда в проге ЕДИНСТВЕННЫЙ вызов SetCommMask с параметром EV_RXCHAR... Всё по три раза перепроверил.. Винда — 2000, компилю VC2003. Может кто сталкивался с таким глюком????? Мозги уже кипят Если нуно выложу код
Здравствуйте, EMU, Вы писали:
EMU>Люди!!!! Помогите!! Уже сутки практически не могу побороть глюк... EMU>Была поставлена задача общения с устройством по COM-порту. Почитал форумы, накропал тестовый код в не-overlapped. EMU>Все круто , работает... Ловлю когда нужно EV_TXEMPTY, когда нужно — EV_RXCHAR... короче все ровно. Переделал все в overlapped. Начались глюки: получаю только EV_TXEMPTY, даже когда в проге ЕДИНСТВЕННЫЙ вызов SetCommMask с параметром EV_RXCHAR... Всё по три раза перепроверил.. Винда — 2000, компилю VC2003. Может кто сталкивался с таким глюком????? Мозги уже кипят Если нуно выложу код
у меня были проблемы с оверлаппедом компортовским — не совсем понятно как должна выглядеть программа в таком случае...
я плюнул — сделал отдельный поток и работаю с ним в синхроне. чего и тебе советую
S>у меня были проблемы с оверлаппедом компортовским — не совсем понятно как должна выглядеть программа в таком случае... S>я плюнул — сделал отдельный поток и работаю с ним в синхроне. чего и тебе советую
А как без оверлаппеда сделать ожидание события с таймаутом? Я всегда предпочитал делать свои потоки и не использовать оверлаппед, но в данном случае приходится, т. к. в не-оверлаппед моде я понял нельзя ждать события с тайм-аутом.
Здравствуйте, EMU, Вы писали:
S>>у меня были проблемы с оверлаппедом компортовским — не совсем понятно как должна выглядеть программа в таком случае... S>>я плюнул — сделал отдельный поток и работаю с ним в синхроне. чего и тебе советую EMU>А как без оверлаппеда сделать ожидание события с таймаутом? Я всегда предпочитал делать свои потоки и не использовать оверлаппед, но в данном случае приходится, т. к. в не-оверлаппед моде я понял нельзя ждать события с тайм-аутом.
ты же писал что у тебя там всё ок в синхроне было...
что за устройство?
S>ты же писал что у тебя там всё ок в синхроне было... S>что за устройство?
все ок было всмысле, что события "правильные" приходили.. а в оверлаппед моде приходит только одно событие — TXEMPTY, вне зависимости от того, с какими параметрами вызываешь SetCommMask... Дело в том, что мне нужно ожидать события (например, EV_RXCHAR) не вечно, а в течение какого-то периода, и по его истечении сделать вывод о том, что устройство не ответило. А если открывать порт в не-оверлаппед режиме, то вызов WaitCommEvent блокирует поток на неопределённое время.
устройство — счёчик электрической энергии.
Здравствуйте, EMU, Вы писали:
EMU>Люди!!!! Помогите!! Уже сутки практически не могу побороть глюк... EMU>Была поставлена задача общения с устройством по COM-порту. Почитал форумы, накропал тестовый код в не-overlapped. EMU>Все круто , работает... Ловлю когда нужно EV_TXEMPTY, когда нужно — EV_RXCHAR... короче все ровно. Переделал все в overlapped. Начались глюки: получаю только EV_TXEMPTY, даже когда в проге ЕДИНСТВЕННЫЙ вызов SetCommMask с параметром EV_RXCHAR... Всё по три раза перепроверил.. Винда — 2000, компилю VC2003. Может кто сталкивался с таким глюком????? Мозги уже кипят Если нуно выложу код
Посмотри в MSDN Monitoring Communications Events
Правда, Ложь — мне все одно — я имею свое мнение.
Если функция недокументированна — это не значит, что ее не используют все ваши конкуренты в своих продуктах.
Любой строй переходный и отрицать это значит быть закостенелым идиотом.
З>Посмотри в MSDN Monitoring Communications Events
Угу, смотрел, когда с COM-портами разбирался... Там такой корявый пример Работать будет раз через 100, а то и вовсе работать не будет
Эээх видимо никто с такой проблемой не сталкивался...
Здравствуйте, EMU, Вы писали:
З>>Посмотри в MSDN Monitoring Communications Events EMU>Угу, смотрел, когда с COM-портами разбирался... Там такой корявый пример Работать будет раз через 100, а то и вовсе работать не будет
Допустим — я не проверял.
EMU>Эээх видимо никто с такой проблемой не сталкивался...
Давай ваш код посмотрим.
Правда, Ложь — мне все одно — я имею свое мнение.
Если функция недокументированна — это не значит, что ее не используют все ваши конкуренты в своих продуктах.
Любой строй переходный и отрицать это значит быть закостенелым идиотом.
Здравствуйте, EMU, Вы писали:
EMU>Люди!!!! Помогите!! Уже сутки практически не могу побороть глюк... EMU>Была поставлена задача общения с устройством по COM-порту. Почитал форумы, накропал тестовый код в не-overlapped. EMU>Все круто , работает... Ловлю когда нужно EV_TXEMPTY, когда нужно — EV_RXCHAR... короче все ровно. Переделал все в overlapped. Начались глюки: получаю только EV_TXEMPTY, даже когда в проге ЕДИНСТВЕННЫЙ вызов SetCommMask с параметром EV_RXCHAR... Всё по три раза перепроверил.. Винда — 2000, компилю VC2003. Может кто сталкивался с таким глюком????? Мозги уже кипят Если нуно выложу код
Приведите фрагменты кода, где вызывается WaitCommEvent и где ожидается событие (WaitForSingleObjet или GetOverlappedResult )
Здравствуйте, TarasCo, Вы писали: TC>Приведите фрагменты кода, где вызывается WaitCommEvent и где ожидается событие (WaitForSingleObjet или GetOverlappedResult )
привожу код:
void CCOMInterface::Initialize(BYTE byPortNumber,
CBaudRate brBaudRate,
CByteSize bsByteSize,
CParity paParity,
CStopBits sbStopBits,
float fTimeoutsMultiplier,
DWORD dwMaxDeviceAnswerTime,
DWORD dwMaxPacketSize,
bool bCloseFirst/*=true*/)
{
try
{
if(bCloseFirst||byPortNumber!=m_byPortNumber)
Free();
if(!m_Overlapped.hEvent)
{
m_Overlapped.hEvent=::CreateEvent(NULL,true,false,NULL);
if(!m_Overlapped.hEvent)
throw CResourceAllocException(ERR_CREATEEVENT,"CCOMInterface::Initialize");
}
CString strPortName;
strPortName.Format("%d",byPortNumber);
strPortName="COM"+strPortName;
if(m_hPort==INVALID_HANDLE_VALUE)
{
// Открытие порта.
m_hPort=::CreateFile(strPortName,GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
0|FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH|FILE_FLAG_OVERLAPPED,0);
if(m_hPort==INVALID_HANDLE_VALUE)
throw CWin32APIException(ERR_CREATEFILE,"CCOMInterface::Initialize");
}
// Сброс буферов порта.int nRetCode=::PurgeComm(m_hPort,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
if(nRetCode==0)
throw CWin32APIException(ERR_PURGECOMM,"CCOMInterface::Initialize");
// Сброс значений регистров порта.
nRetCode=::ClearCommBreak(m_hPort);
if(nRetCode==0)
throw CWin32APIException(ERR_CLEARCOMMBREAK,"CCOMInterface::Initialize");
DCB dcb;
// Получение текущих параметров порта.
nRetCode=::GetCommState(m_hPort,&dcb);
if(nRetCode==0)
throw CWin32APIException(ERR_GETCOMMSTATE,"CCOMInterface::Initialize");
dcb.BaudRate=brBaudRate;
dcb.fBinary=true;
dcb.fParity=paParity!=paNone;
dcb.fOutxCtsFlow=false;
dcb.fOutxDsrFlow=false;
dcb.fDtrControl=DTR_CONTROL_ENABLE;
dcb.fDsrSensitivity=false;
dcb.fOutX=false;
dcb.fInX=false;
dcb.fErrorChar=false;
dcb.fNull=false;
dcb.fRtsControl=RTS_CONTROL_DISABLE;
dcb.fAbortOnError=false;
dcb.ByteSize=bsByteSize;
dcb.Parity=paParity;
dcb.StopBits=sbStopBits;
nRetCode=::SetCommState(m_hPort,&dcb);
if(nRetCode==0)
throw CWin32APIException(ERR_SETCOMMSTATE,"CCOMInterface::Initialize");
nRetCode=::SetupComm(m_hPort,1000,1000);//(dwMaxPacketSize/10+1)*10,0);if(nRetCode==0)
throw CWin32APIException(ERR_SETUPCOMM,"CCOMInterface::Initialize");
float fOneCharTime=1; // Стартовый бит.
fOneCharTime+=bsByteSize; // Размер байта.
fOneCharTime+=paParity==paNone?0:1; // Бит на чётность.switch(sbStopBits) // Стоповые биты.
{
case sb1:
fOneCharTime+=1;
break;
case sb1p5:
fOneCharTime+=1.5;
break;
case sb2:
fOneCharTime+=2;
break;
}
switch(brBaudRate)
{
case br110:
fOneCharTime/=110;
break;
case br300:
fOneCharTime/=300;
break;
case br600:
fOneCharTime/=600;
break;
case br1200:
fOneCharTime/=1200;
break;
case br2400:
fOneCharTime/=2400;
break;
case br4800:
fOneCharTime/=4800;
break;
case br9600:
fOneCharTime/=9600;
break;
case br14400:
fOneCharTime/=14400;
break;
case br19200:
fOneCharTime/=19200;
break;
case 38400:
fOneCharTime/=38400;
break;
case br56000:
fOneCharTime/=56000;
break;
case br57600:
fOneCharTime/=57600;
break;
case br115200:
fOneCharTime/=115200;
break;
case br128000:
fOneCharTime/=128000;
break;
case br256000:
fOneCharTime/=256000;
break;
}
fOneCharTime*=1000;
fOneCharTime*=fTimeoutsMultiplier;
m_ctTimeouts.ReadIntervalTimeout=(DWORD)ceil(fOneCharTime*3);
m_ctTimeouts.ReadTotalTimeoutMultiplier=(DWORD)ceil(fOneCharTime*2);
m_ctTimeouts.ReadTotalTimeoutConstant=(DWORD)ceil(fOneCharTime*3);
m_ctTimeouts.WriteTotalTimeoutMultiplier=m_ctTimeouts.ReadTotalTimeoutMultiplier;
m_ctTimeouts.WriteTotalTimeoutConstant=m_ctTimeouts.ReadTotalTimeoutConstant;
nRetCode=::SetCommTimeouts(m_hPort,&m_ctTimeouts);
if(nRetCode==0)
throw CWin32APIException(ERR_SETCOMMTIMEOUTS,"CCOMInterface::Initialize");
// Установка мониторинга событий.
DWORD dwEventMask=EV_RXCHAR|EV_TXEMPTY;
nRetCode=::SetCommMask(m_hPort,dwEventMask);
if(nRetCode==0)
throw CWin32APIException(ERR_SETCOMMMASK,"CCOMInterface::Initialize");
::Sleep(200);
}
catch(...)
{
Free();
throw;
}
m_byPortNumber=byPortNumber;
m_fTimeoutsMultiplier=fTimeoutsMultiplier;
m_dwMaxDeviceAnswerTime=dwMaxDeviceAnswerTime;
}
//------------------------------------------------------------------------------void CCOMInterface::Recv(BYTE* pBuffer,DWORD dwLength,bool bWaitRXCHAR/*=true*/)
{
ASSERT(pBuffer);
ASSERT(dwLength>0);
ASSERT(m_hPort!=INVALID_HANDLE_VALUE);
try
{
DWORD dwMask=EV_RXCHAR,dwRetCode=0,dwTmp=0;
int nRetCode=0;
if(bWaitRXCHAR)
{
::ResetEvent(m_Overlapped.hEvent);
//nRetCode=::SetCommMask(m_hPort,dwMask);
//if(nRetCode==0)
// throw CWin32APIException(ERR_SETCOMMMASK,"CCOMInterface::Recv");
nRetCode=::WaitCommEvent(m_hPort,&dwMask,&m_Overlapped);
if(nRetCode==0)
{
if(::GetLastError()==ERROR_IO_PENDING)
{
dwRetCode=::WaitForSingleObject(m_Overlapped.hEvent,
(DWORD)ceil(m_dwMaxDeviceAnswerTime*1.5));
if(dwRetCode==WAIT_OBJECT_0)
{
nRetCode=::GetOverlappedResult(m_hPort,&m_Overlapped,&dwMask,false);
if(nRetCode==0)
if(::GetLastError()==ERROR_IO_INCOMPLETE)
throw CBaseException(ERR_TIMEOUT,"CCOMInterface::Recv");
else
throw CWin32APIException(ERR_GETOVERLAPPEDRESULT,"CCOMInterface::Recv");
}
else
throw CBaseException(ERR_TIMEOUT,"CCOMInterface::Recv");
}
else
throw CWin32APIException(ERR_WAITCOMMEVENT,"CCOMInterface::Recv");
}
// ВСЕГДА, В ЛЮБОМ СЛУЧАЕ ПРИХОДИТ EV_TXEMPTY!!! и, соответственно, бросается исключение.
// ЕСЛИ УБРАТЬ ЭТУ ПРОВЕРКУ, ТО ИЗ ПОРТА БЕЗ ОШИБОК И ПРОБЛЕМ МОЖНО ПРОЧИТАТЬ ОТВЕТ УСТРОЙСТВА!if(!(dwMask&EV_RXCHAR))
throw CBaseException(ERR_TIMEOUT,"CCOMInterface::Recv");
}
::ResetEvent(m_Overlapped.hEvent);
::SetThreadPriority(::GetCurrentThread(),THREAD_PRIORITY_HIGHEST);
::Sleep(0);
nRetCode=::ReadFile(m_hPort,pBuffer,dwLength,&dwTmp,&m_Overlapped);
if(nRetCode==0&&::GetLastError()!=ERROR_IO_PENDING)
throw CWin32APIException(ERR_WRITEFILE,"CCOMInterface::Recv");
nRetCode=::GetOverlappedResult(m_hPort,&m_Overlapped,&dwTmp,false);
if(nRetCode==0)
if(::GetLastError()==ERROR_IO_INCOMPLETE)
{
dwRetCode=::WaitForSingleObject(m_Overlapped.hEvent,
m_ctTimeouts.ReadTotalTimeoutMultiplier*dwLength
+m_ctTimeouts.ReadTotalTimeoutConstant);
if(dwRetCode==WAIT_OBJECT_0)
{
nRetCode=::GetOverlappedResult(m_hPort,&m_Overlapped,&dwTmp,false);
if(nRetCode==0)
if(::GetLastError()==ERROR_IO_INCOMPLETE)
throw CBaseException(ERR_TIMEOUT,"CCOMInterface::Recv");
else
throw CWin32APIException(ERR_GETOVERLAPPEDRESULT,"CCOMInterface::Recv");
}
else
throw CBaseException(ERR_TIMEOUT,"CCOMInterface::Recv");
}
else
throw CWin32APIException(ERR_GETOVERLAPPEDRESULT,"CCOMInterface::Recv");
if(dwTmp!=dwLength)
throw CWin32APIException(ERR_WRITEFILE,"CCOMInterface::Recv");
}
catch(...)
{
::SetThreadPriority(::GetCurrentThread(),THREAD_PRIORITY_NORMAL);
throw;
}
::SetThreadPriority(::GetCurrentThread(),THREAD_PRIORITY_NORMAL);
}
В приведённом коде SetCommMask вызывается с паарметром EV_RXCHAR|EV_TXEMPTY. Но пробовал вызыать просто с EV_RXCHAR. Прикол в том, что даже в этом случае когда я дожидаюсь события (именно дожидаюсь, WaitForSingleObject==WAIT_OBJECT_0),
GetOverlappedResult возвращает код события 0x00000004, т. е. EV_TXEMPTY! Это при том, что я вызывал SetCommMask(EV_RXCHAR)!!! Ну и хрень, извиняюсь за выражение!!!
Эта строчка повреждает значение, находящееся в dwMask. По идее после этого dwMask будет равена 4 (поскольку WaitCommEvent возвратила 4 байта ). А EV_TXEMPTY = 0x0004
Кроме тошо замечание. Зачем такой изврат:
ceil(m_dwMaxDeviceAnswerTime*1.5)); ?
лучше m_dwMaxDeviceAnswerTime * 2