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
MatLab API

The client and server interfaces for MatLab applications follow the Buffered Client and the Buffered Server paradigms. In addition, several utilities for browsing and for retrieving archived data, etc. are also available. These will be covered in the sections which follow.

Specifically these are:

Note that if you have installed the TINE MatLab libraries to a local directory (default will be TINE_ROOT%\MatLab, e.g. c:\tine\MatLab) then you will likely need to add this directory to your MatLab path. For instance:

addpath('C:\tine\MatLab')
savepath

will ensure that the MatLab libraries are found on the path by MatLab and that this change in the path persists for future MatLab sessions.

Client API

On the client side, dedicated 'read' and 'write' calls generally allow for easy access to control system variables from MatLab.
In their most basic forms, the calls appear to be 'transactional', which in fact they are for 'write' commands. 'read' calls generally start an asynchronous static listener (i.e. a local monitor) on the desired variable, which is then stored in a local buffer. Thus, repeated 'read' calls merely retrieve the most recent updated value from the local buffer. The update rate can of course be influenced by the calling parameters. A 'read' call can likewise be constructed to in fact issue a synchronous transactional read request.

We shall expore these read calls in some detail below.

tine_read (see also tine_attach_link)

With 'tine_read' you can access the current readback value of any targeted endpoint which contains readback data. Simply typing 'tine_read' at the MatLab prompt will display the following

??? tine_read usage:
ret=tine_read('/<context>/<server>/<device>[<property>]'[,'<data_type>',data_size,timer_interval,callback_id,'callback_fcn']);
'ret' contains the status/error message,timestamps,and returned values

One sees that there is one primary required argument, namely the 'targeted endpoint', and several optional arguments which influence the underlying behavior.

Parameters
targeted_endpointis the initial parameter and must be a string of the form /<context>/<server>/<device>[<property>] which essentially follows the TINE naming hierarchy. If NO other input parameters are given, the default 'read' data type and data size (as established by the targeted server) will be acquired; AND if the property is not 'static' then an asynchronous listener will be established updating the value every 1000 msec. No 'callbacks' events will be issued. It is assumed that the application will continue to issue the same read requests for its life cycle. If this is not the case, then after an idle period of 5 minutes without any subsequent 'read' requests on the same parameter will cause the listener to be canceled, thereby notifying the corresonding server that this client is no longer interested in the parameter.
data_typeis the second parameter and is optional. If used it can specify the desired data acquisition format. MatLab generally works with matrices of 'doubles' or 'strings', and the necessary conversion will always take place. However some servers might potentially have overloaded properties which can return data in different forms depending on what is asked for. Additionally, if it is known that a property has been multiply exported with different data types (i.e. overloaded) then this parameter can be used to determine which specific call is intended. This is often true in the case of structures. If a structure is wished for and the structure tag is known, then the property form of this parameter follows the paradigm: 'STRUCT.<tag>' (see example below. If the canonical data type is a structure, this parameter may be omitted, in which case the data structure will be 'discovered'.
data_size(optional) is the requested data size. Many servers prefer by default to deliver 'multi-channel' arrays of all elements of the desired property (for instance an array containing ALL vacuum pressures beginning at the index determined by the 'device name' input). If the application only needs a single value (or subset), the 'data size' can be used to specify the precise number of elements required.
timer_interval(optional) is the requested timer interval (in milliseconds) which determines the polling access of the underlying 'listener'. By the default this is 1000 msec. If a faster update of the local buffers is desired, then this value may be adjusted accordingly. Note: if the the desired property is being 'scheduled' by the server, then the underlying listener will ALWAYS be updated 'immediately'.
callback_id(optional) is the caller's desired callback ID. If this argument is not included, then it is assumed that no callback event is desired.
callback_fcn(optional) is the name of the MatLab (.m) function which should be called when new data arrive in the listening buffer. If this parameter is missing, but a callback ID was given, then a callback routine under the name of 'tine_dispatch_<property>.m' will be looked for and called if present. In any case the desired .m function must be found in the current working directory. If it does not exist, no attempt will be made to issue a callback. The callback .m file must accept a single scalar matrix, which will contain the value of the 'ID' passed as the fifth argument. A MatLab function with any other input arguments will likely result in an error and unpredictable behavior. Any return values from the callback function will be ignored.
Returns
the acquired data as a Matlab structure matrix with fields
  • 'error' giving the error/status as a string,
  • 'timestamp' giving the UTC timestamp of the returned data as a string
  • 'utc' giving the UTC timestamp of the returned data as double (representing the number of seconds since January 1, 1970 with fractional seconds).
  • '<property>' giving the returned data for the targeted property.
> tine_read('/TEST/SineServer/SineGen0[Amplitude]','float',10)
ans =
error: ''
timestamp: '20.05.11 10:05:37.076 CDT'
utc: '1305878737.076'
Amplitude: [10x1 double]

Note that instead of 'polling' within a MatLab timer function for the desired data (which would introduce extra latency), the MatLab program can be structured to issue a 'tine_read' inside the callback routine, thus making the data available to the application logic immediately after new data have been delivered.

As noted above, in the case of structures, one can specify the 'known' structure type in the call to tine_read as shown:

>> inf = tine_read('/TEST/SineServer/SineGen0[SineInfo]','STRUCT.SineInfo',1,1000)
inf =
error: ''
timestamp: '06.06.11 16:29:02.654 CDT'
utc: '1307370542.654'
SineInfo: [1x1 struct]
>> inf.SineInfo
ans =
amplitude: 80
frequency: 1
noise: 27.5098
phase: 0
numberCalls: 3799009
description: 'Sine Generator 0 at your disposal '

If the structure type is unknown, it may be safely omitted, in which case it will be discovered. In the above example all optional parameters are omitted. Thus the call returns the 'registered' data size and type, in this case an array of 10 such structures:

>> inf = tine_read('/TEST/SineServer/SineGen0[SineInfo]')
inf =
error: ''
timestamp: '06.06.11 16:36:00.904 CDT'
utc: '1307370960.904'
SineInfo: [10x1 struct]
>> inf.SineInfo(2).amplitude
ans =
256

As a final note: the data type given in the 'data_type' parameter is case 'insensitive' with respect to the TINE format type. That it, 'struct' is identical to 'STRUCT', 'float' is identical to 'FLOAT'. However (and this is important) if a structure tag is appended to the format string 'struct' it is case 'sensitive'! That is 'SineInfo' is NOT the same as 'SINEINFO', etc. as far as structure tags are concerned.

tine_readimage

'tine_readimage' is a special call to acquire images. Simply typing 'tine_readimage' at the MatLab prompt produces the following output:

??? tine_readimage usage:
[a,h,s,t]=tine_readimage('/<context>/<server>/<device>[<property>]'[,polling_interval,'access_mode']);
'ret' contains the image, image header, status, timestamp

One sees that there is one primary required argument, namely the 'targeted endpoint', and one optional argument which can be used to specify a polling interval.

Parameters
targeted_endpointis the initial parameter and must be a string of the form /<context>/<server>/<device>[<property>] which essentially follows the TINE naming hierarchy. There is no validation on the entered parameters to insure that the target does produce an image. However it should be noted that for modern (i.e. video system 3) servers, the device entered should be 'Output' and the property entered should be either 'Frame' (for acquisition at the specified timer rate) or 'Frame.Sched' for acquistion at the server's scheduling rate.
polling_interval[optional] is the requested polling interval. If this parameter is either omitted or passed as '0' then the call reverts to a single synchronous acquisition of an image. Otherwise an underyling data link will be established providing a local buffer from which future calls to the same target will retrieve their image data.
access_mode[optional] is the desired access mode flags for the underlying asynchronous link to the data target. Any entered text other than 'NETWORK' (request as multicast) or 'CONNECT' (request as a TCP stream) will be ignored.

Example:

>> [a, hdr, sts, t] = tine_readimage('/PETRA/MDI2_RAWVIDEO1/Output[Frame.Sched]',1000,'NETWORK');
>> sts
sts =
''
>> hdr
hdr =
baseTag: 861295446
cameraPortId: 19410001
versionTag: 1
totalLength: 2895548
timestampSeconds: '1313661023'
timestampMicroseconds: '851000'
cameraPortName: 'Jai Mono'
sourceWidth: 1392
sourceHeight: 1040
aoiWidth: -1
aoiHeight: -1
xStart: 0
yStart: 0
bytesPerPixel: 2
effectiveBitsPerPixel: 12
horizontalBinning: 0
verticalBinning: 0
sourceFormat: 0
imageFormat: 0
frameNumber: 90310
eventNumber: 0
xScale: -1
yScale: -1
imageRotation: 0
fspare1: -1
fspare2: -1
fspare3: -1
imageFlags: 3
ispare1: -1
ispare2: -1
ispare3: -1
appendedFrameSize: 2895360
>> image(a)
>>

The above example will launch a Matlab image display which looks like the following:

tine_write

With 'tine_write' you can set the current target value of any targeted endpoint which allows WRITE access. Simply typing 'tine_write' at the MatLab prompt will display the following

??? tine_write usage:
ret=tine_write(values,'/<context>/<server>/<device>[<property>]'[,'<data_type>',timeout]);
where values = string or double Nx1 array (or omitted to send a COMMAND without input)
'ret' contains the status/error message

One sees that there are in this case two primary required arguments, namely the values to be 'written' and the 'targeted endpoint'. Actually the initial argument (the values to be written) may be omitted to issue a 'command' which does not take input values but does require WRITE access. If this form is used, then ONLY a single input argument is allowed, namely the 'targeted endpoint'. There are also several optional arguments which influence the underlying behavior.

Parameters
valuesis the values to be written and can be a string or an array of values. The precise data format will be determined either by property query to the server or by specifying the data type in the optional third parameter.
targeted_endpointis the target which is to process the WRITE request. Once again, this essentially follows the TINE naming hierarchy. If NO other input parameters are given, the default data type will be acquired from the server. The input data size will be the array dimension of the 'values' argument passed.
data_typeis optional and if used can specify the desired input data type. And as in the case of tine_read, a structure type may be specified using the same paradigm: 'struct.<tag>' for the data_type string
timeoutis optional and if used can specify the maximum amount of time to wait (in milliseconds) for a response.
Returns
the status of the WRITE operation

Note: If a structure is to be sent, then the structure fields (at least as far as the data types and sizes are concerned) MUST be known a priori. Theoretically a call to tine_read can be made to discover the structure data type (as long as it is known that the designated property supports the delivered structure data type also as an 'input' data type!).

In the example below, the data type is explicitly given.

global sinf;
sinf.amplitude = 111;
sinf.frequnecy = 3;
sinf.noise = 65;
sinf.phase = 0;
sinf.numberOfCalls = 1;
sinf.description = 'well, well, well ....';
>> r = tine_write(sinf,'/TEST/SineServer/SineGen0[SineInfo]','STRUCT.SineInfo',1000)
r =
''

An alternative case might omit the optional parameters. However the input data MUST be of the apropriate structure data type. This default input data type will be in this case queried from the server and the given data type must agree with this.

global sinf;
sinf.amplitude = 111;
sinf.frequnecy = 3;
sinf.noise = 65;
sinf.phase = 0;
sinf.numberOfCalls = 1;
sinf.description = 'well, well, well ....';
>> r = tine_write(sinf,'/TEST/SineServer/SineGen0[SineInfo]')
r =
''

tine_writeread

With 'tine_writeread' you can atomically set and readback the current target value of any targeted endpoint which allows WRITE access. Primarily this assumes the targeted endpoint represents an 'attribute'. That is, the property and device accept a 'set' value and deliver a 'read' value with the same data size and format. This is in general different for a 'call', whereby the input data set and output data set are generally different objects and in many cases do not require WRITE access. If such 'calls' are desired, please make use of 'tine_call'.

You can nevertheless use 'tine_writeread' with different data types and sizes for input and output. However, WRITE access will always be assumed!

Simply typing 'tine_writeread' at the MatLab prompt will display the following

??? tine_writeread usage:
ret=tine_writeread(values,'/<context>/<server>/<device>[<property>]'[,'<data_type>',data_size,timeout]);
where values = string or double Nx1 array (or omitted to send a COMMAND without input)
'ret' contains the status/error message,timestamps,and returned values

One sees that there are in this case two primary required arguments, namely the values to be 'written' and the 'targeted endpoint'. Actually the initial argument (the values to be written) may be omitted to issue a 'command' which does not take input values but does require WRITE access. If this form is used, then ONLY a single input argument is allowed, namely the 'targeted endpoint'. There are also several optional arguments which influence the underlying behavior.

Parameters
valuesis the values to be written, can be a string or an array of values. The precise data format will be determined either by property query to the server or by specifying the data type in the optional third parameter.
targeted_endpointis the target which is to process the WRITE request. Once again, this essentially follows the TINE naming hierarchy. If NO other input parameters are given, the default data type will be acquired from the server. The input data size will be the array dimension of the 'values' argument passed.
data_typeis optional and if used can specify the desired input and output data types. If a single type is given then it will be use for both the input and output data types (attribute style). Otherwise both the input and output types can be specified by separating them with a colon ':' as in 'float:int32'. If the 'data_type' is omitted, then a query will ensue in order to determine the default output data size and type. And as in the case of tine_read, a structure type may be specified using the same paradigm: 'struct.<tag>' for the data_type string. If the the input and output take different types (i.e. tags) then again passing the data_type in the form 'struct.<tag_input>:struct.<tag_output>' will instruct the subsystem as to which structures to use.
data_sizerefers to the requested output data size. Note: the input data size is completely determined by the size of the input data array in parameter 1.
timeoutis optional and if used can specify the maximum amount of time to wait (in milliseconds) for a response.
Returns
the acquired data as a Matlab structure matrix with fields
  • 'error' giving the error/status as a string,
  • 'timestamp' giving the UTC timestamp of the returned data as a string
  • 'utc' giving the UTC timestamp of the returned data as double (representing the number of seconds since January 1, 1970 with fractional seconds).
  • '<property>' giving the returned data for the targeted property.

The example below shows how to send and receive a structure from a server. In this case the same structure format (tag) is used for input and output and passed explicitly in the call, although the same results would be obtained by simply passing 'struct.SineInfo'.

global sinf;
sinf.amplitude = 111;
sinf.frequnecy = 3;
sinf.noise = 65;
sinf.phase = 0;
sinf.numberOfCalls = 1;
sinf.description = 'well, well, well ....';
>> sinf = tine_writeread(sinf,'/TEST/SineServer/SineGen0[SineInfo]','STRUCT.SineInfo:STRUCT.SineInfo',1,1000)
sinf =
error: ''
timestamp: '06.06.11 16:54:14.263 CDT'
utc: '1307372054.263'
SineInfo: [1x1 struct]
>> sinf.SineInfo
ans =
amplitude: 111
frequency: 3
noise: 65
phase: 0
numberCalls: 1
description: 'well, well, well .... '

tine_call

As noted above, you can also make use of 'tine_call' to access target endpoints using different input and output data objects, and without the restriction that the access be a WRITE command. In fact, the default data access using 'tine_call' is READ access.

In many ways the use of 'tine_call' parallels that of 'tine_writeread'.

Simply typing 'tine_call' at the MatLab prompt will display the following

??? tine_call usage:
ret=tine_call(values,'/<context>/<server>/<device>[<property>]'[,'<data_type>',data_size,timer_interval,'access_mode']);
where values = string or double Nx1 array
'ret' contains the status/error message,timestamps,and returned values

One sees that there are in this case two primary required arguments, namely the values to be 'sent' and the 'targeted endpoint'. The initial argument (the values to be sent) is in this case NOT optional. However a 'WRITE' command can be fashioned by supplying the data access as 'WRITE' and by providing an empty (zero-length) string as the initial argument. There are also several optional arguments which influence the underlying behavior.

Parameters
valuesis the values to be written, can be a string or an array of values. The precise data format will be determined either by property query to the server or by specifying the data type in the optional third parameter.
targeted_endpointis the target which is to process the CALL request. Once again, this essentially follows the TINE naming hierarchy. If NO other input parameters are given, the default data type will be acquired from the server. The input data size will be the array dimension of the 'values' argument passed.
data_typeis optional and if used can specify the desired input data type. If a single type is given then it will be use for both the input and output data types (attribute style). Otherwise both the input and output types can be specified by separating them with a colon ':' as in 'float:int32'. If the 'data_type' is omitted, then a query will ensue in order to determine the default output data size and type. And as in the case of tine_read, a structure type may be specified using the same paradigm: 'struct.<tag>' for the data_type string. If the the input and output take different types (i.e. tags) then again passing the data_type in the form 'struct.<tag_input>:struct.<tag_output>' will instruct the subsystem as to which structures to use.
data_sizerefers to the requested output data size. Note: the input data size is completely determined by the size of the input data array in parameter 1.
timer_intervalis optional and if used can specify the maximum amount of time to wait (in milliseconds) for a response in the case of a WRITE call or synchronous request, or it specifies the timer polling interval when an asynchronous static listener is in play.
accessmode can be used to specify the desired CALL access. By default this is simply 'READ', which will in fact start an asynchronous static listener for the calling parameters. To specify a synchronous transaction, you should supply the string 'SYNC'. By specifying 'WRITE' the CALL will automatically be made via a synchronous transaction.
Returns
the acquired data as a Matlab structure matrix with fields
  • 'error' giving the error/status as a string,
  • 'timestamp' giving the UTC timestamp of the returned data as a string
  • 'utc' giving the UTC timestamp of the returned data as double (representing the number of seconds since January 1, 1970 with fractional seconds).
  • '<property>' giving the returned data for the targeted property.

Examples for tine_call essentially follow the same model as per tine_writeread.

tine_attach_link

If it is known a priori that the MatLab application should deal in some circumstances with monitor 'links' the the call 'tine_attach_link' should perhaps be used in lieu of 'tine_read'. This call differs from 'tine_read' primarily in that ALL input parameters are required. In addition, the 'partner' call 'tine_close_link' can be used to terminate the underlying listener immediately without waiting for its 'idle time' to expire.

Simply typing 'tine_attach_link' at the MatLab prompt will display the following

??? tine_attach_link usage:
ret=tine_attach_link('/<context>/<server>/<device>[<property>]','data_type',data_size,timer_interval,callback_id,'callback_fcn');
'ret' contains the status/error message,timestamps,and returned values

One sees that there are six required arguments. 'tine_attach_link' will always assume that readback data are being monitored and the access mode is READ.

Parameters
targeted_endpointis the initial parameter and must be a string of the form /<context>/<server>/<device>[<property>] which essentially follows the TINE naming hierarchy. If NO other input parameters are given, the default 'read' data type and data size (as established by the targeted server) will be acquired; AND if the property is not 'static' then an asynchronous listener will be established updating the value every 1000 msec. No 'callbacks' events will be issued. It is assumed that the application will continue to issue the same read requests for its life cycle. If this is not the case, then after an idle period of 5 minutes without any subsequent 'read' requests on the same parameter will cause the listener to be canceled, thereby notifying the corresonding server that this client is no longer interested in the parameter.
data_typeis the second parameter and is optional. If used it can specify the desired data acquisition format. MatLab generally works with matrices of 'doubles' or 'strings', and the necessary conversion will always take place. However some servers might potentially have overloaded properties which can return data in different forms depending on what is asked for. And as in the case of tine_read, a structure type may be specified using the same paradigm: 'struct.<tag>' for the data_type string
data_size(optional) is the requested data size. Many servers prefer by default to deliver 'multi-channel' arrays of all elements of the desired property (for instance an array containing ALL vacuum pressures beginning at the index determined by the 'device name' input). If the application only needs a single value (or subset), the 'data size' can be used to specify the precise number of elements required.
timer_interval(optional) is the requested timer interval (in milliseconds) which determines the polling access of the underlying 'listener'. By the default this is 1000 msec. If a faster update of the local buffers is desired, then this value may be adjusted accordingly. Note: if the the desired property is being 'scheduled' by the server, then the underlying listener will ALWAYS be updated 'immediately'.
callback_id(optional) is the caller's desired callback ID. If this argument is not included, then it is assumed that no callback event is desired.
callback_fcn(optional) is the name of the MatLab (.m) function which should be called when new data arrive in the listening buffer. If this parameter is missing, but a callback ID was given, then a callback routine under the name of 'tine_dispatch_<property>.m' will be looked for and called if present. In any case the desired .m function must be found in the current working directory. If it does not exist, no attempt will be made to issue a callback. The callback .m file must accept a single scalar matrix, which will contain the value of the 'ID' passed as the fifth argument. A MatLab function with any other input arguments will likely result in an error and unpredictable behavior. Any return values from the callback function will be ignored.

A call to tine_attach_link will 'wait' for the initial incoming data set and then return the acquired data.

Returns
a Matlab structure matrix with fields
  • 'error' giving the error/status as a string,
  • 'timestamp' giving the UTC timestamp of the returned data as a string
  • 'utc' giving the UTC timestamp of the returned data as double (representing the number of seconds since January 1, 1970 with fractional seconds).
  • '<property>' giving the returned data for the targeted property.

Note that instead of 'polling' within a MatLab timer function for the desired data (which would introduce extra latency), the MatLab program can be structured to issue a 'tine_read' inside the callback routine, thus making the data available to the application logic immediately after new data have been delivered.

Consider the following example, which establishes a data link to get the horizontal orbit:

Example:

ret = tine_attach_link('/PETRA/LBRENV/BPM_SWR_13[SA_X]','float',226,100,43,'sa_x_callback')

The link specifies a callback 'sa_x_callback' which instructs the subsystem to call the matlab 'm' file named sa_x_callback.m when data arrive. An example callback file might look like the following:

function sa_x_callback(id)
v = tine_read('/PETRA/LBRENV/BPM_SWR_13[SA_X]');
fprintf('%d: %d\n', id, v.SA_X(1))

So within this callback file, an additional call to tine_read() with the same data endpoint is made in order to acquire the most recent data set and, in this case, dump the first array element to the screen.

tine_close_link

As noted above, if the MatLab application knows it has started an asynchronous static listener, it can terminate the listener at any time by calling 'tine_close_link'. Otherwise an idle period of 5 minutes will need to expire before the listener is terminated automatically. An 'idle period' is defined as a period of time where NO calls to 'tine_read' are made to access the current buffered contents of the listener data.

Simply typing 'tine_call' at the MatLab prompt will display the following

??? tine_close_link usage:
ret=tine_close_link('/<context>/<server>/<device>[<property>]'[,'<data_type>',data_size])

The parameter passed are used to identify the link parameters in the listener table. These must match exactly in order for the listening link to be identified so that it can be terminated.

Parameters
targeted_endpointis the initial parameter and must be a string of the form /<context>/<server>/<device>[<property>] which essentially follows the TINE naming hierarchy. If NO other input parameters are given, the default 'read' data type and data size (as established by the targeted server) will be acquired and assumed;
data_typeis optional and if used can specify the known data acquisition format.
data_sizeis optional and if used contains the known requested data size.

Legacy MatLab routines

The legacy MatLab routines 'tineread' and 'tinewrite' are still available but should be considered as deprecated. These are

tineread

TINEREAD reads data from the control system
In the call VAL = TINEREAD(DEVPROPSTR) DEVPROPSTR is a string composed
of the server context CONTEXT, server name SERVER, the device name DEV
and the device properties PROP1, PROP2,... etc.
where the server context (e.g. HERA, PETRA, etc.) is optional.
The command returns the data in a structure composed of
an error string VAL.ERRROR and the property information as
elements of the structure VAL. In case of no error
ERROR is empty; otherwise it contains an error value number.
Syntax:
tineread('/<CONTEXT>/<SERVER>/<DEV>[<PROP1>;<PROP2>;...]')
Or:
tineread('<SERVER>/<DEV>[<PROP1>;<PROP2>;...]')
Example:
val = tineread('/HERA/HeEOrbit/WL 791[ORBIT.X;ORBIT.Z]')
Listener: @rate [msec] @0 no listener

and

tinewrite

TINEWRITE writes data to the control system
In the call TINEWRITE(VALUE,DEVPROPSTR) value is the data to be written to
the server, devpropstr is a string composed of the
server context CONTEXT, the server name SERVER,
the device name DEV and the device property PROP. The type of VALUE
depends an the data structure to be written.
Caution: VALUE must be a column vector!
Syntax:
tinewrite(value,'/<CONTEXT>/<SERVER>/<DEV>[<PROP>]')
Or:
tinewrite(value,'<SERVER>/<DEV>[<PROP>]')
Example:
tinewrite([0; 5; 2], '/HERA/HeEOrbit/WL 791[WrSet_dB]')

Browsing Utilities

Various routines are available for browing the control system within Matlab. These are described below.

tine_contexts

The top tier of the TINE naming hierarchy is the 'context'. To ascertain the available contexts within the control system, simply call 'tine_contexts'. A list of the known contexts will then be provided in the output.

A call to 'tine_contexts' does not take any parameters.
Typing 'tine_contexts' at the MatLab prompt will generate output containing list of available contexts as seen in the example below.

>> tine_contexts
ans =
DORIS: 'DORIS'
HERA: 'HERA'
SERVICE: 'SERVICE'
TTF2: 'TTF2'
TTF: 'TTF'
DESY2: 'DESY2'
LINAC2: 'LINAC2'
DESY3: 'DESY3'
PETRA: 'PETRA'
SITE: 'SITE'
DORIS.DAEMON: 'DORIS.DAEMON'
LINAC3: 'LINAC3'
TEST: 'TEST'
MHF: 'MHF'
Common.SEDAC: 'Common.SEDAC'
PITZ: 'PITZ'
FLASH: 'FLASH'

tine_servers

The next tier of the TINE naming hierarchy is the device server (or device group). Note: a device 'group' can appear as a logical server in a list of device servers, when in fact it refers to a 'group' of physically distinct servers of a the same variety.

In any event a call to 'tine_servers' will return a list of the known servers within the context provided. Simply typing 'tine_servers' at the command prompt will generate the 'usage' message shown below:

??? tine_servers usage:
ret=tine_servers('<context>');
'ret' contains the status/error message and returned names

Supplying a valid 'context' will generate a list of servers as shown in the following example:

>> tine_servers('PETRA')
ans =
GLOBALS: 'GLOBALS'
PETRASTATE: 'PETRASTATE'
MHFHISTORY: 'MHFHISTORY'
CAS.ARCHIVE: 'CAS.ARCHIVE'
CAS: 'CAS'
PEALARMSTATE: 'PEALARMSTATE'
ALARMSTATE: 'ALARMSTATE'
MPU_FEC: 'MPU_FEC'
PT100.1.CDI: 'PT100.1.CDI'
PT100Temp: 'PT100Temp'
PeSenderLH: 'PeSenderLH'
PeBeamLH: 'PeBeamLH'
PeBeam: 'PeBeam'
ALMSTATE: 'ALMSTATE'
SEQUENCER: 'SEQUENCER'
STATE: 'STATE'
BMS_FEC: 'BMS_FEC'
FECSTATS: 'FECSTATS'
TurboPumpen: 'TurboPumpen'
LBRTemp: 'LBRTemp'
TriggerModule_Pe: 'TriggerModule_Pe'
PT100Temps: 'PT100Temps'
PiConditions: 'PiConditions'
PiControls: 'PiControls'

tine_devices

The next tier of the TINE naming hierarchy is the device name. Simply typing 'tine_devices' at the command prompt will generate the 'usage' message shown below:

??? tine_devices usage:
ret=tine_devices('/<context>/<server>'[,'<property>']);
'ret' contains the status/error message and returned names

We see that two parameters are required, namely the desired context and the desired server name. For instance, the device list from the PETRA BPM server might be obtained as shown below

>> tine_devices('/PETRA/BPM')
Get devices returned 0
ans =
device 0: 'BPM_SWR_13'
device 1: 'BPM_SWR_31'
device 2: 'BPM_SWR_46'
device 3: 'BPM_SWR_61'
device 4: 'BPM_SWR_75'
device 5: 'BPM_SWR_90'
device 6: 'BPM_SWR_104'
device 7: 'BPM_SWR_118'
device 8: 'BPM_SWR_133'
device 9: 'BPM_WL_140'
device 10: 'BPM_WL_126'
device 11: 'BPM_WL_111'

In addition, the optional parameter 'property' can be supplied for accessing the device 'keywords' for known property servers. 'Property servers' unlike device servers are property oriented and can maintain different keyword lists for different properties. Attempting the simpler variant of the 'tine_devices' query on a property server will likely produce the status 'error' : 'has query function'. Supplying a particular property in the call will then generate a property specific 'device' (i.e. keyword) list as shown below:

>> tine_devices('/PETRA/Bunche_EWeg')
Get devices returned 16512
ans =
error: 'Names read error: RMT: has query function'
>> tine_devices('/PETRA/Bunche_EWeg','BunchStrom')
Get devices returned 0
ans =
device 0: 'IMA-E03'
device 1: 'IMA-E182'
Note
Knowing which property name to supply in the call anticipates using the next utility in our browsing toolkit, namely 'tine_properies'

tine_properties

The next tier of the TINE naming hierarchy is the property. Simply typing 'tine_properties' at the command prompt will generate the 'usage' message shown below:

??? tine_properties usage:
ret=tine_properties('/<context>/<server>/<device>');
'ret' contains the status/error message and returned names

This takes a single argument supplying the targeted endpoint, which may contain the device name (device oriented servers) but does not have to.

For instance a simpler (without a specific device name) form will work fine for 'property servers' or 'flat' servers (where each device supports the same property list and each property is supported by all devices)

\incluce eg_mlab_tine_properties1.txt

For known 'device oriented' servers, supplying the targeted device name is preferred:

\incluce eg_mlab_tine_properties2.txt

Archive Utilities

Many of the control system parameters will be archived and ready for retrievel and examination when called for.

Archived data can be stored 'centrally', where a range of filtering parameters might be in play (so as to reduce the amount of unnecessary data commited to disk). 'centrally' stored data are always availible and never expired.

Archive data can also be stored 'locally', where simpler filtering based on tolerances might be in play. 'locally' stored data are available only for a (configurable) duration, typically 1 to 3 months.

Archive data might be stored 'centrally' based on an 'event trigger'. This usually refers to 'post-mortem' events, such as an RF trip or unexpected beam loss, etc. Such data are managed differently than the regular trend archives descibed above. Event data generally have an associated event 'comment' (the reason why the event was triggered), which can be edited by 'experts' at any time. Event data are associated with a specific point in time and a specific trigger. Consequently retrieving archived event data is a bit more 'involved' than simple history trends of stored machine variabled.

Many MatLab routines are available to assist in retrieving and analysizing archive data. These will be described below.

tine_history

Simply typing 'tine_history' at the command prompt will generate the 'usage' message shown below:

??? Error using ==> tine_history
tine_history usage:
tine_history('/<context>/<server>/<name>[<property>]','<stop
time>','<depth>'[,sampleInterval,index,'acquireSystemStamps'])
'ret' contains array of (timestamp,data) or (timestamp,system stamp,data)

We see that there are three required input parameters, namely the targeted endpoint, the 'stop time' (i.e. the most recent requested data point) and the depth of the archive trend.

All parameters are strings. The 'stop time' should be given in a string data format ('dd.mm.yyyy hh:mm:ss') or the string 'now' to refer to the current time. The 'depth' is a string begining with a number and followed by a representative unit of time ('days','hours','minutes', etc.)

Optionally one can specify a 'sampling interval'. If this is '0' or less then the targeted server will determined a suitable sampling raster so that the returned data cover the desired time interval. Internally a maximum of 8000 data points will be returned. Thus for a large time interval it could happen that stored data points are 'skipped' in order to supply data throughout the requested range. If this is not the desired behavior, an explicit sampling interval can be provided. To avoid skipping any points a value of '1' should be passed (default = '0'). One can also optionally specify an array 'index' as the 5th parameter. If this value is greater than '0' then the specific array index will be selected from the any archive record that refers to an array. In the case of multi-channel arrays, this parameter is usually not necessary as the the device name will determine the array index (default = '0'). Finally one can optionally indicate in the 6th parameter whether or not to return associated 'system stamps' with the archive data. In most cases one is interested in data versus a timestamp. As most data are also archived along with the accompanying system stamp, it could be useful to retrieve this information as well. The system stamp might refer to a 'cycle number', 'pulse number', or 'shot number' depending on the nature of the accelerator. The timestamp returned is the MatLab time (and not UTC).

The targeted end point can be a specific server, in which case the 'local history' is obtained directly from the server (if it is available!), as in:

>> format long
>> tine_history('/PETRA/Idc/Buffer-0[I]','now','1hour')
ans =
1.0e+005 *
7.354026290012483 0.001006214523315
7.354026290140839 0.001006183395386
7.354026290370469 0.001006119766235
7.354026290498942 0.001006123504639
7.354026290728571 0.001006073532104
7.354026290958316 0.001006025466919

Note that as the number involved are large it is frequently useful to make use of the 'format long' specification in MatLab.

As another example obtaining the system stamp information and a sampling raster of '1':

>> format long
>> tine_history('/PETRA/Idc/Buffer-0[I]','now','1hour',1,0,'Yes')
ans =
1.0e+007 *
0.073540262897827 5.783854800000000 0.000010062985992
0.073540262900125 5.783856000000000 0.000010062145233
0.073540262901408 5.783856700000000 0.000010061833954
0.073540262903705 5.783858000000000 0.000010061197662
0.073540262904989 5.783858700000000 0.000010061235046
0.073540262907286 5.783859900000000 0.000010060735321

The targeted end point can also be a central archive server (the server 'HISTORY' in the desired context) as in:

>> tine_history('/PETRA/HISTORY/keyword[CurDC]','now','20minutes')
ans =
1.0e+005 *
7.3465 0.0010
7.3465 0.0010
7.3465 0.0010
7.3465 0.0010
7.3465 0.0010
7.3465 0.0010
7.3465 0.0010
7.3465 0.0010
7.3465 0.0010
7.3465 0.0010
7.3465 0.0010
7.3465 0.0010
7.3465 0.0010
7.3465 0.0010

or

>> format long
>> tine_history('/PETRA/HISTORY/keyword[CurDC]','now','20minutes',1,0,'Yes')
ans =
1.0e+007 *
0.073540262040709 5.783391900000000 0.000010026293182
0.073540262048884 5.783396400000000 0.000010024203491
0.073540262058089 5.783401200000000 0.000010022074890
0.073540262070856 5.783408100000000 0.000010019866943
0.073540262081075 5.783413700000000 0.000010017713928
0.073540262090533 5.783418800000000 0.000010015662384
0.073540262104313 5.783426200000000 0.000010013182068
0.073540262114786 5.783431900000000 0.000010010919189
0.073540262125274 5.783437500000000 0.000010008818817
0.073540262137789 5.783444300000000 0.000010006736755
0.073540262145964 5.783448800000000 0.000010004698181
0.073540262157719 5.783455000000000 0.000010002652740
0.073540262167937 5.783460600000000 0.000010000652313
0.073540262178426 5.783466200000000 0.000010008623505
0.073540262180723 5.783467500000000 0.000010022171021
0.073540262183273 5.783468900000000 0.000010038332367
0.073540262186601 5.783470700000000 0.000010060972595
0.073540262188897 5.783471900000000 0.000010075041962
0.073540262191194 5.783473100000000 0.000010089102936
0.073540262193509 5.783474400000000 0.000010098716736
0.073540262216513 5.783486800000000 0.000010096574402
0.073540262223656 5.783490700000000 0.000010094542694
0.073540262235158 5.783496900000000 0.000010092428589
0.073540262247944 5.783503800000000 0.000010090139008

These above examples demonstrate the acquisition of the history 'trend' of a specific value over time, which is the most common form of an archive call. Some history records are composed of a waveform 'trace' (or spectrum) of data, that is, an array. A record might also be a multi-channel array (another form on an array). It might be desireable to acquire the archived array at a specific time. This can also be acquieved with a call to 'tine_history'. In such a case, instead of specifying the depth parameter as a number of 'days', 'hours', 'minutes', etc. one gives the simple text 'snapshot', which signals the acquisition of the associated archive record at the time given as the 'stop time' parameter. There is more than likely no record stored at precisely the time indicated as the 'stop time', thus the matlab routine will return a structure containing the 'time of the record found' (equal to or more recent than specified) both in UTC and in text and a 'data' array containing the record at that time. This is shown in the example below:

>> r = tine_history('/PETRA/BLM/#0[LossRates]','21.05.15 08:00:00','snapshot')
r =
timestamp: '21.05.15 08:29:18.000 CDT'
utc: '1432189758'
data: [32x1 double]
>> r.data
ans =
279
97
102
81
74
1585
96
2
68
1
55
2
50
65
44
0
87
8
51
379
5372
40647
1392
971
635
3752
367
813
1969
1137
446
855

tine_eventdata

The event data for a specific event can be retrieved using the call 'tine_eventdata'.

Simply typing 'tine_eventdata' at the command prompt will generate the 'usage' message shown below:

??? tine_eventdata usage:
tine_eventdata('/<context>/<trigger>','/<context>/<server>/<device>[<property>]','<event_number>'[, <data_index>])

We notice that this call requires three input parameters representing the 'context' and 'event' desired. This must be in the form '/<context>/<event trigger>'. The second parameter is the fully specified stored parameter and this must in the form '/<context>/<server>/<device>[<property>]'. And note here, that the 'context' specified for the stored parameter need NOT be the same as the context for the event server! The third parameter is the desired event number (as a raw UTC event number passed as a string). An optional fourth parameter 'data_index' can be used to specify an index within a stored array.

As an example, consider:

>> tine_eventdata('/PETRA/bpm_intlk','/PETRA/BPM/BPM_SWR_13[TRIGGEROFFSET]','1305805040')
ans =
1000
1000
1000
1000
1000
1000
1000

tine_eventtriggers

An event server for a given TINE context will respond to those 'events' which have been configured by an administrator. Such events are then 'triggered' whenever conditions warrant the collection of event data. To see a list of those configured event triggers, use 'tine_eventtriggers'.

Simply typing 'tine_eventtriggers' at the command prompt will generate the 'usage' message shown below:

??? tine_eventtriggers usage:
tine_eventtriggers('<context>')

We notice that this call requires the single input parameter 'context'.
As an example, consider:

>> tine_eventtriggers('PETRA')
ans =
mhf_slsr_trc
mhf_sl0cav_trc
mhf_sr0cav_trc
mhf_sl1cav_trc
mhf_sr1cav_trc
mhf_sl2cav_trc
mhf_sr2cav_trc
mhf_fbo
mhf_slsr_err
mhf_sl1cav_err
mhf_sl2cav_err
mhf_sr1cav_err
mhf_sr2cav_err
file_saved
mhf_test_trc
temp_mdi_intlk
bpm_intlk
mps_intlk
video_test_trig
mps_intlk_test

tine_eventproperties

To see which properties are stored for a given server within a specific event use the call 'tine_eventproperties'. Simply typing 'tine_eventproperties' at the command prompt will generate the 'usage' message shown below:

??? tine_eventproperties usage:
tine_eventproperties('/<context>/<trigger>','<server>')

We notice that call takes two input parameters which must be the desired 'context' qualified with the desired 'event trigger' in the form '/<context>/<event trigger>', as well as the desired server.

For example:

>> tine_eventproperties('/PETRA/bpm_intlk','BPM')
ans =
PM_DATA_Q
PM_DATA_SUM
PM_DATA_X
PM_DATA_Y
TRIGGEROFFSET
PM_MC_TIME
PM_READTIME
PM_TRIGTIME
PM_SYS_TIME

tine_eventservers

To see which servers are incorporated within a specific event use the call 'tine_eventservers'. Simply typing 'tine_eventservers' at the command prompt will generate the 'usage' message shown below:

??? tine_eventservers usage:
tine_eventservers('/<context>/<trigger>')

We notice that call takes a single input parameter which must be the desired 'context' qualified with the desired 'event trigger' in the form '/<context>/<event trigger>'.

For example:

>> tine_eventservers('/PETRA/bpm_intlk')
ans =
/PETRA/BPM

tine_eventlist

To see which events were recorded for a specific event trigger over a time range, use the call 'tine_eventlist'. Simply typing 'tine_eventlist' at the command prompt will generate the 'usage' message shown below:

??? tine_eventlist usage:
tine_evenlist('/<context>/<trigger>','<stop time>'[,'<depth>'])

We notice that call takes two required input parameter which must be the desired 'context' qualified with the desired 'event trigger' in the form '/<context>/<event trigger>' and the 'stop time' used to terminate the search for events. Optionally the 'depth' can be provided as the third argument. The 'stop time' and 'depth' are parsed in the same manner as for the 'tine_history' call. Omitting the 3rd argument will assume a depth of the last 24 hours.

For example:

>> tine_eventlist('/PETRA/bpm_intlk','now')
ans =
1306072476 (Sun May 22 15:54:36 2011)
>> tine_eventlist('/PETRA/bpm_intlk','now','1month')
ans =
1303423528 (Fri Apr 22 00:05:28 2011)
1303424311 (Fri Apr 22 00:18:31 2011)
1303702782 (Mon Apr 25 05:39:42 2011)
1303716140 (Mon Apr 25 09:22:20 2011)
1303716427 (Mon Apr 25 09:27:07 2011)
1303719298 (Mon Apr 25 10:14:58 2011)
1303719500 (Mon Apr 25 10:18:20 2011)
1303722422 (Mon Apr 25 11:07:02 2011)
1303722583 (Mon Apr 25 11:09:43 2011)
1303723037 (Mon Apr 25 11:17:17 2011)
1303726234 (Mon Apr 25 12:10:34 2011)
1303727757 (Mon Apr 25 12:35:57 2011)
1303729438 (Mon Apr 25 13:03:58 2011)
1303730073 (Mon Apr 25 13:14:33 2011)
1303730187 (Mon Apr 25 13:16:27 2011)
1303815412 (Tue Apr 26 12:56:52 2011)
1303843474 (Tue Apr 26 20:44:34 2011)
1303845161 (Tue Apr 26 21:12:41 2011)
1303880416 (Wed Apr 27 07:00:16 2011)
1303895627 (Wed Apr 27 11:13:47 2011)
1303900758 (Wed Apr 27 12:39:18 2011)
1303900884 (Wed Apr 27 12:41:24 2011)
1303903950 (Wed Apr 27 13:32:30 2011)

We see that the event is identified by its event 'time', which is maintained as a UTC time constant. The event list dumped by the above call will give both the raw UTC time as well as the human readable time string, essentially giving the time of the event trigger.

tine_eventcomment

Stored event generally have an associated event comment generated at the time of the event, which can later be 'annotated' by experts who have later deciphered cause of the event.

To see the associated comment for a given event, use the call 'tine_eventcomment'. Simply typing 'tine_eventcomment' at the command prompt will generate the 'usage' message shown below:

??? tine_eventcomment usage:
tine_evencomment('/<context>/<trigger>','<event_number>')

We notice that call takes two required input parameter which must be the desired 'context' qualified with the desired 'event trigger' in the form '/<context>/<event trigger>' and the event 'id', i.e. the event UTC time (shown in the 'tine_eventlist' dump). This second parameter should be the raw UTC 'long' time stamp, input as a string.

For example:

>> tine_eventcomment('/PETRA/bpm_intlk','1305805040')
ans =
PM first triggered by BPM_SOR_67; List of missing PM:

Server API

You are always at liberty to invoke the MatLab engine routines within a standard TINE server to access functions written in MatLab from a standard server. This approach has its merits but also requires you to know your way around in 2 programming languages, namely MatLab AND either C or java.

In many cases this is an unnecessary and unwarranted complication. You can also write a TINE server completely in MatLab by making use of the following MatLab functions described below. Once again, these routines follow in the most part the paradigm of the Buffered Server.

tine_attach_server

If the server's properties and devices are available via a TINE database (produced, for instance, by using the TINE server wizard), then a simple call to 'tine_attach_server' will cause the configuration database to be read and make the configured properties and devices avialable. The server will automatically 'plug' itself into the control system and be visable to prospective clients. At this stage there will likely be NO intersting data to be read from any of the properties, as the underlying buffers will have been initialized to contain '0'.

Parameters
equipment_module_nameis the so-called 'local name' of the equipment module. This is a 6-character name used for administration purposes within the running process and is thus required only to be unique within the process. In MatLab, you will likely have only a single registered server per MatLab process, so this minimal restriction scarely presents a problem. Although a meaningless character string such as "1" will suffice, it is typical to provide a 3-letter acronym followed by "EQM" (for equipment module), for instance "MLBEQM".
export_nameis the equipment module's exported name. This is the server name which all control system clients will 'see'. This can be up to 32-characters in length. This name must be unique within the registered context (as given in the fecid.csv file or fec.xml file).
device_capacityis the maximum number of device instances that this server will manage.

Alternatively you can completely forgo any configuration database and register all necessary information via the registration API calls 'tine_register_fec', 'tine_register_server', 'tine_register_device', and 'tine_register_property' (see below).

tine_pushdata

In order to supply the registered properties with data, the MatLab 'server' should call 'tine_pushdata' when it has determined that new data are available for the property in question. Using just 'tine_attach_server' and 'tine_pushdata' in this manner are theoretically the only MatLab calls necessary to provide a 'READ-ONLY' server.

Parameters
propertyis the property for which the supplied data are to be used.
deviceis the specific device instance for which the supplied data are to be used. This must be a string corresponding to a registered device or a string of the form "#1", etc. which then indicates the device instance 'numerically'.
datais the data (array) which is to be 'pushed' into the underlying property buffer.
size(optional) is the length of the data array to push into the property buffer. If omitted, the entire contents of the data array will be used.
isScheduled(optional) is an integer flag which if non-zero instructs the subsystem to immediately notify all listening clients of a change in the property's data.

If the server is to respond to WRITE commands, it should provide a property dispatch handler by making use of 'tine_attach_handler'.

Note that if the data to be pushed is a structure, this must correspond to a registered structure AND the property in question must be registered to support this structure. See the discussion below concerning registering a structure and registering a property.

tine_attach_handler

If a property is to accept WRITE requests, that is requests which attempt to change a setting, then the Matlab server should provide a dispatch handler for the corresponding property. This is done by make a call to 'tine_attach_handler' and providing the appropriate MatLab function to act as the dispatcher.

Parameters
propertyis the property to which the handler is to be associated.
handler_nameis the name of a MatLab '.m' function to be called when a WRITE transaction for the property is being requested by some client. This '.m' function must return a status (an integer value, where '0' means 'success'), and it must have the prototype <dispatch>('property','device',data), where 'property' and 'device' will be set to the values in the call and 'data' will contain the contents of the set values. If no data have been sent, then this will be a null value. It is up to the dispatch routine to check the data type of this parameter and to either accept the call (return '0') or to reject the setting on some other grounds (return non-zero : see the section on TINE error codes).

tine_dispatch

In some unsual circumstances, the provided MatLab dispatch handler might throw an exception or otherwise be unable to complete normally. This will effectively block any WRITE access to the corresponding property indefinitely (until the process is restarted). In order to free the property WRITE dispatch handler again, a call to tine_dispatch can be made.

Note
Calling this routine is seldom needed and should not be used in functional servers. It can, on the other hand, be useful during the server's debugging period in 'interactive' mode.

Sine Server Example

An example of a fully function Sine Generator written entirely in MatLab is shown below. A MatLab .m file makes calls to 'tine_attach_server', which attaches itself to a pre-configured data base, 'tine_attach_handler', which is used to assign WRITE dispatch routines for certain 'settable' properties. It also starts a MatLab timer which updates the waveforms returned in calls to the property 'Sine'. It also exercises the call 'tine_pushdata'.

As this server uses global arrays for the values of the amplitudes, frequencies, and noise for the individual Sine curves (there are 10 of them), these are also declared in this starup routine.

global ampl
global freq
global nois
% some initial settings :
ampl = [256 256 256 256 256 256 256 256 256 256]
freq = [1 1 1 1 1 1 1 1 1 1]
nois = [5 5 5 5 5 5 5 5 5 5]
% attach to a configuration database using the local equipment module name
% "SINEQM"
tine_attach_server('SINEQM');
% push some data into property "Amplitude" (just for fun)
tine_pushdata('Amplitude','SineGen0',10,1,0);
tine_pushdata('Amplitude','SineGen3',44,1,0);
% attach property dispatch handlers for properties "Amplitude",
% "Frequency", and "Noise"
tine_attach_handler('Amplitude','tine_amplitude_dispatch');
tine_attach_handler('Frequency','tine_frequency_dispatch');
tine_attach_handler('Noise','tine_noise_dispatch');
% start an update task ...
t = timer('TimerFcn',@sine_update,'Period',1.0,'ExecutionMode','fixedRate')
% note: sine_update.m calls putsine.m
start(t)

The call to 'tine_attach_server' as noted above attaches itself to a configuration database.
In this case, it consists of a set of .csv files.

The file 'fecid.csv' is located in the FEC_HOME directory:

EXPORT_NAME,FEC_NAME,Context,SubSystem,Port_Offset,Description,Location,Hardware,Responsible
MLSineServer,MLSINEGEN.7,TEST,SER,7,Test,Bldg 30 Room 502,None,P.Duval

The file 'exports.csv' is located in a subdirectory of the FEC_HOME directory called 'SINEQM' (the subdirectory name MUST be the same as given the call to 'tine_attach_server').

CONTEXT,EXPORT_NAME,LOCAL_NAME,PROPERTY,PROPERTY_SIZE,PROPERTY_INSIZE,PROPERTY_ID,ACCESS,FORMAT,NUM_DEVICES,DESCRIPTION
TEST,MLSineServer,SINEQM,Sine,8192,0,1,READ|XREAD,float.SPECTRUM,10,[-1000:1000 V][0:1000 ms]Sine Curve
TEST,MLSineServer,SINEQM,Amplitude,10,1,2,READ|WRITE,float.CHANNEL,10,[1:1000 V !LOG]Sine Curve Amplitude
TEST,MLSineServer,SINEQM,Frequency,10,1,3,READ|WRITE|SAVERESTORE,float.CHANNEL,10,[1:60]Sine Curve Frequency
TEST,MLSineServer,SINEQM,Phase,10,1,4,READ|STATIC,float.CHANNEL,10,[0:512]Sine Curve Phase
TEST,MLSineServer,SINEQM,Noise,10,1,5,XREAD|WRITE,float.CHANNEL,10,[0:100 V]Sine Curve Noise Level

This file essentially gives the names of the exported properties as well as all relevant information about the exported properties. This information is in fact used to determine the sizes and behaviors of the underlying property buffers. The file 'exports.csv' also provides the exported server name, in this case "MLSineServer". This exported server name is used as a cross-reference within the fecid.csv file to latch onto the appropriate FEC, in case of any ambiguity (note: a fecid.csv can contain multiple entries).

The file 'devices.csv' is also located in the 'SINEQM' subdirectory and provides the device names for the individual devices.

DEVICE_NUMBER,DEVICE_NAME,DEVICE_DESCRIPTION
0,SineGen0,sine generator 1
1,SineGen1,sine generator 2
2,SineGen2,sine generator 3
3,SineGen3,sine generator 4
4,SineGen4,sine generator 5
5,SineGen5,sine generator 6
6,SineGen6,sine generator 7
7,SineGen7,sine generator 8
8,SineGen8,sine generator 9
9,SineGen9,sine generator 10

Note that the number of devices in total is given in the 'exports.csv' file as '10' (the NUM_DEVICES column). Thus, at most 10 entries will be read from the 'devices.csv' file.

The update routine used in the Matlab timer looks like the following:

function sine_update(obj, event)
putsine('SineGen0');
putsine('SineGen1');
putsine('SineGen2');
putsine('SineGen3');
putsine('SineGen4');
putsine('SineGen5');
putsine('SineGen6');
putsine('SineGen7');
putsine('SineGen8');
putsine('SineGen9');

The update routine used in the MatLab timer is called 'putsine'. It looks like the following:

function cc = putsine(DEV)
global ampl
global freq
global nois
% get the array index according to the device name
idx = get_sine_device_index(DEV);
r = 0:1:1024;
% use the correct amplitude, frequency, and noise array elements
% for the calcuation
v = ampl(idx) * sin(r * 2 * freq(idx) * pi / 1024);
v = v + (nois(idx) * randn(1,size(v,2)));
% push the results into the underlying property buffer
cc = tine_pushdata('Sine',DEV,v);

This routine in turn makes use of a .m File to determine the device index from a device name. This looks like the following:

function idx = get_sine_device_index(dev_name)
if strcmp(dev_name,'SineGen0')
idx = 1;
elseif strcmp(dev_name,'SineGen1')
idx = 2;
elseif strcmp(dev_name,'SineGen2')
idx = 3;
elseif strcmp(dev_name,'SineGen3')
idx = 4;
elseif strcmp(dev_name,'SineGen4')
idx = 5;
elseif strcmp(dev_name,'SineGen5')
idx = 6;
elseif strcmp(dev_name,'SineGen6')
idx = 7;
elseif strcmp(dev_name,'SineGen7')
idx = 8;
elseif strcmp(dev_name,'SineGen8')
idx = 9;
elseif strcmp(dev_name,'SineGen9')
idx = 10;
else
idx = 0
end

Several dispatch routines are also registered to handle any incoming WRITE commands to change the value settings. For instance, the dispatch routine used to handle WRITE commands to the property "Amplitude" looks like:

function ret = tine_amplitude_dispatch(PRP,DEV,DATA)
global ampl
% just get the new value and accept it
idx = get_sine_device_index(DEV)
ampl(idx) = DATA;
% push the new value into the corresponding read buffer:
ret = tine_pushdata(PRP,DEV,DATA,1,0);

tine_register_fec

You can assign a FEC name to your MatLab server via the API call 'tine_register_fec'. This will, of course', hard-wire the FEC name within the MatLab code, but this could be a a reasonable alternative to using configuration files, as a MatLab server is most likely to be a single instance middle-layer server and will only ever run as a single instance.

Simply typing 'tine_register_fec' at the MatLab prompt will produce the following output:

??? tine_register_fec usage:
ret=tine_register_fec('fec_name'[,'sub_system','context','description','location','hardware','responsible',portOffset])

The one required argument is the 'fec_name', which must be system wide unique (see the Overview documentation: 'What's in a Name?'). However if all other arguments are omitted, then the default port offset will be '0' which could be in conflict with other servers which are possibly running on the same host, so be careful here! Likewise it is often useful to provide information as the location, responsibility, 'context' (default = "TEST") and 'subsystem' (default = "TEST"). So making use of all parameters is encouraged.

Parameters
fec_nameis the system wide unique name of the FEC process (up to 16 characters in length)
sub_systemis the control subsystem to which the servers should be associated. (e.g. "VAC", "DIAG", "MAG", etc.). This is not a part of the name hierarchy but can be used in browsing.
contextis the control system context in which the servers should be registered.
descriptionis a description (up to 64 characters) of the functionality of the FEC.
locationis a string (32 characters) containing the phyisical location of the FEC host computer.
hardwareis a string description of attached hardware. For most MatLab middle layers, this will simply be "none".
responsibleis the person (or persons) to contact in case of problems. It should also contain the 'user name' if possible of such persons, as administrative actions (such as 'removing' the FEC from the ENS database) will require a 'match' on the user name of the person attempting such actions versus those 'responsible' for the FEC in question.
portOffsetis the port 'offset' to be applied to all of the server's listening service ports. This should be a simple integer between 0 and 65535, but preferably small. The default is '0'.
If multiple FECs run on a single computer, then each must have its own unique port offset. Hence the default value of '0' will work only once per host. Once again, this is not the listening 'port address' but is an 'offset' to be applied to a set of listening ports (UDP, TCP, STREAM, Debug, and even possibly IPX).
Returns
'0' upon success or a TINE error code.

tine_register_server

You can assign the server's exported name and local equipment module name to your MatLab server via the API call 'tine_register_server'.

Simply typing 'tine_register_server' at the MatLab prompt will produce the following output:

??? tine_register_server usage:
ret=tine_register_server('export_name','equipment_module_name',device_capacity)
Parameters
export_nameis the equipment module's exported name. This is the server name which all control system clients will 'see'. This can be up to 32-characters in length. This name must be unique within the registered context (as given in the fecid.csv file or fec.xml file).
equipment_module_nameis the so-called 'local name' of the equipment module. This is a 6-character name used for administration purposes within the running process and is thus required only to be unique within the process. In MatLab, you will likely have only a single registered server per MatLab process, so this minimal restriction scarely presents a problem. Although a meaningless character string such as "1" will suffice, it is typical to provide a 3-letter acronym followed by "EQM" (for equipment module), for instance "MLBEQM".
device_capacityis the maximum number of device instances that this server will manage.
Returns
'0' upon success or a TINE error code.

tine_register_device

You can assign the server's device instance names within your MatLab server via the API call 'tine_register_device'.

Simply typing 'tine_register_device' at the MatLab prompt will produce the following output:

??? tine_register_device usage:
ret=tine_register_device('device_name',device_number[,'device_redirection','device_description'])
Parameters
device_nameis the name of the device instance to be registered.
device_numberis the associated device number. This must be greater than or equal to 0 and smaller than the 'device_capacity' entered in 'tine_register_server' in order to succeed.
device_redirection(optional) must be a string of the form '/<context>/<server>/<device>[<property>]' if the device instance in question does reside on the local server but should be redirected to a remote server.
device_description(optional) can be used to supply a device description.
Returns
'0' upon success or a TINE error code.

tine_register_property

You can assign the server's property names and information within your MatLab server via the API call 'tine_register_property'.

Simply typing 'tine_register_property' at the MatLab prompt will produce the following output:

??? tine_register_property usage:
ret=tine_register_property('property_name',in_size,'in_type',out_size,'out_type',max,min,'egu',access,'description'[,'array_type',row_length])

Here there are in all 10 required parameters:

Parameters
property_nameis the property name to be registered
in_sizegives the array size of any input parameters required by the property
in_typegives the data type of any input parameters required by the property. This should by a string such as 'float', 'int32' (synonym: 'int'), etc. Strings entries are best dealt with by using a 'fixed-capacity' string type such as 'NAME16' or 'NAME64', etc.
out_sizegives the array size of any output parameters deliverd by the property
out_typegives the data type of any output parameters delivered by the property. This should by a string such as 'float', 'int32' (synonym: 'int'), etc. Strings entries are best dealt with by using a 'fixed-capacity' string type such as 'NAME16' or 'NAME64', etc.
maxgives the maximum range of the property values
mingives the minimum range of the property values
egugives the engineering units of the property (a string not to exceed 16 characters)
accessgives the supported access ('READ', 'WRITE', 'READ|WRITE', etc.)
descriptiongives a description of the data supplied by, or the action initiated by calling the property.

In addition, there are two optional parameters which can (and should) be used to supply useful information. These are:

Parameters
array_typegives the type of array returned by a call to the property. This is typically 'unknown', 'scalar', or in the case of a real array 'channel' (for multi-channel arrays) or 'spectrum'(for waveform or trace arrays).
row_lengthgives the row length in cases where 'multi-dimensional' arrays are returned.
The row length will default to the output data size if not explicitly given.
Returns
A positive 'id' for the registered property upon success or the negative of a TINE error code if there is an error.

Sine Server Example II

A second example of a fully function Sine Generator written entirely in MatLab is shown below. This example simply duplicates the functionality of the example shown above, but in this case ALL server information is registered via API.

tine_register_fec('MLFEC','TEST','TEST','MatLab test fec','here','none','me',44);
tine_register_server('MLSineServer','MLEQM',10);
tine_register_property('Amplitude',1,'float',10,'float',512,1,'V','READ|WRITE','Sine Amplitude','CHANNEL');
tine_register_property('Frequency',1,'float',10,'float',50,1,'Hz','READ|WRITE','Sine Frequency','CHANNEL');
tine_register_property('Phase',1,'float',10,'float',6.28,0,' ','READ|WRITE','Sine Phase','CHANNEL');
tine_register_property('Noise',1,'float',10,'float',50,0,'V','READ|WRITE','Sine Noise','CHANNEL');
tine_register_property('Sine',0,'null',1024,'float',512,1,'V','READ','Sine Curve','SPECTRUM');
tine_register_device('SineGen0',0);
tine_register_device('SineGen1',1);
tine_register_device('SineGen2',2);
tine_register_device('SineGen3',3);
tine_register_device('SineGen4',4);
tine_register_device('SineGen5',5);
tine_register_device('SineGen6',6);
tine_register_device('SineGen7',7);
tine_register_device('SineGen8',8);
tine_register_device('SineGen9',9);
global ampl;
global freq;
global nois;
freq = [1 1 1 1 1 1 1 1 1 1];
ampl = [256 256 256 256 256 256 256 256 256 256];
nois = [5 5 5 5 5 5 5 5 5 5];
tine_pushdata('Amplitude','SineGen0',10,1,0);
tine_pushdata('Amplitude','SineGen2',44,1,0);
tine_attach_handler('Amplitude','tine_amplitude_dispatch');
tine_attach_handler('Frequency','tine_frequency_dispatch');
tine_attach_handler('Noise','tine_noise_dispatch');
t = timer('TimerFcn',@sine_update,'Period',1.0,'ExecutionMode','fixedRate');
start(t);

tine_register_type

A MatLab server can handle structures as input or output like any other TINE server. You will need to register the structure(s) you wish to use during initialization. This is best accomplished by making use of a call to 'tine_register_type'.

Simply typing 'tine_register_type' at the command prompt produced the following output:

>> tine_register_type
??? tine_register_type usage:
ret=tine_register_type('name_tag',values);
where 'name_tag' is the structure tag associated with the type and values = MatLab structure array representing the data type
'ret' contains the status/error message
Parameters
name_tagis the structure tag to assign to the data type (16 characters maximum)
valuesis a reference to the structure object to use to register the data type. Note that if this is an array of structures, then the size of the array will reserve the proper amount of space for the structure storage.

The easiest way to register a structure then is to form an instance and pass it along with a structure 'tag' name in a call to tine_register_type.

global inf;
inf.amplitude = 100;
inf.frequency = 1;
inf.noise = 50;
inf.phase = 0;
inf.description = 'just another sine curve';
tine_register_type('MlabInf',inf);

Note that for simplicity, all number fields will automatically use type 'double' and all character fields will automatically use a string capacity on the next largest 64-character boundary. The fields within the structure can also be arrays.

You are now in a position to register a property which uses this structure. Below is an example which will use this both as input and as output.

tine_register_property('SineInfo',1,'struct.MlabInf',1,'struct.MlabInf',0,0,'none','READ|WRITE','Sine info','SPECTRUM');

To push data into this property's buffer simply call 'tine_push_data' as before:

tine_pushdata('SineInfo','SineGen0',inf);

To react to clients sending a structure as input for this property, simply register a dispatch routine as always. The 'data' parameter passed to the dispatch routine will contain the contents of the incoming structure. The dispatch routine should of course examine the contents and make a decision to accept or not.


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