def __init__(self, prefix, ad_prefix, stream, enable_callbacks=0, min_cbtime=0, queuesize=5): """ Parameters ---------- prefix: str The plugin prefix that comes after the areaDetector prefix in the PV names. ad_prefix: str The base areaDetector control prefix. This should match a real areaDetector IOC's prefix. stream: str The image stream to use for the plugins. We'll be using: $(ad_prefix)$(stream):ArrayData for values $(ad_prefix)$(stream):UniqueId_RBV for update monitoring enable_callbcaks: bool, optional If True, start the IOC with callbacks enabled. Start disabled otherwise. min_cbtime: float, optional The initial value for the minimum time for each callback loop. queuesize: int, optional The initial value for the array queue. The default is 5. """ self.server = PypvServer(ad_prefix + prefix) self.ad_prefix = ad_prefix self.ad_directory = {} self.settings_lock = RLock() self.plugins = {} self.has_update = Event() self.enable_callbacks = int(enable_callbacks) self.min_cbtime = float(min_cbtime) self.queue = None queuesize = int(queuesize) self._ndarray_port_cb(value=str(stream)) self._add_builtin('NDArrayPort', str(stream), cb=self._ndarray_port_cb) self._enable_callbacks_cb(value=self.enable_callbacks) self._add_builtin('EnableCallbacks', self.enable_callbacks, cb=self._enable_callbacks_cb) self._min_cbtime_cb(value=self.min_cbtime) self._add_builtin('MinCallbackTime', self.min_cbtime, cb=self._min_cbtime_cb) self._queuesize_cb(value=queuesize) self._add_builtin('QueueSize', queuesize, cb=self._queuesize_cb) self._add_builtin('QueueUse', 0) self._add_builtin('DroppedArrays', 0) arrays = CAThread(target=self._array_cb_loop, args=(), daemon=True) plugins = Thread(target=self._get_queue_loop, args=(), daemon=True) arrays.start() plugins.start()
def setup(self): """Set up the server. Starts threads and registers for EPICS callbacks. """ self._publisher_thread = CAThread(target=self._publisher, args=(self.update_addr, ), daemon=True) self._publisher_thread.start() self._request_thread = CAThread(target=self._request_handler, args=(self.request_addr, ), daemon=True) self._request_thread.start() for attr in self.robot.attrs: pv = getattr(self.robot, attr) pv.add_callback(self._pv_callback) self.robot.client_update.add_callback(self._on_robot_update) self.logger.debug('setup complete')
def start_processes(self, acquire_pv, counter_pv_name, data_pv, frame_type_pv, logger, reportq, *args, **kwargs): """ This function starts processes and callbacks. This is a main thread that starts thread reacting to the callback, starts the consuming process, and sets a callback on the frame counter PV change. The function then awaits for the data in the exit queue that indicates that all frames have been processed. The functin cancells the callback on exit. Parameters ---------- counter_pv : str a PV string for the area detector frame counter data_pv : str a PV string for the area detector frame data frame_type_pv : str a PV string for the area detector data type logger : Logger a Logger instance, typically synchronized with the consuming process logger *args : list a list of arguments specific to the client process Returns ------- None """ data_thread = CAThread(target=self.deliver_data, args=(data_pv, frame_type_pv, logger,)) data_thread.start() p = Process(target=handler.handle_data, args=(self.process_dataq, reportq, args, kwargs,)) p.start() self.counter_pv = PV(counter_pv_name) self.counter_pv.add_callback(self.on_ctr_change, index=1) self.acq_pv = PV(acquire_pv) self.acq_pv.add_callback(self.acq_done, index=2) try: callback_pv_name = kwargs['callback_pv'] self.callback_pv = PV(callback_pv_name) self.callback_pv.add_callback(self.on_change, as_string=True, index=3) except KeyError: pass
def atl(softioc, caclient, tmpdir_factory): AbortCh.fields['ACNT'] = ':ACNT' AbortCh.fields['TCNT'] = ':TCNT' dburi = ('sqlite:///' + str(tmpdir_factory.mktemp('data').join('testdata.db')) ) insert_current_pv_mock(dburi) set_initial_abort_state() atl = Aborttl(dburi, 'ET_dummyHost:RESETw') thread = CAThread(target=atl.run) thread.daemon = True thread.start() time.sleep(5) yield atl atl.stop() thread.join() time.sleep(1)
def start_processes(self, counter_pv, data_pv, frame_type_pv, logger, *args): """ This function starts processes and callbacks. This is a main thread that starts thread reacting to the callback, starts the consuming process, and sets a callback on the frame counter PV change. The function then awaits for the data in the exit queue that indicates that all frames have been processed. The functin cancells the callback on exit. Parameters ---------- counter_pv : str a PV string for the area detector frame counter data_pv : str a PV string for the area detector frame data frame_type_pv : str a PV string for the area detector data type logger : Logger a Logger instance, typically synchronized with the consuming process logger *args : list a list of arguments specific to the client process Returns ------- None """ data_thread = CAThread(target=self.deliver_data, args=( data_pv, frame_type_pv, logger, )) data_thread.start() adapter.start_process(self.process_dataq, logger, *args) self.cntr_pv = PV(counter_pv) self.cntr_pv.add_callback(self.on_change, index=1)
def _process_request(self, message): """Parse requests from the clients and take the appropriate action.""" self.logger.debug('client request: %r', message) operation = message.get('operation') parameters = message.get('parameters', {}) try: target = getattr(self, operation) except (AttributeError, TypeError): self.logger.error('operation does not exist: %r', operation) return {'error': 'invalid request: operation does not exist'} try: operation_type = target._operation_type except AttributeError: self.logger.error('%r must be declared an operation', operation) return { 'error': 'invalid request: %r not an operation' % operation } try: sig = inspect.signature(target) if operation_type == 'query': sig.bind(**parameters) else: sig.bind(None, **parameters) # Must accept a handle argument except (ValueError, TypeError): self.logger.error('invalid arguments for operation %r: %r', operation, parameters) return {'error': 'invalid request: incorrect arguments'} self.logger.debug('calling: %r with %r', operation, parameters) if operation_type == 'query': return target(**parameters) elif operation_type in {'foreground', 'background'}: handle = self._next_handle() thread = CAThread(target=target, args=(handle, ), kwargs=parameters, daemon=True) thread.start() return {'error': None, 'handle': handle} else: return {'error': 'invalid request: unknown operation type'}
def start_processes(self): """ This function starts processes and callbacks. This is a main thread that starts thread reacting to the callback, starts the consuming process, and sets a callback on the frame counter PV change. The function then awaits for the data in the exit queue that indicates that all frames have been processed. The functin cancells the callback on exit. Parameters ---------- none Returns ------- nothing """ data_thread = CAThread(target=self.handle_event, args=()) data_thread.start() self.counter_pv = PV(self.get_counter_pv_name()) self.counter_pv.add_callback(self.on_change, index=1) self.acq_pv = PV(self.get_acquire_pv_name()) self.acq_pv.add_callback(self.acq_done, index=2)
def test_cathread(): write( 'Test use CAThread\n') th1 = CAThread(target=run_CAThread, args=(names_a, 3, 'A')) th2 = CAThread(target=run_CAThread, args=(names_b, 5, 'B')) run_threads((th1, th2))
stdout.flush() # epics.ca.use_initial_context() # epics.ca.create_context() start_time = time.time() pvs = [epics.PV(pvn, callback=onChanges) for pvn in pvnames] while time.time() - start_time < runtime: time.sleep(0.001) [p.clear_callbacks() for p in pvs] stdout.write('Completed Thread %s\n' % (run_name)) stdout.write("First, create a PV in the main thread:\n") for pvname in pvlist_a + pvlist_b: p = epics.PV(pvname) p.connect() p.get() print(p.info) stdout.write("Run 2 Background Threads simultaneously:\n") th1 = CAThread(target=run_test, args=(30, pvlist_a, 'A')) th1.start() th2 = CAThread(target=run_test, args=(60, pvlist_b, 'B')) th2.start() th2.join() th1.join() stdout.write('Done\n')
# pvs_b.append(pvname) names_b.append(pvname) names_a = names_b[1:] pvs_a = pvs_b[1:] epics.ca.create_context() styles = ('decorator', 'init', 'cathread') style = styles[2] if style == 'init': write( 'Test use plain threading.Thread, force use of initial CA Context \n') th1 = Thread(target=test_initcontext, args=(names_a, 2, 'A')) th2 = Thread(target=test_initcontext, args=(names_b, 3, 'B')) run_threads((th1, th2)) elif style == 'decorator': write('Test use plain threading.Thread, withInitialContext decorator\n') th1 = Thread(target=test_decorator, args=(names_a, 3, 'A')) th2 = Thread(target=test_decorator, args=(names_b, 5, 'B')) run_threads((th1, th2)) elif style == 'cathread': write('Test use CAThread\n') th1 = CAThread(target=test_CAThread, args=(names_a, 3, 'A')) th2 = CAThread(target=test_CAThread, args=(names_b, 5, 'B')) run_threads((th1, th2)) write('Test Done\n---------------------\n')