Client Application¶
The client application (fcfClient) is a simple utility allowing to send commands to the Device Manager from
the command line. In this context we use the words commands and events as synonyms.
The fcfClient uses the standard interface module stdif
and the application interface module fcfif
to
compose the payload of the messages. The fcfClient sends the messages using CII MAL request/reply.
$ fcfClient <serviceURI> <command> ["<parameters>"]
Where
<serviceURI> destination of the command (e.g. zpb.rr://127.0.0.1:12081)
<command> command to be sent to the server (e.g. Init)
<parameters> optional parameters of the command.
Warning
The URI shall not contain the ‘/’ at the end otherwise the client will hang trying to connect to a non existing server.
List of Commands¶
The commands (events) currently supported by the fcfClient utility are:
Command |
Parameters |
---|---|
Init |
“” |
Enable |
“” |
Disable |
“” |
GetState |
“” |
GetStatus |
“” |
Setup |
“” |
Recover |
“” |
Reset |
“” |
GetConfig |
“” |
DevNames |
“” |
DevInfo |
“” |
DevConfig |
“<device id>” |
DevStatus |
“[<device id1>, … ,<device idn>]” |
SetLogLevel |
“<ERROR|INFO|DEBUG|TRACE>” |
Simulate |
“<device id1>, … ,[<device idn>]” |
StopSim |
“<device id1>, … ,[<device idn>]” |
Ignore |
“<device id1>, … ,[<device idn>]” |
StopIgn |
“<device id1>, … ,[<device idn>]” |
HwInit |
“<device id1>, … ,[<device idn>]” |
HwEnable |
“<device id1>, … ,[<device idn>]” |
HwDisable |
“<device id1>, … ,[<device idn>]” |
HwReset |
“<device id1>, … ,[<device idn>]” |
StartDaq |
“<daq id>” |
StopDaq |
“<daq id>” |
Exit |
“” |
Warning
Due to the upgrade to CII, the payload of the SETUP command cannot be defined through a JSON file. For sending SETUP and other commands is better to use the Python interface.
Note
The HW commands like HwInit or HwEnable control the state of the controller associated to the device.
Examples¶
Note
The following examples assume the server is listening for incoming events under the URI zpb.rr://127.0.0.1:12081 in the local host.
Enabling debug level in the server¶
$ fcfClient zpb.rr://127.0.0.1:12081 SetLogLevel "DEBUG"
Initialising the server¶
$ fcfClient zpb.rr://127.0.0.1:12081 Init ""
Moving the server to Operational state¶
$ fcfClient zpb.rr://127.0.0.1:12081 Enable ""
Executing a Setup command from the command line¶
This is not possible in this version using fcfClient utility. Please use the FCF Shell instead.
FCF Shell (CLI)¶
The FCF provides an experimental command shell with commands aiming to simplify the interaction with the
Device Manager. The FCF shell can be invoked issuing the command fcfcli
. The FCF Shell is based on a
generic asynchronous shell that it is included in the IFW core libraries.
Command Line Parameters¶
The fcfcli offers few command line parameters. If no parameters are specified, the fcfcli will use the default name services and use nomad/consul to obtain the correct IP and port numbers of the Device Manager. The fcfcli shell commands are not necessary using the same names as the MAL interfaces with the purpose to shorten the commands names. This is also because the name of the commands are the name of the class methods in Python. Commands are asynchronous so the shell can continue being used while the answer from the previous command is not yet received.
Parameter |
optional |
Description |
---|---|---|
–uri |
no |
if the URI is specified, the supcli will use it to connect to the server |
–name |
no |
When using nomad, one could specify the name of the service instead of the URI |
–module |
yes |
Custom interface library |
–class_name |
yes |
Custom command class name |
–timeout |
yes |
Timeout for CII MAL requests in ms |
–log_level |
yes |
log level (ERROR, INFO, DEBUG) |
–help |
yes |
Show the usage message |
Warning
The fcfcli shell assumes NOMAD/CONSUL services are up and running. If this is not the case then –uri parameter shall be used instead of –name.
Note
The fcfcli shell was created for the Device Manager but since it uses the standard interface, it can be used for any server implementing this interface, although only for the standard events like init, enable, disable, etc.
fcfcli --uri zpb.rr://134.171.3.48:30269
fcfSh>?
reply> = Available command list:
- abortdaq
- close
- daqstatus
- devconfig
- devinfo
- devnames
- devstatus
- devstatus_regex
- devtype
...
...
- stopdaq
- switch_off
- switch_on
Shell History¶
The FCF shells keeps its own history file under $HOME/.fcfSh.txt. The history can be accessed using the arrows keys.
Shell Completion¶
The FCF shell provides a completion capability for the supported commands using the Tab key.
The shell completion also gives information about the parameters of each command.
Supported Shell Commands¶
Command |
Parameters |
Description |
---|---|---|
init |
sends the init (stdif) event to the connected server. |
|
enable |
sends the enable (stdif) event to the connected server. |
|
disable |
sends the disable (stdif) event to the connected server. |
|
reset |
sends the reset (stdif) event to the connected server. |
|
stop |
sends the stop (stdif) event to the connected server. |
|
recover |
sends the recover (fcfif) event to the connected server. |
|
hw_init |
<argv> |
sends the init directly to the device controllers. The parameter is a variable list of devices. |
hw_enable |
<argv> |
sends the enable directly to the device controllers. The parameter is a variable list of devices. |
hw_disable |
<argv> |
sends the disable directly to the device controllers. The parameter is a variable list of devices. |
hw_reset |
<argv> |
sends the reset directly to the device controllers. The parameter is a variable list of devices. |
help |
print the list of supported commands |
|
startdaq |
<daqid> |
Start DAQ acquisition |
abortdaq |
<daqid> |
Abort DAQ acquisition |
daqstatus |
<daqid> |
Get DAQ acquisition status |
stopdaq |
<daqid> |
Stop DAQ acquisition |
devnames |
Get the list of devices managed by the server |
|
devinfo |
Get the list of devices managed by the server with their respective types. |
|
devstatus |
<argv> |
Get the status of all devices managed by the server. |
devstatus_regex |
<pattern> |
Get the status of all devices managed by the server and it applies a filter using regular expressions. The output to be included in the reply is the one matching the pattern. |
devconfig |
<device> |
Get the actual configuration of a device (yaml formatting) |
devtype |
<device> |
Get the associated type of the device |
simulate |
<device> |
sends the simulate event to the connected server |
stop_simulate |
<device> |
sends the stopsim event to the connected server |
ignore |
<device> |
sends the ignore event to the connected server |
stop_ignore |
<device> |
sends the stopign event to the connected server |
setup_json_file |
<file> |
The setup commands uses a JSON file to set run-time parameters. The contents of the JSON file shall match the defined schema. |
setup_json_string |
<JSON string> |
The setup commands uses a JSON format to set run-time parameters. The JSON string shall match the defined schema. |
state |
sends the GetState (stdif) event to the connected server |
|
status |
sends the GetStatus (stdif) event to the connected server |
|
get_config |
Get the server configuration (yaml formatting) |
|
close |
<shutter device> |
It closes a shutter |
open |
<shutter device> |
It opens a shutter |
switch_on |
<lamp device> |
It switch on a lamp or an actuator device |
switch_of |
<lamp device> |
It switch off a lamp or an actuator device |
move |
[,<type>] [,<unit>] [,<aux_motor>] |
It moves a motor to a target position |
move_by_name |
<motor>,<name> |
It moves a motor using a named position |
move_by_speed |
<motor>,<speed> |
It moves a motor in speed |
move_by_angle |
<motor>,<angle> |
It moves a drot by position angle |
start_track |
<device>,<mode> |
It start tracking for using a given mode |
stop _track |
<device> |
It stops tracking |
ctrl-d |
Stop the shell |
using devnames command¶
fcsSh> devnames
reply> = shutter1, lamp1, motor1, drot1, adc1, piezo1
OK
using devstatus command¶
fcsSh> devstatus lamp1
reply> = ['lamp1.lcs.state = Operational', 'lamp1.lcs.substate = On', 'lamp1.lcs.intensity = 0.000000', '', 'OK']
fcsSh>
using devstatus_regex command¶
fcsSh> devstatus_regex lamp1\.
reply> = lamp1.lcs.state = Operational
lamp1.lcs.substate = Off
lamp1.lcs.intensity = 0.000000
fcsSh>
Note
The dot character shall be escaped for the python regular expression matching.
using switch_off command¶
fcsSh> switch_off lamp1
fcsSh> reply> = OK setup completed.
fcsSh>
using move command¶
fcsSh> move motor1,50
fcsSh> reply> = OK setup completed.
fcsSh>
using setup command¶
This example uses a test JSON file (test.json).
[{
"id": "shutter1", "param": {
"shutter": {
"action": "OPEN"
}
}
},
{
"id": "lamp1", "param": {
"lamp": {
"action": "OFF"
}
}
},
{
"id": "motor1", "param": {
"motor": {
"action": "MOVE_ABS",
"pos": 50,
"unit": "UU"
}
}
}]
fcsSh> setup_json_file test.json
fcsSh> reply> = OK setup completed.
fcsSh>
fcsSh> setup_json_string '[{"id": "shutter1", "param": { "shutter": {"action": "OPEN"}}}]'
fcsSh> reply> = OK setup completed.
fcsSh>
using DAQ commands¶
These commands are the implementation of the metadaq interface. For more information, please refer to the ECS Metadaq interface module. These commands shall be executed in sequence. First the start and then the stop.
Note
The FCF requires to be in operational to handle the DAQ commands.
Warning
The FCF requires that the DATAROOT variable is defined to properly create the metadaq files.
fcsSh> startdaq science
fcsSh> reply> = science
fcsSh>
fcfSh> daqstatus science
reply> = id: science
state: DaqState.Acquiring
files: ['/scratch/DATAROOT/fcs1_science_start.fits']
keywords:
fcsSh>
fcfSh> stopdaq science
reply> = id: science
files: ['/scratch/DATAROOT/fcs1_science_start.fits', '/scratch/DATAROOT/fcs1_science_stop.fits']
keywords:
fcsSh>
These FIT files shall be created on disk and they shall contain the FCF metadata information
fcfSh> daqstatus science
reply> = id: science
state: DaqState.Succeeded
files: ['/scratch/DATAROOT/fcs1_science_start.fits', '/scratch/DATAROOT/fcs1_science_stop.fits']
keywords:
fcsSh>
Note
The FCF python library converts the output from the metadaq commands to strings such that the users can easily understand it from a shell.
FCF Python Client Library¶
It is possible to communicate with the Device Manager through clients developed in
Python. The FCF provides a library that simplifies the interaction with the Device Manager (clib
).
This is probably the more flexible way to interact with the Device Manager. The clib
encapsulates the creation of the payload for the Setup command by providing predefined methods.
Users might want to interact directly with the server through the FCF ICD binding methods. This is, of course possible, but it is outside the scope of this library.
Note
This Python client library was added in version 2.
Error Handling¶
The clib
reports as a RuntimeError exceptions that may be delivered by the Device Manager.
Classes¶
The clib
library provides internal classes to build the buffer for each device. In addition, this
library provides one class that encapsulates the user interface with the DeviceManager. This class is
the DevmgrCommand class. The clib
also provides an asynchronous version of the same class
(DevmgrAsyncCommands) which does exactly the same but it implements coroutines.
DevmgrCommand¶
The constructor of the DevmgrCommand class support four parameters: uri, timeout, and setup_obj.
Parameter |
Description |
---|---|
uri |
This is URI of the device manger. |
timeout |
The timeout is optional and has a default of one minute, expressed in milliseconds. default: 60000[ms] |
setup_obj |
Dedicated setup object used when sending setup of multiple devices. By using a custom setup buffer object, users can implement more complex setups. default: None |
Unless the setup_obj is provided, the class handles an internal buffer object that is used to build the payload of the Setup command. Each time the command is executed, the buffer is reset. The user can add multiple device settings into the internal buffer before executing the setup command.
The methods names of the class are shown in the tables below. They try to be self explanatory.
Public Methods for building Setup Payload¶
Method |
parameters |
---|---|
close |
device (string) |
open |
device (string) |
switch_on |
device (string), intensity (float) and timer (integer). |
switch_off |
None |
move |
device (string), position (float), type (string), unit (string) and aux_motor (string) |
move_by_name |
device (string), namepos (string) |
move_by_speed |
device (string), speed (float) |
move_by_posangle |
device (string), angle (float) ONLY for derotators. |
start_track |
device (string), mode (string) |
stop_track |
device (string) |
move_piezo_in_user_units |
device (string) |
move_piezo_in_bits |
device (string) |
setup_json_file |
json_file (string), keep (bool) |
setup_json_string |
json_str (string), keep (bool) |
Methods for Command Interface¶
Method |
parameters |
---|---|
devstatus |
device list (argv) |
devstatus_regex |
pattern (string) |
devconfig |
device (string) |
devnames |
None |
devinfo |
None |
devtype |
device (string) |
ignore |
device list (argv) |
simulate |
device list (argv) |
stop_ignore |
device list (argv) |
stop_simulate |
device list (argv) |
hw_init |
device list (argv) |
hw_enable |
device list (argv) |
hw_disable |
device list (argv) |
hw_reset |
device list (argv) |
state |
None |
status |
None |
get_config |
None |
init |
None |
enable |
None |
recover |
None |
disable |
None |
reset |
None |
stop |
None |
startdaq |
id (string) |
stopdaq |
id (string) |
abortdaq |
id (string) |
daqstatus |
id (string) |
setloglevel |
level (string), logger (string) |
Examples¶
Retrieving the Status¶
import ifw.fcf.clib.devmgr_commands as fcs
uri = "zpb.rr://127.0.0.1:12081"
fcsif = fcs.DevMgrCommands(uri)
print(fcsif.devstatus())
['shutter1.simulated = true', 'shutter1.lcs.state = Undefined', 'shutter1.lcs.substate = Undefined',
'lamp1.simulated = true', 'lamp1.lcs.state = Undefined', 'lamp1.lcs.substate = Undefined',
'lamp1.lcs.intensity = 0.000000', 'motor1.simulated = true', 'motor1.lcs.state = Undefined',
'motor1.lcs.substate = Undefined', 'motor1.lcs.pos_target = 0.000000',
'motor1.lcs.pos_actual = 0.000000', 'motor1.lcs.vel_actual = 0.000000',
'motor1.lcs.axis_enable = false', "motor1.pos_actual_name = ''",
'motor1.pos_enc = -2147483648', '', 'OK']
Executing a single Setup¶
import ifw.fcf.clib.devmgr_commands as fcs
uri = "zpb.rr://127.0.0.1:12081"
fcsif = fcs.DevMgrCommands(uri)
# Move single motor1 to absolute position 100 in user units
# Fill the internal setup buffer
fcsif.move("motor1", 100)
Using a custom buffer object¶
import ifw.fcf.clib.devmgr_commands as fcs
import ifw.fcf.clib.setup_buffer as sbuf
uri = "zpb.rr://127.0.0.1:12081"
fcsif = fcs.DevMgrCommands(uri)
buffer = sbuf.SetupBuffer(fcsif._cii)
buffer.add_shutter_open("shutter1")
buffer.add_lamp_switch_on_with_intensity("lamp1", 50)
# Performs the setup with the custom buffer object
fcsif._setup(buffer)
Using a custom buffer object with JSON files and SPF strings¶
In this case, it is loaded first a JSON file with the initial settings. Then, one setting is overwritten. At last, one additional setting is added to the buffer before it is sent to the server.
import ifw.fcf.clib.devmgr_commands as fcs
import ifw.fcf.clib.setup_buffer as sbuf
uri = "zpb.rr://127.0.0.1:12081"
fcsif = fcs.DevMgrCommands(uri)
# Get list of devices and their types from the server. This is needed when using SPF format
# and custom setup buffers.
fcsif._init_devtype()
# initialise setup buffer object
buffer = sbuf.SetupBuffer(fcsif._cii)
# Load json file
buffer.add_json_file(myfile.json)
# Overwrite some contents using SPF
buffer.add_spf_string('motor1:action="MOVE_ABS",motor1:pos=30', fcsif._devtypes)
# extending the buffer with a new setting using SPF
buffer.add_spf_string('actuator1:action="ON"', fcsif._devtypes)
# Convert from JSON to CII
buffer.json2object()
# Performs the setup with the custom buffer object
fcsif._setup(buffer)
JSON Schema¶
JSON is used to compose the payload of the setup command. To minimize possible errors, the client python library validates the payload against a defined schema before sending the command to the server. The FCF provides a schema that covers all standard devices. Instrument implementing custom devices shall extend this schema definition.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "FCF schema",
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "device identifier."
},
"param": {
"$ref": "#/definitions/param"
}
}
},
"definitions": {
"param": {
"type": "object",
"properties": {
"shutter": {
"$ref": "#/definitions/shutter"
},
"actuator": {
"$ref": "#/definitions/actuator"
},
"lamp": {
"$ref": "#/definitions/lamp"
},
"motor": {
"$ref": "#/definitions/motor"
},
"drot": {
"$ref": "#/definitions/drot"
},
"adc": {
"$ref": "#/definitions/adc"
},
"piezo": {
"$ref": "#/definitions/piezo"
},
"iodev": {
"$ref": "#/definitions/iodev"
}
},
"oneOf": [
{ "required":
[ "shutter" ] },
{ "required":
[ "actuator" ] },
{ "required":
[ "lamp" ] },
{ "required":
[ "motor" ] },
{ "required":
[ "drot" ] },
{ "required":
[ "adc" ] },
{ "required":
[ "piezo" ] },
{ "required":
[ "piezo" ] }
]
},
"shutter": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["OPEN", "CLOSE"],
"description": "Shutter action."
}
},
"required": ["action"]
},
"actuator": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["ON", "OFF"],
"description": "Actuator action."
}
},
"required": ["action"]
},
"lamp": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["ON", "OFF"],
"description": "Lamp action."
},
"intensity": {
"type": "number",
"minimum": 1,
"maximum": 100,
"description": "Lamp intensity."
},
"time": {
"type": "integer",
"minimum": 1,
"description": "Lamp timer."
}
},
"required": ["action"],
"additionalProperties": false
},
"motor": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["MOVE_ABS", "MOVE_REL", "MOVE_BY_NAME", "MOVE_BY_SPEED"],
"description": "Motor action."
},
"pos": {
"type": "number",
"description": "Motor position in user units."
},
"enc": {
"type": "integer",
"description": "Motor position in encoders."
},
"unit": {
"type": "string",
"enum": ["UU", "ENC"],
"description": "Motor position unit."
},
"name": {
"type": "string",
"description": "Motor named position."
},
"speed": {
"type": "number",
"description": "Motor speed."
}
},
"required": ["action"]
},
"drot": {
"allOf": [{ "$ref": "#/definitions/motor" }],
"properties": {
"action": {
"type": "string",
"enum": ["MOVE_ABS", "MOVE_REL", "MOVE_BY_NAME", "MOVE_BY_SPEED", "MOVE_BY_POSANG", "START_TRACK", "STOP_TRACK"],
"description": "Drot action."
},
"posang": {
"type": "number",
"description": "Motor position angle."
},
"mode": {
"type": "string",
"enum": ["ENG", "STAT", "SKY", "ELEV", "USER"],
"description": "Drot mode."
}
},
"required": ["action","mode"]
},
"adc": {
"allOf": [{ "$ref": "#/definitions/motor" }],
"properties": {
"action": {
"type": "string",
"enum": ["MOVE_ABS", "MOVE_REL", "MOVE_BY_NAME", "MOVE_BY_SPEED", "MOVE_BY_POSANG", "START_TRACK", "STOP_TRACK"],
"description": "Adc action."
},
"posang": {
"type": "number",
"description": "Motor position angle."
},
"axis": {
"type": "string",
"enum": ["ADC1", "ADC2"],
"description": "Adc axis."
},
"mode": {
"type": "string",
"enum": ["ENG", "OFF", "AUTO"],
"description": "Adc mode."
}
},
"required": ["action","mode"]
},
"piezo": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["SET_AUTO", "SET_POS", "SET_HOME", "MOVE_ALL_BITS", "MOVE_ALL_POS"],
"description": "Piezo action."
},
"pos1": {
"type": "number",
"description": "Piezo position 1 in volts."
},
"pos2": {
"type": "number",
"description": "Piezo position 2 in volts."
},
"pos3": {
"type": "number",
"description": "Piezo position 3 in volts."
},
"bit1": {
"type": "integer",
"description": "Piezo position 1 in bits."
},
"bit2": {
"type": "integer",
"description": "Piezo position 2 in bits."
},
"bit3": {
"type": "integer",
"description": "Piezo position 3 in bits."
}
},
"required": ["action"]
},
"iodev": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["SETOUT", "WRITE"],
"description": "IODev action."
},
"channels": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"name": "string"
},
"signal": {
"type": "string",
"enum": ["DIGITAL","ANALOG", "INTEGER"],
"description": "Signal type."
},
"value": {
"type": ["boolean","integer","number"]
}
},
"required": ["name","value"],
"additionalProperties": false
}
}
},
"required": ["action"],
"additionalProperties": false
}
}
}