OBS-TALK-1

Dialogues with the User:
General Principles

Guy Rixon

Issue 1.2; 28th June 1995




Royal Greenwich Observatory,
Madingley Road,
Cambridge CB3 0HJ

Telephone (01223) 374000
Fax (01223) 374700
Internet G.Rixon@ast.cam.ac.uk

1 Introduction

1.1 Purpose of this document

The distributed nature of the DRAMA infrastructure used at ING requires special arrangements for programs that hold dialogues with the system users. This document describes the standard arrangements for those dialogues and suggests how programmers can use the dialogue facilities in applications.

1.2 Scope of the associated software

Three areas of software are discussed here:

1. Server programs of the class know as `talkers' that present dialogues to the user.

2. Client programs of the kind used throughout the ING DRAMA systems.

3. Function libraries available for connecting clients to talkers.

The arrangements described here are intended to be common to all combinations of telescopes, instruments and detectors in which DRAMA programs are involved. A general communications standard is involved, as discussed in section 2 and supported by libcia.

1.3 References

[1] Distributed Instrument Tasking System
AAO document DITS_SPEC/5 by T. J. Farrell.

[2] Remote Procedure Calls for DRAMA clients
RGO/ING document OBS-RPC-1.

2 Basic principles

2.1 Clients, servers and user interfaces

In all the following sections a fundemental distinction is made between client and server programs. A server is a program that is normally running on a particular processor and is continually ready to provide a set of services in response to messages received from other programs. A client is a program that is run intermittently to request services from a set of servers and which terminates after finishing a predefined sequence of actions.

The actions sequenced by a client may well require interaction with the system users. Usually, this takes the form of an English-language dialogue. Dialogues may be presented as routine progress-messages, as alarms to be acknowledged or as prompts for input.

In a system based on the DRAMA infrastructure, servers are DRAMA tasks that present a set of DITS [1] actions. Clients arrange for servers to execute their actions by an RPC mechanism that is built on DRAMA's Obey/Kick/Status message system; see OBS-RPC-1. A typical client is created by a fork()/exec() mechanism in some other program; the parent may be a standard Unix shell but might be a graphical interface. In this model, user-interface programs are servers rather than clients; they always spawn off clients to get work done in the servers.

Any given client can be run by a shell, by a non-DRAMA program or by a DRAMA task. The client cannot assume that its standard output, error and input streams are connected to anything useful. Equally, the client cannot rely on the presence of a DRAMA communications channel to its parent interface. Any client that wants to hold a dialogue must make an explicit choice of where and how to send its output.

Servers have a different problem. A server will not often want to hold dialogues, but may at times need to raise alarms about critical conditions. These alarms should go to all points of control. That is, if a system is being used simultaneously by an observer, a telescope operator and an engineer, the alarm should be visible to all these people.

2.2 Talkers

Talkers are specialized user-interface servers that conduct dialogues on behalf of clients and servers. A client programs contacts a talker though a specific form of RPC (that is, the client invokes a DITS action on the talker). A server contacts talkers by loading its messages into DRAMA parameters which the talker is monitoring. Hence, a server can address all interested talkers in one operation. Typically, there is one talker for each person using the system. This means that a client started by a given user reports only to that user though his/her local talker.

2.3 RPCs that carry dialogues

The generic RPC-mechanism is described in OBS-RPC-1. Dialogue RPCs are a specialization of this mechanism; the RPCs invoke a particular set of actions supported by talkers.

The actions that a client can invoke on a talker are:

COMMENT record a comment on events with no special attempt to bring it to the user's attention.

ALARM record an exceptional condition. Make every attempt to get the user's attention, including ringing bells, raising dialogue boxes, grabbing the keyboard focus etc. Require the user to acknowledge the alarm.

PROMPTGONOGO output a prompt string, get a proceed/abort decision and return a boolean result to the calling client.

PROMPTSTRING output a prompt string and get a string in response. Return the string to the calling client. The returned string may contain a number or list of numbers; the client must decide how to parse and validate the response.

The attributes of the messages are

Task: the name of the talker. The client picks this up from its environment.

Action: COMMENT, ALARM, PROMPTGONOGO or PROMPTSTRING as listed above.

Text: the input-argument named Text is the text to be displayed. It may include explicit line-breaks.

Sender: the input-argument named Sender identifies the sender of the message. This allow the talker to mark up dialogues by their origin. The talker will probably use this string a prefix when the message is displayed.

Time: the input-argument named Time is optional; if present, it is an ASCII representation of the time of origin of the message. The talker will probably use this string as a prefix when the message is displayed.

Reply: the output-argument named Reply carries the talker's response in the dialogue. If there is no response, there is no return argument-list.

2.4 Interaction with ERS

DRAMA provides the ERS facility to support dialogues. Unfortunately, ERS does not satisfy the needs of the ING infrastructure on a number of points.

z The standard use of ERS in DITS assumes that all clients either have access to standard input/output/error or equivalent facilities in a windowing system. The concept of a transient client run in a sub-process of a UI is not supported.

z Messages produced by servers in standard DITS/ERS are sent only to the client that invoked the action in which the message was generated. Alarms cannot be be copied to several UIs, and a dialogue cannot be held when no actions are active.

z DITS/ERS `dialogues' are actually monologues. There is no provision for a task to prompt the user for input.

ERS cannot be entirely ignored, since most DRAMA libraries use it. In the dialogue-RPC system, ERS is used inside tasks as a way of grouping messages in the `ERS stack'. When the messages are sent, the stack is dumped into the argument list of an RPC and the normal RPC mechanism takes over.

3 Using dialogues in clients

A number of library-functions from libcia manage dialogues for client programs. These functions inter-operate with the facilities discussed in OBS-RPC-1.

3.1 Preconditions

The RPC system uses normal DITS messages and tasking: it cannot function in a client that has not logged in to the DRAMA message net. A client must have completed DitsInit() successfully before starting dialogues.

The general RPC system is enabled

by calling ciaRpcInit(). Clients should call this function after DitsInit().

The dialogue facilities themselves are enabled by ciaTalkInit(). If this call fails or is omitted, the result of dialogue requests is undefined. This call reads the name of the designated talker from the environment variable TALKER.

3.2 Explicit dialogues

Generating a dialogue RPC is similar to the Obey/Kick/Get/Set RPC discussed in OBS-RPC-1; only the function to set up the RPC-control block differs. For example:

ciaRpc_t rpc;

ciaTalkRpc( &status, &rpc, "COMMENT", "This is run %d.", run );
ciaResizeRpc( -1, 0, 1, &rpc, &status );
ciaExecuteRpc( &status, 1, &rpc );
The call to ciaResizeRpc() sets the message-buffer of the outgoing message to the correct size for the dialogue and allows one return message; since this is a comment dialogue, no bytes are allocated for returned arguments. Dialogue RPCs only ever return one message.

Note how the text of the dialogue is formatted in the style of printf(). When using this approach, the text of the the message is set up in the structure for input arguments (rpc.argsIn in the example above) and any reply from the talker can be read back from the output arguments (rpc.argsOut) after ciaExecuteRpc() returns.

Early versions of ciaTalkRpc() do not support printf()-style formatting.

ciaTalkRpc() sets all the attributes of the dialogue listed in section 2.3 except Reply, which is set on return from ciaExecuteRpc(). The Sender argument is set to a value determined by ciaTalkInit(). The Time argument is set to the time at which ciaTalkRpc() was called.

3.3 Dialogues via ERS

Use of DRAMA's error-reporting system (ERS) is unavoidable: most of DRAMA's library functions use it. The default use of ERS by DITS dumps the accumulated text of an error stack on standard error whenever ErsFlush()

is called. This is undesirable: we need the contents of the ERS stack to go to the Talker as a dialogue.

ciaTalkInit() supplies a new output handler to ERS such that ErsFlush() does not write to standard error. After ciaTalkInit(), ErsFlush() writes its text to a global dialogue owned by the CIA library (the variables maintaining this dialogue are not visible to applications). In this mode, ErsFlush() does not start the dialogue with the Talker and successive calls to ErsRep(), ErsFlush() add extra text to the dialogue. Flushing an empty ERS stack is harmless. ciaErsFlush() is a wrap-up for ErsFlush() that not only builds the ERS dialogue but sends it to the Talker.

The following code fragment shows a use of ERS in an RPC client. This is error-recovery code to report and deal with some condition xxx, allowing for the possibility that the recovery may also fail.

    if( status = CLIENT__XXXHAPPENED )
    {
       ErsRep( ERS_M_NOFMT, &status, 
               "Recovering from condition xxx..." );
       ciaErsFlush( NULL );
       status = STATUS__OK;
       RecoverFromXxx( args, &status );
       if( !StatusOk(status) )
       {
          ErsRep( ERS_M_NOFMT, status, 
                  "Critical failure: can't recover from xxx!" );
          ciaErsFlush( "ALARM" );
       }
    }
At the start of the fragment, there may or may not be error messages in the ERS stack. A contextual line is added to these with ErsFlush() and the ERS stack is flushed out to the Talker. Status is reset and the recovery function is called. If the recovery function fails, the ERS stack is flushed again (to send the error messages generated during recovery), but this time the dialogue is made into an ALARM. Note how ciaErsFlush() takes a string argument which, if not NULL, states what type of dialogue to output. The default style of dislogue is COMMENT, unless a message in the ERS stack has the alarm attribute set in which case the default is ALARM.

ciaErsFlush() returns the SDS ID of any arguments returned by the dialogue. This means that text from ERS can be used as a prompt string.

    SomeLibraryFunction( &status );
    if( !StatusOk(status) )
    {
       ErsRep( ERS_M_NOFMT, &status,
               "Ignore this error and proceed?" );
       argsOut = ciaErsFlush( "PROMPTGONOGO" );
       ArgGeti( argsOut, "Reply", &okContinue, &status );
       if( !okContinue ) exit( status );
    }
If there is no talker, the calls discussed in this section execute by writing to standard output and reading from standard input. This is an option of last resort and is not recommended in operational use.

3.4 Trapping messages from servers

When a client invokes an action on a server and the action fails, the server may return error messages. The default behaviour for a client (as defined by DITS) is to write these messages out on standard error. ciaErsTrap() alters this arrangement.

ciaErsTrap() is intended to be installed as an error-message output-handler for RPCs. For example, consider the RPC invocation of CLEAR on CCD1.

#include "ciaRpc.h"
#include "ciaTalk.h"

ciaRpc_t rpc;   

ciaObeyRpc( "CCD1", "CLEAR", &rpc, &status );
rpc.dui.ErrorHandler = ciaErsTrap;
ciaExecuteRpc( &status, 1, &rpc );
Here, the address of ciaErsTrap() (which has an external definition in ciaTalk.h) is copied into the .dui sub-structure of the RPC control-block. With this assignment made, any error messages passed up by the server CCD1 during the RPC are added to the client's ERS stack. They can then be flushed to the talker by ciaErsFlush(). Alternatively, the client can clear the stack with ErsAnnul() and handle the error silently.

3.5 Final report from a client

Typically, a client will make some final report before it exits: a summary of success

or failure. Any messages remaining in the ERS stack should also be flushed out at this point.

The function ciaLastWords() provides this service. It puts a success/failure message onto the ERS stack and then flushes the stack. Thus, the exit-point of a client normally looks like

finalStatus = ciaLastWords( &status );
exit( DitsStop(taskName,&finalStatus) ); 
The final message is normally delivered as a COMMENT dialogue unless one of the messages in the ERS stack has the alarm attribute set in which case the dialogue is an ALARM.

If a client program exits with a non-zero status, DITS reports the final status to standard error. This report is made after in addition to the report from ciaLastWords().

3.6 Compiling and linking

To use dialogue RPCs, a client must be linked with libcia. The linking procedure is described in OBS-RPC-1.

4 Dialogues for servers

Servers can offer dialogues to any talkers that are interested by setting them up in parameters. Any number of talkers can monitor the parameters. This arrangement reflects the fact that the talkers are likely to be started after the other servers are running.

Each server should offer a parameter named for each of the dialogue types that it wants to use: COMMENT and ALARM are supported at present but PROMPTGONOGO and PROMPTSTRING are not.

Each parameter should be an SDS structure with the components Sender, Text, and Time discussed in section 2. The Time component is optional.

A server initiates a dialogue by updating the relevant parameter and calling SdpUpdate() to propagate the new value to all monitoring tasks. The parameter should not be cleared after use as this will look like a new dialogue to monitoring tasks.

Setting the COMMENT parameter is equivalent to invoking a COMMENT action to the talker; setting ALARM is equivalent to invoking an ALARM action. The talker does not try to set any of the components of the parameters.

5 Design principles for talkers

There are many ways to set up a talker. A talker program may be reusable in many systems, or may be tailored to a specific instrument. A talker may be a discreet program, or the talker facilities may be built into a a general user-interface. The talker may use X-windows, curses or may work line by line on a dumb terminal. However it is written, a talker must conform to certain standards as described here.

1. The talker must provide the actions for the basic types of dialogue: COMMENT, ALARM, PROMPTGONOGO and PROMPTSTRING. The actions should have the features mentioned in this document. If these actions are not correctly provided, many client programs may fail and the system is likely to be unusable.

2. The talker should provide facilities to monitor the COMMENT and ALARM parameters of servers. If the facility is provided, the exact form of the interface must be as described in this document. If this facility is missing, the system will still run but the users may be kept ignorant of vital information.

3. Comment dialogues should be presented to the user unobtrusively. In most cases, comments are ignorable output.

4. Alarms should be presented forcibly to the user until acknowledged. If the talker is a GUI and can be iconified, the alarms must not be hidden by iconfication. It is reasonable to lock up the user controls until the alarm is acknowledged

5. Prompts should be brought gently to the user's attention.

6. A talker must be able to handle many (at least 10) alarms active at once.

7. The talker should not block the processing of dialogues while waiting for inputs. This is most critical for alarms.

8. A log of all dialogues should be kept visible to the user. The best form for this is a scrollable window showing the last 10 (say) dialogues. The entries in the log should be marked with the sender's name and a time-stamp. Ideally, the log shoulog be kept on disk for a post-mortem in the case of a system failure. For comment dialogues it may be sufficient to write the comment into the bottom of the log.

Appendix A. Document History

Issue 1.1 04/05/95 Original document.

Issue 1.2 28/06/95 Revised to reflect the interfaces implemented in libcia v4. The `packaged dialogues' suggested in issue 1.1 have been abandoned and the section on trapping error messages from servers is new. Many interfaces have changed in detail.