source: fact/tools/PyDimCtrl/ScriptsForPyDimCtrl.py@ 16946

Last change on this file since 16946 was 14659, checked in by neise, 12 years ago
long time since last checkin
File size: 59.5 KB
Line 
1#!/usr/bin/python -tti
2
3import time
4from factdimserver import *
5import numpy as np
6import types
7import sys
8import threading
9import Queue
10
11import logging
12# create logger with 'spam_application'
13logger = logging.getLogger('PyDimCtrl')
14logger.setLevel(logging.DEBUG)
15# create file handler which logs even debug messages
16fh = logging.FileHandler('PyDimCtrl.log')
17fh.setLevel(logging.DEBUG)
18# create console handler with a higher log level
19ch = logging.StreamHandler()
20ch.setLevel(logging.WARNING)
21# create formatter and add it to the handlers
22formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
23fh.setFormatter(formatter)
24ch.setFormatter(formatter)
25# add the handlers to the logger
26logger.addHandler(fh)
27logger.addHandler(ch)
28
29last_drive_kwargs = {}
30last_drive_method = None
31
32bias_calibration = {}
33
34bias_current = {}
35
36report_length = 0
37
38source_list = [
39 ['Crab', 0.6, 50, -130],
40 ["1ES 2344+51.4", 0.6, 90, -90 ],
41 ["Mrk 501", 0.6, -22, -22+180 ],
42 ["Mrk 421", 0.6, 90, -90 ],
43 ["1ES 1218+304", 0.6, -5, -5+180 ],
44 ["1ES 1959+650", 0.6, 155, 155-180 ],
45 ["Dark Patch 2", 0.6, 90, -90 ],
46 ["Dark Patch 3", 0.6, 90, -90 ],
47 ["H 1426+428", 0.6, 90, -90 ],
48 ["IC 310", 0.6, -18, -18+180 ],
49 ["PKS 2155-304", 0.6, 90, -90 ] ]
50
51crazyPatches = [66,191,193]
52
53sourcedict = {}
54def make_sourcedict():
55 for s in source_list:
56 sourcedict[s[0]] = {}
57 sourcedict[s[0]]['wobble_offset'] = s[1]
58 sourcedict[s[0]]['wobble_angle1'] = s[2]
59 sourcedict[s[0]]['wobble_angle2'] = s[3]
60
61
62
63
64
65def wait_nice(self, state_num, timeout=None):
66 global report_length
67 if not hasattr(self, 'stn'):
68 raise TypeError(self.name+' has no CMD called STATE')
69 if timeout == None:
70 timeout = float('inf')
71 else:
72 timeout = float(timeout)
73 start = time.time()
74 intermed = time.time()-1.
75 while not self.stn == state_num:
76 time.sleep(0.1)
77 if time.time() - intermed >= 1.:
78 report = str(fad_control.events()[0]) + ' events @ ' + str( ftm_control.trigger_rates()[3]) + ' Hz'
79
80 sys.stdout.write('\r'+' '*report_length)
81 sys.stdout.flush()
82 sys.stdout.write('\r'+report)
83 sys.stdout.flush()
84 report_length = len(report)
85
86 intermed = time.time()
87
88 if time.time() >= start+timeout:
89 report_length=0
90 print
91 return False
92 report_length=0
93 print
94 return True
95
96fad_control.wait_nice = types.MethodType( wait_nice, fad_control)
97
98
99def FadConnectCrate( crate ):
100 cratenum = None
101
102 if crate == 'all':
103 print "connecting to all crates"
104 for i in range( 40 ):
105 time.sleep(3.8)
106 fad_control.connect(i)
107 print "... done"
108 else:
109 try:
110 cratenum = int(crate)
111 except ValueError as e:
112 print "cannot convert crate parameter to integer. crate=", crate
113 print e
114 raise
115
116 if cratenum != None:
117 print "connecting to crate", cratenum
118 for i in range(cratenum*10, (cratenum+1)*10 ):
119 time.sleep(3.8)
120 fad_control.connect(i)
121 print "... done"
122
123
124def FadDisconnectCrate( crate ):
125 cratenum = None
126
127 if crate == 'all':
128 print "connecting to all crates"
129 for i in range( 40 ):
130 fad_control.disconnect(i)
131 print "... done"
132 else:
133 try:
134 cratenum = int(crate)
135 except ValueError as e:
136 print "cannot convert crate parameter to integer. crate=", crate
137 print e
138 raise
139
140 if cratenum != None:
141 print "connecting to crate", cratenum
142 for i in range(cratenum*10, (cratenum+1)*10 ):
143 print 'disconnecting from ', i
144 fad_control.disconnect(i)
145 print "... done"
146
147
148
149def IsReadyForDataTaking( verbose=False ):
150 """ Checking the system statuses if they are ready for data taking
151 """
152 if verbose:
153 print "--------------------------------------"
154 print "Checking the system statuses of:"
155 print "FEEDBACK, BIAS, FAD and DRIVE_CONTROL"
156 print "--------------------------------------"
157
158 print "...waiting for FEEDBACK"
159 print " to be in state 12: CurrentControl"
160 feedback.wait(12)
161
162 if verbose:
163 print "...waiting for BIAS_CONTROL"
164 print " to be in state 9: VoltageOn"
165 bias_control.wait(9)
166
167 if verbose:
168 print "...waiting for FAD_CONTROL"
169 print " to be in state 4: Connected"
170 fad_control.wait(4)
171
172 if verbose:
173 print "...waiting for drive_CONTROL"
174 print " to be in state 8: Tracking"
175 drive_control.wait(8)
176
177 if verbose:
178 print "...system statuses OK"
179 print "--------------------------------------"
180
181def NotReadyForDataTaking( servers_n_targets = [ (feedback, 12),
182 (bias_control, 9),
183 (fad_control, 4) ] ):
184 """ Checking the system statuses if they are ready for data taking
185 return list of servers, which are NOT ready for Data Taking
186 so one can use this function like this
187 if not NotReadyForDataTaking():
188 # freak out
189 else:
190 # start data taking
191 """
192 not_ready = []
193
194 print "--------------------------------------"
195 print "Checking the system statuses of:"
196 for server,target in servers_n_targets:
197 print server.__name__ , ','
198 print
199 print "--------------------------------------"
200
201 for n, server, target in enumerate(servers_n_targets):
202 if server.stn != target:
203 print server.__name__, "NOT in state ", target
204 not_ready.apppend((server,target))
205
206 return not_ready
207
208
209
210
211def PrepareBiasForDataTaking():
212 """ should have the original behaviour, no new fancy features
213 check feedback state before switching BIAS ON and ramping up to nominal Voltage
214 """
215
216 start = time.time()
217 while (feedback.stn != 12):
218 time.sleep(0.1)
219 if time.time() > start + 10.:
220 print "==================================================="
221 print " feedback is not in state 'CurrentControl' "
222 print " OPERATOR: "
223 print " goto feedback console and check the state of "
224 print " feedback by typing [st] to find out what the"
225 print " current state means and maybe needs to be done"
226 print " this script will wait for state 'CurrentControl'"
227 print "==================================================="
228 feedback.wait(12)
229
230 bias_control.set_global_dac(1)
231
232 start = time.time()
233 while (bias_control.stn != 9):
234 time.sleep(0.1)
235 if time.time() > start + 10.:
236 print '==================================================='
237 print ' switching on bias not successfull'
238 print ' biasctrl is not in state "VoltageOn"'
239 print ''
240 print ' OPERATOR:'
241 print ' goto biasctrl console and check the state of'
242 print ' biasctrl by typing [st] to find out what the'
243 print ' current state means and maybe needs to be done'
244 print ''
245 print ' this script will wait for state "VoltageOn"'
246 print '==================================================='
247 bias_control.wait(9)
248
249 bias_control.wait(5)
250 bias_control.wait(9)
251
252 print "bias is on, and feedback-program is working, but we wait 45sec for the current readings..."
253 time.sleep(45)
254 print "...done"
255
256
257def StopTracking():
258 """ should have the original behaviour, no new fancy features
259 stop drivectrl tracking the current source
260 """
261 drive_control.stop()
262 drive_control.wait(6) #Armed
263
264 print "Drive Armed"
265 print "Tracking Stopped"
266
267
268def SwitchOnBias():
269 """ should have the original behaviour, no new fancy features
270 bring Feedback to state CurrentControIdle and switch on Bias
271 """
272 print ' switching on current controll feedback'
273 feedback.stop()
274 print ' ... starting current control feedback '
275 feedback.start_current_control(0.)
276 feedback.enable_output(1) # 1 means True here ... this needs improvement.
277
278 print ' ...waiting for FEEDBACK to be in state 9: CurrentCtrlIdle'
279 feedback.wait(9)
280 print '... feedback is running.'
281
282 print ' switching bias on by, setting DAC to 1 globally'
283 bias_control.set_global_dac(1)
284
285 print ' ...waiting for BIAS to be in state 9: VoltageOn'
286 bias_control.wait(9)
287 print ' ...1 DAC globally set'
288
289
290 print ' ...waiting for BIAS to be in state 5: Ramping'
291 bias_control.wait(5)
292 print ' ...ramping to nominal voltage'
293
294 print ' ...waiting for BIAS to be in state 9: VoltageOn'
295 bias_control.wait(9)
296 print ' ...bias on'
297
298 print ' waiting 45sec for the current control to stabilize...'
299 time.sleep(45.)
300 print ' ... done, bias on'
301
302
303 # the feedback should be in state 'CurrentCtrlIdle'(9) now since 30.05.12
304 # if feedback.stn != 9:
305 # print "feedback is in state:", feedback.sts , "(", feedback.stn, ")"
306 # print "but is should be in state CurrentCtrlIdle (9)"
307 # print "aborting"
308 # return
309
310
311
312def WaitForTracking( verbose = False):
313 """ Wait for drivectrl to reply that its tracking the given source
314 """
315 if verbose:
316 print "...waiting for DRIVE_CONTROL"
317 print " to be in state 7: Moving"
318 drive_control.wait(7)
319 if verbose:
320 print "...moving"
321
322 if verbose:
323 print "...waiting for DRIVE_CONTROL"
324 print " to be in state 8: Tracking"
325 drive_control.wait(8)
326 if verbose:
327 print "...tracking requested wobble position"
328
329 if verbose:
330 print "waiting 10 sec for drive to calm down"
331 print "and tracking beeing stable"
332 time.sleep(10)
333
334
335
336
337def Take( time, num_events, runtype, verbose=False):
338 """ more general version of e.g. TakePedestalOnRun
339 Note: One has to check, if Ready for *Take* by oneself
340 """
341 runtype += '\0'
342
343 if verbose:
344 print ' taking', runtype,'. ', num_events, 'events in', time, 'seconds'
345 mcp.start(time, num_events, runtype)
346
347 if verbose:
348 print '...waiting for FAD to be in state 8: Writing Data'
349 fad_control.wait(8) # Writing Data
350 if verbose:
351 print '...waiting for FAD to be in state 4: Connected'
352 fad_control.wait_nice(4) # Connected
353 if verbose:
354 print '... done'
355
356def TakeBetter( time, num_events, runtype,
357 Bias = None,
358 Drive = None,
359
360 verbose=False):
361 """
362 """
363 if Bias not in [None, 'On', 'Off']:
364 raise ValueError('Bias needs to be one of [None, "On", "Off"]')
365 return False
366
367 # Sanity check
368 # Drive can be:
369 # Drive = 'sourcename'
370 # Drive = ('sourcename', wobble_pos = 1 || 2)
371 # Drive = None
372 if type(Drive) not in [type(''), type((0,0)), type(None) ]:
373 raise ValueError('Bias needs to be one of [None, "On", "Off"]')
374 return False
375
376
377 runtype += '\0'
378
379 # FAD:
380 #
381 # It makes no sense to try to take data, when the FADs are not well connected.
382 # Also I think it makes no sense to start datataking, when FAD is in WritingData
383 # and when MCP is not in an Idle state...
384 #
385 # we will check if FAD is in Connected(4), if in Writing_Data(8), we will send: close_all_open_files()
386 # if in one of the configuring states(5,6,7) we will send reset_configure
387 # if in Connecting(3), we will try to find which board is making problems...
388 # and disconnect and connect it --> THREE TIMES
389 # if it doesn't help.
390 # we abort.
391 #
392 #
393
394
395 # FTM:
396 # the ftm is not so critcal, since it makes no problems normally...
397 # It can be in triggerON(4) or Idle(3)
398 # Connected(2) is not good here we need a power cycle
399 # Any of the Configured States (5,6,7) should be treated with reset_configure()
400 #
401 # we will anyway check if in Connected(2) before starting.
402
403 # DRIVE_CONTROL:
404 # in case *Drive* is a valid sourcename from sourcedict,
405 # we will give the command to point to that source in ON mode
406 # in case *Drive* is a tuple of ('sourcename', 1 || 2)
407 # We will point to that soource in wobble mode.
408 #
409 # If Drive is 'Stop. The Drive will be stopped
410 #
411 # In anycase The Drive will be checked for not beeing in the state ERROR
412 # in that case we will send DRIVE_CONTROL/STOP and the last tracking
413 # command or nothing in case Drive = 'Stop'
414 #
415 # In case Drive is None no commands will be send to DRIVE_CONTROL at allow
416
417 # Drive can be:
418 # Drive = 'sourcename'
419 # Drive = ('sourcename', wobble_pos = 1 || 2)
420 # Drive = None
421
422 # RATE_CTRL
423 #
424 # Rate_control should be in Connected(4) and not lower
425 # 5,6,7 should not be the case ... STOP will help, I hope
426 #
427 # we will try to get it into Connected, by sending STOP once
428 # if not successful we abort
429
430 start_time = time.time()
431 duration = 10.
432 while fad_control.stn != 4:
433 if fad_control.stn in [5,6,7]: # Configure State --> Reset_Configure
434 fad_control.reset_configure()
435 elif fad_control.stn == 8: #WritingData --> Close_all_open_files()
436 fad_control.close_open_files()
437 elif fad_control.stn == 3: #Connecting --> try to find 'bad' board and reconnect
438 duration = 60.
439 print 'fad_control in state Connecting ... trying to find "bad" board'
440 print 'timeout increased to 60.sec'
441 conn = GetFadConnections()
442 bad = np.where( conn != 0x42 )[0]
443 print 'possible bad boards', bad
444 print 'disconnecting'
445 for b in bad:
446 fad_control.disconnect(b)
447 time.sleep(3.)
448 for b in bad:
449 fad_control.connect(b)
450 else: # really bad .. abort
451 print 'ERROR: FAD_CTRL in state', fad_control.stn, fad_control.sts
452 print 'I do not know how to treat that ... aborting'
453 return False
454
455 time.sleep(1.)
456 if time.time() - start_time > duration:
457 print 'Timeout during try to get FAD into Connected'
458 return False
459
460 # BIAS
461 #
462 # As well it makes no sense to try to take data, when the Bias control is in an
463 # undefined state.
464 # When *Bias* is 'On' we will take care that the Bias voltage is on, and stays on
465 # When *Bias* is 'Off' we will shut bias down and do nothing more
466 # When *Bias* is None -default- then no commands will be send to BiasCtrl
467
468 start_time = time.time()
469 duration = 20.
470 if Bias == 'On':
471 if ( (bias_control.voltage()[0:320].mean() > 60) and
472 ( (bias_control.stn == 5) or
473 (bias_control.stn == 9) ) ):
474 pass
475
476 elif Bias == 'Off':
477 pass
478
479 if verbose:
480 print ' taking', runtype,'. ', num_events, 'events in', time, 'seconds'
481 mcp.start(time, num_events, runtype)
482
483 if verbose:
484 print '...waiting for FAD to be in state 8: Writing Data'
485 fad_control.wait(8) # Writing Data
486 if verbose:
487 print '...waiting for FAD to be in state 4: Connected'
488 fad_control.wait_nice(4) # Connected
489 if verbose:
490 print '... done'
491
492
493
494def TakeData():
495 """ taking a Data Set (1x Pedestal On, 1x LPext, 4x5min DataRun)
496 """
497 # take a Pedestal run
498 IsReadyForDataTaking()
499 print 'taking pedestal run with 1000 events'
500 Take(-1, 1000, 'pedestal')
501
502 # take a ExtLP run
503 IsReadyForDataTaking()
504 print 'taking External Light Pulser with BIAS on 1000 ...'
505 Take(-1, 1000, 'light-pulser-ext')
506
507 #Data Taking with Full Trigger Area (4x5min)
508 for run in range(4):
509 print 'taking data run', run+1, 'out of 4'
510 IsReadyForDataTaking()
511 Take( 300, -1, 'data')
512
513def TakeDrsCalibration():
514 """ script for DRS-Calibration before Data taking
515 """
516 print 'script for DRS-Calibration before Data taking'
517 print 'starting up...'
518
519 feedback.enable_output(1)
520 # Making sure bias is off, before the DRS calibration starts
521 bias_control.set_zero_voltage()
522 print '...ramping Voltage down'
523 print ' ...waiting for BIAS to be in state 7: Voltage Off'
524 bias_control.wait(7) #VoltageOff
525 print '...BIAS voltage is switched off'
526
527 # starting the DRS calibration
528 fad_control.start_drs_calibration()
529
530 # taking first DRS:Pedestal with 1000 Events and ROI 1024
531 print 'taking DRS:Pedestal 1000 ...'
532 fad_control.wait(4) #Connected
533 Take(-1, 1000, 'drs-pedestal')
534
535 # taking DRS:Gain with 1000 Events and ROI 1024
536 print ' taking DRS:Gain 1000 ...'
537 fad_control.wait(4) #Connected
538 Take(-1, 1000, 'drs-gain')
539
540 # taking DRS:Pedestal 1000 Events and ROI 1024
541 print 'taking DRS:Pedestal 1000 ...'
542 fad_control.wait(4) #Connected
543 Take(-1, 1000, 'drs-pedestal')
544
545 print ' ... done'
546
547 # taking again a DRS:Pedestal with 1000 Events and ROI 1024 for a crosscheck of calculated calibrations constants
548 print ' taking crosscheck DRS:Pedestal 1000 ...'
549 fad_control.set_file_format(2)
550 fad_control.wait(4) #Connected
551 Take(-1, 1000, 'drs-pedestal')
552
553
554 # taking DRS:Time with 1000 Events and ROI 1024
555 print ' taking DRS:Time 1000 ...'
556 fad_control.wait(4) #Connected
557 Take(-1, 1000, 'drs-time')
558
559
560 # taking DRS:Time upshifted 1000 Events and ROI 1024
561 print 'taking DRS:Time upshifted 1000 ...'
562 fad_control.wait(4) #Connected
563 Take(-1, 1000, 'drs-time-upshifted')
564
565 # taking a Pedestal with 1000 Events and ROI 300 for secondary baseline...
566 print 'taking Pedestal 1000 for secondary baseline... with ROI=300'
567 fad_control.reset_secondary_drs_baseline()
568 fad_control.wait(4) #Connected
569 Take(-1, 1000, 'pedestal')
570
571 # taking crosscheck Pedestal 1000 Events and ROI 300
572 print ' taking crosscheck Pedestal 1000 ...with ROI=300'
573 fad_control.set_file_format(2)
574 fad_control.wait(4) #Connected
575 Take(-1, 1000, 'pedestal')
576
577 print '----------------------------------------------------'
578 print 'This is the end of the'
579 print 'DRS-Calibration before Data taking'
580 print '----------------------------------------------------'
581
582
583def FirstDrsCalib( SkipCurrentCalib=False ):
584 logger = logging.getLogger('PyDimCtrl.FDC')
585 """ performs the everything, which is done in the FirstDrsCalib Script as well .
586 """
587 # As a First step we want to calibrate the current, which are read from the bias crate,
588 # and not take a DRS calibration, as it is mentioned in the data taking page...
589 # so for this we should get the feedback and biasctrl programs into known states
590 # I think it is good to try a RECONNECT to the bias, and make sure the voltage is off
591 # Since we do not know, what the feedback program is doing at the moment, we should as well,
592 # tell it to keep its mouth shut ... just to be sure, we know whats going on
593 logger.debug("stopping feedback")
594 feedback.stop()
595
596 time.sleep(2)
597 # stopping should always be possible, and end in state 'Connected'(6)
598
599 logger.debug(" ...waiting for FEEDBACK to be in state 6: Connected")
600 print
601 feedback.wait(6)
602 print "..done"
603
604 #BIAS_CONTROL/RECONNECT
605 # If we were disconnected, and this was the first try of the night, the bias_ctrl should
606 # be in state 'VoltageOff'(7) more or less immediately
607 #.s BIAS_CONTROL 3
608 #.s BIAS_CONTROL 7 5000
609 # if these assumptions are all wrong, then we might have been properly connected anyway,
610 # and just have to ramp down... lets do it, but wait forever, in case it does not work
611 print " switching off bias"
612 bias_control.set_zero_voltage()
613 time.sleep(2)
614 print " ...waiting for BIAS to be in state 7: VoltageOff"
615 bias_control.wait(7)
616 print " ...done"
617
618 if not SkipCurrentCalib:
619 # in case we reach this line, the voltages are all off, and the feedback does not do anything
620 # So lets do the current calibration, therefor we tell the bias crate to ramp up just 1 single DAC count(~22mV)
621 # the result of this action is, to get bias_ctrl into the state 'VoltageOn'(9), but since we only go one DAC count it shouldn't take long
622 print " setting bias globally to 1 DAC"
623 bias_control.set_global_dac(1)
624
625 time.sleep(2)
626 print " ...waiting for BIAS to be in state 9: VoltageOn"
627 bias_control.wait(9)
628 print " ...done"
629
630 # now we may tell the feedback program to calibrate the currents ...
631 # I do not understand, if I have to explicitely allow the feedback program to generate output,
632 # or if it just produces output...
633 # As far as I understand, the feedback output enable status is the same,
634 # as it was before I send the STOP command... so it is unknown at this point.
635 # and in addition enabling or disabling the output, when STOPed is not possible as far as I know...
636 # I try to enable it anyway.
637 print " enabling output for feedback"
638 feedback.enable_output(1)
639 time.sleep(2)
640 print " ...done"
641
642 print " calibrating bias crate current readings..."
643 feedback.calibrate_currents()
644 time.sleep(5)
645 # in order to find out when the calibration ends, we have to wait for the transistion from state
646 # 'Calibrating'(13) back to 'Connected'(6)
647 print " ...waiting for FEEDBACK to be in state 13: Calibrating"
648 feedback.wait(13)
649 print " ...waiting for FEEDBACK to be in state 6: Connected"
650 feedback.wait(6)
651
652 # Thomas Bretz told me, that the feedback, after this is step has disabled its output
653 # and is in the mode, we might call 'temperature control' even there is no temerature beeing controlled.
654 # I don't know where the voltage is ... in order to perform the calibration, the feedback had to
655 # ramp up to 2V below the operational voltage, i.e. about 1V below the breakdown voltage
656
657 # We want to take a DRS amplitude calibration so we have to ramp down the bias voltage.
658 # this 10sec wait is needed in order for the bias not to disconect all the time...
659 print " ... current calibration done"
660 #time.sleep(10)
661
662 print " switching off bias"
663 bias_control.set_zero_voltage()
664 #time.sleep(5)
665 print " ...waiting for BIAS to be in state 7: VoltageOff"
666 bias_control.wait(7)
667 print " ...done"
668
669 # So now we can take the 3 runs, which are called DRS amplitude calibration:
670 # A pedestal run with ROI=1024
671 # A gain calibration run with ROI=1024
672 # and a second pedestal run, with the same ROI as our next data will be, i.e. ROI=300 in this case
673 print "taking DRS:Pedestal 1000 ..."
674 #print "==================================================="
675 #print "OPERATOR: "
676 #print "observe Events tab and make sure there are no patches "
677 #print "with strange behaviour, which can be caused "
678 #print "by DRS-CHIP Problems"
679 #print "==================================================="
680
681 fad_control.start_drs_calibration()
682 #time.sleep(0.5)
683 Take( -1, 1000, 'drs-pedestal')
684
685 print "taking DRS:Gain 1000 ..."
686 Take( -1, 1000, 'drs-gain')
687
688 time.sleep(2)
689 if GetDrsCalibGainRms():
690 print
691 print 'First DRS Calib Script will be aborted'
692 print 'operator, please power cycle FACT'
693 return False
694
695 print "taking Pedestal 1000 ..."
696 Take( -1, 1000, 'pedestal')
697
698 # okay this is the DRS calibration for the next few runs.
699 # we are now asked to take again a pedestal run, which can be used, to
700 # calculate the electronics noise for instance ... since the shutter is closed and the
701 # voltage is off .. there should not be alot of signal in it :-)
702 print "taking crosscheck Pedestal 1000 ..."
703 fad_control.set_file_format(2)
704 Take(-1, 1000, 'pedestal')
705
706 # now we want to take a run, with dark counts events
707 # so we need to ramp up the voltage
708 # we want to use the 'current control' more so we give the commands for this...
709 print "switching on current controll feedback ..."
710 feedback.stop()
711 feedback.start_current_control(0.0)
712 feedback.enable_output(1)
713 # the feedback should be in state 'CurrentControl'(12) now
714 # the feedback should be in state 'CurrentCtrlIdle'(9) now since 30.05.12
715 print "...waiting for FEEDBACK to be in state 12: CurrentControl"
716 feedback.wait(12)
717 print "... done"
718 print "switching on bias"
719 # now we give the feedback a hint, that it may ramp ...
720 bias_control.set_global_dac(1)
721 # after this command the bias_ctrl should be in state 'VoltageOn'(9) after a second or so
722 print "...waiting for BIAS to be in state 9: VoltageOn"
723 bias_control.wait(9)
724 print "...1 DAC globally set"
725 # then usually it takes some time until the feedback has enough information to really start controlling the voltage
726 # when the feedback actually kicks in, the bias is first in state 'Ramping'(5) for some seconds and finally in 'VoltageOn'(9)
727 # again
728 print "...waiting for BIAS to be in state 5: Ramping"
729 bias_control.wait(5)
730 print "...ramping to nominal voltage"
731 print "...waiting for BIAS to be in state 9: VoltageOn"
732 bias_control.wait(9)
733 print "...bias on"
734 # here we should wait 45 sec in order for the current control to get enough current readings and temp readings to stabilize..
735 print "waiting 45sec for the current control to stabilize..."
736 time.sleep(45)
737 print "... done"
738
739 # so now we can take the dark count run ...
740 # this might be changed in the future ... either the number of events or the the ROI might be changed
741 # then the DRS calibration above, and the pedestal run in between have to be changed as well.
742 print "taking Pedestal with BIAS on 3000 ..."
743 Take(-1, 3000, 'pedestal')
744
745 # at the end the bias voltage should be ramped down, since in a few seconds a shifter wit ha flashlight
746 # will come out to open the shutter...
747 print "switching OFF bias ..."
748 bias_control.set_zero_voltage()
749 print "...waiting for BIAS to be in state 7: VoltageOff"
750 bias_control.wait(7)
751 print "...done"
752 print "This is the end of First DRS Calibration"
753 print "----------------------------------------------------"
754 print ">"
755
756def Ratescan( ra=None, dec=None, sourcename=None):
757 """
758# call it by: .x ScriptsForDimCtrl/Ratescan.dim mode=<trackmode> ra=<Right ascension> dec=<Declination> source=<source_name>
759# mode=0: Manual tracking Mode: set tracking in drivectrl manually
760# mode=1: Coordinate Mode: scripts sends tracking command to drivectrl with the given RaDec coordinates
761# mode=2: source Mode: scripts sends tracking command to drivectrl with the given source_name
762
763 """
764 print '======================================'
765 print 'RATESCAN'
766 print '======================================'
767 print 'Preparing Drive'
768
769
770 if None == ra and None == dec and None == sourcename:
771 print 'Manual tracking Mode'
772 print '---------------------'
773 print 'OPERATOR'
774 print 'change tracking in drivectrl manually'
775 print 'script will wait for drive'
776 print 'to be in state tracking'
777 elif None != ra or None != dec:
778 try:
779 ra = float(ra)
780 dec = float(dec)
781 except TypeError:
782 raise
783
784 print '...stop tracking'
785 StopTracking()
786 print '...change tracking of telescope to:'
787 print '...Ra = ', ra
788 print '...Dec = ', dec
789 drive_control.track( ra, dec)
790 elif None != sourcename:
791 print '...stop tracking'
792 StopTracking()
793 print '...change tracking of telescope to:', sourcename
794 sourcename += '\0'
795 drive_control.track_source( 0, 0, sourcename)
796 else:
797 print 'type(ra)', type(ra), '\tra', ra
798 print 'type(dec)', type(dec), '\tdec', dec
799 print 'type(sourcename)', type(sourcename), '\tsourcename', sourcename
800 raise ValueError('RateScan does not know what to do with its parameters. Bug!')
801 return False
802
803 IsReadyForDataTaking()
804
805 print 'Starting Ratescan'
806 print '...waiting for Ratescan'
807 print ' to be in state 4: Connected'
808
809
810 if not rate_scan.wait(4, timeout=5.): #Connected
811 # we went into timeout!
812 print 'Rate_Scan not in correct state'
813 print 'OPERATOR:'
814 print '+ check connection to ftm control'
815 print 'we went into to 5sec. timeout while waiting for RATE_SCAN to be in state Connected'
816 print 'aborting'
817 return False
818
819 rate_scan.start_threshold_scan( 50, 1000, -10)
820 if not rate_scan.wait( 6, timeout=10.): # Statename???
821 # we went into timeout
822 print 'ratescan not started'
823 print 'we went into 10sec. timeout while waiting for RATE_SCAN to start the Scan'
824 print 'aborting'
825 return False
826
827 print '...processing ratescan'
828 if not rate_scan.wait( 4, timeout=2700.): # Connected
829 # we went into timeout
830 print 'we went into 2700sec. timeout while waiting for RATE_SCAN to finish'
831 print 'aborting'
832 return False
833
834 print 'Ratescan finished successfully'
835 return True
836
837
838def ResetCrate( crate_num ):
839 """ Reset Crate
840 crate_num = 0,1,2 or 3 the number of the crate to reset.
841 crate_num = 'all' is NOT YET SUPPORTED
842 """
843 c = int(crate_num)
844
845 print '======================================'
846 print 'Crate-Reset for crate ', c
847 print '======================================'
848
849 print '...resetting MCP'
850 mcp.reset()
851 time.sleep(5.)
852 print '...diconnecting FAD boards of crate ', c
853 FadDisconnectCrate( c )
854 time.sleep(2.)
855
856 print '...disconnecting All FTUs'
857 ftm_control.enable_ftu( -1, 0) # -1 for all, and 0 for False
858 time.sleep(2.)
859
860 print '...checking state of FTM_Control'
861 print '...waiting for state 3: Idle'
862 if not ftm_control.wait(3, 2.): # Idle
863 print '...stopping trigger'
864 ftm_control.stop_trigger()
865 ftm_control.wait(3) # wait for Idle endlessly
866
867 print '...resetting crate'
868 ftm_control.reset_crate( c )
869 time.sleep(2.)
870
871 print '...connecting All FTUs'
872 ftm_control.enable_ftu( -1, 1) # -1 for all, and 1 for yes, or True
873 time.sleep(4.)
874
875 print '...pinging FTUs'
876 ftm_control.ping()
877
878 print '...connecting FAD boards of crate', c
879 FadConnectCrate(c)
880 print '======================================'
881 print 'Crate-Reset for crate', c, 'finished'
882 print '======================================'
883
884def GetDrsCalibGainRms():
885#drs_calibration(self) method of factdimserver.FAD_CONTROL instance
886#DESC in SERVICE_DESC is empty ?!
887#I:1;I:3;F:1474560;F:1474560;F:1474560;F:1474560;F:1474560;F:1474560;F:163840;F:163840
888 data = fad_control.drs_calibration()
889 N1 = data[0]
890 N3 = data[1:4]
891 OffsetMean = np.array(data[4:4+1024*1440]).reshape(1440,1024)
892 OffsetRms = np.array(data[4+1024*1440:4+1024*1440*2]).reshape(1440,1024)
893 GainMean = np.array(data[4+1024*1440*2:4+1024*1440*3]).reshape(1440,1024)
894 GainRms = np.array(data[4+1024*1440*3:4+1024*1440*4]).reshape(1440,1024)
895
896 gr = GainRms.mean(axis=1)
897 lala = np.zeros(len(gr)/9)
898 for i,v in enumerate(lala):
899 lala[i] = gr[i*9:(i+1)*9].mean()
900
901 # outliers
902 mean = lala.mean()
903 std = lala.std()
904
905 print 'Mean DRS GainRms value:', mean
906 print 'std:', std
907 outs = np.where( lala > mean+7*std)[0]
908 if len(outs) > 0:
909 print 'WARNING possible DRS underflow detected!!!'
910 for out in outs:
911 out = int(out)
912 crate= out/40
913 board = (out-40*crate)/4
914 chip = out-40*crate-4*board
915 print 'possible DRS underflow in DRS:', crate, board, chip, '--> Mean-GainRms:', lala[out]
916 return outs
917 else:
918 return False
919
920def GetBiasCalibration():
921 cali = feedback.calibration()
922 bias_calibration['Time'] = time.time()
923 bias_calibration['Calibration'] = cali
924
925def _GetBiasCurrent_Raw(verbose = False):
926 """ return median, std, max and min current
927 """
928 if 'Time' in bias_calibration:
929 cali = bias_calibration['Calibration']
930 else:
931 GetBiasCalibration()
932 cali = bias_calibration['Calibration']
933
934 r = np.array(cali[2*416:2*416+320])
935
936 bias = bias_control
937
938 I = np.array(bias.current()[0:320], dtype=float)
939 II = I/4096. * 5000
940 V = np.array(bias.voltage()[0:320])
941 if len(sys.argv) > 1:
942 i = int(sys.argv[1])
943 else: i=0
944# print 'I:', I[i], 'dac\t', II[i], 'uA'
945# print 'V:', V[i]
946# print ''
947# print 'GUI offset:', V[i]/r[i]*1e6
948# print 'GUI feedback:', II[0] - V[0]/r[0]*1e6
949
950 # GUII means current(I) as it is written in the GUI :-)
951 # read: GUI-I :-)
952 GUII = II-V/r*1e6
953 if verbose:
954 print 'median', np.median(GUII)
955 print 'mean', GUII.mean()
956 # print 'rms', ((GUII- GUII.mean())**2).sum()
957 print 'std', GUII.std()
958 print 'max', GUII.max()
959 print 'min', GUII.min()
960
961 bias_current['Time'] = time.time()
962 bias_current['raw_patch_current'] = GUII
963 return GUII
964
965def GetPatchCurrents(crazyPatches=crazyPatches ,verbose = False, max_age_sec=1. ):
966
967 if 'Time' in bias_current:
968 if time.time() - bias_current['Time'] > max_age_sec:
969 raw_cur = _GetBiasCurrent_Raw()
970 else:
971 raw_cur = bias_current['raw_patch_current']
972 else:
973 raw_cur = _GetBiasCurrent_Raw()
974
975 if crazyPatches is None:
976 return raw_cur
977 else:
978 try:
979 crazyPatches = list(crazyPatches)
980 except:
981 raise
982 goodPatches = [x for x in range(320) if x not in crazyPatches]
983 return raw_cur[goodPatches]
984
985def GetPixelCurrents(crazyPatches=crazyPatches ,verbose = False, max_age_sec=1. ):
986
987 if 'Time' in bias_current:
988 if time.time() - bias_current['Time'] > max_age_sec:
989 raw_cur = _GetBiasCurrent_Raw()
990 else:
991 raw_cur = bias_current['raw_patch_current']
992 else:
993 raw_cur = _GetBiasCurrent_Raw()
994
995 pixel_cur = np.zeros(len(raw_cur))
996 for i in range(len(raw_cur)):
997 if i/2:
998 pixel_cur[i] = raw_cur[i]/5.
999 else:
1000 pixel_cur[i] = raw_cur[i]/4.
1001
1002 if crazyPatches is None:
1003 return pixel_cur
1004 else:
1005 try:
1006 crazyPatches = list(crazyPatches)
1007 except:
1008 raise
1009 goodPatches = [x for x in range(320) if x not in crazyPatches]
1010 return pixel_cur[goodPatches]
1011
1012def PrintPixelCurrents( delay = 4.0):
1013 while True:
1014 time.sleep( delay )
1015 current = GetPixelCurrents()
1016 interesting = current.min(), np.median(current), current.mean(), current.max()
1017 print time.strftime('%d %b %Y %H:%M:%S UTC', time.gmtime()), interesting
1018
1019
1020def TrackSourceWobbleX( sourcename, wobble_pos ):
1021 """ general Tracking function
1022 """
1023 wp = int(wobble_pos)
1024 if wp != 1 and wp != 2:
1025 raise ValueError('wobble_pos *must* be 1 or 2')
1026
1027 if sourcename not in sourcedict:
1028 print sourcedict.keys()
1029 raise ValueError('sourcename: '+ sourcename +' must be in sourcedict.')
1030
1031 logger.debug('TrackSourceWobbleX: sending drive_control.stop()')
1032 drive_control.stop()
1033 logger.debug('TrackSourceWobbleX: waiting for DRIVE_CONTROL to be "Armed"')
1034 drive_control.wait(6) #Armed
1035
1036 logger.info('moving telescope to wobble position %s of %s' % str(wp), sourcename)
1037
1038
1039 wobble_offset = sourcedict[sourcename]['wobble_offset']
1040 wobble_angle = sourcedict[sourcename]['wobble_angle'+str(wp)]
1041 sourcename += '\0'
1042
1043 # this is just book keeping. I store the method, which is used
1044 # in this case drive_control.track_source()
1045 # and the arguments, in some global vars .. in order to be able to
1046 # resend the command if necessary.
1047 last_drive_method = drive_control.track_source
1048 last_drive_kwargs = { 'wobble_offset' : wobble_offset,
1049 'wobble_angle' : wobble_angle,
1050 'source_name' : sourcename }
1051 kwa = last_drive_kwargs
1052 # Here I really send the command
1053 last_drive_method(kwa['wobble_offset'], kwa['wobble_angle'], kwa['source_name'])
1054
1055 logger.debug('TrackSourceWobbleX: waiting for DRIVE_CONTROL to be "Tracking"')
1056 drive_control.wait(8) #Tracking
1057
1058 return True
1059
1060def TakeSource( name ):
1061 if name not in sourcedict:
1062 print name, 'not in dict of sources, possible sources are:'
1063 print sorted(sourcedict.keys())
1064 raise ValueError('wrong source name')
1065
1066 TrackSourceWobbleX( name, 1) # Track Wobble pos 1 of source
1067 WaitForTracking()
1068 # Take a DRS-Calibration before beginning to take physics Data
1069 TakeDrsCalibration()
1070 # check feedback state before switching BIAS ON and ramping up to nominal Voltage
1071 PrepareBiasForDataTaking()
1072 # taking a Data Set (1x Pedestal 1000 Bias On, 1x LPext 1000, 4x5min DataRun)
1073 TakeData()
1074 StopTracking()
1075
1076 TrackSourceWobbleX( name, 2) # Track Wobble pos 2 of source
1077 WaitForTracking()
1078 # taking a Data Set (1x Pedestal 1000 Bias On, 1x LPext 1000, 4x5min DataRun)
1079 TakeData()
1080
1081 StopTracking()
1082
1083def set_file_format_to_FITS():
1084 fad_control.set_file_format(2)
1085
1086# (Time , Drive, Bias, DAQ, call-before-run)
1087class RunType(object):
1088 drs_pedestal = (-1, 1000, 'drs-pedestal')
1089 drs_gain = (-1, 1000, 'drs-gain')
1090 drs_time = (-1, 1000, 'drs-time')
1091 drs_time_upshifted = (-1, 1000, 'drs-gain-upshifted')
1092 pedestal = (-1, 1000, 'pedestal')
1093 lightpulser = (-1, 1000, 'light-pulser-ext')
1094 data = (300, -1, 'data')
1095
1096class Schedule(object):
1097 drs_calib_crab = [
1098 ( None , ('Crab',1) , 'Off', RunType.drs_pedestal , fad_control.start_drs_calibration ),
1099 ( None , ('Crab',1) , 'Off', RunType.drs_gain , None ),
1100 ( None , ('Crab',1) , 'Off', RunType.drs_pedestal , None ),
1101 ( None , ('Crab',1) , 'Off', RunType.drs_pedestal , set_file_format_to_FITS ),
1102 ( None , ('Crab',1) , 'Off', RunType.drs_time , None ),
1103 ( None , ('Crab',1) , 'Off', RunType.drs_time_upshifted , None ),
1104 ( None , ('Crab',1) , 'Off', RunType.pedestal , fad_control.reset_secondary_drs_baseline ),
1105 ( None , ('Crab',1) , 'Off', RunType.pedestal , None )
1106 ]
1107
1108 drs_calib_not_moving = [
1109 ( None , None , 'Off', RunType.drs_pedestal , fad_control.start_drs_calibration ),
1110 ( None , None , 'Off', RunType.drs_gain , None ),
1111 ( None , None , 'Off', RunType.drs_pedestal , None ),
1112 ( None , None , 'Off', RunType.drs_pedestal , set_file_format_to_FITS ),
1113 ( None , None , 'Off', RunType.drs_time , None ),
1114 ( None , None , 'Off', RunType.drs_time_upshifted , None ),
1115 ( None , None , 'Off', RunType.pedestal , fad_control.reset_secondary_drs_baseline ),
1116 ( None , None , 'Off', RunType.pedestal , None )
1117 ]
1118
1119 data_crab_Wobble_1 = [
1120 ( None , ('Crab',1) , 'On', RunType.pedestal , None ),
1121 ( None , ('Crab',1) , 'On', RunType.lightpulser , None ),
1122 ( None , ('Crab',1) , 'On', RunType.data , None ),
1123 ( None , ('Crab',1) , 'On', RunType.data , None ),
1124 ( None , ('Crab',1) , 'On', RunType.data , None ),
1125 ( None , ('Crab',1) , 'On', RunType.data , None ),
1126 ]
1127 data_crab_Wobble_2 = [
1128 ( None , ('Crab',2) , 'On', RunType.pedestal , None ),
1129 ( None , ('Crab',2) , 'On', RunType.lightpulser , None ),
1130 ( None , ('Crab',2) , 'On', RunType.data , None ),
1131 ( None , ('Crab',2) , 'On', RunType.data , None ),
1132 ( None , ('Crab',2) , 'On', RunType.data , None ),
1133 ( None , ('Crab',2) , 'On', RunType.data , None ),
1134 ]
1135
1136
1137
1138class ScheduledDataTakingThread( threading.Thread ):
1139 """
1140
1141 """
1142 def __init__( self , delay = 5):
1143 threading.Thread.__init__(self)
1144 self.stoprequest = threading.Event()
1145 self.warning_state = 'Unknown'
1146 self.state_change = time.time()
1147 self.logger = logging.getLogger('PyDimCtrl.ScheduledDataTakingThread')
1148
1149 self.delay = delay
1150 self.queue = Queue.Queue()
1151
1152 def run(self):
1153 while not self.stoprequest.isSet():
1154
1155 task = self.queue.get()
1156
1157 start_time = task[0]
1158 drive_task = task[1]
1159 bias_task = task[2]
1160 daq_task = task[3]
1161 pre_action = task[4]
1162
1163 if drive_task is not None:
1164 TrackSourceWobbleX( *drive_task )
1165
1166 # if start_time is None or start_time > time.gmtime():
1167 # # do it
1168 # if drive_task is not None:
1169 # TrackSourceWobbleX( *drive_task ) # this blocks until 'Tracking'
1170 # # TODO:
1171 # # spawn a new DriveMonitorThread here and start it.
1172
1173 if bias_task is not None:
1174 if bias_task == 'On':
1175 Make_Bias_On()
1176 else:
1177 Make_Bias_On()
1178 # TODO:
1179 # spawn a new BiasMonitorThread here and start it.
1180
1181 if daq_task is not None:
1182 if pre_action is not None:
1183 pre_action()
1184 MakeReadyForDataTaking()
1185 Take( *daq_task )
1186 # TODO:
1187 # spawn a new DaqMonitorThread here and start it.
1188
1189
1190 self.queue.task_done()
1191 time.sleep( self.delay )
1192
1193 def join( self, timeout=None):
1194 self.stoprequest.set()
1195 self.logger.info('was requested to die with timeout=%s' % str(timeout) )
1196 #super(CheckBiasThread, self).join()
1197 threading.Thread.join(self)
1198
1199
1200
1201
1202def MakeReadyForDataTaking( delay=1 ):
1203 while fad_control.stn != 4 or ftm_control.stn != 3: # Connected & Idle
1204 logger.info('MakeReadyForDataTaking FTM trigger is still on')
1205 if ftm_control.stn == 4: # Trigger is on
1206 ftm_control.stop_trigger()
1207
1208 logger.warning('MakeReadyForDataTaking FAD: still in WritingData')
1209 if fad_control.stn == 8: # Writing Data
1210 fad_control.close_all_open_files()
1211
1212 logger.warning('MakeReadyForDataTaking FAD: still in one of the Configure(ing) states')
1213 if fad_control.stn in [5,6,7]: # one of the Configure(ing) states
1214 fad_control.reset_configure()
1215
1216 logger.warning('MakeReadyForDataTaking FTM: still in one of the Configure(ing) states')
1217 if ftm_control.stn in [5,6,7]: # one of the Configure(ing) states
1218 ftm_control.reset_configure()
1219
1220 time.sleep(delay)
1221
1222 return True
1223
1224def PrintCurrents( x = 1.0):
1225 while True:
1226 time.sleep( x )
1227 GUII = GetBiasCurrent()
1228 interesting = GUII.mean(), GUII.std(), GUII.max(), GUII.min()
1229 print time.strftime('%d %b %Y %H:%M:%S UTC', time.gmtime()), interesting
1230
1231
1232def GetFadConnections( verbose = False ):
1233 """ return np.array(40) with bitmaps, showing the FADs connection status:
1234 apperently this is the meaning:
1235 0x43 -- well connected and well configured -- green with white tick mark
1236 0x42 -- well connected -- green
1237 0x09 -- something is wrong with the connection -- orange or red?
1238 0x00 -- not connected, and not attempting to connect -- grey
1239 """
1240
1241 conn = np.array(map( ord, fad_control.connections()[0] ))
1242 if verbose:
1243 for crate in range(4):
1244 print map( hex, conn[crate*10: (crate+1) *10 ] )
1245 return conn
1246
1247def GetFadBadConnections( good = 0x42 ):
1248 """ returns list of bad FAD IDs
1249 """
1250 conn = GetFadConnections()
1251 bads = np.where( conn != good) [0]
1252 return bads
1253
1254
1255def StartUp():
1256 fad_control.start()
1257 bias_control.reconnect()
1258 bias_control.set_zero_voltage()
1259 while bias_control.stn == 6 : # OverCurrent
1260 bias_control.set_zero_voltage()
1261 bias_control.reset_over_current_status()
1262
1263 ftm_control.reconnect()
1264
1265 number_of_loops = 3
1266 while True:
1267 bad = GetFadBadConnections()
1268 if len(bad) == 0:
1269 break
1270
1271 for b in set( bad/10 ): # set(b/10) contains the crate ids, which have bad FADs
1272 ResetCrate( b )
1273
1274 number_of_loops -= 1
1275 if not number_of_loops:
1276 print 'StartUp aborted while trying to get the FADs into Connected state ... '
1277 return False
1278
1279
1280 if not MakeDriveCtrlReady():
1281 return False
1282
1283 return True
1284
1285def Shutdown():
1286 fad_control.stop()
1287 ftm_control.disconnect()
1288 feedback.stop()
1289 bias_control.set_zero_voltage()
1290
1291
1292
1293def MakeDriveCtrlReady():
1294 """ Tries to get Drive ctrl from
1295 Disconnected, locked or Error to Armed
1296 after a few tries it gives up and returns False
1297 """
1298 outer_counter = 3
1299 while drive_control.stn != 6: #Armed
1300# print 'MakeDriveCtrlReady outer_counter', outer_counter
1301
1302 counter = 3
1303 while drive_control.stn == 1: #Disconnected
1304# print 'MakeDriveCtrlReady in while 1, counter:', counter
1305 drive_control.reconnect()
1306 time.sleep(0.5)
1307 counter -= 1
1308 if not counter:
1309 print 'count not connect drive control to cosy ... please check if cosy is running'
1310 return False
1311
1312 counter = 3
1313 while drive_control.stn == 3: # Locked
1314# print 'MakeDriveCtrlReady in while 2, counter:', counter
1315 drive_control.unlock()
1316 time.sleep(0.5)
1317 counter -= 1
1318 if not counter:
1319 print 'could not unlock drive control WTF?'
1320 return False
1321
1322 counter = 3
1323 while drive_control.stn == 256: # ERROR
1324# print 'MakeDriveCtrlReady in while 3, counter:', counter
1325 drive_control.stop()
1326 time.sleep(0.5)
1327 counter -= 1
1328 if not counter:
1329 print 'could not unlock drive control WTF?'
1330 return False
1331
1332 outer_counter -= 1
1333 if not outer_counter:
1334 print 'ERROR while trying to get Drive control ready'
1335 return False
1336
1337 return True
1338
1339feedback_calibration_done = None # Bool...
1340
1341def Make_Bias_Off():
1342
1343 bias_control.set_zero_voltage()
1344 bias_control.wait(7)
1345
1346
1347def Make_Bias_On():
1348 """ Tries to get the Bias, and Feedback into a defined safe Off state
1349 While beeing as ready as possible to go into On state
1350 """
1351 global feedback_calibration_done
1352 # Feedback states:
1353 #List of available states:
1354 #-[-1]: NotReady (State machine not ready, events are ignored.)
1355 #-[0]: Ready (State machine ready to receive events.)
1356 #-[1]: DimNetworkNotAvailable (The Dim DNS is not reachable.)
1357 #-[2]: Disconnected (The Dim DNS is reachable, but the required subsystems are not available.)
1358 #-[3]: Connecting (Only biasctrl is available and connected with its hardware.)
1359 #-[4]: ConnectedFSC (biasctrl and fscctrl are available and connected with their hardware.)
1360 #-[5]: ConnectedFAD (biasctrl and fadctrl are available and connected with their hardware.)
1361 #-[6]: Connected (biasctrl, fadctrl and fscctrl are available and connected with their hardware.)
1362 #-[7]: TempCtrlIdle (Temperature control activated, but voltage output disabled.)
1363 #-[8]: FeedbackIdle (Feedback control activated, but voltage output disabled.)
1364 #-[9]: CurrentCtrlIdle (Current control activated, but voltage output disabled.)
1365 #-[10]: TempControl (Temperature control activated and voltage output enabled.)
1366 #-[11]: FeedbackControl (Feedback control activated and voltage output enabled.)
1367 #-[12]: CurrentControl (Current/Temp control activated and voltage output enabled.)
1368 #-[13]: Calibrating (Calibrating current offsets.)
1369 #-[256]: ERROR (Common error state.)
1370 #-[65535]: FATAL (A fatal error occured, the eventloop is stopped.)
1371
1372
1373 while not ( (feedback.stn == 12) and
1374 (bias_control.stn == 9) and
1375 (np.array(bias_control.voltage()[0:320]).mean() > 65.) ):
1376
1377 # for security
1378 feedback.enable_output(0)
1379
1380 # try to get bias_control into state: VoltageOn
1381 while not bias_control.stn == 9:
1382
1383 if bias_control.stn == 1: #Disconnected
1384 bias_control.reconnect()
1385 if bias_control.stn == 2: #Connecting
1386 time.sleep(1)
1387 if bias_control.stn == 3: #Initializing
1388 time.sleep(1)
1389 if bias_control.stn == 4: #Connected
1390 # this seems never to happen ...
1391 time.sleep(1)
1392 #bias_control.set_global_dac(1)
1393 if bias_control.stn == 5: #Ramping
1394 time.sleep(1)
1395 if bias_control.stn == 6: #OverCurrent
1396 bias_control.set_zero_voltage()
1397 time.sleep(1)
1398 bias_control.reset_over_current_status()
1399 if bias_control.stn == 7: #VoltageOff
1400 bias_control.set_global_dac(1)
1401 if bias_control.stn == 8: #NotReferenced
1402 bias_control.set_zero_voltage()
1403 if bias_control.stn == 9: #VoltageOn
1404 pass
1405 if bias_control.stn > 9:
1406 print "BIAS control is in strange status... don't know what to do"
1407 time.sleep(1)
1408 time.sleep(1)
1409
1410
1411 # Try to get Feedback into CurrentControl
1412 while not (feedback.stn == 12):
1413
1414 if feedback.stn < 6: # not properly connected.
1415 # State 6 is 'Connected' but this normaly hardly shows up
1416 # Its either voltageOff or any other meaningful state...
1417 print "FEEDBACK not properly connected..."
1418 time.sleep(1)
1419
1420 if feedback.stn == 13: #Calibrating
1421 time.sleep(1)
1422 continue
1423
1424 if not feedback_calibration_done:
1425 if feedback.calibration() is None:
1426 print "FEEDBACK has not CURRENT CALIBRATION"
1427 print "TRYING TO CALIBRATE"
1428 feedback.calibrate_currents()
1429 time.sleep(0.5)
1430 continue
1431 else:
1432 feedback_calibration_done = True
1433
1434 if feedback.stn == 6: #Connected
1435 feedback.start_current_control(0.0)
1436
1437 if feedback.stn in [7,8]: #TempCtrlIdle , FeedbackIdle
1438 feedback.stop()
1439 time.sleep(0.5)
1440 feedback.start_current_control(0.0)
1441
1442 if feedback.stn == 9: #CurrentCtrlIdle
1443 feedback.enable_output(1)
1444
1445 if feedback.stn in [10,11]: #TempControl, FeedbackControl
1446 feedback.stop()
1447 time.sleep(0.5)
1448 feedback.start_current_control(0.0)
1449
1450 if feedback.stn == 12: # This is where we want ot be
1451 pass
1452
1453
1454 time.sleep(1)
1455 # Bias States
1456 #List of available states:
1457 #-[-1]: NotReady (State machine not ready, events are ignored.)
1458 #-[0]: Ready (State machine ready to receive events.)
1459 #-[1]: Disconnected (Bias-power supply not connected via USB.)
1460 #-[2]: Connecting (Trying to establish USB connection to bias-power supply.)
1461 #-[3]: Initializing (USB connection to bias-power supply established, synchronizing USB stream.)
1462 #-[4]: Connected (USB connection to bias-power supply established.)
1463 #-[5]: Ramping (Voltage ramping in progress.)
1464 #-[6]: OverCurrent (At least one channel is in over current state.)
1465 #-[7]: VoltageOff (All voltages are supposed to be switched off.)
1466 #-[8]: NotReferenced (Internal reference voltage does not match last sent voltage.)
1467 #-[9]: VoltageOn (At least one voltage is switched on and all are at reference.)
1468 #-[10]: ExpertMode (Special (risky!) mode to directly send command to the bias-power supply.)
1469 #-[256]: ERROR (Common error state.)
1470 #-[65535]: FATAL (A fatal error occured, the eventloop is stopped.)
1471
1472
1473class CheckBiasThread( threading.Thread ):
1474 """ Thread, which continously monitors the Bias_Control status every
1475 *delay* seconds.
1476 in case of too high currents it will ...
1477 .... do nothing :-) yet.
1478 So far it will just change its internal state from 'Normal'
1479 to 'PreWarning' or 'Serious'.
1480 If the currents remain "high" for more than
1481 *serious_action_after* seconds. some action would be taken.
1482 I our case, just a WARNING will be logged.
1483
1484 The caller thread should check the *warning_state* from outside this
1485 thread and take apropriate actions, when 'PreWarning' is reached...
1486
1487
1488 """
1489 def __init__( self , delay=5, serious_action_after = 60 ):
1490 #super(CheckBiasThread, self).__init__()
1491 threading.Thread.__init__(self)
1492 self.stoprequest = threading.Event()
1493 self.warning_state = 'Unknown'
1494 self.state_change = time.time()
1495 self.delay = delay
1496 self.serious_action_after = serious_action_after
1497 self.logger = logging.getLogger('PyDimCtrl.CheckBiasThread')
1498
1499 def run(self):
1500 while not self.stoprequest.isSet():
1501
1502 if (self.warning_state == 'Serious' and
1503 time.time()-self.state_change > self.serious_action_after):
1504 # Remergency Ramp Down
1505 self.logger.info('At this moment, I would ramp down the voltage')
1506 self.logger.warning('G-APD currents are too high, since %d seconds' % self.serious_action_after)
1507 self.logger.warning('Emergency voltage shutdown [not yet implemented]')
1508
1509 currents = GetPixelCurrents()
1510 if ( (np.median(currents) > 70) or (currents.max() > 90) ):
1511 if self.warning_state != 'Serious':
1512 self.logger.info('trasit into Serious Warning')
1513 self.warning_state = 'Serious'
1514 self.state_change = time.time()
1515
1516 elif ( (np.median(currents) > 60) or (currents.max() > 80) ):
1517 if self.warning_state != 'PreWarning':
1518 self.logger.info('transit into Pre Warning')
1519 self.warning_state = 'PreWarning'
1520 self.state_change = time.time()
1521
1522 elif ( (np.median(currents) < 60) or (currents.max() < 80) ):
1523 if self.warning_state != 'Normal':
1524 self.logger.info('transit into Normal Situation')
1525 self.warning_state = 'Normal'
1526 self.state_change = time.time()
1527
1528 if bias_control.stn == 6: #Overcurrent
1529 if self.warning_state != 'OverCurrent':
1530 self.logger.warning('trasit into Overcurrent State during data Taking')
1531 self.warning_state = 'OverCurrent'
1532 self.state_change = time.time()
1533
1534 if bias_control.stn == 1: #Disconnected
1535 if self.warning_state != 'Disconnected':
1536 self.logger.warning('trasit into Disconnected state during data Taking')
1537 self.warning_state = 'Disconnected'
1538 self.state_change = time.time()
1539
1540
1541
1542 time.sleep( self.delay )
1543
1544 def join( self, timeout=None):
1545 self.stoprequest.set()
1546
1547 self.logger.info('was requested to die with timeout=%s' % str(timeout) )
1548 #super(CheckBiasThread, self).join()
1549 threading.Thread.join(self)
1550
1551
1552class CheckDriveThread( threading.Thread ):
1553 """ Thread, which continously monitors the Drive_Control status every
1554 *delay* seconds.
1555 in case Drive_Control goes into Error State it will
1556 send:
1557 * STOP
1558 * and then resend the last tracking command
1559
1560 In case sending STOP is not bringing the Drive_Control back to
1561 state 'Armed' it will try again. Until the *try_counter* is zero.
1562 Then it will totally Freak out.
1563
1564 .... does nothing really! :-) yet.
1565
1566 """
1567 def __init__( self , try_counter = 5, timeout = 30, delay=5 ):
1568 threading.Thread.__init__(self)
1569 self.stoprequest = threading.Event()
1570
1571 self.error_counter = 0
1572 self.try_counter = try_counter
1573 self.timeout = timeout
1574 self.delay = delay
1575
1576 self.warning_state = 'Unknown'
1577 self.state_change = time.time()
1578
1579 self.logger = logging.getLogger('PyDimCtrl.CheckDriveThread')
1580
1581 def run(self):
1582 while not self.stoprequest.isSet():
1583
1584 if drive_control.stn == 256: #Error
1585 self.error_counter += 1
1586 self.state_change = time.time()
1587 self.warning_state = 'ErrorFound'
1588 self.logger.info('found Error State ... starting to react on it.')
1589 self.logger.warning(' Error State ')
1590
1591 start_of_Error_reaction = time.time()
1592 while not drive.stn == 8: #Tracking
1593 if drive_control.stn == 256: #Error
1594 if try_counter:
1595 self.logger.info('sending STOP')
1596 drive_control.stop()
1597 try_counter -= 1
1598 time.sleep(1)
1599
1600 elif drive_control.stn == 6: #Armed
1601 kwa = last_drive_kwargs
1602 self.logger.info('resending last tracking command')
1603 last_drive_method(kwa['wobble_offset'],
1604 kwa['wobble_angle'],
1605 kwa['source_name'])
1606 time.sleep(2)
1607 else:
1608 self.logger.error('found Error, but now neither Error state nor Armed state?!')
1609 self.logger.error('what should I do?')
1610 self.logger.error('thread aborting')
1611 self.warning_state = 'Critical'
1612 self.stoprequest.set()
1613 threading.Thread.join(self)
1614
1615 if time.time() - start_of_Error_reaction > self.timeout:
1616 self.logger.error('timed out while trying to react on Drive Control Error')
1617 self.logger.error('what should I do?')
1618 self.logger.error('thread aborting')
1619 self.warning_state = 'Critical'
1620 #self.stoprequest.set()
1621 #threading.Thread.join(self)
1622 self.join()
1623
1624 else:
1625 if self.warning_state != 'Normal':
1626 self.logger.info('transit into Normal Situation')
1627 self.warning_state = 'Normal'
1628 self.state_change = time.time()
1629
1630 time.sleep( self.delay )
1631
1632 def join( self, timeout=None):
1633 self.stoprequest.set()
1634 self.logger.info('was requested to die with timeout=%s' % str(timeout))
1635 threading.Thread.join(self)
1636
1637
1638class BiasThread(threading.Thread):
1639 """ A worker thread that takes directory names from a queue, finds all
1640 files in them recursively and reports the result.
1641
1642 Input is done by setting the *requested_state*:
1643 ['On', 'Off']
1644 Output is done by setting the *readyness*:
1645 ['Ready', 'NotYet', 'CantDoIt']
1646
1647 Ask the thread to stop by calling its join() method.
1648 """
1649 requests = ['On', 'Off']
1650 readynesses = ['Ready', 'NotYet', 'CantDoIt']
1651 requested_state = None
1652 readyness = 'NotYet'
1653
1654 def __init__(self, start_state = 'Off'):
1655 super(BiasThread, self).__init__()
1656 BiasThread.requested_state = start_state
1657 self.stoprequest = threading.Event()
1658
1659 def run(self):
1660 # As long as we weren't asked to stop, try to find out, if we are in
1661 # the requested state, if not, try to reach the state...
1662 while not self.stoprequest.isSet():
1663
1664 if not self.InRequestedState():
1665 print 'not in Requested State', BiasThread.requested_state
1666 BiasThread.readyness = 'NotYet'
1667
1668 try:
1669 dirname = self.dir_q.get(True, 0.05)
1670 filenames = list(self._files_in_dir(dirname))
1671 self.result_q.put((self.name, dirname, filenames))
1672 except Queue.Empty:
1673 continue
1674
1675 def join(self, timeout=None):
1676 self.stoprequest.set()
1677 super(BiasThread, self).join(timeout)
1678
1679 def InRequestedState():
1680 """
1681 """
1682 if BiasThread.requested_state == 'On':
1683 pass
1684 elif BiasThread.requested_state == 'Off':
1685 pass
1686 else: # Houston we have a problem!
1687 pass
1688
1689
1690
1691
1692class CheckDaqThread( threading.Thread ):
1693 """ Thread, which continously monitors the Rate
1694
1695 in case the rate is < 1Hz --> Bing bing
1696
1697 """
1698 def __init__( self , delay=5 ):
1699 threading.Thread.__init__(self)
1700 self.stoprequest = threading.Event()
1701
1702 self.delay = delay
1703
1704 self.warning_state = 'Unknown'
1705 self.state_change = time.time()
1706
1707 self.logger = logging.getLogger('PyDimCtrl.CheckDaqThread')
1708
1709 def run(self):
1710 while not self.stoprequest.isSet():
1711
1712 rate = ftm_control.trigger_rates()[3]
1713 if rate < 1:
1714 if self.warning_state != 'SmallRate':
1715 self.logger.warning('SmallRate detected!')
1716 self.warning_state = 'SmallRate'
1717 self.state_change = time.time()
1718 else:
1719 if self.warning_state != 'Normal':
1720 self.logger.info('transit to Normal')
1721 self.warning_state = 'Normal'
1722 self.state_change = time.time()
1723
1724 time.sleep( self.delay )
1725
1726 def join( self, timeout=None):
1727 self.stoprequest.set()
1728 self.logger.info('was requested to die with timeout=%s' % str(timeout))
1729 threading.Thread.join(self)
1730
1731
1732
1733def off():
1734 for m in monis:
1735 m.join()
1736
1737monis = []
1738if __name__ == '__main__':
1739 print 'Welcome to PyDimCtrl'
1740 make_sourcedict()
1741 print
1742 print 'possible sources:'
1743 print sorted( sourcedict.keys() )
1744
1745 print 'available Dim Servers'
1746 for dim in dims:
1747 print dim.name,
1748 print
1749
1750 #bm = CheckBiasThread()
1751 #dm = CheckDriveThread()
1752 #rm = CheckDaqThread()
1753 #monis = [bm, dm, rm]
1754# bm.start()
1755# dm.start()
1756# rm.start()
1757 #print
1758 #print 'monis created'
Note: See TracBrowser for help on using the repository browser.