Bläddra i källkod

读取串口内容太快,导致CMDOPT_GET未能完全读取所有数据的问题处理。

jianfeng1.wang 2 år sedan
förälder
incheckning
7736ea5222

+ 8 - 0
TCLCommand/TCLCommand/Command.cpp

@@ -565,6 +565,14 @@ bool TCLCommand::SendCommand(CommandParam& cmdPara)
         Sleep(cmdPara.read_wait_time);
         int nReadCount = ReadSync(m_pData, MAXSIZE);
 		cmdPara._rtnContext.append((char*)m_pData, nReadCount);
+
+		// 读得太快,只返回了一段;
+		if ( cmdPara._rtnContext.size() <=  5 && cmdPara.nOption == CMDOPT_Get )
+		{
+			memset(m_pData, 0, MAXSIZE);
+			int nReadCount = ReadSync(m_pData, MAXSIZE);
+			cmdPara._rtnContext.append((char*)m_pData, nReadCount);
+		}
     }
 
 	utils::_dprintf("结果:%s = %s", cmdPara.name.c_str(), utils::BytesToHexString((byte*)cmdPara._rtnContext.c_str(), cmdPara._rtnContext.size(), ' ').c_str());

+ 6 - 1
TCLCommand/TCLCommand/ReadMe.txt

@@ -118,7 +118,12 @@ WriteTotalTimeoutMultiplier和WriteTotalTimeoutConstant成员为0代表总写入
 /////////////////////////////////////////////////////////////////////////////
 串口读取事件分为两个阶段(我以Win32 API函数ReadFile读取串口过程来说明一下)
 第一个阶段是:串口执行到ReadFile()函数时,串口还没有开始传输数据,所以串口缓冲区的第一个字节是没有装数据的,这时候总超时起作用,如果在总超时时间内没有进行串口数据的传输,ReadFile()函数就返回,当然 没有读取到任何数据。而且,间隔超时并没有起作用。
-第二阶段:假设总超时为20秒,程序运行到ReadFile(),总超时开始从0 计时,如果在计时到达10秒时,串口开始了数据的传输,那么从接收的第一个字节开始,间隔超时就开始计时,假如间隔超时为1ms,那么在读取完第一个字节后,串口开始等待1ms,如果1ms之内接收到了第二个字节,就读取第二个字节,间隔超时重置为0并计时,等待第三个字节的到来,如果第三个字节到来的时间超过了1ms,那么ReadFile()函数立即返回,这时候总超时计时是没到20秒的。如果在20秒总计时时间结束之前,所有的数据都遵守数据间隔为1ms的约定并陆陆续续的到达串口缓冲区,那么就成功进行了一次串口传输和读取;如果20秒总计时时间到,串口还陆陆续续的有数据到达,即使遵守字节间隔为1ms的约定,ReadFile()函数也会立即返回,这时候总超时就起作用了。
+第二阶段:假设总超时为20秒,程序运行到ReadFile(),总超时开始从0 计时,如果在计时到达10秒时,串口开始了数据的传输,
+那么从接收的第一个字节开始,间隔超时就开始计时,假如间隔超时为1ms,那么在读取完第一个字节后,串口开始等待1ms,
+如果1ms之内接收到了第二个字节,就读取第二个字节,间隔超时重置为0并计时,等待第三个字节的到来,
+如果第三个字节到来的时间超过了1ms,那么ReadFile()函数立即返回,这时候总超时计时是没到20秒的。
+如果在20秒总计时时间结束之前,所有的数据都遵守数据间隔为1ms的约定并陆陆续续的到达串口缓冲区,那么就成功进行了一次串口传输和读取;
+如果20秒总计时时间到,串口还陆陆续续的有数据到达,即使遵守字节间隔为1ms的约定,ReadFile()函数也会立即返回,这时候总超时就起作用了。
 总结起来,总超时在两种情况下起作用
 第一:串口没进行数据传输,等待总超时时间那么长ReadFile()才返回。非正常数据传输
 第二:数据太长,总超时设置太短,数据还没读取完就返回了。读取的数据是不全的

+ 226 - 1
TCLCommand/TCLCommand/Serial.cpp

@@ -434,4 +434,229 @@ bool CBaseSerial::SetupPort()
         return false;
 
     return true;
-}
+}
+
+namespace CFG
+{
+	bool CSerial::Open(int nPort, DWORD dwBaudRate /* = 9600 */, int nParity /* = NOPARITY */, BYTE DataBits /* = 8 */, int nStopBits /* = ONESTOPBIT */, int nFC /* = NoFlowControl */ )
+	{
+		Close();
+		_stprintf_s(_szPort, _T("\\\\.\\COM%d"), nPort);
+
+		// 以独占方式打开串口;
+		_hPort = CreateFile(_szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, NULL /*FILE_ATTRIBUTE_NORMAL*/, NULL);
+		if( _hPort == INVALID_HANDLE_VALUE) 
+			return false;
+
+		// SetupComm设置缓冲区大小;
+		bool bResult = SetupComm(_hPort, 1024, 1024);
+		ASSERT(bResult);
+		if( !bResult )
+			return false;
+
+		// 在串口读写之前,清除缓冲区;
+		bResult = PurgeComm(_hPort, PURGE_TXCLEAR|PURGE_RXCLEAR);
+		ASSERT(bResult);
+		if(!bResult)
+			return false;
+
+		DCB dcb;
+		COMMTIMEOUTS timeout;
+		//////////////////////////////////////////////////////////////////////////
+		// GetCommState获取设备控制块状态;
+		bResult = GetCommState(_hPort, &_DCB);
+		ASSERT(bResult);
+		if(!bResult)
+			return FALSE;
+
+		_DCB.Parity = nParity;
+		if(_DCB.Parity == NOPARITY)
+			_DCB.fParity = FALSE;
+		else
+			_DCB.fParity = TRUE;
+
+		_DCB.BaudRate = dwBaudRate;
+		_DCB.ByteSize = DataBits;
+		_DCB.StopBits = nStopBits;
+		if(_DCB.ByteSize == 8)
+			_DCB.StopBits = ONESTOPBIT;
+
+		//Setup the flow control
+		_DCB.fDsrSensitivity = FALSE;
+		switch (nFC)
+		{
+		case NoFlowControl:
+			{
+				_DCB.fOutxCtsFlow = FALSE;
+				_DCB.fOutxDsrFlow = FALSE;
+				_DCB.fOutX = FALSE;
+				_DCB.fInX = FALSE;
+				break;
+			}
+		case CtsRtsFlowControl:
+			{
+				_DCB.fOutxCtsFlow = TRUE;
+				_DCB.fOutxDsrFlow = FALSE;
+				_DCB.fRtsControl = RTS_CONTROL_HANDSHAKE;
+				_DCB.fOutX = FALSE;
+				_DCB.fInX = FALSE;
+				break;
+			}
+		case CtsDtrFlowControl:
+			{
+				_DCB.fOutxCtsFlow = TRUE;
+				_DCB.fOutxDsrFlow = FALSE;
+				_DCB.fDtrControl = DTR_CONTROL_HANDSHAKE;
+				_DCB.fOutX = FALSE;
+				_DCB.fInX = FALSE;
+				break;
+			}
+		case DsrRtsFlowControl:
+			{
+				_DCB.fOutxCtsFlow = FALSE;
+				_DCB.fOutxDsrFlow = TRUE;
+				_DCB.fRtsControl = RTS_CONTROL_HANDSHAKE;
+				_DCB.fOutX = FALSE;
+				_DCB.fInX = FALSE;
+				break;
+			}
+		case DsrDtrFlowControl:
+			{
+				_DCB.fOutxCtsFlow = FALSE;
+				_DCB.fOutxDsrFlow = TRUE;
+				_DCB.fDtrControl = DTR_CONTROL_HANDSHAKE;
+				_DCB.fOutX = FALSE;
+				_DCB.fInX = FALSE;
+				break;
+			}
+		case XonXoffFlowControl:
+			{
+				_DCB.fOutxCtsFlow = FALSE;
+				_DCB.fOutxDsrFlow = FALSE;
+				_DCB.fOutX = TRUE;
+				_DCB.fInX = TRUE;
+				_DCB.XonChar = 0x11;
+				_DCB.XoffChar = 0x13;
+				_DCB.XoffLim = 100;
+				_DCB.XonLim = 100;
+				break;
+			}
+		default:
+			{
+				ATLASSERT(FALSE);
+				break;
+			}
+		}
+
+		// SetCommState设置设备的控制块状态;
+		bResult = SetCommState(_hPort, &_DCB);
+		ASSERT(bResult);
+		if(!bResult)
+			return false;
+
+		//////////////////////////////////////////////////////////////////////////
+		// 获取设备的超时值;
+		bResult = GetCommTimeouts(_hPort, &_TIMEOUT);
+		ASSERT(bResult);
+		if(!bResult)
+			return false;
+
+		_TIMEOUT.ReadIntervalTimeout = 1;
+		// 设置0,否则读取超时=ReadTotalTimeoutMultiplier*读取的长度+ReadTotalTimeoutConstant;
+		_TIMEOUT.ReadTotalTimeoutMultiplier = 0;
+		_TIMEOUT.ReadTotalTimeoutConstant = 3000;
+		// 写可设置此值,写超时=WriteTotalTimeoutMultiplier*写入长度+WriteTotalTimeoutConstant;
+		_TIMEOUT.WriteTotalTimeoutMultiplier = 5;
+		_TIMEOUT.WriteTotalTimeoutConstant = 1500;
+
+		// 设置设备的超时值;
+		bResult = SetCommTimeouts(_hPort, &_TIMEOUT);
+		ASSERT(bResult);
+		if(!bResult)
+			return false;
+	}
+
+	void CSerial::Close()
+	{
+		if ( IsOpen() ) {
+			CloseHandle(_hPort);
+			_hPort = NULL;
+		}
+	}
+
+	bool CSerial::Write(LPCVOID lpBuffer, DWORD dwNumberOfBytesToWrite)
+	{
+		if (!IsOpen())
+			return false;
+
+		DWORD dwError;
+		if (::ClearCommError(_hPort, &dwError, NULL) && dwError > 0)
+			::PurgeComm(_hPort, PURGE_TXABORT | PURGE_TXCLEAR);    // 清空输出缓冲区(PURGE_TXCLEAR)
+
+		DWORD dwNumberOfBytesWritten = 0;
+		if ( !::WriteFile(_hPort, lpBuffer, dwNumberOfBytesToWrite, &dwNumberOfBytesWritten, NULL) )
+		{
+			DWORD dwError = GetLastError();
+		}
+
+		return dwNumberOfBytesWritten == dwNumberOfBytesToWrite;
+	}
+
+	bool CSerial::Read(LPVOID lpBuffer, DWORD dwNumberOfBytesToRead)
+	{
+		if (!IsOpen())
+			return false;
+
+		COMSTAT Stat;
+		DWORD dwError;
+
+		if ( ::ClearCommError(_hPort, &dwError, &Stat) && dwError > 0 ) {
+			::PurgeComm(_hPort, PURGE_RXABORT | PURGE_RXCLEAR);    // 清空输入缓冲区(PURGE_RXCLEAR)
+		}
+
+		DWORD dwNumberOfBytesRead = 0;
+		if ( !::ReadFile(_hPort, lpBuffer, dwNumberOfBytesToRead, &dwNumberOfBytesRead, NULL) )
+		{
+			DWORD dwError = GetLastError();
+			return false;
+		}
+
+		return dwNumberOfBytesRead > 0;
+	}
+
+	bool CSerial::SetWriteTimeout(DWORD dwWriteTotalTimeoutMultiplier /* = 5 */, DWORD dwWriteTotalTimeoutConstant /* = 1500 */)
+	{
+		_TIMEOUT.WriteTotalTimeoutConstant = dwWriteTotalTimeoutConstant;
+		_TIMEOUT.WriteTotalTimeoutMultiplier = dwWriteTotalTimeoutMultiplier;
+		return IsOpen() ? ::SetCommTimeouts(_hPort, &_TIMEOUT) == TRUE : false;
+	}
+
+	bool CSerial::SetReadTimeout(DWORD dwReadIntervalTimeout /* = 5 */, DWORD dwReadTotalTimeoutMultiplier /* = 0 */, DWORD dwReadTotalTimeoutConstant /* = 3000 */)
+	{
+		_TIMEOUT.ReadIntervalTimeout = dwReadIntervalTimeout;
+		_TIMEOUT.ReadTotalTimeoutMultiplier = dwReadTotalTimeoutMultiplier;
+		_TIMEOUT.ReadTotalTimeoutConstant = dwReadTotalTimeoutConstant;
+		return IsOpen() ? ::SetCommTimeouts(_hPort, &_TIMEOUT) == TRUE : false;
+	}
+
+	bool CSerial::SetBufferSize(DWORD dwInputSize, DWORD dwOutputSize)
+	{
+		// SetupComm设置输入输出缓冲区大小;
+		return IsOpen() ? ::SetupComm(_hPort, dwInputSize, dwOutputSize) == TRUE : false;
+	}
+
+	bool CSerial::SetDTR(BOOL bEnable/* =TRUE */)
+	{
+		return IsOpen() ? EscapeCommFunction(_hPort, bEnable ? SETDTR : CLRDTR) : false;
+	}
+
+	bool CSerial::SetRTS(BOOL bEnable/* =TRUE */)
+	{
+		return IsOpen() ? EscapeCommFunction(_hPort, bEnable ? SETDTR : CLRDTR) : false;
+	}
+	
+	bool CSerial::SetX(BOOL bON/* =TRUE */)
+	{
+		return IsOpen() ? EscapeCommFunction(_hPort, bON ? SETXON : SETXOFF) : false;
+	}
+};

+ 41 - 0
TCLCommand/TCLCommand/Serial.h

@@ -150,3 +150,44 @@ private:
     CBaseSerial &operator=(const CBaseSerial &);
 };
 
+
+namespace CFG
+{
+	enum FlowControl
+	{
+		NoFlowControl,
+		CtsRtsFlowControl,
+		CtsDtrFlowControl,
+		DsrRtsFlowControl,
+		DsrDtrFlowControl,
+		XonXoffFlowControl
+	};
+
+	class CSerial
+	{
+	public:
+		bool IsOpen() {return (_hPort == NULL || _hPort == INVALID_HANDLE_VALUE) ? FALSE : TRUE;};
+		bool Open(int nPort, DWORD dwBaudRate = 9600, int nParity = NOPARITY, BYTE DataBits = 8, int nStopBits = ONESTOPBIT, int nFC = NoFlowControl);
+		void Close();
+		bool Write(LPCVOID lpBuffer, DWORD dwNumberOfBytesToWrite);
+		bool Read(LPVOID lpBuffer, DWORD dwNumberOfBytesToRead);
+		// 设置超时
+		bool SetWriteTimeout(DWORD dwWriteTotalTimeoutMultiplier = 5, DWORD dwWriteTotalTimeoutConstant = 1500);
+		bool SetReadTimeout(DWORD dwReadIntervalTimeout = 5, DWORD dwReadTotalTimeoutMultiplier = 0, DWORD dwReadTotalTimeoutConstant = 3000);		
+		// 设置串口的I/O缓冲区大小
+		bool SetBufferSize(DWORD dwInputSize = 4096, DWORD dwOutputSize = 4096);
+		DWORD ClearBreak() {return IsOpen() ? ClearCommBreak(_hPort) == TRUE : false;};
+		bool SetBreak() {return IsOpen() ? SetCommBreak(_hPort) == TRUE : false;};
+		bool ClearError() {DWORD dwErrors = - 1; if (IsOpen()) ClearCommError(_hPort, &dwErrors, NULL); return dwErrors;}
+		bool SetDTR(BOOL bEnable=TRUE);
+		bool SetRTS(BOOL bEnable=TRUE);
+		bool SetX(BOOL bON=TRUE);
+	protected:
+		DCB				_DCB;
+		COMMTIMEOUTS	_TIMEOUT;
+		HANDLE			_hPort;			    // 句柄;
+		TCHAR			_szPort[13];		// \\\\.\\COM%d
+	private:
+	};
+
+};

+ 16 - 1
TCLCommand/TCLCommand/TCLCommand.cpp

@@ -47,10 +47,11 @@ int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
 	else
 	{
 		// TODO: 在此处为应用程序的行为编写代码。
-        if ( Open(5, 9600, 8, 0, 1) )
+        if ( Open(7, 115200, 8, 0, 1) )
         {
             EnterFactory();
            
+            CheckFireTVPlayready();
             int pid;
             GetProjectId(pid);
 
@@ -613,6 +614,20 @@ bool SetProjectId(LPCTSTR lpPid)
     OPEN_CHECK;
     return false;
 }
+
+bool CheckFireTVPlayready()
+{
+	OPEN_CHECK;
+	GET_CMDS(__FUNCTION__);
+	if (g_TCLCommand.SendCommand(cmdpara))
+	{
+		cmdpara._rtnData;
+		return true;
+	}
+
+	return false;
+}
+
 #endif
 
 #ifdef __MAKE_PYD__

+ 1 - 1
TCLCommand/TCLCommand/TCLCommand.h

@@ -124,5 +124,5 @@ TCLCOMMAND_API bool SetBlueGainRegister(int value);
 TCLCOMMAND_API bool SetRedOffsetRegister(int value);
 TCLCOMMAND_API bool SetGreenOffsetRegister(int value);
 TCLCOMMAND_API bool SetBlueOffsetRegister(int value);
-
+TCLCOMMAND_API bool CheckFireTVPlayready();
 #endif