modbus.cpp

来自「一个modbus协议的opc server」· C++ 代码 · 共 1,120 行 · 第 1/2 页

CPP
1,120
字号
// modbus.cpp: implementation of the CModbus class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "modbus.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif



// Class CModbusException
IMPLEMENT_DYNAMIC(CModbusException, CException)

CModbusException::CModbusException(CString& sMessage,int nError)
{
    m_strMessage = sMessage;
    m_nError = nError;
}

BOOL CModbusException::GetErrorMessage(LPTSTR lpstrError, UINT nMaxError,
                                       PUINT pnHelpContext /*= NULL*/)
{
    
    char text[200];
    if(m_nError == 0) {
        wsprintf(text, "%s error", (const char*) m_strMessage);
    }
    else {
        wsprintf(text, "%s error #%d", (const char*) m_strMessage, m_nError);
    }
    strncpy(lpstrError, text, nMaxError - 1);
    return TRUE;
}


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

IMPLEMENT_DYNAMIC( CModbus, CObject)

CModbus::CModbus()
{
    m_wRetries=1;
    m_bThrowModbusException=FALSE;
    m_dwLockTimeout=1000;
    m_dwDelay=0;
}

CModbus::~CModbus()
{
    
}


WORD CModbus::ReadOutputRegisters(WORD nAddr,  WORD nDataStart , WORD nQtd , CWordArray& anRegValues) {
    
    CByteArray abyQuery;
    short nReplyLength=(3 + 2 * nQtd);
    CByteArray  abyReply;// new int[nReplyLength];
    WORD nError;
    short nByte;
    short nRespByte;
    const short QUERY_LENGHT=6;
    int  iRetry=0;
    
    
    abyQuery.SetSize(6);
    abyReply.SetSize(nReplyLength);
    //Query 
    
    //modbus message 
    abyQuery[0]=(BYTE)nAddr; //ADDR	
    abyQuery[1]=READ_OUTPUT_REGISTERS; //Function 
    abyQuery[2]=HIBYTE(nDataStart);
    abyQuery[3]=LOBYTE(nDataStart);
    abyQuery[4]=HIBYTE(nQtd);
    abyQuery[5]=LOBYTE(nQtd);
    
    
    do {
        
        nError=TxRxMessage(abyQuery,6,abyReply, nReplyLength);
        
        
        if (nError==ERR_OK) {
            if ((abyReply[0]!=abyQuery[0])||(abyReply[1]!=abyQuery[1])) {
                nError=ERR_INV_RESP;
            }
            else {
                nByte=0;//return array 
                for(nRespByte=3;nRespByte<nReplyLength;nRespByte=(short)(nRespByte+2)){
                    anRegValues[nByte] = (abyReply[nRespByte]);
                    anRegValues[nByte]= ((anRegValues[nByte]<<8)|(abyReply[nRespByte+1]));
                    nByte++;
                }
                
            }
        }//nerror=ERR_OK
        
        iRetry++;
        
        ErrorDelay(nError);
        
    } while ((iRetry<m_wRetries)&&(ERR_OK!=nError)); 
    
    
    ThrowModbusException(nError);
    
    return(nError);
    
}//end ReadOutRegisters 



WORD CModbus::ReadOutputRegisters(WORD nAddr,  WORD nDataStart , WORD nQtd , CShortArray& anRegValues) {
    
    
    CWordArray anValues;
    WORD nError;
    anValues.SetSize(anRegValues.GetSize());
    nError =ReadOutputRegisters(nAddr,nDataStart,nQtd,anValues);
    Word2ShortArray(anValues,anRegValues);
    return nError;
    
}


WORD CModbus::ReadInputRegisters(WORD nAddr,  WORD nDataStart , WORD nQtd , CWordArray& anRegValues) {
    
    CByteArray abyQuery;
    short nReplyLength=(3 + 2 * nQtd);
    CByteArray  abyReply;// new int[nReplyLength];
    WORD nError;
    short nByte;
    short nRespByte;
    const short QUERY_LENGHT=6;
    int  iRetry=0;
    
    
    abyQuery.SetSize(6);
    abyReply.SetSize(nReplyLength);
    //Query 
    
    //modbus message 
    abyQuery[0]=(BYTE)nAddr; //ADDR	
    abyQuery[1]=READ_INPUT_REGISTERS; //Function 
    abyQuery[2]=HIBYTE(nDataStart);
    abyQuery[3]=LOBYTE(nDataStart);
    abyQuery[4]=HIBYTE(nQtd);
    abyQuery[5]=LOBYTE(nQtd);
    
    do {
        
        nError=TxRxMessage(abyQuery,6,abyReply, nReplyLength);
        
        
        if (nError==ERR_OK) {
            if ((abyReply[0]!=abyQuery[0])||(abyReply[1]!=abyQuery[1])) {
                nError=ERR_INV_RESP;
            }
            else {
                nByte=0;//return array 
                for(nRespByte=3;nRespByte<nReplyLength;nRespByte=(short)(nRespByte+2)){
                    anRegValues[nByte] = (abyReply[nRespByte]);
                    anRegValues[nByte]= ((anRegValues[nByte]<<8)|(abyReply[nRespByte+1]));
                    nByte++;
                }
                
            }
            
            
        }//nerror=ERR_OK
        
        iRetry++;
        
        ErrorDelay(nError);
        
    } while ((iRetry<m_wRetries)&&(ERR_OK!=nError)); 
    
    
    ThrowModbusException(nError);
    
    return(nError);
    
}//end ReadInRegisters 


WORD CModbus::ReadInputRegisters(WORD nAddr,  WORD nDataStart , WORD nQtd , CShortArray& anRegValues) {
    
    
    CWordArray anValues;
    WORD nError;
    anValues.SetSize(anRegValues.GetSize());
    nError =ReadInputRegisters(nAddr,nDataStart,nQtd,anValues);
    Word2ShortArray(anValues,anRegValues);
    return nError;
    
}


WORD CModbus::ReadInputRegisters(WORD nAddr,  WORD nDataStart , WORD nQtd , CDblArray& anRegValues,WORD wRealType) {
    
    
    CWordArray anValues;
    WORD nError;
    anValues.SetSize(4*anRegValues.GetSize());
    nError =ReadInputRegisters(nAddr,nDataStart,4*nQtd,anValues);
    Word2Dbl(anValues.GetData(),anValues.GetSize(),anRegValues.GetData(),anRegValues.GetSize(),wRealType);
    return nError;
    
}

WORD CModbus::ReadInputRegisters(WORD nAddr,  WORD nDataStart , WORD nQtd , CFloatArray& anRegValues,WORD wRealType) {
    
    
    CWordArray anValues;
    WORD nError;
    anValues.SetSize(2*anRegValues.GetSize());
    nError =ReadInputRegisters(nAddr,nDataStart,2*nQtd,anValues);
    Word2Float(anValues.GetData(),anValues.GetSize(),anRegValues.GetData(),anRegValues.GetSize(),wRealType);
    return nError;
    
}

WORD CModbus::ReadOutputRegisters(WORD nAddr,  WORD nDataStart , WORD nQtd , CDblArray& anRegValues,WORD wRealType) {
    
    
    CWordArray anValues;
    WORD nError;
    anValues.SetSize(4*anRegValues.GetSize());
    nError =ReadOutputRegisters(nAddr,nDataStart,4*nQtd,anValues);
    Word2Dbl(anValues.GetData(),anValues.GetSize(),anRegValues.GetData(),anRegValues.GetSize(),wRealType);
    return nError;
    
}

WORD CModbus::ReadOutputRegisters(WORD nAddr,  WORD nDataStart , WORD nQtd , CFloatArray& anRegValues,WORD wRealType) {
    
    
    CWordArray anValues;
    WORD nError;
    anValues.SetSize(2*anRegValues.GetSize());
    nError =ReadOutputRegisters(nAddr,nDataStart,2*nQtd,anValues);
    Word2Float(anValues.GetData(),anValues.GetSize(),anRegValues.GetData(),anRegValues.GetSize(),wRealType);
    return nError;
    
}

//Read output status "coils" 
//return

WORD CModbus::ReadInputStatus(WORD nAddr, //Modbus device Address 
                              WORD nDataStart , //
                              WORD nQtd , 
                              CByteArray& abCoilValues) {
    
    static WORD const  QUERY_LENGHT=6;
    
    CByteArray abyQuery;
    WORD nReplyLength=(3 + (nQtd + 7) / 8);
    CByteArray  abyReply;//[]  = new int[nReplyLength];
    WORD nError;
    WORD nRespByte;
    WORD nCoil;
    WORD nBit;
    int  iRetry=0;
    
    //set array sizes 
    abyQuery.SetSize(QUERY_LENGHT);
    abyReply.SetSize(nReplyLength); 
    //modbus message 
    abyQuery[0]=(BYTE)nAddr; //ADDR	
    abyQuery[1]=READ_INPUT_STATUS; //Function 
    abyQuery[2]=HIBYTE(nDataStart);
    abyQuery[3]=LOBYTE(nDataStart);
    abyQuery[4]=HIBYTE(nQtd);
    abyQuery[5]=LOBYTE(nQtd);
    
    do {
        
        nError=TxRxMessage(abyQuery,(QUERY_LENGHT),abyReply, nReplyLength);
        
        
        if (nError==ERR_OK) {
            if ((abyReply[0]!=abyQuery[0])||(abyReply[1]!=abyQuery[1])) {
                nError=ERR_INV_RESP;
            }
            else {
                nBit=0;
                nRespByte=3;		
                for(nCoil=0;nCoil<nQtd;nCoil++){
                    
                    if (nBit>7){
                        nBit=0;
                        nRespByte++;
                    }
                    
                    if ((abyReply[nRespByte] & (0x01<<nBit))>0){
                        abCoilValues[nCoil]= TRUE; 
                    }
                    else {
                        abCoilValues[nCoil]= FALSE; 
                    }
                    nBit++; //next bit 
                    
                }// end for 
                
            }// else 
            
            
        }//nerror=ERR_OK
        
        iRetry++;
        
        ErrorDelay(nError);
        
    } while ((iRetry<m_wRetries)&&(ERR_OK!=nError)); 
    
    
    ThrowModbusException(nError);
    
    return(nError);
    
}//end ReadInputStatus 



//Read output status "coils" 
//return

WORD CModbus::ReadOutputStatus(WORD nAddr, //Modbus device Address 
                               WORD nDataStart , //
                               WORD nQtd , 
                               CByteArray& abCoilValues) {
    
    static WORD const  QUERY_LENGHT=6;
    
    CByteArray abyQuery;
    WORD nReplyLength=(3 + (nQtd + 7) / 8);
    CByteArray  abyReply;//[]  = new int[nReplyLength];
    WORD nError;
    WORD nRespByte;
    WORD nCoil;
    WORD nBit;
    int  iRetry=0;
    
    //set array sizes 
    abyQuery.SetSize(QUERY_LENGHT);
    abyReply.SetSize(nReplyLength); 
    //modbus message 
    abyQuery[0]=(BYTE)nAddr; //ADDR	
    abyQuery[1]=READ_OUTPUT_STATUS; //Function 
    abyQuery[2]=HIBYTE(nDataStart);
    abyQuery[3]=LOBYTE(nDataStart);
    abyQuery[4]=HIBYTE(nQtd);
    abyQuery[5]=LOBYTE(nQtd);
    
    
    do {
        
        nError=TxRxMessage(abyQuery,(QUERY_LENGHT),abyReply, nReplyLength);
        
        
        if (nError==ERR_OK) {
            if ((abyReply[0]!=abyQuery[0])||(abyReply[1]!=abyQuery[1])) {
                nError=ERR_INV_RESP;
            }
            else {
                nBit=0;
                nRespByte=3;		
                for(nCoil=0;nCoil<nQtd;nCoil++){
                    
                    if (nBit>7){
                        nBit=0;
                        nRespByte++;
                    }
                    
                    if ((abyReply[nRespByte] & (0x01<<nBit))>0){
                        abCoilValues[nCoil]= TRUE; 
                    }
                    else {
                        abCoilValues[nCoil]= FALSE; 
                    }
                    nBit++; //next bit 
                    
                }// end for 
                
            }// else 
            
            
        }//nerror=ERR_OK
        
        iRetry++;
        
        ErrorDelay(nError);
        
    } while ((iRetry<m_wRetries)&&(ERR_OK!=nError)); 
    
    
    ThrowModbusException(nError);
    
    return(nError);
    
}//end ReadOutStatus 


WORD CModbus::PresetMultipleRegisters(WORD nAddr,  WORD nDataStart , WORD nQtd , CWordArray& anRegValues) {
    
    
    const WORD QUERY_LENGHT=(7+2*nQtd);
    CByteArray abyQuery;//[QUERY_LENGHT];
    short nReplyLength=(6);
    CByteArray  abyReply;
    short nError;
    int	  iReg; 	
    int  iRetry=0;
    
    
    //Query 
    abyQuery.SetSize(QUERY_LENGHT);
    abyReply.SetSize(nReplyLength);
    //modbus message 
    abyQuery[0]=(BYTE)nAddr; //ADDR	
    abyQuery[1]=PRESET_MULTIPLE_REGISTERS; //Function 
    abyQuery[2]=HIBYTE(nDataStart);
    abyQuery[3]=LOBYTE(nDataStart);
    abyQuery[4]=HIBYTE(nQtd);
    abyQuery[5]=LOBYTE(nQtd);
    abyQuery[6]=(2*nQtd);
    
    for (iReg=0;iReg<(nQtd);iReg++){
        abyQuery[7+iReg*2]=HIBYTE(anRegValues[iReg]);
        abyQuery[7+iReg*2+1]=LOBYTE(anRegValues[iReg]);
    }
    
    do {
        nError=TxRxMessage(abyQuery,QUERY_LENGHT,abyReply, nReplyLength);
        
        
        if (nError==ERR_OK) {
            
            for (iReg=0;iReg<6;iReg++){
                if (abyReply[iReg]!=abyQuery[iReg]) {
                    nError=ERR_INV_RESP;
                    break;
                }
            }
            
        }//nerror=ERR_OK
        
        iRetry++;
        
        ErrorDelay(nError);
        
    } while ((iRetry<m_wRetries)&&(ERR_OK!=nError)); 
    
    
    ThrowModbusException(nError);
    
    return(nError);
    
}//end PresetMultipleRegisters 

WORD CModbus::PresetMultipleRegisters(WORD nAddr, //address of modbus device 
                                      WORD nDataStart , //start address, first address is 0 "ZERO" 
                                      WORD nQtd , //number of reg . to write 
                                      CShortArray& anRegValues) {
    
    CWordArray anValues;
    Short2WordArray(anRegValues,anValues);
    return PresetMultipleRegisters(nAddr,nDataStart,nQtd ,anValues);
    
} //end PresetMultipleRegisters //CShortArray


WORD CModbus::PresetMultipleRegisters(WORD nAddr, //address of modbus device 
                                      WORD nDataStart , //start address, first address is 0 "ZERO" 
                                      WORD nQtd , //number of reg . to write 
                                      CDblArray& adRegValues,
                                      WORD wRealType) {
    
    CWordArray anValues;
    anValues.SetSize(nQtd*4);
    ASSERT(nQtd<=adRegValues.GetSize());
    
    Dbl2Word(adRegValues.GetData(),nQtd,anValues.GetData(),nQtd*4,wRealType);
    
    return PresetMultipleRegisters(nAddr,nDataStart,nQtd*4 ,anValues);
    
} //end PresetMultipleRegisters //CShortArray


WORD CModbus::PresetMultipleRegisters(WORD nAddr, //address of modbus device 
                                      WORD nDataStart , //start address, first address is 0 "ZERO" 
                                      WORD nQtd , //number of reg . to write 
                                      CFloatArray& afRegValues,
                                      WORD wRealType) {
    
    CWordArray anValues;
    anValues.SetSize(nQtd*2);
    ASSERT(nQtd<=afRegValues.GetSize());
    
    Float2Word(afRegValues.GetData(),nQtd,anValues.GetData(),nQtd*2,wRealType);
    
    return PresetMultipleRegisters(nAddr,nDataStart,nQtd*2 ,anValues);
    
} //end PresetMultipleRegisters //CFloatArray



WORD CModbus::PresetSingleRegister(WORD nAddr,  WORD nRegister , WORD nRegValue) {
    
    
    const short QUERY_LENGHT=(6);
    CByteArray abyQuery;
    short nReplyLength=(6);
    CByteArray  abyReply;
    short nError;
    int	  iReg; 
    int  iRetry=0;
    
    
    
    //Query 
    abyQuery.SetSize(QUERY_LENGHT); 
    abyReply.SetSize(nReplyLength);
    
    //modbus message 
    abyQuery[0]=(BYTE)nAddr; //ADDR	
    abyQuery[1]=PRESET_SINGLE_REGISTER; //Function 
    abyQuery[2]=HIBYTE(nRegister);
    abyQuery[3]=LOBYTE(nRegister);
    abyQuery[4]=HIBYTE(nRegValue);
    abyQuery[5]=LOBYTE(nRegValue);
    
    do {
        
        nError=TxRxMessage(abyQuery,QUERY_LENGHT,abyReply, nReplyLength);
        
        
        if (nError==ERR_OK) {
            
            for (iReg=0;iReg<QUERY_LENGHT;iReg++){
                if (abyReply[iReg]!=abyQuery[iReg]) {
                    nError=ERR_INV_RESP;
                    break;
                }
            }
            
        }//nerror=ERR_OK
        
        iRetry++;
        
        ErrorDelay(nError);

⌨️ 快捷键说明

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