21
21
22
22
from labscript_devices import BLACS_tab , runviewer_parser
23
23
24
+ from labscript_utils .setup_logging import setup_logging
25
+
24
26
# Define a RFBlasterPseudoclock that only accepts one child clockline
25
27
class RFBlasterPseudoclock (Pseudoclock ):
26
28
def add_device (self , device ):
@@ -261,7 +263,7 @@ def initialise_GUI(self):
261
263
self .address = "http://" + str (self .BLACS_connection ) + ":8080"
262
264
263
265
# Create and set the primary worker
264
- self .create_worker ("main_worker" ,RFBlasterWorker ,{'address' :self .address , 'num_DDS' :self .num_DDS })
266
+ self .create_worker ("main_worker" , RFBlasterWorker , {'address' : self .address , 'num_DDS' : self .num_DDS })
265
267
self .primary_worker = "main_worker"
266
268
267
269
# Set the capabilities of this device
@@ -369,13 +371,39 @@ class RFBlasterWorker(Worker):
369
371
def init (self ):
370
372
exec ('from numpy import *' , globals ())
371
373
global h5py ; import labscript_utils .h5_lock , h5py
372
- self .timeout = 30 #How long do we wait until we assume that the RFBlaster is dead? (in seconds)
374
+ global re ; import re
375
+ self .timeout = 10 # How long do we wait until we assume that the RFBlaster is dead? (in seconds)
376
+ self .retries = 3 # Retry attempts before (a) giving up, or (b) attempting to restart kloned (uniform timeout)
377
+ p = re .compile ('http://([0-9.]+):[0-9]+' )
378
+ m = p .match (self .address )
379
+ self .ip = m .group (1 )
380
+ # self.ip = self.BLACS_connection
381
+ self .netlogger = setup_logging ('rfBlaster_%s' % self .ip )
382
+ self .netlogger .info ('init: Started logging' )
373
383
374
384
# See if the RFBlaster answers
375
385
self .http_request ()
376
386
377
387
self ._last_program_manual_values = {}
378
-
388
+
389
+ def restart_kloned (self , respawn_netcat = True ):
390
+ import socket , time
391
+ s = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
392
+ s .settimeout (self .timeout )
393
+ self .netlogger .info ('restart_kloned: Connecting to %s...' % self .ip )
394
+ s .connect ((self .ip , 8009 ))
395
+ self .netlogger .info ('restart_kloned: Connected!' )
396
+ if respawn_netcat :
397
+ self .netlogger .info ('restart_kloned: Respawning netcat...' )
398
+ s .sendall (b'nohup nc -l -p 8009 -e /bin/sh &' )
399
+ time .sleep (0.5 )
400
+ self .netlogger .info ('restart_kloned: Trying to start/restart kloned...' )
401
+ s .sendall (b'./startup/klone_start.sh' )
402
+ time .sleep (0.5 )
403
+ s .shutdown (socket .SHUT_WR )
404
+ self .netlogger .info ('restart_kloned: Finished. Closing socket.' )
405
+ s .close ()
406
+
379
407
def program_manual (self ,values ):
380
408
self ._last_program_manual_values = values
381
409
@@ -395,7 +423,7 @@ def program_manual(self,values):
395
423
def transition_to_buffered (self ,device_name ,h5file ,initial_values ,fresh ):
396
424
with h5py .File (h5file ,'r' ) as hdf5_file :
397
425
group = hdf5_file ['devices' ][device_name ]
398
- #Strip out the binary files and submit to the webserver
426
+ # Strip out the binary files and submit to the webserver
399
427
form = MultiPartForm ()
400
428
self .final_values = {}
401
429
finalfreq = zeros (self .num_DDS )
@@ -410,9 +438,9 @@ def transition_to_buffered(self,device_name,h5file,initial_values,fresh):
410
438
'gate' :True
411
439
}
412
440
data = group ['BINARY_CODE/DDS%d' % i ].value
413
- form .add_file_content ("pulse_ch%d" % i ,"output_ch%d.bin" % i ,data )
441
+ form .add_file_content ("pulse_ch%d" % i , "output_ch%d.bin" % i , data )
414
442
415
- form .add_field ("upload_and_run" ,"Upload and start" )
443
+ form .add_field ("upload_and_run" , "Upload and start" )
416
444
self .http_request (form )
417
445
return self .final_values
418
446
@@ -426,8 +454,8 @@ def abort_transition_to_buffered(self):
426
454
427
455
def abort_buffered (self ):
428
456
form = MultiPartForm ()
429
- #tell the rfblaster to stop
430
- form .add_field ("halt" ,"Halt execution" )
457
+ # Tell the rfblaster to stop
458
+ form .add_field ("halt" , "Halt execution" )
431
459
self .http_request (form )
432
460
return True
433
461
@@ -438,9 +466,11 @@ def transition_to_manual(self):
438
466
def http_request (self , form = None ):
439
467
"""Make a HTTP request to the RFBlaster, optionally submitting a form"""
440
468
if PY2 :
441
- from urllib2 import urlopen , Request
469
+ from urllib2 import urlopen , Request , URLError , httplib
470
+ HTTPError = httplib .HTTPException
442
471
else :
443
472
from urllib .request import urlopen , Request
473
+ from urllib .error import URLError , HTTPError
444
474
445
475
req = Request (self .address )
446
476
if form is not None :
@@ -449,17 +479,38 @@ def http_request(self, form=None):
449
479
req .add_header (b'Content-length' , len (body ))
450
480
req .data = body
451
481
452
- page = b'' .join (urlopen (req , timeout = self .timeout ).readlines ())
453
- return page
482
+ self ._connection_attempt = 1
483
+ self ._kloned_attempted = False
484
+ response = None
485
+ while not response :
486
+ try :
487
+ self .netlogger .info ('Connection attempt %i.' % self ._connection_attempt )
488
+ response = b'' .join (urlopen (req , timeout = self .timeout ).readlines ())
489
+ self .netlogger .info ('Connected!' )
490
+ break
491
+ except (URLError , HTTPError ) as e :
492
+ self .netlogger .warning (str (e ))
493
+ if self ._connection_attempt < self .retries :
494
+ self .netlogger .info ('Connection failed. Trying again (%i more attempts remain).' % (self .retries - self ._connection_attempt ))
495
+ self ._connection_attempt += 1
496
+ elif not self ._kloned_attempted :
497
+ self ._kloned_attempted = True
498
+ self .restart_kloned ()
499
+ self ._connection_attempt = 1
500
+ else :
501
+ self .netlogger .error (str (e ))
502
+ raise e
503
+
504
+ return response
454
505
455
506
def get_web_values (self , page ):
456
507
page = page .decode ('utf8' )
457
508
import re
458
- #prepare regular expressions for finding the values:
509
+ # Prepare regular expressions for finding the values:
459
510
search = re .compile (r'name="([fap])_ch(\d+?)_in"\s*?value="([0-9.]+?)"' )
460
- webvalues = re .findall (search ,page )
511
+ webvalues = re .findall (search , page )
461
512
462
- register_name_map = {'f' :'freq' ,'a' :'amp' ,'p' :'phase' }
513
+ register_name_map = {'f' : 'freq' , 'a' : 'amp' , 'p' : 'phase' }
463
514
newvals = {}
464
515
for i in range (self .num_DDS ):
465
516
newvals ['dds %d' % i ] = {}
@@ -480,7 +531,7 @@ def get_web_values(self, page):
480
531
return newvals
481
532
482
533
def check_remote_values (self ):
483
- #read the webserver page to see what values it puts in the form
534
+ # Read the webserver page to see what values it puts in the form
484
535
return self .get_web_values (self .http_request ())
485
536
486
537
def shutdown (self ):
0 commit comments