Mid.CBF FPGA Host Server (FHS) Device Simulation Design
How to simulate an FHS device
FHS Tango devices can be simulated using the ska_mid_cbf_fhs_common.testing.simulation module.
This module provides several key classes, including;
FhsSimMode: simulation mix-in for FHS device classes - supplies the simOverrides attribute to the device interface
SimModeCMBase: base for simulating FHS component manager (CM) classes
FhsObsSimMode and SimModeObsCMBase: extensions of the above classes for simulation of observing devices
Any FHS device needing simulation can be turned into a standalone simulator with the following changes:
Create a sim CM for the device that replicates the actual CM’s interface. The FHS sim CM inherits from either SimModeCMBase or SimModeObsCMBase. Three basic things must be implemented:
Default attribute return values, stored in attribute_overrides.
Attribute getters so that attribute_overrides can be read by the device class.
Attribute setters for any write attributes, so the device class can set attribute_overrides.
Default command return values, stored in command_overrides.
Create an FHS simulator device class, that inherits from both the actual FHS device class and one of either FhsSimMode or FhsObsSimMode.
This will need a main() method to run the simulator, which will furthermore require an entrypoint script in pyproject.toml.
This process startup command will lastly need to be added to the chart values such that it is called instead of the genuine device startup when the value standaloneSimulator is set to true.
For a fleshed-out example see the simulation of VCCAllBandsController: ska-mid-cbf-fhs-vcc
Example test code: overriding On command result code
# Get a proxy to the simulated device.
simulator = tango.DeviceProxy("<simulator FQDN>")
# Commands are set by default to return OK.
(result_code, message) = simulator.On()
assert (result_code, message) == (ResultCode.OK, "On completed OK")
# Override the result code value by writing the simOverrides attribute.
# Only behaviours included in the JSON configuration will override the default,
# so here the returned message will stay the same.
simulator.simOverrides = json.dumps(
{
"commands": {
"On": {
"result_code": "FAILED"
}
}
}
)
(result_code, message) = simulator.On()
assert (result_code, message) == (ResultCode.FAILED, "On completed OK")
Class breakdown
FHS simulator device base mix-in (FhsSimMode) - inherits from ska-tango-base tango.Device and implements patterns from the ska-tango-base class TestModeOverrideMixin
Adds the simOverrides attribute: write a JSON-formatted string containing overrides under 2 keys, “attributes” and “commands”, which update the attribute_overrides and command_overrides dicts respectively
“attributes”: keys are attribute names, values are override values for those attributes
Initialized with default values
Updated with values from simOverrides.write; any change in attribute values will push a new change event for those attributes
Attribute write methods also update the override values; clients should be able to write new values to the simulator and expect them to be stored if allowed
“commands”: keys are command names, values are dicts containing the following:
For LRCs: command callback update values, including result code, message, component state updates
For FastCommands: return value tuple
start/stop_communicating: callback update values to edit adminMode pseudo-command behaviour
FHS simulator component manager class (SimModeCMBase) - inherits from the ska-tango-base class TaskExecutorComponentManager
Provides 3 methods for simulating LRC behaviour
sim_command: behaves as typical LRC target method, simply submits private _sim_command method to the task executor queue; the only difference is that it takes in the command name as sole argument, passing it to the private method as well, for logging and task_callback use
is_sim_command_allowed: returns True and thus executes the _sim_command private method if “allowed” is set to True or None in command overrides; if set to False, simulate command rejection. Used by both LRCs and FastCommandSim.
_sim_command: private LRC execution method (following the pattern established for all other Mid.CBF devices), follows command_overrides to indicate behaviour of command
start/stop_communicating: adminMode.write is a pseudo-command, so we can alter the behaviour of these component manager methods as well
Example sequence: using simOverrides