Feat/flomni cont panda data #321

Merged
holler merged 7 commits from feat/flomni_cont_panda_data into main 2026-09-15 15:34:22 +02:00
9 changed files with 2456 additions and 2 deletions
@@ -646,6 +646,24 @@ calculated_signal:
############################################################
#################### OMNY Pandabox #########################
############################################################
# Mode A (legacy per-gate aggregate acquisition) and Mode B (continuous free-running
# raw-sample acquisition, see docs/developer/panda_box_free_running_setup.md) need different
# PandA hardware layouts and can't run simultaneously (see that doc's "Open question"). Only
# one of the two devices below should be active at a time, matching whichever layout is
# currently loaded on the PandA.
#
# NOTE 2026-09-15: setting enabled: false on omny_panda_continuous was not sufficient by
# itself to stop it being active in the running BEC session (both devices ended up
# connected/active simultaneously against the same physical PandA at once) - a device that
# was already connected apparently doesn't get disconnected just by disabling it in a config
# reload. Commenting the block out is the reliable way to guarantee it's not loaded; do the
# same for omny_panda when switching to Mode B, and don't rely on enabled: false alone
# without also confirming (e.g. restarting the device server) that the other device has
# actually dropped its connection.
#
# Currently: Mode B active for speed testing beyond the initial 100 Hz, Mode A commented out
# (both modes confirmed working end-to-end 2026-09-15; this swap 2026-09-15 is for Mode B
# speed testing specifically).
# omny_panda:
# readoutPriority: async
# deviceClass: csaxs_bec.devices.panda_box.panda_box_omny.PandaBoxOMNY
@@ -676,3 +694,31 @@ calculated_signal:
# softwareTrigger: false
# deviceTags:
# - ptycho_flomni
omny_panda_continuous:
readoutPriority: async
deviceClass: csaxs_bec.devices.panda_box.panda_box_omny.PandaBoxOMNY
deviceConfig:
host: omny-panda.psi.ch
raw_stream_mode: true
signal_alias:
FMC_IN.VAL1.Value: cap_voltage_fzp_y
FMC_IN.VAL2.Value: cap_voltage_fzp_x
INENC1.VAL.Value: interf_st_fzp_y
INENC2.VAL.Value: interf_st_fzp_x
INENC3.VAL.Value: interf_st_rotz
INENC4.VAL.Value: interf_st_rotx
PCAP.GATE_DURATION.Value: pcap_gate_duration_value
# TTLIN1 (detector trigger) feeds both blocks below - confirmed 2026-09-15 against the
# omny-panda hardware, see docs/developer/panda_box_free_running_setup.md. PCAP.BITS0
# is a shared 32-bit word; PandaBoxOMNY masks it to bit 0 (TTLIN1.VAL) before
# publishing gate_detector_active. COUNTER1 counts TTLIN1's falling edge, i.e. one
# increment per completed exposure; it also doubles as the on_complete signal. Confirmed
# working end-to-end 2026-09-15; now under speed testing beyond the initial 100 Hz.
PCAP.BITS0.Value: gate_detector_active
COUNTER1.OUT.Value: frame_counter
enabled: true
readOnly: false
softwareTrigger: false
deviceTags:
- ptycho_flomni
@@ -0,0 +1,876 @@
OUTENC1.DATA.DELAY=0
OUTENC2.DATA.DELAY=0
OUTENC3.DATA.DELAY=0
OUTENC4.DATA.DELAY=0
OUTENC1.A.DELAY=0
OUTENC2.A.DELAY=0
OUTENC3.A.DELAY=0
OUTENC4.A.DELAY=0
OUTENC1.QPERIOD.UNITS=s
OUTENC2.QPERIOD.UNITS=s
OUTENC3.QPERIOD.UNITS=s
OUTENC4.QPERIOD.UNITS=s
OUTENC1.Z.DELAY=0
OUTENC2.Z.DELAY=0
OUTENC3.Z.DELAY=0
OUTENC4.Z.DELAY=0
OUTENC1.B.DELAY=0
OUTENC2.B.DELAY=0
OUTENC3.B.DELAY=0
OUTENC4.B.DELAY=0
OUTENC1.ENABLE.DELAY=0
OUTENC2.ENABLE.DELAY=0
OUTENC3.ENABLE.DELAY=0
OUTENC4.ENABLE.DELAY=0
PCOMP1.ENABLE.DELAY=0
PCOMP2.ENABLE.DELAY=0
TTLOUT1.VAL.DELAY=0
TTLOUT2.VAL.DELAY=0
TTLOUT3.VAL.DELAY=0
TTLOUT4.VAL.DELAY=0
TTLOUT5.VAL.DELAY=0
TTLOUT6.VAL.DELAY=0
TTLOUT7.VAL.DELAY=0
TTLOUT8.VAL.DELAY=0
TTLOUT9.VAL.DELAY=0
TTLOUT10.VAL.DELAY=0
PCAP.TS_END.CAPTURE=No
PCAP.GATE.DELAY=1
PCAP.TS_START.CAPTURE=No
PCAP.ENABLE.DELAY=0
PCAP.BITS2.CAPTURE=No
PCAP.BITS0.CAPTURE=No
PCAP.BITS3.CAPTURE=No
PCAP.BITS1.CAPTURE=No
PCAP.GATE_DURATION.CAPTURE=Value
PCAP.TS_TRIG.CAPTURE=No
PCAP.TRIG.DELAY=1
SFP3_SYNC_IN.POS3.UNITS=
SFP3_SYNC_IN.POS3.OFFSET=0
SFP3_SYNC_IN.POS3.SCALE=1
SFP3_SYNC_IN.POS3.CAPTURE=No
SFP3_SYNC_IN.POS4.UNITS=
SFP3_SYNC_IN.POS4.OFFSET=0
SFP3_SYNC_IN.POS4.SCALE=1
SFP3_SYNC_IN.POS4.CAPTURE=No
SFP3_SYNC_IN.POS2.UNITS=
SFP3_SYNC_IN.POS2.OFFSET=0
SFP3_SYNC_IN.POS2.SCALE=1
SFP3_SYNC_IN.POS2.CAPTURE=No
SFP3_SYNC_IN.POS1.UNITS=
SFP3_SYNC_IN.POS1.OFFSET=0
SFP3_SYNC_IN.POS1.SCALE=1
SFP3_SYNC_IN.POS1.CAPTURE=No
DIV1.INP.DELAY=0
DIV2.INP.DELAY=0
DIV1.ENABLE.DELAY=0
DIV2.ENABLE.DELAY=0
INENC1.CLK.DELAY=0
INENC2.CLK.DELAY=0
INENC3.CLK.DELAY=0
INENC4.CLK.DELAY=0
INENC1.VAL.UNITS=
INENC2.VAL.UNITS=
INENC3.VAL.UNITS=
INENC4.VAL.UNITS=
INENC1.VAL.OFFSET=0
INENC2.VAL.OFFSET=0
INENC3.VAL.OFFSET=0
INENC4.VAL.OFFSET=0
INENC1.VAL.SCALE=1
INENC2.VAL.SCALE=1
INENC3.VAL.SCALE=1
INENC4.VAL.SCALE=1
INENC1.VAL.CAPTURE=Min Max Mean
INENC2.VAL.CAPTURE=Min Max Mean
INENC3.VAL.CAPTURE=Min Max Mean
INENC4.VAL.CAPTURE=Min Max Mean
INENC1.CLK_PERIOD.UNITS=s
INENC2.CLK_PERIOD.UNITS=s
INENC3.CLK_PERIOD.UNITS=s
INENC4.CLK_PERIOD.UNITS=s
INENC1.FRAME_PERIOD.UNITS=s
INENC2.FRAME_PERIOD.UNITS=s
INENC3.FRAME_PERIOD.UNITS=s
INENC4.FRAME_PERIOD.UNITS=s
SFP3_SYNC_OUT.BIT8.DELAY=0
SFP3_SYNC_OUT.BIT1.DELAY=0
SFP3_SYNC_OUT.BIT3.DELAY=0
SFP3_SYNC_OUT.BIT2.DELAY=0
SFP3_SYNC_OUT.BIT5.DELAY=0
SFP3_SYNC_OUT.BIT4.DELAY=0
SFP3_SYNC_OUT.BIT7.DELAY=0
SFP3_SYNC_OUT.BIT6.DELAY=0
SEQ1.ENABLE.DELAY=0
SEQ2.ENABLE.DELAY=0
SEQ1.PRESCALE.UNITS=s
SEQ2.PRESCALE.UNITS=s
SEQ1.BITA.DELAY=0
SEQ2.BITA.DELAY=0
SEQ1.BITC.DELAY=0
SEQ2.BITC.DELAY=0
SEQ1.BITB.DELAY=0
SEQ2.BITB.DELAY=0
SEQ1.TABLE.QUEUED_LINES=0
SEQ2.TABLE.QUEUED_LINES=0
SRGATE1.SET.DELAY=0
SRGATE2.SET.DELAY=0
SRGATE3.SET.DELAY=0
SRGATE4.SET.DELAY=0
SRGATE1.ENABLE.DELAY=0
SRGATE2.ENABLE.DELAY=0
SRGATE3.ENABLE.DELAY=0
SRGATE4.ENABLE.DELAY=0
SRGATE1.RST.DELAY=0
SRGATE2.RST.DELAY=0
SRGATE3.RST.DELAY=0
SRGATE4.RST.DELAY=0
LUT1.INPB.DELAY=0
LUT2.INPB.DELAY=0
LUT3.INPB.DELAY=0
LUT4.INPB.DELAY=0
LUT5.INPB.DELAY=0
LUT6.INPB.DELAY=0
LUT7.INPB.DELAY=0
LUT8.INPB.DELAY=0
LUT1.INPC.DELAY=0
LUT2.INPC.DELAY=0
LUT3.INPC.DELAY=0
LUT4.INPC.DELAY=0
LUT5.INPC.DELAY=0
LUT6.INPC.DELAY=0
LUT7.INPC.DELAY=0
LUT8.INPC.DELAY=0
LUT1.INPA.DELAY=0
LUT2.INPA.DELAY=0
LUT3.INPA.DELAY=0
LUT4.INPA.DELAY=0
LUT5.INPA.DELAY=0
LUT6.INPA.DELAY=0
LUT7.INPA.DELAY=0
LUT8.INPA.DELAY=0
LUT1.INPD.DELAY=0
LUT2.INPD.DELAY=0
LUT3.INPD.DELAY=0
LUT4.INPD.DELAY=0
LUT5.INPD.DELAY=0
LUT6.INPD.DELAY=0
LUT7.INPD.DELAY=0
LUT8.INPD.DELAY=0
LUT1.INPE.DELAY=0
LUT2.INPE.DELAY=0
LUT3.INPE.DELAY=0
LUT4.INPE.DELAY=0
LUT5.INPE.DELAY=0
LUT6.INPE.DELAY=0
LUT7.INPE.DELAY=0
LUT8.INPE.DELAY=0
CALC1.OUT.UNITS=
CALC2.OUT.UNITS=
CALC1.OUT.OFFSET=0
CALC2.OUT.OFFSET=0
CALC1.OUT.SCALE=1
CALC2.OUT.SCALE=1
CALC1.OUT.CAPTURE=No
CALC2.OUT.CAPTURE=No
LVDSOUT1.VAL.DELAY=0
LVDSOUT2.VAL.DELAY=0
CLOCK1.ENABLE.DELAY=0
CLOCK2.ENABLE.DELAY=0
CLOCK1.PERIOD.UNITS=s
CLOCK2.PERIOD.UNITS=s
CLOCK1.WIDTH.UNITS=s
CLOCK2.WIDTH.UNITS=us
COUNTER1.OUT.UNITS=
COUNTER2.OUT.UNITS=
COUNTER3.OUT.UNITS=
COUNTER4.OUT.UNITS=
COUNTER5.OUT.UNITS=
COUNTER6.OUT.UNITS=
COUNTER7.OUT.UNITS=
COUNTER8.OUT.UNITS=
COUNTER1.OUT.OFFSET=0
COUNTER2.OUT.OFFSET=0
COUNTER3.OUT.OFFSET=0
COUNTER4.OUT.OFFSET=0
COUNTER5.OUT.OFFSET=0
COUNTER6.OUT.OFFSET=0
COUNTER7.OUT.OFFSET=0
COUNTER8.OUT.OFFSET=0
COUNTER1.OUT.SCALE=1
COUNTER2.OUT.SCALE=1
COUNTER3.OUT.SCALE=1
COUNTER4.OUT.SCALE=1
COUNTER5.OUT.SCALE=1
COUNTER6.OUT.SCALE=1
COUNTER7.OUT.SCALE=1
COUNTER8.OUT.SCALE=1
COUNTER1.OUT.CAPTURE=No
COUNTER2.OUT.CAPTURE=No
COUNTER3.OUT.CAPTURE=No
COUNTER4.OUT.CAPTURE=No
COUNTER5.OUT.CAPTURE=No
COUNTER6.OUT.CAPTURE=No
COUNTER7.OUT.CAPTURE=No
COUNTER8.OUT.CAPTURE=No
COUNTER1.DIR.DELAY=0
COUNTER2.DIR.DELAY=0
COUNTER3.DIR.DELAY=0
COUNTER4.DIR.DELAY=0
COUNTER5.DIR.DELAY=0
COUNTER6.DIR.DELAY=0
COUNTER7.DIR.DELAY=0
COUNTER8.DIR.DELAY=0
COUNTER1.ENABLE.DELAY=0
COUNTER2.ENABLE.DELAY=0
COUNTER3.ENABLE.DELAY=0
COUNTER4.ENABLE.DELAY=0
COUNTER5.ENABLE.DELAY=0
COUNTER6.ENABLE.DELAY=0
COUNTER7.ENABLE.DELAY=0
COUNTER8.ENABLE.DELAY=0
COUNTER1.TRIG.DELAY=0
COUNTER2.TRIG.DELAY=0
COUNTER3.TRIG.DELAY=0
COUNTER4.TRIG.DELAY=0
COUNTER5.TRIG.DELAY=0
COUNTER6.TRIG.DELAY=0
COUNTER7.TRIG.DELAY=0
COUNTER8.TRIG.DELAY=0
PULSE1.ENABLE.DELAY=0
PULSE2.ENABLE.DELAY=0
PULSE3.ENABLE.DELAY=0
PULSE4.ENABLE.DELAY=0
PULSE1.DELAY.UNITS=s
PULSE2.DELAY.UNITS=s
PULSE3.DELAY.UNITS=s
PULSE4.DELAY.UNITS=s
PULSE1.TRIG.DELAY=0
PULSE2.TRIG.DELAY=0
PULSE3.TRIG.DELAY=0
PULSE4.TRIG.DELAY=0
PULSE1.WIDTH.UNITS=s
PULSE2.WIDTH.UNITS=s
PULSE3.WIDTH.UNITS=s
PULSE4.WIDTH.UNITS=s
PULSE1.STEP.UNITS=s
PULSE2.STEP.UNITS=s
PULSE3.STEP.UNITS=s
PULSE4.STEP.UNITS=s
FILTER1.OUT.UNITS=
FILTER2.OUT.UNITS=
FILTER1.OUT.OFFSET=0
FILTER2.OUT.OFFSET=0
FILTER1.OUT.SCALE=1
FILTER2.OUT.SCALE=1
FILTER1.OUT.CAPTURE=No
FILTER2.OUT.CAPTURE=No
FILTER1.ENABLE.DELAY=0
FILTER2.ENABLE.DELAY=0
FILTER1.TRIG.DELAY=0
FILTER2.TRIG.DELAY=0
FMC_IN.VAL8.UNITS=V
FMC_IN.VAL8.OFFSET=0
FMC_IN.VAL8.SCALE=4.65661287e-09
FMC_IN.VAL8.CAPTURE=No
FMC_IN.VAL1.UNITS=V
FMC_IN.VAL1.OFFSET=0
FMC_IN.VAL1.SCALE=4.65661287e-09
FMC_IN.VAL1.CAPTURE=Min Max Mean
FMC_IN.VAL3.UNITS=V
FMC_IN.VAL3.OFFSET=0
FMC_IN.VAL3.SCALE=4.65661287e-09
FMC_IN.VAL3.CAPTURE=No
FMC_IN.VAL2.UNITS=V
FMC_IN.VAL2.OFFSET=0
FMC_IN.VAL2.SCALE=4.65661287e-09
FMC_IN.VAL2.CAPTURE=Min Max Mean
FMC_IN.VAL5.UNITS=V
FMC_IN.VAL5.OFFSET=0
FMC_IN.VAL5.SCALE=4.65661287e-09
FMC_IN.VAL5.CAPTURE=No
FMC_IN.VAL4.UNITS=V
FMC_IN.VAL4.OFFSET=0
FMC_IN.VAL4.SCALE=4.65661287e-09
FMC_IN.VAL4.CAPTURE=No
FMC_IN.VAL7.UNITS=V
FMC_IN.VAL7.OFFSET=0
FMC_IN.VAL7.SCALE=4.65661287e-09
FMC_IN.VAL7.CAPTURE=No
FMC_IN.VAL6.UNITS=V
FMC_IN.VAL6.OFFSET=0
FMC_IN.VAL6.SCALE=4.65661287e-09
FMC_IN.VAL6.CAPTURE=No
PGEN1.OUT.UNITS=
PGEN2.OUT.UNITS=
PGEN1.OUT.OFFSET=0
PGEN2.OUT.OFFSET=0
PGEN1.OUT.SCALE=1
PGEN2.OUT.SCALE=1
PGEN1.OUT.CAPTURE=No
PGEN2.OUT.CAPTURE=No
PGEN1.ENABLE.DELAY=0
PGEN2.ENABLE.DELAY=0
PGEN1.TABLE.QUEUED_LINES=0
PGEN2.TABLE.QUEUED_LINES=0
PGEN1.TRIG.DELAY=0
PGEN2.TRIG.DELAY=0
TTLIN1.TERM=High-Z
TTLIN2.TERM=High-Z
TTLIN3.TERM=High-Z
TTLIN4.TERM=High-Z
TTLIN5.TERM=High-Z
TTLIN6.TERM=High-Z
OUTENC1.DATA=ZERO
OUTENC2.DATA=ZERO
OUTENC3.DATA=ZERO
OUTENC4.DATA=ZERO
OUTENC1.A=ZERO
OUTENC2.A=ZERO
OUTENC3.A=ZERO
OUTENC4.A=ZERO
OUTENC1.ENCODING=Unsigned Binary
OUTENC2.ENCODING=Unsigned Binary
OUTENC3.ENCODING=Unsigned Binary
OUTENC4.ENCODING=Unsigned Binary
OUTENC1.QPERIOD=0
OUTENC2.QPERIOD=0
OUTENC3.QPERIOD=0
OUTENC4.QPERIOD=0
OUTENC1.Z=ZERO
OUTENC2.Z=ZERO
OUTENC3.Z=ZERO
OUTENC4.Z=ZERO
OUTENC1.B=ZERO
OUTENC2.B=ZERO
OUTENC3.B=ZERO
OUTENC4.B=ZERO
OUTENC1.VAL=ZERO
OUTENC2.VAL=ZERO
OUTENC3.VAL=ZERO
OUTENC4.VAL=ZERO
OUTENC1.PROTOCOL=Quadrature
OUTENC2.PROTOCOL=Quadrature
OUTENC3.PROTOCOL=Quadrature
OUTENC4.PROTOCOL=Quadrature
OUTENC1.ENABLE=ZERO
OUTENC2.ENABLE=ZERO
OUTENC3.ENABLE=ZERO
OUTENC4.ENABLE=ZERO
OUTENC1.GENERATOR_ERROR=No
OUTENC2.GENERATOR_ERROR=No
OUTENC3.GENERATOR_ERROR=No
OUTENC4.GENERATOR_ERROR=No
OUTENC1.BITS=0
OUTENC2.BITS=0
OUTENC3.BITS=0
OUTENC4.BITS=0
PCOMP1.PULSES=0
PCOMP2.PULSES=0
PCOMP1.PRE_START=0
PCOMP2.PRE_START=0
PCOMP1.ENABLE=ZERO
PCOMP2.ENABLE=ZERO
PCOMP1.DIR=Positive
PCOMP2.DIR=Positive
PCOMP1.START=0
PCOMP2.START=0
PCOMP1.WIDTH=0
PCOMP2.WIDTH=0
PCOMP1.INP=ZERO
PCOMP2.INP=ZERO
PCOMP1.RELATIVE=Absolute
PCOMP2.RELATIVE=Absolute
PCOMP1.STEP=0
PCOMP2.STEP=0
TTLOUT1.FINE_DELAY=0
TTLOUT2.FINE_DELAY=0
TTLOUT3.FINE_DELAY=0
TTLOUT4.FINE_DELAY=0
TTLOUT5.FINE_DELAY=0
TTLOUT6.FINE_DELAY=0
TTLOUT7.FINE_DELAY=0
TTLOUT8.FINE_DELAY=0
TTLOUT9.FINE_DELAY=0
TTLOUT10.FINE_DELAY=0
TTLOUT1.QUARTER_DELAY=0
TTLOUT2.QUARTER_DELAY=0
TTLOUT3.QUARTER_DELAY=0
TTLOUT4.QUARTER_DELAY=0
TTLOUT5.QUARTER_DELAY=0
TTLOUT6.QUARTER_DELAY=0
TTLOUT7.QUARTER_DELAY=0
TTLOUT8.QUARTER_DELAY=0
TTLOUT9.QUARTER_DELAY=0
TTLOUT10.QUARTER_DELAY=0
TTLOUT1.VAL=ZERO
TTLOUT2.VAL=ZERO
TTLOUT3.VAL=ZERO
TTLOUT4.VAL=ZERO
TTLOUT5.VAL=ZERO
TTLOUT6.VAL=ZERO
TTLOUT7.VAL=ZERO
TTLOUT8.VAL=ZERO
TTLOUT9.VAL=ZERO
TTLOUT10.VAL=ZERO
PCAP.GATE=TTLIN1.VAL
PCAP.ENABLE=ONE
PCAP.SHIFT_SUM=0
PCAP.TRIG_EDGE=Falling
PCAP.TRIG=TTLIN1.VAL
DIV1.DIVISOR=0
DIV2.DIVISOR=0
DIV1.FIRST_PULSE=OutN
DIV2.FIRST_PULSE=OutN
DIV1.INP=ZERO
DIV2.INP=ZERO
DIV1.ENABLE=ZERO
DIV2.ENABLE=ZERO
INENC1.ENCODING=Unsigned Binary
INENC2.ENCODING=Unsigned Binary
INENC3.ENCODING=Unsigned Binary
INENC4.ENCODING=Unsigned Binary
INENC1.CLK=ZERO
INENC2.CLK=ZERO
INENC3.CLK=ZERO
INENC4.CLK=ZERO
INENC1.MSB_DISCARD=0
INENC2.MSB_DISCARD=0
INENC3.MSB_DISCARD=0
INENC4.MSB_DISCARD=0
INENC1.LSB_DISCARD=0
INENC2.LSB_DISCARD=0
INENC3.LSB_DISCARD=0
INENC4.LSB_DISCARD=0
INENC1.CLK_SRC=Internally Generated
INENC2.CLK_SRC=Internally Generated
INENC3.CLK_SRC=Internally Generated
INENC4.CLK_SRC=Internally Generated
INENC1.PROTOCOL=ZMI
INENC2.PROTOCOL=ZMI
INENC3.PROTOCOL=ZMI
INENC4.PROTOCOL=ZMI
INENC1.RST_ON_Z=0
INENC2.RST_ON_Z=0
INENC3.RST_ON_Z=0
INENC4.RST_ON_Z=0
INENC1.CLK_PERIOD=0.2
INENC2.CLK_PERIOD=0
INENC3.CLK_PERIOD=0
INENC4.CLK_PERIOD=0
INENC1.BITS=0
INENC2.BITS=0
INENC3.BITS=0
INENC4.BITS=0
INENC1.FRAME_PERIOD=0.2
INENC2.FRAME_PERIOD=0
INENC3.FRAME_PERIOD=0
INENC4.FRAME_PERIOD=0
BITS.A=0
BITS.C=0
BITS.D=0
BITS.B=1
SFP3_SYNC_OUT.POS4=ZERO
SFP3_SYNC_OUT.POS2=ZERO
SFP3_SYNC_OUT.POS3=ZERO
SFP3_SYNC_OUT.POS1=ZERO
SFP3_SYNC_OUT.BIT8=ZERO
SFP3_SYNC_OUT.BIT1=ZERO
SFP3_SYNC_OUT.BIT3=ZERO
SFP3_SYNC_OUT.BIT2=ZERO
SFP3_SYNC_OUT.BIT5=ZERO
SFP3_SYNC_OUT.BIT4=ZERO
SFP3_SYNC_OUT.BIT7=ZERO
SFP3_SYNC_OUT.BIT6=ZERO
SEQ1.ENABLE=ZERO
SEQ2.ENABLE=ZERO
SEQ1.PRESCALE=0
SEQ2.PRESCALE=0
SEQ1.BITA=ZERO
SEQ2.BITA=ZERO
SEQ1.BITC=ZERO
SEQ2.BITC=ZERO
SEQ1.BITB=ZERO
SEQ2.BITB=ZERO
SEQ1.REPEATS=0
SEQ2.REPEATS=0
SEQ1.POSB=ZERO
SEQ2.POSB=ZERO
SEQ1.POSC=ZERO
SEQ2.POSC=ZERO
SEQ1.POSA=ZERO
SEQ2.POSA=ZERO
SYSTEM.CLOCK_SOURCE=int clock
SYSTEM.TIMESTAMP_SOURCE=None
SRGATE1.WHEN_DISABLED=Set output low
SRGATE2.WHEN_DISABLED=Set output low
SRGATE3.WHEN_DISABLED=Set output low
SRGATE4.WHEN_DISABLED=Set output low
SRGATE1.RST_EDGE=Rising
SRGATE2.RST_EDGE=Rising
SRGATE3.RST_EDGE=Rising
SRGATE4.RST_EDGE=Rising
SRGATE1.SET=ZERO
SRGATE2.SET=ZERO
SRGATE3.SET=ZERO
SRGATE4.SET=ZERO
SRGATE1.SET_EDGE=Rising
SRGATE2.SET_EDGE=Rising
SRGATE3.SET_EDGE=Rising
SRGATE4.SET_EDGE=Rising
SRGATE1.ENABLE=ZERO
SRGATE2.ENABLE=ZERO
SRGATE3.ENABLE=ZERO
SRGATE4.ENABLE=ZERO
SRGATE1.RST=ZERO
SRGATE2.RST=ZERO
SRGATE3.RST=ZERO
SRGATE4.RST=ZERO
FMC_OUT.GAIN4=5V
FMC_OUT.GAIN1=5V
FMC_OUT.GAIN3=5V
FMC_OUT.GAIN2=5V
FMC_OUT.VAL1=ZERO
FMC_OUT.VAL3=ZERO
FMC_OUT.VAL2=ZERO
FMC_OUT.VAL4=ZERO
LUT1.INPB=ZERO
LUT2.INPB=ZERO
LUT3.INPB=ZERO
LUT4.INPB=ZERO
LUT5.INPB=ZERO
LUT6.INPB=ZERO
LUT7.INPB=ZERO
LUT8.INPB=ZERO
LUT1.INPC=ZERO
LUT2.INPC=ZERO
LUT3.INPC=ZERO
LUT4.INPC=ZERO
LUT5.INPC=ZERO
LUT6.INPC=ZERO
LUT7.INPC=ZERO
LUT8.INPC=ZERO
LUT1.INPA=ZERO
LUT2.INPA=ZERO
LUT3.INPA=ZERO
LUT4.INPA=ZERO
LUT5.INPA=ZERO
LUT6.INPA=ZERO
LUT7.INPA=ZERO
LUT8.INPA=ZERO
LUT1.INPD=ZERO
LUT2.INPD=ZERO
LUT3.INPD=ZERO
LUT4.INPD=ZERO
LUT5.INPD=ZERO
LUT6.INPD=ZERO
LUT7.INPD=ZERO
LUT8.INPD=ZERO
LUT1.INPE=ZERO
LUT2.INPE=ZERO
LUT3.INPE=ZERO
LUT4.INPE=ZERO
LUT5.INPE=ZERO
LUT6.INPE=ZERO
LUT7.INPE=ZERO
LUT8.INPE=ZERO
LUT1.FUNC=0x00000000
LUT2.FUNC=0x00000000
LUT3.FUNC=0x00000000
LUT4.FUNC=0x00000000
LUT5.FUNC=0x00000000
LUT6.FUNC=0x00000000
LUT7.FUNC=0x00000000
LUT8.FUNC=0x00000000
LUT1.TYPEA=Input-Level
LUT2.TYPEA=Input-Level
LUT3.TYPEA=Input-Level
LUT4.TYPEA=Input-Level
LUT5.TYPEA=Input-Level
LUT6.TYPEA=Input-Level
LUT7.TYPEA=Input-Level
LUT8.TYPEA=Input-Level
LUT1.TYPEC=Input-Level
LUT2.TYPEC=Input-Level
LUT3.TYPEC=Input-Level
LUT4.TYPEC=Input-Level
LUT5.TYPEC=Input-Level
LUT6.TYPEC=Input-Level
LUT7.TYPEC=Input-Level
LUT8.TYPEC=Input-Level
LUT1.TYPEB=Input-Level
LUT2.TYPEB=Input-Level
LUT3.TYPEB=Input-Level
LUT4.TYPEB=Input-Level
LUT5.TYPEB=Input-Level
LUT6.TYPEB=Input-Level
LUT7.TYPEB=Input-Level
LUT8.TYPEB=Input-Level
LUT1.TYPEE=Input-Level
LUT2.TYPEE=Input-Level
LUT3.TYPEE=Input-Level
LUT4.TYPEE=Input-Level
LUT5.TYPEE=Input-Level
LUT6.TYPEE=Input-Level
LUT7.TYPEE=Input-Level
LUT8.TYPEE=Input-Level
LUT1.TYPED=Input-Level
LUT2.TYPED=Input-Level
LUT3.TYPED=Input-Level
LUT4.TYPED=Input-Level
LUT5.TYPED=Input-Level
LUT6.TYPED=Input-Level
LUT7.TYPED=Input-Level
LUT8.TYPED=Input-Level
CALC1.INPC=ZERO
CALC2.INPC=ZERO
CALC1.INPA=ZERO
CALC2.INPA=ZERO
CALC1.SHIFT=0
CALC2.SHIFT=0
CALC1.INPB=ZERO
CALC2.INPB=ZERO
CALC1.INPD=ZERO
CALC2.INPD=ZERO
CALC1.TYPEA=Value
CALC2.TYPEA=Value
CALC1.TYPEC=Value
CALC2.TYPEC=Value
CALC1.TYPEB=Value
CALC2.TYPEB=Value
CALC1.TYPED=Value
CALC2.TYPED=Value
LVDSOUT1.FINE_DELAY=0
LVDSOUT2.FINE_DELAY=0
LVDSOUT1.QUARTER_DELAY=0
LVDSOUT2.QUARTER_DELAY=0
LVDSOUT1.VAL=ZERO
LVDSOUT2.VAL=ZERO
CLOCK1.ENABLE=ZERO
CLOCK2.ENABLE=ZERO
CLOCK1.PERIOD=1
CLOCK2.PERIOD=0.2
CLOCK1.WIDTH=3e-05
CLOCK2.WIDTH=5
COUNTER1.OUT_MODE=On-Change
COUNTER2.OUT_MODE=On-Change
COUNTER3.OUT_MODE=On-Change
COUNTER4.OUT_MODE=On-Change
COUNTER5.OUT_MODE=On-Change
COUNTER6.OUT_MODE=On-Change
COUNTER7.OUT_MODE=On-Change
COUNTER8.OUT_MODE=On-Change
COUNTER1.SET=0
COUNTER2.SET=0
COUNTER3.SET=0
COUNTER4.SET=0
COUNTER5.SET=0
COUNTER6.SET=0
COUNTER7.SET=0
COUNTER8.SET=0
COUNTER1.DIR=ZERO
COUNTER2.DIR=ZERO
COUNTER3.DIR=ZERO
COUNTER4.DIR=ZERO
COUNTER5.DIR=ZERO
COUNTER6.DIR=ZERO
COUNTER7.DIR=ZERO
COUNTER8.DIR=ZERO
COUNTER1.ENABLE=PCAP.ACTIVE
COUNTER2.ENABLE=ZERO
COUNTER3.ENABLE=ZERO
COUNTER4.ENABLE=ZERO
COUNTER5.ENABLE=ZERO
COUNTER6.ENABLE=ZERO
COUNTER7.ENABLE=ZERO
COUNTER8.ENABLE=ZERO
COUNTER1.TRIG=TTLIN1.VAL
COUNTER2.TRIG=ZERO
COUNTER3.TRIG=ZERO
COUNTER4.TRIG=ZERO
COUNTER5.TRIG=ZERO
COUNTER6.TRIG=ZERO
COUNTER7.TRIG=ZERO
COUNTER8.TRIG=ZERO
COUNTER1.TRIG_EDGE=Falling
COUNTER2.TRIG_EDGE=Rising
COUNTER3.TRIG_EDGE=Rising
COUNTER4.TRIG_EDGE=Rising
COUNTER5.TRIG_EDGE=Rising
COUNTER6.TRIG_EDGE=Rising
COUNTER7.TRIG_EDGE=Rising
COUNTER8.TRIG_EDGE=Rising
COUNTER1.MIN=0
COUNTER2.MIN=0
COUNTER3.MIN=0
COUNTER4.MIN=0
COUNTER5.MIN=0
COUNTER6.MIN=0
COUNTER7.MIN=0
COUNTER8.MIN=0
COUNTER1.MAX=0
COUNTER2.MAX=0
COUNTER3.MAX=0
COUNTER4.MAX=0
COUNTER5.MAX=0
COUNTER6.MAX=0
COUNTER7.MAX=0
COUNTER8.MAX=0
COUNTER1.START=0
COUNTER2.START=0
COUNTER3.START=0
COUNTER4.START=0
COUNTER5.START=0
COUNTER6.START=0
COUNTER7.START=0
COUNTER8.START=0
COUNTER1.STEP=1
COUNTER2.STEP=1
COUNTER3.STEP=0
COUNTER4.STEP=0
COUNTER5.STEP=0
COUNTER6.STEP=0
COUNTER7.STEP=0
COUNTER8.STEP=0
PULSE1.PULSES=0
PULSE2.PULSES=0
PULSE3.PULSES=0
PULSE4.PULSES=0
PULSE1.ENABLE=ONE
PULSE2.ENABLE=ZERO
PULSE3.ENABLE=ZERO
PULSE4.ENABLE=ZERO
PULSE1.DELAY=0
PULSE2.DELAY=0.2
PULSE3.DELAY=0.3
PULSE4.DELAY=0.4
PULSE1.TRIG=ZERO
PULSE2.TRIG=ZERO
PULSE3.TRIG=ZERO
PULSE4.TRIG=ZERO
PULSE1.TRIG_EDGE=Rising
PULSE2.TRIG_EDGE=Rising
PULSE3.TRIG_EDGE=Rising
PULSE4.TRIG_EDGE=Rising
PULSE1.WIDTH=0.001
PULSE2.WIDTH=0.1
PULSE3.WIDTH=0.1
PULSE4.WIDTH=0.1
PULSE1.STEP=0
PULSE2.STEP=0
PULSE3.STEP=0
PULSE4.STEP=0
FILTER1.INP=ZERO
FILTER2.INP=ZERO
FILTER1.MODE=average
FILTER2.MODE=difference
FILTER1.ENABLE=ZERO
FILTER2.ENABLE=ZERO
FILTER1.TRIG=ZERO
FILTER2.TRIG=ZERO
FMC_IN.GAIN5=10V
FMC_IN.GAIN4=10V
FMC_IN.GAIN7=10V
FMC_IN.GAIN6=10V
FMC_IN.GAIN1=10V
FMC_IN.GAIN3=10V
FMC_IN.GAIN2=10V
FMC_IN.GAIN8=10V
PGEN1.REPEATS=0
PGEN2.REPEATS=0
PGEN1.ENABLE=ZERO
PGEN2.ENABLE=ZERO
PGEN1.TRIG=ZERO
PGEN2.TRIG=ZERO
*METADATA.LABEL_CALC1=
*METADATA.LABEL_FILTER1=
*METADATA.LABEL_CALC2=
*METADATA.LABEL_SRGATE4=
*METADATA.LABEL_FMC_IN1=
*METADATA.LABEL_TTLIN6=
*METADATA.LABEL_SRGATE1=
*METADATA.LABEL_TTLIN4=
*METADATA.LABEL_TTLIN5=
*METADATA.LABEL_TTLIN2=TTL input 2
*METADATA.LABEL_TTLIN3=
*METADATA.LABEL_CLOCK1=
*METADATA.LABEL_TTLIN1=TTL input 1
*METADATA.LABEL_PCOMP1=
*METADATA.LABEL_LUT8=
*METADATA.LABEL_BITS1=Soft inputs and constant bits
*METADATA.LABEL_COUNTER8=
*METADATA.LABEL_COUNTER7=
*METADATA.LABEL_COUNTER6=
*METADATA.LABEL_COUNTER5=
*METADATA.LABEL_COUNTER4=
*METADATA.LABEL_COUNTER3=
*METADATA.LABEL_COUNTER2=
*METADATA.LABEL_COUNTER1=
*METADATA.LABEL_TTLOUT3=TTL output 3
*METADATA.LABEL_OUTENC2=
*METADATA.LABEL_OUTENC3=
*METADATA.LABEL_SYSTEM1=System control FPGA
*METADATA.LABEL_OUTENC1=
*METADATA.LABEL_PGEN2=
*METADATA.LABEL_OUTENC4=
*METADATA.LABEL_PGEN1=
*METADATA.LABEL_LUT2=
*METADATA.LABEL_LUT3=
*METADATA.LABEL_LUT1=Lookup table 1
*METADATA.LABEL_LUT6=
*METADATA.LABEL_LUT7=
*METADATA.LABEL_LUT4=
*METADATA.LABEL_LUT5=
*METADATA.LABEL_LVDSOUT2=
*METADATA.LABEL_LVDSOUT1=
*METADATA.LABEL_SFP3_SYNC_OUT1=
*METADATA.LABEL_PULSE3=
*METADATA.LABEL_TTLOUT7=
*METADATA.LABEL_SRGATE2=
*METADATA.LABEL_LVDSIN2=
*METADATA.LABEL_LVDSIN1=
*METADATA.LABEL_SEQ1=
*METADATA.LABEL_CLOCK2=
*METADATA.LABEL_PULSE4=
*METADATA.LABEL_INENC1=
*METADATA.LABEL_INENC2=
*METADATA.LABEL_INENC3=
*METADATA.LABEL_INENC4=
*METADATA.LABEL_PULSE1=
*METADATA.LABEL_PULSE2=
*METADATA.LABEL_FILTER2=
*METADATA.LABEL_TTLOUT10=
*METADATA.LABEL_SEQ2=
*METADATA.LABEL_PCOMP2=
*METADATA.LABEL_DIV1=
*METADATA.LABEL_SRGATE3=
*METADATA.LABEL_FMC_OUT1=
*METADATA.LABEL_DIV2=
*METADATA.LABEL_SFP3_SYNC_IN1=
*METADATA.LABEL_TTLOUT8=
*METADATA.LABEL_TTLOUT9=
*METADATA.LABEL_TTLOUT6=
*METADATA.LABEL_PCAP1=Position capture control
*METADATA.LABEL_TTLOUT4=TTL output 4
*METADATA.LABEL_TTLOUT5=
*METADATA.LABEL_TTLOUT2=TTL output 2
*METADATA.DESIGN=
*METADATA.LABEL_TTLOUT1=TTL output 1
SEQ1.TABLE<B
SEQ2.TABLE<B
PGEN1.TABLE<B
PGEN2.TABLE<B
*METADATA.LAYOUT<
{"PCAP": {"x": -2.0, "y": 132.41562128067017},
"TTLIN1": {"x": -350.0, "y": -127.0},
"INENC1": {"x": 355.0, "y": -441.0},
"INENC2": {"x": 358.0, "y": -240.0},
"INENC3": {"x": 593.0, "y": -440.0},
"INENC4": {"x": 595.0, "y": -232.0},
"COUNTER1": {"x": 69.0, "y": -100.0}}
*METADATA.EXPORTS<
@@ -0,0 +1,877 @@
OUTENC1.DATA.DELAY=0
OUTENC2.DATA.DELAY=0
OUTENC3.DATA.DELAY=0
OUTENC4.DATA.DELAY=0
OUTENC1.A.DELAY=0
OUTENC2.A.DELAY=0
OUTENC3.A.DELAY=0
OUTENC4.A.DELAY=0
OUTENC1.QPERIOD.UNITS=s
OUTENC2.QPERIOD.UNITS=s
OUTENC3.QPERIOD.UNITS=s
OUTENC4.QPERIOD.UNITS=s
OUTENC1.Z.DELAY=0
OUTENC2.Z.DELAY=0
OUTENC3.Z.DELAY=0
OUTENC4.Z.DELAY=0
OUTENC1.B.DELAY=0
OUTENC2.B.DELAY=0
OUTENC3.B.DELAY=0
OUTENC4.B.DELAY=0
OUTENC1.ENABLE.DELAY=0
OUTENC2.ENABLE.DELAY=0
OUTENC3.ENABLE.DELAY=0
OUTENC4.ENABLE.DELAY=0
PCOMP1.ENABLE.DELAY=0
PCOMP2.ENABLE.DELAY=0
TTLOUT1.VAL.DELAY=0
TTLOUT2.VAL.DELAY=0
TTLOUT3.VAL.DELAY=0
TTLOUT4.VAL.DELAY=0
TTLOUT5.VAL.DELAY=0
TTLOUT6.VAL.DELAY=0
TTLOUT7.VAL.DELAY=0
TTLOUT8.VAL.DELAY=0
TTLOUT9.VAL.DELAY=0
TTLOUT10.VAL.DELAY=0
PCAP.TS_END.CAPTURE=No
PCAP.GATE.DELAY=1
PCAP.TS_START.CAPTURE=No
PCAP.ENABLE.DELAY=0
PCAP.BITS2.CAPTURE=No
PCAP.BITS0.CAPTURE=Value
PCAP.BITS3.CAPTURE=No
PCAP.BITS1.CAPTURE=No
PCAP.GATE_DURATION.CAPTURE=Value
PCAP.TS_TRIG.CAPTURE=No
PCAP.TRIG.DELAY=1
SFP3_SYNC_IN.POS3.UNITS=
SFP3_SYNC_IN.POS3.OFFSET=0
SFP3_SYNC_IN.POS3.SCALE=1
SFP3_SYNC_IN.POS3.CAPTURE=No
SFP3_SYNC_IN.POS4.UNITS=
SFP3_SYNC_IN.POS4.OFFSET=0
SFP3_SYNC_IN.POS4.SCALE=1
SFP3_SYNC_IN.POS4.CAPTURE=No
SFP3_SYNC_IN.POS2.UNITS=
SFP3_SYNC_IN.POS2.OFFSET=0
SFP3_SYNC_IN.POS2.SCALE=1
SFP3_SYNC_IN.POS2.CAPTURE=No
SFP3_SYNC_IN.POS1.UNITS=
SFP3_SYNC_IN.POS1.OFFSET=0
SFP3_SYNC_IN.POS1.SCALE=1
SFP3_SYNC_IN.POS1.CAPTURE=No
DIV1.INP.DELAY=0
DIV2.INP.DELAY=0
DIV1.ENABLE.DELAY=0
DIV2.ENABLE.DELAY=0
INENC1.CLK.DELAY=0
INENC2.CLK.DELAY=0
INENC3.CLK.DELAY=0
INENC4.CLK.DELAY=0
INENC1.VAL.UNITS=
INENC2.VAL.UNITS=
INENC3.VAL.UNITS=
INENC4.VAL.UNITS=
INENC1.VAL.OFFSET=0
INENC2.VAL.OFFSET=0
INENC3.VAL.OFFSET=0
INENC4.VAL.OFFSET=0
INENC1.VAL.SCALE=1
INENC2.VAL.SCALE=1
INENC3.VAL.SCALE=1
INENC4.VAL.SCALE=1
INENC1.VAL.CAPTURE=Value
INENC2.VAL.CAPTURE=Value
INENC3.VAL.CAPTURE=Value
INENC4.VAL.CAPTURE=Value
INENC1.CLK_PERIOD.UNITS=s
INENC2.CLK_PERIOD.UNITS=s
INENC3.CLK_PERIOD.UNITS=s
INENC4.CLK_PERIOD.UNITS=s
INENC1.FRAME_PERIOD.UNITS=s
INENC2.FRAME_PERIOD.UNITS=s
INENC3.FRAME_PERIOD.UNITS=s
INENC4.FRAME_PERIOD.UNITS=s
SFP3_SYNC_OUT.BIT8.DELAY=0
SFP3_SYNC_OUT.BIT1.DELAY=0
SFP3_SYNC_OUT.BIT3.DELAY=0
SFP3_SYNC_OUT.BIT2.DELAY=0
SFP3_SYNC_OUT.BIT5.DELAY=0
SFP3_SYNC_OUT.BIT4.DELAY=0
SFP3_SYNC_OUT.BIT7.DELAY=0
SFP3_SYNC_OUT.BIT6.DELAY=0
SEQ1.ENABLE.DELAY=0
SEQ2.ENABLE.DELAY=0
SEQ1.PRESCALE.UNITS=s
SEQ2.PRESCALE.UNITS=s
SEQ1.BITA.DELAY=0
SEQ2.BITA.DELAY=0
SEQ1.BITC.DELAY=0
SEQ2.BITC.DELAY=0
SEQ1.BITB.DELAY=0
SEQ2.BITB.DELAY=0
SEQ1.TABLE.QUEUED_LINES=0
SEQ2.TABLE.QUEUED_LINES=0
SRGATE1.SET.DELAY=0
SRGATE2.SET.DELAY=0
SRGATE3.SET.DELAY=0
SRGATE4.SET.DELAY=0
SRGATE1.ENABLE.DELAY=0
SRGATE2.ENABLE.DELAY=0
SRGATE3.ENABLE.DELAY=0
SRGATE4.ENABLE.DELAY=0
SRGATE1.RST.DELAY=0
SRGATE2.RST.DELAY=0
SRGATE3.RST.DELAY=0
SRGATE4.RST.DELAY=0
LUT1.INPB.DELAY=0
LUT2.INPB.DELAY=0
LUT3.INPB.DELAY=0
LUT4.INPB.DELAY=0
LUT5.INPB.DELAY=0
LUT6.INPB.DELAY=0
LUT7.INPB.DELAY=0
LUT8.INPB.DELAY=0
LUT1.INPC.DELAY=0
LUT2.INPC.DELAY=0
LUT3.INPC.DELAY=0
LUT4.INPC.DELAY=0
LUT5.INPC.DELAY=0
LUT6.INPC.DELAY=0
LUT7.INPC.DELAY=0
LUT8.INPC.DELAY=0
LUT1.INPA.DELAY=0
LUT2.INPA.DELAY=0
LUT3.INPA.DELAY=0
LUT4.INPA.DELAY=0
LUT5.INPA.DELAY=0
LUT6.INPA.DELAY=0
LUT7.INPA.DELAY=0
LUT8.INPA.DELAY=0
LUT1.INPD.DELAY=0
LUT2.INPD.DELAY=0
LUT3.INPD.DELAY=0
LUT4.INPD.DELAY=0
LUT5.INPD.DELAY=0
LUT6.INPD.DELAY=0
LUT7.INPD.DELAY=0
LUT8.INPD.DELAY=0
LUT1.INPE.DELAY=0
LUT2.INPE.DELAY=0
LUT3.INPE.DELAY=0
LUT4.INPE.DELAY=0
LUT5.INPE.DELAY=0
LUT6.INPE.DELAY=0
LUT7.INPE.DELAY=0
LUT8.INPE.DELAY=0
CALC1.OUT.UNITS=
CALC2.OUT.UNITS=
CALC1.OUT.OFFSET=0
CALC2.OUT.OFFSET=0
CALC1.OUT.SCALE=1
CALC2.OUT.SCALE=1
CALC1.OUT.CAPTURE=No
CALC2.OUT.CAPTURE=No
LVDSOUT1.VAL.DELAY=0
LVDSOUT2.VAL.DELAY=0
CLOCK1.ENABLE.DELAY=0
CLOCK2.ENABLE.DELAY=0
CLOCK1.PERIOD.UNITS=s
CLOCK2.PERIOD.UNITS=s
CLOCK1.WIDTH.UNITS=s
CLOCK2.WIDTH.UNITS=us
COUNTER1.OUT.UNITS=
COUNTER2.OUT.UNITS=
COUNTER3.OUT.UNITS=
COUNTER4.OUT.UNITS=
COUNTER5.OUT.UNITS=
COUNTER6.OUT.UNITS=
COUNTER7.OUT.UNITS=
COUNTER8.OUT.UNITS=
COUNTER1.OUT.OFFSET=0
COUNTER2.OUT.OFFSET=0
COUNTER3.OUT.OFFSET=0
COUNTER4.OUT.OFFSET=0
COUNTER5.OUT.OFFSET=0
COUNTER6.OUT.OFFSET=0
COUNTER7.OUT.OFFSET=0
COUNTER8.OUT.OFFSET=0
COUNTER1.OUT.SCALE=1
COUNTER2.OUT.SCALE=1
COUNTER3.OUT.SCALE=1
COUNTER4.OUT.SCALE=1
COUNTER5.OUT.SCALE=1
COUNTER6.OUT.SCALE=1
COUNTER7.OUT.SCALE=1
COUNTER8.OUT.SCALE=1
COUNTER1.OUT.CAPTURE=Value
COUNTER2.OUT.CAPTURE=No
COUNTER3.OUT.CAPTURE=No
COUNTER4.OUT.CAPTURE=No
COUNTER5.OUT.CAPTURE=No
COUNTER6.OUT.CAPTURE=No
COUNTER7.OUT.CAPTURE=No
COUNTER8.OUT.CAPTURE=No
COUNTER1.DIR.DELAY=0
COUNTER2.DIR.DELAY=0
COUNTER3.DIR.DELAY=0
COUNTER4.DIR.DELAY=0
COUNTER5.DIR.DELAY=0
COUNTER6.DIR.DELAY=0
COUNTER7.DIR.DELAY=0
COUNTER8.DIR.DELAY=0
COUNTER1.ENABLE.DELAY=0
COUNTER2.ENABLE.DELAY=0
COUNTER3.ENABLE.DELAY=0
COUNTER4.ENABLE.DELAY=0
COUNTER5.ENABLE.DELAY=0
COUNTER6.ENABLE.DELAY=0
COUNTER7.ENABLE.DELAY=0
COUNTER8.ENABLE.DELAY=0
COUNTER1.TRIG.DELAY=0
COUNTER2.TRIG.DELAY=0
COUNTER3.TRIG.DELAY=0
COUNTER4.TRIG.DELAY=0
COUNTER5.TRIG.DELAY=0
COUNTER6.TRIG.DELAY=0
COUNTER7.TRIG.DELAY=0
COUNTER8.TRIG.DELAY=0
PULSE1.ENABLE.DELAY=0
PULSE2.ENABLE.DELAY=0
PULSE3.ENABLE.DELAY=0
PULSE4.ENABLE.DELAY=0
PULSE1.DELAY.UNITS=s
PULSE2.DELAY.UNITS=s
PULSE3.DELAY.UNITS=s
PULSE4.DELAY.UNITS=s
PULSE1.TRIG.DELAY=0
PULSE2.TRIG.DELAY=0
PULSE3.TRIG.DELAY=0
PULSE4.TRIG.DELAY=0
PULSE1.WIDTH.UNITS=s
PULSE2.WIDTH.UNITS=s
PULSE3.WIDTH.UNITS=s
PULSE4.WIDTH.UNITS=s
PULSE1.STEP.UNITS=s
PULSE2.STEP.UNITS=s
PULSE3.STEP.UNITS=s
PULSE4.STEP.UNITS=s
FILTER1.OUT.UNITS=
FILTER2.OUT.UNITS=
FILTER1.OUT.OFFSET=0
FILTER2.OUT.OFFSET=0
FILTER1.OUT.SCALE=1
FILTER2.OUT.SCALE=1
FILTER1.OUT.CAPTURE=No
FILTER2.OUT.CAPTURE=No
FILTER1.ENABLE.DELAY=0
FILTER2.ENABLE.DELAY=0
FILTER1.TRIG.DELAY=0
FILTER2.TRIG.DELAY=0
FMC_IN.VAL8.UNITS=V
FMC_IN.VAL8.OFFSET=0
FMC_IN.VAL8.SCALE=4.65661287e-09
FMC_IN.VAL8.CAPTURE=No
FMC_IN.VAL1.UNITS=V
FMC_IN.VAL1.OFFSET=0
FMC_IN.VAL1.SCALE=4.65661287e-09
FMC_IN.VAL1.CAPTURE=Value
FMC_IN.VAL3.UNITS=V
FMC_IN.VAL3.OFFSET=0
FMC_IN.VAL3.SCALE=4.65661287e-09
FMC_IN.VAL3.CAPTURE=No
FMC_IN.VAL2.UNITS=V
FMC_IN.VAL2.OFFSET=0
FMC_IN.VAL2.SCALE=4.65661287e-09
FMC_IN.VAL2.CAPTURE=Value
FMC_IN.VAL5.UNITS=V
FMC_IN.VAL5.OFFSET=0
FMC_IN.VAL5.SCALE=4.65661287e-09
FMC_IN.VAL5.CAPTURE=No
FMC_IN.VAL4.UNITS=V
FMC_IN.VAL4.OFFSET=0
FMC_IN.VAL4.SCALE=4.65661287e-09
FMC_IN.VAL4.CAPTURE=No
FMC_IN.VAL7.UNITS=V
FMC_IN.VAL7.OFFSET=0
FMC_IN.VAL7.SCALE=4.65661287e-09
FMC_IN.VAL7.CAPTURE=No
FMC_IN.VAL6.UNITS=V
FMC_IN.VAL6.OFFSET=0
FMC_IN.VAL6.SCALE=4.65661287e-09
FMC_IN.VAL6.CAPTURE=No
PGEN1.OUT.UNITS=
PGEN2.OUT.UNITS=
PGEN1.OUT.OFFSET=0
PGEN2.OUT.OFFSET=0
PGEN1.OUT.SCALE=1
PGEN2.OUT.SCALE=1
PGEN1.OUT.CAPTURE=No
PGEN2.OUT.CAPTURE=No
PGEN1.ENABLE.DELAY=0
PGEN2.ENABLE.DELAY=0
PGEN1.TABLE.QUEUED_LINES=0
PGEN2.TABLE.QUEUED_LINES=0
PGEN1.TRIG.DELAY=0
PGEN2.TRIG.DELAY=0
TTLIN1.TERM=High-Z
TTLIN2.TERM=High-Z
TTLIN3.TERM=High-Z
TTLIN4.TERM=High-Z
TTLIN5.TERM=High-Z
TTLIN6.TERM=High-Z
OUTENC1.DATA=ZERO
OUTENC2.DATA=ZERO
OUTENC3.DATA=ZERO
OUTENC4.DATA=ZERO
OUTENC1.A=ZERO
OUTENC2.A=ZERO
OUTENC3.A=ZERO
OUTENC4.A=ZERO
OUTENC1.ENCODING=Unsigned Binary
OUTENC2.ENCODING=Unsigned Binary
OUTENC3.ENCODING=Unsigned Binary
OUTENC4.ENCODING=Unsigned Binary
OUTENC1.QPERIOD=0
OUTENC2.QPERIOD=0
OUTENC3.QPERIOD=0
OUTENC4.QPERIOD=0
OUTENC1.Z=ZERO
OUTENC2.Z=ZERO
OUTENC3.Z=ZERO
OUTENC4.Z=ZERO
OUTENC1.B=ZERO
OUTENC2.B=ZERO
OUTENC3.B=ZERO
OUTENC4.B=ZERO
OUTENC1.VAL=ZERO
OUTENC2.VAL=ZERO
OUTENC3.VAL=ZERO
OUTENC4.VAL=ZERO
OUTENC1.PROTOCOL=Quadrature
OUTENC2.PROTOCOL=Quadrature
OUTENC3.PROTOCOL=Quadrature
OUTENC4.PROTOCOL=Quadrature
OUTENC1.ENABLE=ZERO
OUTENC2.ENABLE=ZERO
OUTENC3.ENABLE=ZERO
OUTENC4.ENABLE=ZERO
OUTENC1.GENERATOR_ERROR=No
OUTENC2.GENERATOR_ERROR=No
OUTENC3.GENERATOR_ERROR=No
OUTENC4.GENERATOR_ERROR=No
OUTENC1.BITS=0
OUTENC2.BITS=0
OUTENC3.BITS=0
OUTENC4.BITS=0
PCOMP1.PULSES=0
PCOMP2.PULSES=0
PCOMP1.PRE_START=0
PCOMP2.PRE_START=0
PCOMP1.ENABLE=ZERO
PCOMP2.ENABLE=ZERO
PCOMP1.DIR=Positive
PCOMP2.DIR=Positive
PCOMP1.START=0
PCOMP2.START=0
PCOMP1.WIDTH=0
PCOMP2.WIDTH=0
PCOMP1.INP=ZERO
PCOMP2.INP=ZERO
PCOMP1.RELATIVE=Absolute
PCOMP2.RELATIVE=Absolute
PCOMP1.STEP=0
PCOMP2.STEP=0
TTLOUT1.FINE_DELAY=0
TTLOUT2.FINE_DELAY=0
TTLOUT3.FINE_DELAY=0
TTLOUT4.FINE_DELAY=0
TTLOUT5.FINE_DELAY=0
TTLOUT6.FINE_DELAY=0
TTLOUT7.FINE_DELAY=0
TTLOUT8.FINE_DELAY=0
TTLOUT9.FINE_DELAY=0
TTLOUT10.FINE_DELAY=0
TTLOUT1.QUARTER_DELAY=0
TTLOUT2.QUARTER_DELAY=0
TTLOUT3.QUARTER_DELAY=0
TTLOUT4.QUARTER_DELAY=0
TTLOUT5.QUARTER_DELAY=0
TTLOUT6.QUARTER_DELAY=0
TTLOUT7.QUARTER_DELAY=0
TTLOUT8.QUARTER_DELAY=0
TTLOUT9.QUARTER_DELAY=0
TTLOUT10.QUARTER_DELAY=0
TTLOUT1.VAL=ZERO
TTLOUT2.VAL=ZERO
TTLOUT3.VAL=ZERO
TTLOUT4.VAL=ZERO
TTLOUT5.VAL=ZERO
TTLOUT6.VAL=ZERO
TTLOUT7.VAL=ZERO
TTLOUT8.VAL=ZERO
TTLOUT9.VAL=ZERO
TTLOUT10.VAL=ZERO
PCAP.GATE=CLOCK1.OUT
PCAP.ENABLE=ONE
PCAP.SHIFT_SUM=0
PCAP.TRIG_EDGE=Falling
PCAP.TRIG=CLOCK1.OUT
DIV1.DIVISOR=0
DIV2.DIVISOR=0
DIV1.FIRST_PULSE=OutN
DIV2.FIRST_PULSE=OutN
DIV1.INP=ZERO
DIV2.INP=ZERO
DIV1.ENABLE=ZERO
DIV2.ENABLE=ZERO
INENC1.ENCODING=Unsigned Binary
INENC2.ENCODING=Unsigned Binary
INENC3.ENCODING=Unsigned Binary
INENC4.ENCODING=Unsigned Binary
INENC1.CLK=ZERO
INENC2.CLK=ZERO
INENC3.CLK=ZERO
INENC4.CLK=ZERO
INENC1.MSB_DISCARD=0
INENC2.MSB_DISCARD=0
INENC3.MSB_DISCARD=0
INENC4.MSB_DISCARD=0
INENC1.LSB_DISCARD=0
INENC2.LSB_DISCARD=0
INENC3.LSB_DISCARD=0
INENC4.LSB_DISCARD=0
INENC1.CLK_SRC=Internally Generated
INENC2.CLK_SRC=Internally Generated
INENC3.CLK_SRC=Internally Generated
INENC4.CLK_SRC=Internally Generated
INENC1.PROTOCOL=ZMI
INENC2.PROTOCOL=ZMI
INENC3.PROTOCOL=ZMI
INENC4.PROTOCOL=ZMI
INENC1.RST_ON_Z=0
INENC2.RST_ON_Z=0
INENC3.RST_ON_Z=0
INENC4.RST_ON_Z=0
INENC1.CLK_PERIOD=0.2
INENC2.CLK_PERIOD=0
INENC3.CLK_PERIOD=0
INENC4.CLK_PERIOD=0
INENC1.BITS=0
INENC2.BITS=0
INENC3.BITS=0
INENC4.BITS=0
INENC1.FRAME_PERIOD=0.2
INENC2.FRAME_PERIOD=0
INENC3.FRAME_PERIOD=0
INENC4.FRAME_PERIOD=0
BITS.A=0
BITS.C=0
BITS.D=0
BITS.B=1
SFP3_SYNC_OUT.POS4=ZERO
SFP3_SYNC_OUT.POS2=ZERO
SFP3_SYNC_OUT.POS3=ZERO
SFP3_SYNC_OUT.POS1=ZERO
SFP3_SYNC_OUT.BIT8=ZERO
SFP3_SYNC_OUT.BIT1=ZERO
SFP3_SYNC_OUT.BIT3=ZERO
SFP3_SYNC_OUT.BIT2=ZERO
SFP3_SYNC_OUT.BIT5=ZERO
SFP3_SYNC_OUT.BIT4=ZERO
SFP3_SYNC_OUT.BIT7=ZERO
SFP3_SYNC_OUT.BIT6=ZERO
SEQ1.ENABLE=ZERO
SEQ2.ENABLE=ZERO
SEQ1.PRESCALE=0
SEQ2.PRESCALE=0
SEQ1.BITA=ZERO
SEQ2.BITA=ZERO
SEQ1.BITC=ZERO
SEQ2.BITC=ZERO
SEQ1.BITB=ZERO
SEQ2.BITB=ZERO
SEQ1.REPEATS=0
SEQ2.REPEATS=0
SEQ1.POSB=ZERO
SEQ2.POSB=ZERO
SEQ1.POSC=ZERO
SEQ2.POSC=ZERO
SEQ1.POSA=ZERO
SEQ2.POSA=ZERO
SYSTEM.CLOCK_SOURCE=int clock
SYSTEM.TIMESTAMP_SOURCE=None
SRGATE1.WHEN_DISABLED=Set output low
SRGATE2.WHEN_DISABLED=Set output low
SRGATE3.WHEN_DISABLED=Set output low
SRGATE4.WHEN_DISABLED=Set output low
SRGATE1.RST_EDGE=Rising
SRGATE2.RST_EDGE=Rising
SRGATE3.RST_EDGE=Rising
SRGATE4.RST_EDGE=Rising
SRGATE1.SET=ZERO
SRGATE2.SET=ZERO
SRGATE3.SET=ZERO
SRGATE4.SET=ZERO
SRGATE1.SET_EDGE=Rising
SRGATE2.SET_EDGE=Rising
SRGATE3.SET_EDGE=Rising
SRGATE4.SET_EDGE=Rising
SRGATE1.ENABLE=ZERO
SRGATE2.ENABLE=ZERO
SRGATE3.ENABLE=ZERO
SRGATE4.ENABLE=ZERO
SRGATE1.RST=ZERO
SRGATE2.RST=ZERO
SRGATE3.RST=ZERO
SRGATE4.RST=ZERO
FMC_OUT.GAIN4=5V
FMC_OUT.GAIN1=5V
FMC_OUT.GAIN3=5V
FMC_OUT.GAIN2=5V
FMC_OUT.VAL1=ZERO
FMC_OUT.VAL3=ZERO
FMC_OUT.VAL2=ZERO
FMC_OUT.VAL4=ZERO
LUT1.INPB=ZERO
LUT2.INPB=ZERO
LUT3.INPB=ZERO
LUT4.INPB=ZERO
LUT5.INPB=ZERO
LUT6.INPB=ZERO
LUT7.INPB=ZERO
LUT8.INPB=ZERO
LUT1.INPC=ZERO
LUT2.INPC=ZERO
LUT3.INPC=ZERO
LUT4.INPC=ZERO
LUT5.INPC=ZERO
LUT6.INPC=ZERO
LUT7.INPC=ZERO
LUT8.INPC=ZERO
LUT1.INPA=ZERO
LUT2.INPA=ZERO
LUT3.INPA=ZERO
LUT4.INPA=ZERO
LUT5.INPA=ZERO
LUT6.INPA=ZERO
LUT7.INPA=ZERO
LUT8.INPA=ZERO
LUT1.INPD=ZERO
LUT2.INPD=ZERO
LUT3.INPD=ZERO
LUT4.INPD=ZERO
LUT5.INPD=ZERO
LUT6.INPD=ZERO
LUT7.INPD=ZERO
LUT8.INPD=ZERO
LUT1.INPE=ZERO
LUT2.INPE=ZERO
LUT3.INPE=ZERO
LUT4.INPE=ZERO
LUT5.INPE=ZERO
LUT6.INPE=ZERO
LUT7.INPE=ZERO
LUT8.INPE=ZERO
LUT1.FUNC=0x00000000
LUT2.FUNC=0x00000000
LUT3.FUNC=0x00000000
LUT4.FUNC=0x00000000
LUT5.FUNC=0x00000000
LUT6.FUNC=0x00000000
LUT7.FUNC=0x00000000
LUT8.FUNC=0x00000000
LUT1.TYPEA=Input-Level
LUT2.TYPEA=Input-Level
LUT3.TYPEA=Input-Level
LUT4.TYPEA=Input-Level
LUT5.TYPEA=Input-Level
LUT6.TYPEA=Input-Level
LUT7.TYPEA=Input-Level
LUT8.TYPEA=Input-Level
LUT1.TYPEC=Input-Level
LUT2.TYPEC=Input-Level
LUT3.TYPEC=Input-Level
LUT4.TYPEC=Input-Level
LUT5.TYPEC=Input-Level
LUT6.TYPEC=Input-Level
LUT7.TYPEC=Input-Level
LUT8.TYPEC=Input-Level
LUT1.TYPEB=Input-Level
LUT2.TYPEB=Input-Level
LUT3.TYPEB=Input-Level
LUT4.TYPEB=Input-Level
LUT5.TYPEB=Input-Level
LUT6.TYPEB=Input-Level
LUT7.TYPEB=Input-Level
LUT8.TYPEB=Input-Level
LUT1.TYPEE=Input-Level
LUT2.TYPEE=Input-Level
LUT3.TYPEE=Input-Level
LUT4.TYPEE=Input-Level
LUT5.TYPEE=Input-Level
LUT6.TYPEE=Input-Level
LUT7.TYPEE=Input-Level
LUT8.TYPEE=Input-Level
LUT1.TYPED=Input-Level
LUT2.TYPED=Input-Level
LUT3.TYPED=Input-Level
LUT4.TYPED=Input-Level
LUT5.TYPED=Input-Level
LUT6.TYPED=Input-Level
LUT7.TYPED=Input-Level
LUT8.TYPED=Input-Level
CALC1.INPC=ZERO
CALC2.INPC=ZERO
CALC1.INPA=ZERO
CALC2.INPA=ZERO
CALC1.SHIFT=0
CALC2.SHIFT=0
CALC1.INPB=ZERO
CALC2.INPB=ZERO
CALC1.INPD=ZERO
CALC2.INPD=ZERO
CALC1.TYPEA=Value
CALC2.TYPEA=Value
CALC1.TYPEC=Value
CALC2.TYPEC=Value
CALC1.TYPEB=Value
CALC2.TYPEB=Value
CALC1.TYPED=Value
CALC2.TYPED=Value
LVDSOUT1.FINE_DELAY=0
LVDSOUT2.FINE_DELAY=0
LVDSOUT1.QUARTER_DELAY=0
LVDSOUT2.QUARTER_DELAY=0
LVDSOUT1.VAL=ZERO
LVDSOUT2.VAL=ZERO
CLOCK1.ENABLE=ONE
CLOCK2.ENABLE=ZERO
CLOCK1.PERIOD=0.0001
CLOCK2.PERIOD=0.2
CLOCK1.WIDTH=3e-05
CLOCK2.WIDTH=5
COUNTER1.OUT_MODE=On-Change
COUNTER2.OUT_MODE=On-Change
COUNTER3.OUT_MODE=On-Change
COUNTER4.OUT_MODE=On-Change
COUNTER5.OUT_MODE=On-Change
COUNTER6.OUT_MODE=On-Change
COUNTER7.OUT_MODE=On-Change
COUNTER8.OUT_MODE=On-Change
COUNTER1.SET=0
COUNTER2.SET=0
COUNTER3.SET=0
COUNTER4.SET=0
COUNTER5.SET=0
COUNTER6.SET=0
COUNTER7.SET=0
COUNTER8.SET=0
COUNTER1.DIR=ZERO
COUNTER2.DIR=ZERO
COUNTER3.DIR=ZERO
COUNTER4.DIR=ZERO
COUNTER5.DIR=ZERO
COUNTER6.DIR=ZERO
COUNTER7.DIR=ZERO
COUNTER8.DIR=ZERO
COUNTER1.ENABLE=PCAP.ACTIVE
COUNTER2.ENABLE=ZERO
COUNTER3.ENABLE=ZERO
COUNTER4.ENABLE=ZERO
COUNTER5.ENABLE=ZERO
COUNTER6.ENABLE=ZERO
COUNTER7.ENABLE=ZERO
COUNTER8.ENABLE=ZERO
COUNTER1.TRIG=TTLIN1.VAL
COUNTER2.TRIG=ZERO
COUNTER3.TRIG=ZERO
COUNTER4.TRIG=ZERO
COUNTER5.TRIG=ZERO
COUNTER6.TRIG=ZERO
COUNTER7.TRIG=ZERO
COUNTER8.TRIG=ZERO
COUNTER1.TRIG_EDGE=Falling
COUNTER2.TRIG_EDGE=Rising
COUNTER3.TRIG_EDGE=Rising
COUNTER4.TRIG_EDGE=Rising
COUNTER5.TRIG_EDGE=Rising
COUNTER6.TRIG_EDGE=Rising
COUNTER7.TRIG_EDGE=Rising
COUNTER8.TRIG_EDGE=Rising
COUNTER1.MIN=0
COUNTER2.MIN=0
COUNTER3.MIN=0
COUNTER4.MIN=0
COUNTER5.MIN=0
COUNTER6.MIN=0
COUNTER7.MIN=0
COUNTER8.MIN=0
COUNTER1.MAX=0
COUNTER2.MAX=0
COUNTER3.MAX=0
COUNTER4.MAX=0
COUNTER5.MAX=0
COUNTER6.MAX=0
COUNTER7.MAX=0
COUNTER8.MAX=0
COUNTER1.START=0
COUNTER2.START=0
COUNTER3.START=0
COUNTER4.START=0
COUNTER5.START=0
COUNTER6.START=0
COUNTER7.START=0
COUNTER8.START=0
COUNTER1.STEP=1
COUNTER2.STEP=1
COUNTER3.STEP=0
COUNTER4.STEP=0
COUNTER5.STEP=0
COUNTER6.STEP=0
COUNTER7.STEP=0
COUNTER8.STEP=0
PULSE1.PULSES=0
PULSE2.PULSES=0
PULSE3.PULSES=0
PULSE4.PULSES=0
PULSE1.ENABLE=ONE
PULSE2.ENABLE=ZERO
PULSE3.ENABLE=ZERO
PULSE4.ENABLE=ZERO
PULSE1.DELAY=0
PULSE2.DELAY=0.2
PULSE3.DELAY=0.3
PULSE4.DELAY=0.4
PULSE1.TRIG=ZERO
PULSE2.TRIG=ZERO
PULSE3.TRIG=ZERO
PULSE4.TRIG=ZERO
PULSE1.TRIG_EDGE=Rising
PULSE2.TRIG_EDGE=Rising
PULSE3.TRIG_EDGE=Rising
PULSE4.TRIG_EDGE=Rising
PULSE1.WIDTH=0.001
PULSE2.WIDTH=0.1
PULSE3.WIDTH=0.1
PULSE4.WIDTH=0.1
PULSE1.STEP=0
PULSE2.STEP=0
PULSE3.STEP=0
PULSE4.STEP=0
FILTER1.INP=ZERO
FILTER2.INP=ZERO
FILTER1.MODE=average
FILTER2.MODE=difference
FILTER1.ENABLE=ZERO
FILTER2.ENABLE=ZERO
FILTER1.TRIG=ZERO
FILTER2.TRIG=ZERO
FMC_IN.GAIN5=10V
FMC_IN.GAIN4=10V
FMC_IN.GAIN7=10V
FMC_IN.GAIN6=10V
FMC_IN.GAIN1=10V
FMC_IN.GAIN3=10V
FMC_IN.GAIN2=10V
FMC_IN.GAIN8=10V
PGEN1.REPEATS=0
PGEN2.REPEATS=0
PGEN1.ENABLE=ZERO
PGEN2.ENABLE=ZERO
PGEN1.TRIG=ZERO
PGEN2.TRIG=ZERO
*METADATA.LABEL_CALC1=
*METADATA.LABEL_FILTER1=
*METADATA.LABEL_CALC2=
*METADATA.LABEL_SRGATE4=
*METADATA.LABEL_FMC_IN1=
*METADATA.LABEL_TTLIN6=
*METADATA.LABEL_SRGATE1=
*METADATA.LABEL_TTLIN4=
*METADATA.LABEL_TTLIN5=
*METADATA.LABEL_TTLIN2=TTL input 2
*METADATA.LABEL_TTLIN3=
*METADATA.LABEL_CLOCK1=
*METADATA.LABEL_TTLIN1=TTL input 1
*METADATA.LABEL_PCOMP1=
*METADATA.LABEL_LUT8=
*METADATA.LABEL_BITS1=Soft inputs and constant bits
*METADATA.LABEL_COUNTER8=
*METADATA.LABEL_COUNTER7=
*METADATA.LABEL_COUNTER6=
*METADATA.LABEL_COUNTER5=
*METADATA.LABEL_COUNTER4=
*METADATA.LABEL_COUNTER3=
*METADATA.LABEL_COUNTER2=
*METADATA.LABEL_COUNTER1=
*METADATA.LABEL_TTLOUT3=TTL output 3
*METADATA.LABEL_OUTENC2=
*METADATA.LABEL_OUTENC3=
*METADATA.LABEL_SYSTEM1=System control FPGA
*METADATA.LABEL_OUTENC1=
*METADATA.LABEL_PGEN2=
*METADATA.LABEL_OUTENC4=
*METADATA.LABEL_PGEN1=
*METADATA.LABEL_LUT2=
*METADATA.LABEL_LUT3=
*METADATA.LABEL_LUT1=Lookup table 1
*METADATA.LABEL_LUT6=
*METADATA.LABEL_LUT7=
*METADATA.LABEL_LUT4=
*METADATA.LABEL_LUT5=
*METADATA.LABEL_LVDSOUT2=
*METADATA.LABEL_LVDSOUT1=
*METADATA.LABEL_SFP3_SYNC_OUT1=
*METADATA.LABEL_PULSE3=
*METADATA.LABEL_TTLOUT7=
*METADATA.LABEL_SRGATE2=
*METADATA.LABEL_LVDSIN2=
*METADATA.LABEL_LVDSIN1=
*METADATA.LABEL_SEQ1=
*METADATA.LABEL_CLOCK2=
*METADATA.LABEL_PULSE4=
*METADATA.LABEL_INENC1=
*METADATA.LABEL_INENC2=
*METADATA.LABEL_INENC3=
*METADATA.LABEL_INENC4=
*METADATA.LABEL_PULSE1=
*METADATA.LABEL_PULSE2=
*METADATA.LABEL_FILTER2=
*METADATA.LABEL_TTLOUT10=
*METADATA.LABEL_SEQ2=
*METADATA.LABEL_PCOMP2=
*METADATA.LABEL_DIV1=
*METADATA.LABEL_SRGATE3=
*METADATA.LABEL_FMC_OUT1=
*METADATA.LABEL_DIV2=
*METADATA.LABEL_SFP3_SYNC_IN1=
*METADATA.LABEL_TTLOUT8=
*METADATA.LABEL_TTLOUT9=
*METADATA.LABEL_TTLOUT6=
*METADATA.LABEL_PCAP1=Position capture control
*METADATA.LABEL_TTLOUT4=TTL output 4
*METADATA.LABEL_TTLOUT5=
*METADATA.LABEL_TTLOUT2=TTL output 2
*METADATA.DESIGN=
*METADATA.LABEL_TTLOUT1=TTL output 1
SEQ1.TABLE<B
SEQ2.TABLE<B
PGEN1.TABLE<B
PGEN2.TABLE<B
*METADATA.LAYOUT<
{"PCAP": {"x": -2.0, "y": 132.41562128067017},
"TTLIN1": {"x": -350.0, "y": -127.0},
"INENC1": {"x": 355.0, "y": -441.0},
"INENC2": {"x": 358.0, "y": -240.0},
"INENC3": {"x": 593.0, "y": -440.0},
"INENC4": {"x": 595.0, "y": -232.0},
"COUNTER1": {"x": 69.0, "y": -100.0},
"CLOCK1": {"x": -388.7071887784922, "y": 140.75832846288722}}
*METADATA.EXPORTS<
+195 -2
View File
@@ -1,11 +1,14 @@
"""Module to integrate the PandaBox for cSAXS measurements."""
import threading
import time
from typing import Any
from bec_lib.logger import bec_logger
from bec_server.scan_server.scans.scan_base import ScanInfo as ScanServerScanInfo
from ophyd_devices import StatusBase
from ophyd_devices.devices.panda_box.panda_box import PandaBox, PandaState
from pandablocks.responses import FrameData
from csaxs_bec.devices.utils.utils import fetch_scan_info
@@ -13,7 +16,72 @@ logger = bec_logger.logger
class PandaBoxOMNY(PandaBox):
"""PandaBox integration for OMNY. This class implements OMNY specific logic for the PandaBox integration."""
"""PandaBox integration for OMNY. This class implements OMNY specific logic for the PandaBox integration.
Two operation modes are supported, selected via ``raw_stream_mode``:
- Legacy mode (``raw_stream_mode=False``, default): unchanged behavior. Each PCAP gate
(one per scan point / burst sub-frame) produces one aggregate statistic
(Mean/Min/Max/Sum/Diff) that is published immediately, and completion is checked
against the exact expected number of gates (``num_points * frames_per_trigger``).
- Free-running mode (``raw_stream_mode=True``): the PCAP module is expected to be
configured on the PandaBox itself to capture raw ``Value`` samples continuously at a
much higher rate for the duration of a burst window, alongside a digital gate-input bit
and a monotonic frame counter (see docs/developer/panda_box_free_running_setup.md).
Incoming samples are coalesced client-side (by row count or time, whichever comes
first) before being published, to keep the message rate to the BEC message bus
bounded regardless of how the PandaBox itself batches network frames. Completion is
checked against the frame counter (COUNTER1, aliased to ``frame_counter``), which
increments on the detector-trigger's falling edge, reaching the expected
``num_points * frames_per_trigger`` count once the last exposure finishes.
``*PCAP.CAPTURED?`` can't be used for this: on this layout PCAP's gate/trig are driven
continuously by an internal clock, so it never naturally stops incrementing while
armed.
"""
# PCAP.BITS0 is a shared 32-bit capture word; other captured bit_out signals (e.g. other
# TTLIN/LVDSIN/encoder bits also flagged for capture) may share it at different bit
# offsets, so the raw word is not itself a clean 0/1. TTLIN1.VAL (the detector-trigger
# gate signal, aliased to _GATE_SIGNAL_NAME below) was confirmed at bit offset 0 of
# PCAP.BITS0 on the omny-panda hardware on 2026-09-15 via
# `TTLIN1.VAL.CAPTURE_WORD?`/`TTLIN1.VAL.OFFSET?` (see
# docs/developer/panda_box_free_running_setup.md). Re-verify with the same query if the
# PandA layout is ever rebuilt.
_GATE_SIGNAL_NAME = "gate_detector_active"
_GATE_BIT_OFFSET = 0
def __init__(
self,
*,
name: str,
host: str,
signal_alias: dict[str, str] | None = None,
scan_info: ScanServerScanInfo | None = None,
device_manager: Any | None = None,
raw_stream_mode: bool = False,
raw_stream_flush_interval: float = 0.05,
raw_stream_flush_row_count: int = 500,
**kwargs,
) -> None:
# Free-running raw-stream configuration. Defaults preserve today's behavior:
# raw_stream_mode=False means _receive_frame_data/on_stage/on_complete are
# byte-for-byte identical to before this mode was added.
self.raw_stream_mode = raw_stream_mode
self.raw_stream_flush_interval = raw_stream_flush_interval
self.raw_stream_flush_row_count = raw_stream_flush_row_count
self._raw_stream_buffer: dict[str, dict[str, Any]] = {}
self._raw_stream_buffer_row_count = 0
self._raw_stream_buffer_lock = threading.Lock()
self._raw_stream_last_flush = time.monotonic()
super().__init__(
name=name,
host=host,
signal_alias=signal_alias,
scan_info=scan_info,
device_manager=device_manager,
**kwargs,
)
def on_init(self):
super().on_init()
@@ -25,9 +93,17 @@ class PandaBoxOMNY(PandaBox):
start_time = time.time()
super().on_stage()
self.scan_parameters = fetch_scan_info(self.scan_info)
with self._raw_stream_buffer_lock:
self._raw_stream_buffer = {}
self._raw_stream_buffer_row_count = 0
self._raw_stream_last_flush = time.monotonic()
# TODO, adjust as seen fit.
# Adjust the acquisition group based on scan parameters if needed
if self.scan_parameters.scan_type == "hardware_triggered":
if self.raw_stream_mode:
self._acquisition_group = "free_running"
elif self.scan_parameters.scan_type == "hardware_triggered":
self._acquisition_group = "fly"
elif self.scan_parameters.scan_type == "software_triggered":
if self.scan_parameters.frames_per_trigger == 1:
@@ -37,8 +113,19 @@ class PandaBoxOMNY(PandaBox):
logger.info(f"PandaBox {self.name} on_stage completed in {time.time() - start_time:.3f}s.")
def on_unstage(self):
"""Make sure no buffered raw-stream data is left behind before resetting the device."""
self._flush_raw_stream_buffer()
return super().on_unstage()
def on_complete(self):
"""On complete is called after the scan is complete. We need to wait for the capture to complete before we can disarm the PandaBox."""
if self.raw_stream_mode:
return self._on_complete_free_running()
return self._on_complete_burst()
def _on_complete_burst(self):
"""Legacy completion check: wait for the exact expected number of gated captures."""
def _check_capture_complete():
captured = 0
@@ -66,6 +153,112 @@ class PandaBoxOMNY(PandaBox):
self.cancel_on_stop(status_captured)
return status_captured
def _on_complete_free_running(self):
"""Completion check for continuous free-running capture: wait for the frame counter
(COUNTER1, aliased to frame_counter) to reach the exact expected number of frames.
*PCAP.CAPTURED? can't be used here, unlike _on_complete_burst: on this layout PCAP's
gate/trig are driven continuously by an internal clock (CLOCK1), so the captured
count never naturally stops increasing while PCAP stays armed -- there's nothing to
settle. COUNTER1 instead increments on the detector-trigger's falling edge, i.e. once
per completed exposure, so it reaches num_points * frames_per_trigger -- the same
target _on_complete_burst waits for -- exactly when the last exposure finishes. See
docs/developer/panda_box_free_running_setup.md.
"""
def _check_frame_count_complete():
counted = 0
start_time = time.monotonic()
try:
expected_frames = int(
self.scan_parameters.num_points * self.scan_parameters.frames_per_trigger
)
while counted < expected_frames:
ret = self.send_raw("COUNTER1.OUT?")
counted = int(float(ret[0].split("=")[-1]))
time.sleep(0.01)
if (time.monotonic() - start_time) > self._timeout_on_completed / 2:
logger.info(
f"Waiting for frame_counter on device {self.name} to complete: "
f"counted {counted}/{expected_frames} frames."
)
if (time.monotonic() - start_time) > self._timeout_on_completed:
raise TimeoutError(
f"Pandabox {self.name} did not complete after "
f"{self._timeout_on_completed}s with frames counted "
f"{counted}/{expected_frames}"
)
finally:
self._flush_raw_stream_buffer()
self._disarm()
status_captured = self.task_handler.submit_task(_check_frame_count_complete, run=True)
self.cancel_on_stop(status_captured)
return status_captured
def convert_frame_data(self, frame_data: FrameData) -> dict[str, Any]:
"""Same as the base class, but in raw_stream_mode additionally masks
``gate_detector_active`` down to its own bit within the shared PCAP.BITS0 capture
word -- see the class-level note on ``_GATE_BIT_OFFSET`` for why the raw word can't
be trusted as a clean 0/1 on its own.
"""
out = super().convert_frame_data(frame_data)
if self.raw_stream_mode and self._GATE_SIGNAL_NAME in out:
entry = out[self._GATE_SIGNAL_NAME]
entry["value"] = [(int(v) >> self._GATE_BIT_OFFSET) & 1 for v in entry["value"]]
return out
def _receive_frame_data(self, data: FrameData) -> None:
"""Callback to receive frame data from the PandaBox.
In legacy mode this is identical to the base class: publish immediately, one
FrameData in, one `.data.put()` out. In free-running mode, converted rows are
accumulated in a buffer and only published once a row-count or time threshold is
reached, to bound the message rate to the BEC message bus.
"""
if not self.raw_stream_mode:
super()._receive_frame_data(data)
return
converted = self.convert_frame_data(frame_data=data)
with self._raw_stream_buffer_lock:
self._merge_into_raw_stream_buffer(converted)
elapsed = time.monotonic() - self._raw_stream_last_flush
if (
self._raw_stream_buffer_row_count >= self.raw_stream_flush_row_count
or elapsed >= self.raw_stream_flush_interval
):
self._flush_raw_stream_buffer_locked()
def _merge_into_raw_stream_buffer(self, converted: dict[str, dict[str, Any]]) -> None:
"""Append newly converted rows into the pending raw-stream buffer. Must be called
while holding `_raw_stream_buffer_lock`."""
row_count = 0
for key, entry in converted.items():
buffered = self._raw_stream_buffer.setdefault(
key, {"value": [], "timestamp": entry["timestamp"]}
)
buffered["value"].extend(entry["value"])
buffered["timestamp"] = entry["timestamp"]
row_count = max(row_count, len(entry["value"]))
self._raw_stream_buffer_row_count += row_count
def _flush_raw_stream_buffer(self) -> None:
"""Flush any pending buffered raw-stream data, taking the lock. Safe to call from
any thread, e.g. on_complete/on_unstage, even if nothing is buffered."""
with self._raw_stream_buffer_lock:
self._flush_raw_stream_buffer_locked()
def _flush_raw_stream_buffer_locked(self) -> None:
"""Flush any pending buffered raw-stream data. Must be called while holding
`_raw_stream_buffer_lock`."""
self._raw_stream_last_flush = time.monotonic()
if not self._raw_stream_buffer:
return
out, self._raw_stream_buffer = self._raw_stream_buffer, {}
self._raw_stream_buffer_row_count = 0
self.data.put(out, acquisition_group=self._acquisition_group)
if __name__ == "__main__":
import time
@@ -0,0 +1,48 @@
# PandABox free-running (`raw_stream_mode`) raw data schema
> **Status: schema for the acquisition side only.** This document defines
> what raw data `omny_panda` writes to its HDF5 async dataset when
> `raw_stream_mode: true` (see `docs/developer/panda_box_free_running_setup.md`
> for the hardware/mode setup, confirmed against real PandA hardware
> 2026-09-15). Reconstructing the previous averaged/stdev-per-position view
> from this raw data (binning by the `gate_detector_active` transitions or
> timestamps) is a separate, not-yet-planned analysis task and is
> intentionally out of scope here.
## Where this data lands
`omny_panda` is configured with `readoutPriority: async`
(`csaxs_bec/device_configs/ptycho_flomni.yaml`). Its `data` signal is a
`DynamicSignal` (`ophyd_devices/devices/panda_box/panda_box.py`) that BEC's
async file writer appends to an HDF5 dataset per scan, under this device's
async data group. In `raw_stream_mode`, each write corresponds to one
coalesced flush (see the setup doc's mode-comparison table), not one raw
PandA network frame — the row-level data below is still preserved exactly,
just batched differently for publishing efficiency.
## Per-row fields
Each row corresponds to one PCAP capture tick (one raw sample at the
free-running capture rate — `CLOCK1`'s configured rate, started at 100 Hz for
initial testing on 2026-09-15, see the setup doc for the current rate):
| Field (BEC signal name) | Source PandA block | Meaning |
|---|---|---|
| `cap_voltage_fzp_y`/`cap_voltage_fzp_x` etc. (raw analog/encoder value) | `FMC_IN.VAL1.Value` / `FMC_IN.VAL2.Value` / `INENC1`-`4.VAL.Value` | The instantaneous raw sample at this capture tick, replacing the Mode A aggregate (Mean/Min/Max). All six channels (both FMC analog inputs and all four encoders) are switched to raw capture together on this layout — not a subset. |
| `gate_detector_active` | `PCAP.BITS0.Value`, bit 0 (`TTLIN1.VAL`), masked in software — see setup doc | The detector-trigger signal, sampled at this same tick: `1` while a detector trigger is active, `0` otherwise. `PCAP.BITS0` is a shared 32-bit word; `PandaBoxOMNY` masks it down to bit 0 before this reaches the HDF5 file (see `_GATE_BIT_OFFSET` in `panda_box_omny.py`) — the raw word itself is not a clean 0/1. This is what a future reconstruction step would use to delimit which raw samples belong to which detector-gate window. |
| `frame_counter` | `COUNTER1.OUT.Value`, triggered off `TTLIN1.VAL`'s falling edge (i.e. increments once per *completed* detector exposure, not once per PCAP capture tick as originally guessed here) | Monotonically incrementing hardware counter. Doubles as the completion signal for `on_complete` (`PandaBoxOMNY._on_complete_free_running`, `panda_box_omny.py`) — waits for it to reach `num_points * frames_per_trigger`, since `*PCAP.CAPTURED?` free-runs continuously and never naturally stops while armed. Also the post-hoc data-completeness record: a gap-free, strictly increasing sequence means no detector exposures were missed between the PandA and the HDF5 file; a gap indicates lost data (e.g. from the Redis stream's `MAXLEN` trimming if the file writer fell behind — see the acquisition plan's data-path notes). Because it counts completed exposures rather than capture ticks, it verifies detector-frame completeness directly rather than raw-sample completeness. |
| `PCAP.TS_TRIG.Value` (existing) | `PCAP.TS_TRIG` | Absolute/relative timestamp already captured today; usable for time-alignment against other detectors' data during future reconstruction. |
| `PCAP.GATE_DURATION.Value` (existing, aliased as `pcap_gate_duration_value`) | `PCAP.GATE_DURATION` | Existing field, retained; less meaningful once the gate is held open continuously for the whole burst window rather than pulsed per point (see setup doc, Mode B gate/arm row) — re-evaluate whether this still needs to be captured now that real hardware testing has started. |
All rows across a burst window share the same set of fields; there is no
per-point boundary marker in this raw stream other than what can be derived
from `gate_detector_active` transitions and/or absolute timestamps — no
explicit "scan point index" field is captured by the PandA itself.
## What this does *not* include
- No on-the-fly or post-scan computation of Mean/Min/Max/stdev from the raw
samples — the raw stream is the complete record; deriving the previous
per-point statistics from it is a separate future task.
- No changes to how Mode A (legacy) data is written — this schema only
applies when `raw_stream_mode: true`.
@@ -0,0 +1,218 @@
# PandABox (`omny_panda`) burst acquisition: two operation modes
> **Status: Mode B confirmed working end-to-end against real PandA hardware
> (2026-09-15, omny-panda.psi.ch)** — correct per-channel raw values, masked
> `gate_detector_active`, and `frame_counter`-based completion all verified,
> then speed-tested up to 20 kHz with no reported issues (though see the
> caveat under "Saving / restoring layouts" — the saved `omny_freerun.ini`
> layout itself was captured at 10 kHz, not 20 kHz). `ptycho_flomni.yaml`
> currently has `omny_panda_continuous` (Mode B) active — note the PandA's
> Design was switched back to `OMNY` on 2026-09-15 solely to capture the
> `omny.ini` layout file below, so double-check which Design is actually
> loaded on the physical PandA before running a scan against either config.
## Context
flomni burst scans acquire `frames_per_trigger` sub-frames per scan point.
Historically, the PandABox (`omny_panda`, device class `PandaBoxOMNY` in
`csaxs_bec/devices/panda_box/panda_box_omny.py`) reports one PCAP-aggregated
statistic (Mean/Min/Max/Sum/Diff) per gate, discarding the time structure
within a gate. This document describes the two supported operation modes —
the existing per-gate aggregate mode, and a new continuous free-running raw
mode — and how the PandA hardware and `ptycho_flomni.yaml` device config must
be set up for each.
Mode selection is a single software flag (`raw_stream_mode` in the device
config); it does **not** by itself reconfigure the PandA hardware. The PandA
layout must independently match the intended mode (see "Open question" at
the end) before that mode can be used.
## Mode comparison
| | Mode A: legacy (default) | Mode B: free-running (new) |
|---|---|---|
| Selected by | `raw_stream_mode` unset / `false` | `raw_stream_mode: true` |
| PCAP capture fields | `Mean`/`Min`/`Max`/`Sum`/`Diff` per gate | `Value` (raw instantaneous sample) + gate bit + frame counter |
| Gate/arm timing | Pulsed per point / sub-frame (rate = scan rate × `frames_per_trigger`) | PCAP held open continuously for the burst window, free-running at `CLOCK1`'s configured rate (started at **100 Hz** for initial testing on 2026-09-15; will be ramped up as testing progresses) |
| `_acquisition_group` (BEC async metadata) | `fly` / `monitored` / `burst`, chosen from `scan_type`/`frames_per_trigger` | `free_running` |
| Message publishing | One `.data.put()` per PandA network frame, unchanged | Coalesced client-side: flushed every `raw_stream_flush_row_count` rows or `raw_stream_flush_interval` seconds, whichever comes first (mitigates Redis/HDF5 message-rate risk — see the acquisition plan's data-path notes) |
| Completion check (`on_complete`) | Exact count: waits for `*PCAP.CAPTURED?` to reach `num_points * frames_per_trigger` | Exact count: waits for `COUNTER1.OUT?` (`frame_counter`) to reach `num_points * frames_per_trigger`. `*PCAP.CAPTURED?` can't be used here — `CLOCK1` drives `PCAP.gate`/`PCAP.trig` continuously (see "Continuous gate/arm" below), so the captured count never naturally stops increasing while armed; `COUNTER1` instead counts completed detector exposures directly (it's clocked off the detector-trigger's falling edge), so it reaches the expected total exactly when the last exposure finishes |
| Data completeness verification | Implicit in the exact-count completion check | Same mechanism as Mode A: `frame_counter` (`COUNTER1`) is both the completion signal and the post-hoc completeness record — a gap in an otherwise-monotonic sequence in the HDF5 data means dropped rows even though the expected total was reached |
Both modes are implemented in the same `PandaBoxOMNY` class; `raw_stream_mode`
defaults to `false` so any device config that doesn't set it keeps today's
exact behavior unchanged.
## Physical wiring (Mode B only)
The detector-trigger signal is patched into **TTL input 1** (`TTLIN1`) on the
PandA front panel. That same `TTLIN1.VAL` signal feeds both downstream
consumers (see "Block configuration" below): it is the source counted by
`COUNTER1` (the frame counter) and the source captured into the gate bit.
## Block configuration
### Mode A (legacy) — reference baseline
The blocks already configured and aliased today, for reference / so this
layout can be restored unambiguously (see `ptycho_flomni.yaml`):
- `FMC_IN.VAL1`/`FMC_IN.VAL2` (capacitive sensor analog inputs) — `Min`,
`Max`, `Mean` capture fields.
- `INENC1`-`INENC4.VAL` (position-capture encoder inputs) — `Min`, `Max`,
`Mean` capture fields.
- `PCAP.GATE_DURATION` — `Value`.
- PCAP gate is pulsed once per point / sub-frame by the existing external
trigger electronics (unchanged by this work).
### Mode B (new) — free-running raw capture
- **Gate-bit input**: the detector-trigger signal, wired into `TTLIN1` (see
"Physical wiring" above). `TTLIN1.VAL` is captured into **`PCAP.BITS0`,
bit offset 0** — confirmed 2026-09-15 against the omny-panda hardware via:
```
TTLIN1.VAL.CAPTURE_WORD? -> OK =PCAP.BITS0
TTLIN1.VAL.OFFSET? -> OK =0
```
`PCAP.BITS0` is a shared 32-bit capture word — other captured `bit_out`
signals (several TTLIN/LVDSIN/encoder bits are also flagged for capture on
this layout) may occupy other bit positions of the same word, so the raw
`PCAP.BITS0.Value` is **not** itself a clean 0/1. `PandaBoxOMNY` masks it
down to bit 0 in `raw_stream_mode` (see `_GATE_BIT_OFFSET` in
`panda_box_omny.py`) before publishing it as `gate_detector_active` — treat
that masking as required, not optional, unless it's confirmed nothing else
shares `BITS0`. Re-run the query above (read-only, safe against live
hardware) if the PandA layout is ever rebuilt, since bit assignment is
fixed by the FPGA build and not guaranteed stable across rebuilds.
- **Frame counter**: `COUNTER1`, triggered off `TTLIN1.VAL`'s **falling
edge** (see layout below) — i.e. it increments once per *completed*
detector exposure, not once per PCAP capture tick as originally guessed
here. Captured with `CAPTURE=Value`; this is both the data-completeness
signal and the completion-detection signal (`frame_counter` in
`signal_alias`, see below, and "Completion check" in the mode-comparison
table above) — once the last expected exposure's trigger pulse has fallen,
`COUNTER1.OUT` reaches `num_points * frames_per_trigger` exactly.
- **Raw analog/position capture**: `FMC_IN.VAL1`, `FMC_IN.VAL2` and all four
`INENC1`-`4.VAL` are switched from aggregate capture to `CAPTURE=Value`
on this layout (confirmed 2026-09-15) — i.e. every analog/encoder channel
goes raw together, not a subset. This means the current PandA layout
cannot simultaneously produce Mode A's aggregate (Min/Max/Mean) data — see
"Open question" below.
- **Continuous gate/arm**: `CLOCK1`, enabled by the constant `ONE`, drives
`PCAP`'s `gate` and `trig` inputs continuously (instead of the external
per-point trigger used in Mode A), so PCAP free-runs at `CLOCK1`'s
configured rate. Testing started at **100 Hz** on 2026-09-15 and will be
ramped up; there is no PandA-side layout change needed to change the
rate, only `CLOCK1`'s period.
```
TTLIN1 (TTL input 1, detector trigger)
├──▶ COUNTER1.trig, falling edge (Up/Down pulse counter) ──▶ COUNTER1.OUT = frame_counter (CAPTURE=Value)
│ = completion signal too: reaches num_points * frames_per_trigger when the last exposure finishes
└──▶ captured into PCAP.BITS0 bit 0 ──▶ masked in software = gate_detector_active
CLOCK1 (enabled by constant ONE) ──▶ PCAP.gate, PCAP.trig (continuous arm/capture)
```
## Saving / restoring layouts
Use `ophyd_devices/devices/panda_box/utility_scripts.py` to save the current
PandA configuration to a `.ini` layout file and reload it later, so a
configuration survives a PandA power cycle. Both layouts are saved in this
repo under `csaxs_bec/devices/panda_box/layouts/` — `omny.ini` (Mode A) and
`omny_freerun.ini` (Mode B), captured 2026-09-15 directly from the PandA
design named `OMNY`/`omny_freerun` respectively (switch the PandA's active
Design first, then save):
```
python ophyd_devices/devices/panda_box/utility_scripts.py \
--host omny-panda.psi.ch --save-layout csaxs_bec/devices/panda_box/layouts/omny.ini
python ophyd_devices/devices/panda_box/utility_scripts.py \
--host omny-panda.psi.ch --save-layout csaxs_bec/devices/panda_box/layouts/omny_freerun.ini
```
To restore either, swap `--save-layout` for `--load-layout` with the same
file. Diffing the two confirms the mode-specific differences documented
above: `PCAP.GATE`/`PCAP.TRIG` are `TTLIN1.VAL` in Mode A vs `CLOCK1.OUT` in
Mode B; `CLOCK1.ENABLE` is `ZERO` (off) in Mode A vs `ONE` in Mode B;
`INENC1`-`4.VAL.CAPTURE`/`FMC_IN.VAL1/VAL2.CAPTURE` are `Min Max Mean` in
Mode A vs `Value` in Mode B; `PCAP.BITS0.CAPTURE`/`COUNTER1.OUT.CAPTURE` are
`No` in Mode A vs `Value` in Mode B.
`omny_freerun.ini` was captured with `CLOCK1.PERIOD=0.0001` (100 µs → 10 kHz)
— note this doesn't match the 20 kHz reported as tested successfully the
same day, so it may not be the exact layout state the 20 kHz test ran at;
worth double-checking before relying on this file as "the" validated
high-rate layout.
## Signal alias mapping
The physical PandA block feeding each BEC signal name, kept here and in
`csaxs_bec/device_configs/ptycho_flomni.yaml` (`omny_panda.deviceConfig.signal_alias` for
Mode A, `omny_panda_continuous.deviceConfig.signal_alias` for Mode B) in sync as a single
source of truth:
| PandA block | Mode | BEC signal name |
|---|---|---|
| `FMC_IN.VAL1.Min`/`.Max`/`.Mean` | A | `cap_voltage_fzp_y_min`/`_max`/`_mean` |
| `FMC_IN.VAL2.Min`/`.Max`/`.Mean` | A | `cap_voltage_fzp_x_min`/`_max`/`_mean` |
| `INENC1.VAL.Min`/`.Max`/`.Mean` | A | `interf_st_fzp_y_min`/`_max`/`_mean` |
| `INENC2.VAL.Min`/`.Max`/`.Mean` | A | `interf_st_fzp_x_min`/`_max`/`_mean` |
| `INENC3.VAL.Min`/`.Max`/`.Mean` | A | `interf_st_rotz_min`/`_max`/`_mean` |
| `INENC4.VAL.Min`/`.Max`/`.Mean` | A | `interf_st_rotx_min`/`_max`/`_mean` |
| `PCAP.GATE_DURATION.Value` | A, B | `pcap_gate_duration_value` |
| `FMC_IN.VAL1/VAL2.Value`, `INENC1`-`4.VAL.Value` | B | `cap_voltage_fzp_y`/`_x`, `interf_st_fzp_y`/`_x`/`_rotz`/`_rotx` |
| `PCAP.BITS0.Value` (bit 0 = `TTLIN1.VAL`, confirmed 2026-09-15; masked in software, see above) | B | `gate_detector_active` |
| `COUNTER1.OUT.Value` (confirmed 2026-09-15, triggered off `TTLIN1.VAL`'s falling edge) | B | `frame_counter` |
The BEC-side data schema produced by Mode B (what ends up in the HDF5 async
dataset) is documented separately in
`docs/developer/panda_box_free_running_data_schema.md`.
## Switching between modes
`omny_panda` (Mode A) and `omny_panda_continuous` (Mode B) need different PandA hardware
layouts and can't run simultaneously (see "Open question" below), so exactly one should be
active in `ptycho_flomni.yaml` at a time, matching whichever layout is currently loaded on
the PandA — **comment out the other one's block entirely**, don't rely on `enabled: false`
alone.
That's a correction from earlier in this project: `enabled: false` on a device BEC has never
connected to is an inert placeholder — `connect_device` in
`bec_server/device_server/devices/devicemanager.py` is only called when `enabled` — so the
theory was that both entries could stay uncommented and switching would just be flipping the
flag. In practice (2026-09-15), disabling `omny_panda_continuous` this way was **not**
sufficient once it had already been connected in the running session: both devices ended up
active simultaneously against the same physical PandA. A device that's already connected
doesn't appear to get disconnected just because a later config reload marks it disabled.
Commenting the block out (so BEC never even constructs the device object) is the reliable
way to guarantee it's gone; if in doubt, confirm the other device has actually dropped its
connection (e.g. via a device server restart) rather than trusting `enabled: false` alone.
Confirmed end-to-end 2026-09-15: Mode B tested working (correct per-channel values, masked
`gate_detector_active`, `frame_counter`-based completion), then switched back to Mode A
(commented out) for A/B comparison testing.
## Open question, now partially resolved
Can both modes coexist under a single static PandA layout — i.e. is mode
switching purely the `raw_stream_mode` software flag, with the PandA always
capturing both the aggregate and raw fields simultaneously — or do Mode A
and Mode B require two distinct saved layouts that must be loaded before a
scan depending on the desired mode?
As currently wired for testing (2026-09-15), the answer looks like **two
distinct layouts are required**: `FMC_IN.VAL1/VAL2` and `INENC1`-`4.VAL` are
each set to `CAPTURE=Value` (single selection), not simultaneously
`CAPTURE=Value,Min,Max,Mean` — so this layout cannot also produce Mode A's
aggregate statistics at the same time. This has not yet been deliberately
tested against the alternative (whether the PandA capture UI actually
supports selecting `Value` together with `Min`/`Max`/`Mean` on the same
field) — if that turns out to work, a single layout could serve both modes.
Once Mode B testing is far enough along to save a named layout (see
"Saving / restoring layouts" below), settle this explicitly and record the
answer plus, if two layouts are needed, the load procedure to switch between
them.
+9
View File
@@ -233,6 +233,15 @@ The basic scan function can be called by `scans.flomni_fermat_scan()` and offers
Example:
`scans.flomni_fermat_scan(fovx=20, fovy=25, cenx=0.02, ceny=0, zshift=0, angle=0, step=0.5, exp_time=0.01, frames_per_trigger=1)`
`frames_per_trigger` controls burst acquisition for detectors generally.
Separately, the OMNY PandABox is configured as one of two distinct devices in
`csaxs_bec/device_configs/ptycho_flomni.yaml` — `omny_panda` (per-gate
averaged acquisition, currently kept as a commented reference) or
`omny_panda_continuous` (continuous, high-rate raw-sample acquisition) —
because the two modes require different PandA hardware layouts and can't run
simultaneously. See `docs/developer/panda_box_free_running_setup.md` for what
each mode captures and how to switch between them.
#### Overview of the alignment steps
There are several corrections applied to maintain the sample in the FOV:
+9
View File
@@ -338,6 +338,15 @@ The basic scan function can be called by `scans.omny_fermat_scan()` and offers a
Example:
`scans.omny_fermat_scan(fovx=20, fovy=25, cenx=0.02, ceny=0, zshift=0, angle=0, step=0.5, exp_time=0.01, frames_per_trigger=1, readout_time=0)`
`frames_per_trigger` controls burst acquisition for detectors generally.
Separately, the OMNY PandABox is configured as one of two distinct devices in
`csaxs_bec/device_configs/ptycho_flomni.yaml` — `omny_panda` (per-gate
averaged acquisition, currently kept as a commented reference) or
`omny_panda_continuous` (continuous, high-rate raw-sample acquisition) —
because the two modes require different PandA hardware layouts and can't run
simultaneously. See `docs/developer/panda_box_free_running_setup.md` for what
each mode captures and how to switch between them.
#### Overview of the alignment steps
There are several corrections applied to maintain the sample in the FOV:
+178
View File
@@ -5,14 +5,26 @@ from __future__ import annotations
from unittest import mock
import numpy as np
import pytest
from ophyd import Staged
from pandablocks.responses import FrameData
from csaxs_bec.devices.panda_box.panda_box import PandaBoxCSAXS
from csaxs_bec.devices.panda_box.panda_box_omny import PandaBoxOMNY
from csaxs_bec.devices.utils.utils import fetch_scan_info
def _make_frame_data(n_rows: int, start: int = 0) -> FrameData:
"""Build a synthetic FrameData batch with `n_rows` rows for the frame_counter /
gate_detector_active signals used by the raw-stream tests below."""
data = np.array(
[(np.float64(i), np.float64(i % 2)) for i in range(start, start + n_rows)],
dtype=[("COUNTER1.OUT.Value", "<f8"), ("PCAP.BITS0.Value", "<f8")],
)
return FrameData(data)
@pytest.fixture
def panda_omny():
dev_name = "panda_omny"
@@ -31,6 +43,25 @@ def panda_omny():
yield dev
@pytest.fixture
def panda_omny_raw_stream():
dev_name = "panda_omny_raw"
dev = PandaBoxOMNY(
name=dev_name,
host="omny-panda-box.psi.ch",
signal_alias={
"PCAP.BITS0.Value": "gate_detector_active",
"COUNTER1.OUT.Value": "frame_counter",
},
raw_stream_mode=True,
raw_stream_flush_row_count=5,
# Effectively disable the time-based flush so tests are deterministic and only
# exercise the row-count threshold.
raw_stream_flush_interval=1000,
)
yield dev
@pytest.fixture
def panda_csaxs():
dev_name = "panda_csaxs"
@@ -124,6 +155,153 @@ def test_panda_omny_complete(panda_omny):
assert status.success is True
def test_panda_omny_default_raw_stream_mode_is_off(panda_omny):
"""New devices must default to legacy behavior unless raw_stream_mode is explicitly set."""
assert panda_omny.raw_stream_mode is False
def test_panda_omny_legacy_receive_frame_data_is_unbuffered(panda_omny):
"""Backward-compatibility regression: without raw_stream_mode, each FrameData must still
be published immediately, exactly as before this feature was added."""
with mock.patch.object(panda_omny.data, "put") as mock_put:
for i in range(3):
panda_omny._receive_frame_data(_make_frame_data(2, start=i * 2))
assert mock_put.call_count == 3
def test_panda_omny_raw_stream_acquisition_group(panda_omny_raw_stream):
"""raw_stream_mode must select the free_running acquisition group regardless of
scan_type/frames_per_trigger."""
panda_omny_raw_stream.scan_info.msg.info["scan_type"] = "software_triggered"
panda_omny_raw_stream.scan_info.msg.info["frames_per_trigger"] = 10
panda_omny_raw_stream.stage()
assert panda_omny_raw_stream._acquisition_group == "free_running"
assert panda_omny_raw_stream.staged == Staged.yes
def test_panda_omny_raw_stream_coalesces_by_row_count(panda_omny_raw_stream):
"""Multiple small FrameData batches must be coalesced into a single .data.put() call
once the row-count threshold is reached, not published one-by-one."""
dev = panda_omny_raw_stream
with mock.patch.object(dev.data, "put") as mock_put:
dev._receive_frame_data(_make_frame_data(2, start=0))
dev._receive_frame_data(_make_frame_data(2, start=2))
mock_put.assert_not_called() # 4 rows buffered so far, threshold is 5
dev._receive_frame_data(_make_frame_data(2, start=4))
mock_put.assert_called_once() # 6 rows >= 5, flush triggered
out = mock_put.call_args.args[0]
assert [v for v in out["frame_counter"]["value"]] == [0.0, 1.0, 2.0, 3.0, 4.0, 5.0]
assert [v for v in out["gate_detector_active"]["value"]] == [0.0, 1.0, 0.0, 1.0, 0.0, 1.0]
def test_panda_omny_raw_stream_gate_bit_is_masked_from_shared_word(panda_omny_raw_stream):
"""PCAP.BITS0 is a 32-bit word shared with other captured bit_out signals; only bit 0
(TTLIN1.VAL, confirmed via CAPTURE_WORD?/OFFSET? against the omny-panda hardware) is the
detector-trigger gate. gate_detector_active must be masked down to that bit rather than
passed through as the raw word."""
dev = panda_omny_raw_stream
data = np.array(
# bit 0 set (gate active) plus other bits from something else sharing BITS0
[(0.0, 5.0), (1.0, 4.0), (2.0, 3.0)],
dtype=[("COUNTER1.OUT.Value", "<f8"), ("PCAP.BITS0.Value", "<f8")],
)
with mock.patch.object(dev.data, "put") as mock_put:
dev._receive_frame_data(FrameData(data))
dev._flush_raw_stream_buffer()
out = mock_put.call_args.args[0]
assert [v for v in out["gate_detector_active"]["value"]] == [1, 0, 1]
def test_panda_omny_raw_stream_flush_on_demand(panda_omny_raw_stream):
"""Buffered data below the threshold must still be flushed on demand (as on_complete/
on_unstage do), and flushing an empty buffer must not publish again."""
dev = panda_omny_raw_stream
with mock.patch.object(dev.data, "put") as mock_put:
dev._receive_frame_data(_make_frame_data(2, start=0))
mock_put.assert_not_called()
dev._flush_raw_stream_buffer()
mock_put.assert_called_once()
out = mock_put.call_args.args[0]
assert len(out["frame_counter"]["value"]) == 2
dev._flush_raw_stream_buffer()
mock_put.assert_called_once() # still 1: nothing left to flush
def test_panda_omny_unstage_flushes_pending_raw_stream_data(panda_omny_raw_stream):
dev = panda_omny_raw_stream
dev.stage()
with (
mock.patch.object(dev.data, "put") as mock_put,
mock.patch.object(dev, "_disarm", return_value=None),
):
dev._receive_frame_data(_make_frame_data(2, start=0))
mock_put.assert_not_called()
dev.unstage()
mock_put.assert_called_once()
def test_panda_omny_complete_free_running_waits_for_frame_counter(panda_omny_raw_stream):
"""Completion in free-running mode waits for COUNTER1 (frame_counter) to reach the exact
expected frame count -- PCAP.CAPTURED can't be used since it free-runs continuously off
CLOCK1 and never naturally stops increasing while armed."""
dev = panda_omny_raw_stream
dev.scan_info.msg.info["num_points"] = 1
dev.scan_info.msg.info["frames_per_trigger"] = 1
dev.scan_parameters = fetch_scan_info(dev.scan_info)
dev._timeout_on_completed = 5
with (
mock.patch.object(
dev, "send_raw", side_effect=[["=0"], ["=0"], ["=1"]]
) as mock_send_raw,
mock.patch.object(dev, "_disarm", return_value=None) as mock_disarm,
mock.patch.object(dev, "_flush_raw_stream_buffer") as mock_flush,
):
status = dev.on_complete()
status.wait(timeout=4)
assert status.done is True
assert status.success is True
mock_disarm.assert_called_once()
mock_flush.assert_called_once()
assert mock_send_raw.call_args.args[0] == "COUNTER1.OUT?"
def test_panda_omny_complete_free_running_timeout(panda_omny_raw_stream):
"""If the frame count never reaches the expected total, the overall timeout must still
fire."""
dev = panda_omny_raw_stream
dev.scan_info.msg.info["num_points"] = 1
dev.scan_info.msg.info["frames_per_trigger"] = 1
dev.scan_parameters = fetch_scan_info(dev.scan_info)
dev._timeout_on_completed = 0.3
with (
mock.patch.object(dev, "send_raw", side_effect=lambda *a, **k: ["=0"]),
mock.patch.object(dev, "_disarm", return_value=None) as mock_disarm,
mock.patch.object(dev, "_flush_raw_stream_buffer") as mock_flush,
):
status = dev.on_complete()
with pytest.raises(TimeoutError):
status.wait(timeout=4)
mock_disarm.assert_called_once()
mock_flush.assert_called_once()
def test_panda_omny_raw_stream_signal_alias(panda_omny_raw_stream):
all_signal_names = [name for name, _ in panda_omny_raw_stream.data.signals]
assert "gate_detector_active" in all_signal_names
assert "frame_counter" in all_signal_names
assert "PCAP.BITS0.Value" not in all_signal_names
assert "COUNTER1.OUT.Value" not in all_signal_names
def test_panda_csaxs(panda_csaxs):
assert panda_csaxs.name == "panda_csaxs"
assert panda_csaxs.host == "csaxs-panda-box.psi.ch"