COMMTIMEOUT和Thread没有调整串口读取功能

时间:2017-03-29 14:03:34

标签: c++ windows serial-port c++98

我正在调用一个通过串口操作I / O板的功能,以检查它是否在我的主类的实例中进行通信。
我知道这是有风险的,但不幸的是,这是一段旧代码,已经使用了一段时间,所以当我被要求改进它时,我无法改变功能。

如果没有通信问题,应用程序将启动,请使用该功能并继续没有问题 当I / O板出现通信故障时会出现问题,我发现读取功能正在挂起并且大部分时间都停止启动应用程序。有时应用程序将加载并报告存在通信故障。

我想要实现的是每次出现通信故障时应用程序都能成功加载。

comport最初是用COMMTIMEOUT设置的,当我没有任何东西需要读取时,我预计它会超时。我试图改变时间但没有用。

我还试图将一个线程用于读取功能,这样它就不会阻止启动但仍会挂起。

目前端口是同步设置的。

有人有任何建议吗?如果需要,我可以提供一些代码示例。

Main.cpp的

extern COMPort comPort;
BOOL Main::InitInstance()
{
 int i = comPort.DoorLatchOff();
 If(i<0) printf("Error checksum. COM port?\n");
 else printf("checksum ok.\n");
}

COMPort.h

class CCOMPort    
{  
  public:  
   CCOMPort (COM_PORT port = NULL_COM, DCB * state = NULL);
   BOOL SetPortNumber (COM_PORT port = NULL_COM, DCB * state = NULL);
   void Read(BYTE* buff, int count); 
   int DoorLatchOff(void); 
  protected:  
   HANDLE    m_hPort;  
};   
static HANDLE    m_hPortThreaded;
typedef struct readParam{BYTE* readBuff;int readCount;}RP, *PRP;

DWORD WINAPI ThreadedRead( LPVOID lpParam );

COMPort.cpp

CCOMPort::CCOMPort (COM_PORT port, DCB * state) : m_portNum (port), m_hPort(INVALID_HANDLE_VALUE)
{
 SetPortNumber (port, state);
}
BOOL CCOMPort::SetPortNumber (COM_PORT port, DCB * state)
{
  if (m_hPort != INVALID_HANDLE_VALUE){
    ::CloseHandle (m_hPort);
    m_hPort = INVALID_HANDLE_VALUE;
  }

   m_portNum     = port;
   m_currState   = m_defState;
   m_originState = m_defState;

  if (m_portNum != NULL_COM){
  stringstream ssPortName;
  ssPortName << "COM" << (m_portNum + 1) << ":" << flush;

  m_hPort = ::CreateFile (ssPortName.str().c_str(), 
                         GENERIC_READ | GENERIC_WRITE, 
                         FILE_SHARE_READ | FILE_SHARE_WRITE,
                          NULL, 
                          OPEN_EXISTING, 
                          FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, 
                          NULL);

  if (m_hPort == INVALID_HANDLE_VALUE)
    return FALSE;
  else
    {
      GetState (& m_originState);

     if (state)
      m_currState = * state;
     SetState (& m_currState);

     GetCommTimeouts(m_hPort, &timeouts);

     timeouts.ReadIntervalTimeout = 75; //15
     timeouts.ReadTotalTimeoutMultiplier = 5;       //1
     timeouts.ReadTotalTimeoutConstant = 1250;      //250
     timeouts.WriteTotalTimeoutMultiplier = 5;      //1
     timeouts.WriteTotalTimeoutConstant = 1250;     //250
     SetCommTimeouts(m_hPort, &timeouts);
     FlushOutput ();
     FlushInput ();
     PurgeOutput ();
     PurgeInput ();
    }
  }

  return TRUE;
}
void CCOMPort::Read(BYTE* buff, int count)
{
  PRP pReadArray[1];
  DWORD dwThreadArray[1];
  HANDLE hThreadArray[1];
  m_hPortThreaded = m_hPort;

  pReadArray[0] = (PRP) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RP));

  if(pReadArray[0] == NULL){
    ExitProcess(2);
  }

  pReadArray[0]->readBuff = buff;
  pReadArray[0]->readCount = count;
  hThreadArray[0] = CreateThread(NULL,
                                    0,
                         ThreadedRead,
                        pReadArray[0],
                                    0,
                   &dwThreadArray[0]);

  if(hThreadArray[0] == NULL){
    ExitProcess(3);
  }

  WaitForSingleObject(hThreadArray[0],500/*INFINITE*/);
  CloseHandle(hThreadArray[0]);

  if(pReadArray[0] != NULL){
    HeapFree(GetProcessHeap(), 0, pReadArray[0]);
    pReadArray[0] = NULL;    
  }
}

DWORD WINAPI ThreadedRead(LPVOID lpParam)
{
  BOOL bDone = FALSE, bResult;
  //int buff_idx = 0;
  DWORD dwCommModemStatus;
  DWORD dwBytesTransfered;

  PRP pReadArray;
  pReadArray = (PRP)lpParam;
  SetCommMask(m_hPortThreaded, EV_RXCHAR);
  while(!bDone){
    WaitCommEvent(m_hPortThreaded, &dwCommModemStatus, 0);
    if(dwCommModemStatus == 0){
    bDone = TRUE;
    break;
    }
    if(dwCommModemStatus & EV_RXCHAR){
      bResult = ReadFile(m_hPortThreaded, pReadArray[0].readBuff, pReadArray[0].readCount, &dwBytesTransfered, 0);
      bDone = TRUE;
    }
  }
  return(bResult);

}
int COMPort::DoorLatchOff(void)
{
  unsigned char comm_str[10];
  int chksum, chksum1;
  DWORD count = 6;

  WriteComm(21, 7, 0);
  comm.Read(comm_str, count);

  chksum = comm_str[0] + comm_str[2] + comm_str[3];
  chksum1 = comm_str[4];
  chksum1 = (chksum1 << 8) | comm_str[5];

  if(chksum == chksum1)
   return(0);
  else
   return(-1);
}

3 个答案:

答案 0 :(得分:1)

请问,您是否可以尝试从ThreadedRead中删除WaitCommEvent函数并查看它是否仍然挂起?

DWORD WINAPI ThreadedRead(LPVOID lpParam)
{
    BOOL bResult;
    DWORD dwBytesTransfered = 0;

    PRP pReadArray;
    pReadArray = (PRP)lpParam;

    while (dwBytesTransfered == 0) {
        bResult = ReadFile(m_hPortThreaded, pReadArray[0].readBuff, pReadArray[0].readCount, &dwBytesTransfered, 0);

        Sleep(250);
    }

    return(bResult);
}

答案 1 :(得分:1)

最近,我遇到了同样的问题,但是已经解决了。 有两种方法:

  1. 在论坛上,有些人建议将“ ReadIntervalTimeout”和“ ReadTotalTimeoutMultiplier”都设置为MAXDWORD,如“备注”部分中的MSDN文档所建议的那样。但是在这种情况下,每当输入缓冲区中至少有一个字符时,函数就会返回。

  2. 我找到的最可靠的决定就是将ReadIntervalTimeout和ReadTotalTimeoutMultiplier设置为0,并将ReadTotalTimeoutConstant设置为您的超时值,如下所示。对我来说很好。

    COMMTIMEOUTS        commtimeouts;
    
    GetCommTimeouts (hCommFile, &commtimeouts);
    
    commtimeouts.ReadIntervalTimeout         = 0;
    commtimeouts.ReadTotalTimeoutMultiplier  = 0;
    commtimeouts.ReadTotalTimeoutConstant    = timeout;
    commtimeouts.WriteTotalTimeoutMultiplier = 0;
    commtimeouts.WriteTotalTimeoutConstant   = 0;
    
    SetCommTimeouts (hCommFile, &commtimeouts);
    

答案 2 :(得分:-1)

处理hw I / O时,最好将Application(GUI)线程与命令执行线程分离。
如果您正在开发C ++ Win32应用程序,则可以使用SerialLib。它是一个旧的但稳定的Win32事件驱动的串行库。