Commit Graph
1140 Commits
Author SHA1 Message Date
wakonig_k 845822cc34 feat(rt): add data monitor
CI for csaxs_bec / test (push) Successful in 2m13s
CI for csaxs_bec / test (pull_request) Successful in 2m14s
2026-09-19 09:40:52 +02:00
x12saandClaude Sonnet 5 acdca82137 docs(flomni): save the confirmed Mode A/Mode B PandA layouts
CI for csaxs_bec / test (pull_request) Successful in 2m17s
Read the Docs Deploy Trigger / trigger-rtd-webhook (push) Successful in 2s
CI for csaxs_bec / test (push) Successful in 2m15s
Captured 2026-09-15 directly from the omny-panda hardware via
GetState() (ophyd_devices/devices/panda_box/utility_scripts.py), one
per Design: omny.ini (Mode A) and omny_freerun.ini (Mode B). Mode B was
speed-tested successfully up to 20 kHz same day, though the saved
omny_freerun.ini itself reflects CLOCK1.PERIOD=0.0001 (10 kHz) -- flagged
in the setup doc as a discrepancy to double-check rather than assumed
away.

Setup doc updated with the exact save/load commands and a diff summary
of the two layouts' mode-specific differences (PCAP.GATE/TRIG source,
CLOCK1.ENABLE, capture types).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TsfqLcPWspjJ6vedMyCxco
2026-09-15 15:30:10 +02:00
x12saandClaude Sonnet 5 842efeb553 config(flomni): swap panda config back to Mode B for speed testing
CI for csaxs_bec / test (push) Successful in 2m23s
Mode A commented out, omny_panda_continuous active -- next step is
testing above the initial 100 Hz CLOCK1 rate now that Mode B is
confirmed working end-to-end.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TsfqLcPWspjJ6vedMyCxco
2026-09-15 15:08:12 +02:00
x12saandClaude Sonnet 5 f82fd51a72 fix(flomni): comment out omny_panda_continuous, enabled:false wasn't enough
CI for csaxs_bec / test (push) Successful in 2m15s
Both omny_panda and omny_panda_continuous ended up connected and active
simultaneously against the same physical PandA, even though only
omny_panda was enabled: true -- a device already connected apparently
doesn't disconnect just because a later config reload disables it.

Comment the inactive mode's block out entirely instead of relying on
enabled: false, so BEC never constructs the device object at all. Docs
updated to correct the earlier (wrong) guidance that toggling enabled
alone was sufficient to switch between modes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TsfqLcPWspjJ6vedMyCxco
2026-09-15 15:04:59 +02:00
x12saandClaude Sonnet 5 6415db0e2d config(flomni): switch panda config back to Mode A, record Mode B success
CI for csaxs_bec / test (push) Successful in 2m19s
Mode B (omny_panda_continuous) confirmed working end-to-end against real
PandA hardware on 2026-09-15: correct per-channel raw values, masked
gate_detector_active, and frame_counter-based completion all verified.
Switching back to Mode A (omny_panda) for A/B comparison testing.

Both device entries now stay uncommented in ptycho_flomni.yaml, toggled
via enabled: true/false, rather than commenting/uncommenting blocks --
confirmed a disabled device is an inert placeholder that BEC's device
server never connects to. Speed testing Mode B beyond the initial 100 Hz
is still TODO.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TsfqLcPWspjJ6vedMyCxco
2026-09-15 15:02:57 +02:00
x12saandClaude Sonnet 5 f93e591227 feat(flomni): split omny_panda into two devices, fix free-running completion check
CI for csaxs_bec / test (push) Successful in 2m13s
Mode A (per-gate aggregate) and Mode B (continuous raw-sample) need
different PandA hardware layouts and can't run simultaneously, so
omny_panda is now two device config entries in ptycho_flomni.yaml:
omny_panda (legacy, kept commented as the restore reference) and
omny_panda_continuous (raw_stream_mode: true, enabled).

Also fixes on_complete for the continuous case. PCAP.CAPTURED can't be
used to detect end-of-acquisition on this layout: CLOCK1 drives
PCAP.gate/trig continuously, so the captured count never naturally
stops increasing while armed -- the previous settle-based wait would
have just run out its timeout. COUNTER1 (frame_counter) instead counts
completed exposures directly (triggered on the detector-trigger's
falling edge), so PandaBoxOMNY now waits for it to reach the exact
expected num_points * frames_per_trigger, mirroring the legacy
exact-count check instead of guessing when capture has "settled".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TsfqLcPWspjJ6vedMyCxco
2026-09-15 14:22:28 +02:00
x12saandClaude Sonnet 5 3012cd3154 fix(flomni): mask gate_detector_active to its own bit, record confirmed PandA wiring
TTLIN1 (detector trigger) drives both COUNTER1 (frame_counter) and the
PCAP.BITS0 gate-bit capture, confirmed 2026-09-15 against the omny-panda
hardware via TTLIN1.VAL.CAPTURE_WORD?/OFFSET? (PCAP.BITS0, bit 0).

PCAP.BITS0 is a shared 32-bit word -- other captured bit_out signals may
occupy other bit positions of it, so the raw word is not itself a clean
0/1. PandaBoxOMNY now masks gate_detector_active down to bit 0 before
publishing it, instead of trusting the whole word.

Also records the confirmed free-running setup in the developer docs: all
four encoders plus both FMC_IN channels switched to raw Value capture,
CLOCK1 driving continuous PCAP gate/trig, and the initial 100 Hz test
rate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TsfqLcPWspjJ6vedMyCxco
2026-09-15 14:13:22 +02:00
x01dcandClaude Sonnet 5 82ecab4c21 feat(flomni): add continuous free-running raw-sample mode to PandaBoxOMNY
CI for csaxs_bec / test (push) Successful in 2m14s
Adds an opt-in raw_stream_mode to omny_panda alongside the existing
per-gate averaged burst acquisition, so a burst window can instead be
captured as continuous raw samples plus a detector-gate bit and a
monotonic frame counter for completeness checking. Client-side
coalescing bounds the message rate to the BEC message bus regardless of
PandA's own network-frame batching, and completion uses a settle-based
check since an exact expected sample count isn't predictable for
continuous capture. Defaults to off, preserving today's behavior
exactly; hardware wiring/layout and the raw data schema are documented
under docs/developer/ pending PandA hardware access to configure and
validate against.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 13:44:07 +02:00
x12saandClaude Sonnet 5 3f719c8119 feat(ddg): add show_all() status command for the delay generators
CI for csaxs_bec / test (pull_request) Successful in 2m15s
Read the Docs Deploy Trigger / trigger-rtd-webhook (push) Successful in 2s
CI for csaxs_bec / test (push) Successful in 2m16s
Prints the current per-pair delay/width/reference/IO settings and the
trigger/burst configuration for DDG1/DDG2, following the PrettyTable
status pattern already used by the Galil controllers. Exposed via
USER_ACCESS as dev.ddg1.show_all() / dev.ddg2.show_all().

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 12:48:12 +02:00
x12saandClaude Sonnet 5 f1e9b2b3bb feat(ids-cameras): add IDSCameraSettings widget for multi-camera exposure/gain control
CI for csaxs_bec / test (pull_request) Successful in 2m16s
Read the Docs Deploy Trigger / trigger-rtd-webhook (push) Successful in 2s
CI for csaxs_bec / test (push) Successful in 2m13s
OMNY_XRayEye's exposure/pixel-clock controls are hardcoded to a single
camera (cam_xeye). Several beamline configs define more than one IDSCamera
at once (e.g. ptycho_omny.yaml's cam200..cam203), none of which were
reachable from that widget.

Adds a standalone IDSCameraSettings panel: a camera-selection dropdown
(filtered by deviceClass, extensible to other camera classes later) plus
auto-exposure/exposure-time/pixel-clock controls that re-subscribe to the
selected camera's device_read_configuration on every switch, seeded
immediately from the retained redis value. Scaffolded via
bw-generate-cli --target csaxs_bec (client.py, designer_plugins.py).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TUimPoyFQRvxM6R3njvuVj
2026-09-15 08:31:52 +02:00
x01dcandClaude Sonnet 5 2f6f4456f9 docs(ids-cameras): record round-4 HW-testing findings in the exposure/gain plan
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYQTHuSxSaLCijvayoRkX5
2026-09-15 08:31:52 +02:00
x01dcandClaude Sonnet 5 afca16bfe3 fix(xrayeye): make the pixel clock slider index-based over supported values
The server-side snap-to-nearest fix (previous commit) corrected what
got written to hardware, but the slider itself still let an operator
drag to -- and briefly display -- any integer in [min, max] before
self-correcting on the next status message, which reads as "the slider
allows any setting" even though bad ones don't stick.

pixel_clock_slider's range is now [0, len(options)-1], an index into
the real discrete list of supported pixel clocks (fetched once over
RPC at widget startup via get_pixel_clock_list(), disabled until it
arrives -- not a polling loop, this list never changes at runtime).
Every position the slider can physically be dragged to is therefore
one the hardware has already confirmed it accepts.
getting_camera_status() now maps the hardware-reported MHz value to
the nearest option's index instead of setting the slider to a raw MHz
value.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYQTHuSxSaLCijvayoRkX5
2026-09-15 08:31:52 +02:00
x01dcandClaude Sonnet 5 a550fd4f03 docs(ids-cameras): record round-3 HW-testing findings in the exposure/gain plan
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYQTHuSxSaLCijvayoRkX5
2026-09-15 08:31:51 +02:00
x01dcandClaude Sonnet 5 9e1a3f68ba feat(xrayeye): remove the Auto gain toggle
auto_gain_enabled is now purely an internal connect-time mechanism
(IDSCamera pulses it on then off at connect, see its on_connected())
rather than a persistent operator control -- continuous auto-gain had
nothing further to adjust once correctly exposed, and having it
enabled took gain out of manual control. Still reachable via
IDSCamera.set_auto_gain_enabled() (USER_ACCESS) for scripted use.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYQTHuSxSaLCijvayoRkX5
2026-09-15 08:31:51 +02:00
x01dcandClaude Sonnet 5 8cf95196b7 fix(ids-cameras): snap pixel clock to a supported value; pulse auto-gain
Pixel clock: get_pixel_clock_range()'s (min, max, increment) describes
a linear range, but IS_PIXELCLOCK_CMD_SET doesn't actually accept
every value in it -- confirmed on hardware, 49/60/73 MHz all failed on
camera 41. Added Camera.get_pixel_clock_list() (IS_PIXELCLOCK_CMD_GET_
NUMBER + _GET_LIST, the SDK's authoritative source for what's settable)
and IDSCamera.get_pixel_clock_list(); IDSCamera.set_pixel_clock() now
snaps to the nearest supported value before writing, instead of
passing the raw requested value straight to the driver.

Auto gain: HW testing found continuous auto-gain has nothing further
to adjust once correctly exposed, and takes gain out of manual
control. on_connected() now pulses auto_gain_enabled on then off
(_AUTO_GAIN_SETTLE_S = 0.5s in between, for the already-running
continuous capture to feed it a few frames), instead of leaving it
enabled like auto_exposure_enabled -- still does the one-time gain
correction, but leaves gain fixed under manual control afterward.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYQTHuSxSaLCijvayoRkX5
2026-09-15 08:31:51 +02:00
x01dcandClaude Sonnet 5 b01448f161 docs(ids-cameras): record round-2 HW-testing findings in the exposure/gain plan
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYQTHuSxSaLCijvayoRkX5
2026-09-15 08:31:50 +02:00
x01dcandClaude Sonnet 5 69ad5135a9 feat(xrayeye): add pixel clock slider; fix exposure slider's physical bound
Adds a "Pixel clock" slider (MHz) below the exposure-time slider,
bounded to the device's pixel_clock_min/max -- previously that control
was script-only via IDSCamera.set_pixel_clock(). Needed because the
exposure slider's max is bounded by the current pixel clock, and
operators hitting that ceiling need a way to raise it from the GUI.

Also fixes the exposure-time slider allowing a literal 0 ms: its bounds
were rounded to nearest tenth-of-a-ms, which could round a small
nonzero hardware minimum down to 0. Now rounds the min up (ceil,
clamped to >= 1) and the max down (floor) instead, so the slider never
claims a bound the hardware won't actually accept.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYQTHuSxSaLCijvayoRkX5
2026-09-15 08:31:50 +02:00
x01dcandClaude Sonnet 5 9a999bed37 fix(ids-cameras): apply auto-exposure/gain defaults on connect; add pixel clock
auto_exposure_enabled/auto_gain_enabled default to True but were never
actually written to hardware at connect -- is_ResetToDefault() leaves
the sensor's auto-shutter/auto-gain off, so a fresh session ran
under-exposed until an operator happened to re-toggle the GUI switch
(which is what issued the enable call for the first time). Fixed by
round-tripping both through their subscribe callbacks in
on_connected(), same idiom as exposure_time.

Also adds pixel_clock/pixel_clock_min/pixel_clock_max Kind.config
signals, backed by the Camera.get_pixel_clock()/get_pixel_clock_range()/
set_pixel_clock() added earlier -- lowering the pixel clock raises the
achievable max exposure time, and changing it now re-derives
exposure_time_min/max from hardware automatically.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYQTHuSxSaLCijvayoRkX5
2026-09-15 08:31:50 +02:00
x01dc 93e18af4d5 docs(ids-cameras): record HW-testing findings in the exposure/gain plan 2026-09-15 08:31:50 +02:00
x01dc 557ca42a0c feat(xrayeye): reorganize control panel; exposure time as slider, not spinbox
Moves the auto-exposure/auto-gain toggles out of the shutter/camera
switch grid into their own section, bracketed by horizontal separators:
switches -> line -> exposure/gain section -> line -> alignment values
(2D positioner + zoom).

Also replaces the exposure-time QDoubleSpinBox with a QSlider bounded
to the device's real exposure_time_min/max (from IDSCamera, seeded
from hardware) instead of a hardcoded 0.01-1000ms placeholder --
QSlider is int-only, so the widget tracks tenths of a ms internally
and shows one decimal on a companion label. Submission still fires
once on release, not per tick.
2026-09-15 08:31:49 +02:00
x01dc 8c1c322393 fix(ids-cameras): fix auto-gain/auto-exposure SDK call, add exposure-range query
is_SetAutoParameter's pval1/pval2 are double* (8 bytes); set_auto_gain()/
set_auto_shutter() were passing a c_int (4 bytes), so the driver read
garbage past the buffer and rejected it -- this is what raised
UEyeException (surfaced as ophyd's "Subscription value callback
exception") when toggling auto gain on real hardware. Fixed to pass
c_double, matching the SDK's documented signature.

Also wrap the three hardware-write subscribe callbacks in try/except so
a driver failure logs clearly from IDSCamera instead of only via
ophyd's generic subscription-exception message.

Adds Camera.get_exposure_range()/get_pixel_clock()/
get_pixel_clock_range()/set_pixel_clock() (the max exposure time is
bounded by the current pixel clock) and matching IDSCamera
exposure_time_min/max config signals + USER_ACCESS wrappers, seeded on
connect, so the GUI can bound its exposure control to real hardware
limits instead of a placeholder range.
2026-09-15 08:31:49 +02:00
x01dc b98bfb3217 docs(ids-cameras): mark exposure/gain plan implemented; add HW test config
Add a temporary single-camera (ID 41, color) device config for manually
verifying the new exposure/auto-gain controls against real hardware
outside a live beamtime, and update the plan's status accordingly.
2026-09-15 08:31:49 +02:00
x01dc 713eaed245 feat(xrayeye): add exposure/auto-gain control knobs to OMNY_XRayEye
Adds "Auto exposure"/"Auto gain" toggles and an exposure-time spinbox
to the xrayeye widget's control panel, following the existing
cached/event-driven pattern (no polling): writes go through RPC .put()
on IDSCamera's new config signals, reads come from the same
device_read_configuration message already used for live_mode_enabled.

Phase 2 of docs/plans/ids-camera-manual-exposure.md.
2026-09-15 08:31:48 +02:00
x01dc e3323e521e feat(ids-cameras): add manual exposure / auto-gain control signals
Adds exposure_time/auto_exposure_enabled/auto_gain_enabled as
Kind.config Signals on IDSCamera (mirroring live_mode_enabled), with
USER_ACCESS wrappers and hardware seeding of exposure_time on connect.
Extends SimIDSCamera's backend to match, and adds unit test coverage.

Per docs/plans/ids-camera-manual-exposure.md.
2026-09-15 08:31:48 +02:00
x12saandClaude Sonnet 5 cc93d563bf fix(tests): accept _internal kwarg in tomo_scan_projection test doubles
CI for csaxs_bec / test (pull_request) Successful in 2m6s
Read the Docs Deploy Trigger / trigger-rtd-webhook (push) Successful in 2s
CI for csaxs_bec / test (push) Successful in 2m8s
7d64b49 added an _internal kwarg to LamNI.tomo_scan_projection() (used
by tomo_alignment_scan/_at_each_angle to skip the redundant per-angle
filter-out-of-beam check) but left three tests' fake/lambda
replacements without it, causing them to fail in CI with
"got an unexpected keyword argument '_internal'".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFeiCHv3qUxxssmP9Qzhom
2026-09-15 08:27:47 +02:00
x12sa f916b2cec1 config update
CI for csaxs_bec / test (push) Failing after 2m12s
CI for csaxs_bec / test (pull_request) Failing after 2m15s
2026-09-15 08:22:55 +02:00
x12saandClaude Sonnet 5 6e8fc91924 docs(omny): fix omny_fermat_scan parameter table and add docstring example
CI for csaxs_bec / test (push) Failing after 2m10s
Reorders omny.md's parameter table to match the actual signature,
adds the previously undocumented readout_time parameter, and adds an
Examples block to OmnyFermatScan's docstring (mirroring the flomni fix).
Also rewords flomni.md's corridor_size default to read "3 um" for
consistency with omny, while noting it is auto-estimated when omitted.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFeiCHv3qUxxssmP9Qzhom
2026-09-14 20:52:03 +02:00
x12saandClaude Sonnet 5 5141854e14 docs(flomni): fix flomni_fermat_scan parameter table to match code
CI for csaxs_bec / test (push) Failing after 2m5s
Reorders parameters to match the actual signature, adds the
undocumented burst_at_each_point parameter, and corrects the
corridor_size default (None/auto-estimated, not a literal 3 um).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFeiCHv3qUxxssmP9Qzhom
2026-09-14 20:47:20 +02:00
x12saandClaude Sonnet 5 2753bb9243 docs(flomni): add usage example to flomni_fermat_scan docstring
CI for csaxs_bec / test (push) Failing after 2m10s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFeiCHv3qUxxssmP9Qzhom
2026-09-14 20:12:27 +02:00
x12saandClaude Sonnet 5 501c93d41c fix(flomni): use last completed scan number when tomo_reconstruct's cached scan list is stale
CI for csaxs_bec / test (push) Failing after 2m4s
tomo_reconstruct() named the queue file from a fresh next_scan_number but
wrote its content from self._current_scan_list, which is only kept in sync
by tomo_scan_projection()/tomo_acquire_at_angle(). Calling it directly from
the command line -- e.g. after a plain scans.flomni_fermat_scan() -- wrote
whatever scan list was left over from an earlier tomo scan, or raised
AttributeError if none had run yet this session.

Falls back to [next_scan_number - 1] whenever the cached list's last entry
doesn't match the scan that actually just completed. Internal callers are
unaffected since their cached list always matches at the point they call it.

Also notes the identical bug in OMNY.tomo_reconstruct() (a separate,
non-shared implementation) as a TODO for a later fix on its own branch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TUimPoyFQRvxM6R3njvuVj
2026-09-14 17:06:02 +02:00
x12saandClaude Sonnet 5 df7c90c5d7 docs(omny): document manual tomo_alignment_fit offset nudge
CI for csaxs_bec / test (push) Failing after 2m5s
Port the flomni doc addition to omny -- both setups share the identical
tomo_alignment_fit mechanism (OMNYAlignmentMixin.get_alignment_offset
mirrors Flomni's), so the same command-line offset nudge applies verbatim.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFeiCHv3qUxxssmP9Qzhom
2026-09-13 21:56:15 +02:00
x12saandClaude Sonnet 5 d100af5429 docs(flomni): document manual tomo_alignment_fit offset nudge
CI for csaxs_bec / test (push) Failing after 2m16s
Add a snippet to the XrayEye alignment section showing how to patch the
constant x/y offset terms of tomo_alignment_fit directly on the command
line, for a quick few-micron correction (e.g. after moving foptz) without
recording a new fit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFeiCHv3qUxxssmP9Qzhom
2026-09-13 21:54:42 +02:00
x12saandClaude Sonnet 5 5a22651c46 fix(flomni): report correct projection count in tomo PDF/SciLog for golden-ratio scans
CI for csaxs_bec / test (push) Failing after 2m7s
write_pdf_report() always derived "Number of projections" (and the
dependent sub-tomogram-count/angular-step fields) from
_tomo_type1_actual_grid(), which is only valid for tomo_type==1. For
golden-ratio scans (tomo_type 2/3) it silently reported a stale,
unrelated type-1 total left over in the persistent tomo_angle_stepsize
global var instead of golden_max_number_of_projections, causing the
PDF/SciLog entry to disagree with the web page's correct progress
display. Branch on tomo_type the same way tomo_parameters() already
does.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFeiCHv3qUxxssmP9Qzhom
2026-09-12 20:31:24 +02:00
x12saandClaude Sonnet 5 2dae9441ec docs(ids-cameras): extend exposure/gain plan to xrayeye widget controls
CI for csaxs_bec / test (push) Failing after 2m10s
No code changes -- IDSCamera and the xrayeye widget are both used
during beamtimes. Revises the earlier plain-method design to
Cpt(Signal, kind=Kind.config) (mirroring live_mode_enabled) so the
xrayeye widget can read exposure/auto-exposure/auto-gain state via
its existing device_read_configuration subscription instead of
polling the device, and adds the corresponding GUI control knobs
(auto-exposure/auto-gain toggles, exposure spinbox) to the plan.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014s92UHyMfov6Fb934pGqcU
2026-09-11 20:30:54 +02:00
x12saandClaude Sonnet 5 ec3e7c0679 docs(ids-cameras): add plan for manual exposure/auto-gain control
CI for csaxs_bec / test (push) Failing after 2m5s
No code changes -- IDSCamera is in production use during beamtimes.
Documents the intended USER_ACCESS additions (get/set_exposure_time,
set_auto_exposure_enabled, set_auto_gain_enabled) for a future session.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014s92UHyMfov6Fb934pGqcU
2026-09-11 18:01:49 +02:00
x12saandClaude Sonnet 5 0cadd8582e fix(flomni,omny): sanitize sample name spaces in tomography_scannumbers.txt
CI for csaxs_bec / test (push) Failing after 19m49s
The scannumbers log is read column-wise by downstream tooling; a
sample name containing spaces breaks that whitespace-based parsing
since it's written as the trailing field. Replace spaces with
underscores before writing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FB3kYVkJruYsmcVsj7RS1G
2026-09-11 16:24:12 +02:00
x12saandClaude Sonnet 5 47a9c4c444 fix(flomni,lamni): persist tomo_id across client restarts
CI for csaxs_bec / test (push) Failing after 4m17s
self.tomo_id was a plain instance attribute reset to -1 on every
Flomni/LamNI init, so resuming a tomo scan after a client/kernel restart
(tomo_scan_resume(), or tomo_queue_execute()'s automatic resume) kept
reporting/uploading under the wrong id instead of the one actually
registered with OMNY for that measurement.

Back it with the existing _GlobalVarParam descriptor on TomoQueueMixin
(the same BEC Redis-backed global-var mechanism already used for
tomo_shellstep, stitch_x, at_each_angle_hook, etc.) so it survives a
restart like the rest of the tomo-scan state already does.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013gGu5ANBo88Fh7eqmRdFbU
2026-09-11 16:19:10 +02:00
x12saandClaude Sonnet 5 da4007d7e7 fix(flomni,lamni): stop registering test/gac accounts against production omny.psi.ch
TomoIDManager.OMNY_URL and TEST_OMNY_URL both point at omny.psi.ch since
the dedicated omny-test.psi.ch host was retired, so the eaccount check no
longer redirects test/gac-* accounts anywhere different -- it just logs a
warning and still registers them in the production sample database. Skip
registration entirely for non-e-accounts and return FALLBACK_TOMO_ID
instead, to avoid polluting production with test entries.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013gGu5ANBo88Fh7eqmRdFbU
2026-09-11 16:18:51 +02:00
x12saandClaude Sonnet 5 42739fcc7a docs(flomni): flag unguarded heater-vs-OSA collision gap in fosa_in()
CI for csaxs_bec / test (push) Failing after 4m58s
Audit of heater interlocks (pre-first-use) found that fosa_in()/
foptics_in() never check fheater position before driving fosaz, even
though the OSA travels inside the heater's envelope. Heater motion
itself is well protected (ensure_osa_back()/ensure_fheater_up()), but
this one direction is open. Not fixing it yet -- documenting it so it
is remembered when fheater's userParameter is added during hardware
commissioning.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 13:15:58 +02:00
x12saandClaude Sonnet 5 f56d11d730 fix(flomni): close race between sample-storage EPICS writes and reads
CI for csaxs_bec / test (push) Failing after 6m18s
ftransfer_sample_change occasionally raised "The gripper does not carry
a sample" right after a successful get, even though the gripper
physically held one. Root cause: flomni_modify_storage_non_interactive
wrote the sample_in_gripper/sample_placed signals with EpicsSignal.set()
without waiting for the write to complete, and the immediately-following
is_sample_in_gripper()/is_sample_slot_used() checks read the
auto_monitor-cached value, which could still reflect the pre-write state.

Wait on each .set() call (5s timeout, matching the existing
.set(...).wait(timeout=...) pattern used elsewhere for EPICS writes),
and force is_sample_in_gripper()/is_sample_slot_used() to do a live
get(use_monitor=False) read instead of trusting the monitor cache
(mirroring the same pattern already used in ddg_1.py). This closes the
race deterministically instead of masking it with an arbitrary sleep.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 10:18:29 +02:00
x12saandClaude Sonnet 5 59cdc5c512 fix(omny): increase laser tracker on-target wait timeout, add status print
CI for csaxs_bec / test (push) Failing after 7m30s
Bump max_repeat from 25 to 100 (~12.5s to ~50s) in
laser_tracker_wait_on_target, since the tracker was timing out too
early during beamtime. Print a status message once the retry-enable
branch kicks in so it's visible the wait is still in progress.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 09:11:37 +02:00
x12saandClaude Sonnet 5 d6e2ca8d1a fix(omny): mitigate scrambled Galil PUT/GET communication with settle delays
GalilController had zero delay in its socket path (write immediately
followed by a blocking read), unlike sgalil_ophyd.py's GalilController
which already sleeps 10ms in both socket_put and socket_get. This
increased the chance of partial-packet collisions/desync between
commands and responses during flomni beamtime (see command_history
showing merged/missing PUT-GET pairs).

Add a 10ms sleep to socket_put and a socket_get override (also with a
10ms sleep) that logs into command_history, mirroring the existing
sgalil_ophyd.py pattern. This reduces desync likelihood but does not
fully fix it: failed socket_get attempts are still swallowed silently
by retry_once with no trace in command_history, and receive() still
does a single recv(1024) with no terminator framing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 09:11:08 +02:00
x12saandClaude Sonnet 5 780be4bb9f config(ptycho_flomni): update axis calibration values, disable omny_panda
Update fttrx, foptx, ftransy sensor_voltage, fosax and fosay calibration
values for current beamtime alignment. Disable omny_panda device.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 09:10:26 +02:00
x12saandClaude Sonnet 5 0fd52d23e4 config(main): switch active endstation config to flomni
Disable xeye/ssaxs includes and enable ptycho_flomni for flomni beamtime.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 09:09:59 +02:00
x12saandClaude Sonnet 5 0627221491 config(bl_detectors): switch active detector from eiger_9 to eiger_1_5
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 09:09:43 +02:00
x12saandClaude Sonnet 5 031e612394 fix(flomni): re-enable webpage generator start
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 09:09:24 +02:00
x12saandClaude Sonnet 5 36d34d2858 fix(eps): cap alarm texts per event to stop eps_alarm_history.json growing unbounded
CI for csaxs_bec / test (push) Failing after 7m36s
A long-running/flapping EPS alarm appended every slightly-different
AlarmList_EPS text to the open event's texts list with no limit,
eventually growing eps_alarm_history.json past the upload server's
size limit (HTTP 413), which then retried and re-failed indefinitely.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 09:07:25 +02:00
x12saandClaude Sonnet 5 e65389376d fix(flomni): fix UnboundLocalError for dev in tomo_scan_projection
CI for csaxs_bec / test (push) Failing after 2m19s
dev = builtins.__dict__.get("dev") was only executed inside the
`if not _internal:` block, but Python treats any name assigned
anywhere in a function as local to the whole function. The
unconditional dev.rtx.controller.laser_tracker_check_signalstrength()
call later in the function then raised UnboundLocalError whenever
_internal=True (e.g. tomo_alignment_scan() and the fermat branch of
_at_each_angle). Hoist the fetch above the guard so dev is always
bound.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CUx5yV1iCBhL5sFEHEoPe
2026-09-11 07:46:23 +02:00
x12saandClaude Sonnet 5 3bea6b1a30 docs(flomni): add cSAXS_HR August 2018_chip_maxime.pdf
CI for csaxs_bec / test (push) Failing after 2m3s
New reference PDF in the flomni docs folder, served by flomnigui_docs().

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CUx5yV1iCBhL5sFEHEoPe
2026-09-10 16:46:57 +02:00
x12saandClaude Sonnet 5 a457865768 docs(omny): TODO for filter check and missing eye/optics gate
CI for csaxs_bec / test (push) Failing after 2m3s
Notes for the OMNY branch: 1) port the filter-out-of-beam check (added
for flomni/lamni in the previous commit, shared helper already in
OMNY_shared/filter_check.py) into omny.py's tomo_scan()/
tomo_scan_projection(); 2) OMNY.tomo_scan() has no eye-out/optics-in
precondition check at all, unlike Flomni/LamNI's - a pre-existing,
unrelated gap noticed while investigating the filter check.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CUx5yV1iCBhL5sFEHEoPe
2026-09-10 15:41:02 +02:00