├── MANIFEST.in ├── bak ├── .corr_snap_quant.py.swp ├── corr_snap_10gbe_tx_out.py └── corr_snap_10gbe_tx_out_imcomplete_old.py ├── src ├── corr_ddc.py ├── support.py ├── __init__.py ├── LICENSE.txt ├── log_handlers.py ├── termcolors.py ├── threaded.py ├── oogpio.py ├── iadc.py ├── scroll.py ├── corr_wb.py ├── sim.py └── katcp_serial.py ├── .gitignore ├── LICENSE.txt ├── PKG-INFO ├── scripts ├── corr_feng_reset.py ├── corr_10gbe_deconfig.py ├── corr_rst_errors.py ├── corr_arm_feng.py ├── corr_rst_gbe.py ├── corr_deprog_all.py ├── corr_spead_issue.py ├── corr_check_pcnt.py ├── corr_acc_period.py ├── corr_clocks.py ├── corr_nb_chansel.py ├── corr_rx.py ├── sfp_card_info.py ├── corr_fr_del_set.py ├── corr_tx_start_stop.py ├── corr_tvg_feng_sel.py ├── corr_10gbe_core_details.py ├── corr_eq_init.py ├── corr_snap_xeng.py ├── corr_snap_quant.py ├── corr_nb_build_ct_spectrum.py ├── corr_nb_snap_ct.py ├── corr_adc_ampl.py ├── corr_nb_plot_passband.py ├── corr_quant_hist.py ├── corr_fstatus.py ├── corr_snap_xeng_vacc.py ├── corr_xstatus.py ├── corr_nb_snap_soft_fine_fft.py └── corr_snap_feng_10gbe_tx.py ├── setup.py ├── README ├── CHANGELOG └── etc └── default /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.conf 2 | include *.txt 3 | -------------------------------------------------------------------------------- /bak/.corr_snap_quant.py.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ska-sa/corr/master/bak/.corr_snap_quant.py.swp -------------------------------------------------------------------------------- /src/corr_ddc.py: -------------------------------------------------------------------------------- 1 | """ 2 | Functions for controlling a narrowband correlator with a digital downconverter to select the band of interest. 3 | 4 | Author: Paul Prozesky 5 | """ 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS generated files # 2 | ###################### 3 | .DS_Store* 4 | ehthumbs.db 5 | Icon? 6 | Thumbs.db 7 | 8 | # Compiled source # 9 | ################### 10 | *.com 11 | *.class 12 | *.dll 13 | *.exe 14 | *.o 15 | *.so 16 | +build/ 17 | *.egg-info 18 | *.pyc 19 | -------------------------------------------------------------------------------- /src/support.py: -------------------------------------------------------------------------------- 1 | def gzip(filename): 2 | return NotImplementedError 3 | import gzip 4 | f = gzip.open(bof_file, 'rb') 5 | gzipped_already = True 6 | try: 7 | a = f.read() 8 | except: 9 | gzipped_already = False 10 | if not gzipped_already: 11 | tempfile = tempfile.TemporaryFile('w+b') 12 | gzipfile = gzip.open('dontcare', 'wb', 9, tempfile) 13 | gzipfile.write(f) 14 | f.close() 15 | 16 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | A module for controlling and receiving data from a CASPER_N correlator. 3 | 4 | Implements interfaces for controlling a CASPER_N correlator and verifying correct operation. 5 | Used primarily for by the PAPER array project. 6 | 7 | Author: Jason Manley, Aaron Parsons 8 | Email: jason_manley at hotmail.com, aparsons at astron.berkeley.edu 9 | Revisions: 10 | """ 11 | import cn_conf, katcp_wrapper, katcp_serial, log_handlers, corr_functions, bf_functions, corr_wb, corr_nb, corr_ddc, scroll, katadc, iadc, termcolors, rx, sim, snap, threaded 12 | 13 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2006-2007 Aaron Parsons, 2008-2010 Jason Manley 2 | # This program is free software; you can redistribute it and/or 3 | # modify it under the terms of the GNU General Public License 4 | # as published by the Free Software Foundation; either version 2 5 | # of the License, or (at your option) any later version. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 15 | 16 | -------------------------------------------------------------------------------- /src/LICENSE.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2006-2007 Aaron Parsons, 2008-2010 Jason Manley 2 | # This program is free software; you can redistribute it and/or 3 | # modify it under the terms of the GNU General Public License 4 | # as published by the Free Software Foundation; either version 2 5 | # of the License, or (at your option) any later version. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 15 | 16 | -------------------------------------------------------------------------------- /PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.1 2 | Name: corr 3 | Version: 0.6.5 4 | Summary: Interfaces to CASPER correlators 5 | Home-page: http://pypi.python.org/pypi/corr 6 | Author: Jason Manley 7 | Author-email: jason_manley at hotmail.com 8 | License: GPL 9 | Description: Provides interfaces to CASPER hardware and functions to configure packetised correlators. 10 | Platform: UNKNOWN 11 | Classifier: Development Status :: 3 - Alpha 12 | Classifier: Intended Audience :: Developers 13 | Classifier: Operating System :: OS Independent 14 | Classifier: License :: OSI Approved :: GNU General Public License (GPL) 15 | Classifier: Topic :: Scientific/Engineering :: Astronomy 16 | Classifier: Topic :: Software Development :: Libraries :: Python Modules 17 | Requires: katcp 18 | Requires: pylab 19 | Requires: matplotlib 20 | Requires: iniparse 21 | Requires: numpy 22 | Requires: spead 23 | Requires: curses 24 | Provides: corr 25 | -------------------------------------------------------------------------------- /scripts/corr_feng_reset.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """ 3 | Reset ALL THE THINGS! 4 | """ 5 | 6 | import corr, sys, logging, time 7 | 8 | def exit_fail(): 9 | print 'FAILURE DETECTED. Log entries:\n',lh.printMessages() 10 | print "Unexpected error:", sys.exc_info() 11 | try: 12 | c.disconnect_all() 13 | except: pass 14 | exit(1) 15 | 16 | def exit_clean(): 17 | try: 18 | c.disconnect_all() 19 | except: pass 20 | exit(0) 21 | 22 | if __name__ == '__main__': 23 | from optparse import OptionParser 24 | 25 | p = OptionParser() 26 | p.set_usage('%prog [options] [CUSTOM_CONFIG_FILE]') 27 | p.set_description(__doc__) 28 | opts, args = p.parse_args(sys.argv[1:]) 29 | if args == []: 30 | config_file = None 31 | else: 32 | config_file = args[0] 33 | 34 | lh = corr.log_handlers.DebugLogHandler(100) 35 | try: 36 | print 'Connecting...', 37 | c = corr.corr_functions.Correlator(config_file = config_file, log_level = logging.INFO, connect = False, log_handler = lh) 38 | c.connect() 39 | print 'done' 40 | 41 | print 'Pulsing reset line...', 42 | c.feng_ctrl_set_all(sys_rst = 'pulse') 43 | print 'done.' 44 | 45 | except KeyboardInterrupt: 46 | exit_clean() 47 | except: 48 | exit_fail() 49 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | import os, sys, glob 3 | 4 | __version__ = '0.7.3' 5 | 6 | katcp_prefix = '/' 7 | if os.environ.has_key('VIRTUAL_ENV'): 8 | katcp_prefix = os.environ['VIRTUAL_ENV'] 9 | 10 | setup(name = 'corr', 11 | version = __version__, 12 | description = 'Interfaces to CASPER correlators', 13 | long_description = 'Provides interfaces to CASPER hardware and functions to configure packetised FX correlators and co-located beamformers.', 14 | license = 'GPL', 15 | author = 'Jason Manley', 16 | author_email = 'jason_manley at hotmail.com', 17 | url = 'http://pypi.python.org/pypi/corr', 18 | classifiers=[ 19 | 'Development Status :: 3 - Alpha', 20 | 'Intended Audience :: Developers', 21 | 'Operating System :: OS Independent', 22 | 'License :: OSI Approved :: GNU General Public License (GPL)', 23 | 'Topic :: Scientific/Engineering :: Astronomy', 24 | 'Topic :: Software Development :: Libraries :: Python Modules', 25 | ], 26 | install_requires=['katcp', 'matplotlib', 'iniparse', 'numpy', 'spead', 'construct', 'h5py'], 27 | provides=['corr'], 28 | package_dir = {'corr':'src'}, 29 | packages = ['corr'], 30 | scripts=glob.glob('scripts/*'), 31 | data_files=[(os.path.join(katcp_prefix, 'etc/corr'),['etc/default']), 32 | #('/var/run/corr',['support_files/sync_time']) 33 | ] 34 | ) 35 | 36 | -------------------------------------------------------------------------------- /scripts/corr_10gbe_deconfig.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """Stops the tgtap device drivers on all 10GbE interfaces on the ROACH boards. 3 | Author: Jason Manley 4 | Rev 5 | 2010-07-28 JRM Port to corr-0.5.0 6 | """ 7 | import corr, time, sys, numpy, os, logging 8 | 9 | def exit_fail(): 10 | print 'FAILURE DETECTED. Log entries:\n',c.log_handler.printMessages() 11 | print "Unexpected error:", sys.exc_info() 12 | try: 13 | c.disconnect_all() 14 | except: pass 15 | if verbose: 16 | raise 17 | exit() 18 | 19 | def exit_clean(): 20 | try: 21 | c.disconnect_all() 22 | except: pass 23 | exit() 24 | 25 | 26 | if __name__ == '__main__': 27 | from optparse import OptionParser 28 | 29 | p = OptionParser() 30 | p.set_usage('%prog CONFIG_FILE') 31 | p.set_description(__doc__) 32 | p.add_option('-v', '--verbose', dest='verbose',action='store_true', default=False, 33 | help='Be verbose about errors.') 34 | 35 | opts, args = p.parse_args(sys.argv[1:]) 36 | 37 | if args==[]: 38 | config_file=None 39 | else: 40 | config_file=args[0] 41 | verbose=opts.verbose 42 | 43 | try: 44 | print 'Connecting...', 45 | c=corr.corr_functions.Correlator(config_file=config_file,log_level=logging.DEBUG if verbose else logging.INFO,connect=False) 46 | c.connect() 47 | print 'done' 48 | 49 | print('\nKilling all 10GbE tgtap drivers...'), 50 | sys.stdout.flush() 51 | c.deconfig_roach_10gbe_ports() 52 | print 'done.' 53 | 54 | 55 | except KeyboardInterrupt: 56 | exit_clean() 57 | except: 58 | exit_fail() 59 | exit() 60 | -------------------------------------------------------------------------------- /scripts/corr_rst_errors.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """Resets the cumulative error counters on all connected servers. 3 | 4 | Author: Jason Manley 5 | Revs: 6 | 2010-07-26: JRM Port for corr-0.5.0 7 | """ 8 | import corr, time, sys, numpy, os, logging 9 | 10 | def exit_fail(): 11 | print 'FAILURE DETECTED. Log entries:\n', 12 | c.log_handler.printMessages() 13 | print "Unexpected error:", sys.exc_info() 14 | try: 15 | c.disconnect_all() 16 | except: pass 17 | #raise 18 | exit() 19 | 20 | def exit_clean(): 21 | try: 22 | c.disconnect_all() 23 | except: pass 24 | exit() 25 | 26 | if __name__ == '__main__': 27 | from optparse import OptionParser 28 | 29 | p = OptionParser() 30 | p.set_usage('%prog CONFIG_FILE') 31 | p.set_description(__doc__) 32 | p.add_option('-v', '--verbose', dest='verbose',action='store_true', default=False, 33 | help='Be verbose about errors.') 34 | 35 | opts, args = p.parse_args(sys.argv[1:]) 36 | 37 | if args==[]: 38 | config_file=None 39 | else: 40 | config_file=args[0] 41 | verbose=opts.verbose 42 | 43 | lh=corr.log_handlers.DebugLogHandler(100) 44 | 45 | try: 46 | print 'Connecting...', 47 | c=corr.corr_functions.Correlator(config_file=config_file,log_level=logging.DEBUG if verbose else logging.INFO,connect=False, log_handler=lh) 48 | c.connect() 49 | print 'done' 50 | 51 | print('\nResetting error counters...'), 52 | sys.stdout.flush() 53 | c.rst_status_and_count() 54 | print 'done.' 55 | 56 | except KeyboardInterrupt: 57 | exit_clean() 58 | except: 59 | exit_fail() 60 | exit() 61 | -------------------------------------------------------------------------------- /src/log_handlers.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from corr import termcolors 3 | 4 | class DebugLogHandler(logging.Handler): 5 | """A logger for KATCP tests.""" 6 | 7 | def __init__(self,max_len=100): 8 | """Create a TestLogHandler. 9 | @param max_len Integer: The maximum number of log entries 10 | to store. After this, will wrap. 11 | """ 12 | logging.Handler.__init__(self) 13 | self._max_len = max_len 14 | self._records = [] 15 | 16 | def emit(self, record): 17 | """Handle the arrival of a log message.""" 18 | if len(self._records) >= self._max_len: self._records.pop(0) 19 | self._records.append(record) 20 | 21 | def clear(self): 22 | """Clear the list of remembered logs.""" 23 | self._records = [] 24 | 25 | def setMaxLen(self,max_len): 26 | self._max_len=max_len 27 | 28 | def printMessages(self): 29 | for i in self._records: 30 | if i.exc_info: 31 | print termcolors.colorize('%s: %s Exception: '%(i.name,i.msg),i.exc_info[0:-1],fg='red') 32 | else: 33 | if i.levelno < logging.WARNING: 34 | print termcolors.colorize('%s: %s'%(i.name,i.msg),fg='green') 35 | elif (i.levelno >= logging.WARNING) and (i.levelno < logging.ERROR): 36 | print termcolors.colorize('%s: %s'%(i.name,i.msg),fg='yellow') 37 | elif i.levelno >= logging.ERROR: 38 | print termcolors.colorize('%s: %s'%(i.name,i.msg),fg='red') 39 | else: 40 | print '%s: %s'%(i.name,i.msg) 41 | 42 | 43 | #log_handler = TestLogHandler() 44 | #logging.getLogger("katcp").addHandler(log_handler) 45 | -------------------------------------------------------------------------------- /src/termcolors.py: -------------------------------------------------------------------------------- 1 | """ 2 | termcolors.py 3 | """ 4 | 5 | color_names = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white') 6 | foreground = dict([(color_names[x], '3%s' % x) for x in range(8)]) 7 | background = dict([(color_names[x], '4%s' % x) for x in range(8)]) 8 | 9 | RESET = '0' 10 | opt_dict = {'bold': '1', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'} 11 | 12 | def colorize(text='', opts=(), **kwargs): 13 | """ 14 | Returns your text, enclosed in ANSI graphics codes. 15 | 16 | Depends on the keyword arguments 'fg' and 'bg', and the contents of 17 | the opts tuple/list. 18 | 19 | Returns the RESET code if no parameters are given. 20 | 21 | Valid colors: 22 | 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white' 23 | 24 | Valid options: 25 | 'bold' 26 | 'underscore' 27 | 'blink' 28 | 'reverse' 29 | 'conceal' 30 | 'noreset' - string will not be auto-terminated with the RESET code 31 | 32 | Examples: 33 | colorize('hello', fg='red', bg='blue', opts=('blink',)) 34 | colorize() 35 | colorize('goodbye', opts=('underscore',)) 36 | print colorize('first line', fg='red', opts=('noreset',)) 37 | print 'this should be red too' 38 | print colorize('and so should this') 39 | print 'this should not be red' 40 | """ 41 | code_list = [] 42 | if text == '' and len(opts) == 1 and opts[0] == 'reset': 43 | return '\x1b[%sm' % RESET 44 | for k, v in kwargs.iteritems(): 45 | if k == 'fg': 46 | code_list.append(foreground[v]) 47 | elif k == 'bg': 48 | code_list.append(background[v]) 49 | for o in opts: 50 | if o in opt_dict: 51 | code_list.append(opt_dict[o]) 52 | if 'noreset' not in opts: 53 | text = text + '\x1b[%sm' % RESET 54 | return ('\x1b[%sm' % ';'.join(code_list)) + text 55 | -------------------------------------------------------------------------------- /scripts/corr_arm_feng.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """Arms the F engines and resets the cumulative error counters on the X engine. 3 | Rev: 4 | 2010-11-26 JRM Resync VACC after arm. 5 | """ 6 | import corr, time, sys, numpy, os, logging 7 | 8 | def exit_fail(): 9 | print 'FAILURE DETECTED. Log entries:\n', 10 | c.log_handler.printMessages() 11 | print "Unexpected error:", sys.exc_info() 12 | try: 13 | c.disconnect_all() 14 | except: pass 15 | #raise 16 | exit() 17 | 18 | def exit_clean(): 19 | try: 20 | c.disconnect_all() 21 | except: pass 22 | exit() 23 | 24 | if __name__ == '__main__': 25 | from optparse import OptionParser 26 | 27 | p = OptionParser() 28 | p.set_usage('%prog CONFIG_FILE') 29 | p.set_description(__doc__) 30 | p.add_option('-v', '--verbose', dest='verbose',action='store_true', default=False, 31 | help='Be verbose about errors.') 32 | 33 | opts, args = p.parse_args(sys.argv[1:]) 34 | 35 | if args==[]: 36 | config_file=None 37 | else: 38 | config_file=args[0] 39 | verbose=opts.verbose 40 | 41 | try: 42 | print 'Connecting...', 43 | c = corr.corr_functions.Correlator(config_file=config_file,log_level=logging.DEBUG if verbose else logging.INFO, connect=False) 44 | c.connect() 45 | print 'done' 46 | 47 | print ''' Syncing the F engines...''', 48 | sys.stdout.flush() 49 | trig_time = c.arm() 50 | print 'Armed. Expect trigg at %s local (%s UTC).' % (time.strftime('%H:%M:%S', time.localtime(trig_time)), time.strftime('%H:%M:%S', time.gmtime(trig_time))), 51 | print 'SPEAD packet sent.' 52 | 53 | print('Resyncing VACCs...'), 54 | sys.stdout.flush() 55 | c.vacc_sync() 56 | print 'done.' 57 | 58 | print('Resetting error counters...'), 59 | sys.stdout.flush() 60 | c.rst_status_and_count() 61 | print 'done.' 62 | 63 | except KeyboardInterrupt: 64 | exit_clean() 65 | except: 66 | exit_fail() 67 | exit() 68 | -------------------------------------------------------------------------------- /scripts/corr_rst_gbe.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """ 3 | Resets the 10GbE cores on all X engines through fabric rst port toggle. 4 | """ 5 | import corr, time, sys, numpy, os, logging 6 | 7 | def exit_fail(): 8 | print 'FAILURE DETECTED. Log entries:\n', 9 | c.log_handler.printMessages() 10 | try: 11 | c.disconnect_all() 12 | except: pass 13 | time.sleep(1) 14 | raise 15 | exit() 16 | 17 | def exit_clean(): 18 | try: 19 | c.disconnect_all() 20 | except: pass 21 | exit() 22 | 23 | if __name__ == '__main__': 24 | from optparse import OptionParser 25 | 26 | p = OptionParser() 27 | p.set_usage('%prog CONFIG_FILE') 28 | p.set_description(__doc__) 29 | 30 | opts, args = p.parse_args(sys.argv[1:]) 31 | 32 | if args == []: 33 | config_file = None 34 | else: 35 | config_file = args[0] 36 | #verbose=opts.verbose 37 | verbose = False 38 | 39 | try: 40 | print 'Connecting...', 41 | c = corr.corr_functions.Correlator(config_file = config_file, log_level = logging.DEBUG if verbose else logging.INFO, connect = False) 42 | c.connect() 43 | print 'done' 44 | 45 | print('\nResetting GBE cores...'), 46 | sys.stdout.flush() 47 | 48 | #DO NOT RESET THE 10GBE CORES SYNCHRONOUSLY! 49 | if c.config['feng_out_type']=='10gbe': 50 | c.feng_ctrl_set_all(gbe_enable = False, gbe_rst = False) 51 | c.feng_ctrl_set_all(gbe_enable = False, gbe_rst = True) 52 | c.feng_ctrl_set_all(gbe_enable = False, gbe_rst = False) 53 | c.feng_ctrl_set_all(gbe_enable = True, gbe_rst = False) 54 | 55 | c.xeng_ctrl_set_all(gbe_enable = False, gbe_rst = False) 56 | c.xeng_ctrl_set_all(gbe_enable = False, gbe_rst = True) 57 | c.xeng_ctrl_set_all(gbe_enable = False, gbe_rst = False) 58 | c.xeng_ctrl_set_all(gbe_enable = True, gbe_rst = False) 59 | 60 | print 'done.' 61 | 62 | except KeyboardInterrupt: 63 | exit_clean() 64 | except: 65 | exit_fail() 66 | exit() 67 | -------------------------------------------------------------------------------- /scripts/corr_deprog_all.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """ 3 | Script for unloading the casper_n correlator's FPGAs. 4 | 5 | Author: Jason Manley 6 | Revs: 7 | 2010-07-28 JRM Port to corr-0.5.0 8 | 2009-07-01 JRM First release 9 | """ 10 | import corr, time, sys, numpy, os, logging 11 | 12 | def exit_fail(): 13 | print 'FAILURE DETECTED. Log entries:\n', 14 | c.log_handler.printMessages() 15 | print "Unexpected error:", sys.exc_info() 16 | try: 17 | c.disconnect_all() 18 | except: pass 19 | if verbose: 20 | raise 21 | exit() 22 | 23 | def exit_clean(): 24 | try: 25 | c.disconnect_all() 26 | except: pass 27 | exit() 28 | 29 | if __name__ == '__main__': 30 | from optparse import OptionParser 31 | 32 | p = OptionParser() 33 | p.set_usage('%prog [options] CONFIG_FILE') 34 | p.set_description(__doc__) 35 | p.add_option('-m', '--monitor_only', dest='monitor_only', action='store_true', default=False, 36 | help='Skip the initialision. ie Only monitor.') 37 | p.add_option('-r', '--n_retries', dest='n_retries', type='int', default=-1, 38 | help='Number of times to try and sync the system before giving up. Set to -1 for infinity. Default: -1') 39 | p.add_option('-v', '--verbose', dest='verbose',action='store_true', default=False, 40 | help='Be verbose about errors.') 41 | 42 | 43 | opts, args = p.parse_args(sys.argv[1:]) 44 | 45 | if args==[]: 46 | config_file=None 47 | else: 48 | config_file=args[0] 49 | verbose=opts.verbose 50 | 51 | try: 52 | print 'Connecting...', 53 | c=corr.corr_functions.Correlator(config_file=config_file,log_level=logging.DEBUG if verbose else logging.INFO, connect=False) 54 | c.connect() 55 | print 'done' 56 | 57 | print('\nDeprogramming all FPGAs...'), 58 | sys.stdout.flush() 59 | c.deprog_all() 60 | print 'done.' 61 | 62 | # lh.printMessages() 63 | 64 | except KeyboardInterrupt: 65 | exit_clean() 66 | except: 67 | exit_fail() 68 | 69 | exit_clean() 70 | 71 | 72 | -------------------------------------------------------------------------------- /scripts/corr_spead_issue.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """(Re)Issues SPEAD metadata and data descriptors so that receivers will be able to interpret the data. 3 | """ 4 | import corr, time, sys, numpy, os, logging 5 | 6 | def exit_fail(): 7 | print 'FAILURE DETECTED. Log entries:\n',c.log_handler.printMessages() 8 | print "Unexpected error:", sys.exc_info() 9 | try: 10 | c.disconnect_all() 11 | except: pass 12 | if verbose: 13 | raise 14 | exit() 15 | 16 | def exit_clean(): 17 | try: 18 | c.disconnect_all() 19 | except: pass 20 | exit() 21 | 22 | 23 | if __name__ == '__main__': 24 | from optparse import OptionParser 25 | 26 | p = OptionParser() 27 | p.set_usage('%prog CONFIG_FILE') 28 | p.set_description(__doc__) 29 | p.add_option('-v', '--verbose', dest='verbose',action='store_true', default=False, 30 | help='Be verbose about errors.') 31 | 32 | opts, args = p.parse_args(sys.argv[1:]) 33 | 34 | if args==[]: 35 | config_file=None 36 | else: 37 | config_file=args[0] 38 | verbose=opts.verbose 39 | 40 | try: 41 | print 'Connecting...', 42 | c=corr.corr_functions.Correlator(config_file=config_file,log_level=logging.DEBUG if verbose else logging.INFO,connect=False) 43 | c.connect() 44 | print 'done' 45 | 46 | print "Sending meta data to %s:%i."%(c.config['rx_meta_ip_str'],c.config['rx_udp_port']) 47 | 48 | print ''' Issuing data descriptors...''', 49 | sys.stdout.flush() 50 | c.spead_data_descriptor_issue() 51 | print 'SPEAD packet sent.' 52 | 53 | print ''' Issuing static metadata...''', 54 | sys.stdout.flush() 55 | c.spead_static_meta_issue() 56 | print 'SPEAD packet sent.' 57 | 58 | print ''' Issuing timing metadata...''', 59 | sys.stdout.flush() 60 | c.spead_time_meta_issue() 61 | print 'SPEAD packet sent.' 62 | 63 | print ''' Issuing eq metadata...''', 64 | sys.stdout.flush() 65 | c.spead_eq_meta_issue() 66 | print 'SPEAD packet sent.' 67 | 68 | print ''' Issuing input labelling and mapping metadata...''', 69 | sys.stdout.flush() 70 | c.spead_labelling_issue() 71 | print 'SPEAD packet sent.' 72 | 73 | 74 | 75 | except KeyboardInterrupt: 76 | exit_clean() 77 | except: 78 | exit_fail() 79 | exit() 80 | -------------------------------------------------------------------------------- /scripts/corr_check_pcnt.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """ 3 | Check that the pcnt in the f-engines is incrementing correctly. 4 | """ 5 | 6 | import corr, sys, logging, time 7 | 8 | def exit_fail(): 9 | print 'FAILURE DETECTED. Log entries:\n',lh.printMessages() 10 | print "Unexpected error:", sys.exc_info() 11 | try: 12 | c.disconnect_all() 13 | except: pass 14 | exit(1) 15 | 16 | def exit_clean(): 17 | try: 18 | c.disconnect_all() 19 | except: pass 20 | exit(0) 21 | 22 | if __name__ == '__main__': 23 | from optparse import OptionParser 24 | 25 | p = OptionParser() 26 | p.set_usage('%prog [options] [CUSTOM_CONFIG_FILE]') 27 | p.set_description(__doc__) 28 | opts, args = p.parse_args(sys.argv[1:]) 29 | if args == []: 30 | config_file = None 31 | else: 32 | config_file = args[0] 33 | 34 | lh = corr.log_handlers.DebugLogHandler(100) 35 | try: 36 | print 'Connecting...', 37 | c = corr.corr_functions.Correlator(config_file = config_file, log_level = logging.INFO, connect = False, log_handler = lh) 38 | c.connect() 39 | print 'done' 40 | 41 | slist = [64, 32, 16, 8, 4, 2, 1, 0.5, 0.25, 0.125] 42 | wait_time = 1 43 | slist = [1] 44 | 45 | for s in slist: 46 | c.config['pcnt_scale_factor'] = c.config['bandwidth'] / c.config['xeng_acc_len'] * s 47 | 48 | print "s(%f) pcnt_scale(%f) bw(%f) xeng_acc_len(%f)" % (s, c.config['pcnt_scale_factor'], c.config['bandwidth'], c.config['xeng_acc_len']) 49 | 50 | print "Getting current system PCNT...", 51 | pcnta = c.pcnt_current_get() 52 | print pcnta, "." 53 | 54 | print "Waiting %i seconds..." % wait_time, 55 | sys.stdout.flush() 56 | time.sleep(wait_time) 57 | print "done." 58 | 59 | print "Getting current system PCNT...", 60 | pcntb = c.pcnt_current_get() 61 | print pcntb, "." 62 | 63 | print "PCNT: before(%i)\t\tafter_%is(%i)\t\tdiff(%i)" % (pcnta, wait_time, pcntb, pcntb - pcnta) 64 | timea = c.time_from_pcnt(pcnta) 65 | timeb = c.time_from_pcnt(pcntb) 66 | timediff = timeb - timea 67 | print "PCNT to time: before(%.5fs)\tafter_%is(%.5fs)\tdiff(%.5fs)\terror(%.10fms)" % (timea, wait_time, timeb, timediff, (timediff - wait_time) * 1000.) 68 | 69 | except KeyboardInterrupt: 70 | exit_clean() 71 | except: 72 | exit_fail() 73 | -------------------------------------------------------------------------------- /scripts/corr_acc_period.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """Configures the vector accumulators' period on all X engines. 3 | Revs: 4 | 2010-11-13: JRM Pause output before changing acc time. 5 | """ 6 | import corr, time, sys, numpy, os, logging 7 | 8 | def exit_fail(): 9 | print 'FAILURE DETECTED. Log entries:\n',c.log_handler.printMessages() 10 | print "Unexpected error:", sys.exc_info() 11 | try: 12 | c.disconnect_all() 13 | except: pass 14 | if verbose: 15 | raise 16 | exit() 17 | 18 | def exit_clean(): 19 | try: 20 | c.disconnect_all() 21 | except: pass 22 | exit() 23 | 24 | 25 | if __name__ == '__main__': 26 | from optparse import OptionParser 27 | 28 | p = OptionParser() 29 | p.set_usage('%prog CONFIG_FILE') 30 | p.set_description(__doc__) 31 | p.add_option('-t', '--time', dest='acc_time', type='float', default=-1, 32 | help="Specify the how long you'd like to accumulate (in seconds). Default: from config") 33 | p.add_option('-s', '--no_restart', dest='no_restart',action='store_true', default=False, 34 | help='Do not restart output after reconfiguring the VACC.') 35 | p.add_option('-v', '--verbose', dest='verbose',action='store_true', default=False, 36 | help='Be verbose about errors.') 37 | 38 | opts, args = p.parse_args(sys.argv[1:]) 39 | 40 | if args==[]: 41 | config_file=None 42 | else: 43 | config_file=args[0] 44 | verbose=opts.verbose 45 | 46 | try: 47 | print 'Connecting...', 48 | c=corr.corr_functions.Correlator(config_file=config_file,log_level=logging.DEBUG if verbose else logging.INFO,connect=False) 49 | c.connect() 50 | print 'done' 51 | 52 | 53 | if opts.acc_time>0: 54 | acc_time=opts.acc_time 55 | else: 56 | acc_time=c.config['int_time'] 57 | 58 | print ('''Pausing output...'''), 59 | c.tx_stop() 60 | print 'done.' 61 | 62 | print (''' Setting the accumulation period to %2.2f seconds...'''%(acc_time)), 63 | sys.stdout.flush() 64 | c.acc_time_set(acc_time) 65 | print 'done, wrote %i into acc_len (%5.3fs).'%(c.acc_n_get(),c.acc_time_get()) 66 | 67 | 68 | print ('''Restarting output...'''), 69 | if opts.no_restart == False: 70 | c.tx_start() 71 | print 'done.' 72 | else: print 'skipped.' 73 | 74 | except KeyboardInterrupt: 75 | exit_clean() 76 | except: 77 | exit_fail() 78 | exit() 79 | -------------------------------------------------------------------------------- /scripts/corr_clocks.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """ 3 | Script for checking the approximate clock rate of correlator FPGAs. 4 | 5 | Author: Jason Manley\n 6 | Revisions:\n 7 | 2010-07-28 PVP Mods as part of the move to ROACH F-Engines. Get F-engine or X-engine clocks or both.\n 8 | 2009-07-01 JRM Initial revision.\n 9 | """ 10 | import corr, time, sys, numpy, os, logging 11 | 12 | def exit_fail(): 13 | print 'FAILURE DETECTED. Log entries:\n', 14 | c.log_handler.printMessages() 15 | print "Unexpected error:", sys.exc_info() 16 | try: 17 | c.disconnect_all() 18 | except: pass 19 | #raise 20 | exit() 21 | 22 | def exit_clean(): 23 | try: 24 | c.disconnect_all() 25 | except: pass 26 | exit() 27 | 28 | if __name__ == '__main__': 29 | from optparse import OptionParser 30 | 31 | p = OptionParser() 32 | p.set_usage('%prog [options] CONFIG FILE') 33 | p.add_option('-f', '--fengine', dest='fengine', action='store_true', help='Get F-engine clocks.') 34 | p.add_option('-x', '--xengine', dest='xengine', action='store_true', help='Get X-engine clocks.') 35 | p.add_option('-v', '--verbose', dest='verbose', action='store_true', default=False, help='Be verbose about stuff.') 36 | p.set_description(__doc__) 37 | opts, args = p.parse_args(sys.argv[1:]) 38 | 39 | if not (opts.fengine or opts.xengine): 40 | print 'Either -f or -x (or both) must be supplied.' 41 | exit() 42 | 43 | if args==[]: 44 | config_file=None 45 | else: 46 | config_file=args[0] 47 | verbose=opts.verbose 48 | 49 | try: 50 | print 'Connecting...', 51 | c=corr.corr_functions.Correlator(config_file=config_file,log_level=logging.DEBUG if verbose else logging.INFO, connect=False) 52 | c.connect() 53 | print 'done' 54 | 55 | print('\nCalculating all clocks...'), 56 | sys.stdout.flush() 57 | xclks = [] 58 | fclks = [] 59 | if opts.xengine: 60 | xclks = c.xeng_clks_get() 61 | if opts.fengine: 62 | fclks = c.feng_clks_get() 63 | print 'done.' 64 | 65 | if opts.xengine: 66 | for s, server in enumerate(c.xsrvs): 67 | print 'X:' + server + ': %i MHz'%xclks[s] 68 | if opts.fengine: 69 | for s, server in enumerate(c.fsrvs): 70 | print 'F:' + server + ': %i MHz'%fclks[s] 71 | 72 | #lh.printMessages() 73 | 74 | except KeyboardInterrupt: 75 | exit_clean() 76 | except: 77 | exit_fail() 78 | 79 | exit_clean() 80 | 81 | 82 | -------------------------------------------------------------------------------- /scripts/corr_nb_chansel.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """ 3 | Script for selecting the coarse channel to be zoomed for the narrow-band mode. 4 | 5 | Author: Paul Prozesky 6 | """ 7 | """ 8 | Revisions: 9 | 2011-09-02 PVP Initial version. 10 | """ 11 | 12 | import corr, sys, logging 13 | 14 | def exit_fail(): 15 | print 'FAILURE DETECTED. Log entries:\n',lh.printMessages() 16 | print "Unexpected error:", sys.exc_info() 17 | try: 18 | c.disconnect_all() 19 | except: pass 20 | exit(1) 21 | 22 | def exit_clean(): 23 | try: 24 | c.disconnect_all() 25 | except: pass 26 | exit(0) 27 | 28 | if __name__ == '__main__': 29 | from optparse import OptionParser 30 | 31 | p = OptionParser() 32 | p.set_usage('%prog [options] [CUSTOM_CONFIG_FILE]') 33 | p.set_description(__doc__) 34 | #p.add_option('-m', '--mixer', dest = 'mixer_sel', type = 'int', default = -1, 35 | # help = 'Select the unmixed(0) or mixed(1) signal path in the F engine.') 36 | p.add_option('-c', '--channel', dest = 'channel_sel', type = 'int', default = -1, 37 | help = 'Select the coarse channel to be further channelised.') 38 | p.add_option('-f', '--freq', dest = 'freq_hz', type = 'int', default = -1, 39 | help = 'Select a target frequency, in Hz.') 40 | opts, args = p.parse_args(sys.argv[1:]) 41 | if args == []: 42 | config_file = None 43 | else: 44 | config_file = args[0] 45 | 46 | lh = corr.log_handlers.DebugLogHandler(100) 47 | try: 48 | print 'Connecting...', 49 | c = corr.corr_functions.Correlator(config_file = config_file, log_level = logging.INFO, connect = False, log_handler = lh) 50 | if not c.is_narrowband(): 51 | print 'Can only be run on narrowband correlators.' 52 | exit_fail() 53 | c.connect() 54 | print 'done' 55 | 56 | chan_cf, chan, chan_diff = corr.corr_nb.channel_select(c, freq_hz = opts.freq_hz, specific_chan = opts.channel_sel) 57 | 58 | print 'Coarse channel %i chosen, with center frequency %.4fMhz, distance from cf %ihz' % (chan, chan_cf / 1000000.0, chan_diff) 59 | 60 | # print the setup on the fengines 61 | #rv = corr.corr_functions.read_masked_register(c.ffpgas, corr.corr_nb.register_fengine_coarse_control) 62 | # work out the center frequency of the selected band 63 | #c.config['center_freq'] = float(rv[0]['channel_select']) * float(c.config['bandwidth']) 64 | #for ctr, v in enumerate(rv): 65 | # print "%s: channel(%d) cf(%.6f Mhz)" % (c.fsrvs[ctr], v['channel_select'], c.config['center_freq'] / 1000000.0) 66 | 67 | except KeyboardInterrupt: 68 | exit_clean() 69 | except: 70 | exit_fail() 71 | 72 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | CORR 2 | 3 | This package provides functions to control modern CASPER packetised correlators. It also provides a general-purpose wrapper for communicating with ROACH boards over KATCP (src/katcp_wrapper.py). 4 | 5 | Installation: 6 | Do the normal 7 | sudo python setup.py install 8 | 9 | Usage: 10 | 11 | Correlators are configured by writing a configuration file. This is stored in /etc/corr/config as of version 0.6.5. This file should match the bitstreams' configurations (Simulink parameters). Simply change to suite your setup. 12 | 13 | Users can control the entire system by calling the appropriate functions in corr_functions.py. Most common commands also have scripts available. All scripts start with "corr_" which will help users to find the right one for their needs (type corr at the command prompt and most linux distros will list all matching executables in your path). Some have additional options (run with the -h flag to see details). 14 | 15 | Normally users will only need to run corr_init.py to configure everything and start the correlator dumping output. For those not using 10GbE output, you will need to manually start cn_tx_*.py on the ROACH boards. Demonstration receiver scripts are also provided that store data in HDF5 format. Start the appropriate cn_rx*.py script BEFORE initialising the system to capture your data to disk and forward to a katsdisp compatible realtime signal display. If you start the cn_rx script afterwards, you will need to reissue the SPEAD metadata (corr_spead_issue.py) so that the receiver can understand how to unpack the data. The receiver can run on a different computer. 16 | 17 | There are additional scripts for system control and monitoring. For example, ADC input levels can be monitored using corr_adc_ampl.py and histograms plotted using corr_adc_hist.py. Accumulation periods can be configured using corr_acc_period.py and quantisation (equaliser) control with corr_eq_init.py. 18 | 19 | For debugging purposes, the corr_snap_* scripts allow the user to see snapshots of signalflow through the system. Most of these scripts will decode the datastream to the terminal but some are capable of plotting spectrums etc. 20 | 21 | Requires: 22 | - iniparse, numpy, matplotlib (if plotting outputs), katcp, PySPEAD, construct 23 | 24 | Recommended: 25 | - katsdisp, the standalone KAT signal display package for visualising output. 26 | 27 | ToDo: 28 | - Support for parallel connections to ROACH boards. Right now, commands issued to multiple boards are processed sequentially. It should be possible to gain speedups by issuing such commands in parallel. 29 | - Create an error-handling class so that all scripts use the same thing. As it stands, all scripts re-write the same functions repeatedly. 30 | - fix integer rounding in corr_rx and in katsdip 31 | 32 | -------------------------------------------------------------------------------- /scripts/corr_rx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | Capture utility for a relatively generic packetised correlator data output stream. 6 | 7 | The script performs two primary roles: 8 | 9 | Storage of stream data on disk in hdf5 format. This includes placing meta data into the file as attributes. 10 | 11 | Regeneration of a SPEAD stream suitable for us in the online signal displays. At the moment this is basically 12 | just an aggregate of the incoming streams from the multiple x engines scaled with n_accumulations (if set) 13 | 14 | Author: Simon Ratcliffe 15 | Revs: 16 | 2010-11-26 JRM Added command-line option for autoscaling. 17 | """ 18 | 19 | import numpy as np 20 | import spead64_48 as spead 21 | import logging 22 | import sys 23 | import time 24 | import h5py 25 | import corr 26 | 27 | logging.basicConfig(level=logging.WARN) 28 | acc_scale = True 29 | 30 | if __name__ == '__main__': 31 | from optparse import OptionParser 32 | p = OptionParser() 33 | p.set_usage('%prog [options] [CUSTOM_CONFIG_FILE]') 34 | p.set_description(__doc__) 35 | p.add_option( 36 | '-a', 37 | '--disable_autoscale', 38 | dest='acc_scale', 39 | action='store_false', 40 | default=True, 41 | help='Do not autoscale the data by dividing down by the number of accumulations. Default: Scale back by n_accs.' 42 | , 43 | ) 44 | p.add_option( 45 | '-v', 46 | '--verbose', 47 | dest='verbose', 48 | action='store_true', 49 | default=False, 50 | help='Be verbose about errors.', 51 | ) 52 | (opts, args) = p.parse_args(sys.argv[1:]) 53 | 54 | if args == []: 55 | config_file = None 56 | else: 57 | config_file = args[0] 58 | acc_scale = opts.acc_scale 59 | verbose = opts.verbose 60 | 61 | print 'Parsing config file...', 62 | sys.stdout.flush() 63 | c = corr.corr_functions.Correlator(config_file=config_file, 64 | log_level=(logging.DEBUG if verbose else logging.WARN), 65 | connect=False) 66 | config = c.config 67 | print 'done.' 68 | 69 | data_port = config['rx_udp_port'] 70 | sd_ip = config['sig_disp_ip_str'] 71 | sd_port = config['sig_disp_port'] 72 | mode = config['xeng_format'] 73 | 74 | filename = str(time.time()) + '.corr.h5' 75 | 76 | print 'Initalising SPEAD transports for %s data...' % mode 77 | print 'Data reception on port', data_port 78 | print 'Sending Signal Display data to %s:%i.' % (sd_ip, sd_port) 79 | print 'Storing to file %s' % filename 80 | 81 | crx = corr.rx.CorrRx( 82 | mode=mode, 83 | data_port=data_port, 84 | sd_ip=sd_ip, 85 | sd_port=sd_port, 86 | acc_scale=acc_scale, 87 | filename=filename, 88 | log_level=(logging.DEBUG if verbose else logging.INFO), 89 | ) 90 | try: 91 | crx.daemon = True 92 | crx.start() 93 | while crx.isAlive(): 94 | time.sleep(0.1) 95 | print 'RX process ended.' 96 | crx.join() 97 | except KeyboardInterrupt: 98 | print 'Stopping...' 99 | -------------------------------------------------------------------------------- /scripts/sfp_card_info.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | #'192.168.14.89' 4 | #'192.168.64.229' 5 | 6 | import argparse, corr, sfp_mdio, time, sys 7 | 8 | parser = argparse.ArgumentParser(description='Print information about the SFP+ mezzanine cards plugged into a ROACH2.') 9 | parser.add_argument('host', type=str, action='store', nargs=1, help='the hostname or IP for the ROACH2 you wish to query') 10 | args = parser.parse_args() 11 | 12 | fpga = corr.katcp_wrapper.FpgaClient(args.host[0]) 13 | time.sleep(1) 14 | if not fpga.is_connected(): 15 | raise RuntimeError('FPGA not connected?') 16 | 17 | sfp_cards = [] 18 | for c in range(2): 19 | card = sfp_mdio.Sfp_mezzanine_card(fpga, c) 20 | card.initialise() 21 | sfp_cards.append(card) 22 | 23 | for card in sfp_cards: 24 | print 'Mezzanine card', card.slot, ':' 25 | for phy in card.phys: 26 | phy.reset() 27 | phy.check_connection() 28 | temperature = phy.read_temperature() 29 | modules = [] 30 | for m in phy.modules: 31 | vendor_name = m.read_vendor_name() 32 | serial_number = m.read_serial_number() 33 | modules.append({'vendor': vendor_name, 'serial': serial_number}) 34 | print '\tPhy %i:\n\t\ttemperature(%.3fC)' % (phy.id, temperature, ) 35 | for ctr, module in enumerate(modules): 36 | print '\t\tModule %i: vendor(%s) - s/n(%s)' % (ctr, module['vendor'], module['serial'], ) 37 | 38 | print '\tFEC summary:' 39 | for phy in card.phys: 40 | fec_capabilities = phy.fec_enable_check() 41 | fec_counts = phy.fec_read_counts(fec_capabilities = fec_capabilities) 42 | for m in phy.modules: 43 | print '\t\tPhy(%i) channel(%i): supported(%i) error_reporting(%i) locked(%i), error counters: corrected(%i) uncorrected(%i)' % (phy.id, m.id, 44 | fec_capabilities[m.id]['supported'], 45 | fec_capabilities[m.id]['error_reporting'], 46 | fec_capabilities[m.id]['locked'], 47 | fec_counts[m.id]['corrected'], 48 | fec_counts[m.id]['uncorrected'],) 49 | 50 | print '\tLink status:' 51 | for phy in card.phys: 52 | for m in phy.modules: 53 | link_status = phy.read_link_status(m.id) 54 | print "\t\tPhy(%i) channel(%i): TX_up(%i) RX_up(%i)" % (phy.id, m.id, link_status['tx'], link_status['rx']) 55 | 56 | print '\tI2C information:' 57 | for phy in card.phys: 58 | for m in phy.modules: 59 | print '\t\tPhy(%i) channel(%i):' % (phy.id, m.id), 60 | print m.read_temp()[1], 61 | print m.read_voltage()[1], 62 | print m.read_tx_bias_current()[1], 63 | print m.read_tx_power()[1], 64 | print m.read_rx_power()[1], 65 | print m.read_stat()[1] 66 | 67 | print '\tMore:' 68 | for phy in card.phys: 69 | for m in phy.modules: 70 | m.print_module_regs(0x50) 71 | m.print_module_regs(0x51) 72 | print '\n' 73 | -------------------------------------------------------------------------------- /src/threaded.py: -------------------------------------------------------------------------------- 1 | import katcp_wrapper 2 | 3 | def fpga_operation(fpga_list, num_threads = -1, job_function = None, *job_args): 4 | """Run a provided method on a list of FpgaClient objects in a specified number of threads. 5 | 6 | @param fpga_list: list of FpgaClient objects 7 | @param num_threads: how many threads should be used. Default is one per list item 8 | @param job_function: the function to be run - MUST take the FpgaClient object as its first argument 9 | @param *args: further arugments for the job_function 10 | 11 | @return a dictionary of results from the functions, keyed on FpgaClient.host 12 | 13 | """ 14 | 15 | """ 16 | Example: 17 | def xread_all_new(self, register, bram_size, offset = 0): 18 | import threaded 19 | def xread_all_thread(host): 20 | return host.read(register, bram_size, offset) 21 | vals = threaded.fpga_operation(self.xfpgas, num_threads = -1, job_function = xread_all_thread) 22 | rv = [] 23 | for x in self.xfpgas: rv.append(vals[x.host]) 24 | return rv 25 | """ 26 | 27 | if job_function == None: 28 | raise RuntimeError("job_function == None?") 29 | import threading, Queue 30 | # thread class to perform a job from a queue 31 | class Corr_worker(threading.Thread): 32 | def __init__(self, request_queue, result_queue, job_function, *job_args): 33 | self.request_queue = request_queue 34 | self.result_queue = result_queue 35 | self.job = job_function 36 | self.job_args = job_args 37 | threading.Thread.__init__(self) 38 | def run(self): 39 | done = False 40 | while not done: 41 | try: 42 | # get a job from the queue 43 | request_host = self.request_queue.get(False) 44 | # do some work 45 | try: 46 | result = self.job(request_host, *self.job_args) 47 | except Exception as exc: 48 | errstr = "Job %s internal error: %s, %s" % (self.job.func_name, type(exc), exc) 49 | result = RuntimeError(errstr) 50 | # put the result on the result queue 51 | self.result_queue.put((request_host.host, result)) 52 | # and notify done 53 | self.request_queue.task_done() 54 | except: 55 | done = True 56 | if not isinstance(fpga_list, list): 57 | raise TypeError("fpga_list should be a list() of FpgaClient objects only.") 58 | if num_threads == -1: 59 | num_threads = len(fpga_list) 60 | # create the request and result queues 61 | request_queue = Queue.Queue() 62 | result_queue = Queue.Queue() 63 | # put the list items into a Thread-safe Queue 64 | for f in fpga_list: 65 | if not isinstance(f, katcp_wrapper.FpgaClient): 66 | raise TypeError('Currently this function only supports FpgaClient objects.') 67 | request_queue.put(f) 68 | # make as many worker threads a specified and start them off 69 | workers = [Corr_worker(request_queue, result_queue, job_function, *job_args) for i in range(0, num_threads)] 70 | for w in workers: 71 | w.daemon = True 72 | w.start() 73 | # join the last one to wait for completion 74 | request_queue.join() 75 | # format the result into a dictionary by host 76 | rv = {} 77 | while not result_queue.empty(): 78 | res = result_queue.get() 79 | rv[res[0]] = res[1] 80 | return rv 81 | 82 | -------------------------------------------------------------------------------- /scripts/corr_fr_del_set.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """Configures CASPER correlator Fengine's Fringe rotate and delay compensation cores. 3 | Author: Jason Manley 4 | Revs: 5 | 2010-11-20 JRM First release """ 6 | import corr, numpy,sys,os,time,logging 7 | 8 | def exit_fail(): 9 | print 'FAILURE DETECTED. Log entries:\n', 10 | c.log_handler.printMessages() 11 | print "Unexpected error:", sys.exc_info() 12 | try: 13 | c.disconnect_all() 14 | except: pass 15 | #raise 16 | exit() 17 | 18 | def exit_clean(): 19 | try: 20 | c.disconnect_all() 21 | except: pass 22 | exit() 23 | 24 | 25 | if __name__ == '__main__': 26 | from optparse import OptionParser 27 | 28 | p = OptionParser() 29 | p.set_usage('%prog [options] CONFIG_FILE') 30 | p.set_description(__doc__) 31 | p.add_option('-a', '--ant', dest = 'ant_str', action = 'store', 32 | help = 'Specify the antenna and pol. For example, 3x will give pol x for antenna three.') 33 | p.add_option('-f', '--fringe_rate', dest='fringe_rate', type='float', default=0, 34 | help='''Set the fringe rate in cycles per second (Hz). Defaults to zero.''') 35 | p.add_option('-o', '--fringe_offset', dest='fringe_offset', type='float', default=0, 36 | help='''Set the fringe offset in degrees. Defaults to zero''') 37 | p.add_option('-d', '--delay', dest='delay', type='float', default=0, 38 | help='''Set the delay in seconds. Defaults to zero.''') 39 | p.add_option('-r', '--delay_rate', dest='delay_rate', type='float', default=0, 40 | help='''Set the delay rate. Unitless; eg. seconds per second. Defaults to zero.''') 41 | p.add_option('-t', '--ld_time', dest='ld_time', type='float', default=-1, 42 | help='''Load time in seconds since the unix epoch. NOTE: SYSTEM TIME MUST BE ACCURATE! If not specified, load ASAP.''') 43 | p.add_option('-v', '--verbose', dest = 'verbose', action = 'store_true', 44 | help = 'Be verbose about errors.') 45 | 46 | opts, args = p.parse_args(sys.argv[1:]) 47 | 48 | if args==[]: 49 | config_file=None 50 | else: 51 | config_file=args[0] 52 | verbose=opts.verbose 53 | 54 | try: 55 | print 'Connecting...', 56 | c=corr.corr_functions.Correlator(config_file=config_file,log_level=logging.DEBUG if verbose else logging.INFO, connect=False) 57 | c.connect() 58 | print 'done' 59 | 60 | ant_str=opts.ant_str 61 | if not ant_str in c.config._get_ant_mapping_list(): 62 | raise RuntimeError("Bad input specified.") 63 | 64 | if opts.ld_time <0: trig_time = time.time()+0.1 65 | else: trig_time = opts.ld_time 66 | 67 | print "Setting input %s's delay to %es + %es/s with a fringe of %e + %eHz at %s local (%s UTC).... "%( 68 | ant_str,opts.delay,opts.delay_rate,opts.fringe_offset,opts.fringe_rate, 69 | time.strftime('%H:%M:%S',time.localtime(trig_time)),time.strftime('%H:%M:%S',time.gmtime(trig_time))), 70 | act=c.fr_delay_set(ant_str=ant_str, 71 | delay=opts.delay, 72 | delay_rate=opts.delay_rate, 73 | fringe_phase=opts.fringe_offset, 74 | fringe_rate=opts.fringe_rate) 75 | print 'ok.' 76 | 77 | print 'Closest we could get: ' 78 | print '===================== ' 79 | print 'Actual fringe offset: %15.10e'%act['act_fringe_offset'] 80 | print 'Actual fringe rate: %15.10e'%act['act_fringe_rate'] 81 | print 'Actual delay: %15.10e'%act['act_delay'] 82 | print 'Actual delay rate: %15.10e'%act['act_delay_rate'] 83 | 84 | except KeyboardInterrupt: 85 | exit_clean() 86 | except: 87 | exit_fail() 88 | 89 | exit_clean() 90 | 91 | -------------------------------------------------------------------------------- /scripts/corr_tx_start_stop.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """ 3 | Starts UDP packet output on the X engine. Does not do any configuration of the output cores. 4 | 5 | Author: Jason Manley\n 6 | Revisions:\n 7 | 2010-07-29 PVP Cleanup as part of the move to ROACH F-Engines.\n 8 | 2009------ JRM Initial revision.\n 9 | """ 10 | import corr, time, sys, numpy, os, logging 11 | 12 | def exit_fail(): 13 | #print 'FAILURE DETECTED. Log entries:\n',c.log_handler.printMessages() 14 | #print "Unexpected error:", sys.exc_info() 15 | #try: 16 | # c.disconnect_all() 17 | #except: pass 18 | if verbose: 19 | raise 20 | exit() 21 | 22 | def exit_clean(): 23 | #try: 24 | # c.disconnect_all() 25 | #except: pass 26 | exit() 27 | 28 | 29 | if __name__ == '__main__': 30 | from optparse import OptionParser 31 | 32 | p = OptionParser() 33 | p.set_usage('%prog [options] CONFIG_FILE') 34 | p.add_option('', '--start', dest='txStart', action='store_true', help='Start UDP packet transmission from the X-engines.') 35 | p.add_option('', '--stop', dest='txStop', action='store_true', help='Stop UDP packet transmission from the X-engines.') 36 | p.add_option('-v', '--verbose', dest='verbose',action='store_true', default=False, help='Be verbose about stuff.') 37 | p.set_description(__doc__) 38 | opts, args = p.parse_args(sys.argv[1:]) 39 | 40 | if (opts.txStart and opts.txStop): 41 | print 'Epic fail! --stop or --start, not both.' 42 | exit() 43 | 44 | if not (opts.txStart or opts.txStop): 45 | print 'Epic fail! --stop or --start.' 46 | exit() 47 | 48 | if args==[]: 49 | config_file=None 50 | else: 51 | config_file=args[0] 52 | verbose=opts.verbose 53 | 54 | 55 | try: 56 | print 'Connecting...', 57 | c=corr.corr_functions.Correlator(config_file=config_file,log_level=(logging.DEBUG if verbose else logging.INFO),connect=False) 58 | c.connect() 59 | print 'done' 60 | 61 | print "Current settings:" 62 | regValues = c.xeng_ctrl_get_all() 63 | for fn,value in enumerate(regValues): 64 | print "\t" + c.xsrvs[fn] + ": tx " + ("enabled" if value['gbe_out_enable'] else "disabled") 65 | 66 | if opts.txStart: 67 | print "Sending meta data to %s:%i."%(c.config['rx_meta_ip_str'],c.config['rx_udp_port']) 68 | 69 | print ''' Issuing data descriptors...''', 70 | sys.stdout.flush() 71 | c.spead_data_descriptor_issue() 72 | print 'SPEAD packet sent.' 73 | 74 | print ''' Issuing static metadata...''', 75 | sys.stdout.flush() 76 | c.spead_static_meta_issue() 77 | print 'SPEAD packet sent.' 78 | 79 | print ''' Issuing timing metadata...''', 80 | sys.stdout.flush() 81 | c.spead_time_meta_issue() 82 | print 'SPEAD packet sent.' 83 | 84 | print ''' Issuing eq metadata...''', 85 | sys.stdout.flush() 86 | c.spead_eq_meta_issue() 87 | print 'SPEAD packet sent.' 88 | 89 | print 'Starting TX...', 90 | sys.stdout.flush() 91 | c.enable_udp_output() 92 | print 'done.' 93 | 94 | if opts.txStop: 95 | print 'Stopping TX...', 96 | sys.stdout.flush() 97 | c.disable_udp_output() 98 | print 'done.' 99 | 100 | print "Now:" 101 | regValues = c.xeng_ctrl_get_all() 102 | for fn,value in enumerate(regValues): 103 | print "\t" + c.xsrvs[fn] + ": tx " + ("enabled" if value['gbe_out_enable'] else "disabled") 104 | 105 | except KeyboardInterrupt: 106 | exit_clean() 107 | except: 108 | exit_fail() 109 | exit() 110 | -------------------------------------------------------------------------------- /scripts/corr_tvg_feng_sel.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """Selects TVGs thoughout the correlator.\n 3 | """ 4 | import corr, time, sys, numpy, os, logging 5 | 6 | def exit_fail(): 7 | print 'FAILURE DETECTED. Log entries:\n',c.log_handler.printMessages() 8 | print "Unexpected error:", sys.exc_info() 9 | try: 10 | c.disconnect_all() 11 | except: pass 12 | if verbose: 13 | raise 14 | exit() 15 | 16 | def exit_clean(): 17 | try: 18 | c.disconnect_all() 19 | except: pass 20 | exit() 21 | 22 | if __name__ == '__main__': 23 | from optparse import OptionParser 24 | 25 | p = OptionParser() 26 | p.set_usage(__file__ + ' [options] CONFIG_FILE') 27 | p.set_description(__doc__) 28 | # the list of tvgs below 29 | # F-engine 30 | p.add_option('-e', '--enable_tvg', dest = 'tvg_enable', action = 'store', default = -1, help = 'Global enable the TVGs.') 31 | p.add_option('-f', '--fd_fs', dest = 'tvg_fdfs', action = 'store', default = -1, help = 'FD, FS TVG.') 32 | p.add_option('-p', '--packetiser', dest = 'tvg_packetiser',action = 'store', default = -1, help = 'Packetiser TVG.') 33 | p.add_option('-c', '--pre_ct', dest = 'tvg_ct', action = 'store', default = -1, help = 'Pre-CT TVG. Generates a counter so the data for both pols combined forms a 16-bit counter representing the freq channel number.') 34 | p.add_option('-v', '--verbose', dest='verbose',action='store_true', default=False, 35 | help='Be verbose about errors.') 36 | 37 | # X-engine 38 | #p.add_option('-', '--', dest = 'tvg_', action = 'store', default = 0, help = '') 39 | opts, args = p.parse_args(sys.argv[1:]) 40 | 41 | if args==[]: 42 | config_file=None 43 | else: 44 | config_file=args[0] 45 | verbose=opts.verbose 46 | 47 | try: 48 | raise RuntimeError('This script is farked. Don''t use it.') 49 | 50 | print 'Connecting...', 51 | c=corr.corr_functions.Correlator(config_file=config_file,log_level=logging.DEBUG if verbose else logging.INFO,connect=False) 52 | c.connect() 53 | print 'done' 54 | 55 | print 'F-engine TVGs:' 56 | kwargs = {} 57 | 58 | if opts.tvg_enable == 1: 59 | print "\tGlobal TVG enable ON" 60 | kwargs["tvg_en"] = True 61 | elif opts.tvg_enable == 0: 62 | print "\tGlobal TVG enable OFF" 63 | kwargs["tvg_en"] = False 64 | 65 | if opts.tvg_fdfs == 1: 66 | print "\tEnabling FD,FS TVG" 67 | kwargs["tvgsel_fdfs"] = True 68 | elif opts.tvg_fdfs == 0: 69 | print "\tDisabling FD,FS TVG" 70 | kwargs["tvgsel_fdfs"] = False 71 | 72 | if opts.tvg_packetiser == 1: 73 | print "\tEnabling packetiser TVG" 74 | kwargs["tvg_pkt_sel"] = True 75 | elif opts.tvg_packetiser == 0: 76 | print "\tDisabling packetiser TVG" 77 | kwargs["tvg_pkt_sel"] = False 78 | 79 | if opts.tvg_ct == 1: 80 | print "\tEnabling CT TVG" 81 | kwargs["tvg_ct_sel"] = True 82 | elif opts.tvg_ct == 0: 83 | print "\tDisabling CT TVG" 84 | kwargs["tvg_ct_sel"] = False 85 | 86 | c.feng_ctrl_set_all(**kwargs) 87 | 88 | print "Done." 89 | 90 | #print '\nX engine TVGs:' 91 | #if opts.xeng: 92 | # print('\tEnabling Xeng TVG...'), 93 | # c.tvg_xeng_sel(mode=1) 94 | # print 'done Xengine TVG.' 95 | #elif opts.vacc: 96 | # print('\tEnabling VACC TVG...') 97 | # print 'done VACC TVG.' 98 | #print 'done all X engine TVGs.' 99 | 100 | except KeyboardInterrupt: 101 | exit_clean() 102 | except: 103 | exit_fail() 104 | 105 | exit_clean() 106 | 107 | # end 108 | 109 | -------------------------------------------------------------------------------- /scripts/corr_10gbe_core_details.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | # pylint: disable-msg = C0301 5 | # pylint: disable-msg = C0103 6 | 7 | ''' 8 | Prints the details of the 10GbE cores on all the X engines. 9 | Assumes the correlator is already initialsed and running etc. 10 | Revisions 11 | 2010 - 07 - 23 JRM Mods to use corr - 0.5.0 12 | 2009 - 12 - 01 JRM uses katcp_wrapper function now. 13 | 2009 / 11 / 12 JRM after discussion with Dave. 14 | ''' 15 | 16 | import corr 17 | import sys 18 | import logging 19 | 20 | 21 | def exit_fail(): 22 | print 'FAILURE DETECTED. Log entries:\n', \ 23 | c.log_handler.printMessages() 24 | print 'Unexpected error:', sys.exc_info() 25 | try: 26 | c.disconnect_all() 27 | except: 28 | pass 29 | exit() 30 | 31 | 32 | def exit_clean(): 33 | try: 34 | c.disconnect_all() 35 | except: 36 | pass 37 | exit() 38 | 39 | 40 | if __name__ == '__main__': 41 | from optparse import OptionParser 42 | 43 | p = OptionParser() 44 | p.set_usage('%prog [options] CONFIG_FILE') 45 | p.set_description(__doc__) 46 | p.add_option(' - v', ' -- verbose', dest='verbose', 47 | action='store_true', 48 | help='Be Verbose; print raw packet contents of CPU contents.' 49 | ) 50 | p.add_option(' - a', ' -- arp', dest='arp', action='store_true', 51 | help='Print the ARP table.') 52 | 53 | (opts, args) = p.parse_args(sys.argv[1:]) 54 | gbe_device = 'gbe' 55 | 56 | if args == []: 57 | config_file = None 58 | else: 59 | config_file = args[0] 60 | verbose = opts.verbose 61 | 62 | try: 63 | print 'Connecting...', 64 | c = corr.corr_functions.Correlator(config_file=config_file, 65 | log_level=(logging.DEBUG if verbose else logging.INFO), 66 | connect=False) 67 | c.connect() 68 | print 'done' 69 | 70 | # assemble struct for header stuff... 71 | # 0x00 - 0x07: My MAC address 72 | # 0x08 - 0x0b: Not used 73 | # 0x0c - 0x0f: Gateway addr 74 | # 0x10 - 0x13: my IP addr 75 | # 0x14 - 0x17: Not assigned 76 | # 0x18 - 0x1b: Buffer sizes 77 | # 0x1c - 0x1f: Not assigned 78 | # 0x20 : soft reset (bit 0) 79 | # 0x21 : fabric enable (bit 0) 80 | # 0x22 - 0x23: fabric port 81 | 82 | # 0x24 - 0x27: XAUI status (bit 2, 3, 4, 5 = lane sync, bit6 = chan_bond) 83 | # 0x28 - 0x2b: PHY config 84 | # 0x28 : RX_eq_mix 85 | # 0x29 : RX_eq_pol 86 | # 0x2a : TX_preemph 87 | # 0x2b : TX_diff_ctrl 88 | 89 | # 0x1000 : CPU TX buffer 90 | # 0x2000 : CPU RX buffer 91 | # 0x3000 : ARP tables start 92 | 93 | if c.config['feng_out_type'] == '10gbe': 94 | for (f, fpga) in enumerate(c.ffpgas): 95 | print ''' 96 | 97 | == == == == == == == == == == == == == == == == ''' 98 | for core in range(c.config['n_xaui_ports_per_ffpga']): 99 | device = '%s%i' % (gbe_device, core) 100 | print 'F engine', c.fsrvs[f], 'port', core 101 | fpga.print_10gbe_core_details(device, arp=opts.arp, 102 | cpu=opts.verbose) 103 | print ' == == == == == == == == == == == == == == == == ' 104 | 105 | for (f, fpga) in enumerate(c.xfpgas): 106 | print ''' 107 | 108 | == == == == == == == == == == == == == == == == ''' 109 | for core in range(c.config['n_xaui_ports_per_xfpga']): 110 | device = '%s%i' % (gbe_device, core) 111 | print 'X engine', c.xsrvs[f], 'port', core 112 | fpga.print_10gbe_core_details(device, arp=opts.arp, 113 | cpu=opts.verbose) 114 | print ' == == == == == == == == == == == == == == == == ' 115 | except KeyboardInterrupt: 116 | 117 | exit_clean() 118 | except: 119 | exit_fail() 120 | 121 | exit_clean() 122 | 123 | -------------------------------------------------------------------------------- /scripts/corr_eq_init.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """Configures CASPER correlator Fengine's equalisers. 3 | Author: Jason Manley 4 | Revs: 5 | 2010-07-29 JRM Port to corr-0.5.0 """ 6 | import corr, numpy, sys, os, time, logging 7 | 8 | def re_equalize(self, thresh=.1, maxval=2**17-1, max_tries=10): 9 | """Automatically adjust equalization for maximum flatness around 4b pwr of 10.""" 10 | print 'Equalizing' 11 | for i in range(max_tries): 12 | d = 0 13 | for bl in autos: d += read_acc(bl) 14 | d /= len(autos) 15 | neweq = numpy.sqrt(numpy.where(d > 0, 10/d, maxval)) 16 | neweq *= equalization 17 | neweq = numpy.clip(neweq, 0, maxval) 18 | p = remove_spikes(numpy.log10(neweq+1e-5), return_poly=True) 19 | neweq = abs(10**numpy.polyval(p, numpy.arange(d.size))) 20 | neweq = numpy.clip(neweq, 0, maxval) 21 | fit = math.sqrt(numpy.average((1 - (neweq/equalization))**2)) 22 | print ' Percent gain change:', fit, '(thresh=%f)\n' % thresh 23 | if fit < thresh: break 24 | equalization = numpy.round(neweq) 25 | _apply_eq(active_chans, equalization) 26 | curr_acc = self['acc_num'] 27 | print ' Waiting for accumulation...' 28 | while self['acc_num'] <= curr_acc + 1: time.sleep(.01) 29 | 30 | def exit_fail(): 31 | print 'FAILURE DETECTED. Log entries:\n', 32 | c.log_handler.printMessages() 33 | print "Unexpected error:", sys.exc_info() 34 | try: 35 | c.disconnect_all() 36 | except: pass 37 | if verbose: 38 | raise 39 | exit() 40 | 41 | def exit_clean(): 42 | try: 43 | c.disconnect_all() 44 | except: pass 45 | exit() 46 | 47 | 48 | if __name__ == '__main__': 49 | from optparse import OptionParser 50 | 51 | p = OptionParser() 52 | p.set_usage('%prog [options] CONFIG_FILE') 53 | p.set_description(__doc__) 54 | p.add_option('-i', '--init_eq', dest='init_eq', type='int', default=-1, 55 | help='''Initialise all F engine equaliser channels to specified value. Default: use config file''') 56 | p.add_option('-v', '--verbose', dest='verbose', action='store_true', default=False, 57 | help='''Be verbose about errors.''') 58 | 59 | opts, args = p.parse_args(sys.argv[1:]) 60 | 61 | if args==[]: 62 | config_file=None 63 | else: 64 | config_file=args[0] 65 | verbose=opts.verbose 66 | 67 | try: 68 | print 'Connecting...', 69 | c=corr.corr_functions.Correlator(config_file=config_file,log_level=logging.DEBUG if verbose else logging.INFO, connect=False) 70 | c.connect() 71 | print 'done' 72 | 73 | servers = c.fsrvs 74 | fpgas = c.ffpgas 75 | n_ants_per_xaui = c.config['n_ants_per_xaui'] 76 | n_xaui_ports_per_fpga = c.config['n_xaui_ports_per_ffpga'] 77 | n_ants = c.config['n_ants'] 78 | n_chans = c.config['n_chans'] 79 | #auto_eq = c.config['auto_eq'] 80 | 81 | if (opts.init_eq >= 0): 82 | print '''Resetting all F engines' %i channels' gains to %i...''' % (n_chans, opts.init_eq), 83 | sys.stdout.flush() 84 | c.eq_set_all(init_poly = [opts.init_eq]) 85 | print 'Done.' 86 | else: 87 | print '''Configuring channels' gains to default values as listed in config file...''', 88 | sys.stdout.flush() 89 | c.eq_set_all() 90 | print 'Done.' 91 | 92 | #elif (not auto_eq) or opts.eq_poly: 93 | # print '''Configuring channels' gains to default values as listed in config file...''', 94 | # sys.stdout.flush() 95 | # c.ibob_eq_init(verbose_level=verbose_level) 96 | # print 'Done.' 97 | 98 | #else: 99 | #print 'Auto-equalising...' 100 | #print 'Not yet implemented!\n' 101 | #print '''Resetting all ibobs' %i channels' gains to %i...'''%(config['n_chans'],opts.auto_eq), 102 | # Calculate gain in IBOB to extrapolate back to 4b values 103 | #auto_gain = float(opts.acc_len * (opts.clk_per_sync / n_chan)) 104 | #cross_gain = auto_gain / (2**(4+4*cross_shift)) 105 | # Set a default equalization 106 | #equalization = numpy.polyval(opts.eq_poly, range(0,opts.n_chan)) 107 | #apply_eq(range(0,opts.n_chan), equalization) 108 | 109 | except KeyboardInterrupt: 110 | exit_clean() 111 | except: 112 | exit_fail() 113 | 114 | exit_clean() 115 | 116 | -------------------------------------------------------------------------------- /scripts/corr_snap_xeng.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Grabs the contents of "snap_xeng0" (one per FPGA) at the output of the X eng and prints any non-zero values. 4 | Assumes the correlator is already initialsed and running etc. 5 | 6 | NOTE: Only good for 4 bit X engines with demux of 8 and accumulation length of 128. 7 | 8 | Author: Jason Manley\n 9 | Revisions:\n 10 | 2010-08-05: JRM Mods to support corr-0.5.0 11 | 2010-07-29: PVP Cleanup as part of the move to ROACH F-Engines. Testing still needed.\n 12 | 2009------: JRM Initial revision.\n 13 | ''' 14 | import corr, time, numpy, pylab, struct, sys, logging 15 | 16 | dev_name = 'snap_xeng0' 17 | 18 | report=[] 19 | 20 | def exit_fail(): 21 | print 'FAILURE DETECTED. Log entries:\n', 22 | c.log_handler.printMessages() 23 | print "Unexpected error:", sys.exc_info() 24 | try: 25 | c.disconnect_all() 26 | except: pass 27 | raise 28 | exit() 29 | 30 | def exit_clean(): 31 | try: 32 | c.disconnect_all() 33 | except: pass 34 | exit() 35 | 36 | if __name__ == '__main__': 37 | from optparse import OptionParser 38 | 39 | p = OptionParser() 40 | p.set_usage('%prog [options] CONFIG_FILE') 41 | p.add_option('-v', '--verbose', dest='verbose', action='store_true', help='Print all the decoded (including zero valued) results (be verbose).') 42 | p.add_option('-o', '--ch_offset', dest='ch_offset', type='int', default=0, help='Start capturing at specified channel number. Default is 0.') 43 | p.set_description(__doc__) 44 | opts, args = p.parse_args(sys.argv[1:]) 45 | 46 | if args==[]: 47 | config_file=None 48 | else: 49 | config_file=args[0] 50 | verbose=opts.verbose 51 | 52 | try: 53 | print 'Connecting...', 54 | c=corr.corr_functions.Correlator(config_file=config_file,log_level=logging.DEBUG if verbose else logging.INFO,connect=False) 55 | c.connect() 56 | print 'done' 57 | 58 | binary_point = c.config['feng_fix_pnt_pos'] 59 | packet_len=c.config['10gbe_pkt_len'] 60 | n_chans=c.config['n_chans'] 61 | n_chans_per_x=c.config['n_chans_per_x'] 62 | num_bits = c.config['feng_bits'] 63 | adc_bits = c.config['adc_bits'] 64 | adc_levels_acc_len = c.config['adc_levels_acc_len'] 65 | x_per_fpga = c.config['x_per_fpga'] 66 | n_ants = c.config['n_ants'] 67 | xeng_acc_len = c.config['xeng_acc_len'] 68 | n_bls = c.config['n_bls'] 69 | 70 | report = dict() 71 | ch_offset = opts.ch_offset 72 | 73 | if num_bits !=4: 74 | print 'ERR: this script is only written to interpret 4 bit data. Your F engine outputs %i bits.'%num_bits 75 | exit_fail() 76 | if xeng_acc_len !=128: 77 | print 'ERR: this script is only written to interpret data from X engines with acc length of 128 due to hardcoded bitwidth growth limitations. Your X engine accumulates for %i samples.'%xeng_acc_len 78 | exit_fail() 79 | 80 | if c.config['xeng_format'] == 'inter': 81 | offset = ch_offset * n_bls * 2 #hardcoded for demux of 8 82 | else: 83 | offset = (ch_offset)%(n_chans_per_x) * n_bls * 2 #hardcoded for demux of 8 84 | 85 | print '------------------------' 86 | print 'Triggering capture at word offset %i...' % offset, 87 | sys.stdout.flush() 88 | bram_dmp = corr.snap.snapshots_get(c.xfpgas,dev_name, man_trig = False, wait_period = 2, offset = offset) 89 | print 'done.' 90 | 91 | print 'Unpacking bram contents...' 92 | #hardcode unpack of 16 bit values. Assumes bitgrowth of log2(128)=7 bits and input of 4_3 * 4_3. 93 | sys.stdout.flush() 94 | bram_data = [] 95 | for f, fpga in enumerate(c.xfpgas): 96 | unpack_length = bram_dmp['lengths'][f] 97 | print " Unpacking %i values from %s." % (unpack_length, c.xsrvs[f]) 98 | if unpack_length > 0: 99 | bram_data.append(struct.unpack('>%ii' % (unpack_length / 4), bram_dmp['data'][f])) 100 | else: 101 | print " Got no data back for %s." % c.xsrvs[f] 102 | bram_data.append([]) 103 | print 'Done.' 104 | print '========================\n' 105 | 106 | for xeng, fpga in enumerate(c.xfpgas): 107 | print '--------------------' 108 | print '\nX-engine %i'%(xeng) 109 | print '--------------------' 110 | for li in range(len(bram_data[xeng]) / 2): 111 | #index over complex numbers in bram 112 | index = li + bram_dmp['offsets'][xeng] / 2 113 | bls_index = index % n_bls 114 | if c.config['xeng_format'] == 'inter': 115 | freq = (index / n_bls) * x_per_fpga * len(c.xfpgas) + xeng 116 | else: 117 | freq = (index / n_bls) + x_per_fpga * xeng * c.config['n_chans']/c.config['n_xeng'] 118 | i, j = c.get_bl_order()[bls_index] 119 | real_val = bram_data[xeng][li * 2] 120 | imag_val = bram_data[xeng][li * 2 + 1] 121 | if (real_val != 0) or (imag_val != 0) or opts.verbose: 122 | print '[%s] [%4i]: Freq: %i. bls: %s_%s. Raw value: 0x%05x + 0x%05xj (%6i + %6ij).'%(c.xsrvs[xeng], index, freq, i, j, real_val, imag_val, real_val, imag_val) 123 | print 'Done with %s, X-engine %i.'%(c.xsrvs[xeng],xeng) 124 | print 'Done with all.' 125 | 126 | except KeyboardInterrupt: 127 | exit_clean() 128 | except: 129 | exit_fail() 130 | 131 | exit_clean() 132 | 133 | -------------------------------------------------------------------------------- /src/oogpio.py: -------------------------------------------------------------------------------- 1 | """Client for communicating with an Arduino-based SKA-SA optically-isolated GPIO breakout board over KATCP. 2 | 3 | @author Jason Manley 4 | @Revised 2012/09/13 first release 5 | """ 6 | 7 | import serial, logging, sys, time, os 8 | 9 | from katcp import * 10 | log = logging.getLogger("katcp_gpio") 11 | 12 | 13 | class GpioClient(): 14 | """Client for communicating with a GPIO board. Nasty hard-coded KATCP stuff. 15 | 16 | Notes: 17 | - All commands are blocking. 18 | - If there is no response to an issued command, an exception is thrown 19 | with appropriate message after a timeout waiting for the response. 20 | """ 21 | #TODO: migrate to serial-port enabled KATCP library 22 | 23 | def __init__(self, serial_dev, timeout=1.0, logger=log,startup_delay=0): 24 | """Create a basic DeviceClient. 25 | 26 | @param self This object. 27 | @param serial_dev String: /dev/ttyS0 or similar 28 | @param timeout Float: seconds to wait before timing out on 29 | client operations. 30 | @param logger Object: Logger to log to. 31 | """ 32 | 33 | self.strm=serial.Serial(port=serial_dev,baudrate=9600,timeout=timeout) 34 | self._timeout = timeout 35 | self._logger = log 36 | self.mp=MessageParser() 37 | time.sleep(startup_delay) #give the device a chance to startup (for USB powered units) 38 | self.strm.read(1024) 39 | 40 | def _request(self, name, *args): 41 | """Make a blocking request and check the result. 42 | 43 | Raise an error if the reply indicates a request failure. 44 | 45 | @param self This object. 46 | @param name String: name of the request message to send. 47 | @param args List of strings: request arguments. 48 | @return Tuple: containing the reply and a list of inform messages. 49 | """ 50 | request = Message.request(name, *args) 51 | # reply, informs = self.blocking_request(request,keepalive=True) 52 | self._write(request) 53 | reply=self._read() 54 | 55 | if reply.arguments[0] != Message.OK: 56 | self._logger.error("Request %s failed.\n Request: %s\n Reply: %s." 57 | % (request.name, request, reply)) 58 | 59 | raise RuntimeError("Request %s failed.\n Request: %s\n Reply: %s." 60 | % (request.name, request, reply)) 61 | return reply 62 | 63 | #reply, informs = self._request("tap-start", tap_dev, device, ip_str, port_str, mac_str) 64 | #if reply.arguments[0]=='ok': return 65 | #else: raise RuntimeError("Failure starting tap device %s with mac %s, %s:%s"%(device,mac_str,ip_str,port_str)) 66 | 67 | def _write(self,message): 68 | """Sends a message.""" 69 | self.strm.write(str(message)) 70 | #print 'Sent: %s\r'%str(message) 71 | self.strm.write('\r') 72 | 73 | def _read(self): 74 | """Gets a single line from the serial port, handles the reply and returns a message object.""" 75 | ln=self.strm.readline().strip() 76 | #print 'Got: %s'%ln 77 | if len(ln)>0: 78 | return self.mp.parse(ln) 79 | else: 80 | self._logger.error("Reply timed out.") 81 | raise RuntimeError("Reply timed out.") 82 | 83 | def ping(self): 84 | """Tries to ping the FPGA. 85 | @param self This object. 86 | @return boolean: ping result. 87 | """ 88 | reply = self._request("watchdog") 89 | if reply.arguments[0]=='ok': return True 90 | else: return False 91 | 92 | def setd(self,pin,state): 93 | """Sets a boolean value on a digital IO pin.""" 94 | if ((state in [0,1]) or (state in [True,False])): 95 | reply = self._request("setd",int(pin),int(state)) 96 | else: raise RuntimeError("Invalid state.") 97 | 98 | def seta(self,pin,val): 99 | """Starts a PWM signal on a digital IO pin. Pins 3, 5, 6, 9, 10 and 11 are supported. Valid range: 0-255.""" 100 | val_pins=[3,5,6,9,10,11] 101 | assert val in range(255), ("%i is an invalid PWM number. Valid PWM range is 0-255."%int(val)) 102 | assert pin in val_pins, "Invalid pin %i. Valid pins are %s."%(pin,val_pins) 103 | reply = self._request("seta",int(pin),int(val)) 104 | 105 | def geta(self,pin,smoothing=1): 106 | """Retrieve an ADC value, optionally smoothed over "smoothing" measurements.""" 107 | assert (smoothing in range(1,65)), "Can only smooth between 1 and 64 samples!" 108 | assert (pin in range(8)), "Invalid analogue pin selected. Choose in range(0,8)!" 109 | return int(self._request("geta",int(pin),int(smoothing)).arguments[1]) 110 | 111 | def getd(self,pin): 112 | """Gets a boolean value on a digital IO pin.""" 113 | return int(self._request("getd",int(pin)).arguments[1]) 114 | 115 | def set_5b_atten_serial(self,data_pin,clk_pin,le_pin,atten): 116 | self.setd(le_pin,0) 117 | for bit in range(5): 118 | self.setd(clk_pin,0) 119 | self.setd(data_pin,atten>>bit) 120 | self.setd(clk_pin,1) 121 | self.setd(clk_pin,0) 122 | self.setd(le_pin,1) 123 | 124 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | Changelog: 2 | 3 | Version 0.7.2 (2013-02-05) 4 | - Initial beamformer system 5 | 6 | Version 0.7.1 (2012-10-02) 7 | - Initial beamformer additions 8 | 9 | Version 0.7.0 (2012-09-19) 10 | - fringe phase input now mod-360. 11 | 12 | Version 0.6.9 () 13 | - Updates to several snap scripts to improve compatibility with narrow band. 14 | - Bugfix to xstatus to reset terminal after clean exit 15 | - Bugfix to corr_snap_10gbe_tx.py which decoded frequencies incorrectly. 16 | - X-engine 10gbe cores were not being reset correctly in corr_functions.initialise and in the corr_init script (which should use corr_functions.init?). 17 | gbe_enable in the control register was being disabled, but isn't used in the gateware. The gateware uses the gbe_out_enable bit to stop transmission 18 | from the mux_out block. 19 | gbe_reset_hold_x/f and gbe_reset_release_x/f functions added to corr_functions to be used instead of using x/feng_ctrl_set_all directly. 20 | - corr_snap_descramble.py can analyse both descramble snap blocks on an x-engine board. Also plot the reassembled spectrum. 21 | - corr_snap_xaui_feng.py updated for new snapshot blocks. 22 | - corr_snap_xaui_feng_build_spectrum.py added. Rebuild and plot the spectrum from the snap_xaui block. 23 | - corr_nb and corr_wb for functions specific to narrowband/wideband modes. 24 | - Introduced corr_ddc placeholder. 25 | - register description/bitfields now separate 26 | - snapshots now unpacked by snap.py 27 | 28 | Version 0.6.8 (2011-08-03): 29 | - Bugfix to n_accs calc with changes to acc_n_set/get 30 | 31 | Version 0.6.7 (2011-07-20): 32 | - More reliable rx.py for interleaved RX mode. No more repeated accumulations. 33 | - Began adding functions for upcoming narrowband mode. 34 | - Started generalising bitfields 35 | 36 | Version 0.6.6 (2011-04-04): 37 | - Added function to corr_functions to calibrate ADC spectrum. 38 | - Removed bits counter used from adc_amplitudes, which was an inaccurate reflection anyway. 39 | - Prettied time plots from snapshots, added spectrum etc. corr_adc_time now replaces corr_adc_histogram 40 | - RCS blocks now supported. 41 | - changes to fstatus, spead metadata, adc_amplitudes_get 42 | - added colour to log printouts when error occurs 43 | - changes to config file. system now basically single-pol. no more n_stokes, n_pol or pol map 44 | - support for arbitrary antenna names. parameters to all fuctions that used to take antenna,pol params now take single string param. 45 | - get_ant_location replaced by get_ant_str_location 46 | - single RX script... now calls threaded functions in rx.py. 47 | - added functions for per-engine status. useful for system health displays. 48 | - bugfixes to katadc's temp reading 49 | - katadc attenuator get/set implemented 50 | 51 | Version 0.6.5 (2011-03-01): 52 | - Added software control for KATADC and iADC. 53 | 54 | Version 0.6.4 (2011-02-09): 55 | - Bug fixes for systems using xaui loopback 56 | - added clear facilities to fstatus 57 | - removed stats library dependancy 58 | - bug fixes to scroller 59 | - bug fixes to snap capture in katcp_wrapper 60 | 61 | 62 | Version 0.6.2 (2010-11-26): 63 | - Added example.conf file to distribution package. 64 | - Fix to corr_xstatus.py for case where F engines have 10GbE out and X engines have 10GbE (fabric) output. 65 | - Mod to corr_rx_cont_h5.py to allow for commanline disable of n_acc scaleback. 66 | - Mod to corr_arm to resync vaccs after rearm. 67 | 68 | Version 0.6.1 (2010-11-25): 69 | - Fix to corr_snap_quant.py script. 70 | 71 | Version 0.6.0 72 | - Support added for F engines that output data directly on 10GbE ports (ie no XAUI loopback through X engines). 73 | - Support added for X engines that process contiguous frequency chunks. 74 | - Should be backwards compatible with XAUI systems and X engines that process interleaved channels (corr-0.5.1). 75 | - Error handling mostly unified and coded to use logging everywhere rather than printing errors to the console. 76 | - Added funtion to check firmware versions. 77 | - Added SPEAD metadata. 78 | - Feng/Xeng ctrl registers now keep state across function calls and can automatically pulse, set or clear bits. 79 | - ADC and Requant histogram plotting improvements 80 | - Shift to curses display for ADC amplitudes and status reporting 81 | - Fix to fine delay calc in fr_delay_set call and added ability to disable load check. 82 | - New config file params to support above features. Some redundant and unnecessary params removed. 83 | 84 | Version 0.5.1 85 | - Bugfixes relating to KATADC/iADC use. 86 | - Moving all scripts to function calls. 87 | - First PyPI submission. 88 | - Incomplete and untested. Development abandoned to start work on system with native Feng 10Gbe out. 89 | 90 | Version 0.5.0 91 | - Requires reconfigurable (ie ROACH) F engines. Support for iBOB-based F engines has been dropped as we switch to KATCP-only connections. 92 | - significant changes to corr_functions and cn_conf to support ROACH based F engines. 93 | - Changed configuration parsing library to iniparse. 94 | 95 | Version 0.4.2: 2010-04-02 96 | *) tgtap call in katcp_wrapper now takes another parameter to allow naming of tap devices. *NOT BACKWARDS COMPATIBLE* 97 | *) antenna numbering now correct off F engines. 98 | *) cn_tx.py replaced by corr_tx.py 99 | *) cleanup of some functions. 100 | 101 | Version 0.4.0 102 | - KATCP control protocol. 103 | 104 | -------------------------------------------------------------------------------- /scripts/corr_snap_quant.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ''' 4 | Grabs the contents of "snap_xaui" for a given antenna and plots successive accumulations. 5 | Does not use the standard 'corr_functions' error checking. 6 | Assumes 4 bit values for power calculations. 7 | Assumes the correlator is already initialsed and running etc. 8 | 9 | Author: Jason Manley 10 | Date: 2009-07-01 11 | 12 | Revisions: 13 | 2011-06-29 JRM Port to new snap.py 14 | 2010-11-24 PP Fix to plotting 15 | Ability to plot multiple antennas 16 | 2010-07-22: JRM Mods to support ROACH based F engines (corr-0.5.0) 17 | 2010-02-01: JRM Added facility to offset capture point. 18 | Added RMS printing and peak bits used. 19 | 2009-07-01: JRM Ported to use corr_functions connectivity 20 | Fixed number of bits calculation 21 | 22 | ''' 23 | import corr, time, numpy, struct, sys, logging, pylab, matplotlib 24 | 25 | polList = [] 26 | report = [] 27 | logscale = False 28 | 29 | def exit_fail(): 30 | print 'FAILURE DETECTED. Log entries:\n', lh.printMessages() 31 | print "Unexpected error:", sys.exc_info() 32 | try: 33 | c.disconnect_all() 34 | except: pass 35 | if verbose: 36 | raise 37 | exit() 38 | 39 | def exit_clean(): 40 | try: 41 | c.disconnect_all() 42 | except: pass 43 | exit() 44 | 45 | def drawDataCallback(): 46 | for p, pol in enumerate(polList): 47 | get_data(pol) 48 | pol['plot'].cla() 49 | pol['plot'].set_xlim(0, c.config['n_chans'] + 1) 50 | pol['plot'].set_title('Quantiser amplitude output for input %s, averaged over %i spectra.' % (pol['ant_str'], pol['num_accs'])) 51 | pol['plot'].set_xlabel('Frequency channel') 52 | pol['plot'].set_ylabel('Average power level') 53 | if logscale: 54 | pol['plot'].semilogy(numpy.divide(pol['accumulations'], pol['num_accs'])) 55 | else: 56 | pol['plot'].plot(numpy.divide(pol['accumulations'], pol['num_accs'])) 57 | fig.canvas.draw() 58 | fig.canvas.manager.window.after(100, drawDataCallback) 59 | 60 | def parseAntenna(antArg): 61 | import re 62 | #regExp = re.compile('^[0-9]{1,4}[xy]{0,2}$') 63 | ants = antArg.lower().replace(' ','').split(',') 64 | return ants 65 | 66 | def get_data(pol): 67 | print 'Integrating data %i from %s:' % (pol['num_accs'], pol['ant_str']) 68 | print ' Grabbing data off snap blocks...', 69 | sys.stdout.flush() 70 | unpacked_vals, spectra = c.get_quant_snapshot(pol['ant_str'], n_spectra = 1) 71 | print 'done.' 72 | print ' Accumulating...', 73 | sys.stdout.flush() 74 | unpacked_vals = numpy.square(numpy.abs(unpacked_vals)) 75 | if spectra > 1: 76 | unpacked_vals = numpy.sum(unpacked_vals, axis = 0) 77 | pol['accumulations'] = numpy.sum([pol['accumulations'], unpacked_vals], axis = 0) 78 | pol['num_accs'] += spectra 79 | print 'done.' 80 | return 81 | 82 | if __name__ == '__main__': 83 | from optparse import OptionParser 84 | p = OptionParser() 85 | p.set_usage('%prog [options] CONFIG_FILE') 86 | p.set_description(__doc__) 87 | p.add_option('-t', '--man_trigger', dest='man_trigger', action='store_true', 88 | help='Trigger the snap block manually') 89 | p.add_option('-v', '--verbose', dest='verbose', action='store_true', 90 | help='Print raw output.') 91 | p.add_option('-p', '--noplot', dest='noplot', action='store_true', 92 | help='Do not plot averaged spectrum.') 93 | p.add_option('-a', '--ant', dest='ant', type='str', default=None, 94 | help='Select antenna to query.') 95 | p.add_option('-l', '--log', dest='log', action='store_true', default=False, 96 | help='Plot on a log scale.') 97 | opts, args = p.parse_args(sys.argv[1:]) 98 | 99 | if opts.man_trigger: man_trigger = True 100 | else: man_trigger = False 101 | 102 | if args == []: 103 | config_file = None 104 | else: 105 | config_file = args[0] 106 | verbose = opts.verbose 107 | 108 | lh = corr.log_handlers.DebugLogHandler(35) 109 | if opts.ant != None: 110 | ant_strs = parseAntenna(opts.ant) 111 | else: 112 | print 'No antenna given for which to plot data.' 113 | exit_fail() 114 | 115 | logscale = opts.log 116 | 117 | try: 118 | print 'Connecting...', 119 | c = corr.corr_functions.Correlator(config_file = config_file, log_level = logging.DEBUG if verbose else logging.INFO, connect = False) 120 | c.connect() 121 | print 'done' 122 | 123 | binary_point = c.config['feng_fix_pnt_pos'] 124 | packet_len = c.config['10gbe_pkt_len'] 125 | n_chans = c.config['n_chans'] 126 | num_bits = c.config['feng_bits'] 127 | adc_bits = c.config['adc_bits'] 128 | adc_levels_acc_len = c.config['adc_levels_acc_len'] 129 | 130 | if num_bits != 4: 131 | print 'This script is only written to work with 4 bit quantised values.' 132 | exit_clean() 133 | 134 | # set up the figure with a subplot for each polarisation to be plotted 135 | fig = matplotlib.pyplot.figure() 136 | for p, ant_str in enumerate(ant_strs): 137 | if not ant_str in c.config._get_ant_mapping_list(): 138 | print 'Unrecognised input %s. Must be in ' % p, c.config._get_ant_mapping_list() 139 | exit_clean() 140 | polList.append({'ant_str':ant_str}) 141 | polList[p]['accumulations'] = numpy.zeros(c.config['n_chans']) 142 | polList[p]['num_accs'] = 0 143 | polList[p]['plot'] = fig.add_subplot(len(ant_strs), 1, p + 1) 144 | 145 | # start the process 146 | fig.canvas.manager.window.after(100, drawDataCallback) 147 | print 'Plot started.' 148 | matplotlib.pyplot.show() 149 | 150 | except KeyboardInterrupt: 151 | exit_clean() 152 | except: 153 | exit_fail() 154 | 155 | exit_clean() 156 | 157 | #end 158 | 159 | -------------------------------------------------------------------------------- /scripts/corr_nb_build_ct_spectrum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ''' 4 | Uses the "fine" snap block to capture corner-turner data on the F engines and rebuild the spectrum from there. 5 | Assumes 4 bit values for power calculations. 6 | Assumes the correlator is already initialsed and running. 7 | 8 | NOTE: the snap block data width is 32-bit, so that's only 2 samples x 2 pols x 4.3 complex data. 128 values per frequency means 128/2 snap block words per frequency. 9 | 10 | Author: Paul Prozesky 11 | 12 | Revisions: 13 | 2011-09-21: PVP Initial version. 14 | ''' 15 | import corr, time, numpy, struct, sys, logging 16 | 17 | snap_name = 'fine_snap_d' 18 | 19 | def exit_fail(): 20 | print 'FAILURE DETECTED. Log entries:\n', 21 | c.log_handler.printMessages() 22 | print "Unexpected error:", sys.exc_info() 23 | try: 24 | c.disconnect_all() 25 | except: pass 26 | raise 27 | exit() 28 | 29 | def exit_clean(): 30 | try: 31 | c.disconnect_all() 32 | except: pass 33 | exit() 34 | 35 | def raw2fp(num, nbits = 4): 36 | return float(((numpy.int8(num << nbits) >> nbits))) / (2**(nbits-1)) 37 | 38 | def unpack32bit(num): 39 | pol00 = raw2fp((num >> 28) & 0x0f) + (1j * raw2fp((num >> 24) & 0x0f)) 40 | pol10 = raw2fp((num >> 20) & 0x0f) + (1j * raw2fp((num >> 16) & 0x0f)) 41 | pol01 = raw2fp((num >> 12) & 0x0f) + (1j * raw2fp((num >> 8) & 0x0f)) 42 | pol11 = raw2fp((num >> 4) & 0x0f) + (1j * raw2fp((num >> 0) & 0x0f)) 43 | return [pol00, pol01], [pol10, pol11] 44 | 45 | if __name__ == '__main__': 46 | from optparse import OptionParser 47 | p = OptionParser() 48 | p.set_usage('%prog [options] CONFIG_FILE') 49 | p.set_description(__doc__) 50 | p.add_option('-v', '--verbose', dest='verbose', action='store_true', 51 | help='Print raw output.') 52 | p.add_option('-f', '--fengine', dest='fengine', type='int', default=-1, 53 | help='F-engine to read. Default is -1, all.') 54 | opts, args = p.parse_args(sys.argv[1:]) 55 | if args == []: 56 | config_file = None 57 | else: 58 | config_file = args[0] 59 | verbose = opts.verbose 60 | 61 | try: 62 | print 'Connecting...', 63 | c = corr.corr_functions.Correlator(config_file = config_file, log_level = logging.DEBUG if verbose else logging.INFO, connect = False) 64 | c.connect() 65 | print 'done' 66 | n_chans = c.config['n_chans'] 67 | num_bits = c.config['feng_bits'] 68 | if num_bits != 4: 69 | print 'This script is only written to work with 4 bit quantised values.' 70 | raise KeyboardInterrupt 71 | if opts.fengine == -1: fpgas = c.ffpgas 72 | else: fpgas = [c.ffpgas[opts.fengine]] 73 | # set up the path to the corner-turner snap output 74 | corr.corr_functions.write_masked_register(fpgas, corr.corr_nb.register_fengine_fine_control, quant_snap_select = 2) 75 | reports = dict() 76 | spectra = dict() 77 | for n, f in enumerate(fpgas): 78 | reports[n] = dict() 79 | spectra[n] = dict() 80 | spectra[n][0] = dict() 81 | spectra[n][1] = dict() 82 | n_xeng = 2**2 83 | snap_depth_w = 2**13 84 | values_per_fchan = 128 85 | values_per_sword = 2 86 | bytes_per_sword = 4 87 | sword_per_fchan = values_per_fchan / values_per_sword 88 | fchan_per_snap = snap_depth_w / sword_per_fchan 89 | fchan_lookup = [] 90 | for r in range(0, n_chans / n_xeng): fchan_lookup.extend(range(r, n_chans, n_chans / n_xeng)) 91 | up32 = dict() 92 | for n, f in enumerate(fpgas): up32[n] = [] 93 | # grab the data and decode it 94 | print 'Grabbing and processing the spectrum data from corner-turner output snap block (offset/%i)... %5i' % (n_chans, 0), 95 | for offset in range(0, n_chans / fchan_per_snap): 96 | #for offset in range(0, 1): 97 | print 7 * '\b', '%5i' % (offset * fchan_per_snap), 98 | sys.stdout.flush() 99 | dataFine = corr.snap.snapshots_get(fpgas, dev_names = 'fine_snap_d', man_trig = False, man_valid = False, wait_period = 3, offset = offset * snap_depth_w * 4, circular_capture = False) 100 | for n, d in enumerate(dataFine['data']): up32[n].extend(list(struct.unpack('>%iI' % (snap_depth_w*4/4), d))) 101 | print '' 102 | # process the 32-bit numbers and unscramble the order 103 | print 'Processing %i frequency channels in %i x %i bytes: %5i' % (n_chans, len(up32), len(up32[0])*bytes_per_sword, 0), 104 | starttime = time.time() 105 | freq_coverage = [] 106 | for f in range(0, len(up32[0]) / sword_per_fchan): 107 | start_index = f * sword_per_fchan 108 | #print '%i(%i)' % (f, fchan_lookup[f]), 109 | print 7 * '\b', '%5i' % f, 110 | sys.stdout.flush() 111 | for n, updata in enumerate(up32): 112 | pol0 = [] 113 | pol1 = [] 114 | for r in range(0, sword_per_fchan): 115 | a, b = unpack32bit(up32[n][start_index + r]) 116 | pol0.extend(a) 117 | pol1.extend(b) 118 | spectra[n][0][fchan_lookup[f]] = numpy.average(numpy.sqrt(numpy.real(pol0)**2 + numpy.imag(pol0)**2)) 119 | spectra[n][1][fchan_lookup[f]] = numpy.average(numpy.sqrt(numpy.real(pol1)**2 + numpy.imag(pol1)**2)) 120 | freq_coverage.append(fchan_lookup[f]) 121 | print '' 122 | print 'That took %i seconds.' % (time.time() - starttime) 123 | for f in range(0, n_chans): 124 | if not freq_coverage.__contains__(f): raise RuntimeError('Missing frequency %i.' % f) 125 | import matplotlib, pylab 126 | for i in range(0, len(spectra)): 127 | matplotlib.pyplot.figure() 128 | matplotlib.pyplot.subplot(2, 1, 1) 129 | matplotlib.pyplot.plot(spectra[i][0].values()) 130 | matplotlib.pyplot.subplot(2, 1, 2) 131 | matplotlib.pyplot.plot(spectra[i][1].values()) 132 | matplotlib.pyplot.show() 133 | 134 | except KeyboardInterrupt: 135 | exit_clean() 136 | except: 137 | exit_fail() 138 | 139 | exit_clean() 140 | 141 | -------------------------------------------------------------------------------- /src/iadc.py: -------------------------------------------------------------------------------- 1 | """Module for performing various iADC functions from software. 2 | Author: Jason Manley, using code segments from Hong Chen and David George.""" 3 | import numpy,struct,time 4 | 5 | def spi_write_register(fpga,zdok_n,reg_addr,reg_value): 6 | """Writes to a register from the ADC via SPI (two bytes at a time).""" 7 | if not zdok_n in [0,1]: raise RuntimeError("zdok_n must be 0 or 1. Please select your ZDok port.") 8 | #adc 0 is at offset 4 9 | #adc 1 is at offset 8 10 | #these addresses are WRITE-ONLY 11 | fpga.blindwrite('iadc_controller',struct.pack('>H2B',reg_value,reg_addr,0x01), offset=0x4+zdok_n*(0x04)) 12 | 13 | def rst(fpga,zdok_n): 14 | """Reset the ADC and FPGA DCM. This will just pulse the reset lines.""" 15 | #Reset pulse: writing '1' to bit 0 resets ADC0; writing '1' to bit 1 resets ADC1 (at offset 0x3). 16 | if not zdok_n in [0,1]: raise RuntimeError("zdok_n must be 0 or 1. Please select your ZDok port.") 17 | fpga.blindwrite('iadc_controller','%c%c%c%c'%(0x0,0x00,0x03,0x1<500MSps, 10 for 250-500MSps, 01 for 125-250MSps, 00 for <125Msps) 46 | # 14 DMUX (0=Fs/4, 1=Fs/2) 47 | # 15 NA 48 | 49 | def configure(fpga,zdok_n,mode='indep',cal='new',clk_speed=800): 50 | """fpga is an FpgaClient object; 51 | zdok_n is the adc number (0,1); 52 | mode in ('indep','inter_Q','inter_I'); 53 | input select is 'I' or 'Q'; 54 | Clk source will always be from clkI (compat with iADC v1.1 through v1.3); 55 | clk_speed is in MHz and is used for auto-phase calibration. 56 | cal in ('new','old','zero')""" 57 | if not zdok_n in [0,1]: raise RuntimeError("zdok_n must be 0 or 1. Please select your ZDok port.") 58 | clk_bits = 0 if clk_speed<125 else 1 if (clk_speed<250) else 2 if (clk_speed<500) else 3 59 | cal_bits = 0 if cal=='zero' else 1 if cal=='old' else 3 #if cal=='new' else raise RuntimeError ('bad cal option') 60 | mode_bits = 0x2 if mode=='inter_I' else 0 if mode=='inter_Q' else 0xB 61 | spi_write_register(fpga,zdok_n,0x0,(1<<14)+(clk_bits<<12)+(cal_bits<<10)+(mode_bits<<4)+(1<<3)+(1<<2)) 62 | rst(fpga,zdok_n) 63 | 64 | def analogue_gain_adj(fpga,zdok_n,gain_I=0,gain_Q=0): 65 | """Adjusts the on-chip analogue gain for the two ADCs in dB. Valid range is -1.5 to +1.5 in steps of 0.011dB.""" 66 | if gain_I>1.5 or gain_I<-1.5 or gain_Q<-1.5 or gain_Q>1.5: raise RuntimeError("Invalid gain setting. Valid range is -1.5 to +1.5dB") 67 | #bits_I= int(((gain_I+1.5)*256)/3.0) 68 | #bits_Q= int(((gain_Q+1.5)*256)/3.0) 69 | #spi_write_register(fpga,zdok_n,0x1,(bits_Q<<8) + (bits_I<<0)) 70 | bits_I= abs(int(((gain_I)*127)/1.5)) 71 | bits_Q= abs(int(((gain_Q)*127)/1.5)) 72 | sign_I = 1 if gain_I<0 else 0 73 | sign_Q = 1 if gain_Q<0 else 0 74 | val=((sign_Q<<15) + (sign_I<<7) + (bits_Q<<8) + (bits_I<<0)) 75 | print 'Writing %4x'%(val) 76 | spi_write_register(fpga,zdok_n,0x1,val) 77 | 78 | 79 | #NOT TESTED from this point onwards... 80 | def offset_adj(fpga,zdok_n,offset_I=0,offset_Q=0): 81 | """Adjusts the on-chip DC offset. Offset is in range [-31.75LSb:+31.75LSb:0.25LSb]. NOT TESTED. YMMV!""" 82 | if offset_I>31.75 or offset_I<-31.75 or offset_Q<-31.75 or offset_Q>31.75: raise RuntimeError("Invalid offset setting. Valid range is -31.75 to +31.75LSb") 83 | bits_I= abs(int(((offset_I)*127)/31.75)) 84 | bits_Q= abs(int(((offset_Q)*127)/31.75)) 85 | sign_I = 1 if offset_I>0 else 0 86 | sign_Q = 1 if offset_Q>0 else 0 87 | val=((sign_Q<<15) + (sign_I<<7) + (bits_Q<<8) + (bits_I<<0)) 88 | print 'Writing %4x'%(val) 89 | spi_write_register(fpga,zdok_n,0x2,val) 90 | 91 | def gain_adj(fpga,zdok_n,gain): 92 | """Adjusts the on-chip gain for the two ADCs in dB. Valid range is -0.315 to +0.315dB in steps of 0.011dB. NOT TESTED. YMMV!""" 93 | if gain<-0.315 or gain>0.315: raise RuntimeError("Invalid gain setting. Valid range is -1.5 to +1.5dB") 94 | bits= abs(int(((gain)*63)/0.315)) 95 | sign = 1 if gain<0 else 0 96 | print 'Writing %4x'%((sign<<6) + (bits<<0)) 97 | spi_write_register(fpga,zdok_n,0x3,(sign<<6) + (bits<<0)) 98 | 99 | def fisda_Q_adj(fpga,zdock_n,delay=0): 100 | """Adjusts the Fine Sampling Delay Adjustment (FiSDA) on channel Q. delay is in ps and has a valid range of -60 to +60ps in 4ps steps. NOT TESTED! YMMV!""" 101 | if delay<-60 or delay>60: raise RuntimeError("Invalid delay setting. Valid range is -60ps to +60ps.") 102 | bits= abs(int(((delay)*15)/60)) 103 | sign = 1 if delay<0 else 0 104 | print 'Writing %4x'%((sign<<10) + (bits<<6)) 105 | spi_write_register(fpga,zdok_n,0x7,(sign<<10) + (bits<<6)) 106 | 107 | -------------------------------------------------------------------------------- /scripts/corr_nb_snap_ct.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ''' 4 | Uses the "fine" snap block to capture corner-turner data on the F engines and rebuild the spectrum from there. 5 | Assumes 4 bit values for power calculations. 6 | Assumes the correlator is already initialsed and running. 7 | 8 | NOTE: the snap block data width is 32-bit, so that's only 2 samples x 2 pols x 4.3 complex data. 128 values per frequency means 128/2 snap block words per frequency. 9 | 10 | Author: Paul Prozesky 11 | 12 | Revisions: 13 | 2011-09-21: PVP Initial version. 14 | ''' 15 | import corr, time, numpy, struct, sys, logging 16 | 17 | snap_name = 'fine_snap_d' 18 | 19 | def exit_fail(): 20 | print 'FAILURE DETECTED. Log entries:\n', 21 | c.log_handler.printMessages() 22 | print "Unexpected error:", sys.exc_info() 23 | try: 24 | c.disconnect_all() 25 | except: pass 26 | raise 27 | exit() 28 | 29 | def exit_clean(): 30 | try: 31 | c.disconnect_all() 32 | except: pass 33 | exit() 34 | 35 | def raw2fp(num, nbits = 4): 36 | return float(((numpy.int8(num << nbits) >> nbits))) / (2**(nbits-1)) 37 | 38 | def unpack32bit(num): 39 | pol00 = raw2fp((num >> 28) & 0x0f) + (1j * raw2fp((num >> 24) & 0x0f)) 40 | pol10 = raw2fp((num >> 20) & 0x0f) + (1j * raw2fp((num >> 16) & 0x0f)) 41 | pol01 = raw2fp((num >> 12) & 0x0f) + (1j * raw2fp((num >> 8) & 0x0f)) 42 | pol11 = raw2fp((num >> 4) & 0x0f) + (1j * raw2fp((num >> 0) & 0x0f)) 43 | return [pol00, pol01], [pol10, pol11] 44 | 45 | if __name__ == '__main__': 46 | from optparse import OptionParser 47 | p = OptionParser() 48 | p.set_usage('%prog [options] CONFIG_FILE') 49 | p.set_description(__doc__) 50 | p.add_option('-v', '--verbose', dest='verbose', action='store_true', 51 | help='Print raw output.') 52 | p.add_option('-o', '--offset', dest='offset', type='int', default=0, 53 | help='Offset, in CHANNELS, from which to capture.') 54 | p.add_option('-f', '--fengine', dest='fengine', type='int', default=-1, 55 | help='F-engine to read. Default is -1, all.') 56 | opts, args = p.parse_args(sys.argv[1:]) 57 | if args == []: 58 | config_file = None 59 | else: 60 | config_file = args[0] 61 | verbose = opts.verbose 62 | 63 | try: 64 | print 'Connecting...', 65 | c = corr.corr_functions.Correlator(config_file = config_file, log_level = logging.DEBUG if verbose else logging.INFO, connect = False) 66 | c.connect() 67 | print 'done' 68 | n_chans = c.config['n_chans'] 69 | num_bits = c.config['feng_bits'] 70 | if num_bits != 4: 71 | print 'This script is only written to work with 4 bit quantised values.' 72 | raise KeyboardInterrupt 73 | reports = dict() 74 | spectra = dict() 75 | if opts.fengine == -1: fpgas = c.ffpgas 76 | else: fpgas = [c.ffpgas[opts.fengine]] 77 | corr.corr_functions.write_masked_register(fpgas, corr.corr_nb.register_fengine_fine_control, quant_snap_select = 2) 78 | for n, f in enumerate(fpgas): 79 | reports[n] = dict() 80 | spectra[n] = dict() 81 | spectra[n][0] = numpy.zeros(n_chans) 82 | spectra[n][1] = numpy.zeros(n_chans) 83 | n_xeng = 2**2 84 | snap_depth_w = 2**13 85 | values_per_fchan = 128 86 | values_per_sword = 2 87 | bytes_per_sword = 4 88 | sword_per_fchan = values_per_fchan / values_per_sword 89 | fchan_per_snap = snap_depth_w / sword_per_fchan 90 | fchan_lookup = [] 91 | for r in range(0, n_chans / n_xeng): fchan_lookup.extend(range(r, n_chans, n_chans / n_xeng)) 92 | up32 = dict() 93 | for n, f in enumerate(fpgas): up32[n] = [] 94 | # work out the offset for the requested channel 95 | channel_location = fchan_lookup.index(opts.offset) 96 | offset_in_bytes = channel_location * sword_per_fchan * bytes_per_sword 97 | # grab the data and decode it 98 | print 'Grabbing and processing the spectrum data from corner-turner output snap block (channel = %i, offset = %i chans (%i bytes))...' % (opts.offset, channel_location, offset_in_bytes), 99 | sys.stdout.flush() 100 | dataFine = corr.snap.snapshots_get(fpgas, dev_names = 'fine_snap_d', man_trig = False, man_valid = False, wait_period = 3, offset = offset_in_bytes, circular_capture = False) 101 | for n, d in enumerate(dataFine['data']): up32[n].extend(list(struct.unpack('>%iI' % (snap_depth_w*4/4), d))) 102 | print 'done.' 103 | # process the 32-bit numbers and unscramble the order 104 | print 'Processing %i frequency channels in %i x %i bytes, starting at channel offset %i.' % (snap_depth_w / sword_per_fchan, len(up32), len(up32[0])*bytes_per_sword, opts.offset) 105 | starttime = time.time() 106 | freq_coverage = [] 107 | for f in range(0, len(up32[0]) / sword_per_fchan): 108 | freq_index = channel_location + f 109 | start_index = f * sword_per_fchan 110 | if opts.verbose: print '%i(%i)' % (freq_index, fchan_lookup[freq_index]), 111 | sys.stdout.flush() 112 | for n, updata in enumerate(up32): 113 | pol0 = [] 114 | pol1 = [] 115 | for r in range(0, sword_per_fchan): 116 | a, b = unpack32bit(up32[n][start_index + r]) 117 | pol0.extend(a) 118 | pol1.extend(b) 119 | spectra[n][0][fchan_lookup[freq_index]] = numpy.average(numpy.sqrt(numpy.real(pol0)**2 + numpy.imag(pol0)**2)) 120 | spectra[n][1][fchan_lookup[freq_index]] = numpy.average(numpy.sqrt(numpy.real(pol1)**2 + numpy.imag(pol1)**2)) 121 | freq_coverage.append(fchan_lookup[freq_index]) 122 | if opts.verbose: print '' 123 | print 'That took %i seconds.' % (time.time() - starttime) 124 | #for f in range(0, n_chans): 125 | # if not freq_coverage.__contains__(f): raise RuntimeError('Missing frequency %i.' % f) 126 | import matplotlib, pylab 127 | for i in range(0, len(spectra)): 128 | matplotlib.pyplot.figure() 129 | matplotlib.pyplot.subplot(2, 1, 1) 130 | matplotlib.pyplot.plot(spectra[i][0]) 131 | matplotlib.pyplot.subplot(2, 1, 2) 132 | matplotlib.pyplot.plot(spectra[i][1]) 133 | matplotlib.pyplot.show() 134 | 135 | except KeyboardInterrupt: 136 | exit_clean() 137 | except: 138 | exit_fail() 139 | 140 | exit_clean() 141 | 142 | -------------------------------------------------------------------------------- /src/scroll.py: -------------------------------------------------------------------------------- 1 | # pylint: disable-msg=C0301 2 | # pylint: disable-msg=E1101 3 | """ 4 | Playing with ncurses in Python to scroll up and down, left and right, through a list of data that is periodically refreshed. 5 | 6 | Revs: 7 | 2010-12-11 JRM Added concat for status line to prevent bailing on small terminals. 8 | Code cleanup to prevent modification of external variables. 9 | Added left, right page controls 10 | """ 11 | 12 | import curses, types 13 | 14 | def screen_teardown(): 15 | '''Restore sensible options to the terminal upon exit 16 | ''' 17 | curses.nocbreak() 18 | curses.echo() 19 | curses.endwin() 20 | 21 | class Scroll(object): 22 | '''Scrollable ncurses screen. 23 | ''' 24 | 25 | def __init__(self): 26 | '''Constructor 27 | ''' 28 | # what should be printed at the bottom of the screen? 29 | self.instruction_string = "" 30 | 31 | # at which row and col must we draw the screen output? 32 | self.offset_y = 0 33 | self.offset_x = 0 34 | 35 | # the main screen object 36 | self.screen = None 37 | 38 | # the line position at which we're currently drawing 39 | self.curr_y_pos = 0 40 | self.curr_x_pos = 0 41 | 42 | # set up the screen 43 | def screen_setup(self): 44 | '''Set up a curses screen object and associated options 45 | ''' 46 | self.screen = curses.initscr() 47 | self.screen.keypad(1) 48 | self.screen.nodelay(1) 49 | curses.noecho() 50 | curses.cbreak() 51 | 52 | def on_keypress(self): 53 | ''' 54 | Handle key presses. 55 | ''' 56 | key = self.screen.getch() 57 | if key > 0: 58 | try: 59 | if chr(key) == 'q': 60 | raise KeyboardInterrupt # q for quit 61 | elif chr(key) == 'u': 62 | self.offset_y -= curses.LINES 63 | elif chr(key) == 'd': 64 | self.offset_y += curses.LINES 65 | elif chr(key) == 'l': 66 | self.offset_x += curses.COLS 67 | elif chr(key) == 'r': 68 | self.offset_x -= curses.COLS 69 | elif chr(key) == 'h': 70 | self.offset_x = 0 71 | self.offset_y = 0 72 | elif key == 65: 73 | self.offset_y -= 1 # up 74 | elif key == 66: 75 | self.offset_y += 1 # down 76 | elif key == 67: 77 | self.offset_x -= 1 # right 78 | elif key == 68: 79 | self.offset_x += 1 # left 80 | return [key, chr(key)] 81 | except ValueError: 82 | return [0, 0] 83 | else: 84 | return [0, 0] 85 | 86 | def clear_screen(self): 87 | '''Clear the ncurses screen. 88 | ''' 89 | self.screen.clear() 90 | 91 | def draw_string(self, new_line, **kwargs): 92 | '''Draw a new line to the screen, takes an argument as to whether the screen should be immediately refreshed or not 93 | ''' 94 | try: 95 | refresh = kwargs.pop('refresh') 96 | except: 97 | refresh = False 98 | self.screen.addstr(self.curr_y_pos, self.curr_x_pos, new_line, **kwargs) 99 | if new_line.endswith('\n'): 100 | self.curr_y_pos += 1 101 | self.curr_x_pos = 0 102 | else: 103 | self.curr_x_pos += len(new_line) 104 | if refresh: 105 | self.screen.refresh() 106 | 107 | def draw_screen(self, data, lineattrs = None): 108 | '''Draw the screen using the provided data 109 | ''' 110 | # clear the screen 111 | self.screen.clear() 112 | num_lines_total = len(data) 113 | # reserve the bottom three lines for instructions 114 | num_lines_available = curses.LINES -1 115 | # can we fit everything on the screen? 116 | top_line = 0 117 | if num_lines_total > num_lines_available: 118 | top_line = num_lines_total - num_lines_available 119 | # check the offsets, vertical and horizontal 120 | self.offset_y = min(0, self.offset_y) 121 | self.offset_y = max(-1 * top_line, self.offset_y) 122 | self.offset_x = min(0, self.offset_x) 123 | # which line are we showing at the top? 124 | top_line += self.offset_y 125 | top_line = max(top_line, 0) 126 | bottom_line = min(num_lines_total, top_line + num_lines_available) 127 | # add the lines to the curses screen one by one 128 | self.curr_y_pos = 0 129 | for line_num in range(top_line, bottom_line): 130 | #data[line_num] = "%03i-%03i-%03i-%03i-" % (top_line, line_num, self.offset_y, self.offset_x) + data[line_num] 131 | # truncate long lines and add the data to the screen 132 | if (lineattrs == None):# or (len(lineattrs) != len(data)): 133 | attr = [curses.A_NORMAL] 134 | elif (type(lineattrs[line_num]) == types.ListType): 135 | attr = lineattrs[line_num] 136 | else: 137 | attr = [lineattrs[line_num]] 138 | self.screen.addstr(self.curr_y_pos, 139 | 0, 140 | (data[line_num][-1 * self.offset_x:(-1 * self.offset_x) + curses.COLS]) + '\n', 141 | *attr) 142 | self.curr_y_pos += 1 143 | stat_line = "Showing line %i to %i of %i. Column offset %i. %s Scroll with arrow keys. u, d, l, r = page up, down, left and right. h = home, q = quit." % (top_line, bottom_line, num_lines_total, self.offset_x, self.instruction_string) 144 | stat_line = stat_line[-1 * self.offset_x:(-1 * self.offset_x) + (curses.COLS-1)] 145 | self.screen.addstr(num_lines_available, 0, stat_line, curses.A_REVERSE) 146 | self.screen.refresh() 147 | 148 | # set and get the instruction string at the bottom 149 | def get_instruction_string(self): 150 | return self.instruction_string 151 | def set_instruction_string(self, new_string): 152 | self.instruction_string = new_string 153 | 154 | # end of file 155 | -------------------------------------------------------------------------------- /scripts/corr_adc_ampl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # pylint: disable-msg = C0301 3 | # pylint: disable-msg = C0103 4 | ''' 5 | Reads the values of the RMS amplitude accumulators on the ibob through the X engine's XAUI connection.\n 6 | 7 | Revisions: 8 | 2011-01-04 JRM Moved scroller screen teardown into try statement so that it doesn't clobber real error messages in the event that it wasn't instantiated in the first place. 9 | 2010-12-11 JRM Removed bit estimate printing. 10 | ADC overrange now just shows flag, does not cover amplitude text. 11 | ncurses scroller fix to allow fast scrolling of screen. 12 | 1.32 JRM swapped corr.rst_cnt for corr.rst_fstat and swapped column for RMS levels in dB. 13 | 1.31 PVP Changed to accomodate change to corr_functions.adc_amplitudes_get() function - key in return dict changed from rms to rms_raw 14 | 1.30 PVP Change to ncurses interface with ability to clear error statuses using corr.rst_cnt 15 | 1.21 PVP Fix filename in OptionParser section. 16 | 1.20 JRM Support any number of antennas together with F engine 305 and X engine rev 322 and later.\n 17 | 1.10 JRM Requires F engine rev 302 or later and X engine rev 308 or later.\n 18 | 19 | ''' 20 | import corr, time, sys, logging, curses 21 | 22 | def exit_fail(): 23 | print 'FAILURE DETECTED. Log entries:\n', c.log_handler.printMessages() 24 | print "Unexpected error:", sys.exc_info() 25 | try: 26 | #corr.scroll.screen_teardown() 27 | c.disconnect_all() 28 | except: 29 | pass 30 | raise 31 | 32 | def exit_clean(): 33 | corr.scroll.screen_teardown() 34 | try: 35 | c.disconnect_all() 36 | except: 37 | pass 38 | exit() 39 | 40 | if __name__ == '__main__': 41 | from optparse import OptionParser 42 | p = OptionParser() 43 | p.set_usage(__file__ + ' [options] CONFIG FILE') 44 | p.add_option('-v', '--verbose', dest = 'verbose', action = 'store_true', help = 'Print raw output.') 45 | p.set_description(__doc__) 46 | opts, args = p.parse_args(sys.argv[1:]) 47 | 48 | if args == []: 49 | config_file = None 50 | else: 51 | config_file = args[0] 52 | verbose = opts.verbose 53 | 54 | try: 55 | print 'Connecting...', 56 | c = corr.corr_functions.Correlator(config_file = config_file, log_level = logging.DEBUG if verbose else logging.INFO, connect = False) 57 | c.connect() 58 | print 'done' 59 | 60 | time.sleep(1) 61 | # set up the curses scroll screen 62 | scroller = corr.scroll.Scroll() 63 | scroller.screen_setup() 64 | scroller.set_instruction_string("A toggles auto-clear, C to clear once.") 65 | # main program loop 66 | lastUpdate = time.time() - 3 67 | autoClear = False 68 | clearOnce = False 69 | screenData = [] 70 | while(True): 71 | # get key presses from ncurses 72 | keyPress = scroller.on_keypress() 73 | if keyPress[0] > 0: 74 | if (keyPress[1] == 'a') or (keyPress[1] == 'A'): 75 | autoClear = not autoClear 76 | elif (keyPress[1] == 'c') or (keyPress[1] == 'C'): 77 | clearOnce = True 78 | scroller.draw_screen(screenData) 79 | 80 | if (time.time() > (lastUpdate + 1)): 81 | screenData = [] 82 | lineattrs = [] 83 | amps = c.adc_amplitudes_get() 84 | stats = c.feng_status_get_all() 85 | if autoClear or clearOnce: 86 | c.rst_fstatus() 87 | clearOnce = False 88 | screenData.append('IBOB: ADC0 is furthest from power port, ADC1 is closest to power port.') 89 | screenData.append('ROACH: ADC0 is right, ADC1 is left (when viewed from front).') 90 | screenData.append('ADC input amplitudes averaged %i times.' % c.config['adc_levels_acc_len']) 91 | screenData.append('------------------------------------------------') 92 | for line in range(4): 93 | lineattrs.append(curses.A_NORMAL) 94 | for i in range(c.config['n_inputs']): 95 | error = False 96 | ant_str = c.config.map_input_to_ant(i) 97 | ffpga_n, xfpga_n, fxaui_n, xxaui_n, feng_input = c.get_input_location(c.config.map_ant_to_input(ant_str)) 98 | displayString = 'Ant %s (%s in%i): ' % (ant_str, c.fsrvs[ffpga_n], feng_input) 99 | if c.config['adc_type'] == 'katadc': 100 | displayString += ' Board input of %6.2f dBm with preamp of %5.1fdB = %6.2fdBm into ADC.' % ( 101 | amps[ant_str]['input_rms_dbm'], amps[ant_str]['analogue_gain'], amps[ant_str]['adc_rms_dbm']) 102 | else: 103 | displayString += ' %.3f' % (amps[ant_str]['rms_raw']) 104 | if stats[ant_str]['adc_overrange']: 105 | displayString += ' ADC OVERRANGE!' 106 | error = True 107 | if stats[ant_str]['adc_disabled']: 108 | displayString += ' ADC is disabled!' 109 | error = True 110 | if amps[ant_str]['low_level_warn']: 111 | displayString += ' ADC input low; readings inaccurate!' 112 | error = True 113 | screenData.append(displayString) 114 | #lineattrs.append(curses.A_BOLD if error == True else curses.A_NORMAL) 115 | lineattrs.append(curses.A_STANDOUT if error == True else curses.A_NORMAL) 116 | #if error == True: 117 | # screenData.append(corr.termcolors.colorize(displayString, fg = 'red')) 118 | #else: 119 | # screenData.append(corr.termcolors.colorize(displayString, fg = 'green')) 120 | #lineattrs.append(curses.COLOR_RED if error == True else curses.COLOR_GREEN) 121 | screenData.append("") 122 | lineattrs.append(curses.A_NORMAL) 123 | if autoClear: 124 | screenData.append("Auto-clear ON.") 125 | else: 126 | screenData.append("Auto-clear OFF.") 127 | lineattrs.append(curses.COLOR_WHITE) 128 | scroller.draw_screen(screenData, lineattrs) 129 | #scroller.draw_screen(screenData) 130 | lastUpdate = time.time() 131 | time.sleep(0.1) 132 | 133 | except KeyboardInterrupt: 134 | exit_clean() 135 | except: 136 | exit_fail() 137 | 138 | print 'Done with all' 139 | exit_clean() 140 | 141 | # end 142 | 143 | -------------------------------------------------------------------------------- /scripts/corr_nb_plot_passband.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """ 3 | Capture data from all coarse channels in a narrowband correlator mode. Must be initialised and EQ-set first. 4 | """ 5 | 6 | import logging, sys, time 7 | 8 | logging.basicConfig(level = logging.WARN) 9 | 10 | def baseline_to_tuple(h5file, baseline): 11 | l = h5file['bls_ordering'].value[0][baseline].tolist() 12 | return (l[0], l[1]) 13 | 14 | def tuple_to_baseline(h5file, t): 15 | for n, b in enumerate(h5file['bls_ordering'].value[0]): 16 | l = b.tolist() 17 | if t == (l[0], l[1]): 18 | return n 19 | return -1 20 | 21 | if __name__ == '__main__': 22 | from optparse import OptionParser 23 | p = OptionParser() 24 | p.set_usage('%prog [options] [CUSTOM_CONFIG_FILE]') 25 | p.set_description(__doc__) 26 | p.add_option('', '--noplot', dest = 'noplot', action = 'store_true', default = False, help = 'Do not plot.') 27 | p.add_option('', '--plotonly', dest = 'plotonly', action = 'store_true', default = False, help = 'Plot only using exisintg data in the current directory.') 28 | p.add_option('-t', '--time', dest = 'capture_time', type = 'int', default = 20, help = 'Time for which data should be captured for each channel.') 29 | p.add_option('-b', '--baseline', dest = 'baseline', type = 'int', default = 0, help = 'Baseline to plot.') 30 | p.add_option('-a', '--disable_autoscale', dest = 'acc_scale', action = 'store_false', default = True, help = 'Do not autoscale the data by dividing down by the number of accumulations. Default: Scale back by n_accs.') 31 | p.add_option('-v', '--verbose', dest = 'verbose', action = 'store_true', default = False, help = 'Be verbose about errors.') 32 | opts, args = p.parse_args(sys.argv[1:]) 33 | if args == []: 34 | config_file = None 35 | else: 36 | config_file = args[0] 37 | 38 | # record the data 39 | if not opts.plotonly: 40 | if config_file == None: 41 | raise RuntimeError('A config file is necessary to log data.') 42 | 43 | import corr, spead64_48 as spead 44 | 45 | print 'Parsing config file...', 46 | sys.stdout.flush() 47 | c = corr.corr_functions.Correlator(config_file = config_file, log_level = logging.DEBUG if opts.verbose else logging.WARN, connect = False) 48 | c.connect() 49 | print 'done.' 50 | 51 | # check for narrowband 52 | if not c.is_narrowband(): 53 | raise RuntimeError('This script can only be run on narrowband correlators.') 54 | 55 | # stop transmission first off 56 | c.tx_stop() 57 | 58 | # loop through all the channels 59 | start_time = time.time() 60 | for channel in range(0, c.config['coarse_chans']): 61 | filename = 'channel_%03i.h5' % channel 62 | print 'Writing data for channel %i to file %s.' % (channel, filename) 63 | sys.stdout.flush() 64 | 65 | # select the coarse channel and wait a bit 66 | corr.corr_nb.channel_select(c, specific_chan = channel) 67 | time.sleep(2) 68 | 69 | # start the thread to receive the SPEAD data 70 | crx = corr.rx.CorrRx(mode = c.config['xeng_format'], data_port = c.config['rx_udp_port'], 71 | sd_ip = c.config['sig_disp_ip_str'], sd_port = c.config['sig_disp_port'], acc_scale = opts.acc_scale, 72 | filename = filename, log_level = logging.DEBUG if opts.verbose else logging.ERROR) 73 | try: 74 | crx.daemon = True 75 | crx.start() 76 | time.sleep(2) 77 | c.spead_issue_all() 78 | c.tx_start() 79 | timedout = False 80 | s_time = time.time() 81 | while(crx.isAlive() and (not timedout)): 82 | if time.time() - s_time > opts.capture_time: 83 | timedout = True 84 | raise Exception 85 | time.sleep(0.2) 86 | print 'RX process ended.' 87 | crx.join() 88 | except Exception: 89 | c.tx_stop() 90 | time.sleep(2) 91 | print 'Timeout, moving to next channel.' 92 | except KeyboardInterrupt: 93 | print 'Stopping.' 94 | 95 | print 'Done, wrote %i channels in %.3f seconds.' % (c.config['coarse_chans'], time.time() - start_time) 96 | c.disconnect_all() 97 | # end 98 | 99 | # plot 100 | if not opts.noplot: 101 | import numpy, pylab, os, h5py 102 | 103 | h5files = [] 104 | files = os.listdir('.') 105 | for f in files: 106 | if f.endswith('.h5'): h5files.append(f) 107 | h5files.sort() 108 | 109 | # are there any h5 files? 110 | if len(h5files) <= 0: 111 | raise RuntimeError('No H5 files to process.') 112 | 113 | # get metadata from the first file 114 | f = h5py.File(h5files[0], 'r') 115 | mdata = {} 116 | mdata['coarse_chans'] = f['coarse_chans'].value[0] 117 | mdata['n_chans'] = f['n_chans'].value[0] 118 | 119 | # check that the baseline exists 120 | baseline_str = baseline_to_tuple(f, opts.baseline) 121 | baseline = opts.baseline 122 | print 'Processing baseline %i, %s' %(baseline, baseline_str) 123 | 124 | x_phase = numpy.zeros(mdata['coarse_chans'] * (mdata['n_chans'] - 10)) 125 | x_mag = numpy.zeros(mdata['coarse_chans'] * (mdata['n_chans'] - 10)) 126 | ctr = 0 127 | last_chan = -1 128 | for fname in h5files: 129 | f = h5py.File(fname, 'r') 130 | chan = f['current_coarse_chan'].value[0] 131 | if chan <= last_chan: 132 | raise RuntimeError('coarse channel %i does not make sense, last one was %i.' % (chan, last_chan)) 133 | last_chan = chan 134 | if f['coarse_chans'].value[0] != mdata['coarse_chans']: 135 | raise RuntimeError('Can only compare data from the same correlator output. coarse_chans differs from first file checked.') 136 | if f['n_chans'].value[0] != mdata['n_chans']: 137 | raise RuntimeError('Can only compare data from the same correlator output. n_chans differs from first file checked.') 138 | s = f['xeng_raw'] 139 | d = numpy.zeros(mdata['n_chans']) 140 | for data in s: 141 | temp = numpy.vectorize(complex)(data[:,baseline,0], data[:,baseline,1]) 142 | d = d + temp 143 | #pylab.plot(numpy.unwrap(numpy.angle(d))) 144 | si = ctr * (mdata['n_chans']-10) 145 | d = d[5:mdata['n_chans']-5] 146 | #print si, ctr, len(d), si+mdata['n_chans']-10 147 | x_phase[si:si+mdata['n_chans']-10] = numpy.angle(d[0:mdata['n_chans']-10]) 148 | x_mag[si:si+mdata['n_chans']-10] = d[0:mdata['n_chans']-10] 149 | ctr += 1 150 | print '.', 151 | sys.stdout.flush() 152 | print '' 153 | 154 | # plot 155 | pylab.subplot(2,1,1) 156 | pylab.title('magnitude') 157 | pylab.semilogy(x_mag) 158 | pylab.subplot(2,1,2) 159 | pylab.title('phase') 160 | pylab.plot(x_phase) 161 | pylab.show() 162 | 163 | # end 164 | -------------------------------------------------------------------------------- /src/corr_wb.py: -------------------------------------------------------------------------------- 1 | """ 2 | Setup and unique functionality for the wide-band correlator modes. A wideband correlator's FPGAs process all digitised data, which is a multiple of the FPGA clock rates. 3 | """ 4 | """ 5 | Revisions: 6 | 2011-07-07 PVP Initial revision. 7 | """ 8 | import construct, corr_functions 9 | 10 | # f-engine control register 11 | register_fengine_control = construct.BitStruct('control', 12 | construct.Padding(32 - 20 - 1), # 21 - 31 13 | construct.Flag('tvgsel_noise'), # 20 14 | construct.Flag('tvgsel_fdfs'), # 19 15 | construct.Flag('tvgsel_pkt'), # 18 16 | construct.Flag('tvgsel_ct'), # 17 17 | construct.Flag('tvg_en'), # 16 18 | construct.Padding(16 - 13 - 1), # 14 - 15 19 | construct.Flag('adc_protect_disable'), # 13 20 | construct.Flag('flasher_en'), # 12 21 | construct.Padding(12 - 9 - 1), # 10 - 11 22 | construct.Flag('gbe_enable'), # 9 23 | construct.Flag('gbe_rst'), # 8 24 | construct.Padding(8 - 3 - 1), # 4 - 7 25 | construct.Flag('clr_status'), # 3 26 | construct.Flag('arm'), # 2 27 | construct.Flag('soft_sync'), # 1 28 | construct.Flag('mrst')) # 0 29 | 30 | # f-engine status 31 | register_fengine_fstatus = construct.BitStruct('fstatus0', 32 | construct.Padding(32 - 29 - 1), # 30 - 31 33 | construct.BitField("sync_val", 2), # 28 - 29 34 | construct.Padding(28 - 17 - 1), # 18 - 27 35 | construct.Flag('xaui_lnkdn'), # 17 36 | construct.Flag('xaui_over'), # 16 37 | construct.Padding(16 - 6 - 1), # 7 - 15 38 | construct.Flag('dram_err'), # 6 39 | construct.Flag('clk_err'), # 5 40 | construct.Flag('adc_disabled'), # 4 41 | construct.Flag('ct_error'), # 3 42 | construct.Flag('adc_overrange'), # 2 43 | construct.Flag('fft_overrange'), # 1 44 | construct.Flag('quant_overrange')) # 0 45 | 46 | # x-engine control register 47 | register_xengine_control = construct.BitStruct('ctrl', 48 | construct.Padding(32 - 16 - 1), # 17 - 31 49 | construct.Flag('gbe_out_enable'), # 16 50 | construct.Flag('gbe_rst'), # 15 51 | construct.Padding(15 - 12 - 1), # 13 - 14 52 | construct.Flag('flasher_en'), # 12 53 | construct.Flag('gbe_out_rst'), # 11 54 | construct.Flag('loopback_mux_rst'), # 10 55 | construct.Flag('gbe_enable'), # 9 56 | construct.Flag('cnt_rst'), # 8 57 | construct.Flag('clr_status'), # 7 58 | construct.Padding(7 - 0 - 1), # 1 - 6 59 | construct.Flag('vacc_rst')) # 0 60 | 61 | # x-engine status 62 | register_xengine_status = construct.BitStruct('xstatus0', 63 | construct.Padding(32 - 18 - 1), # 19 - 31 64 | construct.Flag('gbe_lnkdn'), # 18 65 | construct.Flag('xeng_err'), # 17 66 | construct.Padding(17 - 5 - 1), # 6 - 16 67 | construct.Flag('vacc_err'), # 5 68 | construct.Flag('rx_bad_pkt'), # 4 69 | construct.Flag('rx_bad_frame'), # 3 70 | construct.Flag('tx_over'), # 2 71 | construct.Flag('pkt_reord_err'), # 1 72 | construct.Flag('pack_err')) # 0 73 | 74 | # x-engine tvg control 75 | register_xengine_tvg_sel = construct.BitStruct('tvg_sel', 76 | construct.Padding(32 - 1 - 2 - 2 - 6), # 11 - 31 77 | construct.BitField("vacc_tvg_sel", 6), # 5 - 10 78 | construct.BitField("xeng_tvg_sel", 2), # 3 - 4 79 | construct.BitField("descr_tvg_sel", 2), # 1 - 2 80 | construct.Flag('xaui_tvg_sel')) # 0 81 | 82 | snap_xengine_rx = construct.BitStruct("snap_rx0", 83 | construct.Padding(128 - 64 - 16 - 5 - 28 - 15), 84 | construct.BitField("ant", 15), 85 | construct.BitField("mcnt", 28), 86 | construct.Flag("loop_ack"), 87 | construct.Flag("gbe_ack"), 88 | construct.Flag("valid"), 89 | construct.Flag("eof"), 90 | construct.Flag("flag"), 91 | construct.BitField("ip_addr", 16), 92 | construct.BitField("data", 64)) 93 | 94 | snap_xengine_gbe_rx = construct.BitStruct("snap_gbe_rx0", 95 | construct.Padding(128 - 64 - 32 - 7), 96 | construct.Flag("led_up"), 97 | construct.Flag("led_rx"), 98 | construct.Flag("eof"), 99 | construct.Flag("bad_frame"), 100 | construct.Flag("overflow"), 101 | construct.Flag("valid"), 102 | construct.Flag("ack"), 103 | construct.BitField("ip_addr", 32), 104 | construct.BitField("data", 64)) 105 | 106 | snap_xengine_gbe_tx = construct.BitStruct("snap_gbe_tx0", 107 | construct.Padding(128 - 64 - 32 - 6), 108 | construct.Flag("eof"), 109 | construct.Flag("link_up"), 110 | construct.Flag("led_tx"), 111 | construct.Flag("tx_full"), 112 | construct.Flag("tx_over"), 113 | construct.Flag("valid"), 114 | construct.BitField("ip_addr", 32), 115 | construct.BitField("data", 64)) 116 | 117 | # the snap block immediately after the x-engine 118 | snap_xengine_vacc = construct.BitStruct("snap_vacc0", construct.BitField("data", 32)) 119 | 120 | # the xaui snap block on the f-engine - this is just after packetisation 121 | snap_fengine_xaui = construct.BitStruct("snap_xaui0", 122 | construct.Padding(128 - 1 - 3 - 1 - 1 - 3 - 64), 123 | construct.Flag("link_down"), 124 | construct.Padding(3), 125 | construct.Flag("mrst"), 126 | construct.Padding(1), 127 | construct.Flag("eof"), 128 | construct.Flag("sync"), 129 | construct.Flag("hdr_valid"), 130 | construct.BitField("data", 64)) 131 | 132 | snap_fengine_gbe_tx = construct.BitStruct("snap_gbe_tx0", 133 | construct.Padding(128 - 64 - 32 - 6), 134 | construct.Flag("eof"), 135 | construct.Flag("link_up"), 136 | construct.Flag("led_tx"), 137 | construct.Flag("tx_full"), 138 | construct.Flag("tx_over"), 139 | construct.Flag("valid"), 140 | construct.BitField("ip_addr", 32), 141 | construct.BitField("data", 64)) 142 | 143 | 144 | def feng_status_get(c, ant_str): 145 | """Reads and decodes the status register for a given antenna. Adds some other bits 'n pieces relating to Fengine status.""" 146 | #'sync_val': 28:30, #This is the number of clocks of sync pulse offset for the demux-by-four ADC 1PPS. 147 | ffpga_n, xfpga_n, fxaui_n, xxaui_n, feng_input = c.get_ant_str_location(ant_str) 148 | rv = corr_functions.read_masked_register([c.ffpgas[ffpga_n]], register_fengine_fstatus, names = ['fstatus%i' % feng_input])[0] 149 | if rv['xaui_lnkdn'] or rv['xaui_over'] or rv['clk_err'] or rv['ct_error'] or rv['fft_overrange']: 150 | rv['lru_state']='fail' 151 | elif rv['adc_overrange'] or rv['adc_disabled']: 152 | rv['lru_state']='warning' 153 | else: 154 | rv['lru_state']='ok' 155 | return rv 156 | 157 | # end 158 | -------------------------------------------------------------------------------- /scripts/corr_quant_hist.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ''' 4 | Plots a histogram of the quantised values from a specified antenna and pol.\n 5 | \n 6 | Revisions:\n 7 | 2010-12-12 JRM: Attempt to get X-axes to stay static at -1 to 1. 8 | 2010-11-16: PVP: Working with 4 bits fixed (affects number of bins). Need reconfigurable dp and number of quant bits. 9 | 2010-08-06: JRM: Initial version based on corr_adc_hist.py from Paul.\n 10 | ''' 11 | import matplotlib, time, corr, numpy, struct, sys, pylab, os, logging 12 | 13 | # exit cleanly 14 | def exit_fail(): 15 | print 'FAILURE DETECTED. Log entries:\n', lh.printMessages() 16 | print "Unexpected error:", sys.exc_info() 17 | try: 18 | c.disconnect_all() 19 | except: 20 | pass 21 | exit() 22 | def exit_clean(): 23 | try: 24 | c.disconnect_all() 25 | except: 26 | pass 27 | exit() 28 | 29 | # main 30 | if __name__ == '__main__': 31 | from optparse import OptionParser 32 | p = OptionParser() 33 | p.set_usage(__file__ + ' [options] CONFIG FILE') 34 | p.add_option('-v', '--verbose', dest = 'verbose', action = 'store_true', help = 'Print raw output.') 35 | p.add_option('-a', '--antenna', dest = 'antAndPol', action = 'store', help = 'Specify an antenna and pol for which to get ADC histograms in the format defined in /var/run/corr/antenna_mapping. Default is, eg, 3x giving pol x for antenna three and 27y will give pol y for antenna 27. 3x,27y will do pol \'x\' of antenna three and pol \'y\' of antenna 27.') 36 | p.add_option('-c', '--compare', dest = 'comparePlots', action = 'store_true', help = 'Compare plots directly using the same y-axis for all plots.') 37 | p.set_description(__doc__) 38 | opts, args = p.parse_args(sys.argv[1:]) 39 | 40 | if args==[]: 41 | config_file=None 42 | else: 43 | config_file=args[0] 44 | verbose=opts.verbose 45 | 46 | # parse the antenna argument passed to the program 47 | def parseAntenna(antArg): 48 | import re 49 | #regExp = re.compile('^[0-9]{1,4}[xy]{0,2}$') 50 | ants = antArg.lower().replace(' ','').split(',') 51 | return ants 52 | #plotList = [] 53 | #for ant in ants: 54 | # if not regExp.search(ant): 55 | # print '\'' + ant + '\' is not a valid -a argument!\nExiting.' 56 | # exit() 57 | # antennaNumber = int(ant.replace('x', '').replace('y', '')) 58 | # if (ant.find('x') < 0) and (ant.find('y') < 0): 59 | # ant = ant + 'xy' 60 | # if ant.find('x') > 0: 61 | # plotList.append({'antenna':antennaNumber, 'pol':'x'}) 62 | # if ant.find('y') > 0: 63 | # plotList.append({'antenna':antennaNumber, 'pol':'y'}) 64 | #return plotList 65 | 66 | 67 | # the function that gets data given a required polarisation 68 | def getUnpackedData(requiredPol): 69 | antLocation = c.get_ant_str_location(requiredPol) 70 | # which fpga do we need? 71 | requiredFpga = antLocation[0] 72 | # get the data 73 | unpacked_vals = corr.snap.get_quant_snapshot(correlator = c, ant_str = requiredPol, man_trig = True, man_valid = True, wait_period = 0.1) 74 | return unpacked_vals, requiredFpga 75 | 76 | # make the log handler 77 | lh = corr.log_handlers.DebugLogHandler(35) 78 | 79 | # check the specified antennae, if any 80 | polList = [] 81 | if opts.antAndPol != None: 82 | polList = parseAntenna(opts.antAndPol) 83 | #polList = opts.antAndPol 84 | else: 85 | print 'No antenna given for which to plot data.' 86 | exit_fail() 87 | 88 | try: 89 | print 'Connecting...', 90 | c = corr.corr_functions.Correlator(config_file = config_file, log_handler = lh, log_level = logging.DEBUG if verbose else logging.INFO, connect = False) 91 | c.connect() 92 | print 'done' 93 | 94 | # some configuration from the config file 95 | quantBits = c.config['feng_bits'] 96 | binaryPoint = c.config['feng_fix_pnt_pos'] 97 | 98 | if quantBits != 4: 99 | print 'This script is only designed to work with 4-bit quantised correlators. Yours has %i bits!'%quantBits 100 | 101 | # set up the figure with a subplot for each polarisation to be plotted 102 | fig = matplotlib.pyplot.figure() 103 | 104 | # create the subplots 105 | subplots = [] 106 | numberOfPolarisations = len(polList) 107 | for p, pol in enumerate(polList): 108 | realPlot = matplotlib.pyplot.subplot(numberOfPolarisations, 2, (p * 2) + 1) 109 | imagPlot = matplotlib.pyplot.subplot(numberOfPolarisations, 2, (p * 2) + 2) 110 | subplots.append([realPlot, imagPlot]) 111 | 112 | # callback function to draw the data for all the required polarisations 113 | def drawDataCallback(comparePlots): 114 | maxYReal = -10000000 115 | maxYImag = -10000000 116 | dataLabel = ["real", "imag"] 117 | 118 | # add the data to the subplots 119 | for p, pol in enumerate(polList): 120 | unpacked_vals, ffpga = getUnpackedData(pol) 121 | data = [] 122 | data.append([val.real for val in unpacked_vals]) 123 | data.append([val.imag for val in unpacked_vals]) 124 | globalHistMaxY = [[0,0], [0,0]] 125 | # real and imag per pol 126 | for d in 0, 1: 127 | subplots[p][d].cla() 128 | #subplots[p][d].set_xlim(-1, 1) 129 | #histData, bins, patches = subplots[p][d].hist(data[d], bins = (2**quantBits), range = (-1, 1)) 130 | histData, bins, patches = subplots[p][d].hist(data[d], bins = (2**quantBits)) 131 | subplots[p][d].set_title('ant %s %s' % (pol, dataLabel[d])) 132 | #subplots[p][d].set_xlim(-1, 1) 133 | maxHistDataReal = max(histData[0]) 134 | maxHistDataImag = max(histData[1]) 135 | globalHistMaxY[d][0] = max(globalHistMaxY[d][0], maxHistDataReal) 136 | globalHistMaxY[d][1] = max(globalHistMaxY[d][1], maxHistDataImag) 137 | maxBoth = max(maxHistDataReal, maxHistDataImag) 138 | if not comparePlots: 139 | matplotlib.pyplot.ylim(ymax = maxBoth * 1.05) 140 | 141 | if comparePlots: 142 | for p, pol in enumerate(polList): 143 | subplots[p][0].set_ylim(ymax = maxYReal) 144 | subplots[p][1].set_ylim(ymax = maxYImag) 145 | #matplotlib.pyplot.subplot(numberOfPolarisations, 2, (p2 * 2) + 1) 146 | #matplotlib.pyplot.ylim(ymax = maxYReal) 147 | #matplotlib.pyplot.subplot(numberOfPolarisations, 2, (p2 * 2) + 2) 148 | #matplotlib.pyplot.ylim(ymax = maxYImag) 149 | 150 | fig.canvas.manager.window.after(100, drawDataCallback, comparePlots) 151 | 152 | # start the process 153 | fig.canvas.manager.window.after(100, drawDataCallback, opts.comparePlots) 154 | matplotlib.pyplot.show() 155 | print 'Plot started.' 156 | 157 | except KeyboardInterrupt: 158 | exit_clean() 159 | except: 160 | exit_fail() 161 | 162 | print 'Done with all.' 163 | exit_clean() 164 | 165 | # end 166 | 167 | -------------------------------------------------------------------------------- /scripts/corr_fstatus.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # pylint: disable-msg = C0301 3 | # pylint: disable-msg = C0103 4 | """ 5 | Reads the error counters on the correlator Xengines and reports such things as accumulated XAUI and packet errors. 6 | \n\n 7 | Revisions: 8 | 2010-12-11 JRM Added sync_val to lookup 9 | added fast scroll ability 10 | added clear error ability 11 | 2010-10-26 PVP Use ncurses via class scroll in scroll.py to allow scrolling around on-screen data 12 | 2010-07-22 JRM Ported for corr-0.5.5 13 | 2009-12-01 JRM Layout changes, check for loopback sync 14 | 2009/11/30 JRM Added support for gbe_rx_err_cnt for rev322e onwards. 15 | 2009/07/16 JRM Updated for x engine rev 322 with KATCP. 16 | 17 | Todo: 18 | print errors in RED. 19 | """ 20 | import corr, time, sys, logging 21 | 22 | lookup = {'adc_overrange': '[ADC OVERRANGE]', 23 | 'ct_error': '[CORNER-TURNER ERROR]', 24 | 'fft_overrange': '[FFT OVERFLOW]', 25 | 'sync_val': 'Sync offset in ADC clock cycles.', 26 | 'quant_overrange': 'Quantiser overrange.', 27 | 'xaui_lnkdn': '[XAUI LINK DOWN]', 28 | 'clk_err': '[SAMPLE CLOCK ERROR]', 29 | 'xaui_over': '[XAUI TX OVERFLOW]'} 30 | 31 | ignore = ['sync_val'] 32 | 33 | def exit_fail(): 34 | print 'FAILURE DETECTED. Log entries:\n', lh.printMessages() 35 | print "Unexpected error:", sys.exc_info() 36 | try: 37 | corr.scroll.screen_teardown() 38 | c.disconnect_all() 39 | except: 40 | pass 41 | if verbose: 42 | raise 43 | exit() 44 | 45 | def exit_clean(): 46 | try: 47 | corr.scroll.screen_teardown() 48 | c.disconnect_all() 49 | except: 50 | pass 51 | exit() 52 | 53 | if __name__ == '__main__': 54 | from optparse import OptionParser 55 | 56 | p = OptionParser() 57 | p.set_usage('%prog [options] CONFIG_FILE') 58 | p.set_description(__doc__) 59 | p.add_option('-c', '--clk_check', dest='clk_check', action='store_true', default=False, 60 | help='Perform clock integrity checks.') 61 | p.add_option('-v', '--verbose', dest='verbose', action='store_true', default=False, 62 | help='Log verbosely.') 63 | opts, args = p.parse_args(sys.argv[1:]) 64 | if args == []: 65 | config_file = None 66 | else: 67 | config_file = args[0] 68 | verbose = opts.verbose 69 | lh = corr.log_handlers.DebugLogHandler(35) 70 | try: 71 | print 'Connecting...', 72 | c = corr.corr_functions.Correlator(config_file = config_file, log_level = logging.DEBUG if verbose else logging.INFO, connect = False, log_handler = lh) 73 | c.connect() 74 | print 'done' 75 | 76 | scroller = None 77 | screenData = [] 78 | # set up the curses scroll screen 79 | scroller = corr.scroll.Scroll() 80 | scroller.screen_setup() 81 | scroller.set_instruction_string("A toggles auto-clear, C to clear once.") 82 | scroller.clear_screen() 83 | scroller.draw_string('Connecting...', refresh = True) 84 | autoClear = False 85 | clearOnce = False 86 | scroller.draw_string(' done.\n', refresh = True) 87 | # get FPGA data 88 | servers = c.fsrvs 89 | n_ants = c.config['n_ants'] 90 | start_t = time.time() 91 | if opts.clk_check: 92 | clk_check = c.feng_clks_get() 93 | scroller.draw_string('Estimating clock frequencies for connected F engines...\n', refresh = True) 94 | sys.stdout.flush() 95 | for fn, feng in enumerate(c.fsrvs): 96 | scroller.draw_string('\t %s (%i MHz)\n' % (feng, clk_check[fn]), refresh = True) 97 | scroller.draw_string('F engine clock integrity: ', refresh = True) 98 | pps_check = c.check_feng_clks() 99 | scroller.draw_string('%s\n' % {True : 'Pass', False: 'FAIL!'}[pps_check], refresh = True) 100 | if not pps_check: 101 | scroller.draw_string(c.check_feng_clk_freq(verbose = True) + '\n', refresh = True) 102 | time.sleep(2) 103 | 104 | # main program loop 105 | lastUpdate = time.time() - 3 106 | while True: 107 | # get key presses from ncurses 108 | keyPress = scroller.on_keypress() 109 | if keyPress[0] > 0: 110 | if (keyPress[1] == 'a') or (keyPress[1] == 'A'): 111 | autoClear = not autoClear 112 | elif (keyPress[1] == 'c') or (keyPress[1] == 'C'): 113 | clearOnce = True 114 | scroller.draw_screen(screenData) 115 | 116 | if (time.time() > (lastUpdate + 1)): # or gotNewKey: 117 | screenData = [] 118 | #lineattrs = [] 119 | 120 | mcnts = c.mcnt_current_get() 121 | status = c.feng_status_get_all() 122 | uptime = c.feng_uptime() 123 | fft_shift = c.fft_shift_get_all() 124 | 125 | if c.config['adc_type'] == 'katadc': 126 | rf_status = c.rf_status_get_all() 127 | if autoClear or clearOnce: 128 | c.rst_fstatus() 129 | clearOnce = False 130 | for in_n, ant_str in enumerate(c.config._get_ant_mapping_list()): 131 | ffpga_n, xfpga_n, fxaui_n, xxaui_n, feng_input = c.get_ant_str_location(ant_str) 132 | screenData.append(' Input %s (%s input %i, mcnt %i):' % (ant_str, c.fsrvs[ffpga_n], feng_input, mcnts[ffpga_n])) 133 | #lineattrs.append(curses.A_UNDERLINE) 134 | if c.config['adc_type'] == 'katadc' : 135 | screenData.append(" RF %8s: gain: %5.1f dB" % ({True: 'Enabled', False: 'Disabled'}[rf_status[ant_str][0]], rf_status[ant_str][1])) 136 | #lineattrs.append(curses.A_NORMAL) 137 | #screenData.append(' FFT shift pattern: 0x%06x' % fft_shift[ant_str]) 138 | #lineattrs.append(curses.A_NORMAL) 139 | printString = ' Cumulative errors: ' 140 | brd_err = False 141 | for item, error in status[ant_str].items(): 142 | if (error == True) and not (item in ignore): 143 | try: 144 | printString += lookup[item] 145 | if lookup[item][0] == '[': 146 | brd_err = True 147 | except KeyError: 148 | printString += item 149 | printString += ', ' 150 | screenData.append(printString) 151 | #lineattrs.append(curses.A_STANDOUT) if brd_err == True else lineattrs.append(curses.A_NORMAL) 152 | screenData.append('') 153 | #lineattrs.append(curses.A_NORMAL) 154 | 155 | screenData.append('Time: %i seconds' % (time.time() - start_t)) 156 | #lineattrs.append(curses.A_NORMAL) 157 | screenData.append("Auto-clear ON." if autoClear else "Auto-clear OFF.") 158 | #lineattrs.append(curses.A_NORMAL) 159 | scroller.draw_screen(screenData)#, lineattrs) 160 | lastUpdate = time.time() 161 | 162 | except KeyboardInterrupt: 163 | exit_clean() 164 | except: 165 | exit_fail() 166 | 167 | exit_clean() 168 | 169 | -------------------------------------------------------------------------------- /scripts/corr_snap_xeng_vacc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Grabs the contents of "snap_xeng0" (one per FPGA) at the output of the X eng and prints any non-zero values. 4 | Assumes the correlator is already initialsed and running etc. 5 | 6 | NOTE: Only good for 4 bit X engines with demux of 8 and accumulation length of 128. 7 | 8 | Author: Jason Manley\n 9 | Revisions:\n 10 | 2011-10-03: PVP New snap block support. 11 | 2010-08-05: JRM Mods to support corr-0.5.0 12 | 2010-07-29: PVP Cleanup as part of the move to ROACH F-Engines. Testing still needed.\n 13 | 2009------: JRM Initial revision.\n 14 | ''' 15 | import corr, time, numpy, pylab, struct, sys, logging 16 | 17 | def exit_fail(): 18 | print 'FAILURE DETECTED. Log entries:\n', 19 | c.log_handler.printMessages() 20 | print "Unexpected error:", sys.exc_info() 21 | try: 22 | c.disconnect_all() 23 | except: pass 24 | raise 25 | exit() 26 | 27 | def exit_clean(): 28 | try: 29 | c.disconnect_all() 30 | except: pass 31 | exit() 32 | 33 | def raw2fp(num, nbits = 4): 34 | return float(((numpy.int8(num << nbits) >> nbits))) / (2**(nbits-1)) 35 | 36 | def unpack32bit(num): 37 | pol01 = raw2fp((num >> 12) & 0x0f) + (1j * raw2fp((num >> 8) & 0x0f)) 38 | pol11 = raw2fp((num >> 4) & 0x0f) + (1j * raw2fp((num >> 0) & 0x0f)) 39 | return [pol00, pol01], [pol10, pol11] 40 | 41 | if __name__ == '__main__': 42 | from optparse import OptionParser 43 | 44 | p = OptionParser() 45 | p.set_usage('%prog [options] CONFIG_FILE') 46 | p.add_option('-s', '--snap', dest='snap', type='int', default=0, help='Pull data from the xeng (0) or vacc (1) snap blocks. Default: 0.') 47 | p.add_option('-v', '--verbose', dest='verbose', action='store_true', help='Print all the decoded (including zero valued) results (be verbose).') 48 | p.add_option('-x', '--xfpga', dest='xfpga', type='int', default=-1, help='Which x-engine fpga should be quried. Default is all.') 49 | p.add_option('-o', '--ch_offset', dest='ch_offset', type='int', default=0, help='Start capturing at specified channel offset. Default is 0.') 50 | p.add_option('-c', '--channel', dest='channel', type='int', default=-1, help='Capture a specific channel. This will automatically choose the correct x-engine.') 51 | 52 | p.set_description(__doc__) 53 | opts, args = p.parse_args(sys.argv[1:]) 54 | 55 | if args==[]: 56 | config_file=None 57 | else: 58 | config_file=args[0] 59 | verbose=opts.verbose 60 | 61 | if opts.snap == 0: 62 | dev_name = 'snap_xeng0' 63 | elif opts.snap == 1: 64 | dev_name = 'snap_vacc0' 65 | else: 66 | raise RuntimeError('Expected 0 or 1 for option -s.') 67 | 68 | try: 69 | print 'Connecting...', 70 | c=corr.corr_functions.Correlator(config_file=config_file,log_level=logging.DEBUG if verbose else logging.INFO,connect=False) 71 | c.connect() 72 | print 'done' 73 | 74 | binary_point = c.config['feng_fix_pnt_pos'] 75 | packet_len = c.config['10gbe_pkt_len'] 76 | n_chans = c.config['n_chans'] 77 | n_chans_per_x = c.config['n_chans_per_x'] 78 | num_bits = c.config['feng_bits'] 79 | adc_bits = c.config['adc_bits'] 80 | adc_levels_acc_len = c.config['adc_levels_acc_len'] 81 | x_per_fpga = c.config['x_per_fpga'] 82 | n_ants = c.config['n_ants'] 83 | xeng_acc_len = c.config['xeng_acc_len'] 84 | n_bls = c.config['n_bls'] 85 | 86 | report = dict() 87 | 88 | # work out offsets and what-not 89 | if opts.channel != -1: 90 | xeng_num = opts.channel / n_chans_per_x 91 | if xeng_num % 2 != 0: 92 | raise RuntimeError('Can\'t show channel %i on x-engine %i, only the even-numbered x-engines have snap blocks.' % (opts.channel, xeng_num)) 93 | xeng_fpga = xeng_num / 2 94 | fpgas = [c.xfpgas[xeng_fpga]] 95 | offset_bytes = ((opts.channel - (xeng_num * n_chans_per_x)) * n_bls) * 4 * 2 96 | print 'Channel %i found on fpga %i, x-engine %i' % (opts.channel, xeng_num, xeng_fpga) 97 | else: 98 | if opts.xfpga == -1: fpgas = c.xfpgas 99 | else: fpgas = [c.xfpgas[opts.xfpga]] 100 | if c.config['xeng_format'] == 'inter': 101 | offset_bytes = opts.ch_offset * n_bls * 4 * 2 102 | else: 103 | offset_bytes = opts.ch_offset * n_bls * 4 * 2 104 | 105 | if num_bits != 4: 106 | print 'ERR: this script is only written to interpret 4 bit data. Your F engine outputs %i bits.' % num_bits 107 | exit_fail() 108 | if xeng_acc_len != 128: 109 | print 'ERR: this script is only written to interpret data from X engines with acc length of 128 due to hardcoded bitwidth growth limitations. Your X engine accumulates for %i samples.'%xeng_acc_len 110 | exit_fail() 111 | 112 | 113 | print '------------------------' 114 | print 'Triggering capture at byte offset %i...' % (offset_bytes), 115 | sys.stdout.flush() 116 | bram_dmp = corr.snap.snapshots_get(fpgas, dev_name, man_trig = False, wait_period = acc_time*2, offset = offset_bytes) 117 | print 'done.' 118 | 119 | print 'Unpacking bram contents...' 120 | # hardcode unpack of 16 bit values. Assumes bitgrowth of log2(128)=7 bits and input of 4_3 * 4_3. 121 | sys.stdout.flush() 122 | bram_data = [] 123 | for f, fpga in enumerate(fpgas): 124 | print " Unpacking %i values from %s." % (len(bram_dmp['data'][f]), c.xsrvs[f]) 125 | if len(bram_dmp['data'][f]) > 0: 126 | bram_data.append(struct.unpack('>%ii' % (len(bram_dmp['data'][f]) / 4), bram_dmp['data'][f])) 127 | else: 128 | print " Got no data back for %s." % c.xsrvs[f] 129 | bram_data.append([]) 130 | print 'Done.' 131 | print '========================\n' 132 | 133 | for xeng, fpga in enumerate(fpgas): 134 | print '--------------------' 135 | print '\nX-engine %i' % xeng 136 | print '--------------------' 137 | for li in range(0, len(bram_data[xeng]) / 2): 138 | # index over complex numbers in bram 139 | index = (bram_dmp['offsets'][xeng]/(4*2)) + li 140 | bls_index = index % n_bls 141 | if c.config['xeng_format'] == 'inter': 142 | freq = (index / n_bls) * x_per_fpga * len(fpgas) + xeng 143 | else: 144 | freq = (index / n_bls) + x_per_fpga * xeng * c.config['n_chans']/c.config['n_xeng'] 145 | #print '(%i,%i,%i,%i)' % (li, index, bls_index, freq), 146 | i, j = c.get_bl_order()[bls_index] 147 | # data is a 128-bit number that was demuxed into 8 16.6 numbers 148 | real_val = bram_data[xeng][li * 2] 149 | imag_val = bram_data[xeng][li * 2 + 1] 150 | if (real_val != 0) or (imag_val != 0) or opts.verbose: 151 | print '[%s] [%4i,%4i]: Freq: %i. bls: %s_%s. Raw value: 0x%05x + 0x%05xj (%6i + %6ij).'%(c.xsrvs[xeng], index, bls_index, freq, i, j, real_val, imag_val, real_val, imag_val) 152 | print 'Done with %s, X-engine %i.'%(c.xsrvs[xeng],xeng) 153 | print 'Done with all.' 154 | 155 | except KeyboardInterrupt: 156 | exit_clean() 157 | except: 158 | exit_fail() 159 | 160 | exit_clean() 161 | 162 | -------------------------------------------------------------------------------- /scripts/corr_xstatus.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # pylint: disable-msg = C0301 3 | # pylint: disable-msg = C0103 4 | """ 5 | Reads the error counters on the correlator Xengines and reports such things as accumulated XAUI and packet errors. 6 | \n\n 7 | Revisions: 8 | 2010-12-11 JRM Fix to allow fast scrolling of curses display 9 | 2010-11-25 JRM Bugfix to also lookup gbe_tx_cnt if hardware outputs 10Gbe 10 | 2010-10-25 PVP Use ncurses via class scroll in scroll.py to allow scrolling around on-screen data 11 | 2010-07-22 JRM Ported for corr-0.5.5 12 | 2009-12-01 JRM Layout changes, check for loopback sync 13 | 2009-11-30 JRM Added support for gbe_rx_err_cnt for rev322e onwards. 14 | 2009-07-16 JRM Updated for x engine rev 322 with KATCP. 15 | """ 16 | import corr, time, sys, logging 17 | 18 | def exit_fail(): 19 | print 'FAILURE DETECTED. Log entries:\n', lh.printMessages() 20 | print "Unexpected error:", sys.exc_info() 21 | try: 22 | corr.scroll.screen_teardown() 23 | c.disconnect_all() 24 | except: 25 | pass 26 | if verbose: 27 | raise 28 | exit() 29 | 30 | def exit_clean(): 31 | try: 32 | corr.scroll.screen_teardown() 33 | c.disconnect_all() 34 | except: 35 | pass 36 | exit() 37 | 38 | if __name__ == '__main__': 39 | from optparse import OptionParser 40 | 41 | parser = OptionParser() 42 | parser.set_usage('%prog [options] CONFIG_FILE') 43 | parser.set_description(__doc__) 44 | parser.add_option('-v', '--verbose', dest = 'verbose', action = 'store_true', default = False, 45 | help = 'Be verbose about errors.') 46 | 47 | opts, args = parser.parse_args(sys.argv[1:]) 48 | 49 | if args == []: 50 | config_file = None 51 | else: 52 | config_file = args[0] 53 | verbose = opts.verbose 54 | lh = corr.log_handlers.DebugLogHandler(35) 55 | try: 56 | print 'Connecting...', 57 | c = corr.corr_functions.Correlator(config_file = config_file, log_handler = lh, log_level = logging.DEBUG if verbose else logging.INFO, connect = False) 58 | c.connect() 59 | print 'done' 60 | 61 | # set up the curses scroll screen 62 | screenData = [] 63 | scroller = corr.scroll.Scroll() 64 | scroller.screen_setup() 65 | # get FPGA data 66 | servers = c.xsrvs 67 | n_xeng_per_fpga = c.config['x_per_fpga'] 68 | n_xaui_ports_per_fpga = c.config['n_xaui_ports_per_xfpga'] 69 | xeng_acc_len = c.config['xeng_acc_len'] 70 | start_t = time.time() 71 | # main program loop 72 | lastUpdate = time.time() - 3 73 | while True: 74 | # get key presses from ncurses 75 | if scroller.on_keypress()[0] > 0: 76 | scroller.draw_screen(screenData) 77 | 78 | if (time.time() > (lastUpdate + 1)): # or gotNewKey: 79 | screenData = [] 80 | 81 | if c.config['feng_out_type'] == 'xaui': 82 | loopmcnt = [] 83 | gbemcnt = [] 84 | try: 85 | loopback_ok = c.check_loopback_mcnt() 86 | except: 87 | loopback_ok = False 88 | xaui_errors = [c.xread_uint_all('xaui_err%i'%(x)) for x in range(n_xaui_ports_per_fpga)] 89 | xaui_rx_cnt = [c.xread_uint_all('xaui_cnt%i'%(x)) for x in range(n_xaui_ports_per_fpga)] 90 | loop_cnt = [c.xread_uint_all('loop_cnt%i'%x) for x in range(min(n_xaui_ports_per_fpga, n_xeng_per_fpga))] 91 | loop_err_cnt = [c.xread_uint_all('loop_err_cnt%i'%x) for x in range(min(n_xaui_ports_per_fpga, n_xeng_per_fpga))] 92 | mcnts = [c.xread_uint_all('loopback_mux%i_mcnt'%(x)) for x in range(min(n_xaui_ports_per_fpga, n_xeng_per_fpga))] 93 | sum_xaui_errs = sum([sum(xaui_error_n) for xaui_error_n in xaui_errors]) 94 | for mi, mv in enumerate(mcnts): 95 | loopmcnt.append([mv[x]/(2**16) for x, f in enumerate(c.xfpgas)]) 96 | gbemcnt.append([mv[x]&((2**16)-1) for x, f in enumerate(c.xfpgas)]) 97 | 98 | if c.config['feng_out_type'] == 'xaui' or c.config['out_type'] == '10gbe': 99 | gbe_tx_cnt = [c.xread_uint_all('gbe_tx_cnt%i'%(x)) for x in range(n_xaui_ports_per_fpga)] 100 | gbe_tx_err = [c.xread_uint_all('gbe_tx_err_cnt%i'%(x)) for x in range(n_xaui_ports_per_fpga)] 101 | 102 | rx_cnt = [c.xread_uint_all('rx_cnt%i'%(x)) for x in range(min(n_xaui_ports_per_fpga, n_xeng_per_fpga))] 103 | gbe_rx_cnt = [c.xread_uint_all('gbe_rx_cnt%i'%x) for x in range(min(n_xaui_ports_per_fpga, n_xeng_per_fpga))] 104 | gbe_rx_err_cnt = [c.xread_uint_all('gbe_rx_err_cnt%i'%x) for x in range(min(n_xaui_ports_per_fpga, n_xeng_per_fpga))] 105 | rx_err_cnt = [c.xread_uint_all('rx_err_cnt%i'%x) for x in range(min(n_xaui_ports_per_fpga, n_xeng_per_fpga))] 106 | 107 | x_cnt = [c.xread_uint_all('pkt_reord_cnt%i'%(x)) for x in range(n_xeng_per_fpga)] 108 | x_miss = [c.xread_uint_all('pkt_reord_err%i'%(x)) for x in range(n_xeng_per_fpga)] 109 | last_miss_ant = [c.xread_uint_all('last_missing_ant%i'%(x)) for x in range(n_xeng_per_fpga)] 110 | 111 | vacc_cnt = [c.xread_uint_all('vacc_cnt%i'%x) for x in range(n_xeng_per_fpga)] 112 | vacc_err_cnt = [c.xread_uint_all('vacc_err_cnt%i'%x) for x in range(n_xeng_per_fpga)] 113 | vacc_ld_stat = c.vacc_ld_status_get() 114 | 115 | sum_bad_pkts = sum([sum(x_miss_n) for x_miss_n in x_miss])/xeng_acc_len 116 | sum_spectra = sum([sum(engcnt) for engcnt in x_cnt]) 117 | 118 | for fn, srv in enumerate(c.xsrvs): 119 | screenData.append(' ' + srv) 120 | 121 | if c.config['feng_out_type'] == 'xaui': 122 | for x in range(n_xaui_ports_per_fpga): 123 | screenData.append('\tXAUI%i RX cnt: %10i Errors: %10i' % (x, xaui_rx_cnt[x][fn], xaui_errors[x][fn])) 124 | 125 | for x in range(min(n_xaui_ports_per_fpga, n_xeng_per_fpga)): 126 | screenData.append('\t10GbE%i TX cnt: %10i Errors: %10i' % (x, gbe_tx_cnt[x][fn], gbe_tx_err[x][fn])) 127 | screenData.append("\t10GbE%i RX cnt: %10i Errors: %10i" % (x, gbe_rx_cnt[x][fn], gbe_rx_err_cnt[x][fn])) 128 | if c.config['feng_out_type'] == 'xaui': 129 | screenData.append('\tLoopback%i cnt: %10i Errors: %10i' % (x, loop_cnt[x][fn], loop_err_cnt[x][fn])) 130 | screenData.append("\tLoopback_mux%i cnt: %10i Errors: %10i" % (x, rx_cnt[x][fn], rx_err_cnt[x][fn])) 131 | screenData.append('\t Loopback%i mcnt: %6i' % (x, loopmcnt[x][fn])) 132 | screenData.append('\t GBE%i mcnt: %6i' % (x, gbemcnt[x][fn])) 133 | 134 | 135 | for x in range(n_xeng_per_fpga): 136 | printString = '\tX engine%i Spectr cnt: %10i Errors: %10.2f' % (x, x_cnt[x][fn], float(x_miss[x][fn])/float(xeng_acc_len)) 137 | if x_miss[x][fn] > 0: 138 | printString = printString + 'Last missing antenna: %i' % last_miss_ant[x][fn] 139 | screenData.append(printString) 140 | screenData.append("\tVector Accum%i cnt: %10i Errors: %10i" % (x, vacc_cnt[x][fn], vacc_err_cnt[x][fn])) 141 | screenData.append("\t arm_cnt: %10i load_cnt: %10i" % (vacc_ld_stat[srv]['arm_cnt%i'%x], vacc_ld_stat[srv]['ld_cnt%i'%x])) 142 | 143 | screenData.append('') 144 | 145 | if c.config['feng_out_type'] == 'xaui': 146 | screenData.append('Total bad XAUI packets received: %i' % sum_xaui_errs) 147 | screenData.append('Loopback muxes all syncd: %i' % loopback_ok) 148 | 149 | screenData.append('Total number of spectra processed: %i' % sum_spectra) 150 | screenData.append('Total bad X engine data: %i packets' % sum_bad_pkts) 151 | screenData.append('Time: %i' %(time.time() - start_t)) 152 | scroller.draw_screen(screenData) 153 | lastUpdate = time.time() 154 | 155 | except KeyboardInterrupt: 156 | exit_clean() 157 | except: 158 | exit_fail() 159 | 160 | exit_clean() 161 | 162 | -------------------------------------------------------------------------------- /bak/corr_snap_10gbe_tx_out.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ''' 4 | Grabs the contents of the 10GbE output snap blocks for analysis of SPEAD packets. THIS SCRIPT IS INCOMPLETE. 5 | 6 | ''' 7 | import corr, time, numpy, struct, sys, logging 8 | 9 | #brams 10 | brams=['bram_msb','bram_lsb','bram_oob'] 11 | 12 | # OOB signalling bit offsets: 13 | ip_addr_bit_width = 32-8 14 | ip_addr_bit_offset = 6 15 | eof_bit = 5 16 | link_up_bit = 4 17 | tx_led_bit = 3 18 | tx_afull_bit = 2 19 | tx_over_bit = 1 20 | valid_bit = 0 21 | 22 | pkt_ip_mask = (2**(ip_addr_bit_width+ip_addr_bit_offset)) -(2**ip_addr_bit_offset) 23 | 24 | def exit_fail(): 25 | print 'FAILURE DETECTED. Log entries:\n',c.log_handler.printMessages() 26 | print "Unexpected error:", sys.exc_info() 27 | 28 | try: 29 | c.disconnect_all() 30 | except: pass 31 | time.sleep(1) 32 | raise 33 | exit() 34 | 35 | def exit_clean(): 36 | try: 37 | c.disconnect_all() 38 | except: pass 39 | exit() 40 | 41 | def ip2str(pkt_ip): 42 | ip_4 = (pkt_ip&((2**32)-(2**24)))>>24 43 | ip_3 = (pkt_ip&((2**24)-(2**16)))>>16 44 | ip_2 = (pkt_ip&((2**16)-(2**8)))>>8 45 | ip_1 = (pkt_ip&((2**8)-(2**0)))>>0 46 | #print 'IP:%i. decoded to: %i.%i.%i.%i'%(pkt_ip,ip_4,ip_3,ip_2,ip_1) 47 | return '%i.%i.%i.%i'%(ip_4,ip_3,ip_2,ip_1) 48 | 49 | def unpack_item(flav1,flav2,data): 50 | rv={} 51 | rv['addr_mode'] = (data & (1<<((flav2+flav1)*8-1)))>>((flav2+flav1)*8-1) 52 | rv['item_id'] = (data & (((2**((flav1)*8-1))-1)<<(flav2*8)))>>(flav2*8) 53 | rv['data_addr'] = (data & ((2**((flav2)*8))-1)) 54 | return rv 55 | 56 | 57 | if __name__ == '__main__': 58 | from optparse import OptionParser 59 | 60 | p = OptionParser() 61 | p.set_usage('%prog [options] CONFIG_FILE') 62 | p.set_description(__doc__) 63 | p.add_option('-t', '--man_trigger', dest='man_trigger', action='store_true',default=False, 64 | help='Trigger the snap block manually') 65 | p.add_option('-v', '--verbose', dest='verbose', action='store_true', 66 | help='Be Verbose; print raw packet contents.') 67 | p.add_option('-n', '--core_n', dest='core_n', type='int', default=0, 68 | help='Core number to decode. Default 0.') 69 | 70 | 71 | opts, args = p.parse_args(sys.argv[1:]) 72 | 73 | if opts.man_trigger: 74 | man_trig=True 75 | else: 76 | man_trig=False 77 | 78 | verbose=opts.verbose 79 | man_valid=False 80 | man_trig=False 81 | 82 | dev_name = 'snap_gbe_tx%i'%opts.core_n 83 | 84 | if args==[]: 85 | config_file=None 86 | else: 87 | config_file=args[0] 88 | verbose=opts.verbose 89 | 90 | try: 91 | print 'Connecting...', 92 | c=corr.corr_functions.Correlator(config_file=config_file,log_level=logging.DEBUG if verbose else logging.INFO, connect=False) 93 | c.connect() 94 | print 'done' 95 | 96 | report = dict() 97 | binary_point = c.config['feng_fix_pnt_pos'] 98 | num_bits = c.config['feng_bits'] 99 | packet_len=c.config['10gbe_pkt_len'] 100 | n_ants = c.config['n_ants'] 101 | n_chans = c.config['n_chans'] 102 | n_ants_per_ibob=c.config['n_ants_per_xaui'] 103 | 104 | print '------------------------' 105 | print 'Grabbing snap data...', 106 | servers = c.xsrvs 107 | fpgas=c.xfpgas 108 | bram_dmp=bram_dmp=corr.snap.snapshots_get(fpgas=c.xfpgas,dev_names=dev_name,man_trig=man_trig,man_valid=man_valid,wait_period=2) 109 | print 'done' 110 | 111 | #print 'BRAM DUMPS:' 112 | #print bram_dmp 113 | 114 | print 'Unpacking bram contents...', 115 | sys.stdout.flush() 116 | bram_oob=dict() 117 | for f,server in enumerate(servers): 118 | if len(bram_dmp[brams[2]][f])<=4: 119 | print '\n No data for engine %s.'%server 120 | bram_oob[f]={} 121 | else: 122 | print '\n Got %i values from %s.'%(len(bram_dmp[brams[2]][f])/4,server) 123 | bram_oob[f]={'raw':struct.unpack('>%iL'%(len(bram_dmp[brams[2]][f])/4),bram_dmp[brams[2]][f])} 124 | bram_oob[f].update({'eof':[bool(i & (2**eof_bit)) for i in bram_oob[f]['raw']]}) 125 | bram_oob[f].update({'valid':[bool(i & (2**valid_bit)) for i in bram_oob[f]['raw']]}) 126 | bram_oob[f].update({'link':[bool(i & (2**link_up_bit)) for i in bram_oob[f]['raw']]}) 127 | bram_oob[f].update({'tx_led':[bool(i & (2**tx_led_bit)) for i in bram_oob[f]['raw']]}) 128 | bram_oob[f].update({'tx_afull':[bool(i & (2**tx_afull_bit)) for i in bram_oob[f]['raw']]}) 129 | bram_oob[f].update({'tx_over':[bool(i & (2**tx_over_bit)) for i in bram_oob[f]['raw']]}) 130 | bram_oob[f].update({'ip_addr':[(i&pkt_ip_mask)>>ip_addr_bit_offset for i in bram_oob[f]['raw']]}) 131 | #print '\n\nFPGA %i, bramoob:'%f,bram_oob 132 | print 'Done unpacking.' 133 | 134 | print 'Analysing packets:' 135 | for f,fpga in enumerate(fpgas): 136 | report[f]=dict() 137 | report[f]['pkt_total']=0 138 | pkt_len = 0 139 | prev_eof_index=-1 140 | 141 | i=0 142 | item_cnt=-1 143 | n_items=0 144 | 145 | 146 | while i < (len(bram_dmp[brams[1]][f])/4): #"i" is 64 bit index 147 | #if verbose==True: 148 | pkt_64bit = struct.unpack('>Q',bram_dmp['bram_msb'][f][(4*i):(4*i)+4]+bram_dmp['bram_lsb'][f][(4*i):(4*i)+4])[0] 149 | print '[%s] IDX: %6i'%(servers[f],i), 150 | print '[%s]'%ip2str(bram_oob[f]['ip_addr'][i]), 151 | if bram_oob[f]['valid'][i]: print '[valid]', 152 | if bram_oob[f]['link'][i]: print '[link]', 153 | if bram_oob[f]['tx_led'][i]: print '[tx_led]', 154 | if bram_oob[f]['tx_afull'][i]: print '[TX buffer almost full!]', 155 | if bram_oob[f]['tx_over'][i]: print '[TX buffer OVERFLOW!]', 156 | 157 | if bram_oob[f]['eof'][i]: 158 | #next piece should be SPEAD header: 159 | item_cnt = -1 160 | print '%016x'%(pkt_64bit), 161 | print '[EOF]' 162 | 163 | elif item_cnt == -1: 164 | #This might be a SPEAD header 165 | magic = (pkt_64bit &(((2**8)-1)<<56))>>56 166 | ver = (pkt_64bit &(((2**8)-1)<<48))>>48 167 | flav1 = (pkt_64bit &(((2**8)-1)<<40))>>40 168 | flav2 = (pkt_64bit &(((2**8)-1)<<32))>>32 169 | n_items = (pkt_64bit &(((2**16)-1))) 170 | if magic == 0x53: 171 | print 'Looks like SPEAD%i-%i, version %i with magic 0x%2x and %i items.'%((flav1+flav2)*8,(flav2*8),ver,magic,n_items) 172 | if flav1 != (c.config['spead_flavour'][0] - c.config['spead_flavour'][1])/8 or flav2 != c.config['spead_flavour'][1]/8 : \ 173 | print 'Warning: SPEAD flavour is not %i-%i.'%(c.config['spead_flavour'][0],c.config['spead_flavour'][1]) 174 | if n_items != 6: print 'Warning: n_items !=6.' 175 | item_cnt=0 176 | else: 177 | print 'Not a SPEAD packet, magic number is %i.'%magic 178 | item_cnt=9999 179 | 180 | elif item_cnt < n_items and item_cnt >=0: 181 | item=unpack_item(flav1,flav2,pkt_64bit) 182 | 183 | if item['addr_mode'] == 0: print '[imm addr]', 184 | elif item['addr_mode'] == 1: print '[abs addr]', 185 | else: print '[UNPACK LOGIC ERR!]' 186 | 187 | if item['item_id'] == 1: print 'Heap PCNT: %12i'%item['data_addr'] 188 | if item['item_id'] == 2: print 'Heap Size: %12i'%item['data_addr'] 189 | if item['item_id'] == 3: print 'Heap Offset: %12i'%item['data_addr'] 190 | if item['item_id'] == 4: print 'Payload len: %12i'%item['data_addr'] 191 | if item['item_id'] == 5632: print 'Timestamp: %12i'%item['data_addr'] 192 | if item['item_id'] == 6144: print 'Data addr: %12i'%item['data_addr'] 193 | item_cnt += 1 194 | 195 | else: 196 | print '%016x'%(pkt_64bit) 197 | 198 | i +=1 199 | 200 | print 'Done with all servers.' 201 | 202 | 203 | 204 | except KeyboardInterrupt: 205 | exit_clean() 206 | except: 207 | exit_fail() 208 | 209 | exit_clean() 210 | -------------------------------------------------------------------------------- /src/sim.py: -------------------------------------------------------------------------------- 1 | """A module for generating simulation data for a casper_n correlator. This 2 | is used to verify the data-flow through the packetization and readout system. 3 | 4 | Author: Aaron Parsons 5 | Modified: Jason Manley 6 | Revisions: 7 | 2010-07-30 JRM Merged with casper-correlator-0.1.1 8 | 2008-02-08 JRM Neatening, removing redundant interfaces 9 | 2007-10-29 JRM added addr_decode and addr_encode functions 10 | 11 | """ 12 | 13 | import struct, time, math 14 | 15 | def xeng_encode(freq,n_xeng=8, n_chans=2048,adc_clk=600,ddc_decimation=4,ddc_mix_freq=0.25): 16 | bandwidth = adc_clk/ddc_decimation 17 | center_freq = adc_clk*ddc_mix_freq 18 | start_freq = center_freq - bandwidth/2 19 | im = freq - start_freq 20 | chan = int((float(im)/bandwidth * n_chans)) 21 | out = dict() 22 | if (chan >= (n_chans/2)): 23 | chan = chan - (n_chans/2) 24 | else: 25 | chan = chan + (n_chans/2) 26 | out['chan'] = chan 27 | out['x_eng'] = int(chan % n_xeng) 28 | out['group'] = int(chan/n_xeng) 29 | return out 30 | 31 | def xeng_decode(x_eng,chan,n_xeng=8, n_chans=2048,adc_clk=600,ddc_decimation=4,ddc_mix_freq=0.25): 32 | bandwidth = float(adc_clk)/ddc_decimation 33 | chan_bw = bandwidth/n_chans 34 | print chan_bw 35 | center_freq = float(adc_clk)*ddc_mix_freq 36 | start_freq = center_freq - bandwidth/2 37 | freq_offset = x_eng * chan_bw 38 | freq = (chan*n_xeng)*chan_bw 39 | freq = freq + freq_offset 40 | if freq >= bandwidth/2: 41 | freq += start_freq 42 | else: 43 | freq += center_freq 44 | return freq 45 | 46 | def addr_decode(address,vector_len=18432): 47 | """Calculates which bank,row,rank,column and block a particular 48 | address maps to. Good for BEE2 1GB DRAMs.""" 49 | if vector_len > 512: 50 | bit_shift = int(math.ceil(math.log(float(vector_len)/512.0,2))) 51 | else: 52 | bit_shift = 1 53 | #print bit_shift 54 | #address = (2**20) + (2**29) +(2**13) 55 | out = dict() 56 | out['bank'] = (address & ((2**28) + (2**29)))>>28 57 | out['row'] = (address & ( ((2**28)-1) - ((2**14)-1) ))>>14 58 | out['rank'] = (address & (2**13))>>13 59 | out['col'] = (address & ( ((2**13)-1) - ((2**3)-1) ))>>3 60 | out['block'] = out['bank'] + ((out['row']>>bit_shift) <<2) + (out['rank']<<10) 61 | #print bank,row,rank,col,block 62 | return out 63 | 64 | def addr_encode(int_num=0,offset=0,vector_len=18432): 65 | """Calculates the address location in DRAM of an integration. 66 | int_num: the number of the integration you're looking for. 67 | offset: 68 | vector_len: Programmed length of the DRAM_VACC.""" 69 | if vector_len > 512: 70 | bit_shift = int(math.ceil(math.log(float(vector_len)/512.0,2))) 71 | else: 72 | bit_shift = 1 73 | 74 | block_row_bits = 14-bit_shift 75 | 76 | bank = int_num & 3 77 | block_row = (int_num >> 2) & ((2**block_row_bits)-1) 78 | rank = (int_num>>(block_row_bits + 2)) 79 | 80 | column = offset & ((2**9)-1) 81 | row_offset = (offset >> 9) 82 | 83 | address = (column << 4) + (rank<<13) + (row_offset << 14) + (block_row<<(14 + bit_shift)) + (bank << 28) 84 | 85 | #print bank,bit_shift, block_row, block_row_bits, rank, column, row_offset 86 | return address 87 | 88 | 89 | def ij2bl(i, j): 90 | """Convert i, j baseline notation (counting from 0) to Miriad's baseline 91 | notation (counting from 1, a 16 bit number).""" 92 | return ((i+1) << 8) | (j+1) 93 | 94 | def bl2ij(bl): 95 | """Convert from Miriad's baseline notation (counting from 1, a 16 bit 96 | number) to i, j baseline notation (counting from 0).""" 97 | return ((bl >> 8) & 255) - 1, (bl & 255) - 1 98 | 99 | def get_bl_order(n_ants): 100 | """Return the order of baseline data output by a CASPER correlator 101 | X engine.""" 102 | order1, order2 = [], [] 103 | for i in range(n_ants): 104 | for j in range(int(n_ants/2),-1,-1): 105 | k = (i-j) % n_ants 106 | if i >= k: order1.append((k, i)) 107 | else: order2.append((i, k)) 108 | order2 = [o for o in order2 if o not in order1] 109 | return tuple([o for o in order1 + order2]) 110 | 111 | def get_bl_order_sp(n_inputs): 112 | """Return the order of baseline data output by a dual-polarisation 113 | CASPER correlator X engine when remapped as a single pol system.""" 114 | dp_bls=get_bl_order(n_inputs/2) 115 | rv=[] 116 | for bl in dp_bls: 117 | rv.append(tuple((bl[0]*2,bl[1]*2))) 118 | rv.append(tuple((bl[0]*2+1,bl[1]*2+1))) 119 | rv.append(tuple((bl[0]*2,bl[1]*2+1))) 120 | rv.append(tuple((bl[0]*2+1,bl[1]*2))) 121 | return rv 122 | 123 | def encode_32bit(i, j, stokes, r_i, chan): 124 | """Encode baseline, stokes, real/imaginary, and frequency info as 125 | a 32 bit unsigned integer.""" 126 | return (r_i << 31) | (stokes << 29) | (chan << 16) | ij2bl(i,j) 127 | 128 | def decode_32bit(data): 129 | """Decode baseline, stokes, real/imaginary, and frequency info from 130 | a 32 bit number.""" 131 | i,j = bl2ij(data & (2**16-1)) 132 | freq = (data >> 16) & (2**13-1) 133 | stokes = (data >> 29) & 3 134 | r_i = (data >> 31) & 1 135 | return i, j , stokes, r_i, freq 136 | 137 | class XEngine: 138 | def __init__(self, nant=8, nchan=2048, npol=4, id=0, pktlen=2048, 139 | engine_id=0, instance_id=0, instrument_id=3, start_t=0, intlen=1): 140 | self.pktlen = pktlen 141 | self.engine_id = engine_id 142 | self.instance_id = instance_id 143 | self.instrument_id = instrument_id 144 | self.t = start_t 145 | self.intlen = intlen 146 | self.data = [] 147 | data = [encode_32bit(i,j,p, r_i, ch) \ 148 | for ch in range(engine_id,nchan,nant) \ 149 | for (i,j) in get_bl_order(nant) \ 150 | for p in range(npol) \ 151 | for r_i in [0,1] \ 152 | ] 153 | self.data = struct.pack('%dI' % len(data), *data) 154 | def init_pkt(self): 155 | pkt = CorrPacket() 156 | pkt.packet_len = self.pktlen 157 | pkt.packet_count = 1 158 | pkt.engine_id = self.engine_id 159 | pkt.instance_id = self.instance_id 160 | pkt.instrument_id = self.instrument_id 161 | pkt.currerr = 0 162 | return pkt 163 | def get_pkt_stream(self): 164 | c, L = 0, self.pktlen 165 | while True: 166 | pkt = self.init_pkt() 167 | pkt.heap_off = c * L 168 | noff = (c+1) * L 169 | pkt.timestamp = self.t 170 | d = self.data[pkt.heap_off:noff] 171 | pkt.set_data(d) 172 | pkt.packet_count = c 173 | yield pkt 174 | if noff >= len(self.data): 175 | c = 0 176 | self.t += self.intlen 177 | else: c += 1 178 | 179 | #class CorrSimulator: 180 | # def __init__(self, xengines=None, nant=8, nchan=2048, npol=4): 181 | # if xengines is None: xengines = range(nant) 182 | # self.xeng = xengines 183 | # self.bls = get_bl_order(nant) 184 | # self.nchan = nchan 185 | # self.npol = npol 186 | # data = n.zeros((len(self.bls), nchan/nant, npol, 2), dtype=n.uint32) 187 | # for c,(i,j) in enumerate(self.bls): data[c,...] = ij2bl(i,j) 188 | # ch = n.arange(0, nchan, nant, dtype=n.uint32) 189 | # ch = n.left_shift(ch, 16) 190 | # ch.shape = (1,nchan/nant,1,1) 191 | # for c,pol in enumerate(range(npol)): 192 | # data[:,:,c,...] = n.bitwise_or(data[:,:,c,...], (pol << 29)) 193 | # data[...,1] = n.bitwise_or(data[...,1], (1 << 31)) 194 | # self.data = data 195 | # def get_pkt(self): 196 | # """Generate data for a casper_n correlator. Each data 197 | # sample is encoded with the baseline, stokes, real/imag, frequency 198 | # that it represents.""" 199 | # #while True: 200 | # # data = self.data.copy() 201 | # # for c in range(self.nchan/nant 202 | # data = [] 203 | # # Loop through channels in X engine (spaced every n_ants channels) 204 | # for coarse_chan in range(n_chans/n_ants): 205 | # c = coarse_chan * n_ants + x_num 206 | # # Loop through baseline order out of X engine 207 | # for bl in bls: 208 | # # Loop through stokes parameters 209 | # for s in range(n_stokes): 210 | # # Real and imaginary components 211 | # for ri in (0, 1): 212 | # data.append(encode_32bit(bl, s, ri, c)) 213 | # fmt = '%s%dI' % (endian, len(data)) 214 | # return struct.pack(fmt, *data) 215 | # 216 | # 217 | # 218 | ##class PacketSimulator: 219 | ## def __init__(self, nant, nchan, npol): 220 | 221 | -------------------------------------------------------------------------------- /scripts/corr_nb_snap_soft_fine_fft.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # 4 | # Use the crs_snap data to do an n-channel fine FFT. 5 | # 6 | # Data out the coarse FFT is four parallel samples of 2 x f18.17 for each pol, which is 4 x 36 x 2 = 288 bits. 7 | # This is converted down to 2 x f16.15 for each sample and only the selected pol is stored by the snap block. 8 | # So that's 4 x 32 = 128 bits. Underneath that's four parallel freq channels, each f16.15 complex. 9 | # 10 | # So buffer up fine_chan of each of the specified channels and plot the FFT of that. 11 | # 12 | 13 | snap_len = 1024 14 | snap_len_bytes = 8192 15 | 16 | import optparse 17 | 18 | options = optparse.OptionParser() 19 | options.add_option("--verbose", "-v", action="store_true", help="Print extra info.", default = False) 20 | options.add_option("--fpga", "", type="int", help="Which f-engine FPGA? 0, 1, 2...", default = 0) 21 | options.add_option("--pol", "-p", type="int", help="Which pol? 0 or 1.", default = 0) 22 | options.add_option("--coarse_chans", "-c", type="string", help="A comma-delimited list of coarse channels to process.", default = "") 23 | options.add_option("--accumulations", "-a", type="int", help="How many accumulations must be done? Default: continue indefinitely.", default = -1) 24 | options.add_option("--finechans", "-f", type="int", help="Specify a different number of fine chans to that in the config file.", default = -1) 25 | options.add_option("--readfile", "-r", type="string", help="Read data from a file instead of from the devices.", default = "") 26 | options.add_option("--writefile", "-w", type="string", help="Write data to file.", default = "") 27 | options.add_option("--buffer", "-b", action="store_true", help="Use the hardware buffer output. Can only do preselected channel then.", default = False) 28 | options.add_option("--noplot", "", action="store_true", help="Don't plot the data.", default = False) 29 | opts, args = options.parse_args() 30 | 31 | opts.coarse_chans = opts.coarse_chans.strip() 32 | if opts.coarse_chans == "": 33 | raise RuntimeError("You must specify at least one coarse channel.") 34 | 35 | readfile = opts.readfile.strip() 36 | writefile = opts.writefile.strip() 37 | if readfile != "" and writefile != "": 38 | raise RuntimeError("Can't read from file and write to file at once. Makes no sense.") 39 | if readfile != "": 40 | try: 41 | f = open(readfile, 'r') 42 | except IOError: 43 | raise RuntimeError("Can't read from file:", readfile) 44 | f.close() 45 | print "Setting accumulations to 1." 46 | opts.accumulations = 1 47 | if writefile != "": 48 | f = None 49 | try: 50 | f = open(writefile, 'r') 51 | except IOError: 52 | donothing = True 53 | if f != None: 54 | f.close() 55 | raise RuntimeError("Cowardly refusing to overwrite file:", writefile) 56 | try: 57 | f = open(writefile, 'w') 58 | except IOError: 59 | raise RuntimeError("Can't write to file:", writefile) 60 | 61 | plot = True 62 | if opts.noplot: plot = False 63 | 64 | if args == []: 65 | raise RuntimeError("No corr config file specified. Please do so.") 66 | else: 67 | config_file = args[0] 68 | 69 | import corr, logging, numpy, time, sys 70 | 71 | def get_coarse_data(c, channels, snaps, pol): 72 | data = {} 73 | for chan in channels: 74 | data[chan] = [] 75 | ctr = 0 76 | print '\tGrabbing snapshot: %4i/%4i' % (ctr, snaps), 77 | while ctr < snaps: 78 | print 11 * '\b', '%4i/%4i' % (ctr, snaps), 79 | sys.stdout.flush() 80 | coarse_fft_data = corr.corr_nb.get_snap_coarse_fft(c, [c.ffpgas[opts.fpga]], pol)[0] 81 | for chan in channels: 82 | d = coarse_fft_data[chan::(c.config['coarse_chans'] * 2)] 83 | data[chan].extend(d) 84 | ctr+=1 85 | print '' 86 | return data 87 | 88 | def get_buffer_data(c, channel, pol): 89 | data = {} 90 | data[channel] = [] 91 | ctr = 0 92 | snaps_to_get = c.config['n_chans'] / snap_len 93 | print '\tGrabbing snapshot: %4i/%4i' % (ctr, snaps_to_get), 94 | while ctr < snaps_to_get: 95 | print 11 * '\b', '%4i/%4i' % (ctr, snaps_to_get), 96 | sys.stdout.flush() 97 | snap_data = corr.corr_nb.get_snap_fine_buffer(c = c, fpgas = [c.ffpgas[opts.fpga]], offset = ctr * snap_len_bytes)[0] 98 | data[channel].extend(snap_data[pol]) 99 | ctr+=1 100 | print '' 101 | return data 102 | 103 | def get_data_from_file(filename, channels): 104 | print "Reading from file", filename 105 | sys.stdout.flush() 106 | f = open(filename, 'r') 107 | data = {} 108 | while True: 109 | try: 110 | d = pickle.load(f) 111 | for k,e in d.items(): 112 | if data.has_key(k): 113 | data[k].extend(e) 114 | else: 115 | data[k] = e 116 | except EOFError: 117 | f.close() 118 | break 119 | for chan in channels: 120 | if data.keys().count(chan) == 0: 121 | print "\tWARNING: can't find requested channel %i in data from file, removing from channel list!" % chan 122 | channels.remove(chan) 123 | return data 124 | 125 | try: 126 | print 'Connecting to correlator...', 127 | c = corr.corr_functions.Correlator(config_file = config_file, log_level = logging.INFO, connect = False) 128 | if not c.is_narrowband(): 129 | raise RuntimeError("Only valid for narrowband modes.") 130 | c.connect() 131 | print 'done' 132 | 133 | if opts.finechans == -1: 134 | n_chans = c.config['n_chans'] 135 | else: 136 | n_chans = opts.finechans 137 | 138 | print 'WARNING - this script is gonna take ages.' 139 | snaps_per_fine_fft = n_chans / (snap_len / (c.config['coarse_chans'] * 2)) 140 | print 'Loading coarse data for one fine FFT. Need to read snap %i times.' % snaps_per_fine_fft 141 | 142 | channels = [] 143 | if opts.coarse_chans == "all": 144 | channels = range(0, c.config['coarse_chans']) 145 | else: 146 | for s in opts.coarse_chans.strip().split(','): 147 | channels.append(int(s)) 148 | print 'Will get data for', channels 149 | 150 | if plot: 151 | import pylab 152 | 153 | import pickle 154 | accum_counter = 0 155 | accumulated = {} 156 | for chan in channels: 157 | accumulated[chan] = numpy.array(numpy.zeros(n_chans)) 158 | while accum_counter < opts.accumulations or opts.accumulations == -1: 159 | print 'Reading snapshot set %i now.' % accum_counter 160 | sys.stdout.flush() 161 | data = {} 162 | 163 | # load data 164 | if readfile != "": 165 | data = get_data_from_file(readfile, channels) 166 | else: 167 | if opts.buffer: 168 | data = get_buffer_data(c, channels[0], opts.pol) 169 | else: 170 | data = get_coarse_data(c, channels, snaps_per_fine_fft, opts.pol) 171 | 172 | # write data to file 173 | if writefile != "": 174 | print '\tWriting to file', writefile, 175 | sys.stdout.flush() 176 | f = open(writefile, 'a') 177 | pickle.dump(data, f) 178 | f.close() 179 | print ', done.' 180 | sys.stdout.flush() 181 | 182 | # accumulate 183 | print 'Accumulating and FFTing...', 184 | sys.stdout.flush() 185 | for chan in channels: 186 | accums = len(data[chan])/n_chans 187 | print 'chan(%i,%i)' % (chan, accums), 188 | for ctr in range(0, accums): 189 | d = data[chan][ctr*n_chans : (ctr+1)*n_chans] 190 | fftd = numpy.fft.fft(d, n = n_chans) 191 | accumulated[chan] += numpy.array(abs(fftd)) 192 | #pwr = (fftd.real**2 + fftd.imag**2) ** 0.5 193 | #accumulated[chan] += numpy.array(pwr) 194 | del data 195 | print 'done.' 196 | 197 | accum_counter += 1 198 | 199 | # update the plots 200 | if plot: 201 | print 'Plotting...', 202 | sys.stdout.flush() 203 | pylab.cla() 204 | for chan in channels: 205 | length = len(accumulated[chan]) 206 | swapped = accumulated[chan][length/2:].tolist() 207 | swapped.extend(accumulated[chan][0:length/2].tolist()) 208 | swapped = numpy.array(swapped) 209 | pylab.plot(swapped / accum_counter) 210 | pylab.show() 211 | print 'done.' 212 | 213 | c.disconnect_all() 214 | 215 | except KeyboardInterrupt, RuntimeError: 216 | 217 | c.disconnect_all() 218 | 219 | # end 220 | 221 | -------------------------------------------------------------------------------- /src/katcp_serial.py: -------------------------------------------------------------------------------- 1 | """Client for communicating with a the PPCs 2nd Serial Port over KATCP. 2 | 3 | @author Simon Cross 4 | @modified Jason Manley 5 | @Revised 2010/11/08 to log incomming log informs 6 | @Revised 2010/06/28 to include qdr stuff 7 | @Revised 2010/01/07 to include bulkread 8 | @Revised 2009/12/01 to include print 10gbe core details. 9 | """ 10 | 11 | import struct, re, threading, socket, select, traceback, logging, sys, time, os 12 | 13 | from katcp import * 14 | log = logging.getLogger("katcp") 15 | 16 | 17 | #class SerialClient(BlockingClient): 18 | class SerialClient(CallbackClient): 19 | """Client for communicating with a the PCCs 2nd serial port. 20 | 21 | Notes: 22 | - All commands are blocking. 23 | - If there is no response to an issued command, an exception is thrown 24 | with appropriate message after a timeout waiting for the response. 25 | - If the TCP connection dies, an exception is thrown with an 26 | appropriate message. 27 | """ 28 | 29 | def __init__(self, host, port=7148, tb_limit=20, timeout=10.0, logger=log): 30 | """Create a basic DeviceClient. 31 | 32 | @param self This object. 33 | @param host String: host to connect to. 34 | @param port Integer: port to connect to. 35 | @param tb_limit Integer: maximum number of stack frames to 36 | send in error traceback. 37 | @param timeout Float: seconds to wait before timing out on 38 | client operations. 39 | @param logger Object: Logger to log to. 40 | """ 41 | super(SerialClient, self).__init__(host, port, tb_limit=tb_limit,timeout=timeout, logger=logger) 42 | self.host = host 43 | self._timeout = timeout 44 | self.start(daemon = True) 45 | 46 | # async stuff 47 | self._nb_request_id = 0 48 | self._nb_requests = {} 49 | self._nb_max_requests = 10 50 | 51 | """**********************************************************************************""" 52 | """**********************************************************************************""" 53 | 54 | def _nb_get_request_by_id(self, request_id): 55 | try: 56 | return self._nb_requests[request_id] 57 | except KeyError: 58 | return None 59 | 60 | def _nb_pop_request_by_id(self, request_id): 61 | try: 62 | return self._nb_requests.pop(request_id) 63 | except KeyError: 64 | return None 65 | 66 | def _nb_pop_oldest_request(self): 67 | req = self._nb_requests[self._nb_requests.keys()[0]] 68 | for k, v in self._nb_requests.iteritems(): 69 | if v.time_tx < req.time_tx: 70 | req = v 71 | return self._nb_pop_request_by_id(req.request_id) 72 | 73 | def _nb_get_request_result(self, request_id): 74 | req = self._nb_get_request_by_id(request_id) 75 | return req.reply, req.informs 76 | 77 | def _nb_add_request(self, request_name, request_id, inform_cb, reply_cb): 78 | if self._nb_requests.has_key(request_id): 79 | raise RuntimeError('Trying to add request with id(%s) but it already exists.' % request_id) 80 | self._nb_requests[request_id] = FpgaAsyncRequest(self.host, request_name, request_id, inform_cb, reply_cb) 81 | 82 | def _nb_get_next_request_id(self): 83 | self._nb_request_id += 1 84 | return str(self._nb_request_id) 85 | 86 | def _nb_replycb(self, msg, *userdata): 87 | """The callback for request replies. Check that the ID exists and call that request's got_reply function. 88 | """ 89 | request_id = ''.join(userdata) 90 | if not self._nb_requests.has_key(request_id): 91 | raise RuntimeError('Recieved reply for request_id(%s), but no such stored request.' % request_id) 92 | self._nb_requests[request_id].got_reply(msg.copy()) 93 | 94 | def _nb_informcb(self, msg, *userdata): 95 | """The callback for request informs. Check that the ID exists and call that request's got_inform function. 96 | """ 97 | request_id = ''.join(userdata) 98 | if not self._nb_requests.has_key(request_id): 99 | raise RuntimeError('Recieved inform for request_id(%s), but no such stored request.' % request_id) 100 | self._nb_requests[request_id].got_inform(msg.copy()) 101 | 102 | def _nb_request(self, request, inform_cb = None, reply_cb = None, *args): 103 | """Make a non-blocking request. 104 | @param self This object. 105 | @param request The request string. 106 | @param inform_cb An optional callback function, called upon receipt of every inform to the request. 107 | @param inform_cb An optional callback function, called upon receipt of the reply to the request. 108 | @param args Arguments to the katcp.Message object. 109 | """ 110 | if len(self._nb_requests) == self._nb_max_requests: 111 | oldreq = self._nb_pop_oldest_request() 112 | self._logger.info("Request list full, removing oldest one(%s,%s)." % (oldreq.request, oldreq.request_id)) 113 | print "Request list full, removing oldest one(%s,%s)." % (oldreq.request, oldreq.request_id) 114 | request_id = self._nb_get_next_request_id() 115 | self.request(msg = Message.request(request, *args), reply_cb = self._nb_replycb, inform_cb = self._nb_informcb, user_data = request_id) 116 | self._nb_add_request(request, request_id, inform_cb, reply_cb) 117 | return {'host': self.host, 'request': request, 'id': request_id} 118 | 119 | """**********************************************************************************""" 120 | """**********************************************************************************""" 121 | 122 | def _request(self, name, *args): 123 | """Make a blocking request and check the result. 124 | 125 | Raise an error if the reply indicates a request failure. 126 | 127 | @param self This object. 128 | @param name String: name of the request message to send. 129 | @param args List of strings: request arguments. 130 | @return Tuple: containing the reply and a list of inform messages. 131 | """ 132 | request = Message.request(name, *args) 133 | reply, informs = self.blocking_request(request) 134 | #reply, informs = self.blocking_request(request,keepalive=True) 135 | 136 | if reply.arguments[0] != Message.OK: 137 | self._logger.error("Request %s failed.\n Request: %s\n Reply: %s." 138 | % (request.name, request, reply)) 139 | 140 | raise RuntimeError("Request %s failed.\n Request: %s\n Reply: %s." 141 | % (request.name, request, reply)) 142 | return reply, informs 143 | 144 | def ping(self): 145 | """Tries to ping the FPGA. 146 | @param self This object. 147 | @return boolean: ping result. 148 | """ 149 | reply, informs = self._request("watchdog") 150 | if reply.arguments[0]=='ok': return True 151 | else: return False 152 | 153 | def setd(self,pin,state): 154 | """Sets a boolean value on a digital IO pin.""" 155 | if ((state in [0,1]) or (state in [True,False])): 156 | reply = self._request("setd",int(pin),int(state)) 157 | else: raise RuntimeError("Invalid state.") 158 | 159 | def seta(self,pin,val): 160 | """Starts a PWM signal on a digital IO pin. Pins 3, 5, 6, 9, 10 and 11 are supported. Valid range: 0-255.""" 161 | val_pins=[3,5,6,9,10,11] 162 | assert val in range(255), ("%i is an invalid PWM number. Valid PWM range is 0-255."%int(val)) 163 | assert pin in val_pins, "Invalid pin %i. Valid pins are %s."%(pin,val_pins) 164 | reply = self._request("seta",int(pin),int(val)) 165 | 166 | def geta(self,pin,smoothing=1): 167 | """Retrieve an ADC value, optionally smoothed over "smoothing" measurements.""" 168 | assert (smoothing in range(1,65)), "Can only smooth between 1 and 64 samples!" 169 | assert (pin in range(8)), "Invalid analogue pin selected. Choose in range(0,8)!" 170 | return int(self._request("geta",int(pin),int(smoothing)).arguments[1]) 171 | 172 | def getd(self,pin): 173 | """Gets a boolean value on a digital IO pin.""" 174 | return int(self._request("getd",int(pin)).arguments[1]) 175 | 176 | def set_atten_db(self,le_pin,data_pin,clk_pin,atten_db=31): 177 | """Sets the db of a serial minicircuits attenuator with a range of 0-31.5 db of attenuation""" 178 | atten_db = int(atten_db*2) 179 | assert atten_db in range(0,63), "Invalid db value %i. Valid range is 0 to 31.5dB."%(atten_db/2.) 180 | self.setd(le_pin,0) 181 | self.setd(clk_pin,0) 182 | for bit in range(5,-1,-1): 183 | self.setd(data_pin,(atten_db>>bit)&1) 184 | self.setd(clk_pin,1) 185 | self.setd(clk_pin,0) 186 | self.setd(le_pin,1) 187 | self.setd(le_pin,0) 188 | -------------------------------------------------------------------------------- /etc/default: -------------------------------------------------------------------------------- 1 | #NO WHITESPACE BETWEEN TEXT DELIMITERS! 2 | #This is a sample config file for KAT7 lab system in South Africa with 8 dual-pol antennas on 16 ROACH boards all plugged into 10GbE switch with 10GbE output. 3 | #Some fields will be automatically overwritten when corr_init is run. 4 | 5 | [katcp] 6 | #List of servers to be used for F/X engines. Comma separated list with no whitespace. 7 | servers_f = roach030268,roach030279,roach030265,roach030203,roach030276,roach030269,roach030267,roach030277 8 | servers_x = roach030274,roach030271,roach030270,roach030273,roach030266,roach030263,roach030275,roach030196 9 | #This is the control port to use when communicating with BORPH. By default, ROACHes use 7147. 10 | katcp_port = 7147 11 | #bitstream to load the FPGAs. Should be present and load-able by ROACH's KATCP server - corr will not do this for you 12 | bitstream_f = r_128w_1024_11_1a_r418_2011_Jul_21_1621.bof 13 | bitstream_x = r_1f_2bx_8a_1k_r358_2013_Jan_07_1005.bof 14 | 15 | [correlator] 16 | # the correlator mode - wbc = wideband, nbc = narrowband, nbch1 = narrowband_ddc h1 mode 17 | mode = wbc 18 | #type of ADC. katadc or iadc. 19 | adc_type = katadc 20 | #number of frequency channels 21 | n_chans = 1024 22 | #number of antennas in the design. 23 | n_ants = 8 24 | #fft shifting schedule in decimal. A binary '1' shifts, a zero does not. 25 | fft_shift = 252 26 | #Number of spectra to integrate in DRAM. 27 | acc_len = 3051 28 | #Number of accumulations performed in the X engine cores. 29 | xeng_acc_len = 128 30 | #Clockrate of ADCs in Hz. 31 | adc_clk = 800000000 32 | ##Number of stokes parameters calculated. Currently only fully supports n_stokes=4. 33 | #n_stokes = 4 34 | #Number of X engines per FPGA 35 | x_per_fpga = 2 36 | #Mixing freqency as a fraction of the sampling frequency. (the DDC block in the F engines). eg, 0.25. Set to zero if no DDC is present. 37 | ddc_mix_freq = 0 38 | #Frequency decimation of the DDC block in the F engines. eg, 4. Set to 1 if no DDC present. 39 | ddc_decimation = 1 40 | #Number of quantisation bits post FFT in the F engines. feng_bits=4 is the only fully supported config option at present. 41 | feng_bits = 4 42 | #Logical binary point position of F engine data. Normally feng_bits-1. 43 | feng_fix_pnt_pos = 3 44 | #pkt len of 10GbE exchange data in 64 bit words. 45 | 10gbe_pkt_len = 32 46 | #Starting ip address to use for FPGA cores (will be auto-incremented for different x engines and auto decremented for F engines) 47 | 10gbe_ip = 10.0.0.128 48 | #UDP data port to use for 10GbE cores. 49 | 10gbe_port = 8888 50 | #clock rate in MHz for X engine boards. 51 | xeng_clk = 210 52 | #Number of accumulations used during ADC amplitude averaging. 53 | adc_levels_acc_len = 65536 54 | #Number of bits in ADC 55 | adc_bits = 8 56 | #Xengine output format. Interleaved (inter) or contiguous (cont). 57 | xeng_format = cont 58 | #how does data exit the F engines? xaui or 10gbe. 59 | feng_out_type = 10gbe 60 | #Number of dual-pol antennas' data coming over one link from the F engines (ie per 10GbE or XAUI cable) 61 | n_ants_per_xaui = 1 62 | #Number of XAUI ports in use per X engine FPGA 63 | n_xaui_ports_per_xfpga = 1 64 | #Number of XAUI or 10GbE ports in use per F engine FPGA 65 | n_xaui_ports_per_ffpga = 1 66 | #Number of bits used in the F engine for timekeeping (the master counter) 67 | mcnt_bits = 48 68 | #number of bits used in the packet header for timestamping 69 | pcnt_bits = 48 70 | # the sync period set in the f-engine design. used for f-engine arming. this default is for WIDEBAND! 71 | feng_sync_period = 134217728 72 | # the number of 1PPS pulses that we expect to elapse between arming the system and actually triggering. This is usually 2, to allow any sync pulses in the pipeline to flush before resyncing. 73 | feng_sync_delay = 2 74 | 75 | [beamformer] 76 | 77 | #calibration type (complex or scalar) 78 | bf_cal_type=complex 79 | #Default values for calibration derived from eq_poly values (poly) or set to eq_coeff values (coef). 80 | bf_cal_default=poly 81 | 82 | # prefix for beamformer related registers 83 | bf_register_prefix = bf 84 | #b-engines per fpga 85 | bf_be_per_fpga = 2 86 | # data type can be raw or visibilities 87 | bf_data_type = raw 88 | #number of beams per beamformer 89 | bf_n_beams_per_be = 2 90 | #complex data output format 91 | bf_bits_out = 8 92 | # number of beams (each polarisation is treated as a separate beam) 93 | # beam id (and subset id) is inserted into HEAP_CNT in SPEAD stream 94 | bf_n_beams = 2 95 | 96 | # beam name 97 | bf_name_beam0 = i 98 | #physical beam offset 99 | bf_location_beam0 = 0 100 | # center frequency of beams (will be subject to quantization) 101 | bf_centre_frequency_beam0 = 200000000 102 | # bandwidth of beams (will be subject to quantization) 103 | bf_bandwidth_beam0 = 400000000 104 | # ip to send SPEAD meta data to 105 | bf_rx_meta_ip_str_beam0 = 10.0.0.2 106 | # destination for SPEAD data 107 | bf_rx_udp_ip_str_beam0 = 10.0.0.2 108 | bf_rx_udp_port_beam0 = 7148 109 | 110 | bf_cal_poly_input0_beam0 = 1 111 | bf_cal_poly_input1_beam0 = 1 112 | bf_cal_poly_input2_beam0 = 1 113 | bf_cal_poly_input3_beam0 = 1 114 | bf_cal_poly_input4_beam0 = 1 115 | bf_cal_poly_input5_beam0 = 1 116 | bf_cal_poly_input6_beam0 = 1 117 | bf_cal_poly_input7_beam0 = 1 118 | bf_cal_poly_input8_beam0 = 1 119 | bf_cal_poly_input9_beam0 = 1 120 | bf_cal_poly_input10_beam0 = 1 121 | bf_cal_poly_input11_beam0 = 1 122 | bf_cal_poly_input12_beam0 = 1 123 | bf_cal_poly_input13_beam0 = 1 124 | bf_cal_poly_input14_beam0 = 1 125 | bf_cal_poly_input15_beam0 = 1 126 | 127 | # beam name 128 | bf_name_beam1 = q 129 | #physical beam offset 130 | bf_location_beam1 = 1 131 | # center frequency of beams (will be subject to quantization) 132 | bf_centre_frequency_beam1 = 200000000 133 | # bandwidth of beams (will be subject to quantization) 134 | bf_bandwidth_beam1 = 400000000 135 | # ip to send SPEAD meta data to 136 | bf_rx_meta_ip_str_beam1 = 127.0.0.1 137 | #SPEAD data output 138 | bf_rx_udp_ip_str_beam1 = 10.0.0.2 139 | bf_rx_udp_port_beam1 = 7148 140 | bf_cal_poly_input0_beam1 = 1 141 | bf_cal_poly_input1_beam1 = 1 142 | bf_cal_poly_input2_beam1 = 1 143 | bf_cal_poly_input3_beam1 = 1 144 | bf_cal_poly_input4_beam1 = 1 145 | bf_cal_poly_input5_beam1 = 1 146 | bf_cal_poly_input6_beam1 = 1 147 | bf_cal_poly_input7_beam1 = 1 148 | bf_cal_poly_input8_beam1 = 1 149 | bf_cal_poly_input9_beam1 = 1 150 | bf_cal_poly_input10_beam1 = 1 151 | bf_cal_poly_input11_beam1 = 1 152 | bf_cal_poly_input12_beam1 = 1 153 | bf_cal_poly_input13_beam1 = 1 154 | bf_cal_poly_input14_beam1 = 1 155 | bf_cal_poly_input15_beam1 = 1 156 | 157 | [receiver] 158 | #How is data to be retrieved from the correlator? either ppc or 10GbE. Only 10GbE is fully (ie automatically) supported. ppc will require manual intervention with the cn_tx.py script. 159 | out_type = 10gbe 160 | #spead flavour. string in the form XX,YY. Default: 64,40. consult the SPEAD documentation for details. Only 64-40 tested. 161 | spead_flavour=64,40 162 | #UDP receiver for output data 163 | rx_udp_ip = 10.0.0.2 164 | rx_udp_port = 7148 165 | rx_meta_ip = 127.0.0.1 166 | #Output packet payload length in bytes. Does not include SPEAD options fields. 167 | rx_pkt_payload_len = 4096 168 | #signal display config: 169 | sig_disp_ip = 127.0.0.1 170 | sig_disp_port=7149 171 | 172 | [equalisation] 173 | #Decimation. Adjacent frequency channels share coefficients. The center equalisation value is chosen for adjacent bins. n_eq_coeffs_per_polarisation == n_chans/eq_decimation 174 | eq_decimation=1 175 | #Equaliser type (complex or scalar) 176 | eq_type=complex 177 | #Default values for equaliser (digital gain) derived from eq_poly values (poly) or set to eq_coeff values (coef). 178 | eq_default=poly 179 | #Tolerance to use for auto-equalization 180 | tolerance = 0.01 181 | 182 | #rf_gain sets the analogue attenuators on the ADCs. Acceptible range on KATADCs is -11 to +22 in 0.5dB steps. 183 | #the antenna string must match your /var/run/corr/antenna_mapping contents! 184 | rf_gain_0 = 4 185 | rf_gain_1 = 4 186 | rf_gain_2 = 4 187 | rf_gain_3 = 4 188 | rf_gain_4 = 4 189 | rf_gain_5 = 4 190 | rf_gain_6 = 4 191 | rf_gain_7 = 4 192 | rf_gain_8 = 4 193 | rf_gain_9 = 4 194 | rf_gain_10 = 4 195 | rf_gain_11 = 4 196 | rf_gain_12 = 4 197 | rf_gain_13 = 4 198 | rf_gain_14 = 4 199 | rf_gain_15 = 4 200 | 201 | #The eq_poly lines are used for setting the equalisers using a polynomial. 202 | #One line entry per input. Item is a list of polynomial coefficients. 203 | #the antenna string must match your /var/run/corr/antenna_mapping contents exactly! 204 | #Eg, 205 | #eq_poly_0x = 10,30,40 206 | #corresponds to 10c^2 + 30c + 40 where c is the frequency channel index. 207 | #In the event of complex equaliser types, these values are applied to both the real and imaginary components (ie scalar). If you want to be able to configure these coefficients separately, use the eq_coeff configuration mode. 208 | eq_poly_0 = 300 209 | eq_poly_1 = 300 210 | eq_poly_2 = 300 211 | eq_poly_3 = 300 212 | eq_poly_4 = 300 213 | eq_poly_5 = 300 214 | eq_poly_6 = 300 215 | eq_poly_7 = 300 216 | eq_poly_8 = 300 217 | eq_poly_9 = 300 218 | eq_poly_10 = 300 219 | eq_poly_11 = 300 220 | eq_poly_12 = 300 221 | eq_poly_13 = 300 222 | eq_poly_14 = 300 223 | eq_poly_15 = 300 224 | #The eq_coeff lines are used for setting the equalisers manually, specifying each frequency channel for every polarisation input. 225 | #Each line should have n_chans/eq_decimation entries. 226 | #Entries are python lists (comma separated values within square brackets). 227 | #eg eq_coeff_0x=[1,2,3,4] 228 | -------------------------------------------------------------------------------- /scripts/corr_snap_feng_10gbe_tx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ''' 4 | Grabs the contents of "snap_gbe_tx" in the F engines for analysis. 5 | Assumes the correlator is already initialsed and running etc. 6 | 7 | ''' 8 | import corr, time, numpy, struct, sys, logging 9 | 10 | def exit_fail(): 11 | print 'FAILURE DETECTED. Log entries:\n',c.log_handler.printMessages() 12 | print "Unexpected error:", sys.exc_info() 13 | try: 14 | c.disconnect_all() 15 | except: pass 16 | time.sleep(1) 17 | raise 18 | exit() 19 | 20 | def exit_clean(): 21 | try: 22 | c.disconnect_all() 23 | except: pass 24 | exit() 25 | 26 | def feng_unpack(f, hdr_index, pkt_len): 27 | hdr_64bit = snap_data[f]['data'][hdr_index].data 28 | pkt_mcnt = (hdr_64bit) >> 16 29 | pkt_ant = hdr_64bit & ((2**16) - 1) 30 | pkt_freq = pkt_mcnt % c.config['n_chans'] 31 | exp_xeng = pkt_freq / (c.config['n_chans'] / c.config['n_xeng']) 32 | 33 | sum_polQ_r = 0 34 | sum_polQ_i = 0 35 | sum_polI_r = 0 36 | sum_polI_i = 0 37 | 38 | # average the packet contents - ignore first entry (header) 39 | for pkt_index in range(1, pkt_len): 40 | pkt_64bit = snap_data[f]['data'][hdr_index + pkt_index].data 41 | for offset in range(0, 64, 16): 42 | polQ_r = (pkt_64bit & ((2**(offset+16)) - (2**(offset+12))))>>(offset+12) 43 | polQ_i = (pkt_64bit & ((2**(offset+12)) - (2**(offset+8))))>>(offset+8) 44 | polI_r = (pkt_64bit & ((2**(offset+8)) - (2**(offset+4))))>>(offset+4) 45 | polI_i = (pkt_64bit & ((2**(offset+4)) - (2**(offset))))>>offset 46 | # square each number and then sum it 47 | sum_polQ_r += (float(((numpy.int8(polQ_r << 4)>> 4)))/(2**binary_point))**2 48 | sum_polQ_i += (float(((numpy.int8(polQ_i << 4)>> 4)))/(2**binary_point))**2 49 | sum_polI_r += (float(((numpy.int8(polI_r << 4)>> 4)))/(2**binary_point))**2 50 | sum_polI_i += (float(((numpy.int8(polI_i << 4)>> 4)))/(2**binary_point))**2 51 | 52 | num_accs = (pkt_len-1)*(64/16) 53 | 54 | level_polQ_r = numpy.sqrt(float(sum_polQ_r)/ num_accs) 55 | level_polQ_i = numpy.sqrt(float(sum_polQ_i)/ num_accs) 56 | level_polI_r = numpy.sqrt(float(sum_polI_r)/ num_accs) 57 | level_polI_i = numpy.sqrt(float(sum_polI_i)/ num_accs) 58 | 59 | rms_polQ = numpy.sqrt(((level_polQ_r)**2) + ((level_polQ_i)**2)) 60 | rms_polI = numpy.sqrt(((level_polI_r)**2) + ((level_polI_i)**2)) 61 | 62 | if level_polQ_r < 1.0/(2**num_bits): 63 | ave_bits_used_Q_r = 0 64 | else: 65 | ave_bits_used_Q_r = numpy.log2(level_polQ_r*(2**binary_point)) 66 | 67 | if level_polQ_i < 1.0/(2**num_bits): 68 | ave_bits_used_Q_i = 0 69 | else: 70 | ave_bits_used_Q_i = numpy.log2(level_polQ_i*(2**binary_point)) 71 | 72 | if level_polI_r < 1.0/(2**num_bits): 73 | ave_bits_used_I_r = 0 74 | else: 75 | ave_bits_used_I_r = numpy.log2(level_polI_r*(2**binary_point)) 76 | 77 | if level_polI_i < 1.0/(2**num_bits): 78 | ave_bits_used_I_i = 0 79 | else: 80 | ave_bits_used_I_i = numpy.log2(level_polI_i*(2**binary_point)) 81 | 82 | return {'pkt_mcnt': pkt_mcnt,\ 83 | 'pkt_freq':pkt_freq,\ 84 | 'pkt_ant':pkt_ant,\ 85 | 'exp_xeng':exp_xeng,\ 86 | 'rms_polQ':rms_polQ,\ 87 | 'rms_polI':rms_polI,\ 88 | 'ave_bits_used_Q_r':ave_bits_used_Q_r,\ 89 | 'ave_bits_used_Q_i':ave_bits_used_Q_i,\ 90 | 'ave_bits_used_I_r':ave_bits_used_I_r,\ 91 | 'ave_bits_used_I_i':ave_bits_used_I_i} 92 | 93 | if __name__ == '__main__': 94 | from optparse import OptionParser 95 | 96 | p = OptionParser() 97 | p.set_usage('%prog [options] CONFIG_FILE') 98 | p.set_description(__doc__) 99 | p.add_option('-c', '--raw', dest='raw', action='store_true', default = False, 100 | help='Capture clock-for-clock data (ignore external valids on snap block, same as man_valid = True).') 101 | p.add_option('-t', '--man_trigger', dest='man_trigger', action='store_true', default = False, 102 | help='Trigger the snap block manually') 103 | p.add_option('-o', '--offset', dest='offset', type = 'int', default = -1, 104 | help='Specify an offset into the data at which to start capturing.') 105 | p.add_option('-v', '--verbose', dest='verbose', action='store_true', 106 | help='Be Verbose; print raw packet contents.') 107 | p.add_option('-n', '--core_n', dest='core_n', type='int', default=0, 108 | help='Core number to decode. Default 0.') 109 | opts, args = p.parse_args(sys.argv[1:]) 110 | if args == []: 111 | config_file = None 112 | else: 113 | config_file = args[0] 114 | verbose = opts.verbose 115 | 116 | try: 117 | print 'Connecting...', 118 | c = corr.corr_functions.Correlator(config_file = config_file, log_level = logging.DEBUG if verbose else logging.INFO, connect = False) 119 | 120 | if not c.is_wideband(): 121 | raise RuntimeError('Only valid for wideband.') 122 | exit_fail() 123 | 124 | c.connect() 125 | print 'done' 126 | print '------------------------' 127 | 128 | dev_name = 'snap_gbe_tx%i' % opts.core_n 129 | binary_point = c.config['feng_fix_pnt_pos'] 130 | num_bits = c.config['feng_bits'] 131 | packet_len=c.config['10gbe_pkt_len'] 132 | n_ants = c.config['n_ants'] 133 | 134 | print 'Grabbing and unpacking snap data from F engines... ', 135 | 136 | #TODO: add check to make sure this is a 10gbe design (as opposed to a xaui link) 137 | servers = c.fsrvs 138 | snap_data = corr.snap.get_gbe_tx_snapshot_feng(c, offset = opts.offset, man_trigger = opts.man_trigger, man_valid = opts.raw) 139 | #snap_data = corr.corr_nb.get_snap_feng_10gbe(c, offset = opts.offset, man_trigger = opts.man_trigger, man_valid = opts.raw) 140 | print 'done.' 141 | 142 | report = dict() 143 | print 'Analysing packets:' 144 | for s in snap_data: 145 | f = s['fpga_index'] 146 | report[f] = dict() 147 | report[f]['pkt_total'] = 0 148 | pkt_len = 0 149 | prev_eof_index = -1 150 | report[f]['fpga_index'] = f 151 | 152 | for i in range(len(s['data'])): 153 | if opts.verbose or opts.raw: 154 | pkt_64bit = s['data'][i].data 155 | print '[%s] IDX: %i Contents: %016x' % (servers[f], i, pkt_64bit), 156 | print '[%s]' % corr.corr_functions.ip2str(s['data'][i].ip_addr), 157 | if s['data'][i].valid: print '[valid]', 158 | if s['data'][i].link_up: print '[link up]', 159 | if s['data'][i].led_tx: print '[led tx]', 160 | if s['data'][i].tx_full: print '[TX buffer full]', 161 | if s['data'][i].tx_over: print '[TX buffer OVERFLOW]', 162 | if s['data'][i].eof: print '[EOF]', 163 | print '' 164 | 165 | if s['data'][i].eof and not opts.raw: 166 | pkt_ip_str = corr.corr_functions.ip2str(s['data'][i].ip_addr) 167 | print '[%s] EOF at %4i. Dest: %12s. Len: %3i. ' % (servers[f], i, pkt_ip_str, i - prev_eof_index), 168 | report[f]['pkt_total'] += 1 169 | hdr_index = prev_eof_index + 1 170 | pkt_len = i - prev_eof_index 171 | prev_eof_index = i 172 | 173 | if not report[f].has_key('dest_ips'): 174 | report[f].update({'dest_ips':{pkt_ip_str:1}}) 175 | elif report[f]['dest_ips'].has_key(pkt_ip_str): 176 | report[f]['dest_ips'][pkt_ip_str] += 1 177 | else: 178 | report[f]['dest_ips'].update({pkt_ip_str:1}) 179 | 180 | if pkt_len != packet_len + 1: 181 | print 'Malformed Fengine Packet' 182 | if not report[f].has_key('Malformed F-engine Packets'): 183 | report[f]['Malformed F-engine Packets'] = 1 184 | else: 185 | report[f]['Malformed F-engine Packets'] += 1 186 | else: 187 | feng_unpkd_pkt = feng_unpack(f, hdr_index, pkt_len) 188 | 189 | ## Record the reception of the packet for this antenna, with this mcnt 190 | #try: mcnts[f][feng_unpkd_pkt['pkt_mcnt']][feng_unpkd_pkt['pkt_ant']]=i 191 | #except: 192 | # mcnts[f][feng_unpkd_pkt['pkt_mcnt']]=numpy.zeros(n_ants,numpy.int) 193 | # mcnts[f][feng_unpkd_pkt['pkt_mcnt']][feng_unpkd_pkt['pkt_ant']]=i 194 | #print mcnts 195 | print 'HDR @ %4i. MCNT %12u. Freq: %4i (X:%3i). Ant: %3i. 4 bit power: PolQ: %4.2f, PolI: %4.2f' % (hdr_index, feng_unpkd_pkt['pkt_mcnt'], feng_unpkd_pkt['pkt_freq'],feng_unpkd_pkt['exp_xeng'], feng_unpkd_pkt['pkt_ant'], feng_unpkd_pkt['rms_polQ'], feng_unpkd_pkt['rms_polI']) 196 | 197 | if not report[f].has_key('Antenna%i' % feng_unpkd_pkt['pkt_ant']): 198 | report[f]['Antenna%i' % feng_unpkd_pkt['pkt_ant']] = 1 199 | else: 200 | report[f]['Antenna%i' % feng_unpkd_pkt['pkt_ant']] += 1 201 | 202 | print '\n\nDone with all servers.\nSummary:\n==========================' 203 | for k, r in report.iteritems(): 204 | keys = report[k].keys() 205 | keys.sort() 206 | srvr = servers[r['fpga_index']] 207 | print '------------------------' 208 | print srvr 209 | print '------------------------' 210 | for key in keys: 211 | print key,': ', r[key] 212 | print '==========================' 213 | 214 | except KeyboardInterrupt: 215 | exit_clean() 216 | except: 217 | exit_fail() 218 | 219 | exit_clean() 220 | -------------------------------------------------------------------------------- /bak/corr_snap_10gbe_tx_out_imcomplete_old.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ''' 4 | Grabs the contents of "snap_gbe_tx" from F engines for analysis. This is for 10GbE output F engines only. Otherwise, use the XAUI script! It doesn't have a way of asking for packets for a specific channel (TODO!) so it just keeps grabbing data, integrating and adding to the spectrum. 5 | Assumes the correlator is already initialsed and running etc. 6 | 7 | ''' 8 | import corr, time, numpy, struct, sys, logging 9 | 10 | def exit_fail(): 11 | print 'FAILURE DETECTED. Log entries:\n',c.log_handler.printMessages() 12 | print "Unexpected error:", sys.exc_info() 13 | try: 14 | c.disconnect_all() 15 | except: pass 16 | time.sleep(1) 17 | raise 18 | exit() 19 | 20 | def exit_clean(): 21 | try: 22 | c.disconnect_all() 23 | except: pass 24 | exit() 25 | 26 | def feng_unpack(f, hdr_index, pkt_len): 27 | pkt_64bit = snap_data[f]['data'][hdr_index].data 28 | # pkt_mcnt = (pkt_64bit&((2**64)-(2**16)))>>16 29 | pkt_mcnt = (pkt_64bit) >> 16 30 | pkt_ant = pkt_64bit & ((2**16) - 1) 31 | pkt_freq = pkt_mcnt % n_chans 32 | exp_xeng = pkt_freq / (n_chans / n_xengs) 33 | 34 | sum_polQ_r = 0 35 | sum_polQ_i = 0 36 | sum_polI_r = 0 37 | sum_polI_i = 0 38 | 39 | # average the packet contents - ignore first entry (header) 40 | for pkt_index in range(1, pkt_len): 41 | pkt_64bit = snap_data[f]['data'][pkt_index].data 42 | 43 | for offset in range(0,64,16): 44 | polQ_r = (pkt_64bit & ((2**(offset+16)) - (2**(offset+12))))>>(offset+12) 45 | polQ_i = (pkt_64bit & ((2**(offset+12)) - (2**(offset+8))))>>(offset+8) 46 | polI_r = (pkt_64bit & ((2**(offset+8)) - (2**(offset+4))))>>(offset+4) 47 | polI_i = (pkt_64bit & ((2**(offset+4)) - (2**(offset))))>>offset 48 | # square each number and then sum it 49 | sum_polQ_r += (float(((numpy.int8(polQ_r << 4)>> 4)))/(2**binary_point))**2 50 | sum_polQ_i += (float(((numpy.int8(polQ_i << 4)>> 4)))/(2**binary_point))**2 51 | sum_polI_r += (float(((numpy.int8(polI_r << 4)>> 4)))/(2**binary_point))**2 52 | sum_polI_i += (float(((numpy.int8(polI_i << 4)>> 4)))/(2**binary_point))**2 53 | 54 | num_accs = (pkt_len-1)*(64/16) 55 | 56 | level_polQ_r = numpy.sqrt(float(sum_polQ_r)/ num_accs) 57 | level_polQ_i = numpy.sqrt(float(sum_polQ_i)/ num_accs) 58 | level_polI_r = numpy.sqrt(float(sum_polI_r)/ num_accs) 59 | level_polI_i = numpy.sqrt(float(sum_polI_i)/ num_accs) 60 | 61 | rms_polQ = numpy.sqrt(((level_polQ_r)**2) + ((level_polQ_i)**2)) 62 | rms_polI = numpy.sqrt(((level_polI_r)**2) + ((level_polI_i)**2)) 63 | 64 | if level_polQ_r < 1.0/(2**num_bits): 65 | ave_bits_used_Q_r = 0 66 | else: 67 | ave_bits_used_Q_r = numpy.log2(level_polQ_r*(2**binary_point)) 68 | 69 | if level_polQ_i < 1.0/(2**num_bits): 70 | ave_bits_used_Q_i = 0 71 | else: 72 | ave_bits_used_Q_i = numpy.log2(level_polQ_i*(2**binary_point)) 73 | 74 | if level_polI_r < 1.0/(2**num_bits): 75 | ave_bits_used_I_r = 0 76 | else: 77 | ave_bits_used_I_r = numpy.log2(level_polI_r*(2**binary_point)) 78 | 79 | if level_polI_i < 1.0/(2**num_bits): 80 | ave_bits_used_I_i = 0 81 | else: 82 | ave_bits_used_I_i = numpy.log2(level_polI_i*(2**binary_point)) 83 | 84 | return {'pkt_mcnt': pkt_mcnt,\ 85 | 'pkt_freq':pkt_freq,\ 86 | 'pkt_ant':pkt_ant,\ 87 | 'exp_xeng':exp_xeng,\ 88 | 'rms_polQ':rms_polQ,\ 89 | 'rms_polI':rms_polI,\ 90 | 'ave_bits_used_Q_r':ave_bits_used_Q_r,\ 91 | 'ave_bits_used_Q_i':ave_bits_used_Q_i,\ 92 | 'ave_bits_used_I_r':ave_bits_used_I_r,\ 93 | 'ave_bits_used_I_i':ave_bits_used_I_i} 94 | 95 | if __name__ == '__main__': 96 | from optparse import OptionParser 97 | 98 | p = OptionParser() 99 | p.set_usage('%prog [options] CONFIG_FILE') 100 | p.set_description(__doc__) 101 | p.add_option('-c', '--raw', dest='raw', action='store_true', 102 | help='Capture clock-for-clock data (ignore external valids on snap block).') 103 | p.add_option('-t', '--man_trigger', dest='man_trigger', action='store_true', 104 | help='Trigger the snap block manually') 105 | p.add_option('-v', '--verbose', dest='verbose', action='store_true', 106 | help='Be Verbose; print raw packet contents.') 107 | p.add_option('-n', '--core_n', dest='core_n', type='int', default=0, 108 | help='Core number to decode. Default 0.') 109 | opts, args = p.parse_args(sys.argv[1:]) 110 | if opts.man_trigger: 111 | man_trig = True 112 | else: 113 | man_trig = False 114 | 115 | if opts.raw: 116 | man_valid = True 117 | else: 118 | man_valid = False 119 | if args == []: 120 | config_file = None 121 | else: 122 | config_file = args[0] 123 | verbose = opts.verbose 124 | 125 | if not (opts.engine == 'x' or opts.engine == 'f'): 126 | print 'Can only choose F- or X-engines. (x or f)' 127 | exit_fail() 128 | 129 | try: 130 | print 'Connecting...', 131 | c = corr.corr_functions.Correlator(config_file = config_file, log_level = logging.DEBUG if verbose else logging.INFO, connect = False) 132 | c.connect() 133 | print 'done' 134 | 135 | if opts.man_trigger: 136 | man_ctrl = (1<<1)+1 137 | else: 138 | man_ctrl = 1 139 | if opts.raw: 140 | man_ctrl += (1<<2) 141 | 142 | print '------------------------' 143 | 144 | dev_name = 'snap_gbe_tx%i' % opts.core_n 145 | binary_point = c.config['feng_fix_pnt_pos'] 146 | num_bits = c.config['feng_bits'] 147 | packet_len=c.config['10gbe_pkt_len'] 148 | n_ants = c.config['n_ants'] 149 | n_chans = c.config['n_chans'] 150 | n_xengs = c.config['n_xeng'] 151 | n_ants_per_ibob=c.config['n_ants_per_xaui'] 152 | 153 | print 'Grabbing and unpacking snap data... ', 154 | if opts.engine == 'x': 155 | servers = c.xsrvs 156 | snap_data = corr.snap.get_gbe_tx_snapshot_xeng(c) 157 | elif opts.engine == 'f': 158 | servers = c.fsrvs 159 | snap_data = corr.snap.get_gbe_tx_snapshot_feng(c) 160 | print 'done.' 161 | 162 | report = dict() 163 | print 'Analysing packets:' 164 | for s in snap_data: 165 | f = s['fpga_index'] 166 | report[f] = dict() 167 | report[f]['pkt_total'] = 0 168 | pkt_len = 0 169 | prev_eof_index = -1 170 | report[f]['fpga_index'] = f 171 | 172 | for i in range(len(s['data'])): 173 | if opts.verbose or opts.raw: 174 | pkt_64bit = s['data'][i].data 175 | print '[%s] IDX: %i Contents: %016x' % (servers[f], i, pkt_64bit), 176 | print '[%s]' % corr.corr_functions.ip2str(s['data'][i].ip_addr), 177 | if s['data'][i].valid: print '[valid]', 178 | if s['data'][i].link_up: print '[link up]', 179 | if s['data'][i].led_tx: print '[led tx]', 180 | if s['data'][i].tx_full: print '[TX buffer full]', 181 | if s['data'][i].tx_over: print '[TX buffer OVERFLOW]', 182 | if s['data'][i].eof: print '[EOF]', 183 | print '' 184 | 185 | if s['data'][i].eof and not opts.raw: 186 | pkt_ip_str = corr.corr_functions.ip2str(s['data'][i].ip_addr) 187 | print '[%s] EOF at %4i. Dest: %12s. Len: %3i. ' % (servers[f], i, pkt_ip_str, i - prev_eof_index), 188 | report[f]['pkt_total'] += 1 189 | hdr_index = prev_eof_index + 1 190 | pkt_len = i - prev_eof_index 191 | prev_eof_index = i 192 | 193 | if not report[f].has_key('dest_ips'): 194 | report[f].update({'dest_ips':{pkt_ip_str:1}}) 195 | elif report[f]['dest_ips'].has_key(pkt_ip_str): 196 | report[f]['dest_ips'][pkt_ip_str] += 1 197 | else: 198 | report[f]['dest_ips'].update({pkt_ip_str:1}) 199 | 200 | if pkt_len != packet_len + 1: 201 | print 'Malformed Fengine Packet' 202 | if not report[f].has_key('Malformed F-engine Packets'): 203 | report[f]['Malformed F-engine Packets'] = 1 204 | else: 205 | report[f]['Malformed F-engine Packets'] += 1 206 | else: 207 | feng_unpkd_pkt = feng_unpack(f, hdr_index, pkt_len) 208 | 209 | ## Record the reception of the packet for this antenna, with this mcnt 210 | #try: mcnts[f][feng_unpkd_pkt['pkt_mcnt']][feng_unpkd_pkt['pkt_ant']]=i 211 | #except: 212 | # mcnts[f][feng_unpkd_pkt['pkt_mcnt']]=numpy.zeros(n_ants,numpy.int) 213 | # mcnts[f][feng_unpkd_pkt['pkt_mcnt']][feng_unpkd_pkt['pkt_ant']]=i 214 | #print mcnts 215 | print 'HDR @ %4i. MCNT %12u. Freq: %4i (X:%i). Ant: %3i. 4 bit power: PolQ: %4.2f, PolI: %4.2f' % (hdr_index, feng_unpkd_pkt['pkt_mcnt'], feng_unpkd_pkt['pkt_freq'],feng_unpkd_pkt['exp_xeng'], feng_unpkd_pkt['pkt_ant'], feng_unpkd_pkt['rms_polQ'], feng_unpkd_pkt['rms_polI']) 216 | 217 | if not report[f].has_key('Antenna%i' % feng_unpkd_pkt['pkt_ant']): 218 | report[f]['Antenna%i' % feng_unpkd_pkt['pkt_ant']] = 1 219 | else: 220 | report[f]['Antenna%i' % feng_unpkd_pkt['pkt_ant']] += 1 221 | 222 | print '\n\nDone with all servers.\nSummary:\n==========================' 223 | for k, r in report.iteritems(): 224 | keys = report[k].keys() 225 | keys.sort() 226 | srvr = servers[r['fpga_index']] 227 | print '------------------------' 228 | print srvr 229 | print '------------------------' 230 | for key in keys: 231 | print key,': ', r[key] 232 | print '==========================' 233 | 234 | except KeyboardInterrupt: 235 | exit_clean() 236 | except: 237 | exit_fail() 238 | 239 | exit_clean() 240 | --------------------------------------------------------------------------------