1
2
3 import datetime
4 import logging
5 import os
6 import re
7 import shm
8 import signal
9 import struct
10 import time
11 import xmlrpclib
12
14 """
15 Class providing an python interface to a Pico Technology Ltd.
16 TC-08 temperature logger using the tc08lnx Linux driver
17 from Pico Technology.
18
19 Requires tc08lnx to be installed in /usr/local/bin. Also requires the
20 non-standard python module shm (System V shared memory).
21 """
22
23 __format = "ii8ll"
24
25 - def __init__(self, channels, channel_names, portname, \
26 units='C', interval=60, name='tc08', id=42, master=True):
27 """
28 Arguments:
29
30 name: A string with which to label this instance. Used
31 for logging purposes
32
33 channels: Type of thermocouple connected to each channel,
34 encoded as a string of eight characters, one per
35 channel. Available types are B, E, J, K, R,
36 S, T and X (microvolts). For unused channels enter
37 '-'.
38
39 channel_names: String containing a comma seperated list of
40 labels for the channels.
41
42 portname: String containing the device name of the serial port
43 that the TC-08 is connected to, e.g. '/dev/ttyS0'
44
45 units: Specifies the units, 'C' for celsius, 'K' for Kelvin.
46
47 interval: Interval, in seconds, at which entries are added to the log
48
49 name: String to indentify the particlar instance for logging
50 purposes.
51
52 id: Unique ID number used to generate the shared memory key.
53
54 master: True is this instance is the 'master', and should start
55 the tc08lnx driver. False if this is a slave instance,
56 which should just connect to a pre-existing shared memory
57 area and log file.
58 """
59
60 self.logger = logging.getLogger(name)
61
62 self.__channels = channels
63
64 self.__channel_names = channel_names.split(',')
65
66 self.__channel_dict = dict(zip(self.channel_names, \
67 range(1, len(self.channel_names)+1)))
68
69 if units == 'C' or 'c':
70 self.__units = 'C'
71 elif units == 'K' or 'k':
72 self.__units = 'K'
73 else:
74 self.logger.warning("Invalid units '%s' given! Using Celsius." \
75 % units)
76 self.__units = 'C'
77
78 self.__id = int(id)
79 key = shm.ftok("/usr/local/bin/tc08lnx", self.__id)
80
81
82 date = datetime.date.fromtimestamp(time.time())
83 filename = '%s_%s.log' % (date.strftime('%Y%m%d'), name)
84 if os.path.exists(filename):
85 i = 1
86 while os.path.exists(filename + '-%i' % i):
87 i += 1
88 filename += '-%i' % i
89
90 try:
91 logfile = file(filename, 'w')
92 logfile.write("# %s %s %s\n" % (name, channels, channel_names))
93 logfile.close
94 except IOError:
95 self.logger.critical("Couldn't access log file %s for writing!" % \
96 filename)
97
98
99 self.logger.info('Connecting to TC-08 on port %s...' % portname)
100 self.__pid = os.spawnlp(os.P_NOWAIT, "/usr/local/bin/tc08lnx", \
101 "tc08lnx", \
102 "-u", "%s" % units, \
103 "-t", channels, \
104 "-k", "%i" % key, \
105 "-o", "%s" % filename, \
106 "-s", "%i" % int(interval), \
107 portname)
108 self.__filename = filename
109
110
111
112 ps_fd = os.popen('ps -p %i -o state=' % self.__pid)
113 state = ps_fd.read(1)
114 ps_fd.close()
115 if state == 'Z' or state == 'X' or state == '':
116
117
118 self.logger.critical('Driver failure for TC-08 on port %s!' \
119 % portname)
120
121
122
123 try:
124 id = shm.getshmid(key)
125 except KeyError:
126
127 self.logger.critical('Shm key failure for TC-08 on port %s!'\
128 % portname)
129
130
131 try:
132 self.__memory = shm.memory(id)
133 except shm.error:
134
135 self.logger.critical('Shm error for TC-08 on port %s!'\
136 % portname)
137
138
139 self.__size = self.__memory.size
140
141 self.__memory.attach()
142
144 """
145 Ensure the tc08lnx driver gets killed.
146 """
147 self.logger.debug('__del__() called')
148 os.kill(self.__pid, signal.SIGINT)
149
151 """
152 Returns the channel config string.
153 """
154 self.logger.debug('getChannels() called.')
155 return self.__channels
156
158 """
159 Returns the current cold junction temperature.
160 """
161 self.logger.debug('getColdJunction() called.')
162 cjt = struct.unpack(tc08.__format, \
163 self.__memory.read(self.__size))[10]\
164 /100.0
165 if self.__units == 'K' or self.__units == 'k':
166 cjt += 273.15
167 return cjt
168
169
171 """
172 Returns the unique ID used to identify the shared memory block.
173 """
174 self.logger.debug('getID() called')
175 return self.__id
176
177
179 """
180 Returns the channel label for a given channel number
181 """
182 self.logger.debug('getName(%i) called.' % number)
183 return self.__channel_names[number-1]
184
186 """
187 Returns the list of channel labels
188 """
189 self.logger.debug('getNames() called.')
190 return self.__channel_names
191
193 """
194 Returns the channel number corresponding to a given label
195 """
196 self.logger.debug('getNumber("%s") called.' % name)
197 return self.channel_dict[name]
198
200 """
201 Returns the current temperatures as an list.
202 """
203 self.logger.debug('getTemps() called.')
204 num_temps = len(self.channel_names)
205 return [t/100.0 for t in \
206 struct.unpack(tc08.__format, \
207 self.__memory.read(self.__size))[2:2+num_temps]]
208
210 """
211 Returns the temperature units in use, either 'C' for celsius or
212 'K' for kelvin.
213 """
214
216 self.logger.debug('isActive() called')
217 if struct.unpack(tc08.__format, self.__memory.read(self.__size))[1]:
218 return True
219 else:
220 return False
221
223 self.logger.debug('isInitialised() called')
224 if struct.unpack(tc08.__format, self.__memory.read(self.__size))[0]:
225 return True
226 else:
227 return False
228