Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ADTimePix3 detector ophyd device classes #1069

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 166 additions & 0 deletions ophyd/areadetector/cam.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"PvcamDetectorCam",
"RoperDetectorCam",
"SimDetectorCam",
"TimePix3DetectorCam",
"URLDetectorCam",
"UVCDetectorCam",
"Xspress3DetectorCam",
Expand Down Expand Up @@ -1289,6 +1290,171 @@ class RoperDetectorCam(CamBase):
roper_shutter_mode = ADCpt(SignalWithRBV, "RoperShutterMode")


class TimePix3Chip(Device):

def __init__(self, chip_number):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The components need to be at the class level. I think you want to use FormattedComponents

ophyd/ophyd/device.py

Lines 369 to 396 in 75a35fd

class FormattedComponent(Component[K]):
"""A Component which takes a dynamic format string
This differs from Component in that the parent prefix is not automatically
added onto the Component suffix. Additionally, `str.format()` style strings
are accepted, allowing access to Device instance attributes:
>>> from ophyd import (Component as Cpt, FormattedComponent as FCpt)
>>> class MyDevice(Device):
... # A normal component, where 'suffix' is added to prefix verbatim
... cpt = Cpt(EpicsSignal, 'suffix')
... # A formatted component, where 'self' refers to the Device instance
... ch = FCpt(EpicsSignal, '{self.prefix}{self._ch_name}')
... # A formatted component, where 'self' is assumed
... ch = FCpt(EpicsSignal, '{prefix}{_ch_name}')
...
... def __init__(self, prefix, ch_name=None, **kwargs):
... self._ch_name = ch_name
... super().__init__(prefix, **kwargs)
>>> dev = MyDevice('prefix:', ch_name='some_channel', name='dev')
>>> print(dev.cpt.pvname)
prefix:suffix
>>> print(dev.ch.pvname)
prefix:some_channel
For additional documentation, refer to Component.
"""
or DynamicDeviceComponent

ophyd/ophyd/device.py

Lines 407 to 437 in 75a35fd

class DynamicDeviceComponent(Component["Device"]):
"""An Device component that dynamically creates an ophyd Device
Parameters
----------
defn : OrderedDict
The definition of all attributes to be created, in the form of::
defn['attribute_name'] = (SignalClass, pv_suffix, keyword_arg_dict)
This will create an attribute on the sub-device of type `SignalClass`,
with a suffix of pv_suffix, which looks something like this::
parent.sub.attribute_name = Cpt(SignalClass, pv_suffix, **keyword_arg_dict)
Keep in mind that this is actually done in the metaclass creation, and
not exactly as written above.
clsname : str, optional
The name of the class to be generated
This defaults to {parent_name}{this_attribute_name.capitalize()}
doc : str, optional
The docstring to put on the dynamically generated class
default_read_attrs : list, optional
A class attribute to put on the dynamically generated class
default_configuration_attrs : list, optional
A class attribute to put on the dynamically generated class
component_class : class, optional
Defaults to Component
base_class : class, optional
Defaults to Device
"""
here.

self.chip_number = chip_number
self.cp_pll = ADCpt(EpicsSignalRO, f'{chip_number}_CP_PLL_RBV')
self.s1_off = ADCpt(EpicsSignalRO, f'{chip_number}_S1_OFF_RBV')
self.s1_on = ADCpt(EpicsSignalRO, f'{chip_number}_S1_ON_RBV')
self.s2_off = ADCpt(EpicsSignalRO, f'{chip_number}_S2_OFF_RBV')
self.s2_on = ADCpt(EpicsSignalRO, f'{chip_number}_S2_ON_RBV')
self.ikrum = ADCpt(EpicsSignalRO, f'{chip_number}_Ikrum_RBV')
self.ixel_dac = ADCpt(EpicsSignalRO, f'{chip_number}_PixelDAC_RBV')
self.preamp_off = ADCpt(EpicsSignalRO, f'{chip_number}_Preamp_OFF_RBV')
self.preamp_on = ADCpt(EpicsSignalRO, f'{chip_number}_Preamp_ON_RBV')
self.t_pbuffer_in = ADCpt(EpicsSignalRO, f'{chip_number}_TPbufferIn_RBV')
self.t_pbuffer_out = ADCpt(EpicsSignalRO, f'{chip_number}_TPbufferOut_RBV')
self.pll_vcntrl = ADCpt(EpicsSignalRO, f'{chip_number}_PLL_Vcntrl_RBV')
self.v_preamp_ncas = ADCpt(EpicsSignalRO, f'{chip_number}_VPreamp_NCAS_RBV')
self.vtp_coarse = ADCpt(EpicsSignalRO, f'{chip_number}_VTP_coarse_RBV')
self.vtp_fine = ADCpt(EpicsSignalRO, f'{chip_number}_VTP_fine_RBV')
self.vfbk = ADCpt(EpicsSignalRO, f'{chip_number}_Vfbk_RBV')
self.vth_coarse = ADCpt(EpicsSignalRO, f'{chip_number}_Vth_coarse_RBV')
self.vth_fine = ADCpt(EpicsSignalRO, f'{chip_number}_Vth_fine_RBV')
self.adjust = ADCpt(EpicsSignalRO, f'{chip_number}_Adjust_RBV')
self.layout = ADCpt(EpicsSignalRO, f'{chip_number}_Layout_RBV')


class TimePix3DetectorCam(CamBase):
_html_docs = ['TimePix3Doc.html']
_default_configuration_attrs = (
CamBase._default_configuration_attrs
)

chip0 = TimePix3Chip(0)
chip1 = TimePix3Chip(1)
chip2 = TimePix3Chip(2)
chip3 = TimePix3Chip(3)
Comment on lines +1325 to +1328
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
chip0 = TimePix3Chip(0)
chip1 = TimePix3Chip(1)
chip2 = TimePix3Chip(2)
chip3 = TimePix3Chip(3)
chip0 = Cpt(TimePix3Chip, 0)
chip1 = Cpt(TimePix3Chip, 1)
chip2 = Cpt(TimePix3Chip, 2)
chip3 = Cpt(TimePix3Chip, 3)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These need to be components or the TimePix3Chip instances will be instantiated on the class instance and shared across all instances of the device (and also miss getting the PV information).


bpc_file_path = ADCpt(SignalWithRBV, 'BPCFilePath')
bpc_file_path_exists = ADCpt(EpicsSignalRO, 'BPCFilePathExists_RBV')
dacs_file_path = ADCpt(SignalWithRBV, 'DACSFilePath')
dacs_file_path_exists = ADCpt(EpicsSignalRO, 'DACSFilePathExists_RBV')
bpc_file_name = ADCpt(SignalWithRBV, 'BPCFileName')
dacs_file_name = ADCpt(SignalWithRBV, 'DACSFileName')
write_bpc_file = ADCpt(EpicsSignal, 'WriteBPCFile')
write_dacs_file = ADCpt(EpicsSignal, 'WriteDACSFile')
write_file_message = ADCpt(EpicsSignal, 'WriteFileMessage')
server_url = ADCpt(EpicsSignalRO, 'ServerURL_RBV')
det_type = ADCpt(EpicsSignalRO, 'DetType_RBV')
fw_ts = ADCpt(EpicsSignalRO, 'FwTS_RBV')
free_space = ADCpt(EpicsSignalRO, 'FreeSpace_RBV')
write_speed = ADCpt(EpicsSignalRO, 'WriteSpeed_RBV')
http_code = ADCpt(EpicsSignalRO, 'HttpCode_RBV')
local_temp = ADCpt(EpicsSignalRO, 'LocalTemp_RBV')
fpga_temp = ADCpt(EpicsSignalRO, 'FPGATemp_RBV')
fan1_speed = ADCpt(EpicsSignalRO, 'Fan1Speed_RBV')
fan2_speed = ADCpt(EpicsSignalRO, 'Fan2Speed_RBV')
bias_voltage = ADCpt(EpicsSignalRO, 'BiasVoltage_RBV')
chip_temps = ADCpt(EpicsSignalRO, 'ChipTemps_RBV')
vdd = ADCpt(EpicsSignalRO, 'VDD_RBV')
avdd = ADCpt(EpicsSignalRO, 'AVDD_RBV')
health = ADCpt(EpicsSignal, 'Health')
iface = ADCpt(EpicsSignalRO, 'Iface_RBV')
chipboard_id = ADCpt(EpicsSignalRO, 'ChipboardID_RBV')
sw_ver = ADCpt(EpicsSignalRO, 'SW_ver_RBV')
fw_ver = ADCpt(EpicsSignalRO, 'FW_ver_RBV')
pix_count = ADCpt(EpicsSignalRO, 'PixCount_RBV')
row_len = ADCpt(EpicsSignalRO, 'RowLen_RBV')
n_chips = ADCpt(EpicsSignalRO, 'NChips_RBV')
n_rows = ADCpt(EpicsSignalRO, 'NRows_RBV')
mpx_type = ADCpt(EpicsSignalRO, 'MpxType_RBV')
b_ch_board_id = ADCpt(EpicsSignalRO, 'BChBoardId_RBV')
ip_addr = ADCpt(EpicsSignalRO, 'IpAddr_RBV')
port = ADCpt(EpicsSignalRO, 'Port_RBV')
chip1 = ADCpt(EpicsSignalRO, 'Chip1_RBV')
chip2 = ADCpt(EpicsSignalRO, 'Chip2_RBV')
chip3 = ADCpt(EpicsSignalRO, 'Chip3_RBV')
chip4 = ADCpt(EpicsSignalRO, 'Chip4_RBV')
acq_modes = ADCpt(EpicsSignalRO, 'AcqModes_RBV')
clock_read = ADCpt(EpicsSignalRO, 'ClockRead_RBV')
max_pulse_cnt = ADCpt(EpicsSignalRO, 'MaxPulseCnt_RBV')
max_pulse_hgt = ADCpt(EpicsSignalRO, 'MaxPulseHgt_RBV')
max_pulse_period = ADCpt(EpicsSignalRO, 'MaxPulsePeriod_RBV')
timer_max_val = ADCpt(EpicsSignalRO, 'TimerMaxVal_RBV')
timer_min_val = ADCpt(EpicsSignalRO, 'TimerMinVal_RBV')
timer_step = ADCpt(EpicsSignalRO, 'TimerStep_RBV')
clock_timepix = ADCpt(EpicsSignalRO, 'ClockTimepix_RBV')
fan1_pwm = ADCpt(EpicsSignalRO, 'Fan1PWM_RBV')
fan2_pwm = ADCpt(EpicsSignalRO, 'Fan2PWM_RBV')
bias_volt = ADCpt(SignalWithRBV, 'BiasVolt')
bias_enbl = ADCpt(SignalWithRBV, 'BiasEnbl')
chain_mode = ADCpt(SignalWithRBV, 'ChainMode')
trigger_in = ADCpt(SignalWithRBV, 'TriggerIn')
trigger_out = ADCpt(SignalWithRBV, 'TriggerOut')
polarity = ADCpt(SignalWithRBV, 'Polarity')
trigger_mode_c = ADCpt(EpicsSignalRO, 'TriggerModeC_RBV')
exposure_time = ADCpt(EpicsSignalRO, 'ExposureTime_RBV')
trigger_period = ADCpt(EpicsSignalRO, 'TriggerPeriod_RBV')
n_triggers = ADCpt(EpicsSignalRO, 'nTriggers_RBV')
det_orient = ADCpt(EpicsSignalRO, 'DetOrient_RBV')
periph_clk80 = ADCpt(SignalWithRBV, 'PeriphClk80')
trigger_delay = ADCpt(SignalWithRBV, 'TriggerDelay')
tdc = ADCpt(EpicsSignalRO, 'Tdc_RBV')
glbl_timestamp_intvl = ADCpt(SignalWithRBV, 'GlblTimestampIntvl')
ref_clock = ADCpt(SignalWithRBV, 'RefClock')
log_level = ADCpt(SignalWithRBV, 'LogLevel')
write_data = ADCpt(EpicsSignal, 'WriteData')
write_raw = ADCpt(SignalWithRBV, 'WriteRaw')
write_img = ADCpt(SignalWithRBV, 'WriteImg')
write_prv_img = ADCpt(SignalWithRBV, 'WritePrvImg')
write_prv_img1 = ADCpt(SignalWithRBV, 'WritePrvImg1')
write_prv_hst = ADCpt(SignalWithRBV, 'WritePrvHst')
raw_file_path = ADCpt(SignalWithRBV, 'RawFilePath')
raw_file_path_exists = ADCpt(EpicsSignalRO, 'RawFilePathExists_RBV')
raw_file_template = ADCpt(SignalWithRBV, 'RawFileTemplate')
raw_split_stg = ADCpt(SignalWithRBV, 'RawSplitStg')
raw_queue_size = ADCpt(SignalWithRBV, 'RawQueueSize')
img_file_path = ADCpt(SignalWithRBV, 'ImgFilePath')
img_file_path_exists = ADCpt(EpicsSignalRO, 'ImgFilePathExists_RBV')
img_file_template = ADCpt(SignalWithRBV, 'ImgFileTemplate')
img_file_fmt = ADCpt(SignalWithRBV, 'ImgFileFmt')
img_file_mode = ADCpt(SignalWithRBV, 'ImgFileMode')
img_intg_size = ADCpt(SignalWithRBV, 'ImgIntgSize')
img_intg_mode = ADCpt(SignalWithRBV, 'ImgIntgMode')
stp_on_dsk_lim = ADCpt(SignalWithRBV, 'StpOnDskLim')
img_queue_size = ADCpt(SignalWithRBV, 'ImgQueueSize')
prv_period = ADCpt(SignalWithRBV, 'PrvPeriod')
prv_smplg_mode = ADCpt(SignalWithRBV, 'PrvSmplgMode')
prv_img_file_path = ADCpt(SignalWithRBV, 'PrvImgFilePath')
prv_img_file_path_exists = ADCpt(EpicsSignalRO, 'PrvImgFilePathExists_RBV')
prv_img_file_template = ADCpt(SignalWithRBV, 'PrvImgFileTemplate')
prv_img_file_fmt = ADCpt(SignalWithRBV, 'PrvImgFileFmt')
prv_img_file_mode = ADCpt(SignalWithRBV, 'PrvImgFileMode')
prv_img_intg_size = ADCpt(SignalWithRBV, 'PrvImgIntgSize')
prv_img_intg_mode = ADCpt(SignalWithRBV, 'PrvImgIntgMode')
prv_stp_on_dsk_lim = ADCpt(SignalWithRBV, 'PrvStpOnDskLim')
prv_img_queue_size = ADCpt(SignalWithRBV, 'PrvImgQueueSize')
prv_img1_file_path = ADCpt(SignalWithRBV, 'PrvImg1FilePath')
prv_img1_file_fmt = ADCpt(SignalWithRBV, 'PrvImg1FileFmt')
prv_img1_file_mode = ADCpt(SignalWithRBV, 'PrvImg1FileMode')
prv_img1_intg_size = ADCpt(SignalWithRBV, 'PrvImg1IntgSize')
prv_img1_intg_mode = ADCpt(SignalWithRBV, 'PrvImg1IntgMode')
prv1_stp_on_dsk_lim = ADCpt(SignalWithRBV, 'Prv1StpOnDskLim')
prv_img1_queue_size = ADCpt(SignalWithRBV, 'PrvImg1QueueSize')
prv_hst_file_path = ADCpt(SignalWithRBV, 'PrvHstFilePath')
prv_hst_file_path_exists = ADCpt(EpicsSignalRO, 'PrvHstFilePathExists_RBV')
prv_hst_file_template = ADCpt(SignalWithRBV, 'PrvHstFileTemplate')
prv_hst_file_fmt = ADCpt(SignalWithRBV, 'PrvHstFileFmt')
prv_hst_file_mode = ADCpt(SignalWithRBV, 'PrvHstFileMode')
prv_hst_intg_size = ADCpt(SignalWithRBV, 'PrvHstIntgSize')
prv_hst_intg_mode = ADCpt(SignalWithRBV, 'PrvHstIntgMode')
prv_hst_stp_on_dsk_lim = ADCpt(SignalWithRBV, 'PrvHstStpOnDskLim')
prv_hst_queue_size = ADCpt(SignalWithRBV, 'PrvHstQueueSize')
trigger_mode = ADCpt(SignalWithRBV, 'TriggerMode')
data_type = ADCpt(SignalWithRBV, 'DataType')
color_mode = ADCpt(SignalWithRBV, 'ColorMode')
pel_evt_rate = ADCpt(EpicsSignalRO, 'PelEvtRate_RBV')
tdc_evt_rate = ADCpt(EpicsSignalRO, 'TdcEvtRate_RBV')
start_time = ADCpt(EpicsSignalRO, 'StartTime_RBV')
elapsed_time = ADCpt(EpicsSignalRO, 'ElapsedTime_RBV')
time_left = ADCpt(EpicsSignalRO, 'TimeLeft_RBV')
frame_cnt = ADCpt(EpicsSignalRO, 'FrameCnt_RBV')
dropped_frames = ADCpt(EpicsSignalRO, 'DroppedFrames_RBV')
status = ADCpt(EpicsSignalRO, 'Status_RBV')


class URLDetectorCam(CamBase):
_html_docs = ["URLDoc.html"]
urls = DDC(
Expand Down
6 changes: 6 additions & 0 deletions ophyd/areadetector/detectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"PvcamDetector",
"RoperDetector",
"SimDetector",
"TimePix3Detector",
"URLDetector",
"UVCDetector",
"Xspress3Detector",
Expand Down Expand Up @@ -242,6 +243,11 @@ class RoperDetector(DetectorBase):
cam = C(cam.RoperDetectorCam, "cam1:")


class TimePix3Detector(DetectorBase):
_html_docs = ['TimePix3Doc.html']
cam = C(cam.TimePix3DetectorCam, 'cam1:')


class URLDetector(DetectorBase):
_html_docs = ["URLDoc.html"]
cam = C(cam.URLDetectorCam, "cam1:")
Expand Down
4 changes: 2 additions & 2 deletions scripts/collect_ad_boilerplate.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ def parse_pv_structure(driver_dir):
# Ex:
# record(stringin, "$(P)$(R)Description_RBV") Splits into
# ['record(stringin, "$(P', '$(R', 'Description_RBV"', '']
# The PV name is the 3rd element, so array index 2, and we remove the last character, '"'
pv_name = line.split(")")[2][:-1]
# The PV name is the 2nd to last element element, so array index -2, and we remove the last character, '"'
pv_name = line.split(")")[-2][:-1]

# Check if it is a readback PV
if pv_name.endswith("_RBV"):
Expand Down