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

📄 xxxopcsrvdlg.cpp

📁 一个modbus协议的opc server
💻 CPP
字号:
// XXXOPCSRVDlg.cpp : implementation file
//

#include "stdafx.h"
#include "xxxOPCSRV.h"
#include "xxxOPCSRVDlg.h"
#include "localmodbus.h"
#include "commparameters.h"
#include "eventview.h"

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

#define DEVICE_ID 1

CCriticalSection s_lkDrv;
CEventView *s_pEventView;
CLocalModbus *s_pLMBus ;

int callsvr(HINSTANCE hInstance, unsigned *nTerminate, BOOL bEmbedding, unsigned nRegister );
void LogMsg (UINT nResID, LPCSTR format, ...);
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CXXXOPCSRVDlg dialog

CXXXOPCSRVDlg::CXXXOPCSRVDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CXXXOPCSRVDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CXXXOPCSRVDlg)
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

    m_bEmbedding = FALSE;
    m_nRegister = FALSE;
    m_nTerminateThread = 0;
    m_pThread = NULL;
}

void CXXXOPCSRVDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CXXXOPCSRVDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CXXXOPCSRVDlg, CDialog)
	//{{AFX_MSG_MAP(CXXXOPCSRVDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(ID_BTN_STOP, OnBtnStop)
	ON_BN_CLICKED(IDC_BTN_START, OnBtnStart)
	ON_BN_CLICKED(IDC_BTN_SETTINGS, OnBtnSettings)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CXXXOPCSRVDlg message handlers

BOOL CXXXOPCSRVDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
    // Split this window into to two panes, one on top of the other.  Top
	// pane will be "data view", and bottowm will be "event view".  Return
	// FALSE if fail.
    
    RECT rc;
	GetClientRect (&rc);
    rc.left = 0;
    rc.top = 43;

	s_pEventView = new CEventView();
    s_pEventView->Create( 0L, "Event", WS_VISIBLE|WS_VSCROLL|WS_HSCROLL|WS_BORDER, rc, this, ID_VIEW_EVENT );

    s_pLMBus = new CLocalModbus();
    
    //Get cfg file path
    char szModule[_MAX_PATH+1] = {0};
    GetModuleFileName( AfxGetInstanceHandle(), szModule, _MAX_PATH);
    // Convert to short path 
    char szModuleShort[_MAX_PATH+1];
    GetShortPathName( szModule, szModuleShort, _MAX_PATH);
    
    char drive[_MAX_DRIVE];
    char dir[_MAX_DIR];
    char fname[_MAX_FNAME];
    char ext[_MAX_EXT];
    
    _splitpath( szModuleShort, drive, dir, fname, ext );
    _makepath( szModuleShort, drive, dir, "", "" );
    
    
    m_strCfgFile.Format( "%s%s", szModuleShort, "tsiopcsrv.cfg");
    
    //get settings from cfg file
    CFile af;
    if ( af.Open(m_strCfgFile, CFile::modeRead ) )
    {
        CArchive ar( &af, CArchive::load );
        s_pLMBus->Serialize( ar );
        ar.Close();
        af.Close();
        LogMsg( tEventInformation, "Read previous configurations OK");
    }
    else //set default value
    {
        LogMsg( tEventInformation, "Using default configuration");
    }
    //open com port
    if ( !s_pLMBus->IsActive() )
        s_pLMBus->UpdateSerialConfig( s_pLMBus->ComPort(), s_pLMBus->BaudRate(), s_pLMBus->Parity() ) ;
    if (!s_pLMBus->IsActive())
    {
        LogMsg( tEventError, "Failed to open Com%d", s_pLMBus->ComPort() );
    }
    else
    {
        LogMsg( tEventInformation, "Opened Com%d", s_pLMBus->ComPort() );
    }

    StartServer() ;
    
    if ( m_bEmbedding )
        ShowWindow( SW_MINIMIZE );

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CXXXOPCSRVDlg::StartServer( BOOL bFlag )
{
    if ( bFlag )
    {
        if ( m_pThread )
            return; //already started
        LogMsg( tEventInformation, "Server starting...");
        m_nTerminateThread = 0;
        m_pThread = AfxBeginThread( ThreadLoop, (LPVOID) this );
    }
    else
    {
        if ( !m_pThread )
            return; //not started 
        m_nTerminateThread = 1;
        LogMsg( tEventInformation, "Server aborting...");
    }
}

/////////////////////////////////////////////////////////////////////////////
UINT CXXXOPCSRVDlg::ThreadLoop(LPVOID pParam)
{
    CXXXOPCSRVDlg *pDlg = (CXXXOPCSRVDlg *)pParam;
    ASSERT( pDlg );
    
    //if ( s_pLMBus->LoopbackTest( DEVICE_ID ) )    
    //    LogMsg( tEventError, "Modbus salve device not found on Com%d", s_pLMBus->ComPort() );
    //enter service loop
	callsvr( AfxGetInstanceHandle(), &(pDlg->m_nTerminateThread), pDlg->m_bEmbedding, pDlg->m_nRegister );


    //release resources
    pDlg->m_pThread = NULL;
    pDlg->PostMessage( WM_CLOSE );
    return 0;
}

void CXXXOPCSRVDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CXXXOPCSRVDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}


// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CXXXOPCSRVDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

//driver functions called by opc server
WORD GetDrvData( WORD nAddr,  WORD nPDU, WORD nPos, WORD *pData )
{
    ASSERT ( s_pLMBus );

    CSafeLock sf (&s_lkDrv);

    WORD wErr = 0;

    switch( nPDU )
    {
    case 1:
        {
            BYTE ba;
            CByteArray ary;
            ary.Add( ba );
            wErr = s_pLMBus->ReadOutputStatus( nAddr, nPos, 1, ary );
            *pData = ary[0];
        }
        break;
    case 2:
        {
            BYTE ba;
            CByteArray ary;
            ary.Add( ba );
            wErr = s_pLMBus->ReadInputStatus( nAddr, nPos, 1, ary );
            *pData = ary[0];
        }
        break;
    case 3:
        {
            WORD wa;
            CWordArray ary;
            ary.Add( wa );
            wErr = s_pLMBus->ReadOutputRegisters( nAddr, nPos, 1, ary );
            *pData = ary[0];
        }
        break;
    case 4:
        {
            WORD wa;
            CWordArray ary;
            ary.Add( wa );
            wErr = s_pLMBus->ReadInputRegisters( nAddr, nPos, 1, ary );
            *pData = ary[0];
        }
        break;
    default: 
        wErr = 1;
    }
    return (wErr == 0);
}

WORD GetDrvData10( WORD nAddr,  WORD nPDU, WORD nPos, WORD *pData )
{
    ASSERT ( s_pLMBus );

    CSafeLock sf (&s_lkDrv);

    WORD wErr = 0;
#define nCount  10
    switch( nPDU )
    {
    case 1:
        {
            BYTE ba[nCount];
            CByteArray ary;
            for (int i = 0 ; i < nCount; i++ )
                ary.Add( ba[i] );
            wErr = s_pLMBus->ReadOutputStatus( nAddr, nPos, nCount, ary );
            for ( i = 0 ; i < nCount; i++ )
                *pData++ = ary[i];
        }
        break;
    case 2:
        {
            BYTE ba[nCount];
            CByteArray ary;
            for (int i = 0 ; i < nCount; i++ )
                ary.Add( ba[i] );
            wErr = s_pLMBus->ReadInputStatus( nAddr, nPos, nCount, ary );
            for ( i = 0 ; i < nCount; i++ )
                *pData++ = ary[i];
        }
        break;
    case 3:
        {
            WORD wa[nCount];
            CWordArray ary;
            for (int i = 0 ; i < nCount; i++ )
                ary.Add( wa[i] );
            wErr = s_pLMBus->ReadOutputRegisters( nAddr, nPos, nCount, ary );
            for ( i = 0 ; i < nCount; i++ )
                *pData++ = ary[i];
        }
        break;
    case 4:
        {
            WORD wa[nCount];
            CWordArray ary;
            for (int i = 0 ; i < nCount; i++ )
                ary.Add( wa[i] );
            wErr = s_pLMBus->ReadInputRegisters( nAddr, nPos, nCount, ary );
            for ( i = 0 ; i < nCount; i++ )
                *pData++ = ary[i];
        }
        break;
    default: 
        wErr = 1;
    }
    return (wErr == 0);
}

BOOL SetDrvData( WORD nAddr,  WORD nPDU, WORD nPos, WORD wA )
{
    ASSERT ( s_pLMBus );

    CSafeLock sf (&s_lkDrv);

    WORD wErr = 0;
    switch( nPDU )
    {
    case 1:
        {
            wErr = s_pLMBus->ForceSingleCoil( nAddr, nPos, wA == 0 ? 0 : 1 );
        }
        break;
    case 3:
        {
            wErr = s_pLMBus->PresetSingleRegister( nAddr, nPos, wA );
        }
        break;
    
    default: 
        return 1;
    }
    return (wErr == 0);
}


void CXXXOPCSRVDlg::OnBtnStop() 
{
	// TODO: Add your control notification handler code here
	StartServer( FALSE );
}

void CXXXOPCSRVDlg::OnBtnStart() 
{
	// TODO: Add your control notification handler code here
	StartServer();
}

void CXXXOPCSRVDlg::OnCancel() 
{
    if ( !m_bEmbedding && s_pLMBus || m_pThread )
	    if ( !(AfxMessageBox("Server is running, Exit anyway?", MB_OKCANCEL) == IDOK) )
            return;
    m_nTerminateThread = 1;
    
    //waitting for termination of service
    UINT nTick = GetTickCount();
    while ( m_pThread && ( GetTickCount() - nTick < 1000 ))
        Sleep( 20 );

    delete s_pLMBus;
    delete s_pEventView;

    CDialog::OnCancel();
}

void CXXXOPCSRVDlg::OnBtnSettings() 
{
	// TODO: Add your control notification handler code here
    if ( !s_pLMBus )
        return;
	CCommParameters dlgSetting;
    dlgSetting.m_pLModbus = s_pLMBus;
    if ( dlgSetting.DoModal() == IDOK )
    {
        //save settings to cfg file
        CFile af;
        if ( af.Open( m_strCfgFile, CFile::modeCreate | CFile::modeWrite ) )
        {
            CArchive ar( &af, CArchive::store );
            s_pLMBus->Serialize( ar );
            AfxMessageBox("To ensure that changes take effect, please restart server.");
            ar.Close();
            af.Close();
        }
        else
            AfxMessageBox("Failed to save changes.");
        
    }
}


void LogMsg (UINT nResID, LPCSTR format, ...)
{
    ASSERT( s_pEventView );

    va_list data;
    char cMsgBuffer[ MAX_PATH ];
    
    va_start(data, format);
    int msgLen =_vsnprintf(cMsgBuffer, MAX_PATH-3, format, data);
    if (msgLen == -1)
        return ;

    
    // Add the message to the queue.
    
    s_pEventView->LogMsg ((EVENTTYPE)nResID, cMsgBuffer);
    
    // Reset additional arguments pointer:
    va_end(data);
}

BOOL CXXXOPCSRVDlg::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) 
{
	// re-direct menu messages to event view
    if (( nID == ID_VIEW_CLEAR || nID == ID_VIEW_ERRORONLY) && !nCode )
	    s_pEventView->SendMessage( WM_COMMAND, nID, 0L );
	return CDialog::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}


⌨️ 快捷键说明

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