def pitch_pvs(pitchid): x = { ':P%d:Select' % pitchid: PV('select_%d' % pitchid, read_only=False, doc='Select pitch', type='int'), ':P%d:Selectable' % pitchid: PV('selectable_%d' % pitchid, type='int', read_only=True, doc='Pitch can be ' 'selected'), ':P%d:Selected' % pitchid: PV('selected_%d' % pitchid, type='int', read_only=True, doc='Pitch is selected'), ':P%d:ParkPosition' % pitchid: PV('park_position_%d' % pitchid, doc='Pitch is parked', type='int', read_only=True), ':P%d:Alarm' % pitchid: PV('alarm_%d' % pitchid, read_only=True, type='int') } return x
class VerySimpleInterface(EpicsInterface): """ This is the EPICS interface to a quite simple device. It offers 5 PVs that expose different things that are part of the device, the interface or neither. """ pvs = { "Param-Raw": PV("param", type="int", doc="The raw underlying parameter."), "Param": PV(("get_param", "set_param"), type="int"), "Second": PV("second", meta_data_property="param_raw_meta"), "Second-Int": PV("second_int", type="int"), "Constant": PV(lambda: 4, doc="A constant number."), } @property def param_raw_meta(self): return { "lolo": self.device.lower_limit, "hihi": self.device.upper_limit } @property def second_int(self): """The second parameter as an integer.""" return int(self.device.second)
class VerySimpleInterface(EpicsInterface): """ This is the EPICS interface to a quite simple device. It offers 5 PVs that expose different things that are part of the device, the interface or neither. """ pvs = { 'Param-Raw': PV('param', type='int', doc='The raw underlying parameter.'), 'Param': PV(('get_param', 'set_param'), type='int'), 'Second': PV('second', meta_data_property='param_raw_meta'), 'Second-Int': PV('second_int', type='int'), 'Constant': PV(lambda: 4, doc='A constant number.') } @property def param_raw_meta(self): return { 'lolo': self.device.lower_limit, 'hihi': self.device.upper_limit } @property def second_int(self): """The second parameter as an integer.""" return int(self.device.second)
def _bind_device(self): self.pvs = {} for module in self.device.modules: for param in self.device.get_parameters(module): param_properties = self.device.get_properties(module, param) param_type = self.type_map.get(param_properties['validator'], None) if param_type is not None: pv_name = module + ':' + param self.log.debug('Generating PV %s of type %s', pv_name, param_type) self.pvs[pv_name] = PV( (lambda modu=module, par=param: self.device. get_parameter(modu, par), lambda value, modu=module, par=param: self.device. set_parameter(modu, par, value)), type=param_type, count=40 if param_type == 'char' else 1) else: self.log.warn( 'Param %s of module %s has type that can not be mapped to EPICS: %s', param, module, param_properties['validator']) super(SecopEpicsInterface, self)._bind_device()
class ChopperEpicsInterface(EpicsInterface): """ ESS chopper EPICS interface Interaction with this interface should happen via ChannelAccess (CA). The PV-names usually carry a prefix which depends on the concrete device and environment, so it is omitted in this description. The dynamically generated description of the PVs does however contain the prefix so that the names can be copy-pasted easily. The first step is to initialize the chopper, for example via caput on the command line: $ caput CmdS init After this, the chopper is in a state where it can be started: $ caget State State stopped To set a specific speed and phase, the setpoints have to be configured via caput: $ caput Spd 100 $ caput Phs 34.5 Then the chopper can be commanded to move towards those values: $ caput CmdS start Now the disc accelerates to the setpoints, the state should now be different: $ caget State State accelerating The possible commands are part of the PV-specific documentation. """ pvs = { 'Spd-RB': PV('target_speed', read_only=True, doc='Readback value of the speed setpoint in Hz.'), 'Spd': PV('target_speed', doc='Speed setpoint in Hz.'), 'ActSpd': PV('speed', read_only=True, doc='Current rotation speed of the chopper disc in Hz.'), 'Phs-RB': PV('target_phase', read_only=True, doc='Readback value of phase setpoint in degrees.'), 'Phs': PV('target_phase', doc='Phase setpoint in degrees.'), 'ActPhs': PV('phase', read_only=True, doc='Current phase of the chopper disc in degrees.'), 'ParkAng-RB': PV('target_parking_position', read_only=True, doc= 'Readback value of the discs parking position setpoint in degrees.' ), 'ParkAng': PV('target_parking_position', doc='The discs parking position setpoint in degrees.'), 'AutoPark': PV('auto_park', doc='If enabled, the chopper disc will be moved to the parking ' 'position automatically when the speed is 0 or the chopper ' 'is otherwise stopped. 0 means False, 1 means True, the string ' 'representations of the enum values are "false" and "true".', type='enum', enums=['false', 'true']), 'State': PV('state', read_only=True, type='string'), 'CmdS': PV('execute_command', type='string'), 'CmdL': PV('last_command', type='string', read_only=True), } _commands = { 'start': 'start', 'stop': 'stop', 'set_phase': 'lock_phase', 'unlock': 'unlock', 'park': 'park', 'init': 'initialize', 'deinit': 'deinitialize' } _last_command = '' @property def execute_command(self): """ Command to execute. Possible commands are start, stop, set_phase, unlock, park, init, deinit. """ return '' @execute_command.setter def execute_command(self, value): command = self._commands.get(value) getattr(self.device, command)() self._last_command = command @property def last_command(self): """ The last command that was executed successfully. """ return self._last_command
class SpsS7EpicsInterface(EpicsInterface): pvs = { ':MCU1:FineAdjustment:Select': PV('fa_select1', doc='Enable fine adjustment of the ' 'mirrors', type='int'), ':MCU2:FineAdjustment:Select': PV('fa_select2', doc='Enable fine adjustment of the ' 'mirrors', type='int'), ':MCU1:FineAdjustment:Selected': PV('fa_read1', doc='Fine adjustment selected', read_only=True, type='int'), ':MCU2:FineAdjustment:Selected': PV('fa_read2', doc='Fine adjustment selected', read_only=True, type='int'), ':MCU2:Move': PV('move', doc='NOT WORKING -- Motor is moving', read_only=True, type='int'), ':MCU1:Move': PV('move', doc='NOT WORKING -- Motor is moving', read_only=True, type='int'), '.AOUT': PV('aout', doc='Direct connection to EPICS asyn Octet', type='string'), '.AINP': PV('ainp', doc='Readback from EPICS asyn Octet', type='string'), } for pid in range(1, 37): pvs.update(pitch_pvs(pid)) _commands = { 'start': 'start', 'stop': 'stop', } _last_command = '' @property def execute_command(self): """ Command to execute. Possible commands are start, stop. """ return '' @execute_command.setter def execute_command(self): command = self._commands.get(value) getattr(self.device, command)() self._last_command = command @property def last_command(self): """ The last command that was executed successfully. """ return self._last_command
class ExampleMotorEpicsInterface(EpicsInterface): pvs = { 'Pos': PV('position', read_only=True, unit='mm', doc='Current position of the motor'), 'Tgt': PV('target', meta_data_property='target_meta', unit='mm', doc= 'Target of motor. Changing the target automatically moves the motor.' ), 'Spd': PV('speed', unit='mm/s', lolim='0', hilim='10', doc='Speed of motor in mm/s'), 'Stop': PV('stop', type='int', lolim=1, hilim=1), 'Stat': PV('state', type='string', doc='Current state of the motor, either idle or moving.') } target_lolim = 10 target_hilim = 200 @property def target(self): return self._device.target @target.setter @check_limits('target_lolim', 'target_hilim') def target(self, new_target): if self.device.state != 'idle': raise AccessViolationException( 'Can not change target while motor is moving.') self._device.target = new_target @property def target_meta(self): return {'lolim': self.target_lolim, 'hilim': self.target_hilim} @target_meta.setter def target_meta(self, new_target_meta): pass @property def speed(self): return self._device.speed @speed.setter @check_limits(0, 10) def speed(self, new_speed): self._device.speed = new_speed @property def stop(self): """ Write 1 to this PV to stop the motor. Other values are silently ignored. """ return 0 @stop.setter def stop(self, stop_value): if stop_value == 1: self._device.stop()
class ChopperEpicsInterface(EpicsInterface): """ ESS chopper EPICS interface Interaction with this interface should happen via ChannelAccess (CA). The PV-names usually carry a prefix which depends on the concrete device and environment, so it is omitted in this description. The dynamically generated description of the PVs does however contain the prefix so that the names can be copy-pasted easily. The first step is to initialize the chopper, for example via caput on the command line: $ caput CmdS init After this, the chopper is in a state where it can be started: $ caget State State stopped To set a specific speed and phase, the setpoints have to be configured via caput: $ caput Spd 100 $ caput Phs 34.5 Then the chopper can be commanded to move towards those values: $ caput CmdS start Now the disc accelerates to the setpoints, the state should now be different: $ caget State State accelerating The possible commands are part of the PV-specific documentation. """ pvs = { "Spd-RB": PV( "target_speed", read_only=True, doc="Readback value of the speed setpoint in Hz.", ), "Spd": PV("target_speed", doc="Speed setpoint in Hz."), "ActSpd": PV( "speed", read_only=True, doc="Current rotation speed of the chopper disc in Hz.", ), "Phs-RB": PV( "target_phase", read_only=True, doc="Readback value of phase setpoint in degrees.", ), "Phs": PV("target_phase", doc="Phase setpoint in degrees."), "ActPhs": PV( "phase", read_only=True, doc="Current phase of the chopper disc in degrees." ), "ParkAng-RB": PV( "target_parking_position", read_only=True, doc="Readback value of the discs parking position setpoint in degrees.", ), "ParkAng": PV( "target_parking_position", doc="The discs parking position setpoint in degrees.", ), "AutoPark": PV( "auto_park", doc="If enabled, the chopper disc will be moved to the parking " "position automatically when the speed is 0 or the chopper " "is otherwise stopped. 0 means False, 1 means True, the string " 'representations of the enum values are "false" and "true".', type="enum", enums=["false", "true"], ), "State": PV("state", read_only=True, type="string"), "CmdS": PV("execute_command", type="string"), "CmdL": PV("last_command", type="string", read_only=True), } _commands = { "start": "start", "stop": "stop", "set_phase": "lock_phase", "unlock": "unlock", "park": "park", "init": "initialize", "deinit": "deinitialize", } _last_command = "" @property def execute_command(self): """ Command to execute. Possible commands are start, stop, set_phase, unlock, park, init, deinit. """ return "" @execute_command.setter def execute_command(self, value): command = self._commands.get(value) getattr(self.device, command)() self._last_command = command @property def last_command(self): """ The last command that was executed successfully. """ return self._last_command
class MotorEpicsInterface(EpicsInterface): """ Motor EPICS interface """ pvs = { 'RBV': PV('position', read_only=True, doc='Readback value of the position setpoint in mm.'), 'VAL': PV('target', doc='Position setpoint in mm.'), 'STOP': PV('stop', doc='Force the motor to stop '), 'DMOV': PV('done_moving', read_only=True, doc='True if the motor has finished its movement.'), 'MOVN': PV('moving', read_only=True, doc='True if the motor is moving.'), 'MISS': PV('miss', read_only=True, doc='True if the motor couldn\'t reach the target.'), 'HOMF': PV('homf', read_only=True, doc='.'), 'HOMR': PV('homr', doc='.'), 'VELO': PV('speed', doc='motor_velocity'), 'OFF': PV('motor_offset', doc='Initial offset of the motor'), 'HLM': PV('high_limit', read_only=True, doc='Hardware high limit in mm'), 'LLM': PV('low_limit', read_only=True, doc='Hardware low limit in mm'), 'LVIO': PV('soft_limit', doc='Soft limit in mm'), 'HLS': PV('high_limit_switch', doc='High limit switch in mm'), 'LLS': PV('low_limit_switch', doc='Low limit switch in mm'), 'CNEN': PV('cnen'), 'MsgTxt': PV('error_message', read_only=True, type='string', doc='Error message'), 'State': PV('state', read_only=True, type='string'), } _commands = { 'start': 'start', 'stop': 'stop', } _last_command = '' # def __init__(self): # EpicsInterface.__init__(self) # MotorEpicsInterfaceFactory(['t1', 't2']) @property def execute_command(self): """ Command to execute. Possible commands are start, stop. """ return '' @execute_command.setter def execute_command(self, value): command = self._commands.get(value) getattr(self.device, command)() self._last_command = command @property def last_command(self): """ The last command that was executed successfully. """ return self._last_command
class PetEpicsInterface(EpicsInterface): """ This is the EPICS interface to a simulated pet. Keep it happy by feeding it, tucking it in, whashing it and playing with it or it dies after a while. """ actions = ['none', 'feed', 'tuck_in', 'wash', 'play'] pvs = { 'energy': PV('energy', read_only=True, type='int', low=35, lolo=5, doc='Energy level of the pet, should be above 35, 5 is critical.'), 'tired': PV('tired', read_only=True, type='int', high=80, hihi=95, doc='Tiredness of the pet, should be below 80, 95 is critical.'), 'bored': PV('bored', read_only=True, type='int', high=75, doc='How bored the pet is. Should be below 75.'), 'clean': PV('clean', read_only=True, type='int', low=25, lolo=5, doc='Cleanliness of the pet, should be above 25, 5 is critical.'), 'state': PV('state', read_only=True, type='string', doc='Indicates what the pet is doing at the moment.'), 'age': PV('age', read_only=True, type='int', unit='m', doc='The age of the pet in months.'), 'name': PV('name', type='string'), 'action': PV('action', type='enum', enums=actions) } last_action = 0 @property def name(self): """The name of the pet. Has to be set before the simulation starts.""" return self._device.name or 'None yet!' @name.setter def name(self, new_name): self._device.name = new_name @property def action(self): """An action to perform. Will make the pet busy for a while""" return 0 @action.setter def action(self, new_action): if new_action > 0: getattr(self._device, self.actions[new_action])()