// ProtocolPMC916.cpp: implementation of the CProtocolModbus class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "ProtocolModbus.h" #include "winsock2.h" #include "modbusasc.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, char chMsg[80]) { if(!m_pComm) return ERR_CODE_MODBUS_ASC_COM_FAULT; // 串口通信故障 int nRet; nRet = RequestStatus(SetBasePara); if( nRet != 0 ) { return nRet; // 串口忙 } nRet = ResponseStatus(SetBasePara.nAddr, SetBasePara.nRegNum, nDataLen, chMsg); return nRet; } int CProtocolModbus:: WriteCommand(SETBASEPARAM SetBasePara, double dbData, int nDataLen) { int iResult = 0; if(!m_pComm) return ERR_CODE_MODBUS_ASC_COM_FAULT; iResult = RequestWrStatus(SetBasePara, dbData, nDataLen); if (iResult == 0) return ResponseWrStatus(SetBasePara.nAddr, SetBasePara.nRegNum, nDataLen); else return iResult; } int CProtocolModbus::ResponseStatus( int nAddr, int nRegNum, int nDataLen, char chMsg[80]) { RESPONSE_STRUCT structResponse; memset( &structResponse, 0, sizeof(RESPONSE_STRUCT) ); // Modbus Ascii设备,所以一个寄存器占用4个字节,即4 * nRegNum //int nLen = sizeof(RESPONSE_STRUCT) - sizeof(structResponse.StrRtnMsg) + 4 * nRegNum; if (nDataLen <= 0) { TRACE("变量长度小于等于0,为非法变量"); return ERR_CODE_MODBUS_ASC_COM_VARLEN; } int nLen = sizeof(RESPONSE_STRUCT) - sizeof(structResponse.StrRtnMsg) + 2 * nDataLen; char *pBuffer = new char[ nLen]; memset(pBuffer, 0, nLen); int nProcessLen = 0; int nReadLen = 0; TRACE("nLen: %d\r\n", nLen); nReadLen = ReadMessage((BYTE *)pBuffer, nLen); if( nReadLen <= 0 ) { // 串口没有读到数据 TRACE("串口没有读到数据!\r\n"); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_READ_NO_DATA; } else if( nReadLen < nLen ) { TRACE("长度没有收够,断续接收,止到收完为止!\r\n"); #if DEBUG_PROTOCOL SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_FAULT; #else nProcessLen += nReadLen; nReadLen = ReadMessage( (BYTE *)(pBuffer + nProcessLen), nLen - nProcessLen ); while( nReadLen != nLen - nProcessLen ) { if( nReadLen == 0 ) { SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_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_MODBUS_ASC_COM_FAULT; } #endif } else if( nReadLen > nLen ) { // 完全代码,不一定能执行到 TRACE("接收的长度超时所需的长度,认为是非法包,扔掉\r\n"); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_READ_LEN_OVER; } else if( nReadLen == nLen ) // 长度刚好 { char chRegNum[3] = {0}; chRegNum[0] = pBuffer[5]; chRegNum[1] = pBuffer[6]; // 判断寄存器的个数正确吗? //if (atoi(chRegNum) == nRegNum*2) goto NormalProcess; //if( atoi(chRegNum) > nRegNum * 2 ) if (atoi(chRegNum) == nDataLen) goto NormalProcess; if( atoi(chRegNum) > nDataLen) { TRACE("请求寄存器个数超时所需的长度,认为是非法包,收完扔掉\r\n"); #if DEBUG_PROTOCOL SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_READ_LEN_OVER; #else nProcessLen += nReadLen; //nReadLen = ReadMessage( (BYTE *)(pBuffer + nProcessLen), atoi(chRegNum) - nRegNum * 2 ); nReadLen = ReadMessage( (BYTE *)(pBuffer + nProcessLen), atoi(chRegNum) - nDataLen); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_READ_LEN_OVER; #endif } else//小于 { TRACE("读到数据长度小于需要的数据长度,读到回车换行结束符为止!\r\n"); #if DEBUG_PROTOCOL SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_READ_LEN_OVER; #else char chEndvalue[2] = {0}; while(1) { memset(chEndvalue, 0 ,2); nReadLen = ReadMessage( (BYTE *)chEndvalue, 2); if (chEndvalue[1] == 0x0A) { SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_READ_LEN_OVER; } if (chEndvalue[1] == 0x0D) { nReadLen = ReadMessage( (BYTE *)chEndvalue, 1); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_READ_LEN_OVER; } if (nReadLen == 0) { SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_READ_LEN_OVER; } } #endif } } NormalProcess: // 判断校验 BYTE btCrc = GetCheckCode(pBuffer, nLen - sizeof(structResponse.Lrc) - sizeof(structResponse.End)); char chAsc[3] = {0}; sprintf(chAsc, "%X", btCrc); if( !( pBuffer[nLen - 4] == chAsc[0] && pBuffer[nLen - 3] == chAsc[1] ) ) { TRACE("lrc 校验失败!\r\n"); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_LRC_LOST; } EnterCriticalSection( &m_csWrFinished ); memcpy( &m_structResponse.StatusStruct, pBuffer, sizeof(STATUS_STRUCT) ); //for( int i = 0; i < 4 * nRegNum; i++ ) for( int i = 0; i < 2 * nDataLen; i++ ) { chMsg[i] = pBuffer[sizeof(STATUS_STRUCT) + i]; //m_structResponse.StrRtnMsg[i] = pBuffer[sizeof(STATUS_STRUCT) + i]; } LeaveCriticalSection(&m_csWrFinished); // 设置串口等待事件为有信号 SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return 0; } int CProtocolModbus::RequestStatus( SETBASEPARAM SetBasePara)//请求读数据 { int iLen = sizeof(REQUESTPARAM); REQUESTPARAM RequestPara; memset(&RequestPara, 0, iLen); RequestPara.Start = ':'; RequestPara.AddrCode[0] = ByteToAscii((SetBasePara.nAddr >> 4) & 0x0f);//地址码高位Ascii码 RequestPara.AddrCode[1] = ByteToAscii(SetBasePara.nAddr & 0x0f);//地址码低位Ascii码 RequestPara.FuncCode[0] = ByteToAscii((SetBasePara.FuncCode >> 4) & 0x0f);//功能码高位Ascii码 RequestPara.FuncCode[1] = ByteToAscii(SetBasePara.FuncCode & 0x0f);//功能码低位Ascii码 RequestPara.StartAddr[0] = ByteToAscii((SetBasePara.nStartAddr >> 12) & 0x0f); RequestPara.StartAddr[1] = ByteToAscii((SetBasePara.nStartAddr >> 8) & 0x0f); RequestPara.StartAddr[2] = ByteToAscii((SetBasePara.nStartAddr >> 4) & 0x0f); RequestPara.StartAddr[3] = ByteToAscii(SetBasePara.nStartAddr & 0x0f); RequestPara.RequestRegNum[0] = ByteToAscii((SetBasePara.nRegNum >> 12) & 0x0f); RequestPara.RequestRegNum[1] = ByteToAscii((SetBasePara.nRegNum >> 8) & 0x0f); RequestPara.RequestRegNum[2] = ByteToAscii((SetBasePara.nRegNum >> 4) & 0x0f); RequestPara.RequestRegNum[3] = ByteToAscii(SetBasePara.nRegNum & 0x0f); int iBufLen = iLen - sizeof(RequestPara.Lrc) - sizeof(RequestPara.End); char *pBuf = new char[iBufLen]; memset(pBuf, 0, iBufLen); memcpy(pBuf, &RequestPara, iBufLen); char *Tmpbuf = pBuf; BYTE Lrc = GetCheckCode(pBuf, iBufLen); char chAsc[3] = {0}; sprintf(chAsc, "%X", Lrc); RequestPara.Lrc[0] = chAsc[0]; RequestPara.Lrc[1] = chAsc[1]; RequestPara.End[0] = 0x0D; RequestPara.End[1] = 0x0A; if( WaitForSingleObject( m_hSemComm, 0 ) == WAIT_OBJECT_0 ) // 有信号才写串口 { ResetEvent( m_hSemComm ); int nResult = WriteMessage((unsigned char *)&RequestPara, iLen); if( nResult == iLen ) { } else { delete []Tmpbuf; SetEvent( m_hSemComm ); return EER_CODE_MODBUS_ASC_COM_WRITE_DATA; } } else { delete []Tmpbuf; return ERR_CODE_MODBUS_ASC_COM_BUSY; } delete []Tmpbuf; return 0; } int CProtocolModbus::RequestWrStatus( SETBASEPARAM SetBasePara , double dbData, int nDataLen)//请求写数据 { int iResult = 0; REQUESTWRPARAM RequestwrPara; memset(&RequestwrPara, 0, sizeof(REQUESTWRPARAM)); int iLen = sizeof(REQUESTWRPARAM) - sizeof(RequestwrPara.Data) + nDataLen*2; char *TmpSendBuf = new char[iLen]; RequestwrPara.Start = ':'; RequestwrPara.AddrCode[0] = ByteToAscii((SetBasePara.nAddr >> 4) & 0x0f);//地址码高位Ascii码 RequestwrPara.AddrCode[1] = ByteToAscii(SetBasePara.nAddr & 0x0f);//地址码低位Ascii码 RequestwrPara.FuncCode[0] = ByteToAscii((SetBasePara.FuncCode >> 4) & 0x0f);//功能码高位Ascii码 RequestwrPara.FuncCode[1] = ByteToAscii(SetBasePara.FuncCode & 0x0f);//功能码低位Ascii码 RequestwrPara.StartAddr[0] = ByteToAscii((SetBasePara.nStartAddr >> 12) & 0x0f); RequestwrPara.StartAddr[1] = ByteToAscii((SetBasePara.nStartAddr >> 8) & 0x0f); RequestwrPara.StartAddr[2] = ByteToAscii((SetBasePara.nStartAddr >> 4) & 0x0f); RequestwrPara.StartAddr[3] = ByteToAscii(SetBasePara.nStartAddr & 0x0f); RequestwrPara.RequestRegNum[0] = ByteToAscii((SetBasePara.nRegNum >> 12) & 0x0f); RequestwrPara.RequestRegNum[1] = ByteToAscii((SetBasePara.nRegNum >> 8) & 0x0f); RequestwrPara.RequestRegNum[2] = ByteToAscii((SetBasePara.nRegNum >> 4) & 0x0f); RequestwrPara.RequestRegNum[3] = ByteToAscii(SetBasePara.nRegNum & 0x0f); switch(nDataLen) { case 1: union __Rensitivity1{ char ch; char f; }unionRensitivity1; unionRensitivity1.f = (char)dbData; unionRensitivity1.f = 0x01; RequestwrPara.Data[0] = ByteToAscii((unionRensitivity1.ch >> 4) & 0x0f); RequestwrPara.Data[1] = ByteToAscii((unionRensitivity1.ch) & 0x0f); break; case 2: union __Rensitivity2{ char ch[2]; short int f; }unionRensitivity2; unionRensitivity2.f = (short int)dbData; unionRensitivity2.ch[0] = 0x01; unionRensitivity2.ch[1] = 0x03; RequestwrPara.Data[0] = ByteToAscii((unionRensitivity2.ch[0] >> 4) & 0x0f); RequestwrPara.Data[1] = ByteToAscii((unionRensitivity2.ch[0]) & 0x0f); RequestwrPara.Data[2] = ByteToAscii((unionRensitivity2.ch[1] >> 4) & 0x0f); RequestwrPara.Data[3] = ByteToAscii((unionRensitivity2.ch[1]) & 0x0f); break; case 4: union __Rensitivity{ char ch[4]; float f; }unionRensitivity; unionRensitivity.f = (float)dbData; RequestwrPara.Data[0] = ByteToAscii((unionRensitivity.ch[0] >> 4) & 0x0f); RequestwrPara.Data[1] = ByteToAscii((unionRensitivity.ch[0]) & 0x0f); RequestwrPara.Data[2] = ByteToAscii((unionRensitivity.ch[1] >> 4) & 0x0f); RequestwrPara.Data[3] = ByteToAscii((unionRensitivity.ch[1]) & 0x0f); RequestwrPara.Data[4] = ByteToAscii((unionRensitivity.ch[2] >> 4) & 0x0f); RequestwrPara.Data[5] = ByteToAscii((unionRensitivity.ch[2]) & 0x0f); RequestwrPara.Data[6] = ByteToAscii((unionRensitivity.ch[3] >> 4) & 0x0f); RequestwrPara.Data[7] = ByteToAscii((unionRensitivity.ch[3]) & 0x0f); break; } int iTmpLen = sizeof(m_RequestWrParam.Start) + sizeof(m_RequestWrParam.AddrCode) + sizeof(m_RequestWrParam.FuncCode) + sizeof(m_RequestWrParam.StartAddr) + sizeof(m_RequestWrParam.RequestRegNum); int iBufLen = iLen - sizeof(RequestwrPara.Lrc); char *pBuf = new char[iBufLen]; memset(pBuf, 0, iBufLen); memcpy(pBuf, &RequestwrPara, iBufLen); char *Tmpbuf = pBuf; BYTE Lrc = GetCheckCode(pBuf, iBufLen - sizeof(RequestwrPara.End)); char chAsc[3] = {0}; sprintf(chAsc, "%X", Lrc); RequestwrPara.Lrc[0] = chAsc[0]; RequestwrPara.Lrc[1] = chAsc[1]; RequestwrPara.End[0] = 0x0D; RequestwrPara.End[1] = 0x0A; memcpy(TmpSendBuf, &RequestwrPara, iTmpLen); memcpy((TmpSendBuf + iTmpLen), &RequestwrPara.Data, nDataLen*2); memcpy((TmpSendBuf + iTmpLen + nDataLen*2), &RequestwrPara.Lrc, sizeof(RequestwrPara.Lrc)); memcpy((TmpSendBuf + iTmpLen + nDataLen*2 + sizeof(RequestwrPara.Lrc)), &RequestwrPara.End, sizeof(RequestwrPara.End)); iResult = WriteMessage((unsigned char *)TmpSendBuf, iLen); delete []Tmpbuf; if( NULL != TmpSendBuf ) { delete []TmpSendBuf; TmpSendBuf = NULL; } return 0; } int CProtocolModbus::ResponseWrStatus(int nAddr, int nRegNum, int nDataLen) { REQUESTWRPARAM RequestWrPara; int iLen = sizeof(REQUESTWRPARAM) - sizeof(RequestWrPara.Data) + 2*nDataLen; memset(&RequestWrPara, 0, iLen); char *pBuffer = new char[iLen]; memset(pBuffer, 0, iLen); int iProcessLen = 0; //int iReadLen = ReadMessage((BYTE *)&RequestWrPara, iLen); int iReadLen = ReadMessage((BYTE *)pBuffer, iLen); if( iReadLen <= 0) // 串口没有读到数据 { if( pBuffer ) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_READ_NO_DATA; } else if(iReadLen< iLen) { TRACE("长度没有收够,断续接收,直到收完为止!\r\n"); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_FAULT; } else if( iReadLen > iLen )//实际读到包长度大于要求包的长度 { // 完全代码,不一定能执行到 TRACE("接收的长度超时所需的长度,认为是非法包,扔掉\r\n"); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_READ_LEN_OVER; } else if (iReadLen == iLen)//读到的包长度相等 { char chDataNum[4] = {0}; chDataNum[0] = pBuffer[9]; chDataNum[1] = pBuffer[10]; chDataNum[2] = pBuffer[11]; chDataNum[2] = pBuffer[12]; // 判断寄存器的个数正确吗? if (atoi(chDataNum) == nRegNum) goto NormalProcess; if( atoi(chDataNum) > nRegNum) { TRACE("请求寄存器个数超时所需的长度,认为是非法包,收完扔掉\r\n"); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_READ_LEN_OVER; } else//小于 { TRACE("读到数据长度小于需要的数据长度,读到回车换行结束符为止!\r\n"); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_READ_LEN_OVER; } } NormalProcess: BYTE btCrc = GetCheckCode(pBuffer, iLen - sizeof(RequestWrPara.Lrc) - sizeof(RequestWrPara.End)); char chAsc[3] = {0}; sprintf(chAsc, "%X", btCrc); if( !( pBuffer[iLen - 4] == chAsc[0] && pBuffer[iLen - 3] == chAsc[1] ) ) { TRACE("lrc 校验失败!\r\n"); SetEvent( m_hSemComm ); if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } return ERR_CODE_MODBUS_ASC_COM_LRC_LOST; } EnterCriticalSection( &m_csWrFinished ); memset(&m_RequestWrParam, 0, sizeof(REQUESTWRPARAM)); int iTmpLen = sizeof(m_RequestWrParam.Start) + sizeof(m_RequestWrParam.AddrCode) + sizeof(m_RequestWrParam.FuncCode) + sizeof(m_RequestWrParam.StartAddr) + sizeof(m_RequestWrParam.RequestRegNum); memcpy( &m_RequestWrParam, pBuffer, iTmpLen);//起始位、地址码、功能码、起始地址、寄存器数 memcpy( &m_RequestWrParam.Data, pBuffer + iTmpLen, 2*nDataLen);//数据 iTmpLen = iTmpLen + 2*nDataLen; memcpy( &m_RequestWrParam.Lrc, pBuffer + iTmpLen, 2);//校验位 iTmpLen = iTmpLen + 2; memcpy( &m_RequestWrParam.End, pBuffer + iTmpLen, 2);//结束位 LeaveCriticalSection(&m_csWrFinished); // 设置串口等待事件为有信号 if( pBuffer != NULL) { delete[] pBuffer; pBuffer = NULL; } SetEvent( m_hSemComm ); return 0; } BOOL CProtocolModbus::InitParam(PPORTPARAM pPortParam, CCommAsyn *pComm) { int addr=pPortParam->StartAddr; m_pComm=pComm; return TRUE; } BYTE GetCheckCode(const char * pSendBuf, int nEnd)//获得校验码 { BYTE byLrc = 0; char pBuf[4]; int nData = 0; for(int i=1; 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; }