def _read_config(self): """ Read the instrument configuration from self.config_source. :return: True if the instrument read a config successfully, raise an error if not? """ Instrument._read_config(self) _d = self.configd # check that the bitstream names are present try: open(_d['fengine']['bitstream'], 'r').close() open(_d['xengine']['bitstream'], 'r').close() except IOError: self.logger.error('xengine bitstream: ' '%s' % _d['xengine']['bitstream']) self.logger.error('fengine bitstream: ' '%s' % _d['fengine']['bitstream']) self.logger.error('One or more bitstream files not found.') raise IOError('One or more bitstream files not found.') # TODO: Load config values from the bitstream meta information - # f per fpga, x per fpga, etc self.arp_wait_time = int(_d['FxCorrelator']['arp_wait_time']) self.sensor_poll_time = int(_d['FxCorrelator']['sensor_poll_time']) self.katcp_port = int(_d['FxCorrelator']['katcp_port']) self.f_per_fpga = int(_d['fengine']['f_per_fpga']) self.x_per_fpga = int(_d['xengine']['x_per_fpga']) self.sample_rate_hz = int(_d['FxCorrelator']['sample_rate_hz']) self.adc_demux_factor = int(_d['fengine']['adc_demux_factor']) self.accumulation_len = int(_d['xengine']['accumulation_len']) self.xeng_accumulation_len = int(_d['xengine']['xeng_accumulation_len']) self.n_chans = int(_d['fengine']['n_chans']) self.n_antennas = int(_d['fengine']['n_antennas']) self.min_load_time = float(_d['fengine']['min_load_time']) self.set_stream_destination( _d['xengine']['output_destination_ip'], int(_d['xengine']['output_destination_port'])) self.set_meta_destination(_d['xengine']['output_destination_ip'], int(_d['xengine']['output_destination_port'])) # get this from the running x-engines? self.xeng_clk = int(_d['xengine']['x_fpga_clock']) self.xeng_outbits = int(_d['xengine']['xeng_outbits']) # the f-engines have this many 10Gbe ports per f-engine # unit of operation self.ports_per_fengine = int(_d['fengine']['ports_per_fengine']) # check if beamformer exists with x-engines self.found_beamformer = False if 'bengine' in self.configd.keys(): self.found_beamformer = True # set up the hosts and engines based on the configuration in the ini file self.fhosts = [] for host in _d['fengine']['hosts'].split(','): host = host.strip() fpgahost = fhost_fpga.FpgaFHost.from_config_source( host, self.katcp_port, config_source=_d['fengine']) self.fhosts.append(fpgahost) # choose class (b-engine inherits x-engine functionality) if self.found_beamformer: _targetClass = bhost_fpga.FpgaBHost else: _targetClass = xhost_fpga.FpgaXHost self.xhosts = [] for host in _d['xengine']['hosts'].split(','): host = host.strip() fpgahost = xhost_fpga.FpgaXHost.from_config_source( host, self.katcp_port, config_source=_d['xengine']) self.xhosts.append(fpgahost) self.bhosts = [] # x-eng host b-eng for host in _d['xengine']['hosts'].split(','): host = host.strip() fpgahost = bhost_fpga.FpgaBHost.from_config_source( host, self.katcp_port, config_source=_d['xengine']) self.bhosts.append(fpgahost) # check that no hosts overlap for _fh in self.fhosts: for _xh in self.xhosts: if _fh.host == _xh.host: self.logger.error('Host %s is assigned to both X- and ' 'F-engines' % _fh.host) raise RuntimeError # what data sources have we been allocated? self._handle_sources() # turn the product names into a list prodlist = _d['xengine']['output_products'].replace('[', '').replace(']', '').split(',') _d['xengine']['output_products'] = [] for prod in prodlist: _d['xengine']['output_products'].append(prod.strip(''))
def _read_config(self): """ Read the instrument configuration from self.config_source. :return: True if the instrument read a config successfully, raise an error if not? """ Instrument._read_config(self) if use_demo_fengine: self.configd['fengine']['bitstream'] = '/srv/bofs/feng/feng_rx_test_2014_Jul_22_1556.fpg' # check that the bitstream names are present try: open(self.configd['fengine']['bitstream'], 'r').close() open(self.configd['xengine']['bitstream'], 'r').close() except IOError: LOGGER.error('One or more bitstream files not found.') raise IOError('One or more bitstream files not found.') # TODO: Load config values from the bitstream meta information self.katcp_port = int(self.configd['FxCorrelator']['katcp_port']) self.f_per_fpga = int(self.configd['fengine']['f_per_fpga']) self.x_per_fpga = int(self.configd['xengine']['x_per_fpga']) self.sample_rate_hz = int(self.configd['FxCorrelator']['sample_rate_hz']) self.accumulation_len = int(self.configd['xengine']['accumulation_len']) self.txip_str = self.configd['xengine']['output_destination_ip'] self.txport = int(self.configd['xengine']['output_destination_port']) # TODO: Work on the logic of sources->engines->hosts # 2 pols per FPGA on this initial design, but should be mutable self.inputs_per_fengine = int(self.configd['fengine']['inputs_per_fengine']) # what antenna ids have we been allocated? self.source_names = self.configd['fengine']['source_names'].strip().split(',') self.source_mcast = [] mcast = self.configd['fengine']['source_mcast_ips'].strip().split(',') for address in mcast: bits = address.split(':') port = int(bits[1]) address, number = bits[0].split('+') self.source_mcast.append((address, int(number), int(port))) comparo = self.source_mcast[0][1] assert comparo == 3, 'F-engines should be receiving from 4 streams.' for mcast_addresses in self.source_mcast: assert mcast_addresses[1] == comparo, 'All f-engines should be receiving from 4 streams.' if len(self.source_names) != len(self.source_mcast): raise RuntimeError('We have different numbers of sources and multicast groups. Problem.') # set up the hosts and engines based on the config self.fhosts = [] self.xhosts = [] for hostconfig, hostlist in [(self.configd['fengine'], self.fhosts), (self.configd['xengine'], self.xhosts)]: hosts = hostconfig['hosts'].strip().split(',') for host in hosts: host = host.strip() fpgahost = FpgaHost(host, self.katcp_port, hostconfig['bitstream'], connect=True) hostlist.append(fpgahost) if len(self.source_names) != len(self.fhosts): raise RuntimeError('We have different numbers of sources and f-engine hosts. Problem.') for fnum, fhost in enumerate(self.fhosts): # TODO - logic for inputs vs fengines for ctr in range(0, self.inputs_per_fengine): engine = FengineCasperFpga(fhost, ctr, self.source_names[fnum], self.configd) fhost.add_engine(engine) for xnum, xhost in enumerate(self.xhosts): for ctr in range(0, self.x_per_fpga): engine = XengineCasperFpga(xhost, ctr, self.configd) xhost.add_engine(engine) # SPEAD receiver self.spead_tx = spead.Transmitter(spead.TransportUDPtx(self.configd['xengine']['rx_meta_ip'], int(self.configd['xengine']['rx_udp_port']))) self.spead_ig = spead.ItemGroup() # done return True
def _read_config(self): """ Read the instrument configuration from self.config_source. :return: """ Instrument._read_config(self) _d = self.configd # check that the bitstream names are present try: open(_d['fengine']['bitstream'], 'r').close() open(_d['xengine']['bitstream'], 'r').close() except IOError: self.logger.error('xengine bitstream: ' '%s' % _d['xengine']['bitstream']) self.logger.error('fengine bitstream: ' '%s' % _d['fengine']['bitstream']) self.logger.error('One or more bitstream files not found.') raise IOError('One or more bitstream files not found.') # TODO: Load config values from the bitstream meta information - # f per fpga, x per fpga, etc _fxcorr_d = self.configd['FxCorrelator'] self.arp_wait_time = int(_fxcorr_d['arp_wait_time']) self.sensor_poll_time = int(_fxcorr_d['sensor_poll_time']) self.katcp_port = int(_fxcorr_d['katcp_port']) self.sample_rate_hz = int(_fxcorr_d['sample_rate_hz']) self.timestamp_bits = int(_fxcorr_d['timestamp_bits']) self.time_jitter_allowed_ms = int(_fxcorr_d['time_jitter_allowed_ms']) self.time_offset_allowed_s = int(_fxcorr_d['time_offset_allowed_s']) try: self.post_switch_delay = int(_fxcorr_d['switch_delay']) except KeyError: self.post_switch_delay = 10 _feng_d = self.configd['fengine'] self.adc_demux_factor = int(_feng_d['adc_demux_factor']) self.n_chans = int(_feng_d['n_chans']) self.n_antennas = int(_feng_d['n_antennas']) self.min_load_time = float(_feng_d['min_load_time']) self.f_per_fpga = int(_feng_d['f_per_fpga']) self.ports_per_fengine = int(_feng_d['ports_per_fengine']) self.analogue_bandwidth = int(_feng_d['bandwidth']) self.true_cf = float(_feng_d['true_cf']) self.quant_format = _feng_d['quant_format'] self.adc_bitwidth = int(_feng_d['sample_bits']) self.fft_shift = int(_feng_d['fft_shift']) try: self.qdr_ct_error_threshold = int(_feng_d['qdr_ct_error_threshold']) except KeyError: self.qdr_ct_error_threshold = 100 try: self.qdr_cd_error_threshold = int(_feng_d['qdr_cd_error_threshold']) except KeyError: self.qdr_cd_error_threshold = 100 _xeng_d = self.configd['xengine'] self.x_per_fpga = int(_xeng_d['x_per_fpga']) self.accumulation_len = int(_xeng_d['accumulation_len']) self.xeng_accumulation_len = int(_xeng_d['xeng_accumulation_len']) try: self.qdr_vacc_error_threshold = int( _xeng_d['qdr_vacc_error_threshold']) except KeyError: self.qdr_vacc_error_threshold = 100 # get this from the running x-engines? self.xeng_clk = int(_xeng_d['x_fpga_clock']) self.xeng_outbits = int(_xeng_d['xeng_outbits']) # check if beamformer exists with x-engines self.found_beamformer = False if 'bengine' in self.configd.keys(): self.found_beamformer = True self.beng_outbits = 8 # set up hosts and engines based on the configuration in the ini file _targetClass = fhost_fpga.FpgaFHost self.fhosts = [] for host in _feng_d['hosts'].split(','): host = host.strip() fpgahost = _targetClass.from_config_source(host, self.katcp_port, config_source=_feng_d) self.fhosts.append(fpgahost) # choose class (b-engine inherits x-engine functionality) if self.found_beamformer: _targetClass = bhost_fpga.FpgaBHost else: _targetClass = xhost_fpga.FpgaXHost self.xhosts = [] hostlist = _xeng_d['hosts'].split(',') for hostindex, host in enumerate(hostlist): host = host.strip() fpgahost = _targetClass.from_config_source( host, hostindex, self.katcp_port, config_source=_xeng_d) self.xhosts.append(fpgahost) # check that no hosts overlap for _fh in self.fhosts: for _xh in self.xhosts: if _fh.host == _xh.host: self.logger.error('Host %s is assigned to ' 'both X- and F-engines' % _fh.host) raise RuntimeError # update the list of baselines on this system self.baselines = utils.baselines_from_config(config=self.configd) # what data sources have we been allocated? self._handle_sources() # turn the stream names into a list prodlist = _xeng_d['output_products'].replace('[', '') prodlist = prodlist.replace(']', '').split(',') _xeng_d['output_products'] = [prod.strip(' ') for prod in prodlist]