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

📄 opcsvr.cpp

📁 一个modbus协议的opc server
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/**************************************************************************
*                                                                        *
* XXX OPC Server development library                                     *
*                                                                        *
**************************************************************************/

#define _WIN32_DCOM
#include <windows.h>
#include "unilog.h"
#define LOGID log,0
#include <ole2.h>
#include <olectl.h>
#include <oleauto.h>
#include <process.h>
#include <stdio.h>
#include <errno.h>
#include <locale.h>
#include "opcda.h"
#include "opcerror.h"
#include "lightopc.h"

#define DEVICE_ID 1

WORD GetDrvData( WORD nAddr,  WORD nPDU, WORD nPos, WORD *pData );
BOOL SetDrvData( WORD nAddr,  WORD nPDU, WORD nPos, WORD wA );
WORD GetDrvData10( WORD nAddr,  WORD nPDU, WORD nPos, WORD *pData );
void LogMsg (UINT nResID, LPCSTR format, ...);

unilog *log;                    /* logging entry */
int use_console = 0;

/********************* OPC vendor info ***************************************/
static const loVendorInfo vendor = {
    0 /*Major */ , 1 /*Minor */ , 1 /*Build */ , 0 /*Reserv */ ,
        "XXX Inc."
};

loService *my_service;
static int driver_init(int lflags);
static void driver_destroy(void);
static void work_loop(unsigned pause, unsigned *nTerminate);

// {4EA2713D-CA07-11d4-BEF5-00002120DB5C}   exe-server
static const GUID CLSID_XXXOPCServerEXE ={ 0x4ea2713d, 0xca07, 0x11d4, {0xbe, 0xf5, 0x0, 0x0, 0x21, 0x20, 0xdb,0x5c} };

/**** Server Counting stuff & OLE ICF implementation *****************************
The IClassFactory is unavoidable evil. Feel free to go ahead.
Basically we've to unload when the server_count being zero.
But there are different techniques for in-/out-of- proc servers.
*/

class myClassFactory: public IClassFactory
{
public:
    int  is_out_of_proc, 
        server_inuse; /* go 0 when unloading initiated */
    LONG server_count;
    CRITICAL_SECTION lk_count;  /* protect server_count */
    
    myClassFactory(): is_out_of_proc(0), server_inuse(0), server_count(0)
    {
        InitializeCriticalSection(&lk_count);
    }
    ~myClassFactory()
    {
        DeleteCriticalSection(&lk_count);
    }
    
    void serverAdd(void);
    void serverRemove(void);
    
    /* Do nothing: we're static, he-he */  
    STDMETHODIMP_(ULONG) AddRef(void) { return 1; }
    STDMETHODIMP_(ULONG) Release(void) { return 1; }
    
    STDMETHODIMP QueryInterface(REFIID iid, LPVOID *ppInterface)
    {
        if (ppInterface == NULL)
            return E_INVALIDARG;
        if (iid == IID_IUnknown || iid == IID_IClassFactory)
        {
            UL_DEBUG((LOGID, "myClassFactory::QueryInterface() Ok"));
            *ppInterface = this;
            AddRef();
            return S_OK;
        }
        UL_DEBUG((LOGID, "myClassFactory::QueryInterface() Failed"));
        *ppInterface = NULL;
        return E_NOINTERFACE;
    }
    
    STDMETHODIMP LockServer(BOOL fLock)
    {
        UL_DEBUG((LOGID, "myClassFactory::LockServer(%d)", fLock));
        if (fLock) serverAdd();
        else serverRemove();
        return S_OK;
    }
    
    STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid,
        LPVOID *ppvObject);
    
};

static myClassFactory my_CF;

void myClassFactory::serverAdd(void)
{
    EnterCriticalSection(&lk_count);
    if (is_out_of_proc) CoAddRefServerProcess();  
    ++server_count;
    LeaveCriticalSection(&lk_count);
}

void myClassFactory::serverRemove(void)
{
    EnterCriticalSection(&lk_count);
    if (is_out_of_proc)
    {
        if (0 == CoReleaseServerProcess())
            server_inuse = 0;
    }
    if (0 == --server_count && server_inuse) server_inuse = 0;
    LeaveCriticalSection(&lk_count);
}

static void a_server_finished(void *arg, loService *b, loClient *c)
{
    /* ARG is the same as we've passed to loClientCreate() */
    UL_DEBUG((LOGID, "a_server_finished(%lu)...", my_CF.server_count));
    my_CF.serverRemove();
    
    /* OPTIONAL: */
    UL_INFO((LOGID, "a_server_finished(%lu) USERID=<%ls>",
        my_CF.server_count, arg? arg: L"<null>"));
    
    LogMsg( 0, "-Detaching a client. USERID: <%ls>", arg? arg: L"<null>");
}

//static void dll_simulator_wait(void); /* in-proc specefic */
//static void dll_simulator_start(void); /* in-proc specefic */

STDMETHODIMP myClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid,
                                            LPVOID *ppvObject)
{
    IUnknown *server = 0;
    HRESULT hr = S_OK;
    
    /* OPTIONAL: security stuff */
    OLECHAR *userid = 0;
    wchar_t *cuserid;
    LONG userno;
    static LONG usercount;
    
    userno = InterlockedIncrement(&usercount);
    
    CoQueryClientBlanket(0, 0, 0, 0, 0, (RPC_AUTHZ_HANDLE*)&userid, 0);
    if (!userid) userid = L"{unknown}";
    
    UL_WARNING((LOGID, "USER:#%ld <%ls>", userno, userid));
    LogMsg( 0, "+Attaching a client #%ld. USERID: <%ls>", usercount, userid);
    
    if (cuserid = (wchar_t*)malloc((wcslen(userid) + 16) * sizeof(wchar_t)))
        swprintf(cuserid, L"#%ld %ls", userno, userid);
    /* -- end of security stuff */
    
    if (pUnkOuter)
    {
#if 1 /* Do we support aggregation? */
        if (riid != IID_IUnknown) 
#endif
            return CLASS_E_NOAGGREGATION;
    }
    
    serverAdd();  /* the lock for a_server_finished() */
    
    /***********************************************
     * check other conditions (i.e. security) here *
    ***********************************************/
    
    if (0 == server_inuse) /* we're stopped */
    {                    /* stopping initiated when there are no active instances */
        if (is_out_of_proc) 
        {                /* a stopped EXE should exit soon and can't work anymore */
            UL_MESSAGE((LOGID, "myClassFactory:: Server already finished"));
            serverRemove();
            return E_FAIL;
        }
    }
    {
        IUnknown *inner = 0;
        if (loClientCreate_agg(my_service, (loClient**)&server, 
            pUnkOuter, &inner,
            0, &vendor, a_server_finished, cuserid/*this*/))
        {
            serverRemove();
            hr = E_OUTOFMEMORY;
            UL_MESSAGE((LOGID, "myClassFactory::loClientCreate_agg() failed"));
        }
        else if (pUnkOuter) *ppvObject = (void*)inner; /*aggregation requested*/
        else /* no aggregation */
        {
        /* loClientCreate(my_service, (loClient**)&server, 
            0, &vendor, a_server_finished, cuserid) - with no aggregation */
            /* Initally the created SERVER has RefCount=1 */
            hr = server->QueryInterface(riid, ppvObject); /* Then 2 (if success) */
            server->Release(); /* Then 1 (on behalf of client) or 0 (if QI failed) */
            if (FAILED(hr)) 
                UL_MESSAGE((LOGID, "myClassFactory::loClient QueryInterface() failed"));
            /* So we shouldn't carry about SERVER destruction at this point */
        }
    }
    if (SUCCEEDED(hr))
    {
        loSetState(my_service, (loClient*)server,
            loOP_OPERATE, (int)OPC_STATUS_RUNNING, /* other states are possible */
            "Finished by client");
        UL_DEBUG((LOGID, "myClassFactory::server_count = %ld", server_count));
    }
    
    return hr;
}

/************************* The END of OLE-specific ***************************/

/****************** The Process Data to be exported via OPC ******************
(driver's internal representation) */

static CRITICAL_SECTION lk_values;     /* protects ti[] from simultaneous 
access by workloop() and WriteTags() */
/* Our data tags: */
/* zero is resierved for an invalid RealTag */

#define TI_output_coil      (1)
#define TI_input_status      (2)
#define TI_holding_register (3)
#define TI_input_register    (4)

#define TI_MAX       (255)

static loTagId ti[TI_MAX + 1];          /* their IDs */
static const char *ttn = "MICROLOGIX";
static const char *tcn[5] =     /* their names */
{ "--not--used--", "coil", "status", "holdregs", "inputregs" };
static loTagValue tv[TI_MAX + 1];       /* their values */
static BOOL ta[TI_MAX + 1];       /* their active/inactive */
static unsigned tg[TI_MAX + 1]; /* their groups, 1, 2, 3, 4 -- "coil", "status", "holdregs", "inputregs" */
static unsigned tin[TI_MAX + 1]; /* their index in group, 0 based */
static unsigned tnum[] =  //numbers of tags, should be the times of 10
{   0,      /* not used */
    30,     /* coils */
    30,     /* status */
    60,     /* holding registers */
    30      /* input registers */
};
/**********************************************************************
            server initiation & simulation
**********************************************************************/

/* OPTIONAL: show client's interests */

void activation_monitor(const loCaller *ca, int count, loTagPair *til)
{
    int act = 1;
    if (0 > count)
        act = 0, count = -count;
    while(count--)
    {
        ta[(int) til[count].tpRt] = act ? TRUE : FALSE;
        UL_DEBUG((LOGID, "MON: %u %s %s", til[count].tpTi,
            tv[(int) til[count].tpRt], act ? "On" : "Off"));
        //tn[(int) til[count].tpRt], act ? "On" : "Off"));
    }
}


/* OPTIONAL: write back to the device */

int WriteTags(const loCaller *ca,
              unsigned count, loTagPair taglist[],
              VARIANT values[], HRESULT error[], HRESULT *master, LCID lcid)
{
    unsigned ii;
    UL_TRACE((LOGID, "WriteTags(%x) invoked"));
    
    EnterCriticalSection(&lk_values);
    
    for(ii = 0; ii < count; ii++)
    {
        HRESULT hr = S_OK;
        loTagId clean = 0;
        
        int i = (int)taglist[ii].tpRt;
        if ( i > 0 && i <= TI_MAX )
        {
            hr = VariantChangeType(&tv[i].tvValue, &values[ii], 0, VT_I2);
            if (S_OK == hr)
                lo_statperiod(V_I2(&tv[i].tvValue)); /* VERY OPTIONAL, really */
            if ( !SetDrvData( DEVICE_ID, tg[i], tin[i], tv[i].tvValue.iVal ) )
            {
                *master = S_FALSE;
                error[ii] = S_FALSE;

                LogMsg( 1, "Failed to WriteTags(Rt=%u Ti=%u %s%02d)", 
                  taglist[ii].tpRt, taglist[ii].tpTi, 
                  tcn[tg[i]], tin[i]);
            }
        }    
        if (S_OK != hr) 
        {
            *master = S_FALSE;
            error[ii] = hr;
        }
        
        taglist[ii].tpTi = clean; /* clean if ok */
    }
    
    LeaveCriticalSection(&lk_values);
    
    return loDW_TOCACHE; /* put to the cache all tags unhandled here */
    // loDW_ALLDONE; 
}

/* OPTIONAL: example of non-trivial datatype conversion */


void ConvertTags(const loCaller *ca,
                 unsigned count, const loTagPair taglist[],
                 VARIANT *values, WORD *qualities, HRESULT *errs,
                 HRESULT *master_err, HRESULT *master_qual,
                 const VARIANT src[], const VARTYPE vtypes[], LCID lcid)
{
    unsigned ii;
    
    for(ii = 0; ii < count; ii++)
    {
        HRESULT hr = S_OK;
        VARTYPE reqtype = vtypes[ii];
        if (reqtype == VT_EMPTY) reqtype = V_VT(&src[ii]);
        
        switch((int)taglist[ii].tpRt)
        {
        case 0: /* ignore */
            break;
/*          
        case TI_array:
            if (V_VT(&src[ii]) == reqtype)
            {
                hr = values == src? S_OK : VariantCopy(&values[ii], (VARIANT*)&src[ii]);
            }
            else 
            { 
                hr = lo_variant_changetype_array(&values[ii], 
                    (VARIANT*)&src[ii], lcid, 0, reqtype);
            }
            break;
            
*/          
        default:
            if (reqtype == V_VT(&src[ii]))
            {
                if (values == src) hr = S_OK;
                else hr = VariantCopy(values + ii, (VARIANT*)&src[ii]);
            }
            else
                hr = VariantChangeType(values + ii, (VARIANT*)&src[ii], 0, reqtype);
            
            UL_ERROR((LOGID, "ConvII NotRequested(%u %u)[%u/%u]", 
                taglist[ii].tpRt, taglist[ii].tpTi, ii, count));
            break;
        } /* end of switch( */
        
        if (S_OK != hr)
        {
            errs[ii] = hr;
            qualities[ii] = OPC_QUALITY_BAD;
            *master_err = *master_qual = S_FALSE;
            
//          UL_WARNING((LOGID, "%!l ConvII Error(Rt=%u Ti=%u %s)[%u/%u]", 
//              hr, taglist[ii].tpRt, taglist[ii].tpTi, 
//              tn[(int)taglist[ii].tpRt <= TI_MAX? (int)taglist[ii].tpRt: 0],
//              ii, count));
        }
    } /* end of for(...*/
}

/* OPTIONAL: DS_DEVICE read(). */

loTrid ReadTags(const loCaller *ca,
                unsigned count, loTagPair taglist[],
                VARIANT *values, WORD *qualities,
                FILETIME *stamps, HRESULT *errs,
                HRESULT *master_err, HRESULT *master_qual,
                const VARTYPE vtypes[], LCID lcid)
{
    UL_TRACE((LOGID, "ReadTags( ) invoked"));
    EnterCriticalSection(&lk_values);
    
    unsigned ii = 0;
    FILETIME ft;
    GetSystemTimeAsFileTime(&ft); 
    for(ii = 0; ii < count; ii++)
    {
        loTagId clean = 0;
        
        int i = (int)taglist[ii].tpRt;
        if ( i > 0 && i < TI_MAX )
        {
            WORD wa=0;
            if ( GetDrvData( DEVICE_ID, tg[i], tin[i], &wa ))
            {
                V_I2(&tv[i].tvValue) = (short)wa;
                V_VT(&tv[i].tvValue) = VT_I2;
                tv[i].tvState.tsQuality = OPC_QUALITY_GOOD;
                tv[i].tvState.tsError = S_OK;
                tv[i].tvState.tsTime = ft;
            }
            else
            {
                V_VT(&tv[i].tvValue) = VT_EMPTY;

⌨️ 快捷键说明

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