Проблема с SetCommMask и WaitCommEvent
От: EMU  
Дата: 26.08.04 07:44
Оценка:
Люди!!!! Помогите!! Уже сутки практически не могу побороть глюк...
Была поставлена задача общения с устройством по COM-порту. Почитал форумы, накропал тестовый код в не-overlapped.
Все круто , работает... Ловлю когда нужно EV_TXEMPTY, когда нужно — EV_RXCHAR... короче все ровно. Переделал все в overlapped. Начались глюки: получаю только EV_TXEMPTY, даже когда в проге ЕДИНСТВЕННЫЙ вызов SetCommMask с параметром EV_RXCHAR... Всё по три раза перепроверил.. Винда — 2000, компилю VC2003. Может кто сталкивался с таким глюком????? Мозги уже кипят Если нуно выложу код
Re: Проблема с SetCommMask и WaitCommEvent
От: shrek  
Дата: 26.08.04 07:58
Оценка:
Здравствуйте, EMU, Вы писали:

EMU>Люди!!!! Помогите!! Уже сутки практически не могу побороть глюк...

EMU>Была поставлена задача общения с устройством по COM-порту. Почитал форумы, накропал тестовый код в не-overlapped.
EMU>Все круто , работает... Ловлю когда нужно EV_TXEMPTY, когда нужно — EV_RXCHAR... короче все ровно. Переделал все в overlapped. Начались глюки: получаю только EV_TXEMPTY, даже когда в проге ЕДИНСТВЕННЫЙ вызов SetCommMask с параметром EV_RXCHAR... Всё по три раза перепроверил.. Винда — 2000, компилю VC2003. Может кто сталкивался с таким глюком????? Мозги уже кипят Если нуно выложу код

у меня были проблемы с оверлаппедом компортовским — не совсем понятно как должна выглядеть программа в таком случае...
я плюнул — сделал отдельный поток и работаю с ним в синхроне. чего и тебе советую
Re[2]: Проблема с SetCommMask и WaitCommEvent
От: EMU  
Дата: 26.08.04 08:03
Оценка:
S>у меня были проблемы с оверлаппедом компортовским — не совсем понятно как должна выглядеть программа в таком случае...
S>я плюнул — сделал отдельный поток и работаю с ним в синхроне. чего и тебе советую
А как без оверлаппеда сделать ожидание события с таймаутом? Я всегда предпочитал делать свои потоки и не использовать оверлаппед, но в данном случае приходится, т. к. в не-оверлаппед моде я понял нельзя ждать события с тайм-аутом.
Re[3]: Проблема с SetCommMask и WaitCommEvent
От: shrek  
Дата: 26.08.04 08:15
Оценка:
Здравствуйте, EMU, Вы писали:

S>>у меня были проблемы с оверлаппедом компортовским — не совсем понятно как должна выглядеть программа в таком случае...

S>>я плюнул — сделал отдельный поток и работаю с ним в синхроне. чего и тебе советую
EMU>А как без оверлаппеда сделать ожидание события с таймаутом? Я всегда предпочитал делать свои потоки и не использовать оверлаппед, но в данном случае приходится, т. к. в не-оверлаппед моде я понял нельзя ждать события с тайм-аутом.
ты же писал что у тебя там всё ок в синхроне было...
что за устройство?
Re[4]: Проблема с SetCommMask и WaitCommEvent
От: EMU  
Дата: 26.08.04 08:26
Оценка:
S>ты же писал что у тебя там всё ок в синхроне было...
S>что за устройство?
все ок было всмысле, что события "правильные" приходили.. а в оверлаппед моде приходит только одно событие — TXEMPTY, вне зависимости от того, с какими параметрами вызываешь SetCommMask... Дело в том, что мне нужно ожидать события (например, EV_RXCHAR) не вечно, а в течение какого-то периода, и по его истечении сделать вывод о том, что устройство не ответило. А если открывать порт в не-оверлаппед режиме, то вызов WaitCommEvent блокирует поток на неопределённое время.
устройство — счёчик электрической энергии.
Re: Проблема с SetCommMask и WaitCommEvent
От: Злость Россия  
Дата: 26.08.04 08:30
Оценка:
Здравствуйте, EMU, Вы писали:

EMU>Люди!!!! Помогите!! Уже сутки практически не могу побороть глюк...

EMU>Была поставлена задача общения с устройством по COM-порту. Почитал форумы, накропал тестовый код в не-overlapped.
EMU>Все круто , работает... Ловлю когда нужно EV_TXEMPTY, когда нужно — EV_RXCHAR... короче все ровно. Переделал все в overlapped. Начались глюки: получаю только EV_TXEMPTY, даже когда в проге ЕДИНСТВЕННЫЙ вызов SetCommMask с параметром EV_RXCHAR... Всё по три раза перепроверил.. Винда — 2000, компилю VC2003. Может кто сталкивался с таким глюком????? Мозги уже кипят Если нуно выложу код

Посмотри в MSDN Monitoring Communications Events
Правда, Ложь — мне все одно — я имею свое мнение.
Если функция недокументированна — это не значит, что ее не используют все ваши конкуренты в своих продуктах.
Любой строй переходный и отрицать это значит быть закостенелым идиотом.
Re[2]: Проблема с SetCommMask и WaitCommEvent
От: EMU  
Дата: 26.08.04 08:41
Оценка:
З>Посмотри в MSDN Monitoring Communications Events
Угу, смотрел, когда с COM-портами разбирался... Там такой корявый пример Работать будет раз через 100, а то и вовсе работать не будет
Эээх видимо никто с такой проблемой не сталкивался...
Re[3]: Проблема с SetCommMask и WaitCommEvent
От: Злость Россия  
Дата: 26.08.04 08:48
Оценка:
Здравствуйте, EMU, Вы писали:

З>>Посмотри в MSDN Monitoring Communications Events

EMU>Угу, смотрел, когда с COM-портами разбирался... Там такой корявый пример Работать будет раз через 100, а то и вовсе работать не будет

Допустим — я не проверял.

EMU>Эээх видимо никто с такой проблемой не сталкивался...


Давай ваш код посмотрим.
Правда, Ложь — мне все одно — я имею свое мнение.
Если функция недокументированна — это не значит, что ее не используют все ваши конкуренты в своих продуктах.
Любой строй переходный и отрицать это значит быть закостенелым идиотом.
Re: Проблема с SetCommMask и WaitCommEvent
От: TarasCo  
Дата: 26.08.04 08:49
Оценка:
Здравствуйте, EMU, Вы писали:

EMU>Люди!!!! Помогите!! Уже сутки практически не могу побороть глюк...

EMU>Была поставлена задача общения с устройством по COM-порту. Почитал форумы, накропал тестовый код в не-overlapped.
EMU>Все круто , работает... Ловлю когда нужно EV_TXEMPTY, когда нужно — EV_RXCHAR... короче все ровно. Переделал все в overlapped. Начались глюки: получаю только EV_TXEMPTY, даже когда в проге ЕДИНСТВЕННЫЙ вызов SetCommMask с параметром EV_RXCHAR... Всё по три раза перепроверил.. Винда — 2000, компилю VC2003. Может кто сталкивался с таким глюком????? Мозги уже кипят Если нуно выложу код

Приведите фрагменты кода, где вызывается WaitCommEvent и где ожидается событие (WaitForSingleObjet или GetOverlappedResult )
Да пребудет с тобою сила
Re[2]: Проблема с SetCommMask и WaitCommEvent
От: EMU  
Дата: 26.08.04 09:11
Оценка:
Здравствуйте, 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);
}
Re: Проблема с SetCommMask и WaitCommEvent
От: EMU  
Дата: 26.08.04 10:47
Оценка:
В приведённом коде SetCommMask вызывается с паарметром EV_RXCHAR|EV_TXEMPTY. Но пробовал вызыать просто с EV_RXCHAR. Прикол в том, что даже в этом случае когда я дожидаюсь события (именно дожидаюсь, WaitForSingleObject==WAIT_OBJECT_0),
GetOverlappedResult возвращает код события 0x00000004, т. е. EV_TXEMPTY! Это при том, что я вызывал SetCommMask(EV_RXCHAR)!!! Ну и хрень, извиняюсь за выражение!!!
Re[3]: Проблема с SetCommMask и WaitCommEvent
От: TarasCo  
Дата: 26.08.04 11:27
Оценка:
Здравствуйте, EMU, Вы писали:

ИМХО косяк здесь:
nRetCode=::GetOverlappedResult(m_hPort,&m_Overlapped,&dwMask,false);

Эта строчка повреждает значение, находящееся в dwMask. По идее после этого dwMask будет равена 4 (поскольку WaitCommEvent возвратила 4 байта ). А EV_TXEMPTY = 0x0004

Кроме тошо замечание. Зачем такой изврат:
ceil(m_dwMaxDeviceAnswerTime*1.5)); ?
лучше m_dwMaxDeviceAnswerTime * 2
Да пребудет с тобою сила
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.