Blame view
instruments/TPG261.py
10.9 KB
91efd0ebc Add files via upload |
1 2 3 4 5 6 7 |
from abstract_instrument import abstract_instrument import serial #============================================================================== ALL_VAL_TYPE = ['PRE'] ALL_CHANNELS = ['1'] |
9058343c5 some minor fixes |
8 |
ADDRESS = "/dev/ttyS0" |
91efd0ebc Add files via upload |
9 10 11 12 |
#============================================================================== class TPG261(abstract_instrument): |
9058343c5 some minor fixes |
13 14 |
def __init__(self, channels, vtypes, address): self.address = address |
bb6b08041 Add configure method |
15 16 |
self.channels = channels self.vtypes = vtypes |
91efd0ebc Add files via upload |
17 18 19 20 21 |
def model(self): return "PfeifferTPG261" def connect(self): |
9058343c5 some minor fixes |
22 23 |
print('Connecting to device @%s...' %(self.address)) self.TPG = MaxiGauge(self.address) |
bb6b08041 Add configure method |
24 25 26 27 28 |
print(' --> Ok') print(self.model()) self.configure() def configure(self): |
b383042b0 - |
29 |
pass |
91efd0ebc Add files via upload |
30 31 |
def getValue(self): |
b383042b0 - |
32 |
self.read() |
91efd0ebc Add files via upload |
33 34 35 36 |
return "%s "%self.ps[0].pressure def read(self): |
b383042b0 - |
37 |
self.ps = self.TPG.pressures() |
91efd0ebc Add files via upload |
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
def disconnect(self): self.TPG.disconnect() def send(self, command): pass # from Philipp Klaus, philipp.l.klaus AT web.de PfeifferVacuum.py class MaxiGauge (object): def __init__(self, serialPort, baud=9600, debug=False): self.debug=debug try: self.connection = serial.Serial(serialPort, baudrate=baud, timeout=0.2) except serial.serialutil.SerialException as se: raise MaxiGaugeError(se) #self.send(C['ETX']) ### We might reset the connection first, but it doesn't really matter: def checkDevice(self): message = "The Display Contrast is currently set to %d (out of 20). " % self.displayContrast() message += "Keys since MaxiGauge was switched on: %s (out of 1,2,3,4,5). " % ", ".join( map (str, self.pressedKeys()) ) return message def pressedKeys(self): keys = int(self.send('TKB',1)[0]) pressedKeys = [] for i in [4,3,2,1,0]: # It's got 5 keys if keys/2**i == 1: pressedKeys.append(i+1) keys = keys%2**i pressedKeys.reverse() return pressedKeys def displayContrast(self,newContrast=-1): if newContrast == -1: return int(self.send('DCC',1)[0]) else: return int(self.send('DCC,%d' % (newContrast,) ,1)[0]) def pressures(self): return [self.pressure(i+1) for i in range(1)] def pressure(self, sensor): if sensor < 1 or sensor >6: raise MaxiGaugeError('Sensor can only be between 1 and 6. You choose ' + str(sensor)) reading = self.send('PR%d' % sensor, 1) ## reading will have the form x,x.xxxEsx <CR><LF> (see p.88) try: r = reading[0].split(',') status = int(r[0]) pressure = float(r[-1]) except: raise MaxiGaugeError("Problem interpreting the returned line: %s" % reading) return PressureReading(sensor, status, pressure) def debugMessage(self, message): if self.debug: print(repr(message)) def send(self, mnemonic, numEnquiries = 0): self.connection.flushInput() self.write(mnemonic+LINE_TERMINATION) #if mnemonic != C['ETX']: self.read() #self.read() self.getACQorNAK() response = [] for i in range(numEnquiries): self.enquire() response.append(self.read()) return response def write(self,what): self.debugMessage(what) self.connection.write(what) def enquire(self): self.write(C['ENQ']) def read(self): data = "" while True: x = self.connection.read() self.debugMessage(x) data += x if len(data)>1 and data[-2:]==LINE_TERMINATION: break return data[:-len(LINE_TERMINATION)] def getACQorNAK(self): returncode = self.connection.readline() self.debugMessage(returncode) ## The following is usually expected but our MaxiGauge controller sometimes forgets this parameter... That seems to be a bug with the DCC command. #if len(returncode)<3: raise MaxiGaugeError('Only received a line termination from MaxiGauge. Was expecting ACQ or NAK.') if len(returncode)<3: self.debugMessage('Only received a line termination from MaxiGauge. Was expecting ACQ or NAK.') if len(returncode)>2 and returncode[-3] == C['NAK']: self.enquire() returnedError = self.read() error = str(returnedError).split(',' , 1) print repr(error) errmsg = { 'System Error': ERR_CODES[0][int(error[0])] , 'Gauge Error': ERR_CODES[1][int(error[1])] } raise MaxiGaugeNAK(errmsg) #if len(returncode)>2 and returncode[-3] != C['ACQ']: raise MaxiGaugeError('Expecting ACQ or NAK from MaxiGauge but neither were sent.') if len(returncode)>2 and returncode[-3] != C['ACQ']: self.debugMessage('Expecting ACQ or NAK from MaxiGauge but neither were sent.') # if no exception raised so far, the interface is just fine: return returncode[:-(len(LINE_TERMINATION)+1)] def disconnect(self): #self.send(C['ETX']) if hasattr(self, 'connection') and self.connection: self.connection.close() def __del__(self): self.disconnect() class PressureReading(object): def __init__(self, id, status, pressure): if int(id) not in range(1,7): raise MaxiGaugeError('Pressure Gauge ID must be between 1-6') self.id = int(id) if int(status) not in PRESSURE_READING_STATUS.keys(): raise MaxiGaugeError('The Pressure Status must be in the range %s' % PRESSURE_READING_STATUS.keys()) self.status = int(status) self.pressure = float(pressure) def statusMsg(self): return PRESSURE_READING_STATUS[self.status] def __repr__(self): return "Gauge #%d: Status %d (%s), Pressure: %f mbar " % (self.id, self.status, self.statusMsg(), self.pressure) ### ------ now we define the exceptions that could occur ------ class MaxiGaugeError(Exception): pass class MaxiGaugeNAK(MaxiGaugeError): pass ### ------- Control Symbols as defined on p. 81 of the english ### manual for the Pfeiffer Vacuum TPG256A ----------- C = { 'ETX': "\x03", # End of Text (Ctrl-C) Reset the interface 'CR': "\x0D", # Carriage Return Go to the beginning of line 'LF': "\x0A", # Line Feed Advance by one line 'ENQ': "\x05", # Enquiry Request for data transmission 'ACQ': "\x06", # Acknowledge Positive report signal 'NAK': "\x15", # Negative Acknowledge Negative report signal 'ESC': "\x1b", # Escape } LINE_TERMINATION=C['CR']+C['LF'] # CR, LF and CRLF are all possible (p.82) ### Mnemonics as defined on p. 85 M = [ 'BAU', # Baud rate Baud rate 95 'CAx', # Calibration factor Sensor x Calibration factor sensor x (1 ... 6) 92 'CID', # Measurement point names Measurement point names 88 'DCB', # Display control Bargraph Bargraph 89 'DCC', # Display control Contrast Display control contrast 90 'DCD', # Display control Digits Display digits 88 'DCS', # Display control Screensave Display control screensave 90 'DGS', # Degas Degas 93 'ERR', # Error Status Error status 97 'FIL', # Filter time constant Filter time constant 92 'FSR', # Full scale range of linear sensors Full scale range of linear sensors 93 'LOC', # Parameter setup lock Parameter setup lock 91 'NAD', # Node (device) address for RS485 Node (device) address for RS485 96 'OFC', # Offset correction Offset correction 93 'OFC', # Offset correction Offset correction 93 'PNR', # Program number Program number 98 'PRx', # Status, Pressure sensor x (1 ... 6) Status, Pressure sensor x (1 ... 6) 88 'PUC', # Underrange Ctrl Underrange control 91 'RSX', # Interface Interface 94 'SAV', # Save default Save default 94 'SCx', # Sensor control Sensor control 87 'SEN', # Sensor on/off Sensor on/off 86 'SPx', # Set Point Control Source for Relay xThreshold value setting, Allocation 90 'SPS', # Set Point Status A,B,C,D,E,F Set point status 91 'TAI', # Test program A/D Identify Test A/D converter identification inputs 100 'TAS', # Test program A/D Sensor Test A/D converter measurement value inputs 100 'TDI', # Display test Display test 98 'TEE', # EEPROM test EEPROM test 100 'TEP', # EPROM test EPROM test 99 'TID', # Sensor identification Sensor identification 101 'TKB', # Keyboard test Keyboard test 99 'TRA', # RAM test RAM test 99 'UNI', # Unit of measurement (Display) Unit of measurement (pressure) 89 'WDT', # Watchdog and System Error Control Watchdog and system error control 101 ] ### Error codes as defined on p. 97 ERR_CODES = [ { 0: 'No error', 1: 'Watchdog has responded', 2: 'Task fail error', 4: 'IDCX idle error', 8: 'Stack overflow error', 16: 'EPROM error', 32: 'RAM error', 64: 'EEPROM error', 128: 'Key error', 4096: 'Syntax error', 8192: 'Inadmissible parameter', 16384: 'No hardware', 32768: 'Fatal error' } , { 0: 'No error', 1: 'Sensor 1: Measurement error', 2: 'Sensor 2: Measurement error', 4: 'Sensor 3: Measurement error', 8: 'Sensor 4: Measurement error', 16: 'Sensor 5: Measurement error', 32: 'Sensor 6: Measurement error', 512: 'Sensor 1: Identification error', 1024: 'Sensor 2: Identification error', 2048: 'Sensor 3: Identification error', 4096: 'Sensor 4: Identification error', 8192: 'Sensor 5: Identification error', 16384: 'Sensor 6: Identification error', } ] ### pressure status as defined on p.88 PRESSURE_READING_STATUS = { 0: 'Measurement data okay', 1: 'Underrange', 2: 'Overrange', 3: 'Sensor error', 4: 'Sensor off', 5: 'No sensor', 6: 'Identification error' } |