def parse_header(): tcu_params = TCUParams(HEADER_FILE) logger.debug('Extracted parameters from header:\n' + str(tcu_params)) global num_pulses global num_repeats global x_amp_delay global l_amp_delay global rex_delay global pri_pulse_width global pulses global status global instruction global pre_pulse hex_params = tcu_params.get_hex_params() num_pulses = hex_params['num_pulses'] num_repeats = hex_params['num_repeats'] # ensuring num_repeats is 32bit hex number if len(num_repeats) == 8: # NOTE: change this depending on how num_repeats is stored in HDL # num_repeats = '\\x00\\x00' + num_repeats num_repeats = num_repeats + '\\x00\\x00' x_amp_delay = hex_params['x_amp_delay'] l_amp_delay = hex_params['l_amp_delay'] rex_delay = hex_params['rex_delay'] pri_pulse_width = hex_params['pri_pulse_width'] # ensuring pri_pulse_width is 32bit hex number if len(pri_pulse_width) == 8: # NOTE: change this depending on how pri_pulse_width is stored in HDL # pri_pulse_width = '\\x00\\x00' + pri_pulse_width pri_pulse_width = pri_pulse_width + '\\x00\\x00' pulses = hex_params['pulses'] pre_pulse = hex_params['pre_pulse'] for index, pulse in enumerate(pulses): # ensuring PRI is 32bit hex number if len(pulse['pri']) == 8: # NOTE: change this depending on how PRI is stored in HDL # pulse['pri'] = '\\x00\\x00' + pulse['pri'] pulse['pri'] = pulse['pri'] + '\\x00\\x00' logging.info('header parsing complete')
# PARSE COMMAND LINE ARGUMENTS # ------------------------------------------------------------------------- clargparser = argparse.ArgumentParser( usage='creator.py [-f FILE]', description='Experiment creator for the ' 'NeXtRAD Timing Control Unit') clargparser.add_argument('-f', '--file', help='header file default [./NeXtRAD.ini]', default='./NeXtRAD.ini') clargparser.add_argument( '-o', '--outputfile', help='output file for exported params [./PulseParameters.ini]', default='./PulseParameters.ini') args = clargparser.parse_args() HEADER_FILE = args.file OUTPUT_FILE = args.outputfile tcu_params = TCUParams(HEADER_FILE, OUTPUT_FILE) app = QtWidgets.QApplication(sys.argv) window = QtWidgets.QMainWindow() program = Creator(tcu_params, window) window.show() sys.exit(app.exec_())
class TCUController(harpoon.Project): """ Class that controls NeXtRAD's Timing Control unit Making use of the Harpoon Framework """ def __init__(self, fpga_con, name='tcu_controller', description='project to communicate with the RHINO-TCU', cores=list(), address=None, headerfile=None, verify=False, bof_exe=None, debug=False, log_dir=str(), auto_update=False, auto_arm=False, voice=False ): """creates a new instance of TCUController :param harpoon.FPGAConnection: Class to facilitate the low level communication between PC and TCU :param str name: name of the project :param str description: description of the project :param list cores: harpoon.cores associated to this project :param str address: IP address of TCU :param str headerfile: name and path of the headerfile containing TCU parameters :param str bof_exe: name of the .bof executable residing in the TCU :param bool debug: display debug output to console :param str log_dir: path to store log file :param bool auto_update: automatically update registers when header file has changed :param bool auto_arm: automatically update registers AND arm the TCU when header file has changed :param bool voice: voice prompts """ harpoon.Project.__init__(self, name, description, cores) self.fpga_con = fpga_con self.address = address self.headerfile = headerfile self.verify = verify self.bof_exe = bof_exe self.auto_arm = auto_arm if self.auto_arm: self.auto_update = True else: self.auto_update = auto_update self.voice = voice self.is_connected = False self.is_running = False self._init_logger(log_dir, debug) self.logger.debug('TCUController controller instance created with args:') self.logger.debug('\taddress = {}'.format(self.address)) self.logger.debug('\theaderfile = {}'.format(self.headerfile)) self.logger.debug('\tbof_exe = {}'.format(self.bof_exe)) self.logger.debug('\tauto_arm = {}'.format(self.auto_arm)) self.logger.debug('\tauto_update = {}'.format(self.auto_update)) self.logger.debug('\tvoice = {}'.format(self.voice)) self.init_headerfile_thread() def _init_logger(self, log_dir='', debug=False): self.logger = logging.getLogger('tcu_project_logger') self.logger.setLevel(logging.DEBUG) self.log_dir = log_dir # create file handler which logs even debug messages fh = logging.FileHandler(self.log_dir+'tcu_'+self.fpga_con.address+'.log') fh.setLevel(logging.DEBUG) # create console handler with a higher log level ch = logging.StreamHandler() if debug is True: ch.setLevel(logging.DEBUG) else: ch.setLevel(logging.INFO) # create formatter and add it to the handlers formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') formatter2 = logging.Formatter('[%(levelname)s] %(message)s') ch.setFormatter(formatter2) fh.setFormatter(formatter) # add the handlers to logger # use logging.getLogger() with no params to get all the other loggers from imported modules logging.getLogger().addHandler(fh) self.logger.addHandler(ch) def init_headerfile_thread(self): if self.headerfile is not None: watched_dir = os.path.split(self.headerfile)[0] # os.path.split() returns tuple (path, filename) print('watched_dir = {watched_dir}'.format(watched_dir=watched_dir)) patterns = [self.headerfile] print('patterns = {patterns}'.format(patterns=', '.join(patterns))) self.event_handler = FileEventHandler(self.logger, patterns=patterns) self.observer = Observer() self.observer.schedule(self.event_handler, watched_dir, recursive=False) self.observer.start() else: self.logger.warn('no headerfile path given, cannot start headerfile monitor') def connect(self): if self.address is not None: self.logger.info('initializing rhino connection, IP address: ' + self.address) try: self.fpga_con.connect() self.is_connected = True self.power_fmc() self.logger.info('connection successful!') if self.voice: os.system('spd-say -t female1 -i -0 "connected" -r -30 -p -30') except Exception as e: self.logger.exception('failed to connect to tcu') else: self.logger.error('IP address not set, cannot connect.') def disconnect(self): self.logger.info('disconnecting from tcu...') try: self.fpga_con.disconnect() self.logger.info('disconnect successful!') except Exception as e: self.logger.exception('failed to disconnect from tcu') def power_fmc(self): self.logger.debug('calling power_fmc.sh script...') fpga_con._action('./power_fmc.sh') # time.sleep(3) # self.fpga_con._action('echo 102 > /sys/class/gpio/export') # self.fpga_con._action('echo out > /sys/class/gpio/gpio102/direction') # self.fpga_con._action('echo 1 > /sys/class/gpio/gpio102/value') # self.fpga_con._action('echo out > /sys/class/gpio/gpio100/direction') # self.fpga_con._action('echo 1 > /sys/class/gpio/gpio100/value') def start(self): if fpga_con.ssh_connected(): self.logger.info('starting bof...') self.fpga_con.launch_bof(self.bof_exe, link=True) if self.fpga_con.running(): self.logger.info('bof started!') else: self.logger.error('failed to start bof \'{}\' on TCU \'{}\', please check log file \'{}\'' .format(self.bof_exe,self.address, self.log_dir+'tcu_'+self.fpga_con.address+'.log')) else: self.logger.error('cannot start bof without connection, connect to TCU first. Use tcu.connect() method.') def stop(self): if fpga_con.ssh_connected(): self.logger.info('stopping .bof...') self.fpga_con.kill_bof() else: self.logger.error('cannot kill bof without connection, connect to TCU first. Use tcu.connect() method') def parse_header(self): self.logger.info('parsing header file...') self.tcu_params = TCUParams(self.headerfile) self.logger.debug('Extracted parameters from header:\n' + str(self.tcu_params)) def write_registers(self): if fpga_con.ssh_connected(): if fpga_con.running(): self.logger.info('writing registers...') params = self.tcu_params.get_int_params() reg_num_repeats.write(params['num_repeats']) reg_num_pulses.write(params['num_pulses']) reg_x_amp_delay.write(params['x_amp_delay']) reg_l_amp_delay.write(params['l_amp_delay']) reg_rex_delay.write(params['rex_delay']) reg_pri_pulse_width.write(params['pri_pulse_width']) reg_pre_pulse.write(params['pre_pulse']) # need to do a bit more work for reg_pulses, # as it is a more complex data structure hex_params = self.tcu_params.get_hex_params() pulses = hex_params['pulses'] pulse_param_str = str() for pulse in pulses: pulse_param_str += pulse['pulse_width'].replace('\\x', '') \ + pulse['pri'].replace('\\x', '') \ + pulse['pol_mode'].replace('\\x', '') \ + pulse['frequency'].replace('\\x', '') pulse_param_bytearray = bytearray.fromhex(pulse_param_str) reg_pulses.write_bytes(pulse_param_bytearray, raw=True) self.logger.debug('registers written') if self.verify: self.logger.debug('checking registers...') self.check_regs() else: self.logger.error('No bof running, cannot perform register writes. Use tcu.start() method.') else: self.logger.error('No ssh connection to TCU, cannot perform register writes. Use tcu.connect() method') def check_regs(self): """reads back the TCU registers and compares them with the parameters sent""" if fpga_con.ssh_connected(): if fpga_con.running(): self.logger.info('verifying registers...') params = self.tcu_params.get_int_params() register_value_correct = True if self.check_reg(reg_num_repeats, params['num_repeats']) == False: register_value_correct = False if self.check_reg(reg_num_pulses, params['num_pulses']) == False: register_value_correct = False if self.check_reg(reg_x_amp_delay, params['x_amp_delay']) == False: register_value_correct = False if self.check_reg(reg_l_amp_delay, params['l_amp_delay']) == False: register_value_correct = False if self.check_reg(reg_rex_delay, params['rex_delay']) == False: register_value_correct = False if self.check_reg(reg_pri_pulse_width, params['pri_pulse_width']) == False: register_value_correct = False if self.check_reg(reg_pre_pulse, params['pre_pulse']) == False: register_value_correct = False # need to do a bit more work for reg_pulses, # as it is a more complex data structure hex_params = self.tcu_params.get_hex_params(hdl_format=True) pulses = hex_params['pulses'] pulse_param_str = str() for pulse in pulses: pulse_param_str += pulse['pulse_width'].replace('\"', '') + pulse['pri'].replace('\"', '') + pulse['pol_mode'].replace('\"', '') + pulse['frequency'].replace('\"', '') pulse_param_str = pulse_param_str.replace('x', '') num_pulses = reg_num_pulses.read() read_value = reg_pulses.read_bytes()[0:(10*num_pulses)] read_value_str = str() if sys.version_info >= (3, 6): for pulse_index in range(num_pulses): # print('pulse[{}]'.format(pulse_index)) pulse_width = read_value[pulse_index*10 + 0:pulse_index*10 + 2] # print('pw {}'.format(pulse_width.hex())) pri = read_value[pulse_index*10 + 4:pulse_index*10 + 6] + read_value[pulse_index*10 + 2:pulse_index*10 + 4] # print('pri {}'.format(pri.hex())) mode = read_value[pulse_index*10 + 6:pulse_index*10 + 8] # print('mode {}'.format(mode.hex())) freq = read_value[pulse_index*10 + 8:pulse_index*10 + 10] # print('freq {}'.format(freq.hex())) read_value_str += pulse_width.hex() + pri.hex() + mode.hex() + freq.hex() if read_value_str == pulse_param_str: self.logger.debug('Register \'{}\' verified'.format('pulses')) else: self.logger.error('Value mismatch for register \'{}\' retrieved {}, expected {}'.format('pulses', read_value_str, pulse_param_str)) register_value_correct = False else: self.logger.warning('cannot verify the pulses register. needs Python >= 3.6') if register_value_correct: self.logger.debug('All registers have been verified') else: self.logger.error('One or more registers contain incorrect value(s) - see {} for details'.format(self.log_dir+'tcu_'+self.fpga_con.address+'.log')) else: self.logger.error('No bof running, cannot perform register reads. Use tcu.start() method.') else: self.logger.error('No ssh connection to TCU, cannot perform register reads. Use tcu.connect() method.') def check_reg(self, register, expected_value): """returns True if the contents of given register matches a given value""" read_value = register.read() if read_value == expected_value: self.logger.debug('Register \'{}\' verified'.format(register.name)) return True else: self.logger.error('Value mismatch for register \'{}\' retrieved {}, expected {}' .format(register.name, read_value, expected_value)) return False def arm(self): """arms the TCU""" if fpga_con.ssh_connected(): if fpga_con.running(): self.logger.info('arming tcu...') reg_instruction.write(0) # time.sleep(3) reg_instruction.write(1) if self.voice: os.system('spd-say -t female1 -i -0 "armed" -r -30 -p -30') else: self.logger.error('No bof running TCU, cannot arm TCU. Use tcu.start() method.') else: self.logger.error('No ssh connection to TCU, cannot arm TCU. Use tcu.connect() method.')
def parse_header(self): self.logger.info('parsing header file...') self.tcu_params = TCUParams(self.headerfile) self.logger.debug('Extracted parameters from header:\n' + str(self.tcu_params))