Main Page | Features | Central Services | csv-Files | Types | Transfer | Access | API-C | API-.NET | API-Java | Examples | Downloads
page generated on 21.11.2024 - 04:45
NETMEX

Introduction

The name "Netmex" is an acronym built from the words 'Network', 'machines' and 'experiments' (or possibly 'exchange') and refers to a system used at DESY for exchanging data between computers of the accelerators and the HERA experiments over the DESY Network. Since there are many types of computers at DESY, it is important that such a system be 'platform-neutral'. Hence TINE was chosen as the basis for data exchange.

Netmex is TINE, with a thin wrapper of additional code which serves two functions.
First, it enforces, through compulsory 'C' header files, documentation of the Keywords and associated data values and types supplied by each of the Netmex servers. This is a rather crude mechanism, but has turned out to be an effective solution to the problem of sharing up-to-date documentation. The header files are stored in a central directory and are compiled into the programs which require access to the data. Second, it shields some of the underlying TINE functionality from the Netmex clients, enforcing 'READ-ONLY' and discouraging users from directly accessing front end computers in the control system.

NETMEX Servers

In the platform-specific server repositories (e.g. ../linux/server/ or ../solaris/server/) you will find a mexsrv.mak make file which puts together an example netmex server.
Specifically, this make file makes use of keyeqm.c and mexsrc.c which are found in the ../source repository and can be used as is. The make file also make use of a source module called 'mydata.c'. An copy of this module is found in the ../examples/ansi-c/netmex repository. This should be regarded as simply an example as it demonstrates how one registers a NETMEX keyword, binds it to data, and updates the contents.

NETMEX Keywords are TINE Properties (Read-only). Thus a call to RegisterKeywordEx() will register a NETMEX keyword and provide a 'background' function to be called at regular intervals, specified in a call to setKeywordRefreshRoutine().

This example registers a Keyword "MYDATA", a background routine called MyDataCpy() and signals the TINE engine to call this background routine once every 500 milliseconds.

It is a matter of minutes to compile a test server. The real problem, for which some custom programming is required, is that the server must somehow be interfaced to a source for the data which it exports. Because each group at DESY has different systems for internal data communication, there is no universal solution here. In some cases, the TINE code can be combined with a program which uses a different mechanism for pulling in data, in other cases shared memory could be used, or, as a last resort, diskfiles.
The 'gateway server' principle for Netmex means that it is desirable for each group to have a computer where all of the relevant data is available in some form, with a suitable refresh rate (typically 1 Hz or more).

Please consult the NETMEX Server API for more detailed information.

NETMEX Headers

The NETMEX servers are TINE servers and can of course be queried to ascertain there keywords and calling parameters. However another ingredient for rapid application development is usually provided in the form of a NETMEX header file. These are "C" header files to be used with the NETMEX client API described below. As these 'header' files assign NETMEX keywords within them, they can be #included in in only one module of a NETMEX project. To this end, they should have used an extension of '.mex' instead of '.h' to avoid confusion (next version!).

The header files explicitly make use of the NETKEY structure shown below, as does the NETMEX client API.

typedef struct {
char Eqpname[16]; /* TINE device server name */
char Property[32];/* TINE propertery: Keyword at server */
short format; /* TINE data type */
short no_el; /* # of elements (array size) */
short EqNo; /* first element to send */
short Ret_Code; /* 0=ok, else error # */
int TimeStamp; /* 4 Byte Int for timestamp */
short Status; /* data status word */
short Version; /* version # for data header */
void * data; /* data array */
void (*fcn)(char *,int); /*callback for async calls*/
char DevName[16]; /* device name (bound to EqNo) */
} NETKEY;

An example NETMEX header file is also shown, illustrating how to specify all information pertinent to a NETMEX keyword.

/*========================= Doris Netmex Data ========================*/
#ifndef DORISVER
#define DORISVER 101
char rms_vertical[16];
char rms_horizontal[16];
char state_vertical[16];
char state_horizontal[16];
float rmsvalues[6];
float wrmsvalues[6];
NETKEY HRMSSTR={ "LAGERGL","HLRMS",CF_BYTE,16,1,RC_INI,T_INIT,ST_INI,DORISVER,(void*)rms_horizontal};
NETKEY VRMSSTR={ "LAGERGL","VLRMS",CF_BYTE,16,1,RC_INI,T_INIT,ST_INI,DORISVER,(void*)rms_vertical};
NETKEY HSTATESTR={ "LAGERGL","STATESTR",CF_BYTE,16,1,RC_INI,T_INIT,ST_INI,DORISVER,(void*)state_vertical};
NETKEY VSTATESTR={ "LAGERGL","STATESTR",CF_BYTE,16,2,RC_INI,T_INIT,ST_INI,DORISVER,(void*)state_vertical};
NETKEY RMSVALUES={ "LAGERGL","RMS",CF_FLOAT,6,1,RC_INI,T_INIT,ST_INI,DORISVER,(void*)rmsvalues};
NETKEY WRMSVALUES={ "LAGERGL","WRMS",CF_FLOAT,6,1,RC_INI,T_INIT,ST_INI,DORISVER,(void*)wrmsvalues};
#define DoBLBeamPos_NUM 38
NAME16 gn16DoBLBeamPosNAM[DoBLBeamPos_NUM];
float gfDoBLBeamPosX[DoBLBeamPos_NUM];
float gfDoBLBeamPosY[DoBLBeamPos_NUM];
float gfDoBLMonPosX[DoBLBeamPos_NUM];
float gfDoBLMonPosY[DoBLBeamPos_NUM];
NETKEY DoBLBeamPosNames={ "DORISDATA","DoBLBeamPos.X.NAM",CF_NAME16,DoBLBeamPos_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gn16DoBLBeamPosNAM};
NETKEY DoBLBeamPosX={ "DORISDATA","DoBLBeamPos.X",CF_FLOAT,DoBLBeamPos_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoBLBeamPosX};
NETKEY DoBLBeamPosY={ "DORISDATA","DoBLBeamPos.Y",CF_FLOAT,DoBLBeamPos_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoBLBeamPosY};
NETKEY DoBLMonPosX={ "DORISDATA","DoBLMonPos.X",CF_FLOAT,DoBLBeamPos_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoBLMonPosX};
NETKEY DoBLMonPosX={ "DORISDATA","DoBLMonPos.Y",CF_FLOAT,DoBLBeamPos_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoBLMonPosY};
#define DoBunCur_NUM 10
float gfDoBunCur[DoBunCur_NUM];
NETKEY DoBunCur={ "DORISDATA","DoBunCur",CF_FLOAT,DoBunCur_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoBunCur};
#define DoBunCount_NUM 1
float gfDoBunCount[DoBunCount_NUM];
NETKEY DoBunCount={ "DORISDATA","DoBunchCount",CF_FLOAT,DoBunCount_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoBunCount};
#define DoSumCur_NUM 1
float gfDoSumCur[DoSumCur_NUM];
NETKEY DoSumCur={ "DORISDATA","DoSumCur",CF_FLOAT,DoSumCur_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoSumCur};
#define DoDCCur_NUM 1
float gfDoDCCur[DoDCCur_NUM];
NETKEY DoDCCur={ "DORISDATA","DoDCCur",CF_FLOAT,DoDCCur_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoDCCur};
float gfDoDCLoss[DoDCCur_NUM];
NETKEY DoDCLoss={ "DORISDATA","DoDCLoss",CF_FLOAT,DoDCCur_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoDCLoss};
float gfDoDCTau[DoDCCur_NUM];
NETKEY DoDCTau={ "DORISDATA","DoDCTau",CF_FLOAT,DoDCCur_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoDCTau};
#define DoEnergy_NUM 1
float gfDoEnergy[DoEnergy_NUM];
NETKEY DoEnergy={ "DORISDATA","DoEnergy",CF_FLOAT,DoEnergy_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoEnergy};
#define DoOrbit_NUM 40
float gfDoOrbitHor[DoOrbit_NUM];
float gfDoOrbitVer[DoOrbit_NUM];
NETKEY DoOrbitHor={ "DORISDATA","DoOrbitHor",CF_FLOAT,DoOrbit_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoOrbitHor};
NETKEY DoOrbitVer={ "DORISDATA","DoOrbitVer",CF_FLOAT,DoOrbit_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoOrbitVer};
#define DoRWegVacPres_NUM 2
float gfDoRWegVacPres[DoRWegVacPres_NUM];
NETKEY DoRWegVacPres={ "DORISDATA","DoRWegVacPres",CF_FLOAT,DoRWegVacPres_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoRWegVacPres};
#define DoSTATE_NUM 1
NAME32 gn32DoSTATE[DoSTATE_NUM];
NETKEY DoSTATE={ "DORISDATA","DoSTATE",CF_NAME32,DoSTATE_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gn32DoSTATE};
#define DoVacPressure_NUM 156
NAME32 gfDoVacPressure[DoVacPressure_NUM];
NETKEY DoVacPressure={ "DORISDATA","DoVacPressure",CF_FLOAT,DoVacPressure_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoVacPressure};
#define DoVacAvePr_NUM 1
NAME32 gfDoVacAvePr[DoVacAvePr_NUM];
NETKEY DoVacAvePr={ "DORISDATA","DOVACAvePr",CF_FLOAT,DoVacAvePr_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoVacAvePr};
#define DoTVText_NUM 64
char gtDoTVText[DoTVText_NUM];
NETKEY DoTVText={ "DORISDATA","DoTVText",CF_TEXT,DoTVText_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gtDoTVText};
#define DoMODUS_NUM 32
char gtDoMODUS[DoMODUS_NUM];
NETKEY DoMODUS={ "DORISDATA","DoMODUS",CF_TEXT,DoMODUS_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gtDoMODUS};
#define DoArcTemp_NUM 46
float gfDoArcTemp[DoArcTemp_NUM];
NETKEY DoArcTemp={ "DORISDATA","DoArcTemp",CF_FLOAT,DoArcTemp_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoArcTemp};
#define DoBLWigglerGap_NUM 10
float gfDoBLWigglerGap[DoBLWigglerGap_NUM];
NETKEY DoBLWigglerGap={ "DORISDATA","DoBLWigglerGap",CF_FLOAT,DoBLWigglerGap_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoBLWigglerGap};
#define DoVCorrSoll_NUM 40
float gfDoVCorrSoll[DoVCorrSoll_NUM];
NETKEY DoVCorrSoll={ "DORISDATA","DoVCorrSoll",CF_FLOAT,DoVCorrSoll_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoVCorrSoll};
#define DoSekiDelay_NUM 5
float gfDoSekiDelay[DoSekiDelay_NUM];
NETKEY DoSekiDelay={ "DORISDATA","DoSekiDelay",CF_FLOAT,DoSekiDelay_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoSekiDelay};
#define DoSekiSoll_NUM 5
float gfDoSekiSoll[DoSekiSoll_NUM];
NETKEY DoSekiSoll={ "DORISDATA","DoSekiSoll",CF_FLOAT,DoSekiSoll_NUM,0,RC_INI,T_INIT,ST_INI,DORISVER,(void*)gfDoSekiSoll};
#endif /* DORISVER */

NETMEX Clients

NETMEX clients are also very easy to put together, especially as someone has done most of the work collating the information for you. Namely, the associated netmex 'header' files are typically provided by an administrator as soon as the server is on-line.

All NETMEX parameters are then accessed simply through their keywords. As NETMEX servers are TINE servers the normal TINE client APIs can be used to access the NETMEX keywords on the target platform, keeping in mind that a NETMEX keyword is a TINE property. In addition NETMEX provides a simplified client-side API, largely based on the information contained in the NETMEX header files. A secondary advantage of using the NETMEX client API and the NETMEX header files is that when large number of clients access the same keywords, they do so in precisely the same manner. That is, the calling parameters are identical, which means that the corresponding NETMEX server need only service one entry in its contract table for a given keyword.

Please consult the NETMEX Client API for more detailed information.

NAME32
Defines a TINE 32-character fixed-length string data object.
Definition: tinetype.h:253
NAME16
Defines a TINE 16-character fixed-length string data object.
Definition: tinetype.h:243

Impressum   |   Imprint   |   Datenschutzerklaerung   |   Data Privacy Policy   |   Declaration of Accessibility   |   Erklaerung zur Barrierefreiheit
Generated for TINE API by  doxygen 1.5.8