Code Listing#

Here is the full listing of the Linkam class code.

An up-to-date version can be found here at BMM’s GitHub site.

Note that the status() method makes use of convenience tools explained in Colored text in bsui. They are imported at lines 4 and 5 and used in several places.

  1     from ophyd import Component as Cpt, EpicsSignal, EpicsSignalRO, PVPositioner
  2     from ophyd.signal import DerivedSignal
  3
  4     from BMM.functions import boxedtext
  5     from BMM.functions import error_msg, go_msg
  6
  7     class AtSetpoint(DerivedSignal):
  8         '''A signal that does bit-wise arithmetic on the Linkam's status code'''
  9         def __init__(self, parent_attr, *, parent=None, **kwargs):
 10             code_signal = getattr(parent, parent_attr)
 11             super().__init__(derived_from=code_signal, parent=parent, **kwargs)
 12
 13         def inverse(self, value):
 14             if int(value) & 2 == 2:
 15                 return 1
 16             else:
 17                 return 0
 18
 19         def forward(self, value):
 20             return value
 21
 22     class Linkam(PVPositioner):
 23         '''An ophyd wrapper around the Linkam T96 controller
 24         '''
 25
 26         ## following https://blueskyproject.io/ophyd/positioners.html#pvpositioner
 27         readback = Cpt(EpicsSignalRO, 'TEMP')
 28         setpoint = Cpt(EpicsSignal, 'SETPOINT:SET')
 29         status_code = Cpt(EpicsSignal, 'STATUS')
 30         done = Cpt(AtSetpoint, parent_attr = 'status_code')
 31
 32         ## all the rest of the Linkam signals
 33         init = Cpt(EpicsSignal, 'INIT')
 34         model_array = Cpt(EpicsSignal, 'MODEL')
 35         serial_array = Cpt(EpicsSignal, 'SERIAL')
 36         stage_model_array = Cpt(EpicsSignal, 'STAGE:MODEL')
 37         stage_serial_array = Cpt(EpicsSignal, 'STAGE:SERIAL')
 38         firm_ver = Cpt(EpicsSignal, 'FIRM:VER')
 39         hard_ver = Cpt(EpicsSignal, 'HARD:VER')
 40         ctrllr_err = Cpt(EpicsSignal, 'CTRLLR:ERR')
 41         config = Cpt(EpicsSignal, 'CONFIG')
 42         stage_config = Cpt(EpicsSignal, 'STAGE:CONFIG')
 43         disable = Cpt(EpicsSignal, 'DISABLE')
 44         dsc = Cpt(EpicsSignal, 'DSC')
 45         RR_set = Cpt(EpicsSignal, 'RAMPRATE:SET')
 46         RR = Cpt(EpicsSignal, 'RAMPRATE')
 47         ramptime = Cpt(EpicsSignal, 'RAMPTIME')
 48         startheat = Cpt(EpicsSignal, 'STARTHEAT')
 49         holdtime_set = Cpt(EpicsSignal, 'HOLDTIME:SET')
 50         holdtime = Cpt(EpicsSignal, 'HOLDTIME')
 51         power = Cpt(EpicsSignalRO, 'POWER')
 52         lnp_speed = Cpt(EpicsSignal, 'LNP_SPEED')
 53         lnp_mode_set = Cpt(EpicsSignal, 'LNP_MODE:SET')
 54         lnp_speed_set = Cpt(EpicsSignal, 'LNP_SPEED:SET')
 55
 56         def on(self):
 57             self.startheat.put(1)
 58
 59         def off(self):
 60             self.startheat.put(0)
 61
 62         def on_plan(self):
 63             return(yield from mv(self.startheat, 1))
 64
 65         def off_plan(self):
 66             return(yield from mv(self.startheat, 0))
 67
 68         def arr2word(self, lst):
 69             word = ''
 70             for l in lst[:-1]:
 71                 word += chr(l)
 72             return word
 73
 74         @property
 75         def serial(self):
 76             return self.arr2word(self.serial_array.get())
 77
 78         @property
 79         def model(self):
 80             return self.arr2word(self.model_array.get())
 81
 82         @property
 83         def stage_model(self):
 84             return self.arr2word(self.stage_model_array.get())
 85
 86         @property
 87         def stage_serial(self):
 88
 89         @property
 90         def firmware_version(self):
 91             return self.arr2word(self.firm_ver.get())
 92
 93         @property
 94         def hardware_version(self):
 95             return self.arr2word(self.hard_ver.get())
 96
 97         def status(self):
 98             text = f'\nCurrent temperature = {self.readback.get():.1f}, setpoint = {self        .setpoint.get():.1f}\n\n'
 99             code = int(self.status_code.get())
100             if code & 1:
101                 text += error_msg('Error        : yes') + '\n'
102             else:
103                 text += 'Error        : no\n'
104             if code & 2:
105                 text += go_msg('At setpoint  : yes') + '\n'
106             else:
107                 text += 'At setpoint  : no\n'
108             if code & 4:
109                 text += go_msg('Heater       : on') + '\n'
110             else:
111                 text += 'Heater       : off\n'
112             if code & 8:
113                 text += go_msg('Pump         : on') + '\n'
114             else:
115                 text += 'Pump         : off\n'
116             if code & 16:
117                 text += go_msg('Pump Auto    : yes') + '\n'
118             else:
119                 text += 'Pump Auto    : no\n'
120
121             boxedtext(f'Linkam {self.model}, stage {self.stage_model}', text, 'brown', width = 45)