Beispiel #1
0
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')
Beispiel #2
0
    # 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_())
Beispiel #3
0
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.')
Beispiel #4
0
 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))