1
|
|
|
# -*- coding: utf-8 -*- |
2
|
|
|
|
3
|
|
|
""" |
4
|
|
|
This file contains the Qudi hardware file implementation for FastComtec p7887 . |
5
|
|
|
|
6
|
|
|
Qudi 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
|
|
|
Qudi 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
|
|
|
along with Qudi. If not, see <http://www.gnu.org/licenses/>. |
18
|
|
|
|
19
|
|
|
Copyright (c) the Qudi Developers. See the COPYRIGHT.txt file at the |
20
|
|
|
top-level directory of this distribution and at <https://github.com/Ulm-IQO/qudi/> |
21
|
|
|
""" |
22
|
|
|
|
23
|
|
|
#TODO: start stop works but pause does not work, i guess gui/logic problem |
24
|
|
|
#TODO: What does get status do or need as return? |
25
|
|
|
#TODO: Check if there are more modules which are missing, and more settings for FastComtec which need to be put, should we include voltage threshold? |
26
|
|
|
|
27
|
|
|
from core.module import Base, ConfigOption |
28
|
|
|
from core.util.modules import get_main_dir |
29
|
|
|
from interface.fast_counter_interface import FastCounterInterface |
30
|
|
|
import time |
31
|
|
|
import os |
32
|
|
|
import numpy as np |
33
|
|
|
import ctypes |
34
|
|
|
|
35
|
|
|
|
36
|
|
|
|
37
|
|
|
""" |
38
|
|
|
Remark to the usage of ctypes: |
39
|
|
|
All Python types except integers (int), strings (str), and bytes (byte) objects |
40
|
|
|
have to be wrapped in their corresponding ctypes type, so that they can be |
41
|
|
|
converted to the required C data type. |
42
|
|
|
|
43
|
|
|
ctypes type C type Python type |
44
|
|
|
---------------------------------------------------------------- |
45
|
|
|
c_bool _Bool bool (1) |
46
|
|
|
c_char char 1-character bytes object |
47
|
|
|
c_wchar wchar_t 1-character string |
48
|
|
|
c_byte char int |
49
|
|
|
c_ubyte unsigned char int |
50
|
|
|
c_short short int |
51
|
|
|
c_ushort unsigned short int |
52
|
|
|
c_int int int |
53
|
|
|
c_uint unsigned int int |
54
|
|
|
c_long long int |
55
|
|
|
c_ulong unsigned long int |
56
|
|
|
c_longlong __int64 or |
57
|
|
|
long long int |
58
|
|
|
c_ulonglong unsigned __int64 or |
59
|
|
|
unsigned long long int |
60
|
|
|
c_size_t size_t int |
61
|
|
|
c_ssize_t ssize_t or |
62
|
|
|
Py_ssize_t int |
63
|
|
|
c_float float float |
64
|
|
|
c_double double float |
65
|
|
|
c_longdouble long double float |
66
|
|
|
c_char_p char * |
67
|
|
|
(NUL terminated) bytes object or None |
68
|
|
|
c_wchar_p wchar_t * |
69
|
|
|
(NUL terminated) string or None |
70
|
|
|
c_void_p void * int or None |
71
|
|
|
|
72
|
|
|
""" |
73
|
|
|
# Reconstruct the proper structure of the variables, which can be extracted |
74
|
|
|
# from the header file 'struct.h'. |
75
|
|
|
|
76
|
|
|
class AcqStatus(ctypes.Structure): |
77
|
|
|
""" Create a structured Data type with ctypes where the dll can write into. |
78
|
|
|
|
79
|
|
|
This object handles and retrieves the acquisition status data from the |
80
|
|
|
Fastcomtec. |
81
|
|
|
|
82
|
|
|
int started; // acquisition status: 1 if running, 0 else |
83
|
|
|
double runtime; // running time in seconds |
84
|
|
|
double totalsum; // total events |
85
|
|
|
double roisum; // events within ROI |
86
|
|
|
double roirate; // acquired ROI-events per second |
87
|
|
|
double nettosum; // ROI sum with background subtracted |
88
|
|
|
double sweeps; // Number of sweeps |
89
|
|
|
double stevents; // Start Events |
90
|
|
|
unsigned long maxval; // Maximum value in spectrum |
91
|
|
|
""" |
92
|
|
|
_fields_ = [('started', ctypes.c_int), |
93
|
|
|
('runtime', ctypes.c_double), |
94
|
|
|
('totalsum', ctypes.c_double), |
95
|
|
|
('roisum', ctypes.c_double), |
96
|
|
|
('roirate', ctypes.c_double), |
97
|
|
|
('ofls', ctypes.c_double), |
98
|
|
|
('sweeps', ctypes.c_double), |
99
|
|
|
('stevents', ctypes.c_double), |
100
|
|
View Code Duplication |
('maxval', ctypes.c_ulong), ] |
|
|
|
|
101
|
|
|
|
102
|
|
|
class AcqSettings(ctypes.Structure): |
103
|
|
|
""" Create a structured Data type with ctypes where the dll can write into. |
104
|
|
|
|
105
|
|
|
This object handles and retrieves the acquisition settings of the Fastcomtec. |
106
|
|
|
""" |
107
|
|
|
|
108
|
|
|
_fields_ = [('range', ctypes.c_ulong), |
109
|
|
|
('prena', ctypes.c_long), |
110
|
|
|
('cftfak', ctypes.c_long), |
111
|
|
|
('roimin', ctypes.c_ulong), |
112
|
|
|
('roimax', ctypes.c_ulong), |
113
|
|
|
('eventpreset', ctypes.c_double), |
114
|
|
|
('timepreset', ctypes.c_double), |
115
|
|
|
('savedata', ctypes.c_long), |
116
|
|
|
('fmt', ctypes.c_long), |
117
|
|
|
('autoinc', ctypes.c_long), |
118
|
|
|
('cycles', ctypes.c_long), |
119
|
|
|
('sweepmode', ctypes.c_long), |
120
|
|
|
('syncout', ctypes.c_long), |
121
|
|
|
('bitshift', ctypes.c_long), |
122
|
|
|
('digval', ctypes.c_long), |
123
|
|
|
('digio', ctypes.c_long), |
124
|
|
|
('dac0', ctypes.c_long), |
125
|
|
|
('dac1', ctypes.c_long), |
126
|
|
|
('swpreset', ctypes.c_double), |
127
|
|
|
('nregions', ctypes.c_long), |
128
|
|
|
('caluse', ctypes.c_long), |
129
|
|
|
('fstchan', ctypes.c_double), |
130
|
|
|
('active', ctypes.c_long), |
131
|
|
|
('calpoints', ctypes.c_long), ] |
132
|
|
|
|
133
|
|
|
class ACQDATA(ctypes.Structure): |
134
|
|
|
""" Create a structured Data type with ctypes where the dll can write into. |
135
|
|
|
|
136
|
|
|
This object handles and retrieves the acquisition data of the Fastcomtec. |
137
|
|
|
""" |
138
|
|
|
_fields_ = [('s0', ctypes.POINTER(ctypes.c_ulong)), |
139
|
|
|
('region', ctypes.POINTER(ctypes.c_ulong)), |
140
|
|
|
('comment', ctypes.c_char_p), |
141
|
|
|
('cnt', ctypes.POINTER(ctypes.c_double)), |
142
|
|
|
('hs0', ctypes.c_int), |
143
|
|
|
('hrg', ctypes.c_int), |
144
|
|
|
('hcm', ctypes.c_int), |
145
|
|
|
('hct', ctypes.c_int), ] |
146
|
|
|
|
147
|
|
|
|
148
|
|
|
|
149
|
|
|
class FastComtec(Base, FastCounterInterface): |
150
|
|
|
""" |
151
|
|
|
unstable: Jochen Scheuer, Simon Schmitt |
152
|
|
|
|
153
|
|
|
Hardware Class for the FastComtec Card. |
154
|
|
|
""" |
155
|
|
|
_modclass = 'FastComtec' |
156
|
|
|
_modtype = 'hardware' |
157
|
|
|
gated = ConfigOption('gated', False, missing='warn') |
158
|
|
|
trigger_safety = ConfigOption('trigger_safety', 200e-9, missing='warn') |
159
|
|
|
aom_delay = ConfigOption('aom_delay', 400e-9, missing='warn') |
160
|
|
|
minimal_binwidth = ConfigOption('minimal_binwidth', 0.25e-9, missing='warn') |
161
|
|
|
|
162
|
|
|
def __init__(self, config, **kwargs): |
163
|
|
|
super().__init__(config=config, **kwargs) |
164
|
|
|
|
165
|
|
|
self.log.debug('The following configuration was found.') |
166
|
|
|
|
167
|
|
|
# checking for the right configuration |
168
|
|
|
for key in config.keys(): |
169
|
|
|
self.log.info('{0}: {1}'.format(key,config[key])) |
170
|
|
|
#this variable has to be added because there is no difference |
171
|
|
|
#in the fastcomtec it can be on "stopped" or "halt" |
172
|
|
|
self.stopped_or_halt = "stopped" |
173
|
|
|
self.timetrace_tmp = [] |
174
|
|
|
|
175
|
|
|
def on_activate(self): |
176
|
|
|
""" Initialisation performed during activation of the module. |
177
|
|
|
""" |
178
|
|
|
self.dll = ctypes.windll.LoadLibrary('dp7887.dll') |
179
|
|
|
if self.gated: |
180
|
|
|
self.change_sweep_mode(gated=True) |
181
|
|
|
else: |
182
|
|
|
self.change_sweep_mode(gated=False) |
183
|
|
|
return |
184
|
|
|
|
185
|
|
|
|
186
|
|
|
def on_deactivate(self): |
187
|
|
|
""" Deinitialisation performed during deactivation of the module. |
188
|
|
|
""" |
189
|
|
|
return |
190
|
|
|
|
191
|
|
|
def get_constraints(self): |
192
|
|
|
""" Retrieve the hardware constrains from the Fast counting device. |
193
|
|
|
|
194
|
|
|
@return dict: dict with keys being the constraint names as string and |
195
|
|
|
items are the definition for the constaints. |
196
|
|
|
|
197
|
|
|
The keys of the returned dictionary are the str name for the constraints |
198
|
|
|
(which are set in this method). |
199
|
|
|
|
200
|
|
|
NO OTHER KEYS SHOULD BE INVENTED! |
201
|
|
|
|
202
|
|
|
If you are not sure about the meaning, look in other hardware files to |
203
|
|
|
get an impression. If still additional constraints are needed, then they |
204
|
|
|
have to be added to all files containing this interface. |
205
|
|
|
|
206
|
|
|
The items of the keys are again dictionaries which have the generic |
207
|
|
|
dictionary form: |
208
|
|
|
{'min': <value>, |
209
|
|
|
'max': <value>, |
210
|
|
|
'step': <value>, |
211
|
|
|
'unit': '<value>'} |
212
|
|
|
|
213
|
|
|
Only the key 'hardware_binwidth_list' differs, since they |
214
|
|
|
contain the list of possible binwidths. |
215
|
|
|
|
216
|
|
|
If the constraints cannot be set in the fast counting hardware then |
217
|
|
|
write just zero to each key of the generic dicts. |
218
|
|
|
Note that there is a difference between float input (0.0) and |
219
|
|
|
integer input (0), because some logic modules might rely on that |
220
|
|
|
distinction. |
221
|
|
|
|
222
|
|
|
ALL THE PRESENT KEYS OF THE CONSTRAINTS DICT MUST BE ASSIGNED! |
223
|
|
|
""" |
224
|
|
|
|
225
|
|
|
constraints = dict() |
226
|
|
|
|
227
|
|
|
# the unit of those entries are seconds per bin. In order to get the |
228
|
|
|
# current binwidth in seconds use the get_binwidth method. |
229
|
|
|
constraints['hardware_binwidth_list'] = list(self.minimal_binwidth * (2 ** np.array( |
230
|
|
|
np.linspace(0,24,25)))) |
231
|
|
|
constraints['max_sweep_len'] = 6.8 |
232
|
|
|
return constraints |
233
|
|
|
|
234
|
|
|
def configure(self, bin_width_s, record_length_s, number_of_gates=0, filename=None): |
235
|
|
|
""" Configuration of the fast counter. |
236
|
|
|
|
237
|
|
|
@param float bin_width_s: Length of a single time bin in the time trace |
238
|
|
|
histogram in seconds. |
239
|
|
|
@param float record_length_s: Total length of the timetrace/each single |
240
|
|
|
gate in seconds. |
241
|
|
|
@param int number_of_gates: optional, number of gates in the pulse |
242
|
|
|
sequence. Ignore for not gated counter. |
243
|
|
|
|
244
|
|
|
@return tuple(binwidth_s, record_length_s, number_of_gates): |
245
|
|
|
binwidth_s: float the actual set binwidth in seconds |
246
|
|
|
gate_length_s: the actual record length in seconds |
247
|
|
|
number_of_gates: the number of gated, which are accepted, |
248
|
|
|
None if not-gated |
249
|
|
|
""" |
250
|
|
|
|
251
|
|
|
# when not gated, record length = total sequence length, when gated, record length = laser length. |
252
|
|
|
# subtract 200 ns to make sure no sequence trigger is missed |
253
|
|
|
record_length_FastComTech_s = record_length_s |
254
|
|
|
if self.gated: |
255
|
|
|
# add time to account for AOM delay |
256
|
|
|
no_of_bins = int((record_length_FastComTech_s + self.aom_delay) / self.set_binwidth(bin_width_s)) |
257
|
|
|
else: |
258
|
|
|
# subtract time to make sure no sequence trigger is missed |
259
|
|
|
no_of_bins = int((record_length_FastComTech_s - self.trigger_safety) / self.set_binwidth(bin_width_s)) |
260
|
|
|
|
261
|
|
|
self.set_length(no_of_bins, preset=1, cycles=number_of_gates) |
262
|
|
|
|
263
|
|
|
if filename is not None: |
264
|
|
|
self._change_filename(filename) |
265
|
|
|
|
266
|
|
|
return (self.get_binwidth(), record_length_FastComTech_s, number_of_gates) |
267
|
|
|
|
268
|
|
|
|
269
|
|
|
|
270
|
|
|
def get_status(self): |
271
|
|
|
""" |
272
|
|
|
Receives the current status of the Fast Counter and outputs it as return value. |
273
|
|
|
0 = unconfigured |
274
|
|
|
1 = idle |
275
|
|
|
2 = running |
276
|
|
|
3 = paused |
277
|
|
|
-1 = error state |
278
|
|
|
""" |
279
|
|
|
status = AcqStatus() |
280
|
|
|
self.dll.GetStatusData(ctypes.byref(status), 0) |
281
|
|
|
if status.started == 1: |
282
|
|
|
return 2 |
283
|
|
|
elif status.started == 0: |
284
|
|
|
if self.stopped_or_halt == "stopped": |
285
|
|
|
return 1 |
286
|
|
|
elif self.stopped_or_halt == "halt": |
287
|
|
|
return 3 |
288
|
|
|
else: |
289
|
|
|
self.log.error('FastComTec neither stopped nor halt') |
290
|
|
|
|
291
|
|
|
return -1 |
292
|
|
|
else: |
293
|
|
|
self.log.error( |
294
|
|
|
'There is an unknown status from FastComtec. The status message was %s' % (str(status.started))) |
295
|
|
|
return -1 |
296
|
|
|
|
297
|
|
|
def get_current_runtime(self): |
298
|
|
|
""" |
299
|
|
|
Returns the current runtime. |
300
|
|
|
@return float runtime: in s |
301
|
|
|
""" |
302
|
|
|
status = AcqStatus() |
303
|
|
|
self.dll.GetStatusData(ctypes.byref(status), 0) |
304
|
|
|
return status.runtime |
305
|
|
|
|
306
|
|
|
def get_current_sweeps(self): |
307
|
|
|
""" |
308
|
|
|
Returns the current runtime. |
309
|
|
|
@return int sweeps: in sweeps |
310
|
|
|
""" |
311
|
|
|
status = AcqStatus() |
312
|
|
|
self.dll.GetStatusData(ctypes.byref(status), 0) |
313
|
|
|
return status.sweeps |
314
|
|
|
|
315
|
|
|
def start_measure(self): |
316
|
|
|
"""Start the measurement. """ |
317
|
|
|
status = self.dll.Start(0) |
318
|
|
|
while self.get_status() != 2: |
319
|
|
|
time.sleep(0.05) |
320
|
|
|
return status |
321
|
|
|
|
322
|
|
|
def pause_measure(self): |
323
|
|
|
"""Make a pause in the measurement, which can be continued. """ |
324
|
|
|
self.stopped_or_halt = "halt" |
325
|
|
|
status = self.dll.Halt(0) |
326
|
|
|
while self.get_status() != 3: |
327
|
|
|
time.sleep(0.05) |
328
|
|
|
|
329
|
|
|
if self.gated: |
330
|
|
|
self.timetrace_tmp = self.get_data_trace() |
331
|
|
|
return status |
332
|
|
|
|
333
|
|
|
def stop_measure(self): |
334
|
|
|
"""Stop the measurement. """ |
335
|
|
|
self.stopped_or_halt = "stopped" |
336
|
|
|
status = self.dll.Halt(0) |
337
|
|
|
while self.get_status() != 1: |
338
|
|
|
time.sleep(0.05) |
339
|
|
|
|
340
|
|
|
if self.gated: |
341
|
|
|
self.timetrace_tmp = [] |
342
|
|
|
return status |
343
|
|
|
|
344
|
|
|
def continue_measure(self): |
345
|
|
|
"""Continue a paused measurement. """ |
346
|
|
|
if self.gated: |
347
|
|
|
status = self.start_measure() |
348
|
|
|
else: |
349
|
|
|
status = self.dll.Continue(0) |
350
|
|
|
while self.get_status() != 2: |
351
|
|
|
time.sleep(0.05) |
352
|
|
|
return status |
353
|
|
|
|
354
|
|
|
def get_binwidth(self): |
355
|
|
|
""" Returns the width of a single timebin in the timetrace in seconds. |
356
|
|
|
|
357
|
|
|
@return float: current length of a single bin in seconds (seconds/bin) |
358
|
|
|
|
359
|
|
|
The red out bitshift will be converted to binwidth. The binwidth is |
360
|
|
|
defined as 2**bitshift*minimal_binwidth. |
361
|
|
|
""" |
362
|
|
|
return self.minimal_binwidth*(2**int(self.get_bitshift())) |
363
|
|
|
|
364
|
|
|
|
365
|
|
|
def is_gated(self): |
366
|
|
|
""" Check the gated counting possibility. |
367
|
|
|
|
368
|
|
|
@return bool: Boolean value indicates if the fast counter is a gated |
369
|
|
|
counter (TRUE) or not (FALSE). |
370
|
|
|
""" |
371
|
|
|
return self.gated |
372
|
|
|
|
373
|
|
|
def get_data_trace(self): |
374
|
|
|
""" |
375
|
|
|
Polls the current timetrace data from the fast counter and returns it as a numpy array (dtype = int64). |
376
|
|
|
The binning specified by calling configure() must be taken care of in this hardware class. |
377
|
|
|
A possible overflow of the histogram bins must be caught here and taken care of. |
378
|
|
|
If the counter is UNgated it will return a 1D-numpy-array with returnarray[timebin_index] |
379
|
|
|
If the counter is gated it will return a 2D-numpy-array with returnarray[gate_index, timebin_index] |
380
|
|
|
|
381
|
|
|
@return arrray: Time trace. |
382
|
|
|
""" |
383
|
|
|
setting = AcqSettings() |
384
|
|
|
self.dll.GetSettingData(ctypes.byref(setting), 0) |
385
|
|
|
N = setting.range |
386
|
|
|
|
387
|
|
|
if self.gated: |
388
|
|
|
bsetting=AcqSettings() |
389
|
|
|
self.dll.GetSettingData(ctypes.byref(bsetting), 0) |
390
|
|
|
H = bsetting.cycles |
391
|
|
|
data = np.empty((H, int(N / H)), dtype=np.uint32) |
392
|
|
|
|
393
|
|
|
else: |
394
|
|
|
data = np.empty((N,), dtype=np.uint32) |
395
|
|
|
|
396
|
|
|
p_type_ulong = ctypes.POINTER(ctypes.c_uint32) |
397
|
|
|
ptr = data.ctypes.data_as(p_type_ulong) |
398
|
|
|
self.dll.LVGetDat(ptr, 0) |
399
|
|
|
time_trace = np.int64(data) |
400
|
|
|
|
401
|
|
|
if self.gated and self.timetrace_tmp != []: |
402
|
|
|
time_trace = time_trace + self.timetrace_tmp |
403
|
|
|
|
404
|
|
|
return time_trace |
405
|
|
|
|
406
|
|
|
|
407
|
|
|
def get_data_testfile(self): |
408
|
|
|
''' Load data test file ''' |
409
|
|
|
data = np.loadtxt(os.path.join(get_main_dir(), 'tools', 'FastComTec_demo_timetrace.asc')) |
410
|
|
|
time.sleep(0.5) |
411
|
|
|
return data |
412
|
|
|
|
413
|
|
|
|
414
|
|
|
# ========================================================================= |
415
|
|
|
# Non Interface methods |
416
|
|
|
# ========================================================================= |
417
|
|
|
|
418
|
|
|
def get_bitshift(self): |
419
|
|
|
"""Get bitshift from Fastcomtec. |
420
|
|
|
|
421
|
|
|
@return int settings.bitshift: the red out bitshift |
422
|
|
|
""" |
423
|
|
|
|
424
|
|
|
settings = AcqSettings() |
425
|
|
|
self.dll.GetSettingData(ctypes.byref(settings), 0) |
426
|
|
|
return int(settings.bitshift) |
427
|
|
|
|
428
|
|
|
def set_bitshift(self, bitshift): |
429
|
|
|
""" Sets the bitshift properly for this card. |
430
|
|
|
|
431
|
|
|
@param int bitshift: |
432
|
|
|
|
433
|
|
|
@return int: asks the actual bitshift and returns the red out value |
434
|
|
|
""" |
435
|
|
|
|
436
|
|
|
cmd = 'BITSHIFT={0}'.format(bitshift) |
437
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
438
|
|
|
return self.get_bitshift() |
439
|
|
|
|
440
|
|
|
def set_binwidth(self, binwidth): |
441
|
|
|
""" Set defined binwidth in Card. |
442
|
|
|
|
443
|
|
|
@param float binwidth: the current binwidth in seconds |
444
|
|
|
|
445
|
|
|
@return float: Red out bitshift converted to binwidth |
446
|
|
|
|
447
|
|
|
The binwidth is converted into to an appropiate bitshift defined as |
448
|
|
|
2**bitshift*minimal_binwidth. |
449
|
|
|
""" |
450
|
|
|
bitshift = int(np.log2(binwidth/self.minimal_binwidth)) |
451
|
|
|
new_bitshift=self.set_bitshift(bitshift) |
452
|
|
|
|
453
|
|
|
return self.minimal_binwidth*(2**new_bitshift) |
454
|
|
|
|
455
|
|
|
|
456
|
|
|
#TODO: Check such that only possible lengths are set. |
457
|
|
|
def set_length(self, length_bins, preset=None, cycles=None, sequences=None): |
458
|
|
|
""" Sets the length of the length of the actual measurement. |
459
|
|
|
|
460
|
|
|
@param int length_bins: Length of the measurement in bins |
461
|
|
|
|
462
|
|
|
@return float: Red out length of measurement |
463
|
|
|
""" |
464
|
|
|
constraints = self.get_constraints() |
465
|
|
|
if length_bins * self.get_binwidth() < constraints['max_sweep_len']: |
466
|
|
|
cmd = 'RANGE={0}'.format(int(length_bins)) |
467
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
468
|
|
|
cmd = 'roimax={0}'.format(int(length_bins)) |
469
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
470
|
|
|
if preset != None: |
471
|
|
|
cmd = 'swpreset={0}'.format(preset) |
472
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
473
|
|
|
if cycles != None and cycles != 0: |
474
|
|
|
cmd = 'cycles={0}'.format(cycles) |
475
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
476
|
|
|
if sequences != None and sequences != 0: |
477
|
|
|
cmd = 'sequences={0}'.format(sequences) |
478
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
479
|
|
|
return self.get_length() |
480
|
|
|
else: |
481
|
|
|
self.log.error( |
482
|
|
|
'Length of sequence is too high: %s' % (str(length_bins * self.get_binwidth()))) |
483
|
|
|
return -1 |
484
|
|
|
|
485
|
|
|
def set_preset(self, preset): |
486
|
|
|
cmd = 'swpreset={0}'.format(preset) |
487
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
488
|
|
|
return preset |
489
|
|
|
|
490
|
|
|
def set_cycles(self, cycles): |
491
|
|
|
cmd = 'cycles={0}'.format(cycles) |
492
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
493
|
|
|
return cycles |
494
|
|
|
|
495
|
|
|
def get_length(self): |
496
|
|
|
""" Get the length of the current measurement. |
497
|
|
|
|
498
|
|
|
@return int: length of the current measurement |
499
|
|
|
""" |
500
|
|
|
setting = AcqSettings() |
501
|
|
|
self.dll.GetSettingData(ctypes.byref(setting), 0) |
502
|
|
|
return int(setting.range) |
503
|
|
|
|
504
|
|
|
def _change_filename(self,name): |
505
|
|
|
""" Changed the name in FCT""" |
506
|
|
|
cmd = 'datname=%s'%name |
507
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
508
|
|
|
return name |
509
|
|
|
|
510
|
|
|
def change_sweep_mode(self, gated): |
511
|
|
|
if gated: |
512
|
|
|
cmd = 'sweepmode={0}'.format(hex(1978500)) |
513
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
514
|
|
|
cmd = 'prena={0}'.format(hex(16)) #To select starts preset |
515
|
|
|
# cmd = 'prena={0}'.format(hex(4)) #To select sweeps preset |
516
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
517
|
|
|
self.gated = True |
518
|
|
|
else: |
519
|
|
View Code Duplication |
# fastcomtch standard settings for ungated acquisition (check manual) |
|
|
|
|
520
|
|
|
cmd = 'sweepmode={0}'.format(hex(1978496)) |
521
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
522
|
|
|
cmd = 'prena={0}'.format(hex(0)) |
523
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
524
|
|
|
self.gated = False |
525
|
|
|
return gated |
526
|
|
|
|
527
|
|
|
|
528
|
|
|
def change_save_mode(self, mode): |
529
|
|
|
""" Changes the save mode of p7887 |
530
|
|
|
|
531
|
|
|
@param int mode: Specifies the save mode (0: No Save at Halt, 1: Save at Halt, |
532
|
|
|
2: Write list file, No Save at Halt, 3: Write list file, Save at Halt |
533
|
|
|
|
534
|
|
|
@return int mode: specified save mode |
535
|
|
|
""" |
536
|
|
|
cmd = 'savedata={0}'.format(mode) |
537
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
538
|
|
|
return mode |
539
|
|
|
|
540
|
|
|
def set_delay_start(self, delay_s): |
541
|
|
|
""" Sets the record delay length |
542
|
|
|
|
543
|
|
|
@param int delay_s: Record delay after receiving a start trigger |
544
|
|
|
|
545
|
|
|
@return int mode: specified save mode |
546
|
|
|
""" |
547
|
|
|
|
548
|
|
|
# A delay can only be adjusted in steps of 6.4ns |
549
|
|
|
delay_bins = np.rint(delay_s / 6.4e-9 /2.5) |
550
|
|
|
cmd = 'fstchan={0}'.format(int(delay_bins)) |
551
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
552
|
|
|
return delay_bins |
553
|
|
|
|
554
|
|
|
def get_delay_start(self): |
555
|
|
|
""" Returns the current record delay length |
556
|
|
|
|
557
|
|
|
@return float delay_s: current record delay length in seconds |
558
|
|
|
""" |
559
|
|
|
bsetting = AcqSettings() |
560
|
|
|
self.dll.GetSettingData(ctypes.byref(bsetting), 0) |
561
|
|
|
delay_s = bsetting.fstchan * 6.4e-9 *2.5 |
562
|
|
|
#prena = bsetting.prena |
563
|
|
|
return delay_s |
564
|
|
|
|
565
|
|
|
# ========================================================================= |
566
|
|
|
# The following methods have to be carefully reviewed and integrated as |
567
|
|
|
# internal methods/function, because they might be important one day. |
568
|
|
|
# ========================================================================= |
569
|
|
|
|
570
|
|
|
def SetDelay(self, t): |
571
|
|
|
#~ setting = AcqSettings() |
572
|
|
|
#~ self.dll.GetSettingData(ctypes.byref(setting), 0) |
573
|
|
|
#~ setting.fstchan = t/6.4 |
574
|
|
|
#~ self.dll.StoreSettingData(ctypes.byref(setting), 0) |
575
|
|
|
#~ self.dll.NewSetting(0) |
576
|
|
|
self.dll.RunCmd(0, 'DELAY={0:f}'.format(t)) |
577
|
|
|
return self.GetDelay() |
578
|
|
|
|
579
|
|
|
def GetDelay(self): |
580
|
|
|
setting = AcqSettings() |
581
|
|
|
self.dll.GetSettingData(ctypes.byref(setting), 0) |
582
|
|
|
return setting.fstchan * 6.4 |
583
|
|
|
|
584
|
|
|
|
585
|
|
|
#former SaveData_fast |
586
|
|
|
def SaveData_locally(self, filename, laser_index): |
587
|
|
|
# os.chdir(r'D:\data\FastComTec') |
588
|
|
|
data = self.get_data() |
589
|
|
|
fil = open(filename + '.asc', 'w') |
590
|
|
|
for i in laser_index: |
591
|
|
|
for n in data[i:i+int(round(3000/(self.minimal_binwidth*2**self.GetBitshift()))) |
592
|
|
|
+int(round(1000/(self.minimal_binwidth*2**self.GetBitshift())))]: |
593
|
|
|
fil.write('{0!s}\n'.format(n)) |
594
|
|
|
fil.close() |
595
|
|
|
|
596
|
|
|
def SetLevel(self, start, stop): |
597
|
|
|
setting = AcqSettings() |
598
|
|
|
self.dll.GetSettingData(ctypes.byref(setting), 0) |
599
|
|
|
def FloatToWord(r): |
600
|
|
|
return int((r+2.048)/4.096*int('ffff',16)) |
601
|
|
|
setting.dac0 = ( setting.dac0 & int('ffff0000',16) ) | FloatToWord(start) |
602
|
|
|
setting.dac1 = ( setting.dac1 & int('ffff0000',16) ) | FloatToWord(stop) |
603
|
|
|
self.dll.StoreSettingData(ctypes.byref(setting), 0) |
604
|
|
|
self.dll.NewSetting(0) |
605
|
|
|
return self.GetLevel() |
606
|
|
|
|
607
|
|
|
def GetLevel(self): |
608
|
|
|
setting = AcqSettings() |
609
|
|
|
self.dll.GetSettingData(ctypes.byref(setting), 0) |
610
|
|
|
def WordToFloat(word): |
611
|
|
|
return (word & int('ffff',16)) * 4.096 / int('ffff',16) - 2.048 |
612
|
|
|
return WordToFloat(setting.dac0), WordToFloat(setting.dac1) |
613
|
|
|
|
614
|
|
|
#used in one script for SSR |
615
|
|
|
#Todo: Remove |
616
|
|
|
def Running(self): |
617
|
|
|
s = self.GetStatus() |
618
|
|
|
return s.started |
619
|
|
|
|
620
|
|
|
def GetStatus(self): |
621
|
|
|
status = AcqStatus() |
622
|
|
|
self.dll.GetStatusData(ctypes.byref(status), 0) |
623
|
|
|
return status |
624
|
|
|
|
625
|
|
|
|
626
|
|
|
def load_setup(self, configname): |
627
|
|
|
cmd = 'loadcnf={0}'.format(configname) |
628
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |