// ProtocolPMC916.cpp: implementation of the CProtocolModbus class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "ProtocolModbus.h" #include "winsock2.h" #include "stulz.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CProtocolModbus::CProtocolModbus() : CProtocol() { InitializeCriticalSection( &m_csReadFinished ); InitializeCriticalSection( &m_csWrFinished ); MTVERIFY( m_hSemComm = CreateEvent( NULL, TRUE, TRUE, 0 ) ); } CProtocolModbus::~CProtocolModbus() { DeleteCriticalSection( &m_csReadFinished ); DeleteCriticalSection( &m_csWrFinished ); MTVERIFY( CloseHandle( m_hSemComm ) ); } int CProtocolModbus::WorkMain(SETBASEPARAM SetBasePara, int nDataLen, int iCmdPos, int iCmdLen, char chMsg[10]) { if(!m_pComm) return ERR_CODE_AIR_STULZ_COM_FAULT; // 串口通信故障 int nRet; nRet = RequestStatus(SetBasePara); if( nRet != 0 ) { return nRet; // 串口忙 } nRet = ResponseStatus( nDataLen, iCmdPos, iCmdLen, chMsg); return nRet; } int CProtocolModbus:: WriteCommand(char DataBuffer[80], char ResDataBuffer[2]) { int iResult = 0; if(!m_pComm) return ERR_CODE_AIR_STULZ_COM_FAULT; iResult = RequestWrStatus(DataBuffer); if (iResult == 0) return ResponseWrStatus(ResDataBuffer); else return iResult; } //nDataLen 数据的总长度,iCmdPos 命令位置,iCmdLen 变量数据长度,chMsg 变量数据 int CProtocolModbus::ResponseStatus(int nDataLen, int iCmdPos, int iCmdLen, char chMsg[10]) { RESPONSE_STRUCT structResponse; memset( &structResponse, 0, sizeof(RESPONSE_STRUCT) ); if (nDataLen <= 0) { TRACE("变量长度小于等于0,为非法变量"); return ERR_CODE_AIR_STULZ_COM_VARLEN; } int nLen = sizeof(RESPONSE_STRUCT) - sizeof(structResponse.StrRtnMsg) + nDataLen; char *pBuffer = new char[ nLen ]; memset(pBuffer, 0, nLen); int nProcessLen = 0; int nReadLen = 0; nReadLen = ReadMessage((BYTE *)pBuffer, nLen); if( nReadLen <= 0) { // 串口没有读到数据 TRACE("串口没有读到数据!\r\n"); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_AIR_STULZ_COM_READ_NO_DATA; } else if( nReadLen < nLen ) { TRACE("长度没有收够,断续接收,止到收完为止!\r\n"); #if DEBUG_PROTOCOL SetEvent( m_hSemComm ); if( pBuffer ) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_AIR_STULZ_COM_FAULT; #else nProcessLen += nReadLen; nReadLen = ReadMessage( (BYTE *)(pBuffer + nProcessLen), nLen - nProcessLen ); while( nReadLen != nLen - nProcessLen ) { if( nReadLen == 0 ) { SetEvent( m_hSemComm ); if( pBuffer ) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_AIR_STULZ_COM_READ_NO_DATA; // 还是没有收到数据,直接返回 } nProcessLen += nReadLen; nReadLen = ReadMessage( (BYTE *)(pBuffer + nProcessLen), nLen - nProcessLen); } if( nReadLen == nLen ) { //goto NormalProcess; if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_AIR_STULZ_COM_FAULT; } #endif } else if( nReadLen > nLen ) { // 完全代码,不一定能执行到 TRACE("接收的长度超时所需的长度,认为是非法包,扔掉\r\n"); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_AIR_STULZ_COM_READ_LEN_OVER; } else if( nReadLen == nLen ) // 长度刚好 { unsigned char chRegNum = pBuffer[2]; // 判断数据长度 if (chRegNum == (unsigned char)nDataLen) goto NormalProcess; if( chRegNum > (unsigned char)nDataLen) { TRACE("请求寄存器个数超时所需的长度,认为是非法包,收完扔掉\r\n"); #if DEBUG_PROTOCOL SetEvent( m_hSemComm ); if( pBuffer ) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_AIR_STULZ_COM_READ_LEN_OVER; #else nProcessLen += nReadLen; nReadLen = ReadMessage( (BYTE *)(pBuffer + nProcessLen), chRegNum - nDataLen); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_AIR_STULZ_COM_READ_LEN_OVER; #endif } else//小于 { TRACE("读到数据长度小于需要的数据长度!\r\n"); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_AIR_STULZ_COM_READ_LEN_OVER; } } NormalProcess: // 判断校验 int iCrc = GetCheckSum((byte*) pBuffer, nLen - 2); BYTE high = iCrc>>8&0xff; BYTE low = iCrc&0xff; if( !( ((byte)pBuffer[nLen - 2] == low) && ((byte)pBuffer[nLen - 1] ==high) ) ) { TRACE("crc 校验失败!\r\n"); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_AIR_STULZ_COM_LRC_LOST; } EnterCriticalSection( &m_csWrFinished ); memcpy( &m_structResponse.StatusStruct, pBuffer, sizeof(STATUS_STRUCT) ); int nIndex = 0; for( int i = iCmdPos; i < (iCmdPos + iCmdLen); i++ ) { int nTmp = sizeof(STATUS_STRUCT) + i; chMsg[nIndex] = pBuffer[sizeof(STATUS_STRUCT) + i]; nIndex++; } LeaveCriticalSection(&m_csWrFinished); // 设置串口等待事件为有信号 SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return 0; } int CProtocolModbus::RequestStatus(SETBASEPARAM SetBasePara) { REQUESTPARAM RequestPara; int iLen = sizeof(REQUESTPARAM); #if 0 if (SetBasePara.nStartAddr==0) iLen -=sizeof(RequestPara .StartAddr); #endif if (SetBasePara.FuncCode==1 || //长状态请求1 SetBasePara.FuncCode==33 || //长状态请求2 SetBasePara.FuncCode==9 || //控制器状态2 SetBasePara.FuncCode==10 ||//控制器ID SetBasePara.FuncCode==11 ||//单元配置 SetBasePara.FuncCode==12)//c5000增加项 { iLen -= sizeof(RequestPara.StartAddr); } char *pData = new char[iLen]; memset( pData, 0, iLen ); memset( &RequestPara, 0, iLen ); RequestPara.AddrCode = SetBasePara.nAddr; //地址码 RequestPara.FuncCode = SetBasePara.FuncCode; //功能码 RequestPara.StartAddr = SetBasePara.nStartAddr; //起始地址 int iTmpLen = sizeof(RequestPara.AddrCode) + sizeof(RequestPara.FuncCode);// + sizeof(RequestPara.Number); memcpy(pData, &RequestPara, iTmpLen); if (SetBasePara.FuncCode==1 || //长状态请求1 SetBasePara.FuncCode==33 || //长状态请求2 SetBasePara.FuncCode==9 || //控制器状态2 SetBasePara.FuncCode==10 ||//控制器ID SetBasePara.FuncCode==11 ||//单元配置 SetBasePara.FuncCode==12)//c5000增加项 { RequestPara.Number = 2; //下面字节数 memcpy( pData + iTmpLen, &RequestPara.Number, sizeof(RequestPara.Number) ); iTmpLen += sizeof(RequestPara.Number); } else { memcpy(pData + iTmpLen, &RequestPara.StartAddr, sizeof(RequestPara .StartAddr)); iTmpLen +=sizeof(RequestPara .StartAddr); RequestPara.Number = 3; //下面字节数 memcpy(pData + iTmpLen, &RequestPara.Number, sizeof(RequestPara.Number) ); iTmpLen += sizeof(RequestPara.Number); } SHORT iCheck = GetCheckSum( (BYTE*)pData, iTmpLen); BYTE high = iCheck>>8&0xff; BYTE low = iCheck&0xff; #if 1 RequestPara.Crc[0] = low; RequestPara.Crc[1] = high; #else RequestPara.Crc[0] = high; RequestPara.Crc[1] = low; #endif memcpy(pData + iTmpLen, RequestPara.Crc, sizeof(RequestPara.Crc)); if( WaitForSingleObject( m_hSemComm, 0 ) == WAIT_OBJECT_0 ) // 有信号才写串口 { ResetEvent( m_hSemComm ); int nResult = WriteMessage( (BYTE *)pData, iLen ); if( nResult == iLen ) { } else { delete []pData; SetEvent( m_hSemComm ); return EER_CODE_AIR_STULZ_COM_WRITE_DATA; } } else { delete []pData; return ERR_CODE_AIR_STULZ_COM_BUSY; } delete[]pData; return 0; } int CProtocolModbus::RequestWrStatus(char DataBuffer[80])//请求写数据 { char tmpData[4] = {0}; memcpy(tmpData, DataBuffer, sizeof(tmpData)); int iCheck = GetCheckSum( (BYTE*)tmpData, sizeof(tmpData)); BYTE high = iCheck>>8&0xff; BYTE low = iCheck&0xff; DataBuffer[4] = low; DataBuffer[5] = high; if( WaitForSingleObject( m_hSemComm, 0 ) == WAIT_OBJECT_0 ) // 有信号才写串口 { ResetEvent( m_hSemComm ); int iResult = WriteMessage((unsigned char *)DataBuffer, sizeof(tmpData) + 2); if (iResult == ( sizeof(tmpData) + 2)) return 0; else { SetEvent( m_hSemComm ); return EER_CODE_AIR_STULZ_COM_WRITE_DATA; } } else { return EER_CODE_AIR_STULZ_COM_WRITE_DATA; } } int CProtocolModbus::ResponseWrStatus(char ResDataBuffer[2]) { char chBuffer[6] = {0}; int iProcessLen = 0; int iLen = sizeof(chBuffer); int iReadLen = ReadMessage((BYTE *)chBuffer, iLen); if( iReadLen <= 0) // 串口没有读到数据 { SetEvent( m_hSemComm ); return ERR_CODE_AIR_STULZ_COM_READ_NO_DATA; } else if(iReadLen< iLen) { TRACE("长度没有收够,断续接收,直到收完为止!\r\n"); iProcessLen += iReadLen; iReadLen = ReadMessage( (BYTE *)(chBuffer + iProcessLen), iLen - iProcessLen ); while( iReadLen != iLen - iProcessLen ) { if( iReadLen == 0 ) { SetEvent( m_hSemComm ); return ERR_CODE_AIR_STULZ_COM_READ_NO_DATA;// 还是没有收到数据,直接返回 } iProcessLen += iReadLen; iReadLen = ReadMessage( (BYTE *)(chBuffer + iProcessLen), iLen - iProcessLen); } if( iReadLen == iLen ) { SetEvent( m_hSemComm ); return ERR_CODE_AIR_STULZ_COM_FAULT; } } else if( iReadLen > iLen )//实际读到包长度大于要求包的长度 { // 完全代码,不一定能执行到 TRACE("接收的长度超时所需的长度,认为是非法包,扔掉\r\n"); SetEvent( m_hSemComm ); return ERR_CODE_AIR_STULZ_COM_READ_LEN_OVER; } else if (iReadLen == iLen)//读到的包长度相等 { // 判断寄存器的个数正确吗? if (chBuffer[1] == 7 && chBuffer[2] == 3) { goto NormalProcess; } else { SetEvent( m_hSemComm ); return ERR_CODE_AIR_STULZ_COM_READ_LEN_OVER; } } NormalProcess: char tmpData[4] = {0}; memcpy(tmpData, chBuffer, sizeof(tmpData)); int iCheck = GetCheckSum( (BYTE*)tmpData, sizeof(tmpData)); BYTE high = iCheck>>8&0xff; BYTE low = iCheck&0xff; //DataBuffer[4] = low; //DataBuffer[5] = high; if( !( chBuffer[4] == low && chBuffer[5] == high ) ) { TRACE("应答数据校验失败!\r\n"); SetEvent( m_hSemComm ); return ERR_CODE_AIR_STULZ_COM_LRC_LOST; } ResDataBuffer[0] = chBuffer[3]; // 设置串口等待事件为有信号 SetEvent( m_hSemComm ); return 0; } WORD CProtocolModbus::GetCheckSum(BYTE *pBuf, int len) { WORD iSum = 0; WORD iCompliment; unsigned char chCompliment[2] = {0}; for(int i=0; iStartAddr; m_pComm=pComm; return TRUE; } void strReverse( char *str ) { int l = strlen(str); for( int i = 0; i < l; i++ ) { for(int i = 0; i < l; i++) { if( str[i] >= 'A' && str[i] <= 'Z' ) { str[i] += 32; } else if(str[i] >= 'a' && str[i] <= 'z') { str[i] -= 32; } } } } char lowercase2uppercase(BYTE btSrc) { if( btSrc >= 'a' && btSrc <= 'z' ) { return btSrc - 'a' + 'A'; } return btSrc; } char ByteToAscii(BYTE btSrc) { char chDest; if( btSrc < 10 ) { chDest = (char)(btSrc % 10 + '0'); chDest = lowercase2uppercase(chDest); return chDest; } else { chDest = ByteToAscii( btSrc / 10 ) + (char)( btSrc % 10 + '0' ); chDest = lowercase2uppercase(chDest); return chDest; } } WORD AsciiToBYTE(BYTE btSrc) { WORD chDest = (WORD)btSrc; if ((btSrc >= 'A')&&(btSrc <= 'F')) { chDest = chDest - 'A' + 10; } else if ((btSrc >= 'a')&&(btSrc <= 'f')) { chDest = chDest - 'a' + 10; } else if ((btSrc >= '0')&&(btSrc <= '9')) { chDest -= '0'; } return chDest; }