📄 sample.cpp
字号:
/* OPTIONAL: example of DS_DEVICE read(). It enforces significant delay,
sufficient for view request's queueing and test the cancellation. */
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"));
Sleep(33333); /* just for Cancel() testing */
return loDR_CACHED; /* perform actual reading from cache */
}
/* OPTIONAL: example of dynamic tag creation */
HRESULT AskItemID(const loCaller *ca, loTagId *ti,
void **acpa, const loWchar *itemid,
const loWchar *accpath, int vartype, int goal) /* Dynamic tags */
{
HRESULT hr = S_OK;
VARIANT var;
VariantInit(&var);
V_R4(&var) = 3; /* God likes 3 */
V_VT(&var) = VT_R4;
UL_NOTICE((LOGID, "AskItemID %ls type = %u(0x%x)", itemid, vartype, vartype));
if (VT_EMPTY != vartype) /* check conversion */
hr = VariantChangeType(&var, &var, 0, vartype);
if (S_OK == hr) /* we got a value of requested type */
{
int rv;
rv =
loAddRealTag_aW(ca->ca_se, ti, 0, itemid, 0,
OPC_READABLE | OPC_WRITEABLE, &var, 0, 100);
if (rv)
{
if (rv == EEXIST) *ti = 0; /* Already there? - Use existing one! */
else hr = E_OUTOFMEMORY;
}
}
VariantClear(&var);
return hr;
}
/******* ******* ******* ******* ******* ******* ******* *******/
int driver_init(int lflags)
{
loDriver ld;
VARIANT var;
loTagId tti;
int ecode;
setlocale(LC_CTYPE, "");
if (my_service)
{
UL_ERROR((LOGID, "Driver already initialized!"));
return 0;
}
memset(&ld, 0, sizeof(ld)); /* basic server parameters: */
// ld.ldRefreshRate = 3;//10;
ld.ldSubscribe = activation_monitor;
ld.ldWriteTags = WriteTags;
// ld.ldReadTags = ReadTags;
ld.ldConvertTags = ConvertTags;
#if 0
ld.ldAskItemID = AskItemID;
#endif
ld.ldFlags = lflags | loDF_IGNCASE | /*loDf_FREEMARSH | loDf_BOTHMODEL | */
/*loDF_NOCOMP| */ loDf_NOFORCE & 0 /*| loDF_SUBSCRIBE_RAW*/;
/*Fix the Bug in ProTool *//*|loDF_IGNCASE */ ;
ld.ldBranchSep = '/'; /* Hierarchial branch separator */
ecode = loServiceCreate(&my_service, &ld, 64 /* number of tags in the cache */);
/* 500000 is ok too */
UL_TRACE((LOGID, "%!e loCreate()=", ecode));
if (ecode) return -1;
InitializeCriticalSection(&lk_values);
memset(tv, 0, sizeof(tv)); /* instead of VariantInit() for each of them */
VariantInit(&var);
/* OPTIONAL: Tags creation. Do you need a few tags? */
ecode = loAddRealTag_b(my_service, /* actual service context */
&tti, /* returned TagId */
0, /* != 0 driver's key */
"Just the hint / [0...999]", /* tag name (hint) */
0, /* loTF_ Flags */
OPC_READABLE | OPC_WRITEABLE, 0);
V_I1(&var) = -1; /* the good practice: set the value first, then type. */
V_VT(&var) = VT_I1; /* Do you know why? */
ecode = loAddRealTag_a(my_service,
&ti[TI_bandwidth], /* returned TagId (lightopc's identifier)*/
(loRealTag)TI_bandwidth, /* != 0 (driver's internal identifier)*/
tn[TI_bandwidth], /* tag name */
0, /* loTF_ Flags */
OPC_READABLE, /* OPC access rights */
&var, /* type and value for conversion checks */
-1, 101); /*Analog EUtype: from -1 (unknown) to 101% (overload)*/
/* Shows current bandwidth */
/* We needn't to VariantClear() for simple datatypes like numbers */
V_R8(&var) = 214.1; /* initial value. Will be used to check types conersions */
V_VT(&var) = VT_R8;
ecode = loAddRealTag_a(my_service, /* actual service context */
&ti[TI_zuzu], /* returned TagId */
(loRealTag)TI_zuzu, /* != 0 driver's key */
tn[TI_zuzu], /* tag name */
0, /* loTF_ Flags */
OPC_READABLE | OPC_WRITEABLE, &var, 12., 1200.);
UL_TRACE((LOGID, "%!e loAddRealTag_a(zuzu) = %u ", ecode, ti[TI_zuzu]));
V_I2(&var) = 1000;
V_VT(&var) = VT_I2;
ecode = loAddRealTag(my_service, /* actual service context */
&ti[TI_lulu], /* returned TagId */
(loRealTag) TI_lulu, /* != 0 driver's key */
tn[TI_lulu], /* tag name */
0, /* loTF_ Flags */
OPC_READABLE | OPC_WRITEABLE, &var, 0, 0);
UL_TRACE((LOGID, "%!e loAddRealTag(lulu) = %u ", ecode, ti[TI_lulu]));
/* This 2nd 'zuzu' will fail with EEXISTS */
ecode = loAddRealTag(my_service,
&tti, /* returned TagId */
(loRealTag) TI_zuzu, /* != 0 driver's key */
"zuzu", /* tag name */
0, /* loTF_ Flags */
OPC_READABLE | OPC_WRITEABLE, &var, 0, 0);
UL_TRACE((LOGID, "%!e loAddRealTag(zuzu) = %u (duplicated)", ecode, tti));
#if 1 /* OPTIONAL: generate several tags to test capabilites & performance */
{
char name[64];
int ii, sep;
DWORD sttime = GetTickCount();
memset(name, 0, sizeof(name));
strcpy(name, "A Huge list /");
ii = strlen(name);
memset(name + ii, 'Z', 32 - ii);
for(ecode = 0, sep = '-'; *name <= 'B'; sep = '/', (*name)++)
{
for(ii = 0; ii < 4 /*0000 */ && !ecode; ii++)
{
loTagId tt;
sprintf(name + 32, ".%010u%c@", ii, sep);
ecode = loAddRealTag_b(my_service,
&tt, 0, name, 0, OPC_READABLE,
ti[TI_bandwidth]);
/* loAddRealTag_b() inherits attributes of specified tag - ti[TI_bandwidth] */
}
UL_WARNING((LOGID, "%u tags created for %d mS",
ii * (*name - 'A' + 1), GetTickCount() - sttime));
}
}
#endif
loAddRealTag(my_service, &ti[TI_quiet], (loRealTag) TI_quiet, tn[TI_quiet],
0, OPC_READABLE, &var, 0, 0);
loAddRealTag(my_service, &tti, 0, "wr-only", 0, OPC_WRITEABLE, &var, 0, 0);
/* OPTIONAL: Create some Hierachial structure: */
#define ADD_TAG(name) loAddRealTag_b(my_service, &tti, \
0, name, 0,\
OPC_READABLE|OPC_WRITEABLE, tti)
ADD_TAG("Tree/qw/qq");
ADD_TAG("Tree/qw/zz");
ADD_TAG("Tree/qw/ii/hh");
ADD_TAG("Tree/qw/ii/yy");
ADD_TAG("Tree/qw/ii/yy/mm/dd");
ADD_TAG("Tree/eec/ii/yy/mMm/dd");
ADD_TAG("Tree/eec/ii/yy/mMm/ddd");
ADD_TAG("Tree/ee/ii/yy/mm/dd");
ADD_TAG("Tree/ee/ii/yyy/mm/dd");
/* OPTIONAL: Advanced Item Properies: defining and assignement */
{
loPLid plid;
if (0 == (plid = loPropListCreate(my_service)))
{
UL_WARNING((LOGID, "loPropListCreate() FAILED"));
}
else
{
V_R8(&var) = 999.9;
V_VT(&var) = VT_R8;
if (loPropertyAdd(my_service, plid, 102, &var, 0, 0) ||
loPropertyAdd(my_service, plid, 5001, 0, "/Two", 0) ||
loPropertyAdd(my_service, plid, 5002, 0, "//Two", 0) ||
loPropertyAdd(my_service, plid, 5003, 0, "Two",
"a Custom property Two"))
{
UL_WARNING((LOGID, "loPropertyAdd() FAILED"));
}
ADD_TAG("device/port/one/Two");
loPropListAssign(my_service, plid, tti, 1);
ADD_TAG("device/port/one");
loPropListAssign(my_service, plid, tti, 1);
ADD_TAG("device/port/Two");
loPropListAssign(my_service, plid, tti, 1);
ADD_TAG("device/port");
loPropListAssign(my_service, plid, tti, 1);
ADD_TAG("device/Two");
loPropListAssign(my_service, plid, tti, 1);
ADD_TAG("device");
loPropListAssign(my_service, plid, tti, 1);
ADD_TAG("Two");
loPropListAssign(my_service, plid, tti, 1);
}
}
#undef ADD_TAG
#if 1 /* OPTIONAL: Creation of complex datatypes */
{
SAFEARRAY *sa;
SAFEARRAYBOUND sbound[1];
sbound[0].lLbound = 0;
sbound[0].cElements = 2;
/*** VT_ARRAY type */
VariantInit(&tv[TI_array].tvValue);
if (sa = SafeArrayCreate(VT_I4, 1, sbound))
{
HRESULT hr;
long ix0 = 0, ix1 = 1, val = 333;
V_ARRAY(&tv[TI_array].tvValue) = sa;
V_VT(&tv[TI_array].tvValue) = VT_ARRAY | VT_I4;
if (S_OK != (hr = SafeArrayPutElement(sa, &ix0, &val)) ||
S_OK != (hr = SafeArrayPutElement(sa, &ix1, &val)))
{
UL_NOTICE((LOGID, "%!l SafeArray", hr));
VariantClear(&tv[TI_array].tvValue);
}
else
if (!loAddRealTag(my_service, &ti[TI_array],
(loRealTag)TI_array, tn[TI_array],
loTF_CONVERT, OPC_READABLE | OPC_WRITEABLE,
&tv[TI_array].tvValue, 0, 0))
{
tv[TI_array].tvTi = ti[TI_array];
tv[TI_array].tvState.tsError = S_OK;
tv[TI_array].tvState.tsQuality = OPC_QUALITY_GOOD;
}
}
else
{
UL_ERROR((LOGID, "driver_init(): SafeArrayCreate() failed"));
}
/*** An enumerated type (localized weekdays names) with EUinfo ***/
sbound[0].lLbound = 0;
sbound[0].cElements = 7;
VariantInit(&tv[TI_enum].tvValue);
V_I2(&tv[TI_enum].tvValue) = 6;
V_VT(&tv[TI_enum].tvValue) = VT_I2;
if (sa = SafeArrayCreate(VT_BSTR, 1, sbound))
{
VARIANT ed;
VariantInit(&ed);
long ix;
V_VT(&ed) = VT_ARRAY | VT_BSTR;
V_ARRAY(&ed) = sa;
for(ix = 0; ix < 7; ix++)
{
HRESULT hr;
BSTR bs;
WCHAR ws[32];
local_text(ws, (unsigned)ix, 0); /* generates localized name */
bs = SysAllocString(ws);
if (S_OK != (hr = SafeArrayPutElement(sa, &ix, bs)))
{
UL_NOTICE((LOGID, "%!l SafeArray PutString", hr));
}
SysFreeString(bs);
}
if (!loAddRealTag(my_service, &ti[TI_enum], (loRealTag) TI_enum,
tn[TI_enum], loTF_CONVERT/*localization request*/,
OPC_READABLE, &tv[TI_enum].tvValue, OPC_ENUMERATED, &ed))
{
tv[TI_enum].tvTi = ti[TI_enum];
tv[TI_enum].tvState.tsError = S_OK;
tv[TI_enum].tvState.tsQuality = OPC_QUALITY_GOOD;
}
VariantClear(&ed);
}
else
{
UL_ERROR((LOGID, "driver_init(): SafeArrayCreate(enum) failed"));
}
}
#endif
/*** Show differnt OPC-Qualities ***/
V_BSTR(&tv[TI_quality].tvValue) = SysAllocString(L"");
V_VT(&tv[TI_quality].tvValue) = VT_BSTR;
ecode = loAddRealTag(my_service, &ti[TI_quality],
(loRealTag) TI_quality, tn[TI_quality],
0, OPC_READABLE | OPC_WRITEABLE,
&tv[TI_quality].tvValue, 0, 0);
/*** STRING (VT_BSTR) datatype ***/
V_BSTR(&tv[TI_string].tvValue) = SysAllocString(L"");
V_VT(&tv[TI_string].tvValue) = VT_BSTR;
ecode = loAddRealTag(my_service, &ti[TI_string],
(loRealTag) TI_string, tn[TI_string],
0, OPC_READABLE | OPC_WRITEABLE,
&tv[TI_string].tvValue, 0, 0);
// VariantClear(&var);
/* don't required because we didn't assigned complex types to var */
return 0;
}
void driver_destroy(void)
{
if (my_service)
{
int ecode = loServiceDestroy(my_service);
UL_INFO((LOGID, "%!e loDelete(%p) = ", ecode));
for(ecode = 0; ecode < sizeof(tv) / sizeof(tv[0]); ecode++)
VariantClear(&tv[ecode].tvValue);
DeleteCriticalSection(&lk_values);
my_service = 0;
}
}
/********* Data simulator stuff ************************************************/
void simulate(unsigned pause)
{
DWORD hitime = 0;
unsigned starttime = GetTickCount();
UL_WARNING((LOGID, "Simulator Started..."));
EnterCriticalSection(&lk_values);
/* Set up initial values for the tags we didn't initialized in driver_init(): */
tv[TI_zuzu].tvTi = ti[TI_zuzu];
tv[TI_zuzu].tvState.tsError = S_OK;
tv[TI_zuzu].tvState.tsQuality = OPC_QUALITY_GOOD;
V_VT(&tv[TI_zuzu].tvValue) = VT_R8;
V_R8(&tv[TI_zuzu].tvValue) = -100;
tv[TI_lulu].tvTi = ti[TI_lulu];
tv[TI_lulu].tvState.tsError = S_OK;
tv[TI_lulu].tvState.tsQuality = OPC_QUALITY_GOOD;
V_VT(&tv[TI_lulu].tvValue) = VT_I2;
V_I2(&tv[TI_lulu].tvValue) = 78;
tv[TI_enum].tvTi = ti[TI_enum];
tv[TI_enum].tvState.tsError = S_OK;
tv[TI_enum].tvState.tsQuality = OPC_QUALITY_GOOD;
V_VT(&tv[TI_enum].tvValue) = VT_I2;
V_I2(&tv[TI_enum].tvValue) = 1;
tv[TI_bandwidth].tvTi = ti[TI_bandwidth];
tv[TI_bandwidth].tvState.tsError = S_OK;
tv[TI_bandwidth].tvState.tsQuality = OPC_QUALITY_GOOD;
V_VT(&tv[TI_bandwidth].tvValue) = VT_I1;
V_I1(&tv[TI_bandwidth].tvValue) = -1;
tv[TI_quiet].tvTi = ti[TI_quiet];
tv[TI_quiet].tvState.tsError = S_OK;
tv[TI_quiet].tvState.tsQuality = OPC_QUALITY_LAST_KNOWN;
V_VT(&tv[TI_quiet].tvValue) = VT_I2;
V_I2(&tv[TI_quiet].tvValue) = 1412;
tv[TI_quality].tvTi = ti[TI_quality];
tv[TI_quality].tvState.tsError = S_OK;
// tv[TI_quality].tvValue -- already assigned
tv[TI_string].tvTi = ti[TI_string];
tv[TI_string].tvState.tsQuality = OPC_QUALITY_GOOD;
tv[TI_string].tvState.tsError = S_OK;
// tv[TI_string].tvValue -- already assigned
// tv[TI_enum], tv[TI_array], string, quality, -- already assigned
LeaveCriticalSection(&lk_values);
/**** Then do simulate ***********/
while(0 != my_CF.server_inuse) /* still working? */
{
FILETIME ft;
Sleep(10); /* main delay */
GetSystemTimeAsFileTime(&ft); /* awoke */
/* OPTIONAL: reload log's configuration fromtime to time */
if (hitime != (ft.dwLowDateTime & 0xf8000000)) /* 13.5 sec */
{ /* 0xff000000 is about 1.67 sec */
hitime = ft.dwLowDateTime & 0xf8000000;
#if 0
unilog_Refresh(0); /* all logs */
#else
unilog_Refresh("LightOPC");
unilog_Refresh("Lopc-Sample-exe");
unilog_Refresh("Lopc-Sample-dll");
#endif
}
/***** The main job: update the values ******/
EnterCriticalSection(&lk_values);
double zuzu =
(V_R8(&tv[TI_zuzu].tvValue) += 1./3.); /* main simulation */
V_VT(&tv[TI_zuzu].tvValue) = VT_R8;
tv[TI_zuzu].tvState.tsTime = ft;
V_I2(&tv[TI_lulu].tvValue) = (short)zuzu;
V_VT(&tv[TI_lulu].tvValue) = VT_I2;
tv[TI_lulu].tvState.tsTime = ft;
V_I2(&tv[TI_enum].tvValue) = (short)((ft.dwLowDateTime >> 22) % 7);
V_VT(&tv[TI_enum].tvValue) = VT_I2;
tv[TI_enum].tvState.tsTime = ft;
V_I1(&tv[TI_bandwidth].tvValue) = (char)loGetBandwidth(my_service, 0);
V_VT(&tv[TI_bandwidth].tvValue) = VT_I1;
tv[TI_bandwidth].tvState.tsTime = ft;
/** OPTIONAL: enumerate all possible qualities: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -