我正在调用一个通过串口操作I / O板的功能,以检查它是否在我的主类的实例中进行通信。
我知道这是有风险的,但不幸的是,这是一段旧代码,已经使用了一段时间,所以当我被要求改进它时,我无法改变功能。
如果没有通信问题,应用程序将启动,请使用该功能并继续没有问题 当I / O板出现通信故障时会出现问题,我发现读取功能正在挂起并且大部分时间都停止启动应用程序。有时应用程序将加载并报告存在通信故障。
我想要实现的是每次出现通信故障时应用程序都能成功加载。
comport最初是用COMMTIMEOUT设置的,当我没有任何东西需要读取时,我预计它会超时。我试图改变时间但没有用。
我还试图将一个线程用于读取功能,这样它就不会阻止启动但仍会挂起。
目前端口是同步设置的。
有人有任何建议吗?如果需要,我可以提供一些代码示例。
extern COMPort comPort;
BOOL Main::InitInstance()
{
int i = comPort.DoorLatchOff();
If(i<0) printf("Error checksum. COM port?\n");
else printf("checksum ok.\n");
}
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 );
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);
}
答案 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)
最近,我遇到了同样的问题,但是已经解决了。 有两种方法:
在论坛上,有些人建议将“ ReadIntervalTimeout”和“ ReadTotalTimeoutMultiplier”都设置为MAXDWORD,如“备注”部分中的MSDN文档所建议的那样。但是在这种情况下,每当输入缓冲区中至少有一个字符时,函数就会返回。
我找到的最可靠的决定就是将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事件驱动的串行库。