⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 devserver.cpp

📁 国家环保总局污染源在线通讯协议的简化版
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	}
	return strProtocol;
	
}

///	函数功能:	对一个Byte数组中的数值置位。
///	函数返回:	成功返回TRUE。
///	参数意义:	byte			要操作的数组。
///				dData			预置值。
///				nBit			位序号。
///	备	  注:	此函数用于提供通用服务,建议不修改。
///	
BOOL CDevServer::SvrSetByteBit(CByteArray& byte, double dData, int nBit)
{	
	if (byte.GetSize()*8 <= nBit)
	{
		ASSERT(FALSE);
		return FALSE;
	}
	int nData = int(dData);
	if (nData != 0) nData = 1;
	BYTE bytTemp = byte[nBit/8];
	bytTemp = (bytTemp & (0xff - (0x01<<(nBit%8))))|(nData<<(nBit%8));
	byte[nBit/8] = bytTemp;
	return TRUE;
}

/// 函数功能:	获取写命令的数值
/// 函数返回:	正确TRUE,错误FALSE。
/// 参数意义:	strPara			用户设备命令中的参数值(字符型)
///				fParaVal		从命令中取回的数值(字符型)
///	备	  注:	如果是变量,则从数据中心取出变量的数据;
///				如果是数值,则直接返回其数值
BOOL CDevServer::SvrGetParaValue(CString &strPara, float &fParaVal)
{
	fParaVal = 0;
	long nType = 0;
	CString strVal(_T(""));
	
	nType = g_datacentre.GetDataType(strPara);
	
	switch (nType)
	{	
	case VINTEGER:
		{
			long lParaVal = 0;
			g_datacentre.GetValueFromName(strPara, lParaVal);
			fParaVal = (float)lParaVal;
		}
		break;
	case VSINGLE:
		{
			g_datacentre.GetValueFromName(strPara, fParaVal);
		}
		break;
	case VSTRING:
		{
			ASSERT(FALSE);
			return FALSE;
		}
		break;
	default :
		{
			strVal = strPara.SpanIncluding(_T("1234567890."));
			strVal.TrimLeft ();
			strVal.TrimRight ();			
			if (strVal == _T(""))
			{
				fParaVal = 0;
			}
			else
			{
				_stscanf(strVal, _T("%f"), &fParaVal);
			}			
		}
	}
	
	return TRUE;
}

/// 函数功能:	获取写命令的数值
/// 函数返回:	正确TRUE,错误FALSE。
/// 参数意义:	strPara			用户设备命令中的参数值(字符型)
///				strParaVal		从命令中取回的数值(字符型)
///	备	  注:	如果是变量,则从数据中心取出变量的数据;
///				如果是数值,则直接返回其数值
BOOL CDevServer::SvrGetParaValue(CString &strPara, CString &strParaVal)
{
	strParaVal = _T("");
	long nType = 0;
	
	nType = g_datacentre.GetDataType(strPara);
	
	switch (nType)
	{	
	case VINTEGER:
		{
			ASSERT(FALSE);
			return FALSE;
		}
		break;
	case VSINGLE:
		{
			ASSERT(FALSE);
			return FALSE;
		}
		break;
	case VSTRING:
		{
			g_datacentre.GetValueFromName(strPara, strParaVal);
		}
		break;
	default :
		{
			strParaVal = strPara;
		}
	}
	
	return TRUE;
}

/// 函数功能:	设置数据中心数据变量的数值
/// 函数返回:	正确TRUE,错误FALSE。
/// 参数意义:	strPara			用户设备命令中的参数值(字符型)
///				fParaVal		从命令中取回的数值(字符型)
///	备	  注:	如果是变量,则从数据中心取出变量的数据;
///				如果是数值,则直接返回其数值
BOOL CDevServer::SvrSetParaValue(CString &strPara, float &fParaVal)
{	
	long nType = 0;	
	
	nType = g_datacentre.GetDataType(strPara);
	
	switch (nType)
	{	
	case VINTEGER:
		{
			long lParaVal = long(fParaVal);
			g_datacentre.SetValueFromName(strPara, lParaVal);			
		}
		break;
	case VSINGLE:
		{
			g_datacentre.SetValueFromName(strPara, fParaVal);
		}
		break;
	case VSTRING:
		{
			ASSERT(FALSE);
			return FALSE;
		}
		break;
	default :
		{
			ASSERT(FALSE);
			return FALSE;			
		}
	}
	
	return TRUE;
}

/// 函数功能:	设置数据中心数据变量的数值
/// 函数返回:	正确TRUE,错误FALSE。
/// 参数意义:	strPara			用户设备命令中的参数值(字符型)
///				strParaVal		从命令中取回的数值(字符型)
///	备	  注:	如果是变量,则从数据中心取出变量的数据;
///				如果是数值,则直接返回其数值
BOOL CDevServer::SvrSetParaValue(CString &strPara, CString &strParaVal)
{	
	long nType = 0;
	
	nType = g_datacentre.GetDataType(strPara);
	
	switch (nType)
	{	
	case VINTEGER:
		{
			ASSERT(FALSE);
			return FALSE;
		}
		break;
	case VSINGLE:
		{
			ASSERT(FALSE);
			return FALSE;
		}
		break;
	case VSTRING:
		{
			g_datacentre.SetValueFromName(strPara, strParaVal);
		}
		break;
	default :
		{
			ASSERT(FALSE);
			return FALSE;
		}
	}
	
	return TRUE;
}

///	函数功能:	解析命令字符串,把字符串按分割符分解成两部分。
///	函数返回:	成功返回TRUE,失败返回FALSE。
///	参数意义:	strCmd			已去掉命令,只剩下数据和通道信息的命令字符串。
///				strDivision		命令字符串的分割字符。
///				strChannel		用来保存分割字符左边的字符串。
///				strData			用来保存分割字符右边的字符串。
///	备	  注:	此函数用于提供通用服务,建议不修改。
///	
BOOL CDevServer::SvrGetCmdStr(CString& strCmd,
							  CString& strDivision,
							  CString& strLeft,
							  CString& strRight)
{
	int nPos = strCmd.Find(strDivision);
	if (nPos < 0)
	{
		return FALSE;
	}
	strLeft = strCmd.Left(nPos);
	strRight = strCmd.Right(strCmd.GetLength() - nPos - 1);	
	strLeft.TrimLeft();
	strLeft.TrimRight();
	strRight.TrimLeft();
	strRight.TrimRight();
	return TRUE;
}

///	函数功能:	写串口函数,往串口写一个字符串,用重叠操作的方式。
///	函数返回:	成功返回TRUE,失败返回FALSE。
///	参数意义:	data			MCGS传过来的MCGS_DATA结构的指针
///				nstrType		发送字符串协议类型,0:字符串协议。1:16进制协议。
///				str				用来保存写到串口的数据。
///	备	  注:	此函数用于提供通用服务,建议不修改。
///	
BOOL CDevServer::SvrWriteComm(MCGS_DATA& data,
							  int nStrType,
							  CString& strProtocol)
{	
	CByteArray	bytArProtocol;	
	
	switch (nStrType)
	{
	case DEV_PROTOCOL_ASII:
		{
			CDevServer::SvrStr2Byte(strProtocol, bytArProtocol);			
		}break;
	case DEV_PROTOCOL_HEX:
		{			
			CDevServer::SvrHStr2HByte(strProtocol, bytArProtocol);			
		}break;
	default :
		{
			ASSERT(FALSE);
			return FALSE;
		}break;
	}
	
	TRACE(_T("\n串口输出:") + strProtocol + _T("\n"));
	
	CDevServer c;
	return c.SvrWriteComm(data, bytArProtocol);
}

///	函数功能:	读串口函数,从串口读一个字符串,用重叠操作的方式。
///	函数返回:	成功返回读取的字节数,失败返回<=0。
///	参数意义:	data			MCGS传过来的MCGS_DATA结构的指针
///				nstrType		发送字符串协议类型,0:字符串协议。1:16进制协议。
///				str				数组用来保存从串口读回来的数据。
///				dwDelayTime		用来保存超时值。
///				nInputFlag		读串口的结束方式
///								0:收到ucStopChar所指定的字符马上结束。
///								1:收到dwInputLen个字符后马上结束。
///								2:Sleep(dwDelayTime)后接收串口所有数据,结束。
///								3:满足0或1中的条件马上结束。如果操作的时间
///								   超过了dwDelayTime所指定的时间则无条件退出。
///				dwInputLen		要接收的长度。
///				ucStopChar		停止字符。
///	备	  注:	此函数用于提供通用服务,建议不修改。
///	
int CDevServer::SvrReadComm(MCGS_DATA& data,
							int nStrType,
							CString& strProtocol,
							DWORD dwDelayTime,
							int nInputFlag,
							DWORD dwInputLen,
							unsigned char ucStopChar)
{
	CDevServer c;
	CByteArray	bytArProtocol;
	
	int nLen = c.SvrReadComm(data, bytArProtocol, dwDelayTime,
		nInputFlag, dwInputLen, ucStopChar);
	
	switch (nStrType)
	{
	case DEV_PROTOCOL_ASII:
		{
			SvrByte2Str(bytArProtocol, strProtocol);
		}break;
	case DEV_PROTOCOL_HEX:
		{			
			SvrHByte2HStr(bytArProtocol, strProtocol);
		}break;
	default :
		{
			ASSERT(FALSE);
			return -1;
		}break;
	}
	
	TRACE(_T("\n串口输入:") + strProtocol + _T("\n"));
	
	return nLen;
}

///	函数功能:	操作串口函数,发送命令并接收设备回应。
///	函数返回:	成功返回读取的字节数,失败返回<=0。
///	参数意义:	data			MCGS传过来的MCGS_DATA结构的指针
///				nstrType		发送字符串协议类型,0:字符串协议。1:16进制协议。
///				byteArray		数组用来保存从串口读回来的数据。
///				dwDelayTime		用来保存超时值。
///				nInputFlag		读串口的结束方式
///								0:收到ucStopChar所指定的字符马上结束。
///								1:收到dwInputLen个字符后马上结束。
///								2:Sleep(dwDelayTime)后接收串口所有数据,结束。
///								3:满足0或1中的条件马上结束。如果操作的时间
///								   超过了dwDelayTime所指定的时间则无条件退出。
///				dwInputLen		要接收的长度。
///				ucStopChar		停止字符。
///	备	  注:	此函数用于提供通用服务,建议不修改。
///	
int CDevServer::SvrWriteAndReadComm(MCGS_DATA& data,
									int nStrType,
									CString& strProtocol,
									DWORD dwDelayTime, 
									int nInputFlag,
									DWORD dwInputLen,
									unsigned char ucStopChar)
{
	///	清空串口输入缓冲区
	SvrClearCommInBuff(data);
	
	///	发送命令
	SvrWriteComm(data, nStrType, strProtocol);
	
	///	读取返回的数据
	return SvrReadComm(data, nStrType, strProtocol,
		dwDelayTime, nInputFlag, dwInputLen, ucStopChar);
}



int CDevServer::SvrReadTcpip(MCGS_DATA &data, CByteArray& byteArray)
{
	if (!mfIsTcpipDev(data)) return 0;
	HANDLE hHandle = (HANDLE)data.m_pParentData;
	if (hHandle == NULL || hHandle == INVALID_HANDLE_VALUE)
	{
		ASSERT(FALSE);
		return -1;
	}
	
	DWORD dwSize = 0;
	CAsyncSocket *pSocket = (CAsyncSocket *)data.m_pParentData;
	
	long lngRt = pSocket->IOCtl(FIONREAD, &dwSize);
	if(dwSize == 0)
		return 0;
	if(lngRt == -1 )
		///&& pSocket->GetLastError() == SOCKET_ERROR)
	{
		ASSERT(FALSE);
		return -1;
	}
	byteArray.SetSize(dwSize);
	
	lngRt = pSocket->Receive(byteArray.GetData(), byteArray.GetSize());
	if(lngRt == -1)
		///&& pSocket->GetLastError() == SOCKET_ERROR)
	{
		ASSERT(FALSE);
		return -1;
	}
	return byteArray.GetSize();	
}

int CDevServer::SvrWriteTcpip(MCGS_DATA &data, CByteArray& byteArray)
{
	int iReturn, iError=0;
	BOOL bSuccess = FALSE; // 是否发送成功. 假设失败

	if (!mfIsTcpipDev(data)) return 0;
	
	HANDLE hHandle = (HANDLE)data.m_pParentData;
	if (hHandle == NULL || hHandle == INVALID_HANDLE_VALUE)
	{
		ASSERT(FALSE);
		return -1;
	}

	CAsyncSocket* pSocket = (CAsyncSocket*)data.m_pParentData;
	// 发送缓冲区大小, SO_SNDBUF. WinCE:16K, XP:8192
//	int iSendBuffer, iIntSize = 4;
//	pSocket->GetSockOpt(SO_SNDBUF, &iSendBuffer, &iIntSize, SOL_SOCKET);
//	if(iSendBuffer != 50)
//	{
//		iSendBuffer = 50;
//		iReturn = pSocket->SetSockOpt(SO_SNDBUF, &iSendBuffer, sizeof(int), SOL_SOCKET);
//	}
	
#ifdef MCGSSET_ESET
 // 模拟运行环境. 上位机运行环境的Socket是异步的,判断错误复杂
	WSAEVENT hEventObject = WSACreateEvent(); // 事件对象
	iReturn = WSAEventSelect(pSocket->m_hSocket, hEventObject, FD_WRITE); // 关联事件对象与网络事件FD_WRITE
#endif

	iReturn = pSocket->Send(byteArray.GetData(), byteArray.GetSize());
//	if(lngRt == -1 && pSocket->GetLastError() == SOCKET_ERROR)
//	{
//		ASSERT(FALSE);
//		return -1;
//	}

#ifdef MCGSSET_ESET
  // 模拟运行环境. 上位机运行环境的Socket是异步的,要等待发送完成之后再判断发送错误
	if(iReturn == -1)
	{// 发送失败
		iError = ::WSAGetLastError();
		if(iError == WSAEWOULDBLOCK)
		{// 异步发送未完成,等待完成
			while(1)
			{
				DWORD dwReturn = WSAWaitForMultipleEvents(1, &hEventObject, FALSE, 300, FALSE);
				if(dwReturn == WSA_WAIT_EVENT_0)
				{// 连接完成
					WSANETWORKEVENTS NetworkEvents;
					WSAEnumNetworkEvents(pSocket->m_hSocket, hEventObject, &NetworkEvents);
					if(NetworkEvents.lNetworkEvents & FD_WRITE)
					{
						int iErrorCode = NetworkEvents.iErrorCode[FD_WRITE_BIT];
						if(iErrorCode == ERROR_SUCCESS)
						{// 发送成功
							bSuccess = TRUE;
						}
						else
						{// 发送错误
							;
						}
						WSASetLastError(iErrorCode); // 设置错误码,便于以后获取
						iError = iErrorCode ;
					}
					break;
				}
				else if(dwReturn == WSA_WAIT_TIMEOUT)
				{// 等待300ms超时,继续等待吧
					;
				}
				else
				{// 错误!WSAWaitForMultipleEvents()不应该返回错误码
					iError = WSAGetLastError();
					ASSERT(FALSE);
					break;
				}
			}
		}
		else
		{// 真正发送失败
			;
		}
	}
	else
	{// 发送成功
		bSuccess = TRUE;
	}

	WSAEventSelect(pSocket->m_hSocket, 0, 0);  // 解除关联
	WSACloseEvent(hEventObject); // 关闭事件

#else  // 下位机运行环境. 下位机的Socket是同步的,判断错误很简单

	iError = ::WSAGetLastError();
	if(iReturn == -1)
	{// 发送失败
		ASSERT(::WSAGetLastError() != WSAEWOULDBLOCK); // 同步的Socket不可能返回这个错误码
	}
	else
	{// 发送成功
		bSuccess = TRUE;
	}

#endif

	{
		// 写日志
		if(((DEV_DATA*)data.m_pDevData)->bLog){
			// 发送状态
			CString strSend;
			strSend.Format(_T("bSuccess=%d, iReturn = %d, iError=%d,"), bSuccess, iReturn, iError);
			CDevBas::mfWriteLog(data, ((DEV_DATA*)data.m_pDevData)->dwLogN, _T("发送状态:"),
				strSend, DEV_PROTOCOL_ASII);
			((DEV_DATA*)data.m_pDevData)->dwLogN ++;

		}
	}

	return bSuccess ? byteArray.GetSize() : -1 ;	
}






⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -