Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Device properties have one of the following scalar types (This list of types was extracted from ACS/LGPL/CommonSoftware/baciidl/ws/idl/baci.idl in ALMA-RELEASE-B branch of Subversion revision 242801): *float{*}, *double{*}, *long* (32-bit signed integer), *uLong* (32-bit unsigned integer), *longLong* (64-bit signed integer), *uLongLong* (64-bit unsigned integer), *boolean{*}, *string{*}, *pattern* and  enum, where "pattern" stands for an unsigned long. The typedef pattern is used because this type will mostly be used to encode a pattern of status bits. Furthermore, "pattern" is a single word as opposed to "unsigned long". The type pattern can be used also for raw binary data. In the next generation of ACS we plan to use code generators, either from a special template preprocessor or from UML models. In then, it will be much easier to add any new type, therefore it doesn't make much sense to spend the time now.

...

If methods on remote objects (either Component or property) fail for unexpected reasons, in particular methods that do not even return a completion, such as calls to characteristics or invocation of monitors, then, and only then, exceptions are thrown. If the remote object can not be reached, then the local ORB raises a CORBA::NO_IMPLEMENT exception. If the remote object can not finish the request for whatever reason, it raises CORBA::NO_RESOURCES. These exceptions are unchecked, i.e. they are not predeclared in the signature of the method in the IDL file.

...

...

Applying BACI Patterns to ACS Property Data Types

This chapter section describes the implementation of the patterns described in BACI with the concrete types defined for ACS.

...

Callbacks

Asynchronous notification of results can be implemented with CORBA in two ways: either through callbacks or with the CORBA event/notification services. The latter is very powerful and suited also for clients that are not multi-thread capable. The advantage of callbacks on the other side is that they are simpler to use and that callbacks are implemented by all existing ORBs. Callbacks furthermore allow for type checking during compile-time, while events are always of type CORBA::any. We therefore use callbacks.
Program execution flow when executing callbacks is reversed to what we are used to. After the device server has finished executing a requested command, it becomes a client and requests execution of a callback method on the client, which for the time of this method call becomes a server. Two things have to considered by the client developer:

  • The client has to first create a callback object, then it invokes the remote asynchronous command, giving the reference to the callback object as one of the parameters of the call
  • The callback is executed on request of the device server, completely independent of the normal execution flow on the client. The callback is therefore running in a separate thread. The thread itself is created and managed by CORBA, so there is no work for the client programmer.

...

BACI

...

also

...

prescribes

...

the

...

pattern,

...

how

...

asynchronous

...

requests

...

must

...

be

...

done:

Code Block

request(par1, par2,…,in CB<type> cb, in CBDescIn desc);
\\

We

...

see,

...

that

...

when

...

the

...

client

...

passes

...

the

...

callback

...

to

...

the

...

server,

...

it

...

must

...

accompany

...

it

...

with

...

the

...

CBDescIn

...

structure.

...

And

...

both

...

are

...

always

...

at

...

the

...

end

...

of

...

the

...

parameter

...

list.

...

The

...

callback

...

object

...

CB<type>

...

is

...

explained

...

in

...

detail

...

below.

...

The

...

parameter

...

desc

...

(for

...

descriptor)

...

allows

...

the

...

client

...

to

...

describe

...

some

...

attributes

...

of

...

the

...

callback

...

object:

Code Block
languagecpp

struct CBDescIn\ {
  TimeInterval normal_timeout;
  TimeInterval negotiable_timeout; // not used in ACS, 
  Tag id_tag; // Provided by Client to uniquely tag the incoming callback call.
\};
\\

The

...

TimeInterval

...

normal_timeout

...

is

...

sent

...

by

...

the

...

client

...

to

...

the

...

server

...

to

...

inform

...

it

...

that

...

it

...

expects

...

a

...

reply

...

in

...

the

...

normal_timeout

...

period,

...

before

...

it

...

will

...

raise

...

a

...

timeout

...

error

...

condition.

...

The

...

server

...

must

...

complete

...

the

...

operation

...

or

...

send

...

a

...

notification

...

that

...

the

...

operation

...

is

...

still

...

in

...

progress.

...

The

...

Tag

...

id_tag

...

is

...

discussed

...

with

...

the

...

CBDescOut

...

structure.

...

For

...

clients

...

written

...

in

...

Java,

...

the

...

Abeans

...

\[5\]

...

library

...

conveniently

...

does

...

all

...

the

...

work,

...

so

...

that

...

the

...

programmer

...

doesn't

...

even

...

have

...

to

...

know

...

CORBA

...

and

...

even

...

less

...

all

...

those

...

callbacks

...

and

...

descriptors.

...

The

...

callback

...

interface

...

for

...

simple

...

types

...

is

...

illustrated

...

with

...

these

...

two

...

examples:

Code Block
languagecpp

interface CBvoid: Callback\ {
  oneway void working(in Completion c, in CBDescOut desc);
  oneway void done(in Completion c, in CBDescOut desc);
\};
interface CBdouble: Callback\{  
  oneway void working(in double value, in Completion c, in CBDescOut desc);  
  oneway void done(in double value, in Completion c, in CBDescOut desc); 
\};
\\

All

...

callback

...

methods

...

are

...

of

...

type

...

oneway,

...

which

...

means

...

that

...

the

...

invoker

...

(the

...

device

...

server

...

in

...

this

...

case)

...

does

...

not

...

have

...

to

...

wait

...

for

...

the

...

callback

...

methods

...

to

...

finish.

...

The

...

reason

...

for

...

this

...

is

...

that

...

we

...

do

...

not

...

want

...

to

...

influence

...

the

...

performance

...

of

...

device

...

servers

...

if

...

client

...

code

...

is

...

written

...

badly.

...

The

...

callback

...

CBvoid

...

does

...

not

...

return

...

any

...

value,

...

only

...

the

...

time

...

stamp

...

and

...

possible

...

errors

...

in

...

the

...

completion

...

structure.

...

It

...

is

...

used

...

mainly

...

to

...

return

...

the

...

completion

...

after

...

an

...

asynchronous

...

command

...

has

...

been

...

executed

...

or

...

to

...

act

...

as

...

an

...

event

...

without

...

data.

...

Since

...

BACI

...

takes

...

extreme

...

care

...

to

...

be

...

type-safe,

...

there

...

is

...

one

...

callback

...

class

...

for

...

each

...

data

...

type

...

that

...

is

...

transferred.

...

The

...

above

...

example

...

of

...

CBdouble

...

is

...

for

...

values

...

of

...

type

...

double.

...

Callbacks

...

for

...

other

...

types

...

are

...

equivalent;

...

just

...

replace

...

all

...

three

...

occurrences

...

of

...

"double"

...

with

...

the

...

appropriate

...

primitive

...

type.

...

The

...

CBDescOut

...

type

...

defines

...

a

...

structure

...

that

...

is

...

a

...

descriptor

...

of

...

the

...

callback

...

with

...

information

...

from

...

the

...

server:

Code Block
languagecpp

struct CBDescOut\ {
  TimeInterval estimated_timeout; 
  Tag id_tag; 
\};
\\

The

...

parameter

...

estimated_timeout

...

contains

...

the

...

estimated

...

time

...

for

...

the

...

callback

...

to

...

be

...

returned.

...

This

...

value

...

can

...

be

...

used

...

by

...

the

...

client

...

for

...

timeout

...

handling

...

...

if

...

the

...

callback

...

is

...

not

...

received

...

within

...

this

...

time

...

plus

...

some

...

safety

...

margin,

...

the

...

client

...

can

...

assume

...

that

...

there

...

was

...

a

...

problem

...

on

...

the

...

server

...

side.

...

The

...

id_tag

...

is

...

a

...

numeric

...

index

...

(the

...

Tag

...

data

...

type

...

is

...

nothing

...

but

...

an

...

unsigned

...

long),

...

which

...

has

...

been

...

provided

...

by

...

the

...

client

...

in

...

the

...

CBDescIn

...

structure,

...

when

...

making

...

the

...

asynchronous

...

request.

...

This

...

can

...

be

...

used

...

by

...

the

...

client

...

to

...

distinguish

...

callbacks

...

from

...

different

...

requests.

...

When

...

the

...

callback

...

is

...

used

...

for

...

asynchronous

...

notification

...

in

...

response

...

to

...

some

...

action,

...

the

...

done

...

method

...

must

...

be

...

invoked

...

when

...

the

...

action

...

terminates,

...

either

...

with

...

error

...

condition

...

or

...

success.

...

When

...

the

...

client

...

processes

...

the

...

done

...

invocation,

...

it

...

may

...

discard

...

the

...

callback.

...

If

...

the

...

action

...

is

...

time

...

consuming,

...

i.e.

...

it

...

cannot

...

be

...

completed

...

before

...

the

...

normal_timeout

...

parameter,

...

the

...

server

...

must

...

issue

...

a

...

working

...

notification

...

periodically

...

(the

...

server

...

works

...

under

...

presupposition

...

that

...

each

...

invocation

...

resets

...

the

...

client's

...

timeout

...

timer

...

to

...

the

...

normal_timeout

...

period).

...

The

...

client

...

must

...

not

...

discard

...

the

...

callback

...

before

...

done

...

notification

...

is

...

called

...

or

...

one

...

of

...

the

...

notifications

...

timeout

...

on

...

the

...

client

...

side.

...

See

...

the

...

BACI

...

specifications

...

for

...

a

...

detailed

...

discussion

...

on

...

timeouts.

...

In

...

normal

...

cases,

...

a

...

"single-shot"

...

command

...

invokes

...

the

...

done

...

method

...

of

...

the

...

callback,

...

while

...

monitors

...

regularly

...

call

...

working.

...

...

Event Sets and Alarms

The BACI specification does not explicitly define alarms. BACI specifies more general ways of user notifications, called events. Any multiple asynchronous notification that can be subscribed to is an event. Most of event types will be defined by device server programmers, who know what kind of events happen for a device and its properties. It is not the task of ACS to prescribe device events. The exception are alarms, which are a very standard kind of events. We can therefore define alarms as BACI-type events already for ACS. QUESTION: If alarm is a part of event, does BACI property need to call working() method every normal_timeout in the same way as other events? If so, can we use the same error type and code for Completion structure?
We may probably have to check the alarm behavior of the current C++ BACI implementation, and document its behavior here as the specificationalready for ACS. Alarms are passed asynchronously as usual through callbacks, which correspond to the type of the property value. As always, a callback descriptor has to be given in the parameter list. As also alarms must be type-safe, ACS foresees several alarms, one for each property type.

For each value type there is an Alarm event set. They all follow the same design pattern: Each alarm event set contains two events, alarm_raised and alarm_cleared. If the reason for an alarm changes, then alarm_raised can be invoked again, sending the new value and/or the new alarm code. It is not necessary that a new alarm_raised event should occur only after the alarm has been cleared. Each event is a callback method call that returns the value that is responsible for the event, a completion structure that contains the reasons for the alarm and a CBDescOut structure, which is returned with all callbacks.

Code Block
languagecpp
interface Alarmpattern : Callback{

...


    oneway void alarm_raised(in pattern value, in Completion c, in CBDescOut desc);

...


    oneway void alarm_cleared(in pattern value, in Completion c, in CBDescOut desc);

...


};

...



interface Alarmdouble : Callback{

...


    oneway void alarm_raised(in double value, in Completion c, in CBDescOut desc);

...


    oneway void alarm_cleared(in double value, in Completion c, in CBDescOut desc);

...


};

...



interface Alarmlong : Callback{

...


    oneway void alarm_raised(in long value, in Completion c, in CBDescOut desc);

...


    oneway void alarm_cleared(in long value, in Completion c, in CBDescOut desc);

...


};

...



interface Alarmstring : Callback{

...


    oneway void alarm_raised(in string value, in Completion c, in CBDescOut desc);

...


    oneway void alarm_cleared(in string value, in Completion c, in CBDescOut desc);

...


}; 


There are no alarm types for sequences of values, because the alarm can only be triggered by a single value. This means that <type>Seq property may raise an alarm and the client may subscribe to the alarm by passing Alarm<type> CORBA object, but the callback is invoked for each element in the sequence. For example, if 4 values in a sequence go over a certain limit, the callback will be invoked 4 times.QUESTION: This is how <type>Seq is implemented in C++ (I just checked the code and did not test its actual behavior, so it could be wrong), and I added these sentences here. However, I think it is not a good implementation because, from the view point of the client, the client cannot know which element raises an alarm because Completion or CBDescOut structures do not have a field which holds the index of the element.
I personally think that the alarm is not necessary for Seq type. If the device server developer needs to define an alarm for Seq type, he can extend BACI property to support alarm by himself and the alarm condition should be defined by the developer (e.g. if average of all elements go over a certain value). I cannot come up with a good usage of the current alarm implementation for Seq types in C++.
My suggestion is that we explicitly state that BACI specification does not officially provide alarms for Seq types. This means that the client may still use the existing C++ BACI Seq type properties, but it won't be officially supported and jBACI won't also implement the alarms for Seq types.
Is this a reasonable solution?
A process subscribes to alarms via a method that is part of all RO (read-only) properties. Following is the code from the ROdouble property; for other types all occurrences of double have to be replaced correspondingly:
Subscription new_subscription_Alarm(in Alarmdouble cb, in CBDescIn desc);QUESTION: The method name was formally new_subscription_Alarmdouble, but as far as I see baci.idl, its name was new_subscription_Alarm and the method name is the same for all types. I think it is better to modify this specification in this case. Is it OK?
Note that, even if the same method name is used for different types, type checking will be still done by the compiler by checking the type of the first argument (Alarmdouble in this case).
Only properties of type RO have alarms, as RW properties should not even be able to set values in the alarm ranges. The method returns a Subscription object, which has to be used to destroy the subscription to the alarm events. The Subscription object is the event source interface. It is also the superclass for monitors (see next section).
interface Subscription{
// temporarily suspends dissemination of event callbacks.
void suspend();
// resumes dissemination of callbacks. Ignored if no previous suspend occured.
void resume();QUESTION: For monitoring purpose, if resume() is called after suspend, when shall the first timer trigger be invoked? Immediately after resume() invocation? Or, the time shall be aligned to start_time? If I were a client developer, I would expect that the timer trigger is always aligned to start_time so that the callback is called, for example, at 0:0:0, 0:0:10, 0:0:20, 0:0:30, … if we set the time interval to 10 seconds.
The same discussion goes for the case where the time interval is changed by set_timer_trigger().
// stops dissemination of event callbacks and releases all resources.
void destroy();QUESTION1: Is there any specification (in CORBA or ACS) about what the servant should do when a method is called after destroy() is called. This could happen when a client has several threads, and one thread may call destroy() and, right after that, another thread may call another method.
QUESTION2: Is this destroy() method a standard method to destroy a remote CORBA object? If so, how CORBA ORB responds to the client when a remote object is destroyed (or being destroyed).
QUESTION3: Is there a good document about the lifecycle of the dynamically created CORBA objects. Particularly, I would like to know how such CORBA object shall be implemented in Java (e.g. what methods should be implemented to support the lifecycle of CORBA object and what assumptions can be made to implement those methods). For Java implementation, I am also wondering how the corresponding Java object will be removed from the heap (e.g. when CORBA ORB releases the reference of that Java object?).

...

The above discussion is not necessary for monitors, because monitor callbacks are sent repeatedly and even if a few are lost due to client or server downtime, the actual situation is always restored with the new arriving callback.
Alarms can occur for any reason, which are mostly related to hardware. However, for values types that can be defined in intervals, such as double and long, most alarms will come from values that exceed some safety limits. For those value types, a RO-property contains four characteristics that define the limits for alarms:
readonly attribute double alarm_low_on; // below this value alarm is set
readonly attribute double alarm_low_off; // above this value alarm is cleared
readonly attribute double alarm_high_on; // above this value alarm is set
readonly attribute double alarm_high_off; // below this value alarm is clearedQUESTION1: Which software component is in charge of ensuring that alarm_low_on <= alarm_low_off < alarm_high_off <= alarm_high_on. Is it MACI? XML schema of CDB? If this relation is not guaranteed by any other software component than BACI, BACI has to define the behavior if the above relation is not fulfilled.

QUESTION2: It must be clarified whether "below" and "above" mean inclusive or exclusive. As far as I see the current BACI implementation in C++, both words indicate inclusive (see baci::AlarmSystemMonitorCont<T, TPROP>::check method implementation in the following file):
https://svn.alma.cl/p2/branches/ALMA-RELEASE-B/ACS/LGPL/CommonSoftware/baci/ws/include/baciAlarmSystemMonitorCont_T.i
However, this is neither good specification nor implementation because, if the same value is set to alarm_low_on and alarm_low_off and the property value is exactly the same as them, the alarm will be raised and cleared alternatingly until the value changes.
I think the best specification would be that, an alarm is raised when the subjected value becomes equal to alarm_high_on or more, and the alarm is cleared when it becomes less than alarm_high_off. And the same thing goes for alarm_low_on and alarm_low_off.
However, this specification change causes incompatibility, and C++ implementation has to be modified accordingly. Is it an acceptable solution? Or, do we have a better solution?
There are two values for each interval boundary, in order to have hysteresis that prevents from constant triggering of alarms due to noisy signal levels.

...

...

Monitors

A client will often need to get the value of a property on a regular basis, either at given time intervals or whenever the value changes. A regular callback with the updated value is invoked by means of a monitor. The client creates a remote monitor on the server by calling one of the two methods of a property (again, the example is from the Pdouble property):
Monitordouble create_monitor(in CBdouble cb, in CBDescIn desc);
Monitordouble create_postponed_monitor(in Time start_time, in CBdouble cb, in CBDescIn desc);
The first method create_monitor() starts continuous monitoring with default time interval specified by default_timer_triger characteristic. It implies that the client does not have to explicitly call resume() method on the returned Monitor<type> object to start the monitoring. The monitoring with the default time interval automatically starts. As in all asynchronous requests, a callback object cb and its descriptor desc have to be provided. See callbacks for more details.
The second method create_postponed_monitor() registers a monitor whose beginning will be postponed until the specified start_time, which is given in absolute time. Once it starts to regularly send callbacks, it is undistinguishable from a normal monitor. Note that start_time corresponds to an absolute time such that the monitor callback will not be sent before this time. It can generally not be guaranteed that the callback is sent exactly at the specified time. It is the responsibility of the user to specify a reasonable start time. If the specified time is smaller than the actual time, the method is equivalent to create_monitor().
As we are already used to, also the use of monitors are strongly typed. Each property has a different signature for create_monitor(), depending on the type of callback object it is given to. Monitors, however, are not typed, because a monitor is only managing the dissemination of callbacks and has nothing to do with the type:
interface Monitor: Subscription{
void set_timer_trigger(in TimeInterval timer);
void get_timer_trigger(out TimeInterval timer);
readonly attribute Time start_time;
};
Monitors start with a default repetition rate, which can be obtained via the property characteristic default_timer_trigger (see next section). A client can request different monitor rates with the method set_timer_trigger(), which sets the requested delta time between two consecutive monitor callbacks. In order to protect network bandwidth, there is also an absolute minimal time, given by the property characteristic min_timer_trigger. A client can not request timer triggers lower than that value. The timer trigger can be disabled by passing the value 0 for timer parameter. That means that monitors will be sent only if a value changes significantly and the value trigger is set (see below). Invalid values (out-of-limits) are treated as valid extremes (a time interval out-of-limits defined by the server is interpreted as minimumQUESTION: Originally, this sentence said that "out-of-limits defined by the server is interpreted as maximum allowed time interval", but, to my understanding, there is no upper limit for the time interval. Instead, there is the lower limit that is determined by min_timer_trigger. Is it true? allowed time interval).
Note that the TimeInterval timer is an approximate time between two callbacks. The real time between two callbacks can be more, as real-time performance cannot be guaranteed. The TimeInterval is related to the monitor, not to the property, i.e. two clients, or even the same client can request monitors on a given property at different rates.
The method get_timer_trigger() returns the current TimeInterval between two consecutive monitor callbacks. An interesting attribute for postponed monitors is the read-only attribute Time start_time, which returns the absolute time of the first monitor callback that will occur. This can be used to check for erroneous inputs to create_postponed_monitor(). In case of normal monitors, start_time holds the absolute time of the first callback sent by the monitor.
As the monitor interface inherits from subscription, a monitor can also be suspended and resumed. When a client does not want to receive monitor event any more, it calls the destroy() method on the monitor. It then gets one more callback, with the method done() instead of working() – as described in the section on callbacks. After the reception of done(), the callback object can be safely destroyed, because there will be no monitor callbacks anymore.
Apart from the usual timer triggers, which trigger a callback at regular intervals, there are also variable triggers for the numeric property types. Those can be customized to trigger callbacks whenever a value changes by a certain amount. This amount is set and retrieved via similar methods as for the timer trigger, as can be seen in the following IDL code:
interface Monitordouble: ACS::Monitor{
void set_value_trigger(in double delta, in boolean enable);
void get_value_trigger(out double delta, out boolean enable);
void set_value_percent_trigger(in double delta, in boolean_enable);
void get_value_percent_trigger (out double delta, out boolean enable);QUESTION1: I added these two methods because they are defined in baci.idl in ALMA-RELEASE-B branch, but it is not clear to me when the monitor should be triggered. The inline document of baci.idl says, if the value changes by a percentage delta, but percentage of what? I thought it could be the percentage of (max_value – min_value), but these characteristics do not exist in RO property types…
QUESTION2: If the client calls set_value_trigger() and set_value_percent_trigger(), do value trigger and percentage trigger coexist?

};
On creation of a monitor, the only trigger present will be the timer trigger. Calling the set_value_trigger() method determines the behavior of the value triggerTODO: It implies that both timer trigger and value trigger can coexist at the same time. Make a test case to check if the coexistence of two triggers work properly.. The enable parameter determines whether the value trigger is active or not . Value 0 assigned to value trigger means that a notification should be sent on every change of the monitored value. This is very dangerous as it could flood the network. Therefore, there is a characteristic of the property, similar to min_timer_trigger, called min_delta_trigger, which specifies the minimum allowed threshold for value change. Invalid values (out-of-limits) are treated as valid extremes (a delta trigger below min_delta_trigger is treated as min_delta_trigger).
The interval at which the callback is invoked by the monitor is determined by the default setup for the specific property, which is typically in the order of one or several second. The ACS cannot guarantee, however, that the requested time intervals are met by the control system. The given values correspond just to approximate orders of magnitude. It can happen furthermore that not all control systems are able to respond in the order of milliseconds. The values should be therefore taken as a lower limit for the time between two consecutive monitor callbacks.QUESTION: This implies that, for example, if the timer trigger interval is set to 1 second and the first timer trigger is invoked at 0:0:0.000, the next triggers would be invoked at 0:0:1.001, 0:0:2.003, 0:0:3.00,5, 0:0:4.006, … (here I assumed there would be 1 ~ 2 ms delay for each trigger). In 5 minutes or so, the timer trigger would be invoked at 0:5:0.521. In the end, the time trigger would be invoked 3594 times during one hour.
Is this really what the client expects? If I were the developer of the client program, I would expect that the timer trigger is invoked 3600 times every hour, and the invocation time is aligned to 000 millisecond for each second (I guess create_postponed_monitor() exists for that purpose).

...

...

Properties

Wiki Markup
Having defined all concepts, we can now put them together into the most important interface of BACI, the property. The BACI specifications define only the core method of the root property interface, meaningfully called Property. For ACS, we have to define concrete properties that will be used to control and supervise all points of ALMA. In order to keep the interface definitions reasonably simple, we have kept the number of different property types small.
Properties are the basic entities that are manipulated by the control system. For a discussion on the meaning of properties and their relation to Components see the BACI white paper\[6\]. Two basic flavors of properties exist: RO = read-only (e.g. encoder position, device status) and RW = read-write (e.g. power supply voltage, pointing coordinate). In addition, properties have a certain type like double, long, string, etc.
!worddav254deeaa31b662cce7058d7e95ec63b1.png|height=305,width=389!
_Figure 1: Inheritance diagram for Acs::PdoubleSeq_
For the normal user of ACS, the object hierarchy of properties has little meaning (see figure 1). It may be confusing at best, because the only properties that a Component actually contains are of the type RO and RW. However, the hierarchy is very important for the code generator (not yet provided for ACS) and to account for all BACI concepts, which include groups of Components and others. In this document, we will simply state and explain all methods that all Properties have and then jump directly to the presentation of RO and RW properties.

...

Methods and Attributes Common to All Properties

Wiki Markup
The following methods and attributes are common to all properties, because they come from the interfaces higher up the inheritance hierarchy (CharacteristicModel, Property, TypelessProperty). They can be common, because they do not depend on the type of the property value. A normal client would use only those in italics. The others are mainly used by generic clients, like the Object Explorer, and the Abeans libraries that provide Java Beans components for fast client development.
readonly attribute string name; // The fully qualified name of the Property
\\
//generic access to characteristics, even those that are not declared in the IDL
any get_characteristic_by_name(in string name) raises (NoSuchCharacteristic);
\\
//returns a sequence of characteristic names that match the regular expressions
//reg_exp. It returns a sequence of length 0 if no match is found.  
stringSeq find_characteristic(in string reg_exp);
\\
// The name of the parent Component
readonly attribute string characteristic_component_name; 
\\
//Returns a PropertySet object containing all characteristics of the Property.
CosPropertyService::PropertySet get_all_characteristics();
\\
readonly attribute string description; // the description of the Property
readonly attribute string format;      // the format for printf in C-syntax 
readonly attribute string units;       // the units of the Property
readonly attribute pattern resolution; // a bitpattern of significant bits
\\
// Publish the value of the property.
// This method is meant to be called when the value of this property must be
// archived/monitored in relation to a change or error of another monitor point.
void publish_now();
\\
Some more explanations on the definitions: The main BACI components, such as Component and Property are named: they have a name, which the manager (see \[7\]) can convert to object reference if the client has the correct access level (only for Component). A Property cannot exist on its own - it is always a read-only attribute of a Component and thus knows the name of it. It does not keep an object reference to the Component for security reasons. The attribute pattern resolution is actually a bit pattern representing the significant bits of the word carrying the value. It is useful also for returning the resolution of analog-digital converters in case of numeric properties.

...

The Interface for Double PropertiesTODO: compare the contents of this section with baci.idl and update this section accordingly. Or, maybe we can copy the contents of this section to the inline documents in baci.idl, and put the link to baci.idl so that we don't have to worry about the consistency between two separate documents.

Here comes the part of properties which is type and access specific. They all follow the same patterns. For each type, there are the interfaces P<type>, the base class of a Property, which subclasses RO<type>, a read-only version and RW<type>, a read-write version of the Property class. Additional patterns are for Properties that return sequences of values, i.e. P<type>Seq, RO<type>Seq and RW<type>Seq, which are discussed in section 4.1 of this document.
The following types are missing from the IDL for ACS, because they were not requested: , PpatternSeq and PstringSeq with their subclasses. In the next version of ACS, there will probably be a generator that will create any IDL, code and config skeleton just from design pattern definitions in Rational RoseQUESTION: What is the current situation?. Therefore, it does not make sense to manually define and implement all those property types already now.
Note that all Property patterns are type safe, i.e. they return the explicit type of the property value and its characteristics - no casting or use of type any is required. Even the callbacks and in some cases the Monitors are of the correct type, according to the design patterns. Actually, to get the interface for Plong, one just has to replace all occurrences of double in the following IDL definition:
Therefore, only the double type occurrence of those patterns is documented in detail, others are equivalent, unless the difference is explicitly described in the following subsections. All the explanations are part of the comments of the interfaces, because it is rather difficult to write a concise description in a separate text. The IDL code is in boldface, the comments in plain text format.
interface Pdouble: TypelessProperty{
/*
Synchronous call that returns the value of the property in the correct type, no casting is required.
*/
double get_sync(
out Completion c // The Completion structure of the request is returned as out parameter
);
/*
Request one value through callback. The callback cb and its descriptor desc have to be created by the client.
The callback is of type CBdouble, because it explicitly carries a value of type double.
*/
void get_async(in CBdouble cb, in CBDescIn desc);
/*
Read n_last_lalues or all values (whichever is less) from the server's local archive. If n_last_values
is 0, then read complete local archive. Method returns number of actually transmitted values.
*/
long get_history(
in long n_last_values, // The number of last monitored values to return
out doubleSeq vs, // a sequence returning the requested values in ascending temporal order
out TimeSeq ts // a sequence returning the timestamps corresponding to the returned values
);
/*
Start continuous monitoring (with default time interval). As in all asynchronous requests, a callback
object cb and its descriptor desc have to be provided. See callbacks for more details.
*/
Monitordouble create_monitor(in CBdouble cb, in CBDescIn desc);
/*
Register a monitor whose beginning will be postponed until the specified start_time, which is given
in absolute time. See create_monitor for more details on monitors.
*/
Monitordouble create_postponed_monitor(in Time start_time, in CBdouble cb, in CBDescIn desc);
readonly attribute TimeInterval default_timer_trigger; // default time interval between two consecutive monitor callbacks
readonly attribute TimeInterval min_timer_trigger; // the minimum allowed time between two consecutive time triggers
readonly attribute double min_delta_trigger; // the minimum allowed threshold for value change in value triggers
readonly attribute double default_value; // default value, error-free value, etc.
readonly attribute double graph_min; // the recommended minimum for charts and gauges that display the value
readonly attribute double graph_max; // the recommended maximum for charts and gauges that display the value
readonly attribute double min_step; // smallest incremental step over whole range
};
A pedantic reader might notice that two attributes, default_timer_trigger and min_timer_trigger, are the only ones that are not dependent on the type double. A nitpicking might even comment, that as such they should belong to the TypelessProperty interface. However, there is no code to implement them in this type. They really belong to the interface, which has the monitor factory (i.e. create_monitor()), as they are related to the corresponding implementation code. The monitor factories can also not be moved, since create_monitor() methods are different per each property type.
The following interface is already known to us, all its pieces have been shown in section 3.2 on alarms: it request a subscription to the alarm event set for this property. Only properties of type RO have alarms, as RW properties should not even be able to set values in the alarm ranges.
interface ROdouble: Pdouble{
Subscription new_subscription_Alarm(in Alarmdouble cb, in CBDescIn desc);
readonly attribute double alarm_low_on; // belowQUESTION: Is the term "below" or "above" the right word to express inclusive boundary? At least, in C++ BACI implementation, these terms are considered as the inclusive boundary. For example, in baci::AlarmSystemMonitorCont<T, TPROP>::check() method, the alarm is raised when "value <= alarm_low_on".
It is a quite confusing term because, in "ACS Basic Control Interface Specification", the term "below" seems to be used to express exclusive boundary…
At least, for this alarm specification, we could rephrase like "alarm is raised when the value is less than this attribute" or something like that. this value alarm is set
readonly attribute double alarm_low_off; // above this value alarm is cleared
readonly attribute double alarm_high_on; //below this value alarm is cleared
readonly attribute double alarm_high_off; // above this value alarm is setQUESTION: I generally don't like the way this IDL is written because the same sets of methods and attributes are defined in ROdoubleSeq. To my understanding, IDL allows multiple inheritances, so I would define a separate interface like AlarmSourceDouble that contains these methods and attributes, and define ROdouble as simply the child of Pdouble and AlarmSourceDouble. Can I probably modify baci.idl in that way?
// The following methods are defined in the IDL, but they are not used.
void enable_alarm_system();
void disable_alarm_system();
boolean alarm_system_enabled();QUESTION: As Takashi discussed with Jorge A., it seems that these methods are not used anywhere. So, maybe we can remove them from the IDL, or, at least, it can be mentioned that they are not officially supported in the inline document of baci.idl. Which way is better?
};
The read-write interface is somewhat more complex, because of the added degree of freedom, namely setting the value of the property:
interface RWdouble: Pdouble{
/*
Synchronous setting of the property value - the returned Completion structure informs of the success/failure of the operation.
*/
Completion set_sync(in double value);
/*
Asynchronous setting of the property value - it is equivalent to the synchronous case, only that the Completion structure informing of the success/failure is returned via the callback object cb. As it does not carry a value, the callback is of type CBvoid. As usual, a callback descriptor is at the end of the signature.
*/
void set_async(in double value, in CBvoid cb, in CBDescIn desc);
/*
Method for fast consecutive sets that minimizes communication overhead. No assurance exists that the command has actually arrived to the server. Therefore also no completion code is returned.
*/
void set_nonblocking(in double value);
/*
Increment the raw value by one bit. This method can be used for fine-tuning actuators controlled by the property.
*/
void increment(in CBvoid cb, in CBDescIn desc);
/*
Decrement the raw value by one bit. This method can be used for fine-tuning actuators controlled by the property.
*/
void decrement(in CBvoid cb, in CBDescIn desc);
readonly attribute long min_value; // minimal allowed value for set
readonly attribute long max_value; // maximal allowed value for set
};

...

...

The Interface for PpatternTODO: compare the contents of this section with baci.idl and update this section accordingly. Or, maybe we can copy the contents of this section to the inline documents in baci.idl, and put the link to baci.idl so that we don't have to worry about the consistency between two separate documents.

The pattern Property has no monitor with value trigger, as a difference of values makes no sense.QUESTION: baci.idl in ALMA-RELEASE-B defines set_value_trigger(delta, enable), get_value_trigger(delta, enable), set_value_percent_trigger(delta, enable) and get_value_percent_trigger(delta, enable) for Monitorpattern. Which is true?
Semantically, I agree that a difference of values makes no sense. However, because pattern type is 64-bit variable, difference of value can be defined.
I believe that, in many cases, the client is only interested in whether the bit pattern is changed or not. So, I would define only set_value_trigger(enable) and get_value_trigger(enable) for Monitorpattern (note that these methods do not take "delta" argument). This value trigger invokes the callback whenever the bit pattern changes. I propose this modification, but is it acceptable in terms of compatibility? However, it has three other attributes that provide sequences that describe the meaning of each bit in the pattern: bitDescription, whenSet and whenCleared. The latter two keep one value of type condition per bit, which is an enum that describes the meaning of a bit in the status being set (to one) or cleared (to zero). The values correspond to usual colors of status LEDs:, which describe possible conditions of a physical device or its state. GREY corresponds to the LED being off.
enum Condition {
RED,
YELLOW,
GREEN,
GREY
};
The rest of the interface is equivalent to the Pdouble property:
interface Ppattern: TypelessProperty{
pattern get_sync(out Completion c);
void get_async(in CBpattern cb, in CBDescIn desc);
long get_history(in long n_last_values, out patternSeq vs, out TimeSeq ts);
Monitor create_monitor(in CBpattern cb, in CBDescIn desc);
Monitor create_postponed_monitor(in Time start_time, in CBpattern cb, in CBDescIn desc);
readonly attribute TimeInterval default_timer_trigger;
readonly attribute TimeInterval min_timer_trigger;
readonly attribute pattern default_value;
readonly attribute stringSeq bitDescription; // one description for each bit
readonly attribute ConditionSeq whenSet; // for each bit, defines the colour of LED when bit is set
readonly attribute ConditionSeq whenCleared; // for each bit, defines the colour of LED when bit is cleared
};

...

...

The interface for PstringTODO: compare the contents of this section with baci.idl and update this section accordingly. Or, maybe we can copy the contents of this section to the inline documents in baci.idl, and put the link to baci.idl so that we don't have to worry about the consistency between two separate documents.

The string Property has no monitor with value trigger, as a difference of values makes no sense. The rest of the interface is equivalent to the Pdouble property, as can be seen in the following IDL code:
interface Pstring : TypelessProperty{
string get_sync(out Completion c);
void get_async(in CBstring cb, in CBDescIn desc);
long get_history(in long n_last_values, out stringSeq vs, out TimeSeq ts);
Monitor create_monitor(in CBstring cb, in CBDescIn desc);
Monitor create_postponed_monitor(in Time start_time, in CBstring cb, in CBDescIn desc);
readonly attribute TimeInterval default_timer_trigger;
readonly attribute TimeInterval min_timer_trigger;
readonly attribute string default_value;
};

...

Solutions to Some Particular Requests for ACSTODO: Remove this chapter after it is confirmed that the contents in this chapter is addressed in another part of this document or in other documents. Some sections in this chapter are already removed because it was found that it was simply duplication of what has already mentioned in this document or another document. In general, the readers of this document are not interested in the historical discussion, but what is the latest interface. So, if new interfaces are already reflected in the IDL, the previous chapter should address them.

During the discussions, some particular requests emerged, which are addressed explicitly in the following sections. They have all been already taken care of in the IDL (see online documentation) and also indirectly mentioned in all previous chapters and sections.

...

Properties with Sequences

Sequences are very easy to add: keep the Property exactly the same as for scalar types, including all characteristics. Wherever a value is returned in a scalar type, return a sequence. It is simplest to explain with an example. This is all the IDL that is related to ROdoubleSeq and RWdoubleSeq (the syntax related to a sequence of doubles is highlighted with bold typeface):
typedef sequence<doubleSeq> doubleSeqSeq;
interface CBdoubleSeq: Callback{
oneway void working(in doubleSeq value, in Completion c, in CBDescOut desc);
oneway void done(in doubleSeq value, in Completion c, in CBDescOut desc);
};
interface PdoubleSeq: TypelessProperty{ doubleSeq get_sync(out Completion c);
void get_async(in CBdoubleSeq cb, in CBDescIn desc); long get_history(in long n_last_values, out doubleSeqSeq vs, out TimeSeq ts);
Monitordouble create_monitor(in CBdoubleSeq cb, in CBDescIn desc);QUESTION: This method returns an instance of Monitordouble, which means that value trigger is available for sequence types, but when the value trigger shall be invoked? Is it invoked when any element in the sequence fulfills the value trigger criteria? Or, is it invoked when all elements in the sequence fulfill the criteria?
Monitordouble create_postponed_monitor(in Time start_time, in CBdoubleSeq cb, in CBDescIn desc);
readonly attribute TimeInterval default_timer_trigger; readonly attribute TimeInterval min_timer_trigger; readonly attribute double min_delta_trigger; readonly attribute double default_value; readonly attribute double graph_min; readonly attribute double graph_max; readonly attribute double min_step;};
/* Yes, the ROdoubleSeq contains no items related to sequences. The Alarm is always triggered for a single value exceeding the limits, therefore the scalar Alarmdouble event is fired */
interface ROdoubleSeq: PdoubleSeq{ Subscription new_subscription_Alarmdouble(in Alarmdouble cb, in CBDescIn desc);TODO: As far as I investigated C++ BACI code, the alarm is raised or cleared per element in the sequence. Check if the behavior of the alarm with test code and document it here or somewhere else (maybe baci.idl is better).
readonly attribute double alarm_low_on;
readonly attribute double alarm_low_off;
readonly attribute double alarm_high_on;
readonly attribute double alarm_high_off;
};
interface RWdoubleSeq: PdoubleSeq{
Completion set_sync(in doubleSeq value); void set_async(in doubleSeq value, in CBvoid cb, in CBDescIn desc);
void set_nonblocking(in doubleSeq value);
void increment(in CBvoid cb, in CBDescIn desc);
void decrement(in CBvoid cb, in CBDescIn desc); readonly attribute double min_value;
readonly attribute double max_value;
};

...

Properties with Structs

WARNING: the following section has not been implemented yet. It is added merely for completeness, as we have just discussed the properties with sequences.QUESTION: What is the current situation?
A similar approach as above is taken for properties with structs. Here, the main dilemma is how to display the structure, i.e. the interpretation of formats and units, which is already defined in the interface TypelessProperty, which is a superclass of all properties. We propose to keep the TypelessProperty superclass as it is, and define the following interpretations of its attributes:

...

where the variables format and units have references to members of the struct in the same order as they appear in the IDL (which may not be the same for a given language binding).
Note that the monitor object used for struct properties is the base monitor interface. Then the IDL for struct properties looks rather straightforward, as we show in the example for ROmyStruct and RWmyStruct (the syntax related to the struct is highlighted with bold typeface), where the example struct is composed of an integer and a double:
typedef struct {int a; double b} myStruct;
typedef sequence<myStruct> myStructSeq;
interface CBmyStruct: Callback{
oneway void working(in myStruct value, in Completion c, in CBDescOut desc);
oneway void done(in myStruct value, in Completion c, in CBDescOut desc);
};
interface AlarmmyStruct : Callback {
oneway void alarm_raised(in myStruct value, in Completion c, in CBDescOut desc); oneway void alarm_cleared(in myStruct value, in Completion c, in CBDescOut desc);
};
interface PmyStruct: TypelessProperty{
myStruct get_sync(out Completion c);
void get_async(in CBmyStruct cb, in CBDescIn desc);
long get_history(in long n_last_values, out myStructSeq vs, out TimeSeq ts);
//use only the base Monitor object
Monitor create_monitor(in CBmyStruct cb, in CBDescIn desc);
Monitor create_postponed_monitor(in Time start_time, in CBmyStruct cb, in CBDescIn desc);
readonly attribute TimeInterval default_timer_trigger;
readonly attribute TimeInterval min_timer_trigger;
readonly attribute myStruct default_value; // yes, no characteristics for display limits
};
/* Yes, the ROmyStruct contains no alarm limits, but in case of alarm the structured AlarmmyStruct event is fired */
interface ROmyStruct: PmyStruct{
Subscription new_subscription_AlarmmyStruct(in AlarmmyStruct cb, in CBDescIn desc);
};
interface RWmyStruct: PmyStruct{
Completion set_sync(in myStruct value);
void set_async(in myStruct value, in CBvoid cb, in CBDescIn desc);
void set_nonblocking(in myStruct value);
// no inc/dec and no set limits; makes no sense for structs
};
Although those two cases for sequenced and structured properties look rather straightforward, is has to be noted that they each form a special case in the IDL generating templates used by "meta IDL", i.e. the templates for primitive typed properties can not be used for complex typed properties.

...

Generic Access to CharacteristicsTODO: This section is not necessary as ACS Basic Control Interface Specification already addresses the generic access to Characteristics. I already copies some sentences in this section to ACS Basic Control Interface Specification except the last statements about the regular expression because they are doubtful and I couldn't move it to another document without confirmation. After the regular expression matter is clarified, and after the regular expression description is addressed in ACS Basic Control Interface Specification, delete this section from this document.

At ALMA there will be some hardware and low level device characteristics in the configuration database that will never appear in the IDL, interesting only for the driver. However, some clients may want to access this information. For such cases, a generic access to characteristics is required. One way would be through the PropertySet interface, which is returned by the method get_all_characteristics() defined both for the Component and the base Property (see section 3.4.1), however, this returns all characteristics that are defined in the IDL, for fast initialization of client APIs like Abeans. So it does not make sense to use PropertySet just to get the value of one characteristic.
Therefore, two extra methods have been defined for the interface CharacteristicModel, which is the ancestor of Components and Properties, as both have their own set of characteristics:
exception NoSuchCharacteristic {
/** The name of the requested characteristic */
string characteristic_name;
/** The name of the NamedComponent which raised the exception */
string component_name;
};
any get_characteristic_by_name(in string name) raises (NoSuchCharacteristic);
stringSeq find_characteristic(in string reg_exp);
The first method returns the value of a characteristic named name as a type any object. It is up to the user of this value to convert it to whichever type is necessary. The second method allows generic tools to find some characteristics that are hidden from the IDL. The string reg_exp is a regular expression that is compared to all available characteristics in the configuration database. A sequence of matching characteristics names is returned as a sequence of strings. In order to simplify the implementation, it may be sufficient to provide wildcard search (with '' and '?') and not support a full regular expression parser. It is doubtful whether more than wildcard search is necessary, in particular as the names of the characteristics are relatively straight forward.QUESTION: According to baci.idl in ALMA-RELEASE-B, the parameter reg_exp is a 'Windows style regular expression (e.g., "")'. So, maybe this sentence is not necessary, but what is "Windows style regular expression"?
Interestingly, in C++ BACI implantation, CharacteristicModelImpl::find_characteristic() in baci/ws/src/baciCharacteristicModelImpl.cpp, Wildcard::wildcardfit() is internally called, but the inline document of wildcardfit() method in acsutil/ws/include/acsutilWildcard.h says that "this function implements the UN*X wildcards." Which is true? In either case, what is the exact definition of "*-style"?
In jBACI case, WildcharMatcher.simpleWildcardToRegex() is used to resolve wildcard string (see CharacteristicModelImpl.java). WildcharMatcher is more or less well documented as can be seen in jacsutil/src/com/cosylab/util/WildcharMatcher.java. It says it is "A Unix-like whildchar matcher" with more detailed description following. I also found in ICT wiki that there was an effort to consolidate the wildcard implementation between Java and python.
https://ictwiki.alma.cl/twiki/bin/view/Main/Acs1010ReleaseNotes
So, maybe, we can modify the description in baci.idl to address the same specification as WildcharMatcher, or make a link to the inline document of WildcharMatcher. If necessary, we may need to provide the equivalent wildcard matcher in C+, and use it for find_characteristic() method in C+ BACI to keep the compatibility between two languages, though it may break the backward-compatibility.
What solution is the best?