示例#1
0
class BPMExperiment():

    def __init__(self, fpga_hostname = 'localhost', rffe_hostname = 'localhost', debug = False):
        self.fpga_hostname = fpga_hostname
        self.rffe_hostname = rffe_hostname
        self.debug = debug

        from metadata_parser import MetadataParser
        self.metadata_parser = MetadataParser()

    def load_from_metadata(self, input_metadata_filename):
        # Parse metadata file into a dictionary
        self.metadata_parser.parse(input_metadata_filename)
        self.metadata = self.metadata_parser.options

    def get_metadata_lines(self):
        experiment_parameters = list(self.metadata.keys())
        lines = []
        for key in experiment_parameters:
            lines.append(key + ' = ' + self.metadata[key] + '\n')
        return lines

    def run(self, data_filename, datapath):
        if datapath == 'adc':
            data_rate_decim_factor = '1'
            acq_channel = '0'
            acq_npts = '100000'
        elif datapath == 'tbt':
            data_rate_decim_factor = self.metadata['adc_clock_sampling_harmonic'].split()[0] # FIXME: data_rate_decim_factor should be ideally read from FPGA
            acq_channel = '1'
            acq_npts = '100000'
        elif datapath == 'fofb':
            data_rate_decim_factor = '1000' # FIXME: data_rate_decim_factor should be ideally read from FPGA
            acq_channel = '3'
            acq_npts = '1000000'

        deswitching_phase_offset = str(int(self.metadata['dsp_deswitching_phase'].split()[0]) - int(self.metadata['rffe_switching_phase'].split()[0]))

        import subprocess
        # Run FPGA configuration commands
        command_argument_list = ['fcs_client']
        command_argument_list.extend(['--setdivclk', self.metadata['rffe_switching_frequency_ratio'].split()[0]])
        command_argument_list.extend(['--setkx', self.metadata['bpm_Kx'].split()[0]])
        command_argument_list.extend(['--setky', self.metadata['bpm_Ky'].split()[0]])
        command_argument_list.extend(['--setphaseclk', deswitching_phase_offset])
        command_argument_list.extend(['--setsw' + self.metadata['rffe_switching'].split()[0]])
        command_argument_list.extend(['--setwdw' + self.metadata['dsp_sausaging'].split()[0]])
        command_argument_list.extend(['--setsamples', acq_npts])
        command_argument_list.extend(['--setchan', acq_channel])
        command_argument_list.extend(['--setfpgahostname', self.fpga_hostname])
        if not self.debug:
            subprocess.call(command_argument_list)
        else:
            print(command_argument_list)

        # Run RFFE configuration commands
        command_argument_list = ['fcs_client']
        command_argument_list.extend(['--setfesw' + self.metadata['rffe_switching'].split()[0]])
        att_items = self.metadata['rffe_attenuators'].split(',')
        i = 1
        for item in att_items:
            item.strip()
            command_argument_list.extend(['--setfeatt' + str(i), item.split()[0]])
            i = i+1
        command_argument_list.extend(['--setrffehostname', self.rffe_hostname])
        if not self.debug:
            subprocess.call(command_argument_list)
        else:
            print(command_argument_list)

        # TODO: Check if everything was properly set

        # Timestamp the start of data acquisition
        # FIXME: timestamp should ideally come together with data.
        from time import time
        t = time()

        # Run acquisition
        command_argument_list = ['fcs_client']
        command_argument_list.append('--startacq')
        command_argument_list.extend(['--setfpgahostname', self.fpga_hostname])
        if not self.debug:
            p = subprocess.call(command_argument_list)
        else:
            print(command_argument_list)

        # The script execution is blocked here until data acquisition has completed

        # Get the result of data acquisition and write it to data file
        command_argument_list = ['fcs_client']
        command_argument_list.extend(['--getcurve', acq_channel])
        command_argument_list.extend(['--setfpgahostname', self.fpga_hostname])

        # Ensure file path exists
        import os
        path = os.path.dirname(data_filename)
        try:
            os.makedirs(path)
        except OSError as exception:
            if not os.path.isdir(path):
                raise

        f = open(data_filename, 'x')
        if not self.debug:
            p = subprocess.call(command_argument_list, stdout=f)
        else:
            f.writelines(['10 11 -9 80\n54 5 6 98\n']);
            print(command_argument_list)
        f.close()

        # Compute data file signature
        f = open(data_filename, 'r')
        text = f.read()
        f.close()

        import hashlib
        if self.metadata['data_signature_method'].split()[0] == 'md5':
            md = hashlib.md5()
        elif self.metadata['data_signature_method'].split()[0] == 'sha-1':
            md = hashlib.sha1()
        elif self.metadata['data_signature_method'].split()[0] == 'sha-256':
            md = hashlib.sha256()
        md.update(text.encode(f.encoding))
        filesignature = md.hexdigest()

        # Format date and hour as an standard UTC timestamp (ISO 8601)
        from time import strftime, gmtime
        from math import floor
        ns = int(floor((t * 1e9) % 1e9))
        timestamp_start = '%s.%09dZ' % (strftime('%Y-%m-%dT%H:%M:%S', gmtime(t)), ns)

        # Trhow away absolute path of data filename
        data_filename_basename = os.path.basename(data_filename)

        # Build metadata file based on template metadata file and post-processed metadata

        config_base_metadata_lines = self.get_metadata_lines()

        config_automatic_lines = [];
        config_automatic_lines.append('data_original_filename = ' + data_filename_basename + '\n')
        config_automatic_lines.append('data_signature = ' + filesignature + '\n')
        config_automatic_lines.append('dsp_data_rate_decim_factor = ' + data_rate_decim_factor + '\n')
        config_automatic_lines.append('timestamp_start = ' + timestamp_start + '\n')
        #config_automatic_lines.append('adc_board_temperature = ' + '0' + ' C\n') #TODO: implement ADC temperature read on FPGA
        #config_automatic_lines.append('rffe_board_temperature = ' + '0' + ' C\n') #TODO: implement RFFE temperature read on FPGA

        config_fromfile_lines = []
        config_fromfile_lines.extend(config_base_metadata_lines)
        config_fromfile_lines.extend(config_automatic_lines)

        # Metadata file is placed in the same path and with the same filename as the data file, but with .metadata extension
        from os.path import basename
        output_metadata_filename = os.path.splitext(data_filename)[0] + '.metadata'

        f = open(output_metadata_filename, 'x')
        f.writelines(sorted(config_fromfile_lines))
        f.close()