class ScanPointTickerController(Controller): def create_attributes(self): self.value = Attribute(NumberMeta(description="Value")) self.value.meta.set_dtype('float64') yield 'value', self.value self.generator = Attribute( PointGeneratorMeta(description="Scan Point Generator")) yield "generator", self.generator self.axis_name = Attribute(StringMeta(description="Name of the axis")) yield "axis_name", self.axis_name self.exposure = Attribute(NumberMeta(description="Exposure time")) self.value.meta.set_dtype('float64') yield "exposure", self.exposure @takes("generator", PointGeneratorMeta( description="Generator instance"), REQUIRED, "axis_name", StringMeta( description="Specifier for axis"), REQUIRED, "exposure", NumberMeta( description="Detector exposure time"), REQUIRED) def configure(self, params): """ Configure the controller Args: generator(PointGenerator): Generator to create points axis_name(String): Specifier for axis exposure(Double): Exposure time for detector """ self.generator.set_value(params.generator) self.axis_name.set_value(params.axis_name) self.exposure.set_value(params.exposure) self.exposure.meta.set_dtype('float64') self.block.notify_subscribers() @Method.wrap_method def run(self): """ Start the ticker process Yields: Point: Scan points from PointGenerator """ axis_name = self.axis_name.value for point in self.generator.value.iterator(): self.value.set_value(point.positions[axis_name]) self.block.notify_subscribers() time.sleep(self.exposure.value)
class ScanPointTickerController(Controller): def create_attributes(self): self.value = Attribute(NumberMeta(description="Value")) self.value.meta.set_dtype('float64') yield 'value', self.value self.generator = Attribute( PointGeneratorMeta(description="Scan Point Generator")) yield "generator", self.generator self.axis_name = Attribute(StringMeta(description="Name of the axis")) yield "axis_name", self.axis_name self.exposure = Attribute(NumberMeta(description="Exposure time")) self.value.meta.set_dtype('float64') yield "exposure", self.exposure @takes("generator", PointGeneratorMeta(description="Generator instance"), REQUIRED, "axis_name", StringMeta(description="Specifier for axis"), REQUIRED, "exposure", NumberMeta(description="Detector exposure time"), REQUIRED) def configure(self, params): """ Configure the controller Args: generator(PointGenerator): Generator to create points axis_name(String): Specifier for axis exposure(Double): Exposure time for detector """ self.generator.set_value(params.generator) self.axis_name.set_value(params.axis_name) self.exposure.set_value(params.exposure) self.exposure.meta.set_dtype('float64') self.block.notify_subscribers() @Method.wrap_method def run(self): """ Start the ticker process Yields: Point: Scan points from PointGenerator """ axis_name = self.axis_name.value for point in self.generator.value.iterator(): self.value.set_value(point.positions[axis_name]) self.block.notify_subscribers() time.sleep(self.exposure.value)
class CounterController(Controller): def create_attributes(self): self.counter = Attribute(NumberMeta(description="A counter")) self.counter.meta.set_dtype('uint32') self.counter.set_put_function(self.counter.set_value) self.counter.set_value(0) yield "counter", self.counter @Controller.Resetting def do_reset(self): self.counter.set_value(0, notify=False) # Transition will do the notify for us @takes() def increment(self): self.counter.set_value(self.counter.value + 1)
class CAPart(Part): def create_attributes(self): params = self.params if params.pv is None and params.rbv is None: raise ValueError('must pass pv rbv') if params.rbv is None: if params.rbv_suff is None: params.rbv = params.pv else: params.rbv = params.pv + params.rbv_suff # Meta instance self.name = params.name self.meta = self.create_meta(params.description) # Pv strings self.pv = params.pv self.rbv = params.rbv # camonitor subscription self.monitor = None self.ca_format = catools.FORMAT_CTRL # This will be our attr self.attr = None # The attribute we will be publishing self.attr = Attribute(self.meta) self.attr.set_put_function(self.caput) yield self.name, self.attr def create_meta(self, description): raise NotImplementedError def get_datatype(self): raise NotImplementedError @Controller.Resetting def connect_pvs(self): # release old monitor self.close_monitor() # make the connection in cothread's thread, use caget for initial value pvs = [self.rbv] if self.pv: pvs.append(self.pv) ca_values = cothread.CallbackResult( catools.caget, pvs, format=self.ca_format, datatype=self.get_datatype()) # check connection is ok for i, v in enumerate(ca_values): assert v.ok, "CA connect failed with %s" % v.state_strings[v.state] self.update_value(ca_values[0]) # now setup monitor on rbv self.monitor = catools.camonitor( self.rbv, self.on_update, notify_disconnect=True, format=self.ca_format, datatype=self.get_datatype()) def close_monitor(self): if self.monitor is not None: cothread.CallbackResult(self.monitor.close) self.monitor = None def caput(self, value): cothread.CallbackResult( catools.caput, self.pv, value, wait=True, timeout=None, datatype=self.get_datatype()) # now do a caget value = cothread.CallbackResult( catools.caget, self.rbv, format=self.ca_format, datatype=self.get_datatype()) self.update_value(value) def on_update(self, value): # Called on cothread's queue, so don't block self.process.spawn(self.update_value, value) def update_value(self, value): self.log_debug("Camonitor update %r", value) # TODO: make Alarm from value.status and value.severity # TODO: make Timestamp from value.timestamp if not value.ok: # TODO: set disconnect self.attr.set_value(None) else: # update value self.attr.set_value(value)