📄 lightopc.h
字号:
/**************************************************************************
* *
* Light OPC Server development library *
* *
* Copyright (c) Timofei Bondarenko 2000-2002, *
* Copyright (c) Kostya Volovich 2000 *
**************************************************************************/
#ifndef LIGHTOPC_H
#define LIGHTOPC_H (0x0888)
#ifndef WINAPI
#include <windows.h>
#endif
/**************************************************************************
General architecture
~~~~~~~~~~~~~~~~~~~~
.......................................
: OPC Server :
: ______ _________ : ___________
: / \ / \ : / \
/ CUSTOM \ / Light-OPC \ OLE-COM / \
< DRIVER > lo-API < LIBRARY > OPC-DA < An OPC-Client >
\ / interface \ / interface \ (SCADA) /
: \______/ \_________/ : \___________/
: :
:.....................................:
Data path
~~~~~~~~~
_________ ........................
| | : _________________ :
| Process |---------\ loCacheUpdate() ----->| | :
| | DRIVER > : | Secondary | :
| Data |-----^---/ loCacheLock() ------->| Cache | :
|_________| | : |_________________| :
| ______________ : | | :
+----| ldReadTags() | : | | :
| ldWriteTags()| : \|loUpdatePipe |/ :
|______________| : \ thread / :
| : \ / :
| : ___\_________/___ :
_____^____ : | | :
/============= __| | /----------| Primary | :
/ __| | loClient |< | Cache | :
< OPC DA | | |__________| \----------|_________________| :
\ | |__________| : :
\========== |___________| :...... loService .....:
Async. model
~~~~~~~~~~~~
... OPC-DA ..... ...loClient::client_scheduler() thread... .. D ..
: ___________ : : R :
___ : | |/--/ UpdatePipe /= I :
| <--------- Subscription --| Primary |\--\~~ thread ~~\= V :
| <--------- OnDataChange --| Cache |<===+ :......: E :
| : |_____^_____| | : R :
| <-------------------------------|-------------Async--+ : :
| : | | | : :
| +---------------+ CACHE | | : :
AsyncIO ---->| Request Queue | | | _____|__:____ :
| q_req |-- Async--+--DEVICE----->| |:
| | | | ldWriteTags |:
DEVICE -->+---------------+-- Sync-DEVICE --------->| ldReadTags |:
| : | |_____________|:
| +---------------+ | | : :
SyncIO-+ <---| Response Queue| | | : :
| | q_ret |<------------------------Sync--+ : :
| +---------------+ | : :
CACHE <========================================+ : :
:...............................................:.....:
**************************************************************************/
/** The <lo-API> is mostly described here. **/
/**************************************************************************
Almost all functions are thread-safe except object destruction procedures.
Naturally, once destruction initiated no one may use that object.
**************************************************************************
Public definitions to be exported:
**************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
#ifndef LO_PUBLIC
#define LO_PUBLIC /*extern*/
#endif
LO_PUBLIC
int loServerRegister(const GUID *CLSID_Svr, const char *ProgID,
const char *ServName, const char *exPath,
const char *Model /* 0=exe, ""=STA dll, "Both", "Free" ...*/);
LO_PUBLIC
int loServerUnregister(const GUID *CLSID_Svr, const char *ProgID);
/* Returns 0: OK; != 0 on Failure,
GetLastError() will return error code.
The exPath can be NULL or "" for an NT-Service. */
/*struct loService;*/
typedef struct loService loService;
/*struct loRealTag_;*/
typedef struct loRealTag_ *loRealTag;
#ifdef __cplusplus
class LightOPCServer;
typedef LightOPCServer loClient;
#else
struct LightOPCServer;
typedef struct LightOPCServer loClient;
#endif
#if 0
typedef loTagDesc *loTagId;
#else
typedef unsigned loTagId;
#endif
/* 0 is UNEXISTING TagId / RealTag */
typedef unsigned loTrid; /* Transaction identifier for loUpdateCache */
typedef unsigned loPLid; /* Identifier of a proprties' list */
/* 0 is UNEXISTING list */
#if 1
typedef WCHAR loWchar;
#else
typedef wchar_t loWchar;
#endif
typedef unsigned long loMilliSec; /* must be unsigned */
typedef struct loCaller /* Caller's context for ldCallbacks */
{
loService *ca_se;
void *ca_se_arg; /* a copy of loDriver::ldFirstArg */
loClient *ca_cli; /* can be NULL if no loClient assotiated with request */
void *ca_cli_arg; /* a copy of loClientCreate(,,,,, void *release_handle_arg)*/
} loCaller;
typedef struct loTagPair
{
loTagId tpTi;
loRealTag tpRt;
void *tpAP; /* identifier of AccessPath */
} loTagPair;
typedef struct loTagState
{
FILETIME tsTime;
HRESULT tsError;
int tsQuality;
} loTagState;
/* NOTE: if tsTime.dwHighDateTime == 0 then
tsTime.dwLowDateTime should contain index in the timestamp array
(see loCacheTimestamp()). Time from timestamp array will
be substituted when actual reading occure. */
typedef struct loTagValue
{
VARIANT tvValue;
loTagState tvState;
loTagId tvTi;
} loTagValue;
/* loDriver contains all driver-specefic information. All fields
can be set to 0 */
typedef struct loDriver
{
void *ldDriverArg; /* user-defined parameter for passing back using
loDriverArg() to all loDriver:: functions */
loMilliSec ldRefreshRate; /* Granularity for client's UpdateRate > 0 */
/* 0 mean implementation dependent default */
/* It's better to set it explicitly ****** */
loMilliSec ldRefreshRate_min; /* The shortest possible UpdateRate */
/* 0 mean implementation dependent default */
unsigned ldQueueMax; /* the limit of queued requests (mostly from Async
operations). Value 0 mean reasonable default */
unsigned ldFlags; /* loDF_XXXX constants */
char ldBranchSep; /* single character branch separator for
IOPCBrowseAddressSpace. if = 0 then FLAT */
HRESULT (*ldAskItemID)(const loCaller *,
loTagId *ti, void **acpa, /* return values */
const loWchar *itemid, const loWchar *accpath,
int vartype, int goal);
/* Called when client trying to AddItem(), ValidateItem()
and so on with an unknown tag. vartype indicates requested datatype,
usally it is VT_EMPTY. The exact goal of each call is indicated by goal.
It may be one of loDAIG_XXXX constans.
Driver may return OPC_E_INVALIDITEMID, OPC_E_UNKNOWNITEMID, OPC_E_UNKNOWNPATH
or E_FAIL when the tag cannot be created.
Also driver may find an existing or create new tag and return S_OK.
In this case returned *ti will help the server to identify requested tag.
Also driver may return driver-dependent key for specified accpath in *acpa.
this key will be transferred to driver in ldReadTags()/ldWriteTags() */
int (*ldWriteTags)(const loCaller *,
unsigned count, loTagPair taglist[], VARIANT values[],
HRESULT error[], HRESULT *master_err, LCID);
/* Called for writing tags into controller/driver.
A driver have to write listed tags into device. Also <error> should be set
for each handled tag. If a tpTi in taglist is 0 driver should ignore this tag
(and don't touch the appropriating error[]). In the case of an error driver
have to set *master_err to S_FALSE (or left it unchanged when all is ok).
The values[] passed as they are specified by a client. Conversion to canonical
datatypes may be reqired, also LCID (group-specefic) may be used in such
conversion. The driver may modify the passed values[] so they can be converted
"in-place".
Driver may also change some of taglist[].tpTi to 0.
If driver return loDW_TOCACHE then lopc will put values with non-zero tpTi
into cache.
If the driver return loDW_ALLDONE then none of values will be copied to cache.
Naturally, driver may update the cache explicitly via loUpdateCache().
*/
loTrid (*ldReadTags)(const loCaller *,
unsigned count, loTagPair taglist[],
VARIANT values[], WORD qualities[],
FILETIME stamps[], HRESULT errs[],
HRESULT *master_err, HRESULT *master_qual,
const VARTYPE vtype[], LCID);
/* Called for reading tags from controller/driver
to satisfy clients' requests for DEVICE reading.
Driver may actually update the cache and/or fill the output parameters.
Possible return values:
- a value, returned by loCacheUpdate() or loCacheUnlock(), the LightOPC will
wait until the specified transaction completed ant then return cached values;
- loDR_CACHED -- all data is already in cache, no waiting necessary;
- loDR_STORED -- driver have stored actual values in values[].
In the case of a Refresh request the <values> will be 0 as well as
qualities, stamps and errs thus driver must not fill these output parameters
and must not return loDR_STORED.
If the driver returns loDR_STORED the returned values will be transferred to
client "as is" that ensure athomicity of "device read" operations. Thus driver
have to convert returned values to vtype[] & LCID requestd by client.
Also driver have to update the cache because the returned values will not be
placed in the cache automatically.
If driver returns other than loDR_STORED the cached values will be posted to
client and athomicity of this portion of data can not be guaranted.
The master_err master_qual should be set to S_FALSE if the driver set
any of errs[] and qualities[] to values other than S_OK and GOOD_XXX
respectively.
If a tpTi in taglist is 0 driver have to ignore this tag.
On another hand, driver may forcibly set a tpTi/tpRt to 0 if it decided to
return value other than loDR_STORED. The LOPC will get from cache only tags
with non-zero tpTi. Therefore driver may perform device read only for some
tags in a request.
*/
void (*ldConvertTags)(const loCaller *,
unsigned count, const loTagPair taglist[],
VARIANT values[], WORD qualities[], HRESULT errs[],
HRESULT *master_err, HRESULT *master_qual,
const VARIANT source[], const VARTYPE vtype[], LCID);
/* This function is called to convert (localize) those tags that have loTF_CONVERT
set after they have been read from CACHE.
For tags read from DEVICE the ldRadTags() should perform such conversion.
This function have convert source[] to values[] according requested
vtype[] & LCID. The values[] might be the same as source[].
It also may modify errs[] and qualities[] when conversion can't be done.
The master_err & master_qual are also must be set to S_FALSE if any
errors occured.
This function have to ignore the tags with taglist[].tpTi is 0.
If all conversions are completed successfully or no conversion
performed at all (as in case of empty taglist[]) then
the master_err & master_qual must left unchanged.
Unlike other ldXXXX callbacks the ldConvertTags() might be called
a) very often;
b) from unclear state of the lightopc library.
Therefore there are following limitations:
a) loClientName(), loClientArg(), loDriverArg() can be called freely.
b) loTridWait(), loSetState() must not be called due to deadlock.
c) calling of other lightopc functions (referencing to loCervice / loClient)
may decrease performance.
d) this function must work fast and must not wait for a event due
to performance reason.
See loTF_CONVERT for additional info.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -