1 """Reads .gpatch data files.
2
3 Copyright 2008-2011 Research Foundation State University of New York
4 This file is part of QUB Express.
5
6 QUB Express is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 QUB Express is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License,
17 named LICENSE.txt, in the QUB Express program directory. If not, see
18 <http://www.gnu.org/licenses/>.
19
20 """
21
22 import mmap
23 import os
24 import re
25 import sys
26 from qubx.data_types import *
27 from ctypes import *
28
29 c_uint_p = POINTER(c_uint)
30 c_short_p = POINTER(c_short)
31
33 _pack_ = 1
34 _fields_ = [('amp', c_short * 8),
35 ('pulseFilter', c_short),
36 ('decimFactor', c_short),
37 ('dur', c_int * 9),
38 ('dummy0', c_float),
39 ('durAP', c_int),
40 ('durBP', c_int),
41 ('durSP', c_int),
42 ('cyclePeriod', c_float),
43 ('numSweeps', c_short),
44 ('numSubPul', c_short),
45 ('numPulses', c_short),
46 ('triggerPulse', c_short),
47 ('dummy1', c_short),
48 ('triggerDelay', c_int),
49 ('dummy2', c_int),
50 ('ampHP', c_short),
51 ('ampSH', c_short),
52 ('dummy3', c_short),
53 ('dummy8', c_short),
54 ('acqFilter', c_short),
55 ('numAver', c_short),
56 ('acqRate', c_float),
57 ('year', c_short),
58 ('date', c_byte * 2),
59 ('time', c_byte * 4),
60 ('photonCounter', c_short),
61 ('multiplexer', c_short),
62 ('dummy4', c_short),
63 ('dummy5', c_int),
64 ('dummy6', c_short),
65 ('dummy7', c_short),
66 ('gain', c_float),
67 ('units', c_float),
68 ('aDRange', c_float),
69 ('extra', c_char * 16)]
70
71 GPM_headerSize = 2048
72 GPM_maxPulses = 64
73 GPM_maxTriggers = 8
74 GPM_maxCharSize = 16
75 GPM_currSizeUsed = 1336
76
78 _pack_ = 1
79 _fields_ = [('magicField', c_char * GPM_maxCharSize),
80 ('sweepGroupSign', c_int),
81 ('dateDay', c_int),
82 ('dateMonth', c_int),
83 ('dateYear', c_int),
84 ('timeHours', c_int),
85 ('timeMinuts', c_int),
86 ('timeSeconds', c_int),
87 ('timeHundredOfSec', c_int),
88 ('acqNumPoints', c_int),
89 ('acqAcqRate', c_float),
90 ('acqDecimation', c_int),
91 ('acqTemperature', c_float),
92 ('acqNumAverages', c_int),
93 ('acqDataType', c_int),
94 ('acqAcqFilter', c_float),
95 ('acqPulseFilter', c_float),
96 ('acqGain', c_float),
97 ('acqUnits', c_float),
98 ('pulNumPulses', c_int),
99 ('pulDurBP', c_int),
100 ('pulDurAP', c_int),
101 ('pulDurCP', c_int),
102 ('pulAmpHP', c_float),
103 ('pulAmp', c_float * GPM_maxPulses),
104 ('pulDur', c_int * GPM_maxPulses),
105 ('pulIsRamp', c_int * GPM_maxPulses),
106 ('pulRampEnd', c_float * GPM_maxPulses),
107 ('trPulse', c_int * GPM_maxTriggers),
108 ('trDelay', c_int * GPM_maxTriggers),
109 ('trGate', c_int * GPM_maxTriggers),
110 ('trEndGate', c_int * GPM_maxTriggers),
111 ('trIsActive', c_int * GPM_maxTriggers),
112 ('subNumSP', c_int),
113 ('subAmpSH', c_float),
114 ('subDurBwSP', c_int),
115 ('setBoardType', c_char * GPM_maxCharSize),
116 ('setDACGain', c_float),
117 ('setADRange', c_int),
118 ('setADMax', c_int),
119 ('setMembrOrient', c_int)]
120
129 - def read(self, first, last, latency=0, skip=1):
130 ifirst, ilast = [self.data.segmentation.index_at(x) for x in (first, last)]
131 if ifirst != ilast:
132 raise Exception("ABF: can't read() from multiple segments at once")
133 segfirst = self.data.segmentation.segments[ifirst][0]
134 seglast = self.data.segmentation.segments[ifirst][1]
135 return read_with_latency(self.read_in_seg, first, last, latency, skip, ifirst, segfirst, seglast)
147
148
149
150
151
152
153
154
155
156
158 exists = os.path.exists(path)
159 size = 0
160 if exists:
161
162 size = os.stat(path)[6]
163 if size:
164 fileno = os.open(path, os.O_RDONLY)
165 map = mmap.mmap(fileno, size, access=mmap.ACCESS_READ)
166 return fileno, size, map
167 return None, None
168
169 GPATCH_MAX_SIGNALS = 8
170
172 """One open GPATCH dat file.
173
174 @ivar segbufs_of_signal: array[signal_ix][seg_ix] of numpy.array (float32)
175 @ivar sweeps: array[seg_ix] of GPatchWSweep or GPatchMSweep
176 """
178 QubData.__init__(self)
179 self.path = path
180 self.fileno = []
181 self.filesize = []
182 self.mmap = []
183 self.segbufs_of_signal = []
184 self.sweeps = []
185
186 match = re.match(r"(.*_ch)\d+(.*)", path)
187 if match:
188 for i in xrange(GPATCH_MAX_SIGNALS):
189 fileno, filesize, map = open_mmap_readonly("%s%d%s" % (match.group(1), i+1, match.group(2)))
190 if not (map is None):
191 self.signals.append({'Name' : 'ch%d' % (i+1)})
192 self.fileno.append(fileno)
193 self.filesize.append(filesize)
194 self.mmap.append(map)
195 self.segbufs_of_signal.append([])
196 else:
197 fileno, filesize ,map = open_mmap_readonly(path)
198 if not (map is None):
199 self.signals.append({'Name' : 'Current'})
200 self.fileno.append(fileno)
201 self.filesize.append(filesize)
202 self.mmap.append(map)
203 self.segbufs_of_signal.append([])
204 if not self.mmap:
205 raise Exception('No data signals found.')
206
207
208 map = self.mmap[0]
209 segm = []
210 offset = 0
211 try:
212 while map[offset:offset+GPM_maxCharSize] == "gpatch_m ":
213 offset += GPM_headerSize
214 struct = GPatchMSweep.from_buffer_copy(map, offset)
215 count = struct.acqNumPoints
216 segm.append((offset, count, struct))
217 offset += 2*count
218 except:
219 pass
220 if not segm:
221 offset = self.filesize[0] - sizeof(GPatchWSweep)
222 while offset >= 0:
223 struct = GPatchWSweep.from_buffer_copy(map, offset)
224 if struct.dummy5 == -12345:
225 print 'amp: ', struct.amp[:]
226 print 'pulseFilter: ', struct.pulseFilter
227 print 'decimFactor: ', struct.decimFactor
228 print 'dur: ', struct.dur[:]
229 print 'dummy0: ', struct.dummy0
230 print 'durAP: ', struct.durAP
231 print 'durBP: ', struct.durBP
232 print 'durSP: ', struct.durSP
233 print 'cyclePeriod: ', struct.cyclePeriod
234 print 'numSweeps: ', struct.numSweeps
235 print 'numSubPul: ', struct.numSubPul
236 print 'numPulses: ', struct.numPulses
237 print 'triggerPulse: ', struct.triggerPulse
238 print 'dummy1: ', struct.dummy1
239 print 'triggerDelay: ', struct.triggerDelay
240 print 'dummy2: ', struct.dummy2
241 print 'ampHP: ', struct.ampHP
242 print 'ampSH: ', struct.ampSH
243 print 'dummy3: ', struct.dummy3
244 print 'gain: ', struct.gain
245 print 'acqFilter: ', struct.acqFilter
246 print 'numAver: ', struct.numAver
247 print 'acqRate: ', struct.acqRate
248 print 'year: ', struct.year
249 print 'date: ', struct.date[:]
250 print 'time: ', struct.time[:]
251 print 'photonCounter: ', struct.photonCounter
252 print 'multiplexer: ', struct.multiplexer
253 print 'dummy4: ', struct.dummy4
254 print 'dummy5: ', struct.dummy5
255 print 'dummy6: ', struct.dummy6
256 print 'dummy7: ', struct.dummy7
257 print 'dummy8: ', struct.dummy8
258 print 'units: ', struct.units
259 print 'aDRange: ', struct.aDRange
260 print 'extra: ', struct.extra
261 offset -= sizeof(GPatchWSweep)
262 else:
263 offset -= 1
264
265
266
267
268
269
270
271
272
273
274
275
276 base, ext = os.path.splitext(path)
277 sess = qubx.tree.Open(base+'.qsf', True)
278 sess.close()
279 self.qsf = sess
280
281 self.read_session(sess, progressf)
282
284 for map in self.mmap:
285 if map:
286 map.close()
287 for fileno in self.fileno:
288 if fileno:
289 os.close(fileno)
290
291
292
293
294
295
296
297
298