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: Check if there are more modules which are missing, and more settings for FastComtec which need to be put, should we include voltage threshold? |
25
|
|
|
|
26
|
|
|
|
27
|
|
|
|
28
|
|
|
from core.module import Base, ConfigOption |
29
|
|
|
from core.util.modules import get_main_dir |
30
|
|
|
from interface.fast_counter_interface import FastCounterInterface |
31
|
|
|
import time |
32
|
|
|
import os |
33
|
|
|
import numpy as np |
34
|
|
|
import ctypes |
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
|
|
|
('maxval', ctypes.c_ulong), ] |
101
|
|
|
|
102
|
|
|
|
103
|
|
|
class AcqSettings(ctypes.Structure): |
104
|
|
|
_fields_ = [('range', ctypes.c_long), |
105
|
|
|
('cftfak', ctypes.c_long), |
106
|
|
|
('roimin', ctypes.c_long), |
107
|
|
|
('roimax', ctypes.c_long), |
108
|
|
|
('nregions', ctypes.c_long), |
109
|
|
|
('caluse', ctypes.c_long), |
110
|
|
|
('calpoints', ctypes.c_long), |
111
|
|
|
('param', ctypes.c_long), |
112
|
|
|
('offset', ctypes.c_long), |
113
|
|
|
('xdim', ctypes.c_long), |
114
|
|
|
('bitshift', ctypes.c_ulong), |
115
|
|
|
('active', ctypes.c_long), |
116
|
|
|
('eventpreset', ctypes.c_double), |
117
|
|
|
('dummy1', ctypes.c_double), |
118
|
|
|
('dummy2', ctypes.c_double), |
119
|
|
|
('dummy3', ctypes.c_double), ] |
120
|
|
|
|
121
|
|
|
class ACQDATA(ctypes.Structure): |
122
|
|
|
""" Create a structured Data type with ctypes where the dll can write into. |
123
|
|
|
|
124
|
|
|
This object handles and retrieves the acquisition data of the Fastcomtec. |
125
|
|
|
""" |
126
|
|
|
_fields_ = [('s0', ctypes.POINTER(ctypes.c_ulong)), |
127
|
|
|
('region', ctypes.POINTER(ctypes.c_ulong)), |
128
|
|
|
('comment', ctypes.c_char_p), |
129
|
|
|
('cnt', ctypes.POINTER(ctypes.c_double)), |
130
|
|
|
('hs0', ctypes.c_int), |
131
|
|
|
('hrg', ctypes.c_int), |
132
|
|
|
('hcm', ctypes.c_int), |
133
|
|
|
('hct', ctypes.c_int), ] |
134
|
|
|
|
135
|
|
View Code Duplication |
|
|
|
|
|
136
|
|
|
class BOARDSETTING(ctypes.Structure): |
137
|
|
|
_fields_ = [('sweepmode', ctypes.c_long), |
138
|
|
|
('prena', ctypes.c_long), |
139
|
|
|
('cycles', ctypes.c_long), |
140
|
|
|
('sequences', ctypes.c_long), |
141
|
|
|
('syncout', ctypes.c_long), |
142
|
|
|
('digio', ctypes.c_long), |
143
|
|
|
('digval', ctypes.c_long), |
144
|
|
|
('dac0', ctypes.c_long), |
145
|
|
|
('dac1', ctypes.c_long), |
146
|
|
|
('dac2', ctypes.c_long), |
147
|
|
|
('dac3', ctypes.c_long), |
148
|
|
|
('dac4', ctypes.c_long), |
149
|
|
|
('dac5', ctypes.c_long), |
150
|
|
|
('fdac', ctypes.c_int), |
151
|
|
|
('tagbits', ctypes.c_int), |
152
|
|
|
('extclk', ctypes.c_int), |
153
|
|
|
('maxchan', ctypes.c_long), |
154
|
|
|
('serno', ctypes.c_long), |
155
|
|
|
('ddruse', ctypes.c_long), |
156
|
|
|
('active', ctypes.c_long), |
157
|
|
|
('holdafter', ctypes.c_double), |
158
|
|
|
('swpreset', ctypes.c_double), |
159
|
|
|
('fstchan', ctypes.c_double), |
160
|
|
|
('timepreset', ctypes.c_double), ] |
161
|
|
|
|
162
|
|
|
class FastComtec(Base, FastCounterInterface): |
163
|
|
|
""" |
164
|
|
|
stable: Jochen Scheuer, Simon Schmitt |
165
|
|
|
|
166
|
|
|
Hardware Class for the FastComtec Card. |
167
|
|
|
""" |
168
|
|
|
_modclass = 'FastComtec' |
169
|
|
|
_modtype = 'hardware' |
170
|
|
|
gated = ConfigOption('gated', False, missing='warn') |
171
|
|
|
trigger_safety = ConfigOption('trigger_safety', 200e-9, missing='warn') |
172
|
|
|
aom_delay = ConfigOption('aom_delay', 400e-9, missing='warn') |
173
|
|
|
minimal_binwidth = ConfigOption('minimal_binwidth', 0.2e-9, missing='warn') |
174
|
|
|
|
175
|
|
|
def __init__(self, config, **kwargs): |
176
|
|
|
super().__init__(config=config, **kwargs) |
177
|
|
|
|
178
|
|
|
self.log.debug('The following configuration was found.') |
179
|
|
|
|
180
|
|
|
# checking for the right configuration |
181
|
|
|
for key in config.keys(): |
182
|
|
|
self.log.info('{0}: {1}'.format(key,config[key])) |
183
|
|
|
|
184
|
|
|
#this variable has to be added because there is no difference |
185
|
|
|
#in the fastcomtec it can be on "stopped" or "halt" |
186
|
|
|
self.stopped_or_halt = "stopped" |
187
|
|
|
self.timetrace_tmp = [] |
188
|
|
|
|
189
|
|
|
def on_activate(self): |
190
|
|
|
""" Initialisation performed during activation of the module. |
191
|
|
|
""" |
192
|
|
|
|
193
|
|
|
self.dll = ctypes.windll.LoadLibrary('C:\Windows\System32\DMCS6.dll') |
194
|
|
|
if self.gated: |
195
|
|
|
self.change_sweep_mode(gated=True) |
196
|
|
|
else: |
197
|
|
|
self.change_sweep_mode(gated=False) |
198
|
|
|
return |
199
|
|
|
|
200
|
|
|
def on_deactivate(self): |
201
|
|
|
""" Deinitialisation performed during deactivation of the module. |
202
|
|
|
""" |
203
|
|
|
return |
204
|
|
|
|
205
|
|
|
def get_constraints(self): |
206
|
|
|
""" Retrieve the hardware constrains from the Fast counting device. |
207
|
|
|
|
208
|
|
|
@return dict: dict with keys being the constraint names as string and |
209
|
|
|
items are the definition for the constaints. |
210
|
|
|
|
211
|
|
|
The keys of the returned dictionary are the str name for the constraints |
212
|
|
|
(which are set in this method). |
213
|
|
|
|
214
|
|
|
NO OTHER KEYS SHOULD BE INVENTED! |
215
|
|
|
|
216
|
|
|
If you are not sure about the meaning, look in other hardware files to |
217
|
|
|
get an impression. If still additional constraints are needed, then they |
218
|
|
|
have to be added to all files containing this interface. |
219
|
|
|
|
220
|
|
|
The items of the keys are again dictionaries which have the generic |
221
|
|
|
dictionary form: |
222
|
|
|
{'min': <value>, |
223
|
|
|
'max': <value>, |
224
|
|
|
'step': <value>, |
225
|
|
|
'unit': '<value>'} |
226
|
|
|
|
227
|
|
|
Only the key 'hardware_binwidth_list' differs, since they |
228
|
|
|
contain the list of possible binwidths. |
229
|
|
|
|
230
|
|
|
If the constraints cannot be set in the fast counting hardware then |
231
|
|
|
write just zero to each key of the generic dicts. |
232
|
|
|
Note that there is a difference between float input (0.0) and |
233
|
|
|
integer input (0), because some logic modules might rely on that |
234
|
|
|
distinction. |
235
|
|
|
|
236
|
|
|
ALL THE PRESENT KEYS OF THE CONSTRAINTS DICT MUST BE ASSIGNED! |
237
|
|
|
""" |
238
|
|
|
|
239
|
|
|
constraints = dict() |
240
|
|
|
|
241
|
|
|
# the unit of those entries are seconds per bin. In order to get the |
242
|
|
|
# current binwidth in seonds use the get_binwidth method. |
243
|
|
|
constraints['hardware_binwidth_list'] = list(self.minimal_binwidth * (2 ** np.array( |
244
|
|
|
np.linspace(0,24,25)))) |
245
|
|
|
constraints['max_sweep_len'] = 6.8 |
246
|
|
|
return constraints |
247
|
|
|
|
248
|
|
|
def configure(self, bin_width_s, record_length_s, number_of_gates=0, filename=None): |
249
|
|
|
""" Configuration of the fast counter. |
250
|
|
|
|
251
|
|
|
@param float bin_width_s: Length of a single time bin in the time trace |
252
|
|
|
histogram in seconds. |
253
|
|
|
@param float record_length_s: Total length of the timetrace/each single |
254
|
|
|
gate in seconds. |
255
|
|
|
@param int number_of_gates: optional, number of gates in the pulse |
256
|
|
|
sequence. Ignore for not gated counter. |
257
|
|
|
|
258
|
|
|
@return tuple(binwidth_s, record_length_s, number_of_gates): |
259
|
|
|
binwidth_s: float the actual set binwidth in seconds |
260
|
|
|
gate_length_s: the actual record length in seconds |
261
|
|
|
number_of_gates: the number of gated, which are accepted, |
262
|
|
|
None if not-gated |
263
|
|
|
""" |
264
|
|
|
|
265
|
|
|
# when not gated, record length = total sequence length, when gated, record length = laser length. |
266
|
|
|
# subtract 200 ns to make sure no sequence trigger is missed |
267
|
|
|
record_length_FastComTech_s = record_length_s |
268
|
|
|
if self.gated: |
269
|
|
|
# add time to account for AOM delay |
270
|
|
|
no_of_bins = int((record_length_FastComTech_s + self.aom_delay) / self.set_binwidth(bin_width_s)) |
271
|
|
|
else: |
272
|
|
|
# subtract time to make sure no sequence trigger is missed |
273
|
|
|
no_of_bins = int((record_length_FastComTech_s - self.trigger_safety) / self.set_binwidth(bin_width_s)) |
274
|
|
|
|
275
|
|
|
self.set_length(no_of_bins, preset=1, cycles=number_of_gates) |
276
|
|
|
|
277
|
|
|
if filename is not None: |
278
|
|
|
self._change_filename(filename) |
279
|
|
|
|
280
|
|
|
return (self.get_binwidth(), record_length_FastComTech_s, number_of_gates) |
281
|
|
|
|
282
|
|
|
#card if running or halt or stopped ... |
283
|
|
|
def get_status(self): |
284
|
|
|
""" |
285
|
|
|
Receives the current status of the Fast Counter and outputs it as return value. |
286
|
|
|
0 = unconfigured |
287
|
|
|
1 = idle |
288
|
|
|
2 = running |
289
|
|
|
3 = paused |
290
|
|
|
-1 = error state |
291
|
|
|
""" |
292
|
|
|
status = AcqStatus() |
293
|
|
|
self.dll.GetStatusData(ctypes.byref(status), 0) |
294
|
|
|
# status.started = 3 measn that fct is about to stop |
295
|
|
|
while status.started == 3: |
296
|
|
|
time.sleep(0.1) |
297
|
|
|
self.dll.GetStatusData(ctypes.byref(status), 0) |
298
|
|
|
if status.started == 1: |
299
|
|
|
return 2 |
300
|
|
|
elif status.started == 0: |
301
|
|
|
if self.stopped_or_halt == "stopped": |
302
|
|
|
return 1 |
303
|
|
|
elif self.stopped_or_halt == "halt": |
304
|
|
|
return 3 |
305
|
|
|
else: |
306
|
|
|
self.log.error('There is an unknown status from FastComtec. The status message was %s' % (str(status.started))) |
307
|
|
|
|
308
|
|
|
return -1 |
309
|
|
|
else: |
310
|
|
|
self.log.error( |
311
|
|
|
'There is an unknown status from FastComtec. The status message was %s' % (str(status.started))) |
312
|
|
|
return -1 |
313
|
|
|
|
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
|
|
|
def is_gated(self): |
365
|
|
|
""" Check the gated counting possibility. |
366
|
|
|
|
367
|
|
|
@return bool: Boolean value indicates if the fast counter is a gated |
368
|
|
|
counter (TRUE) or not (FALSE). |
369
|
|
|
""" |
370
|
|
|
return self.gated |
371
|
|
|
|
372
|
|
|
def set_gated(self, gated): |
373
|
|
|
""" Check the gated counting possibility. |
374
|
|
|
|
375
|
|
|
@return bool: Boolean value indicates if the fast counter is a gated |
376
|
|
|
counter (TRUE) or not (FALSE). |
377
|
|
|
""" |
378
|
|
|
self.gated = gated |
379
|
|
|
self.change_sweep_mode(gated) |
380
|
|
|
return self.gated |
381
|
|
|
|
382
|
|
|
def get_data_trace(self): |
383
|
|
|
""" |
384
|
|
|
Polls the current timetrace data from the fast counter and returns it as a numpy array (dtype = int64). |
385
|
|
|
The binning specified by calling configure() must be taken care of in this hardware class. |
386
|
|
|
A possible overflow of the histogram bins must be caught here and taken care of. |
387
|
|
|
If the counter is UNgated it will return a 1D-numpy-array with returnarray[timebin_index] |
388
|
|
|
If the counter is gated it will return a 2D-numpy-array with returnarray[gate_index, timebin_index] |
389
|
|
|
|
390
|
|
|
@return arrray: Time trace. |
391
|
|
|
""" |
392
|
|
|
setting = AcqSettings() |
393
|
|
|
self.dll.GetSettingData(ctypes.byref(setting), 0) |
394
|
|
|
N = setting.range |
395
|
|
|
|
396
|
|
|
if self.gated: |
397
|
|
|
bsetting=BOARDSETTING() |
398
|
|
|
self.dll.GetMCSSetting(ctypes.byref(bsetting), 0) |
399
|
|
|
H = bsetting.cycles |
400
|
|
|
data = np.empty((H, int(N / H)), dtype=np.uint32) |
401
|
|
|
|
402
|
|
|
else: |
403
|
|
|
data = np.empty((N,), dtype=np.uint32) |
404
|
|
|
|
405
|
|
|
p_type_ulong = ctypes.POINTER(ctypes.c_uint32) |
406
|
|
|
ptr = data.ctypes.data_as(p_type_ulong) |
407
|
|
|
self.dll.LVGetDat(ptr, 0) |
408
|
|
|
time_trace = np.int64(data) |
409
|
|
|
|
410
|
|
|
if self.gated and self.timetrace_tmp != []: |
411
|
|
|
time_trace = time_trace + self.timetrace_tmp |
412
|
|
|
|
413
|
|
|
return time_trace |
414
|
|
|
|
415
|
|
|
|
416
|
|
|
|
417
|
|
|
# ========================================================================= |
418
|
|
|
# Non Interface methods |
419
|
|
|
# ========================================================================= |
420
|
|
|
|
421
|
|
|
def get_data_testfile(self): |
422
|
|
|
''' Load data test file ''' |
423
|
|
|
data = np.loadtxt(os.path.join(get_main_dir(), 'tools', 'FastComTec_demo_timetrace.asc')) |
424
|
|
|
time.sleep(0.5) |
425
|
|
|
return data |
426
|
|
|
|
427
|
|
|
def get_bitshift(self): |
428
|
|
|
"""Get bitshift from Fastcomtec. |
429
|
|
|
|
430
|
|
|
@return int settings.bitshift: the red out bitshift |
431
|
|
|
""" |
432
|
|
|
settings = AcqSettings() |
433
|
|
|
self.dll.GetSettingData(ctypes.byref(settings), 0) |
434
|
|
|
return int(settings.bitshift) |
435
|
|
|
|
436
|
|
|
def set_bitshift(self, bitshift): |
437
|
|
|
""" Sets the bitshift properly for this card. |
438
|
|
|
|
439
|
|
|
@param int bitshift: |
440
|
|
|
|
441
|
|
|
@return int: asks the actual bitshift and returns the red out value |
442
|
|
|
""" |
443
|
|
|
cmd = 'BITSHIFT={0}'.format(bitshift) |
444
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
445
|
|
|
return self.get_bitshift() |
446
|
|
|
|
447
|
|
|
def set_binwidth(self, binwidth): |
448
|
|
|
""" Set defined binwidth in Card. |
449
|
|
|
|
450
|
|
|
@param float binwidth: the current binwidth in seconds |
451
|
|
|
|
452
|
|
|
@return float: Red out bitshift converted to binwidth |
453
|
|
|
|
454
|
|
|
The binwidth is converted into to an appropiate bitshift defined as |
455
|
|
|
2**bitshift*minimal_binwidth. |
456
|
|
|
""" |
457
|
|
|
bitshift = int(np.log2(binwidth/self.minimal_binwidth)) |
458
|
|
|
new_bitshift=self.set_bitshift(bitshift) |
459
|
|
|
|
460
|
|
|
return self.minimal_binwidth*(2**new_bitshift) |
461
|
|
|
|
462
|
|
|
#TODO: Check such that only possible lengths are set. |
463
|
|
|
def set_length(self, length_bins, preset=None, cycles=None): |
464
|
|
|
""" Sets the length of the length of the actual measurement. |
465
|
|
|
|
466
|
|
|
@param int length_bins: Length of the measurement in bins |
467
|
|
|
|
468
|
|
|
@return float: Red out length of measurement |
469
|
|
|
""" |
470
|
|
|
constraints = self.get_constraints() |
471
|
|
|
if length_bins * self.get_binwidth() < constraints['max_sweep_len']: |
472
|
|
|
cmd = 'RANGE={0}'.format(int(length_bins)) |
473
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
474
|
|
|
cmd = 'roimax={0}'.format(int(length_bins)) |
475
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
476
|
|
|
if preset != None: |
477
|
|
|
cmd = 'swpreset={0}'.format(preset) |
478
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
479
|
|
|
if cycles != None and cycles != 0: |
480
|
|
|
cmd = 'cycles={0}'.format(cycles) |
481
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
482
|
|
|
return self.get_length() |
483
|
|
|
else: |
484
|
|
|
self.log.error( |
485
|
|
|
'Length of sequence is too high: %s' % (str(length_bins * self.get_binwidth()))) |
486
|
|
|
return -1 |
487
|
|
|
|
488
|
|
|
def get_length(self): |
489
|
|
|
""" Get the length of the current measurement. |
490
|
|
|
|
491
|
|
|
@return int: length of the current measurement in bins |
492
|
|
|
""" |
493
|
|
|
setting = AcqSettings() |
494
|
|
|
self.dll.GetSettingData(ctypes.byref(setting), 0) |
495
|
|
|
return int(setting.range) |
496
|
|
|
|
497
|
|
|
def set_preset(self, preset): |
498
|
|
|
""" Sets the preset/ |
499
|
|
|
|
500
|
|
|
@param int preset: Preset in sweeps of starts |
501
|
|
|
|
502
|
|
|
@return int mode: specified save mode |
503
|
|
|
""" |
504
|
|
|
cmd = 'swpreset={0}'.format(preset) |
505
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
506
|
|
|
return preset |
507
|
|
|
|
508
|
|
|
def get_preset(self): |
509
|
|
|
""" Gets the preset |
510
|
|
|
@return int mode: current preset |
511
|
|
|
""" |
512
|
|
|
bsetting = BOARDSETTING() |
513
|
|
|
self.dll.GetMCSSetting(ctypes.byref(bsetting), 0) |
514
|
|
View Code Duplication |
preset = bsetting.swpreset |
|
|
|
|
515
|
|
|
return int(preset) |
516
|
|
|
|
517
|
|
|
def set_cycles(self, cycles): |
518
|
|
|
""" Sets the cycles |
519
|
|
|
|
520
|
|
|
@param int cycles: Total amount of cycles |
521
|
|
|
|
522
|
|
|
@return int mode: current cycles |
523
|
|
|
""" |
524
|
|
|
cmd = 'cycles={0}'.format(cycles) |
525
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
526
|
|
|
return cycles |
527
|
|
|
|
528
|
|
|
def get_cycles(self): |
529
|
|
|
""" Gets the cycles |
530
|
|
|
@return int mode: current cycles |
531
|
|
|
""" |
532
|
|
|
bsetting = BOARDSETTING() |
533
|
|
|
self.dll.GetMCSSetting(ctypes.byref(bsetting), 0) |
534
|
|
|
cycles = bsetting.cycles |
535
|
|
|
return cycles |
536
|
|
|
|
537
|
|
|
def _change_filename(self,name): |
538
|
|
|
""" Changed the name in FCT""" |
539
|
|
|
cmd = 'mpaname=%s'%name |
540
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
541
|
|
|
return name |
542
|
|
|
|
543
|
|
|
def change_sweep_mode(self, gated): |
544
|
|
|
if gated: |
545
|
|
|
cmd = 'sweepmode={0}'.format(hex(1978500)) |
546
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
547
|
|
|
cmd = 'prena={0}'.format(hex(16)) #To select starts preset |
548
|
|
|
# cmd = 'prena={0}'.format(hex(4)) #To select sweeps preset |
549
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
550
|
|
|
self.gated = True |
551
|
|
|
else: |
552
|
|
|
# fastcomtch standard settings for ungated acquisition (check manual) |
553
|
|
|
cmd = 'sweepmode={0}'.format(hex(1978496)) |
554
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
555
|
|
|
cmd = 'prena={0}'.format(hex(0)) |
556
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
557
|
|
|
self.gated = False |
558
|
|
|
return gated |
559
|
|
|
|
560
|
|
|
def change_save_mode(self, mode): |
561
|
|
|
""" Changes the save mode of Mcs6 |
562
|
|
|
|
563
|
|
|
@param int mode: Specifies the save mode (0: No Save at Halt, 1: Save at Halt, |
564
|
|
|
2: Write list file, No Save at Halt, 3: Write list file, Save at Halt |
565
|
|
|
|
566
|
|
|
@return int mode: specified save mode |
567
|
|
|
""" |
568
|
|
|
cmd = 'savedata={0}'.format(mode) |
569
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
570
|
|
|
return mode |
571
|
|
|
|
572
|
|
|
def set_delay_start(self, delay_s): |
573
|
|
|
""" Sets the record delay length |
574
|
|
|
|
575
|
|
|
@param int delay_s: Record delay after receiving a start trigger |
576
|
|
|
|
577
|
|
|
@return int mode: specified save mode |
578
|
|
|
""" |
579
|
|
|
|
580
|
|
|
# A delay can only be adjusted in steps of 6.4ns |
581
|
|
|
delay_bins = np.rint(delay_s / 6.4e-9) |
582
|
|
|
cmd = 'fstchan={0}'.format(int(delay_bins)) |
583
|
|
|
self.dll.RunCmd(0, bytes(cmd, 'ascii')) |
584
|
|
|
return delay_bins |
585
|
|
|
|
586
|
|
|
def get_delay_start(self): |
587
|
|
|
""" Returns the current record delay length |
588
|
|
|
|
589
|
|
|
@return float delay_s: current record delay length in seconds |
590
|
|
|
""" |
591
|
|
|
bsetting = BOARDSETTING() |
592
|
|
|
self.dll.GetMCSSetting(ctypes.byref(bsetting), 0) |
593
|
|
|
delay_s = bsetting.fstchan * 6.4e-9 |
594
|
|
|
return delay_s |
595
|
|
|
|
596
|
|
|
# ========================================================================= |
597
|
|
|
# The following methods have to be carefully reviewed and integrated as |
598
|
|
|
# internal methods/function, because they might be important one day. |
599
|
|
|
# ========================================================================= |
600
|
|
|
|
601
|
|
|
|
602
|
|
|
|
603
|
|
|
def SetLevel(self, start, stop): |
604
|
|
|
setting = AcqSettings() |
605
|
|
|
self.dll.GetSettingData(ctypes.byref(setting), 0) |
606
|
|
|
def FloatToWord(r): |
607
|
|
|
return int((r+2.048)/4.096*int('ffff',16)) |
608
|
|
|
setting.dac0 = ( setting.dac0 & int('ffff0000',16) ) | FloatToWord(start) |
609
|
|
|
setting.dac1 = ( setting.dac1 & int('ffff0000',16) ) | FloatToWord(stop) |
610
|
|
|
self.dll.StoreSettingData(ctypes.byref(setting), 0) |
611
|
|
|
self.dll.NewSetting(0) |
612
|
|
|
return self.GetLevel() |
613
|
|
|
|
614
|
|
|
def GetLevel(self): |
615
|
|
|
setting = AcqSettings() |
616
|
|
|
self.dll.GetSettingData(ctypes.byref(setting), 0) |
617
|
|
|
def WordToFloat(word): |
618
|
|
|
return (word & int('ffff',16)) * 4.096 / int('ffff',16) - 2.048 |
619
|
|
|
return WordToFloat(setting.dac0), WordToFloat(setting.dac1) |
620
|
|
|
|
621
|
|
|
|
622
|
|
|
|
623
|
|
|
|
624
|
|
|
|
625
|
|
|
|
626
|
|
|
|
627
|
|
|
|
628
|
|
|
|
629
|
|
|
|
630
|
|
|
|