ts_salobj 4 is coming. This is a complete rewrite that uses OpenSplice dds libraries directly, instead of using SALPY libraries generated by ts_sal. This posting is intended to give an overview of what changed and some help with converting code.
Overview of changes:
- salobj 4 uses OpenSplice dds libraries directly, rather than SALPY libraries. salobj 4 gets its topic information from IDL files, which are generated by ts_sal.
- More topic fields are visible than with SALPY. All but one of these field names start with the prefix “private_” and salobj sets the values of these fields automatically. The fields are:
- component_nameId: the SAL index of the component. Example field names include TestId and ATPtgId.
- private_seqNum: the command ID. This is generated by the sender (e.g. salobj.RemoteCommand) and copied by the receiver (e.g. salobj.ControllerCommand) to the ackcmd samples it sends in response.
- private_rcvStamp: the time the sample was received
- private_sndStamp: The time the sample was sent
- private_host: an integer specified by environment variable LSST_DDS_IP; intended to be the sender’s IP address
- private_origin: the process ID of the sender
- Command acknowledgement uses the topic “ackcmd”.
- There is only one ackcmd topic per SAL component, and it is used for (shared by) all commands for that component. SAL differentiates between different commands by using a different range of
private_seqNumfor each command. - The field
private_seqNumis the value salobj formerly called “command ID” or “cmd_id”. - Familiar fields include “ack”, “error”, “reason”
- There is only one ackcmd topic per SAL component, and it is used for (shared by) all commands for that component. SAL differentiates between different commands by using a different range of
- DDS code should use a single “domain participant” per process; this saves time and memory, as the domain participant contains the cache of topic data. salobj encapsulates the domain participant in a new class
Domain. - I have changed salobj to expose as much of DDS as I felt we could manage.
Backward Incompatible Changes:
-
Remote's constructor no longer blocks until historical data is read. Instead it has a new attributestart_taskthat is set done when historical data is read and the remote is reading new data. - The
CommandIdDataclass is gone because command ID is is available directly in the data as fieldprivate_seqNum.do_command methods and callbacks now simply receive the command data (as specified by the IDL, with the additional formerly hidden fields mentioned in the introduction). To update your code:- Change
id_data.datatodata - Change
id_data.cmd_idtodata.private_seqNum(rare) - Change
id_datatodata - If you have unit tests that create
CommandIdDatainstances, just make the data instead.
- Change
- The
CommandIdAckclass is gone.RemoteCommand.startandnext_ackcmdboth receiveackcmdtopic data. To update your code:- Change
id_ack.cmd_idtoackcmd.private_seqNum - Change
id_ack.acktoackcmd - Change
id_acktoackcmd
- Change
- The command acknowledgement object is now called
ackcmdinstead ofack,
to match the topic name and to eliminate the confusion ofack.ack. - The
AckErrorobject now has just one field:ackcmd, instead of two fieldscmd_idandack.- Change code that raises AckError (rare)
- Change access of error fields from
.ackto.ackcmdand.cmd_idto.ackcmd.private_seqNum.
-
SalInfo.makeAckis nowSalInfo.makeAckCmdand it has one new required parameter:private_seqNum. - If your CSC has method
startit now takes no arguments, becauseBaseCsc.startnow accepts no arguments; you no longer pass ininitial_simulation_mode. - If your CSC implements
stop, change it toclose_tasksand in that method callawait super().close_tasks()and close your own extra tasks.BaseCsc.stophas been replaced byBaseCsc.closewhich callsBaseCsc.close_tasksandclose_tasksis normally all a CSC will have to override. - salobj now uses IDL files instead of SALPY libraries. These files are built by ts_sal and kept in new package
ts_idl. To make the IDL files usingmake_idl_files.pyfor examplemake_idl_files.py Test Script ScriptQueue.
We plan to have ts_sal generate modules for the enums found in the XML, but that is not yet supported. - Make
ts_idla dependency of your package, instead ofts_sal - Read topics (RemoteEvent, RemoteTelemetry, ControllerCommand) do not have the
dataproperty; usegetinstead. - You cannot set an array field to a scalar; with SALPY salobj this had the effect of setting every element
to the specified value, but it will raise an exception in dds salobj when sending the data. - If you try to send an array with too many values the extra items are silently ignored.
- Construct a
Controllerwith(name, index)instead of(SALPY_name, index). - Construct a
Remotewith(domain, name, index)instead of(SALPY_name, index). Getdomainfromcontroller.domainor make one explicitly. I made this change because best practice is to have only one dds domain participant per process. - Shutdown requires more care, especially in unit tests. Everything is cleaned up eventually
if you just shut down the process, but it takes some time, and if too many things are being cleaned up at once in a unit test you may start running out of resources. Both Controller and Domain are async context managers, so you can use them as follows:
async with Controller(...) as controller: # or async with Domain() as domain: # ...do stuff here
-
SalInfo.start()must be awaited after all topics have been created. Controller and Remote do this automatically, but it is important for code that has neither, such as some unit tests and Jupyter scripts. If you forget then read topics will not read any data. - The
Loggerclass is gone; its functionality has been incorporated into theControllerclass. - CSCs and Scripts take several seconds to close, which is slower than it used to be. This may require small changes to existing unit tests.
Other changes:
- New method
ControllerCommand.set_startallows you to specify command data and start a command using one call. - The default log level is now
INFO