/*参数说明:
dwBufferLength 缓冲区长度
buff           缓冲区指针
m_WaitTime     超时时长
返回值说明: 0 串口未打开 
             非0 缓冲区数据长度
*/
UINT CSerialPorts::ReadComData(DWORD dwBufferLength,UCHAR * buff,int m_WaitTime)
{
	if(FALSE==CheckPortOpen())
		return 0;

	DWORD dwErr;
	COMSTAT comStat;  //设备信息
	//清错,同时填充设备信息结构体
	ClearCommError(hCom,&dwErr,&comStat);

	DWORD dwReadLength=0; //实际读取长度
	//判断最小值作为读取长度
	dwReadLength=min(dwBufferLength,comStat.cbInQue);

	if(FALSE==ReadFile(hCom,buff,dwReadLength,&dwReadLength,&m_overLappedRead))
	{
		if(ERROR_IO_PENDING==GetLastError())
		{
			//结束异步IO
			WaitForSingleObject(m_overLappedRead.hEvent,m_WaitTime);
			if(FALSE==GetOverlappedResult(hCom,&m_overLappedRead,&dwReadLength,false))
				dwReadLength=0;
		}
		else
			dwReadLength=0;
	}

	return dwReadLength;
}
//设置DCB结构体
BOOL CSerialPorts::SetDCBParam()
{
	if(FALSE==CheckPortOpen())
		return FALSE;
	if(FALSE==GetCommState(hCom,&m_dcb))
	{
		AfxMessageBox(_T("串口连接失败,请重新连接!"));
		CloseComPort();
		return FALSE;
	}

	switch(m_nBaud)
	{
	case 0:
		m_nBaud=9600;   break;
	case 1:
		m_nBaud=19200;  break;
	case 2:
		m_nBaud=38400;  break;
	case 3:
		m_nBaud=57600;  break;
	case 4:
		m_nBaud=115200; break;
	}

	//m_dcb.BaudRate=m_nBaud;
	m_dcb.ByteSize=m_nDataBits;

	switch(m_nParity)
	{
	case 0:
		m_dcb.Parity=NOPARITY;  break;
	case 1:
		m_dcb.Parity=ODDPARITY; break;
	case 2:
		m_dcb.Parity=EVENPARITY;break;
	}

	switch(m_nStopBits)
	{
	case 0:
		m_dcb.StopBits=ONESTOPBIT;  break;
	//case 1:
	//	m_dcb.StopBits=ONESSTOPBITS;break; 
	case 2:
		m_dcb.StopBits=TWOSTOPBITS; break;
	}

	m_dcb.StopBits=m_nStopBits;

	SetCommState(hCom,&m_dcb);

	return TRUE;

}
//设置端口缓冲区大小
BOOL CSerialPorts::SetPortBuffSize()
{
	if(FALSE==CheckPortOpen())
		return FALSE;
	if(FALSE==SetupComm(hCom,m_inputBuff,m_outputBuff))
	{
		AfxMessageBox(_T("串口数据缓冲区设置失败,请重新连接!"));
		CloseComPort();
		return FALSE;
	}
	else
		return TRUE;
}
//关闭串口
void CSerialPorts::CloseComPort()
{
	if(TRUE==CheckPortOpen())
	{
		CloseHandle(hCom);
		hCom=INVALID_HANDLE_VALUE;
	}

	if(m_overLappedRead.hEvent)
		CloseHandle(m_overLappedRead.hEvent);
	if(m_overLappedWrite.hEvent)
		CloseHandle(m_overLappedWrite.hEvent);

	return;
}
//超时设置
BOOL CSerialPorts::SetTimerOut()
{
	if(FALSE==CheckPortOpen())
		return FALSE;
	
	//设置两个字符到达之间的最大时间间隔
	m_timeOuts.ReadIntervalTimeout=MAXDWORD;
	//读操作的总超时时间的计算系数(ms)
	m_timeOuts.WriteTotalTimeoutMultiplier=0;
	//读操作的总超时时间的计算常数(ms)
	m_timeOuts.ReadTotalTimeoutConstant=0;

	m_timeOuts.WriteTotalTimeoutConstant=0;
	m_timeOuts.WriteTotalTimeoutMultiplier=0;

	return TRUE;
}
//打开并初始化串口
BOOL CSerialPorts::InitComPortSet(int nCom, int nBaud,int nParity)
{
	//检查串口是否已经打开
	if(TRUE==CheckPortOpen())
		CloseComPort();
	//设置异步读写事件
	if(FALSE==SetEventToReadWrite())
		AfxMessageBox(_T("串口连接设置失败,请重新连接!"));
	//设置波特率、串口名和校验方式
	m_nBaud=nBaud;
	m_nParity=nParity;
	switch(nCom)
	{
	case 0: m_cName=_T("COM1"); break;
	case 1: m_cName=_T("COM2"); break;
	case 2: m_cName=_T("COM3"); break;
	case 3: m_cName=_T("COM4"); break;
	case 4: m_cName=_T("COM5"); break;
	case 5: m_cName=_T("COM6"); break;
	case 6: m_cName=_T("COM7"); break;
	case 7: m_cName=_T("COM8"); break;
	}
	//打开端口
	hCom=CreateFile(m_cName,        //端口名               
		GENERIC_READ|GENERIC_WRITE, //访问类型:读写
		0,                          //是否共享端口,0为独占
		NULL,                       //默认安全性
		OPEN_EXISTING,              //只打开而不创建
		FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //重叠方式
		NULL);                      //端口打开时不需要,参数为0
	if(INVALID_HANDLE_VALUE==hCom)
		return FALSE;
	//设置串口缓冲区大小
	SetPortBuffSize();
	//设置DCB结构体
	if(FALSE==SetDCBParam())
		return FALSE;
	//设置超时结构体
	SetTimerOut();
	//清空串口数据缓冲区
	PurgeComm(hCom,PURGE_RXABORT|PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_TXABORT);	
	return TRUE;
}
Beispiel #7
0
uint8_t TSerialPort::ReadByte()
{
    CheckPortOpen();

    if (!Select(Settings.ResponseTimeout))
        throw TSerialDeviceTransientErrorException("timeout");

    uint8_t b;
    if (read(Fd, &b, 1) < 1)
        throw TSerialDeviceException("read() failed");

    if (Dbg) {
        std::ios::fmtflags f(std::cerr.flags());
        std::cerr << "Read: " << std::hex << std::setw(2) << std::setfill('0') << int(b) << std::endl;
        std::cerr.flags(f);
    }

    return b;
}
Beispiel #8
0
void TSerialPort::Close()
{
    CheckPortOpen();
    modbus_close(Context->Inner);
    Fd = -1;
}
Beispiel #9
0
int TSerialPort::ReadFrame(uint8_t* buf, int size,
                           const std::chrono::microseconds& timeout,
                           TFrameCompletePred frame_complete)
{
    CheckPortOpen();
    int nread = 0;
    while (nread < size) {
        if (frame_complete && frame_complete(buf, nread)) {
            // XXX A hack.
            // The problem is that if we don't pause here and the
            // serial client switches to another device after
            // processing this frame, that device may miss the frame
            // boundary and consider the last response (from this
            // device) and the query (from the master) to be single
            // frame. On the other hand, we don't want to use
            // device-specific frame timeout here as it can be quite
            // long. The proper solution would be perhaps ensuring
            // that there's a pause of at least
            // DeviceConfig->FrameTimeoutMs before polling each
            // device.
            usleep(DefaultFrameTimeout.count());
            break;
        }

        if (!Select(!nread ? Settings.ResponseTimeout :
                    timeout.count() < 0 ? DefaultFrameTimeout :
                    timeout))
            break; // end of the frame

        // We don't want to use non-blocking IO in general
        // (e.g. we want blocking writes), but we don't want
        // read() call below to block because actual frame
        // size is not known at this point. So we must
        // know how many bytes are available
        int nb;
        if (ioctl(Fd, FIONREAD, &nb) < 0)
            throw TSerialDeviceException("FIONREAD ioctl() failed");
        if (!nb)
            continue; // shouldn't happen, actually
        if (nb > size - nread)
            nb = size - nread;

        int n = read(Fd, buf + nread, nb);
        if (n < 0)
            throw TSerialDeviceException("read() failed");
        if (n < nb) // may happen only due to a kernel/driver bug
            throw TSerialDeviceException("short read()");

        nread += nb;
    }

    if (!nread)
        throw TSerialDeviceTransientErrorException("request timed out");

    if (Dbg) {
        // TBD: move this to libwbmqtt (HexDump?)
        std::ios::fmtflags f(std::cerr.flags());
        std::cerr << "ReadFrame:" << std::hex << std::uppercase << std::setfill('0');
        for (int i = 0; i < nread; ++i) {
            std::cerr << " " << std::setw(2) << int(buf[i]);
        }
        std::cerr << std::endl;
        std::cerr.flags(f);
    }

    return nread;
}