When the eye is already out, optics in, and feedback running, skip the
eye-out/optics-in transition to avoid an interferometer reset. Enables
repeated alignment scans and interleaving alignment into a tomogram
without leaving the current measurement position.
feedback_disable/enable_with_reset cycle re-zeros the interferometers
and moves off the current sample position. Only run it when the FZP
actually needs to move; add force_feedback_reset kwarg and _ffzp_is_in
helper.
X-Ray Eye alignment GUI + script now share a single, device-configured
pixel calibration and the GUI shows live ROI dimensions.
GUI (x_ray_eye.py):
- Add read-only "ROI size" field below the message box, showing the active
ROI's x/y extent, updated live via each ROI's sigRegionChanged. Rectangles
report width/height; circular ROIs read raw state["size"] so an ellipse
state would be reflected (currently aspect-locked upstream).
- Add "Calibration" field showing microns/pixel, or "uncalibrated (pixels)"
when the camera parameter is absent.
- Resolve mm/pixel from dev.cam_xeye.user_parameter["pixel_calibration"];
fall back to raw pixels (scale 1.0, unit "px") if unavailable.
- Enlarge the message field from 60 to 90 px height.
Alignment script (x_ray_eye_align.py):
- Replace the hard-coded PIXEL_CALIBRATION constant with a pixel_calibration
property reading the same cam_xeye user parameter; fall back to
PIXEL_CALIBRATION_DEFAULT if unavailable.
- Fold the recurring factor of 2 into the calibration: xval_x_* come straight
from raw ROI pixels on submit, so the true scale is 0.05/113 mm/pixel.
Default is now 0.05/113 and the three /2 factors (FZP center x, height
centering, FOV) are removed. Computed physical values are unchanged.
Device config (cam_xeye_pixel_calibration.yaml):
- Add pixel_calibration userParameter (0.05/113 mm per raw ROI pixel) to
cam_xeye. Merge the userParameter block into the existing device entry.
scilog_last_scans now puts the user comment at the top of the entry and
drops the flOMNI logo attachment. number_of_scans accepts 0 to send a
comment-only entry. When fewer projection records exist than requested
(e.g. non-ptycho scans, which write no timing record), the available ones
are used and a note reports how many of the requested count were found.
At BEC session start, compare bec.active_account against the new global
var defaults_applied_for_account. On a genuine account change, interactively
offer to reset all tomo scan parameters to their defaults for the new
experiment; a client restart within the same account is a silent no-op.
Add _set_default_tomo_params() writing all 20 scan parameters via the
property setters.
process looks like a BEC client), plus a delayed (500 ms) backup
stop_devices request, defaulting to stop-all so the widget doubles as
a generic emergency stop when opened standalone from the launcher menu
The gripper routines (#GRGET/#GRPUT) run autonomously on the Galil
(thread 3); Ctrl+C previously only killed the BEC-side polling loop
while the controller kept executing, including ongoing motion.
- add FlomniSampleTransferMixin.ftransfer_abort(): dev.ftransy.stop()
(stop_devices endpoint -> device server -> XQ#STOP), wait for thread 3
to halt, then put the controller back in posmode; deliberately no
ensure_gripper_up() - recovery after an abort is manual
- wrap the mntprgs polling loops in ftransfer_get_sample/put_sample in
try/except KeyboardInterrupt -> ftransfer_abort()
- answering "No" at a confirmation point now also hard-aborts the
controller routine instead of leaving it parked in #CONFIRL
- ConsoleButtonsWidget ABORT: keep SIGINT to the client, plus a delayed
(500 ms) backup stop_devices request so the hardware stops even if
the client is hung; delay ensures the controlled client-side abort
wins the race against #STOP clearing mntprgs
Add a small ConsoleButtonsWidget (Yes/No/Abort + message label) as a
GUI alternative to console yesno() prompts during sample transfer,
docked below the live camera view.
- bec_widgets: new ConsoleButtonsWidget (csaxs_bec/bec_widgets/widgets/
console_buttons/). Yes/No write to a response property polled by the
caller; Abort sends a real SIGINT to the BEC client process (captured
via os.getppid() at construction), stopping any blocking call
(including an in-progress motor move) exactly like a console Ctrl+C.
- omny_general_tools: add OMNYTools.gui_yesno(), a GUI-backed
alternative to yesno() with the same message/default/autoconfirm
semantics, polling the widget's response instead of blocking on
input(). Not yet used as a general yesno() replacement.
- gui_tools: flomnigui_show_cameras() now also opens the console widget
docked below the two camera views (set_layout_ratios for relative
sizing, since dock_area.new() has no pixel width/height kwarg).
flomnigui_show_gui() now passes an explicit window geometry, right-
aligned on a 2560x1440 screen.
- flomni: add ftransfer_confirm_dialog(), which uses the GUI console
when available (falling back to the plain CLI yesno() otherwise) and
wire it into ftransfer_confirm()'s per-step "All OK? Continue?"
prompt during sample transfer. Other yesno() call sites (stage-in
flight-tube check, gripper-move stage-out check) intentionally left
on the CLI for now.
Known issue: requested window height in flomnigui_show_gui() is not
taking effect as expected at startup; needs follow-up.
Passing -1 stows the sample currently in the sample stage into a free
tray slot without mounting a replacement, matching the old control
system's sample_change(-1) behavior. Existing swap-path logic is
unchanged.
Add collect_empty_frames(), which acquires 10 flat-field frames at
angle 0 with fsamx shifted out of the beam by fovx/2 (opposite the
normal alignment x-offset). Called once at the start of a new
tomo_scan() (not on resume). Frames are excluded from the ptycho
reconstruction queue and logged to tomography_scannumbers.txt with
subtomo_number=0.
Expose the ConstEmitter runtime constants through the high-level flomni
interface, alongside the existing laser_tracker_* methods, and add an
interactive tweak tool for the two tracking target positions.
New methods on FlomniSampleTransferMixin (thin wrappers delegating to
dev.rtx.controller, same pattern as laser_tracker_show_all):
laser_parameters_show_all()
laser_parameters_set_targety(val)
laser_parameters_set_targetz(val)
laser_parameters_set_intensity_threshold_laser(val)
laser_parameters_set_psd_intensity_threshold_tracking_low(val)
laser_tweak(): interactive 2D raw-terminal loop for the two tracking targets,
modeled on OMNYTools.tweak_cursor.
left/right : target y -/+ (fixed 0.01 step, absolute set of current +/- step)
up/down : target z +/-
s : return both targets to their launch positions
q : quit (terminal state restored in finally)
On launch and after every change it prints the current y/z targets and the
fzp x interferometer signal (read_ssi_interferometer channel 1), so the signal
response can be watched while tweaking.
termios/tty/fcntl/sys are imported locally in laser_tweak to avoid touching
module-level imports. Additive change; no existing behaviour modified. Requires
the ConstEmitter emitter_* methods on RtFlomniController.
Replace ~44 per-slot blocking device reads per poll with a single bulk
flomni_samples.read(), and add change-detection so cells only repaint
when their state actually changes. The old per-slot accessors stalled
the GUI event loop every 2s; steady-state polling now does no UI work.
Writes invalidate the changed slot's cache so local edits still repaint
immediately.
GUI for ftransfer_show / ftransfer_modify. Displays the
sample stage (0), gripper (100) and magazine slots 1-20 in a 4x5 grid
matching the CLI layout. Right-click per slot corrects the records
(new / rename / clear), each action confirmed by its own dialog and
written immediately. Bookkeeping only: writes flomni_samples directly
(mirroring flomni_modify_storage_non_interactive), never moves hardware.
Guarded on fsamroy; OMNY shows a not-implemented placeholder.
Expose the flOMNI ConstEmitter runtime constants (served over the control-loop
TCP server, command letter 'e') to BEC users. These were previously baked into
Orchestra module parameter files; they can now be read and set live.
New RtFlomniController methods (all added to USER_ACCESS):
emitter_get() -> dict of the four values
emitter_show_all() -> PrettyTable printout
emitter_set_tracking_target_y(val) -> "ey<val>"
emitter_set_tracking_target_z(val) -> "ez<val>"
emitter_set_intensity_threshold_laser(val) -> "et<val>"
emitter_set_psd_intensity_threshold_tracking_low(val) -> "el<val>"
emitter_get issues "es" and parses the CSV reply
(targetpos_tracking_y, targetpos_tracking_z, intensity_threshold_laser,
PSD_intensity_threshold_tracking_low), same pattern as the Ts/sr readouts.
Setters use socket_put with a fixed %.4f value, same pattern as the pa
setpoint command; they are fire-and-forget (the server does not ack sets).
The rotation-loop laser threshold (intensity_threshold_rot_laser) is a startup
constant on the server side and is intentionally neither read back nor settable
here.
Named methods were chosen over a single opaque command to match the existing
laser_tracker_* / feedback_* convention and to self-document each value.
Requires the corresponding flOMNI control-loop change (ConstEmitter module +
'e' command in CommunicationServer). Additive change; no existing behaviour
modified.
Expose the ConstEmitter runtime constants through the high-level flomni
interface, alongside the existing laser_tracker_* methods, and add an
interactive tweak tool for the two tracking target positions.
New methods on FlomniSampleTransferMixin (thin wrappers delegating to
dev.rtx.controller, same pattern as laser_tracker_show_all):
laser_parameters_show_all()
laser_parameters_set_targety(val)
laser_parameters_set_targetz(val)
laser_parameters_set_intensity_threshold_laser(val)
laser_parameters_set_psd_intensity_threshold_tracking_low(val)
laser_tweak(): interactive 2D raw-terminal loop for the two tracking targets,
modeled on OMNYTools.tweak_cursor.
left/right : target y -/+ (fixed 0.01 step, absolute set of current +/- step)
up/down : target z +/-
s : return both targets to their launch positions
q : quit (terminal state restored in finally)
On launch and after every change it prints the current y/z targets and the
fzp x interferometer signal (read_ssi_interferometer channel 1), so the signal
response can be watched while tweaking.
termios/tty/fcntl/sys are imported locally in laser_tweak to avoid touching
module-level imports. Additive change; no existing behaviour modified. Requires
the ConstEmitter emitter_* methods on RtFlomniController.
A block is external and self-resolving, so the immediate "measurement stopped,
confirm" warning chime was misleading there - the user cannot act on it and
should just wait. Suppress startWarning when the destination status is blocked;
the blocked track still handles it (silent until the 60-min blockedChime, then
hourly). scanning->idle (success tone) and scanning->other (warning tone) are
unchanged. Help text updated.
- Audio: a normal finish (scanning -> idle) now plays a rising success
arpeggio (C5-E5-G5) instead of the falling warning chime, so a completed
measurement is audibly distinct from a stop to any other state (which keeps
the falling 660->440 warning). startWarning(finished) selects the chime for
both the initial tone and the 30s repeats; the Watch LED text reads
"Measurement finished" vs "Measurement stopped" accordingly. Help text
updated.
- Layout: body uses min-height:100dvh (with 100vh fallback) so the page no
longer extends below the visible viewport on mobile, where iOS 100vh counts
the retracted-toolbar height and leaves empty scroll room at the bottom.
The instrument-details pane showed only a hand-built 6-row settings summary,
far less than the tomo queue shows per job, and nothing useful for a tomo
started outside the queue.
- Flomni _collect_setup_data now returns current_params: the tomo parameters
read live from global vars, keyed by the same names the queue stores in
job.params (_CURRENT_PARAM_KEYS, matching TQ_PARAM_DISPLAY). Values left raw;
the page formats them. Replaces the old settings dict.
- Extract the queue's param-table builder into a shared buildParamRows() JS
helper (carries the computed Projections row), used by both the queue and the
new instrument 'Current measurement' section, so they can't drift.
- renderInstrument renders current_params via buildParamRows (Sample name row
first); card hides only when there are neither params nor temperatures.
- Base _collect_setup_data contract updated: settings -> current_params.
umvr_fsamy_tracked/umv_fsamy_tracked require feedback OFF but did not
enforce it. Add an _internal flag; for user/CLI calls, warn that feedback
must be off (active alignment may be lost), prompt (default yes), and
disable feedback on confirm. Internal callers pass _internal=True since
they already manage the feedback lifecycle (ftransfer_flomni_stage_out,
x_ray_eye_align height-centering and mvy jog).
Match the deleted-widget detection used by all other flomniGuiTools
methods. The previous _flomnigui_check_attribute_not_exists path relied
on hasattr(self.gui.flomni, "Image"/"Image_0"), which returns stale/
mismatched results when docks are recreated, leaving an empty window
after a user closed the GUI mid sample-transfer. _is_deleted() checks
registry membership and reliably triggers a rebuild.
renderTomoQueue auto-opened the running job whenever the open-state snapshot
was empty, so collapsing the only open job (the running one) made the snapshot
empty and re-opened it on the next refresh. Open-state was also keyed by
positional index, which mis-assigns the flag when jobs are added/removed/
reordered.
- Snapshot open jobs by stable key (added_at|label) via a data-key attribute
instead of positional index.
- Auto-open a running job only once, on first appearance, tracked in
window.__tqAutoOpened; afterwards honor the DOM snapshot so a manual collapse
sticks. Prune the set when jobs disappear.
A block interrupts the running scan, clearing active_request_block, so
the old _derive_status() (which only returned 'blocked' inside the
queue_has_active_scan branch) fell through to 'idle' with the blocked
LED off, despite watched beamline states being out of spec.
- _derive_status: return 'blocked' on beamline_blocking OR queue_locks,
independent of active scan; only fresh-heartbeat 'scanning' outranks it.
- _cycle: beamline_blocking = enabled is True AND any(state mismatched).
Gated on enabled so a disabled/unknown interlock with an out-of-spec
state does not raise BLOCKED. Also counted as activity so the idle
clock restarts once cleared.
- beamline-states card summary updated in lock-step: mismatched states are
only called "currently blocking" when enabled, else "out of spec
(interlock disabled/unknown, not blocking)", so pill and card can't
disagree.
- status-detail JS: describe blocking beamline states when no explicit
queue lock is present. Update help text.
webpage_generator: report blocked on interlock even when scan is interrupted
- Add HAS_TOMO_QUEUE and TOMO_TYPES capability flags to
WebpageGeneratorBase, defaulting to flomni's current behavior
(type1 grid-8, type2/3 golden-capped) so this is a no-op for flomni.
- Gate the tomo_queue global-var read in _cycle() behind
HAS_TOMO_QUEUE; unaffected: queue_status/queue_locks/beamline_states,
which come from BEC's own primary scan queue and stay common to
all setups.
- _render_html() now conditionally emits the 'Tomo queue' card and
its DEFAULT_ORDER slot, and drives the projection-count formula
from a TOMO_TYPES JSON blob (generic calcProjections()) instead of
a hardcoded per-instrument JS branch.
- LamniWebpageGenerator: HAS_TOMO_QUEUE=False, TOMO_TYPES with
2-subtomo and 8-subtomo equally_spaced_grid entries (placeholder
keys pending real tomo_type values from the LamNI producer side).
A block interrupts the running scan, clearing active_request_block, so
the old _derive_status() (which only returned 'blocked' inside the
queue_has_active_scan branch) fell through to 'idle' with the blocked
LED off, despite watched beamline states being out of spec.
- _derive_status: return 'blocked' on beamline_blocking OR queue_locks,
independent of active scan; only fresh-heartbeat 'scanning' outranks it.
- _cycle: compute beamline_blocking = any(state mismatched), defined
identically to the beamline-states card so pill and card can't disagree;
also count it as activity so the idle clock restarts once cleared.
- status-detail JS: describe blocking beamline states when no explicit
queue lock is present. Update help text."
fosaz_info previously only reported remaining collision clearance for the
live fosaz position, giving no indication of clearance once OSA is moved
back to its defined IN position if foptz has shifted while OSA was OUT.
Now compares live fosaz against fosaz_in (10 um tolerance):
- if live fosaz is further IN than nominal (closer to collision), warn and
show current remaining space (the number that matters right now)
- if OSA is OUT/away from IN, no warning, but also report remaining space
at the IN position using current foptz, as a heads-up before moving OSA in
- Add HAS_TOMO_QUEUE and TOMO_TYPES capability flags to
WebpageGeneratorBase, defaulting to flomni's current behavior
(type1 grid-8, type2/3 golden-capped) so this is a no-op for flomni.
- Gate the tomo_queue global-var read in _cycle() behind
HAS_TOMO_QUEUE; unaffected: queue_status/queue_locks/beamline_states,
which come from BEC's own primary scan queue and stay common to
all setups.
- _render_html() now conditionally emits the 'Tomo queue' card and
its DEFAULT_ORDER slot, and drives the projection-count formula
from a TOMO_TYPES JSON blob (generic calcProjections()) instead of
a hardcoded per-instrument JS branch.
- LamniWebpageGenerator: HAS_TOMO_QUEUE=False, TOMO_TYPES with
2-subtomo and 8-subtomo equally_spaced_grid entries (placeholder
keys pending real tomo_type values from the LamNI producer side).
Add JSONL timing logs under ~/data/raw/logs/timing_statistics/ for
building a scan-time prediction model. Times each projection in
_tomo_scan_at_angle (final successful attempt only, retries excluded)
and each tomogram in tomo_scan, capturing raw scan parameters plus
elapsed/idle/active durations.
tomo_scan_projection always runs a fermat scan; warn and confirm when
called directly with single_point_instead_of_fermat_scan set, pointing
to tomo_acquire_at_angle instead. Internal callers pass _internal=True
to skip the prompt.