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

📄 localmodbus.cpp

📁 一个modbus协议的opc server
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// LocalModbus.cpp: implementation of the CLocalModbus class.
//
//////////////////////////////////////////////////////////////////////

//#include "mbu.h"
#include "stdafx.h"
#include "LocalModbus.h"

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



IMPLEMENT_DYNAMIC(CLocalModbus,CModbus)

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

CLocalModbus::CLocalModbus()
{
    m_hComHandle=INVALID_HANDLE_VALUE;
    m_lTimeOut=1000;
    m_ComPort=2;
    m_byParity=NOPARITY; 
    m_BaudRate=9600;
    m_dwSilentInterval=0;
    FlowControl(FC_NONE);
    StopBits(ONESTOPBIT);
    m_wByteSize=8;
    m_wTranmitionMode=MODE_RTU;
    m_abyBuffer.SetSize(RESP_BUFFER*2);
}

CLocalModbus::~CLocalModbus()
{
    CloseCommPort();
}

//properties 

BOOL CLocalModbus::SetTimeouts(COMMTIMEOUTS* timeouts_p )
{
    ASSERT( m_hComHandle!=INVALID_HANDLE_VALUE );
    
    // Choose to live
    
    if ( m_hComHandle ==INVALID_HANDLE_VALUE )
    {
        return( FALSE );
    }
    
    BOOL return_value = FALSE;
    
    COMMTIMEOUTS communications_timeouts;
    
    ::ZeroMemory( &communications_timeouts, sizeof( communications_timeouts ) );
    
    if ( timeouts_p != NULL )
    {
        // We were passed a pointer, do not trust it
        
        try
        {
            communications_timeouts.ReadIntervalTimeout         = timeouts_p->ReadIntervalTimeout;
            communications_timeouts.ReadTotalTimeoutMultiplier  = timeouts_p->ReadTotalTimeoutMultiplier;
            communications_timeouts.ReadTotalTimeoutConstant    = timeouts_p->ReadTotalTimeoutConstant;
            communications_timeouts.WriteTotalTimeoutMultiplier = timeouts_p->WriteTotalTimeoutMultiplier;
            communications_timeouts.WriteTotalTimeoutConstant   = timeouts_p->WriteTotalTimeoutConstant;
        }
        catch( ... )
        {
            communications_timeouts.ReadIntervalTimeout         = MAXDWORD;
            communications_timeouts.ReadTotalTimeoutMultiplier  = 0;
            communications_timeouts.ReadTotalTimeoutConstant    = 0;
            communications_timeouts.WriteTotalTimeoutMultiplier = 0;
            communications_timeouts.WriteTotalTimeoutConstant   = 0;
        }
    }
    else
    {
        // Use our defaults
        communications_timeouts.ReadIntervalTimeout         = MAXDWORD;
        communications_timeouts.ReadTotalTimeoutMultiplier  = 0;
        communications_timeouts.ReadTotalTimeoutConstant    = 0;
        communications_timeouts.WriteTotalTimeoutMultiplier = 0;
        communications_timeouts.WriteTotalTimeoutConstant   = 0;
    }
    
    return_value = ::SetCommTimeouts( (HANDLE) m_hComHandle, &communications_timeouts );
    
    return( return_value );
}

BOOL CLocalModbus::GetTimeouts( COMMTIMEOUTS& timeouts )
{
    ASSERT( m_hComHandle != INVALID_HANDLE_VALUE );
    
    // Choose to live
    
    if ( m_hComHandle ==INVALID_HANDLE_VALUE )
    {
        ::ZeroMemory( &timeouts, sizeof( COMMTIMEOUTS ) );
        return( FALSE );
    }
    
    BOOL return_value = FALSE;
    
    return_value = ::GetCommTimeouts(m_hComHandle, &timeouts );
    
    return( return_value );
}


DWORD CLocalModbus::Timeout() const {
    return m_lTimeOut;
}


void CLocalModbus::Timeout(DWORD dwTimeout){
    m_lTimeOut=dwTimeout;
}


DWORD CLocalModbus::SilentInterval() const {
    return m_dwSilentInterval;
}

void CLocalModbus::SilentInterval(DWORD dwSilentInterval ){
    if (dwSilentInterval>0){
        m_dwSilentInterval=dwSilentInterval;
    }
}

BYTE CLocalModbus::ComPort()
{
    return m_ComPort;  
    
}


void CLocalModbus::ComPort(BYTE byComPort)
{
    m_ComPort=byComPort;  
    
}

BYTE CLocalModbus::FlowControl() {
    
    return  m_byFlowControl;
    
}

void CLocalModbus::FlowControl(BYTE byFlowControl){
    
    m_byFlowControl= byFlowControl;
    
}

BYTE CLocalModbus::StopBits() {
    
    return  m_byStopBits;
    
}

void CLocalModbus::StopBits(BYTE byStopBits){
    
    m_byStopBits= byStopBits;
    
}


DWORD CLocalModbus::BaudRate()
{
    
    return m_BaudRate;
}

void CLocalModbus::BaudRate(DWORD dwBaudRate)
{
    
    m_BaudRate=dwBaudRate;
}

BYTE CLocalModbus::Parity()
{
    return m_byParity;
    
}

void  CLocalModbus::Parity(BYTE byParity) {
    
    m_byParity = byParity;
}

//close serial port 
BOOL CLocalModbus::CloseCommPort(){
    if (m_hComHandle!=INVALID_HANDLE_VALUE){
        if (::CloseHandle(m_hComHandle)) {
            m_hComHandle=INVALID_HANDLE_VALUE;
            return TRUE;
        }
        else {
            return FALSE;
        }
    }
    else {
        return (TRUE);
    }
}

BOOL CLocalModbus::UpdateSerialConfig(BYTE byComPort,  //com port
                                      DWORD dwBaudRate, // Baudrate 9600,4800 actual values  
                                      BYTE byParity){    //Parity EVENPARITY or ODDPARITY or NOPARITY DCB definitions 				  	
    
    // set timeouts
    CString sPort;
    COMMTIMEOUTS cto;
    DCB dcb;
    DWORD dwSilentInterval;
    BYTE bSet;
    
    Lock();
    
    if (!CloseCommPort()){
        TRACE("Can't close comm port");
        goto OpenCommError;
    }
    
    if (0==byComPort){
        byComPort=m_ComPort;
    }
    
    if ((byComPort>=1)&&(byComPort<=MAX_COM_PORTS)){
        m_ComPort=byComPort;
    }
    else {
        goto OpenCommError;
    }
    
    sPort.Format(_T("COM%d"),m_ComPort);
    
    m_hComHandle = ::CreateFile((LPCTSTR)sPort,
        GENERIC_READ|GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);
    
    if(m_hComHandle == INVALID_HANDLE_VALUE) {
        
        sPort.Format(_T("\\\\.\\COM%d"),m_ComPort); //Try NT Format 
        
        m_hComHandle = ::CreateFile((LPCTSTR)sPort,
            GENERIC_READ|GENERIC_WRITE,
            0,
            NULL,
            OPEN_EXISTING,
            0,
            NULL);
        
        if(m_hComHandle == INVALID_HANDLE_VALUE) {
            TRACE("CreateFile Failed \n");
            goto OpenCommError;
        } 
    }
    
    if(!::SetupComm(
        m_hComHandle,	// handle of communications device
        INPUT_BUFFER_SIZE,	// size of input buffer
        OUTPUT_BUFFER_SIZE	// size of output buffer
        )
        ){
        TRACE("SetupComm failed \n");
        goto OpenCommError;
    }
    
    //missinig verify baudrate and pairty *****
    
    // set DCB
    if (0==dwBaudRate) {
        //m_byParity=dcb.Parity; 
        dwBaudRate =m_BaudRate;
    }
    
    if (INVALID_PARITY==byParity) {
        byParity=m_byParity;
    }
    
    ::memset(&dcb,0,sizeof(dcb));
    dcb.DCBlength = sizeof(dcb);
    dcb.BaudRate = dwBaudRate;
    dcb.fBinary = TRUE;
    dcb.StopBits = StopBits();
    dcb.Parity = byParity;
    dcb.ByteSize = BYTE(m_wByteSize);
    
    bSet=(BYTE) ((FlowControl()& FC_DTRDSR)!=0);
    dcb.fOutxDsrFlow = bSet ;
    
    if (bSet)
        dcb.fDtrControl = DTR_CONTROL_HANDSHAKE ;
    else
        dcb.fDtrControl = DTR_CONTROL_ENABLE ;
    
    bSet = (BYTE) ((FlowControl()& FC_RTSCTS) != 0) ;
    dcb.fOutxCtsFlow = bSet ;
    
    if (bSet)
        dcb.fRtsControl = RTS_CONTROL_HANDSHAKE ;
    else
        dcb.fRtsControl = RTS_CONTROL_ENABLE ;
    
    // setup software flow control
    
    bSet = (BYTE) ((FlowControl()&FC_XONXOFF) != 0) ;
    
    dcb.fInX = dcb.fOutX = bSet ;
    dcb.XonChar = ASCII_XON ;
    dcb.XoffChar = ASCII_XOFF ;
    dcb.XonLim = 100 ;
    dcb.XoffLim = 100 ;
	 	 
    dwSilentInterval= (DWORD)((dcb.ByteSize+4)*(4)*1000L)/(dcb.BaudRate);
    m_byParity=dcb.Parity; 
    m_BaudRate=dcb.BaudRate;
    
    if (dwSilentInterval>m_dwSilentInterval) {
        SilentInterval(dwSilentInterval);
    }
    
    cto.ReadIntervalTimeout=SilentInterval();//Max Char Interval 
    cto.ReadTotalTimeoutMultiplier=(DWORD)((dcb.ByteSize+4)*(1)*1000L)/(dcb.BaudRate);
    
    if (cto.ReadTotalTimeoutMultiplier<=0){ 
        cto.ReadTotalTimeoutMultiplier=1;
    }
    
    cto.ReadTotalTimeoutConstant=m_lTimeOut;
    cto.WriteTotalTimeoutMultiplier=SilentInterval();
    cto.WriteTotalTimeoutConstant=m_lTimeOut;
    
    
    if (MODE_RTU==m_wTranmitionMode){
        if(!SetTimeouts(&cto)){
            TRACE("SetTimeouts failed ");
            goto OpenCommError;
        }
    }
    else {	
        if(!SetTimeouts(NULL)){
            TRACE("SetTimeouts failed ");
            goto OpenCommError;
        }
    }
    
    
    if(!::SetCommState(m_hComHandle,&dcb)){
        TRACE("SetCommState failed \n");
        goto OpenCommError;
    }
    
    Unlock();
    return (TRUE);
    
OpenCommError:
    Unlock();
    return (FALSE);	 
}
 
BOOL CLocalModbus::IsActive() {
    if (m_hComHandle!=INVALID_HANDLE_VALUE) {
        return TRUE;
    }
    else {
        return FALSE;
    }
}
 
 
void CLocalModbus::Serialize( CArchive& archive )
{
    // call base class function first
    // base class is CObject in this case
    CModbus::Serialize( archive );
    
    BOOL bIsActive;	
    // now do the stuff for our specific class
    if( archive.IsStoring() ){
        archive << m_dwSilentInterval << m_lTimeOut;
        archive <<m_ComPort<<m_byParity<<m_BaudRate<<IsActive();
        archive <<m_byStopBits<<m_byFlowControl<<m_wTranmitionMode<<m_wByteSize;
        
    } 
    else {
        
        archive >> m_dwSilentInterval >> m_lTimeOut >> m_ComPort >> m_byParity >> m_BaudRate >> bIsActive;
        archive >>m_byStopBits >> m_byFlowControl>>m_wTranmitionMode>>m_wByteSize;
        
        if (bIsActive) {
            UpdateSerialConfig(m_ComPort,  //com port
                m_BaudRate, // Baudrate 9600,4800 actual values  
                m_byParity);
            
        }
        
    }
}
 
WORD CLocalModbus::TxRxMessage(CByteArray& abyQuery, //modbus query without CRC
     WORD wLengthQuery, //QueryLength without CRC
     CByteArray& abyResponse, //modbus Response without CRC
     WORD wLengthResponse , WORD* pwNumOfBytesRead){ //wLengthResponse Response without CRC
     
     
     WORD wcrc ;
     DWORD  dwNumberOfBytesWritten;
     
     //CByteArray m_abyBuffer;
     DWORD dwNumberOfBytesRead;
     WORD wRespSize;	
     WORD wError;
     
     //Fill response 
     if (abyResponse.GetSize()<wLengthResponse) {
         abyResponse.SetSize(wLengthResponse);
     }
     
     //lock com device  
     if (!Lock()) {
         TRACE("Lock Failed");
         return(ERR_LOCK_TIME_OUT);
     }
     
     if (m_hComHandle==INVALID_HANDLE_VALUE){
         TRACE("Port Not opened"); 
         
         wError=(ERR_NOT_INT);
         goto TxRxError;
     }
     
     
     if (MODE_ASCII==m_wTranmitionMode) {
         wError=TxRxMessageAscii(abyQuery,wLengthQuery,abyResponse,wLengthResponse,pwNumOfBytesRead);
         Unlock();
         return wError;
     }
     
     //Add CRC16 to query 
     wcrc=m_crc.CalcCrcFast(abyQuery,wLengthQuery);
     
     if (abyQuery.GetSize()<(wLengthQuery+2)) {
         abyQuery.SetSize(wLengthQuery+2);
     }
     
     abyQuery[wLengthQuery]=HIBYTE(wcrc); 
     abyQuery[wLengthQuery+1]=LOBYTE(wcrc);
     
     
     if(!ClearBuffers()){
         TRACE("ClearBuffers Error");
     };
     
     //write query 
     if (!WriteQuery(abyQuery,wLengthQuery+2,dwNumberOfBytesWritten)){
         TRACE("Write Query Error");
         wError=(ERR_WR_PORT);
         goto TxRxError;
     } 
     
     
     //read response 
     m_abyBuffer.SetSize(RESP_BUFFER); //fill temp buffer 
     
     ::ZeroMemory(m_abyBuffer.GetData(),m_abyBuffer.GetSize());
     
     //if (!ReadResponse(m_abyBuffer,dwNumberOfBytesRead,wLengthResponse+2)) //using COMMTIMEOUTS
     if (!ReadResponseRTU(m_abyBuffer,dwNumberOfBytesRead)) 
     {
         TRACE("ReadResponse Failed"); 
         wError=(ERR_RD_PORT);
         goto TxRxError;
         
     }
     
     
     if (dwNumberOfBytesRead == 0){
         m_PerfCounter.End();
         wError=(ERR_TIMEOUT);
         goto TxRxError;
     }
     
     
     //Verify if ocurred modbus exception 
     if (m_abyBuffer[1]>0x80) { 
         //slave message error 
         if (!VerifyRespCRC(m_abyBuffer,3)){ //length modbus error message=3 
             wError=(ERR_CRC);
             goto TxRxError;
         }   
         else {
             wError= (ERR_EXCPTION_CODE+m_abyBuffer[2]);
             goto TxRxError;
             
         }
     }
     
     //ResponseLength not defined 
     
     if (0==wLengthResponse) {
         wRespSize=WORD(dwNumberOfBytesRead);
     }
     else {
         wRespSize=wLengthResponse;
     }
     
     //verify if response have a valid CRC 
     
     if (!VerifyRespCRC(m_abyBuffer,wRespSize)){ //length modbus error message=3 
         wError=(ERR_CRC);
         goto TxRxError;
     }   
     
     
     if (0==wLengthResponse) {
         if  (wRespSize>2) {
             wLengthResponse=(wRespSize-2);
         }
     }
     
     //Discard possible garbage read from buffer 
     
     m_abyBuffer.SetSize(wLengthResponse);
     //abyQuery.SetSize(wLengthQuery);
     
     abyResponse.Copy(m_abyBuffer);
     
     if (pwNumOfBytesRead!=NULL) {
         *pwNumOfBytesRead=wLengthResponse;
     }
     
     Unlock();
     return(ERR_OK);
     
TxRxError:
     
     if (Delay()>0) {
         ::Sleep(Delay());
     }
     
     Unlock();
     return(wError);
}

CString CLocalModbus::ErrorMessage(WORD wErrorCode){
    return CModbus::ErrorMessage(wErrorCode);
}

WORD CLocalModbus::TxRxMessageAscii(CByteArray& abyQuery, //modbus query without CRC
                                    WORD wLengthQuery, //QueryLength without CRC
                                    CByteArray& abyResponse, //modbus Response without CRC
                                    WORD wLengthResponse, //wLengthResponse Response without CRC
                                    WORD* pwNumOfBytesRead){
    
    int iBufferSize;
    int i;
    int iDataSize;
    BYTE byLRC;
    DWORD dwNumberOfBytesWritten;
    DWORD dwNumberOfBytesRead;
    WORD wError;
    
    m_abyBuffer.SetSize(wLengthQuery*2+5);
    
    iBufferSize=m_abyBuffer.GetSize();
    ::ZeroMemory(m_abyBuffer.GetData(),m_abyBuffer.GetSize());
    
    RTU2ASCII(abyQuery.GetData(),wLengthQuery,&m_abyBuffer[1]);
    
    
    //byLRC=CRC16::LRC(&m_abyBuffer[1],wLengthQuery*2);
    byLRC=CRC16::LRC(abyQuery.GetData(),wLengthQuery);

⌨️ 快捷键说明

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