Commit 91efd0ebc5b41da7d6b45177f563eb5b40337d5e
Committed by
GitHub
1 parent
861f505391
Exists in
master
Add files via upload
Showing 9 changed files with 806 additions and 0 deletions Side-by-side Diff
instruments/AG34461A.py
1 | +from abstract_instrument import abstract_instrument | |
2 | +import socket | |
3 | + | |
4 | +#============================================================================== | |
5 | + | |
6 | +ALL_VAL_TYPE = ['DCV', 'ACV', 'DCI', 'ACI', 'RES2W', 'RES4W', 'FREQ'] | |
7 | +ALL_CHANNELS = ['1'] | |
8 | + | |
9 | +ADRESS = "192.168.0.61" | |
10 | +CONF_VAL_TYPE = ['CONF:VOLT:DC', 'CONF:VOLT:AC', 'CONF:CURR:DC', 'CONF:CURR:AC', 'CONF:RES', 'CONF:FRES', 'CONF:FREQ'] | |
11 | + | |
12 | +#============================================================================== | |
13 | + | |
14 | +class AG34461A(abstract_instrument): | |
15 | + def __init__(self, channels, vtypes, adress=ADRESS): | |
16 | + self.adress = adress | |
17 | + self.port = 5025 | |
18 | + self.channels = channels | |
19 | + self.vtypes = vtypes | |
20 | + | |
21 | + def model(self): | |
22 | + #self.send("*IDN?") | |
23 | + #return self.read() | |
24 | + return "AG34461A" | |
25 | + | |
26 | + def connect(self): | |
27 | + print('Connecting to device @%s:%s...' %(self.adress, self.port)) | |
28 | + self.sock = socket.socket(socket.AF_INET, | |
29 | + socket.SOCK_STREAM, | |
30 | + socket.IPPROTO_TCP) | |
31 | + self.sock.settimeout(10.0) # Don't hang around forever | |
32 | + self.sock.connect((self.adress, self.port)) | |
33 | + self.send("SYST:BEEP") | |
34 | + print(' --> Ok') | |
35 | + print(self.model()) | |
36 | + self.configure() | |
37 | + | |
38 | + def configure(self): | |
39 | + for ch in self.channels: | |
40 | + self.send(CONF_VAL_TYPE[ALL_VAL_TYPE.index(self.vtypes[self.channels.index(ch)])]) | |
41 | + | |
42 | + def getValue(self): | |
43 | + mes = '' | |
44 | + for ch in self.channels: | |
45 | + self.send("READ?") | |
46 | + mesTemp = self.read() | |
47 | + mes = mes + '\t' + mesTemp | |
48 | + return mes | |
49 | + | |
50 | + def read(self): | |
51 | + ans = '' | |
52 | + nb_data_list = [] | |
53 | + nb_data = '' | |
54 | + try: | |
55 | + while ans != '\n': | |
56 | + ans = self.sock.recv(1) | |
57 | + nb_data_list.append(ans) # Return the number of data | |
58 | + list_size = len(nb_data_list) | |
59 | + for j in range (0, list_size): | |
60 | + nb_data = nb_data+nb_data_list[j] | |
61 | + return nb_data | |
62 | + except socket.timeout: | |
63 | + print "Socket timeout error when reading." | |
64 | + raise | |
65 | + | |
66 | + def disconnect(self): | |
67 | + self.send('*RST') | |
68 | + self.send("SYST:BEEP") | |
69 | + self.sock.close() | |
70 | + | |
71 | + def send(self, command): | |
72 | + self.sock.send("%s\n"%command) |
instruments/AG34972A.py
1 | +from abstract_instrument import abstract_instrument | |
2 | +import socket | |
3 | + | |
4 | +#============================================================================== | |
5 | + | |
6 | +ALL_VAL_TYPE = ['DCV', 'ACV', 'DCI', 'ACI', 'RES2W', 'RES4W', 'FREQ'] | |
7 | +ALL_CHANNELS = ['101', '102', '103', '104', '105'] | |
8 | + | |
9 | +ADRESS = "192.168.0.72" | |
10 | +CONF_VAL_TYPE = ['CONF:VOLT:DC', 'CONF:VOLT:AC', 'CONF:CURR:DC', 'CONF:CURR:AC', 'CONF:RES', 'CONF:FRES', 'CONF:FREQ'] | |
11 | + | |
12 | +#============================================================================== | |
13 | + | |
14 | +class AG34972A(abstract_instrument): | |
15 | + def __init__(self, channels, vtypes, adress): | |
16 | + self.adress = adress | |
17 | + self.port = 5025 | |
18 | + self.channels = channels | |
19 | + self.vtypes = vtypes | |
20 | + | |
21 | + def model(self): | |
22 | + #self.send("*IDN?") | |
23 | + #return self.read() | |
24 | + return "AG34972A" | |
25 | + | |
26 | + def connect(self): | |
27 | + print('Connecting to device @%s:%s...' %(self.adress, self.port)) | |
28 | + self.sock = socket.socket(socket.AF_INET, | |
29 | + socket.SOCK_STREAM, | |
30 | + socket.IPPROTO_TCP) | |
31 | + self.sock.settimeout(2.0) # Don't hang around forever | |
32 | + self.sock.connect((self.adress, self.port)) | |
33 | + self.send("SYST:BEEP") | |
34 | + print(' --> Ok') | |
35 | + print(self.model()) | |
36 | + self.configure() | |
37 | + | |
38 | + def configure(self): | |
39 | + self.strCh = '' | |
40 | + for ch in self.channels: | |
41 | + self.send('%s (@%s)'%(CONF_VAL_TYPE[ALL_VAL_TYPE.index(self.vtypes[self.channels.index(ch)])], ch)) | |
42 | + self.strCh = self.strCh + ch + ',' | |
43 | + self.strCh = self.strCh[0:-1] | |
44 | + self.send("ROUT:SCAN (@%s)"%self.strCh) | |
45 | + self.send("TRIG:COUN 1") | |
46 | + | |
47 | + def getValue(self): | |
48 | + self.send("INIT") | |
49 | + self.send("FETC?") | |
50 | + return self.read() | |
51 | + | |
52 | + def read(self): | |
53 | + ans = '' | |
54 | + nb_data_list = [] | |
55 | + nb_data = '' | |
56 | + try: | |
57 | + while ans != '\n': | |
58 | + ans = self.sock.recv(1) | |
59 | + nb_data_list.append(ans) # Return the number of data | |
60 | + list_size = len(nb_data_list) | |
61 | + for j in range (0, list_size): | |
62 | + nb_data = nb_data+nb_data_list[j] | |
63 | + return nb_data | |
64 | + except socket.timeout: | |
65 | + print "Socket timeout error when reading." | |
66 | + raise | |
67 | + | |
68 | + def disconnect(self): | |
69 | + self.send('*RST') | |
70 | + self.sock.close() | |
71 | + | |
72 | + def send(self, command): | |
73 | + self.sock.send("%s\n"%command) |
instruments/LS350.py
1 | +from abstract_instrument import abstract_instrument | |
2 | +import socket | |
3 | + | |
4 | +#============================================================================== | |
5 | + | |
6 | +ALL_VAL_TYPE = ['TEMP', 'RES'] | |
7 | +ALL_CHANNELS = ['a', 'b', 'c', 'd'] | |
8 | + | |
9 | +ADRESS = "192.168.0.12" | |
10 | +CONF_VAL_TYPE = ['krdg?', 'srdg?'] | |
11 | + | |
12 | +#============================================================================== | |
13 | + | |
14 | +class LS350(abstract_instrument): | |
15 | + def __init__(self, channels, vtypes, adress): | |
16 | + self.adress = adress | |
17 | + self.port = 7777 | |
18 | + self.channels = channels | |
19 | + self.vtypes = vtypes | |
20 | + | |
21 | + def model(self): | |
22 | + #self.send("*IDN?") | |
23 | + #return self.read() | |
24 | + return "LS350" | |
25 | + | |
26 | + def connect(self): | |
27 | + print('Connecting to device @%s:%s...' %(self.adress, self.port)) | |
28 | + self.sock = socket.socket(socket.AF_INET, | |
29 | + socket.SOCK_STREAM, | |
30 | + socket.IPPROTO_TCP) | |
31 | + self.sock.settimeout(10.0) # Don't hang around forever | |
32 | + self.sock.connect((self.adress, self.port)) | |
33 | + print(' --> Ok') | |
34 | + print(self.model()) | |
35 | + self.configure() | |
36 | + | |
37 | + def configure(self): | |
38 | + self.strCh = '' | |
39 | + for ch in self.channels: | |
40 | + self.strCh = self.strCh + '%s %s;'%(CONF_VAL_TYPE[ALL_VAL_TYPE.index(self.vtypes[self.channels.index(ch)])], ch) | |
41 | + self.strCh = self.strCh[0:-1] | |
42 | + print(self.strCh) | |
43 | + | |
44 | + def getValue(self): | |
45 | + self.send(self.strCh) | |
46 | + return self.read() | |
47 | + | |
48 | + def read(self): | |
49 | + self.send("++read eoi") | |
50 | + ans = '' | |
51 | + nb_data_list = [] | |
52 | + nb_data = '' | |
53 | + try: | |
54 | + while ans != '\n': | |
55 | + ans = self.sock.recv(1) | |
56 | + nb_data_list.append(ans) # Return the number of data | |
57 | + list_size = len(nb_data_list) | |
58 | + for j in range (0, list_size): | |
59 | + nb_data = nb_data+nb_data_list[j] | |
60 | + return nb_data | |
61 | + except socket.timeout: | |
62 | + print "Socket timeout error when reading." | |
63 | + raise | |
64 | + | |
65 | + def disconnect(self): | |
66 | + self.send('MODE0') | |
67 | + self.sock.close() | |
68 | + | |
69 | + def send(self, command): | |
70 | + self.sock.send("%s\n"%command) |
instruments/PM100D.py
1 | +from abstract_instrument import abstract_instrument | |
2 | +import os | |
3 | + | |
4 | +#============================================================================== | |
5 | + | |
6 | +ALL_VAL_TYPE = ['PWR'] | |
7 | +ALL_CHANNELS = ['1'] | |
8 | + | |
9 | +ADRESS = "/dev/usbtmc0" | |
10 | +CONF_VAL_TYPE = ['PWR'] | |
11 | + | |
12 | +#============================================================================== | |
13 | + | |
14 | +class PM100D(abstract_instrument): | |
15 | + def __init__(self, channels, vtypes, adress): | |
16 | + self.adress = adress | |
17 | + self.channels = channels | |
18 | + self.vtypes = vtypes | |
19 | + | |
20 | + def model(self): | |
21 | + #self.send("*IDN?") | |
22 | + #return self.read() | |
23 | + return "PM100D" | |
24 | + | |
25 | + def connect(self): | |
26 | + print('Connecting to device @%s...' %(self.adress)) | |
27 | + self.FILE = os.open(self.adress, os.O_RDWR) | |
28 | + print(' --> Ok') | |
29 | + print(self.model()) | |
30 | + self.configure() | |
31 | + | |
32 | + def configure(self): | |
33 | + pass | |
34 | + | |
35 | + def getValue(self): | |
36 | + self.send("READ?") | |
37 | + return self.read() | |
38 | + | |
39 | + def read(self): | |
40 | + return os.read(self.FILE, 300) | |
41 | + | |
42 | + def disconnect(self): | |
43 | + self.send('*RST') | |
44 | + | |
45 | + def send(self, command): | |
46 | + os.write(self.FILE, command) |
instruments/T7Pro.py
1 | +from abstract_instrument import abstract_instrument | |
2 | +from labjack import ljm | |
3 | +import numpy | |
4 | + | |
5 | +#============================================================================== | |
6 | + | |
7 | +ALL_VAL_TYPE = ['TEMP', 'RES'] | |
8 | +ALL_CHANNELS = ['TEMP', '1', '2', '3', '4'] | |
9 | +ADRESS = "192.168.0.25" | |
10 | + | |
11 | +#============================================================================== | |
12 | + | |
13 | +class T7Pro(abstract_instrument): | |
14 | + def __init__(self, adress=ADRESS, vtype=[ALL_VAL_TYPE[0]], channels = [ALL_CHANNELS[0]]): | |
15 | + self.adress = adress | |
16 | + self.vtype = vtype | |
17 | + self.tempName = ["TEMPERATURE_AIR_K"] | |
18 | + self.res1Name = ["AIN0", "AIN10"] | |
19 | + self.res2Name = ["AIN2", "AIN11"] | |
20 | + self.res3Name = ["AIN4", "AIN12"] | |
21 | + self.res4Name = ["AIN6", "AIN13"] | |
22 | + | |
23 | + def model(self): | |
24 | + return 'T7Pro' | |
25 | + | |
26 | + def connect(self): | |
27 | + try: | |
28 | + print('Connecting to device @%s...' %(self.adress)) | |
29 | + self.handle = ljm.openS("T7", "ETHERNET", self.adress) | |
30 | + self.configureAINs() | |
31 | + print(' --> Ok') | |
32 | + | |
33 | + print(self.model()) | |
34 | + | |
35 | + if self.vtype == "TEMP": | |
36 | + 1 | |
37 | + elif self.vtype == "RES": | |
38 | + 1 | |
39 | + else: | |
40 | + print("Wrong -v argument") | |
41 | + raise | |
42 | + | |
43 | + except Exception as er: | |
44 | + print("Unexpected error during connection: " + str(er)) | |
45 | + raise | |
46 | + | |
47 | + def getValue(self): | |
48 | + mesTemp = self.read(self.tempName) | |
49 | + mesRes1 = self.read(self.res1Name) | |
50 | + mesRes2 = self.read(self.res2Name) | |
51 | + mesRes3 = self.read(self.res3Name) | |
52 | + mesRes4 = self.read(self.res4Name) | |
53 | +# mesRes4 = [1, 1] | |
54 | +# print("~~~~~~~~~~~~~~~~~~~~~~\n" + str(results) + "~~~~~~~~~~~~~~~~~~~~~~\n") | |
55 | + temp = mesTemp[0] | |
56 | + res1 = 100.*mesRes1[0]/mesRes1[1] | |
57 | + res2 = 100.*mesRes2[0]/mesRes2[1] | |
58 | + res3 = 100.*mesRes3[0]/mesRes3[1] | |
59 | + res4 = 100.*mesRes4[0]/mesRes4[1] | |
60 | + | |
61 | + if self.vtype == 'TEMP': | |
62 | + # Temperature calculation | |
63 | + temp1 = self.res2tempSensor(628, res1) | |
64 | + temp2 = self.res2tempSensor(16947, res2) | |
65 | + temp3 = self.res2tempSensor(625, res3) | |
66 | + temp4 = self.res2tempSensor(100, res4) | |
67 | + string = '%f\t%f\t%f\t%f\t%f\n'%(temp, temp1, temp2, temp3, temp4) | |
68 | +# string = '%f\t%f\n'%(temp, temp1) | |
69 | + elif self.vtype == 'RES': | |
70 | + string = '%f\t%f\t%f\t%f\t%f\n'%(temp, res1, res2, res3, res4) | |
71 | +# string = '%f\t%f\n'%(temp, res1) | |
72 | + else: | |
73 | + string = '' | |
74 | + | |
75 | + return string | |
76 | + | |
77 | + def read(self, names): | |
78 | + return ljm.eReadNames(self.handle, len(names), names) | |
79 | + | |
80 | + def disconnect(self): | |
81 | + ljm.close(self.handle) | |
82 | + | |
83 | + def send(self, command): | |
84 | + pass | |
85 | + | |
86 | + def configureAINs(self): | |
87 | + # Setup and call eWriteNames to configure AINs on the LabJack. | |
88 | + names = ["AIN0_NEGATIVE_CH", "AIN0_RANGE", "AIN0_RESOLUTION_INDEX", | |
89 | + "AIN1_NEGATIVE_CH", "AIN1_RANGE", "AIN1_RESOLUTION_INDEX", | |
90 | + "AIN2_NEGATIVE_CH", "AIN2_RANGE", "AIN2_RESOLUTION_INDEX", | |
91 | + "AIN3_NEGATIVE_CH", "AIN3_RANGE", "AIN3_RESOLUTION_INDEX", | |
92 | + "AIN4_NEGATIVE_CH", "AIN4_RANGE", "AIN4_RESOLUTION_INDEX", | |
93 | + "AIN5_NEGATIVE_CH", "AIN5_RANGE", "AIN5_RESOLUTION_INDEX", | |
94 | + "AIN6_NEGATIVE_CH", "AIN6_RANGE", "AIN6_RESOLUTION_INDEX", | |
95 | + "AIN7_NEGATIVE_CH", "AIN7_RANGE", "AIN7_RESOLUTION_INDEX", | |
96 | + "AIN8_NEGATIVE_CH", "AIN8_RANGE", "AIN8_RESOLUTION_INDEX", | |
97 | + "AIN9_NEGATIVE_CH", "AIN9_RANGE", "AIN9_RESOLUTION_INDEX", | |
98 | + "AIN10_NEGATIVE_CH", "AIN10_RANGE", "AIN10_RESOLUTION_INDEX", | |
99 | + "AIN11_NEGATIVE_CH", "AIN11_RANGE", "AIN11_RESOLUTION_INDEX", | |
100 | + "AIN12_NEGATIVE_CH", "AIN12_RANGE", "AIN12_RESOLUTION_INDEX", | |
101 | + "AIN13_NEGATIVE_CH", "AIN13_RANGE", "AIN13_RESOLUTION_INDEX" | |
102 | + ] | |
103 | + l_names = len(names) | |
104 | + aValues = [1, 0.1, 12,#0 | |
105 | + 199, 0.1, 12,#1 | |
106 | + 3, 0.1, 12,#2 | |
107 | + 199, 0.1, 12,#3 | |
108 | + 5, 0.1, 12,#4 | |
109 | + 199, 0.1, 12,#5 | |
110 | + 7, 0.1, 12,#6 | |
111 | + 199, 0.1, 12,#7 | |
112 | + 199, 0.1, 12,#8 | |
113 | + 199, 0.1, 12,#9 | |
114 | + 199, 0.1, 12,#10 | |
115 | + 199, 0.1, 12,#11 | |
116 | + 199, 0.1, 12,#12 | |
117 | + 199, 0.1, 12#13 | |
118 | + ] | |
119 | + ljm.eWriteNames(self.handle, l_names, names, aValues) | |
120 | + | |
121 | + | |
122 | + def res2tempSensor(self, sensor, res): | |
123 | + if sensor==627: | |
124 | + K = [0.399341181655472610, | |
125 | + 10.8420092277810909, | |
126 | + -26.4597939187660813, | |
127 | + 245.9828566655493379, | |
128 | + -668.069876596331596, | |
129 | + 1001.69882618263364, | |
130 | + -267.272089680656791] | |
131 | + if sensor==625: | |
132 | + K = [0.333548856582638109, | |
133 | + 11.7361551595386118, | |
134 | + -31.32988932320903987, | |
135 | + 262.878643524833024, | |
136 | + -704.163538021035492, | |
137 | + 1056.6040485650301, | |
138 | + -307.057196729816496] | |
139 | + if sensor==628: | |
140 | + K = [0.463200932294057566, | |
141 | + 13.5049710820894688, | |
142 | + -30.5191222755238414, | |
143 | + 231.098593852017075, | |
144 | + -550.122691885568202, | |
145 | + 806.038547554984689, | |
146 | + -198.510489917360246] | |
147 | + if sensor==16945: | |
148 | + K = [3.2497, 5.1777, 2.499] | |
149 | + if sensor==16943: | |
150 | + K = [3.4738, 5.1198, 2.3681] | |
151 | + if sensor==16944: | |
152 | + K = [3.3674, 5.2874, 2.5165] | |
153 | + if sensor==16941: | |
154 | + K = [2.9486, 4.5862, 2.266] | |
155 | + if sensor==16947: | |
156 | + K = [3.4597, 5.2422, 2.4169] | |
157 | + if sensor==100: | |
158 | + K = [0.003850] | |
159 | + return self.res2temp(K, res) | |
160 | + | |
161 | + def res2temp(K, res): | |
162 | + temp = 0 | |
163 | + tmp = 1000./res | |
164 | + if len(K)==7: | |
165 | + for i in range(len(K)): | |
166 | + temp += K[i]*tmp**i | |
167 | + if len(K)==3: | |
168 | + for i in range(len(K)): | |
169 | + temp += K[i]*numpy.log10(tmp)**(2-i) | |
170 | + temp = 10**temp | |
171 | + if len(K)==1: | |
172 | + temp = (res/100.-1)/K[0]+273.15 | |
173 | + return temp |
instruments/TPG261.py
1 | +from abstract_instrument import abstract_instrument | |
2 | +import serial | |
3 | + | |
4 | +#============================================================================== | |
5 | + | |
6 | +ALL_VAL_TYPE = ['PRE'] | |
7 | +ALL_CHANNELS = ['1'] | |
8 | +ADRESS = "/dev/ttyS0" | |
9 | + | |
10 | +#============================================================================== | |
11 | + | |
12 | +class TPG261(abstract_instrument): | |
13 | + def __init__(self, adress=ADRESS, vtype=[ALL_VAL_TYPE[0]], channels = [ALL_CHANNELS[0]]): | |
14 | + self.adress = adress | |
15 | + self.vtype = vtype | |
16 | + | |
17 | + def model(self): | |
18 | + return "PfeifferTPG261" | |
19 | + | |
20 | + def connect(self): | |
21 | + try: | |
22 | + print('Connecting to device @%s...' %(self.adress)) | |
23 | + self.TPG = MaxiGauge(self.adress) | |
24 | + print(' --> Ok') | |
25 | + | |
26 | + print(self.model()) | |
27 | + | |
28 | + if self.vtype == "PRE": | |
29 | + 1 | |
30 | + else: | |
31 | + print("Wrong -v argument") | |
32 | + raise | |
33 | + | |
34 | + except Exception as er: | |
35 | + print("Unexpected error during connection: " + str(er)) | |
36 | + raise | |
37 | + | |
38 | + def getValue(self): | |
39 | + self.read() | |
40 | + return "%s\n"%self.ps[0].pressure | |
41 | + | |
42 | + def read(self): | |
43 | + self.ps = self.TPG.pressures() | |
44 | + | |
45 | + def disconnect(self): | |
46 | + self.TPG.disconnect() | |
47 | + | |
48 | + def send(self, command): | |
49 | + pass | |
50 | + | |
51 | + | |
52 | + | |
53 | + | |
54 | +# from Philipp Klaus, philipp.l.klaus AT web.de PfeifferVacuum.py | |
55 | + | |
56 | +class MaxiGauge (object): | |
57 | + def __init__(self, serialPort, baud=9600, debug=False): | |
58 | + self.debug=debug | |
59 | + try: | |
60 | + self.connection = serial.Serial(serialPort, baudrate=baud, timeout=0.2) | |
61 | + except serial.serialutil.SerialException as se: | |
62 | + raise MaxiGaugeError(se) | |
63 | + #self.send(C['ETX']) ### We might reset the connection first, but it doesn't really matter: | |
64 | + | |
65 | + def checkDevice(self): | |
66 | + message = "The Display Contrast is currently set to %d (out of 20).\n" % self.displayContrast() | |
67 | + message += "Keys since MaxiGauge was switched on: %s (out of 1,2,3,4,5).\n" % ", ".join( map (str, self.pressedKeys()) ) | |
68 | + return message | |
69 | + | |
70 | + def pressedKeys(self): | |
71 | + keys = int(self.send('TKB',1)[0]) | |
72 | + pressedKeys = [] | |
73 | + for i in [4,3,2,1,0]: # It's got 5 keys | |
74 | + if keys/2**i == 1: | |
75 | + pressedKeys.append(i+1) | |
76 | + keys = keys%2**i | |
77 | + pressedKeys.reverse() | |
78 | + return pressedKeys | |
79 | + | |
80 | + def displayContrast(self,newContrast=-1): | |
81 | + if newContrast == -1: return int(self.send('DCC',1)[0]) | |
82 | + else: return int(self.send('DCC,%d' % (newContrast,) ,1)[0]) | |
83 | + | |
84 | + def pressures(self): | |
85 | + return [self.pressure(i+1) for i in range(1)] | |
86 | + | |
87 | + def pressure(self, sensor): | |
88 | + if sensor < 1 or sensor >6: raise MaxiGaugeError('Sensor can only be between 1 and 6. You choose ' + str(sensor)) | |
89 | + reading = self.send('PR%d' % sensor, 1) ## reading will have the form x,x.xxxEsx <CR><LF> (see p.88) | |
90 | + try: | |
91 | + r = reading[0].split(',') | |
92 | + status = int(r[0]) | |
93 | + pressure = float(r[-1]) | |
94 | + except: | |
95 | + raise MaxiGaugeError("Problem interpreting the returned line:\n%s" % reading) | |
96 | + return PressureReading(sensor, status, pressure) | |
97 | + | |
98 | + def debugMessage(self, message): | |
99 | + if self.debug: print(repr(message)) | |
100 | + | |
101 | + def send(self, mnemonic, numEnquiries = 0): | |
102 | + self.connection.flushInput() | |
103 | + self.write(mnemonic+LINE_TERMINATION) | |
104 | + #if mnemonic != C['ETX']: self.read() | |
105 | + #self.read() | |
106 | + self.getACQorNAK() | |
107 | + response = [] | |
108 | + for i in range(numEnquiries): | |
109 | + self.enquire() | |
110 | + response.append(self.read()) | |
111 | + return response | |
112 | + | |
113 | + def write(self,what): | |
114 | + self.debugMessage(what) | |
115 | + self.connection.write(what) | |
116 | + | |
117 | + def enquire(self): | |
118 | + self.write(C['ENQ']) | |
119 | + | |
120 | + def read(self): | |
121 | + data = "" | |
122 | + while True: | |
123 | + x = self.connection.read() | |
124 | + self.debugMessage(x) | |
125 | + data += x | |
126 | + if len(data)>1 and data[-2:]==LINE_TERMINATION: | |
127 | + break | |
128 | + return data[:-len(LINE_TERMINATION)] | |
129 | + | |
130 | + def getACQorNAK(self): | |
131 | + returncode = self.connection.readline() | |
132 | + self.debugMessage(returncode) | |
133 | + ## The following is usually expected but our MaxiGauge controller sometimes forgets this parameter... That seems to be a bug with the DCC command. | |
134 | + #if len(returncode)<3: raise MaxiGaugeError('Only received a line termination from MaxiGauge. Was expecting ACQ or NAK.') | |
135 | + if len(returncode)<3: self.debugMessage('Only received a line termination from MaxiGauge. Was expecting ACQ or NAK.') | |
136 | + if len(returncode)>2 and returncode[-3] == C['NAK']: | |
137 | + self.enquire() | |
138 | + returnedError = self.read() | |
139 | + error = str(returnedError).split(',' , 1) | |
140 | + print repr(error) | |
141 | + errmsg = { 'System Error': ERR_CODES[0][int(error[0])] , 'Gauge Error': ERR_CODES[1][int(error[1])] } | |
142 | + raise MaxiGaugeNAK(errmsg) | |
143 | + #if len(returncode)>2 and returncode[-3] != C['ACQ']: raise MaxiGaugeError('Expecting ACQ or NAK from MaxiGauge but neither were sent.') | |
144 | + if len(returncode)>2 and returncode[-3] != C['ACQ']: self.debugMessage('Expecting ACQ or NAK from MaxiGauge but neither were sent.') | |
145 | + # if no exception raised so far, the interface is just fine: | |
146 | + return returncode[:-(len(LINE_TERMINATION)+1)] | |
147 | + | |
148 | + def disconnect(self): | |
149 | + #self.send(C['ETX']) | |
150 | + if hasattr(self, 'connection') and self.connection: self.connection.close() | |
151 | + | |
152 | + def __del__(self): | |
153 | + self.disconnect() | |
154 | + | |
155 | +class PressureReading(object): | |
156 | + def __init__(self, id, status, pressure): | |
157 | + if int(id) not in range(1,7): raise MaxiGaugeError('Pressure Gauge ID must be between 1-6') | |
158 | + self.id = int(id) | |
159 | + if int(status) not in PRESSURE_READING_STATUS.keys(): raise MaxiGaugeError('The Pressure Status must be in the range %s' % PRESSURE_READING_STATUS.keys()) | |
160 | + self.status = int(status) | |
161 | + self.pressure = float(pressure) | |
162 | + | |
163 | + def statusMsg(self): | |
164 | + return PRESSURE_READING_STATUS[self.status] | |
165 | + | |
166 | + def __repr__(self): | |
167 | + return "Gauge #%d: Status %d (%s), Pressure: %f mbar\n" % (self.id, self.status, self.statusMsg(), self.pressure) | |
168 | + | |
169 | + | |
170 | +### ------ now we define the exceptions that could occur ------ | |
171 | + | |
172 | +class MaxiGaugeError(Exception): | |
173 | + pass | |
174 | + | |
175 | +class MaxiGaugeNAK(MaxiGaugeError): | |
176 | + pass | |
177 | + | |
178 | +### ------- Control Symbols as defined on p. 81 of the english | |
179 | +### manual for the Pfeiffer Vacuum TPG256A ----------- | |
180 | +C = { | |
181 | + 'ETX': "\x03", # End of Text (Ctrl-C) Reset the interface | |
182 | + 'CR': "\x0D", # Carriage Return Go to the beginning of line | |
183 | + 'LF': "\x0A", # Line Feed Advance by one line | |
184 | + 'ENQ': "\x05", # Enquiry Request for data transmission | |
185 | + 'ACQ': "\x06", # Acknowledge Positive report signal | |
186 | + 'NAK': "\x15", # Negative Acknowledge Negative report signal | |
187 | + 'ESC': "\x1b", # Escape | |
188 | +} | |
189 | + | |
190 | +LINE_TERMINATION=C['CR']+C['LF'] # CR, LF and CRLF are all possible (p.82) | |
191 | + | |
192 | +### Mnemonics as defined on p. 85 | |
193 | +M = [ | |
194 | + 'BAU', # Baud rate Baud rate 95 | |
195 | + 'CAx', # Calibration factor Sensor x Calibration factor sensor x (1 ... 6) 92 | |
196 | + 'CID', # Measurement point names Measurement point names 88 | |
197 | + 'DCB', # Display control Bargraph Bargraph 89 | |
198 | + 'DCC', # Display control Contrast Display control contrast 90 | |
199 | + 'DCD', # Display control Digits Display digits 88 | |
200 | + 'DCS', # Display control Screensave Display control screensave 90 | |
201 | + 'DGS', # Degas Degas 93 | |
202 | + 'ERR', # Error Status Error status 97 | |
203 | + 'FIL', # Filter time constant Filter time constant 92 | |
204 | + 'FSR', # Full scale range of linear sensors Full scale range of linear sensors 93 | |
205 | + 'LOC', # Parameter setup lock Parameter setup lock 91 | |
206 | + 'NAD', # Node (device) address for RS485 Node (device) address for RS485 96 | |
207 | + 'OFC', # Offset correction Offset correction 93 | |
208 | + 'OFC', # Offset correction Offset correction 93 | |
209 | + 'PNR', # Program number Program number 98 | |
210 | + 'PRx', # Status, Pressure sensor x (1 ... 6) Status, Pressure sensor x (1 ... 6) 88 | |
211 | + 'PUC', # Underrange Ctrl Underrange control 91 | |
212 | + 'RSX', # Interface Interface 94 | |
213 | + 'SAV', # Save default Save default 94 | |
214 | + 'SCx', # Sensor control Sensor control 87 | |
215 | + 'SEN', # Sensor on/off Sensor on/off 86 | |
216 | + 'SPx', # Set Point Control Source for Relay xThreshold value setting, Allocation 90 | |
217 | + 'SPS', # Set Point Status A,B,C,D,E,F Set point status 91 | |
218 | + 'TAI', # Test program A/D Identify Test A/D converter identification inputs 100 | |
219 | + 'TAS', # Test program A/D Sensor Test A/D converter measurement value inputs 100 | |
220 | + 'TDI', # Display test Display test 98 | |
221 | + 'TEE', # EEPROM test EEPROM test 100 | |
222 | + 'TEP', # EPROM test EPROM test 99 | |
223 | + 'TID', # Sensor identification Sensor identification 101 | |
224 | + 'TKB', # Keyboard test Keyboard test 99 | |
225 | + 'TRA', # RAM test RAM test 99 | |
226 | + 'UNI', # Unit of measurement (Display) Unit of measurement (pressure) 89 | |
227 | + 'WDT', # Watchdog and System Error Control Watchdog and system error control 101 | |
228 | +] | |
229 | + | |
230 | + | |
231 | +### Error codes as defined on p. 97 | |
232 | +ERR_CODES = [ | |
233 | + { | |
234 | + 0: 'No error', | |
235 | + 1: 'Watchdog has responded', | |
236 | + 2: 'Task fail error', | |
237 | + 4: 'IDCX idle error', | |
238 | + 8: 'Stack overflow error', | |
239 | + 16: 'EPROM error', | |
240 | + 32: 'RAM error', | |
241 | + 64: 'EEPROM error', | |
242 | + 128: 'Key error', | |
243 | + 4096: 'Syntax error', | |
244 | + 8192: 'Inadmissible parameter', | |
245 | + 16384: 'No hardware', | |
246 | + 32768: 'Fatal error' | |
247 | + } , | |
248 | + { | |
249 | + 0: 'No error', | |
250 | + 1: 'Sensor 1: Measurement error', | |
251 | + 2: 'Sensor 2: Measurement error', | |
252 | + 4: 'Sensor 3: Measurement error', | |
253 | + 8: 'Sensor 4: Measurement error', | |
254 | + 16: 'Sensor 5: Measurement error', | |
255 | + 32: 'Sensor 6: Measurement error', | |
256 | + 512: 'Sensor 1: Identification error', | |
257 | + 1024: 'Sensor 2: Identification error', | |
258 | + 2048: 'Sensor 3: Identification error', | |
259 | + 4096: 'Sensor 4: Identification error', | |
260 | + 8192: 'Sensor 5: Identification error', | |
261 | + 16384: 'Sensor 6: Identification error', | |
262 | + } | |
263 | +] | |
264 | + | |
265 | +### pressure status as defined on p.88 | |
266 | +PRESSURE_READING_STATUS = { | |
267 | + 0: 'Measurement data okay', | |
268 | + 1: 'Underrange', | |
269 | + 2: 'Overrange', | |
270 | + 3: 'Sensor error', | |
271 | + 4: 'Sensor off', | |
272 | + 5: 'No sensor', | |
273 | + 6: 'Identification error' | |
274 | +} |
instruments/__init__.py
instruments/abstract_instrument.py
1 | +import abc | |
2 | + | |
3 | +class abstract_instrument(object): | |
4 | + __metaclass__ = abc.ABCMeta | |
5 | + | |
6 | + @abc.abstractmethod | |
7 | + def __init__(self, adress, vtype, channel): | |
8 | + """Build the class""" | |
9 | + return | |
10 | + | |
11 | + @abc.abstractmethod | |
12 | + def model(self): | |
13 | + """return the instrument model""" | |
14 | + return | |
15 | + | |
16 | + @abc.abstractmethod | |
17 | + def connect(self): | |
18 | + """Create a connection with the instrument""" | |
19 | + return | |
20 | + | |
21 | + @abc.abstractmethod | |
22 | + def disconnect(self): | |
23 | + """Disconnect the instrument""" | |
24 | + return | |
25 | + | |
26 | + @abc.abstractmethod | |
27 | + def configure(self): | |
28 | + """Configure the instrument""" | |
29 | + return | |
30 | + | |
31 | + @abc.abstractmethod | |
32 | + def read(self): | |
33 | + """read the buffer""" | |
34 | + return | |
35 | + | |
36 | + @abc.abstractmethod | |
37 | + def send(self): | |
38 | + """send a command""" | |
39 | + return | |
40 | + | |
41 | + @abc.abstractmethod | |
42 | + def getValue(self): | |
43 | + """return the value of measurment""" | |
44 | + return |
instruments/testDevice.py
1 | +from abstract_instrument import abstract_instrument | |
2 | +import numpy, time | |
3 | + | |
4 | +#============================================================================== | |
5 | + | |
6 | +ALL_VAL_TYPE = ['vtype', 'DCV', 'ACV', 'DCI', 'ACI', 'RES2W', 'RES4W', 'FREQ'] | |
7 | +ALL_CHANNELS = ['0', '1'] | |
8 | +ADRESS = "123.456.789.123" | |
9 | + | |
10 | +#============================================================================== | |
11 | + | |
12 | +class testDevice(abstract_instrument): | |
13 | + def __init__(self, channels, vtype, adress = ADRESS): | |
14 | + self.adress = adress | |
15 | + self.port = 9999 | |
16 | + self.channels = channels | |
17 | + print(self.channels) | |
18 | + self.vtype = vtype | |
19 | + print(self.vtype) | |
20 | + | |
21 | + def model(self): | |
22 | + return 'test_device' | |
23 | + | |
24 | + def connect(self): | |
25 | + print('Connecting to device @%s:%s...' %(self.adress, self.port)) | |
26 | + time.sleep(1) | |
27 | + print(' --> Ok') | |
28 | + | |
29 | + print(self.model()) | |
30 | + | |
31 | + def getValue(self): | |
32 | + mes = "" | |
33 | + for ch in self.channels: | |
34 | + mes = mes + str(numpy.random.rand()) + '\t' | |
35 | + return mes + '\n' | |
36 | + | |
37 | + def read(self): | |
38 | + print('reading') | |
39 | + return 1 | |
40 | + | |
41 | + def disconnect(self): | |
42 | + print('disconnect') | |
43 | + | |
44 | + def send(self, command): | |
45 | + print('send %s'%command) |