Skip to content

Scaler ophyd-async device implementation - #306

Draft
Thomas Hopkins (thopkins32) wants to merge 3 commits into
NSLS2:mainfrom
thopkins32:scaler-async
Draft

Thomas Hopkins (thopkins32) wants to merge 3 commits into
NSLS2:mainfrom
thopkins32:scaler-async

Conversation

@thopkins32

@thopkins32 Thomas Hopkins (thopkins32) commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closes #287

Adds nslsii.ophyd_async.devices.scaler.Scaler:

  • Scaler: the SynApps scalerRecord (e.g. a Struck SIS3820 run as a plain VME scaler): .CNT/.TP-driven step counting via trigger(), per-channel .Sn/.NMn/.PRn/.Gn readouts (num_channels, hinted_channels), and an optional SIS calc-record extension (num_calculations) for sites (HXN) that compute a derived scalar from the channels on the same IOC, in the same trigger cycle.

Here is how it is used:

scaler = Scaler("XF:99ID-ES{Sclr:1}", num_channels=8, hinted_channels=(2, 3))

Motivation / Context

Plain SynApps scaler records and the HXN SIS calc-record extension, and ad hoc retrying-read signal subclasses are independently reimplemented across csx, tes, xfm, fxi, srx, ios, and hxn profile collections. This consolidates them into one configurable pair of devices instead of each site's bespoke subclass.

I originally tried to implement the flyscanning ScalerMCS class but decided against it since it depends on a custom ZebraSaver IOC and otherwise does not follow the proper flyscanning protocol. To do this work would require a standard mechanism to write this data to disk (HDF writer or similar) and then use of StandardDetector and a data logic.

Testing

  • Unit tests
  • Integration tests with RE against a real/simulated IOC
  • Tested at a beamline

References

SynApps / hardware

Beamline-specific implementations reviewed

Beamline Source Relevant behavior
CSX 90-softGluescalar.py Scaler/FixedScalerCH pattern
TES 25-sclr.py Byte-identical to CSX's 90-softGluescalar.py
XFM 20-scaler.py Single device with a runtime mode='counting'/'flying' switch toggling read_attrs/configuration_attrs between a ScalerCH and a ScalerMCA sub-device — exactly the single-object, mode-switching design this PR deliberately avoids by keeping Scaler/ScalerMCS as two independent devices
SRX 30-scaler.py SRXScaler, MCS fly-buffer usage, unpadded mca{1..32} naming
FXI 05-ion-chamber.py FXIScaler, EpicsSignalROLazyier retry-on-stale-read subclass (obsoleted here by Format.UNCACHED_SIGNAL reads plus a trigger() that only completes once counting has actually finished)
IOS 20-detectors.py DodgyEpicsScaler, same retry-on-stale-read motivation as FXI
HXN 22-scalers.py, hxntools/struck_scaler.py StruckScaler/HxnTriggeringScaler, internal/external (modal) channel-advance triggering, SIS calc-record extension, Mca:{1..32}-style (colon) buffer naming

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate SynApps / SIS / SoftGlue scalers to ophyd-async

1 participant