TPG261.py
10.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
from abstract_instrument import abstract_instrument
import serial
#==============================================================================
ALL_VAL_TYPE = ['PRE']
ALL_CHANNELS = ['1']
ADRESS = "/dev/ttyS0"
#==============================================================================
class TPG261(abstract_instrument):
def __init__(self, channels, vtypes, adress):
self.adress = adress
self.channels = channels
self.vtypes = vtypes
def model(self):
return "PfeifferTPG261"
def connect(self):
print('Connecting to device @%s...' %(self.adress))
self.TPG = MaxiGauge(self.adress)
print(' --> Ok')
print(self.model())
self.configure()
def configure(self):
pass
def getValue(self):
self.read()
return "%s\n"%self.ps[0].pressure
def read(self):
self.ps = self.TPG.pressures()
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).\n" % self.displayContrast()
message += "Keys since MaxiGauge was switched on: %s (out of 1,2,3,4,5).\n" % ", ".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:\n%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\n" % (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'
}