def test_records(request): info = conftest.run_example_ioc_by_name( 'caproto.ioc_examples.records', request=request, ) prefix = info.prefix # check that the alarm fields are linked b = f'{prefix}B' b_val = f'{prefix}B.VAL' b_stat = f'{prefix}B.STAT' b_severity = f'{prefix}B.SEVR' sync.write(b_val, 0, notify=True) assert list(sync.read(b_val).data) == [0] assert list(sync.read(b_stat).data) == [b'NO_ALARM'] assert list(sync.read(b_severity).data) == [b'NO_ALARM'] # write a special value that causes it to fail with pytest.raises(ca.ErrorResponseReceived): sync.write(b_val, 1, notify=True) # status should be WRITE, MAJOR assert list(sync.read(b_val).data) == [0] assert list(sync.read(b_stat).data) == [b'WRITE'] assert list(sync.read(b_severity).data) == [b'MAJOR'] # now a field that's linked back to the precision metadata: b_precision = f'{prefix}B.PREC' assert list(sync.read(b_precision).data) == [3] sync.write(b_precision, 4, notify=True) assert list(sync.read(b_precision).data) == [4] # does writing to .PREC update the ChannelData metadata? data = sync.read(b, data_type=ca.ChannelType.CTRL_DOUBLE) assert data.metadata.precision == 4
def poll_readiness(pv_to_check, attempts=15): logger.debug(f'Checking PV {pv_to_check}') start_repeater() for attempt in range(attempts): try: read(pv_to_check, timeout=1, repeater=False) except TimeoutError: continue else: break else: raise TimeoutError(f"ioc fixture failed to start in " f"{attempts} seconds (pv: {pv_to_check})")
def poll_readiness(pv_to_check, attempts=5, timeout=1): logger.debug(f'Checking PV {pv_to_check}') start_repeater() for attempt in range(attempts): try: read(pv_to_check, timeout=timeout, repeater=False) except (TimeoutError, ConnectionRefusedError): continue else: break else: raise TimeoutError(f"ioc fixture failed to start in " f"{attempts * timeout} seconds (pv: {pv_to_check})")
def test_records_subclass(request, prefix, ioc_name): info = conftest.run_example_ioc_by_name(ioc_name, request=request) prefix = info.prefix motor = f'{prefix}motor1' motor_val = f'{motor}.VAL' motor_rbv = f'{motor}.RBV' motor_drbv = f'{motor}.DRBV' sync.write(motor_val, 100, notify=True) # sleep for a few pollling periods: time.sleep(0.5) assert abs(sync.read(motor_rbv).data[0] - 100) < 0.1 assert abs(sync.read(motor_drbv).data[0] - 100) < 0.1
def test_limit_fields_and_description(request, prefix, context): pv = f'{prefix}C' run_example_ioc('caproto.ioc_examples.mocking_records', request=request, args=['--prefix', prefix], pv_to_check=pv) PV = get_pv(pv, context=context) def check_fields(): for k, v in PV.get_ctrlvars().items(): if k in field_map: fv, = read(f'{pv}.{field_map[k]}').data assert v == fv check_fields() for v in field_map.values(): work_pv = f'{pv}.{v}' write(work_pv, 2 * read(work_pv).data) check_fields() def string_read(pv): return b''.join(read(pv, data_type=ChannelType.STRING).data) assert string_read(f'{pv}.DESC') == b'The C pvproperty' write(f'{pv}.DESC', 'a new description', notify=True) assert string_read(f'{pv}.DESC') == b'a new description'
def test_pvproperty_string_array(request, ioc_name): info = conftest.run_example_ioc_by_name(ioc_name, request=request) array_string_pv = f'{info.prefix}array_string' sync.write(array_string_pv, ['array', 'of', 'strings'], notify=True) time.sleep(0.5) assert sync.read(array_string_pv).data == [b'array', b'of', b'strings']
def poll_readiness(pv_to_check, attempts=5, timeout=1, process=None): logger.debug(f'Checking PV {pv_to_check}') start_repeater() for _attempt in range(attempts): if process is not None and process.returncode is not None: raise TimeoutError(f'IOC process exited: {process.returncode}') try: read(pv_to_check, timeout=timeout, repeater=False) except (TimeoutError, ConnectionRefusedError): continue else: break else: raise TimeoutError(f"ioc fixture failed to start in " f"{attempts * timeout} seconds (pv: {pv_to_check})")
async def AdjustedAcquireTime(self, instance, value): open_delay = read(self.parent.shutter_prefix + 'ShutterOpenDelay_RBV').data close_delay = read(self.parent.shutter_prefix + 'ShutterCloseDelay_RBV').data if not open_delay + value + close_delay <= self.parent.AdjustedAcquirePeriod.readback.value: await self.parent.AdjustedAcquirePeriod.setpoint.write(open_delay + value + close_delay) write(self.parent.camera_prefix + 'AcquireTime', value + close_delay + open_delay) write(self.parent.shutter_prefix + 'ShutterTime', value + open_delay) await self.readback.write(value) return value
async def AdjustedAcquirePeriod(self, instance, value): readout_time = self.parent.ReadoutTime.value open_delay = read(self.parent.shutter_prefix + 'ShutterOpenDelay_RBV').data close_delay = read(self.parent.shutter_prefix + 'ShutterCloseDelay_RBV').data if not value - open_delay - close_delay >= self.parent.AdjustedAcquireTime.readback.value: await self.parent.AdjustedAcquireTime.setpoint.write(value - open_delay - close_delay) write(self.parent.camera_prefix + 'AcquirePeriod', value) write(self.parent.shutter_prefix + 'TriggerRate', 1. / value) await self.readback.write(value) return value
def test_pv_connection(name: str, timeout: int = 1): """ Tests whether CA can connect to a PV and get its value. Args: name (str): The PV. timeout (int, optional): PV connection timeout in seconds, Defaults to 1. Returns: (boolean): True if connected, False otherwise. """ try: read(pv_name=name, timeout=timeout) return True except Exception as e: manager_logger.error(e) return False
def test_process_field(request, prefix, async_lib): run_example_ioc('caproto.tests.ioc_process', request=request, args=['--prefix', prefix, '--async-lib', async_lib], pv_to_check=f'{prefix}record.PROC') write(f'{prefix}record.PROC', [1], notify=True) write(f'{prefix}record.PROC', [1], notify=True) assert read(f'{prefix}count').data[0] == 2
def test_mocking_records_subclass(request, prefix): from .conftest import run_example_ioc run_example_ioc('caproto.ioc_examples.mocking_records_subclass', request=request, args=['--prefix', prefix], pv_to_check=f'{prefix}motor1') from caproto.sync.client import read, write motor = f'{prefix}motor1' motor_val = f'{motor}.VAL' motor_rbv = f'{motor}.RBV' motor_drbv = f'{motor}.DRBV' write(motor_val, 100, notify=True) # sleep for a few pollling periods: time.sleep(0.5) assert abs(read(motor_rbv).data[0] - 100) < 0.1 assert abs(read(motor_drbv).data[0] - 100) < 0.1
def test_char_write(request, prefix): pv = f'{prefix}chararray' run_example_ioc('caproto.ioc_examples.type_varieties', request=request, args=['--prefix', prefix], pv_to_check=pv) write(pv, b'testtesttest', notify=True) response = read(pv) assert ''.join(chr(c) for c in response.data) == 'testtesttest'
def test_raw_timestamp(request): info = conftest.run_example_ioc_by_name( "caproto.ioc_examples.advanced.raw_timestamp", request=request) print("Triggering an update of value.") sync.write(f'{info.prefix}update', 1, notify=True) time.sleep(0.5) print("Reading back ``value``...") data = sync.read(f'{info.prefix}value', data_type='time') print(f"data={data} stamp={data.metadata.stamp}") assert data.metadata.stamp.nanoSeconds == 2**16 - 1
def test_long_strings(request, ioc_name): info = conftest.run_example_ioc_by_name(ioc_name, request=request) prefix = info.prefix stringin = f'{prefix}E' regular = sync.read(f'{stringin}.VAL', data_type='native') assert regular.data_type == ca.ChannelType.STRING data, = regular.data length = len(data) assert length > 1 # based on the default value in the test for dtype in ('native', 'control', 'time', 'graphic'): longstr = sync.read(f'{stringin}.VAL$', data_type=dtype) longstr_data = b''.join(longstr.data) expected_dtype = ca._dbr.field_types[dtype][ca.ChannelType.CHAR] assert longstr.data_type == expected_dtype assert len(longstr.data) == length assert longstr_data == data with pytest.raises(TimeoutError): # an analog input .VAL has no long string option sync.read(f'{prefix}A.VAL$', data_type='native')
async def AdjustedAcquire(self, instance, value): self._capture_goal = read(self.hdf5_prefix + 'NumCapture').data # write(self.shutter_prefix + 'TriggerEnabled', [int(value)]) # write(self.hdf5_prefix + 'Capture', [value]) print(f'comparing: {value} {instance.value}') if value != instance.value: write(self.camera_prefix + 'Acquire', [0]) # import time # time.sleep(1) write(self.camera_prefix + 'Acquire', [1]) # time.sleep(1) return value
def _run(self): from caproto.sync.client import (read, write, subscribe) if self.acquire: write(self.pvs['enabled'], [1]) write(self.pvs['image_mode'], 'Continuous', data_type=ChannelType.STRING) write(self.pvs['acquire'], [1], notify=False) width = read(self.pvs['array_size0']).data[0] height = read(self.pvs['array_size1']).data[0] depth = read(self.pvs['array_size2']).data[0] color_mode = read(self.pvs['color_mode']).data[0].decode('ascii') bayer_pattern = read(self.pvs['bayer_pattern']) bayer_pattern = bayer_pattern.data[0].decode('ascii') self.new_image_size.emit(width, height, depth, color_mode, bayer_pattern) print(f'width: {width} height: {height} depth: {depth} ' f'color_mode: {color_mode}') def update(response): if self.stop_event.is_set(): raise KeyboardInterrupt native_type = ca.field_types['native'][response.data_type] self.new_image.emit(response.metadata.timestamp, width, height, depth, color_mode, bayer_pattern, native_type, response.data) if self.barrier is not None: # Synchronize with image viewer widget, if necessary self.barrier.wait() sub = subscribe(self.pvs['array_data'], data_type='time') sub.add_callback(update) sub.block() self.stop_event.wait()
def test_write_without_notify(request, prefix, async_lib): pv = f'{prefix}pi' run_example_ioc('caproto.ioc_examples.type_varieties', request=request, args=['--prefix', prefix, '--async-lib', async_lib], pv_to_check=pv) write(pv, 3.179, notify=False) # We do not get notified so we have to poll for an update. for _attempt in range(20): if read(pv).data[0] > 3.178: break time.sleep(0.1) else: raise AssertionError("Server never processed WriteRequest.")
def test_pvproperty_string_array(request, prefix): from .conftest import run_example_ioc run_example_ioc('caproto.ioc_examples.scalars_and_arrays', request=request, args=['--prefix', prefix], pv_to_check=f'{prefix}scalar_int') from caproto.sync.client import read, write array_string_pv = f'{prefix}array_string' write(array_string_pv, ['array', 'of', 'strings'], notify=True) time.sleep(0.5) assert read(array_string_pv).data == [b'array', b'of', b'strings']
def test_mocking_records(request, prefix): from .conftest import run_example_ioc run_example_ioc('caproto.ioc_examples.mocking_records', request=request, args=['--prefix', prefix], pv_to_check=f'{prefix}A') from caproto.sync.client import read, write # check that the alarm fields are linked b = f'{prefix}B' b_val = f'{prefix}B.VAL' b_stat = f'{prefix}B.STAT' b_severity = f'{prefix}B.SEVR' write(b_val, 0, notify=True) assert list(read(b_val).data) == [0] assert list(read(b_stat).data) == [b'NO_ALARM'] assert list(read(b_severity).data) == [b'NO_ALARM'] # write a special value that causes it to fail with pytest.raises(ca.ErrorResponseReceived): write(b_val, 1, notify=True) # status should be WRITE, MAJOR assert list(read(b_val).data) == [0] assert list(read(b_stat).data) == [b'WRITE'] assert list(read(b_severity).data) == [b'MAJOR'] # now a field that's linked back to the precision metadata: b_precision = f'{prefix}B.PREC' assert list(read(b_precision).data) == [3] write(b_precision, 4, notify=True) assert list(read(b_precision).data) == [4] # does writing to .PREC update the ChannelData metadata? data = read(b, data_type=ca.ChannelType.CTRL_DOUBLE) assert data.metadata.precision == 4
def test_limit_fields(request, prefix, context): pv = f'{prefix}C' run_example_ioc('caproto.ioc_examples.mocking_records', request=request, args=['--prefix', prefix], pv_to_check=pv) PV = get_pv(pv, context=context) def check_fields(): for k, v in PV.get_ctrlvars().items(): if k in field_map: fv, = read(f'{pv}.{field_map[k]}').data assert v == fv check_fields() for v in field_map.values(): work_pv = f'{pv}.{v}' write(work_pv, 2 * read(work_pv).data) check_fields()
def test_ioc_examples(request, module_name, async_lib): from caproto.server import PvpropertyReadOnlyData info = conftest.run_example_ioc_by_name(module_name, async_lib=async_lib, request=request) put_values = [ (PvpropertyReadOnlyData, None), (ca.ChannelNumeric, [1]), (ca.ChannelString, ['USD']), (ca.ChannelChar, 'USD'), (ca.ChannelByte, b'USD'), (ca.ChannelEnum, [0]), ] skip_pvs = [('ophyd', ':exit')] def find_put_value(pv, channeldata): 'Determine value to write to pv' for skip_ioc, skip_suffix in skip_pvs: if skip_ioc in module_name: if pv.endswith(skip_suffix): return None for put_class, put_value in put_values: if isinstance(channeldata, put_class): return put_value else: raise Exception('Failed to set default value for channeldata:' f'{channeldata.__class__}') for pv, channeldata in info.pvdb.items(): value = find_put_value(pv, channeldata) if value is None: print(f'Skipping write to {pv}') continue print(f'Writing {value} to {pv}') sync.write(pv, value, timeout=15) value = sync.read(pv, timeout=15) print(f'Read {pv} = {value}')
def get_instrument_list(): """ Retrieve the instrument list. Returns: (list): instruments with their host names """ err_msg = "Error getting instrument list:" try: bytes_data = read(INST_LIST_PV).data raw = ints_to_string([int(x) for x in bytes_data]) except CaprotoError as e: logger.error(f"{err_msg} {e}") return [] try: full_inst_list_string = dehex_and_decompress(raw) full_inst_list = json.loads(full_inst_list_string) except Exception as e: logger.error(f"{err_msg} {e}") return [] return full_inst_list
def _test_ioc_examples(request, module_name, pvdb_class_name, class_kwargs, prefix, async_lib='curio'): from .conftest import run_example_ioc from caproto.sync.client import read, write from caproto.server import PvpropertyReadOnlyData import subprocess module = __import__(module_name, fromlist=(module_name.rsplit('.', 1)[-1], )) pvdb_class = getattr(module, pvdb_class_name) print(f'Prefix: {prefix} PVDB class: {pvdb_class}') pvdb = pvdb_class(prefix=prefix, **class_kwargs).pvdb pvs = list(pvdb.keys()) pv_to_check = pvs[0] print(f'PVs:', pvs) print(f'PV to check: {pv_to_check}') stdin = (subprocess.DEVNULL if 'io_interrupt' in module_name else None) print('stdin=', stdin) run_example_ioc(module_name, request=request, args=['--prefix', prefix, '--async-lib', async_lib], pv_to_check=pv_to_check, stdin=stdin) print(f'{module_name} IOC now running') put_values = [ (PvpropertyReadOnlyData, None), (ca.ChannelNumeric, [1]), (ca.ChannelString, ['USD']), ] skip_pvs = [('ophyd', ':exit')] def find_put_value(pv): 'Determine value to write to pv' for skip_ioc, skip_suffix in skip_pvs: if skip_ioc in module_name: if pv.endswith(skip_suffix): return None for put_class, put_value in put_values: if isinstance(channeldata, put_class): return put_value else: raise Exception('Failed to set default value for channeldata:' f'{channeldata.__class__}') for pv, channeldata in pvdb.items(): value = find_put_value(pv) if value is None: print(f'Skipping write to {pv}') continue print(f'Writing {value} to {pv}') write(pv, value) value = read(pv) print(f'Read {pv} = {value}')
def get_VAL(self): from caproto.sync.client import read value = read(self.prefix + 'VAL') return value
def get_RBV(self): from caproto.sync.client import read value = read(self.prefix + 'RBV') return value
def string_read(pv): return b''.join(read(pv, data_type=ChannelType.STRING).data)
def check_fields(): for k, v in PV.get_ctrlvars().items(): if k in field_map: fv, = read(f'{pv}.{field_map[k]}').data assert v == fv
def test_ioc(ioc): print(f'This is a {ioc.type} IOC. Process={ioc.process}') print(f'Name: {ioc.name}') print(f'Available PVs: {ioc.pvs.items()}') if ioc.type == 'epics-base': read(f'{ioc.prefix}ao1') # test a PV from the pyepics 'debug' IOC
def string_read(pv): return b''.join(sync.read(pv, data_type=ca.ChannelType.STRING).data)