-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for saving and restoring pv fields with autosave
- Loading branch information
Showing
16 changed files
with
1,181 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from softioc import autosave, builder, softioc | ||
import cothread | ||
|
||
# Set the record prefix | ||
builder.SetDeviceName("MY-DEVICE-PREFIX") | ||
|
||
# Create records, set some of them to autosave, also save some of their fields | ||
|
||
builder.aOut("AO", autosave=True) | ||
builder.aIn("AI", autosave=["PREC", "EGU"]) | ||
builder.boolIn("BO") | ||
builder.WaveformIn("WAVEFORMIN", [0, 0, 0, 0], autosave=True) | ||
with autosave.Autosave(["VAL", "LOPR", "HOPR"]): | ||
builder.aOut("AUTOMATIC-AO", autosave=["EGU"]) | ||
seconds = builder.longOut("SECONDSRUN", autosave=True) | ||
|
||
autosave.configure( | ||
directory="/tmp/autosave-data", | ||
name="MY-DEVICE-PREFIX", | ||
save_period=5.0 | ||
) | ||
|
||
builder.LoadDatabase() | ||
softioc.iocInit() | ||
|
||
# Start processes required to be run after iocInit | ||
def update(): | ||
while True: | ||
cothread.Sleep(1) | ||
seconds.set(seconds.get() + 1) | ||
|
||
cothread.Spawn(update) | ||
|
||
softioc.interactive_ioc(globals()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
Use `softioc.autosave` in an IOC | ||
================================ | ||
|
||
`../tutorials/creating-an-ioc` shows how to create a pythonSoftIOC. | ||
|
||
|
||
Example IOC | ||
----------- | ||
|
||
.. literalinclude:: ../examples/example_autosave_ioc.py | ||
|
||
Records are instantiated as normal and configured for automatic loading and | ||
periodic saving to a backup file with use of the keyword argument ``autosave``. | ||
``autosave`` resolves to a list of strings, which are the names of fields to be | ||
tracked by autosave. By default ``autosave=False``, which disables autosave for that PV. | ||
Setting ``autosave=True`` is equivalent to passing ``["VAL"]``. Note that ``"VAL"`` must be | ||
explicitly passed when tracking other fields, e.g. ``["VAL", "LOPR", "HOPR"]``. | ||
``autosave`` can also accept a single string field name as an argument. | ||
|
||
The field values get written into a yaml-formatted file containing key-value pairs. | ||
By default the keys are the same as the full PV name, including any device name specified | ||
in :func:`~softioc.builder.SetDeviceName()`. | ||
|
||
Autosave is disabled until :func:`~softioc.autosave.configure()` is called. The first two arguments, | ||
``directory`` and ``name`` are required. Backup files are periodically written into | ||
``directory`` with the name ``<name>.softsav`` every ``save_period`` seconds, | ||
set to 30.0 by default. The directory must exist, and should be configured with the appropriate | ||
read/write permissions for the user running the IOC. | ||
|
||
IOC developers should only need to interface with autosave via the :func:`~softioc.autosave.configure()` | ||
method and the ``autosave`` keyword argument. Alternatively, | ||
PVs can be instantiated inside the :class:`~softioc.autosave.Autosave()` context manager, which | ||
automatically passes the ``autosave`` argument to any PVs created | ||
inside the context manager. If any fields are already specified by the ``autosave`` keyword | ||
argument of a PV's initialisation call the lists of fields to track get combined. | ||
All other module members are intended for internal use only. | ||
|
||
In normal operation, loading from a backup is performed once during the | ||
:func:`~softioc.builder.LoadDatabase()` call and periodic saving to the backup file begins when | ||
:func:`~softioc.softioc.iocInit()` is called, provided that any PVs are configured to be saved. | ||
Currently, manual loading from a backup at runtime after ioc initialisation is not supported. | ||
Saving only occurs when any of the saved field values have changed since the last save. | ||
Users are discouraged from manually editing the backup files while the | ||
IOC is running so that the internal state of the autosave thread is consistent with | ||
the backup file. | ||
|
||
If autosave is enabled and active, a timestamped copy of the latest existing autosave backup file is created | ||
when the IOC is restarted, e.g. ``<name>.softsav_240717-095004`` (timestamps are in the format yymmdd-HHMMSS). | ||
If you only wish to store one backup of the autosave file at a time, ``timestamped_backups=False`` | ||
can be passed to :func:`~softioc.autosave.configure()` when it is called, this will create a backup file | ||
named ``<name>.softsav.bu``. To disable any autosaving, comment out the | ||
:func:`~softioc.autosave.configure()` call or pass it the keyword argument | ||
``enabled=False``. | ||
|
||
The resulting backup file after running the example IOC for about 30 seconds is the following: | ||
|
||
.. code-block:: | ||
MY-DEVICE-PREFIX:AI.EGU: '' | ||
MY-DEVICE-PREFIX:AI.PREC: '0' | ||
MY-DEVICE-PREFIX:AO: 0.0 | ||
MY-DEVICE-PREFIX:AUTOMATIC-AO: 0.0 | ||
MY-DEVICE-PREFIX:AUTOMATIC-AO.EGU: '' | ||
MY-DEVICE-PREFIX:AUTOMATIC-AO.HOPR: '0' | ||
MY-DEVICE-PREFIX:AUTOMATIC-AO.LOPR: '0' | ||
MY-DEVICE-PREFIX:SECONDSRUN: 29 | ||
MY-DEVICE-PREFIX:WAVEFORMIN: [0, 0, 0, 0] | ||
If the IOC is stopped and restarted, the SECONDSRUN record will load its saved | ||
value of 29 from the backup. | ||
All non-VAL fields are stored as strings. Waveform type records holding arrays | ||
are cast into lists before saving. | ||
|
||
This example IOC uses cothread, but autosave works identically when using | ||
an asyncio dispatcher. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.