diff options
author | eb | 2009-08-15 18:34:45 +0000 |
---|---|---|
committer | eb | 2009-08-15 18:34:45 +0000 |
commit | ea57c1b52b8bed12296ba51441afcfc57a0b9d34 (patch) | |
tree | f86aee7b4b75aef3d27f7d876431296838e8cb8e | |
parent | cdecd3aa94c0ed24312c869c27b3cbd01998004e (diff) | |
download | gnuradio-ea57c1b52b8bed12296ba51441afcfc57a0b9d34.tar.gz gnuradio-ea57c1b52b8bed12296ba51441afcfc57a0b9d34.tar.bz2 gnuradio-ea57c1b52b8bed12296ba51441afcfc57a0b9d34.zip |
Merged VRT work-in-progress from eb/vrt2 (11518:11598) into trunk.
Passes distcheck.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@11600 221aa14e-8319-0410-a670-987f0aec2ac5
55 files changed, 5258 insertions, 0 deletions
diff --git a/config/Makefile.am b/config/Makefile.am index b921ec510..d6a3ad393 100644 --- a/config/Makefile.am +++ b/config/Makefile.am @@ -67,9 +67,11 @@ m4macros = \ grc_gr_trellis.m4 \ grc_gr_usrp.m4 \ grc_gr_video_sdl.m4 \ + grc_gr_vrt.m4 \ grc_gr_wxgui.m4 \ grc_mblock.m4 \ grc_gruel.m4 \ + grc_vrt.m4 \ gr_check_createfilemapping.m4 \ gr_check_mc4020.m4 \ gr_check_shm_open.m4 \ diff --git a/config/grc_gr_vrt.m4 b/config/grc_gr_vrt.m4 new file mode 100644 index 000000000..ff2d06347 --- /dev/null +++ b/config/grc_gr_vrt.m4 @@ -0,0 +1,38 @@ +dnl Copyright 2008,2009 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, +dnl Boston, MA 02110-1301, USA. + +AC_DEFUN([GRC_GR_VRT],[ + GRC_ENABLE(gr-vrt) + + dnl Don't do gr-usrp if gnuradio-core or vrt skipped + GRC_CHECK_DEPENDENCY(gr-vrt, vrt) + GRC_CHECK_DEPENDENCY(gr-vrt, gnuradio-core) + + AC_CONFIG_FILES([ \ + gr-vrt/Makefile \ + gr-vrt/gnuradio-vrt.pc \ + gr-vrt/src/Makefile \ + gr-vrt/src/run_tests \ + ]) + + GRC_BUILD_CONDITIONAL(gr-vrt,[ + dnl run_tests is created from run_tests.in. Make it executable. + AC_CONFIG_COMMANDS([run_tests_vrt], [chmod +x gr-vrt/src/run_tests]) + ]) +]) diff --git a/config/grc_vrt.m4 b/config/grc_vrt.m4 new file mode 100644 index 000000000..d473c5581 --- /dev/null +++ b/config/grc_vrt.m4 @@ -0,0 +1,51 @@ +dnl Copyright 2008,2009 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, +dnl Boston, MA 02110-1301, USA. + +AC_DEFUN([GRC_VRT],[ + GRC_ENABLE(vrt) + + dnl If execution gets to here, $passed will be: + dnl with : if the --with code didn't error out + dnl yes : if the --enable code passed muster and all dependencies are met + dnl no : otherwise + if test $passed = yes; then + dnl Needed for vrt_socket_opener + AC_CHECK_HEADERS(arpa/inet.h byteswap.h linux/if_packet.h sys/socket.h sys/un.h) + fi + if test $passed != with; then + dnl how and where to find INCLUDES and LA + VRT_INCLUDES="-I\${abs_top_srcdir}/vrt/include" + VRT_LA="\${abs_top_builddir}/vrt/lib/libvrt.la" + fi + + dnl Include the vrt INCLUDES and LA + AC_SUBST(VRT_INCLUDES) + AC_SUBST(VRT_LA) + + AC_CONFIG_FILES([ + vrt/Makefile + vrt/vrt.pc + vrt/include/Makefile + vrt/include/vrt/Makefile + vrt/lib/Makefile + vrt/apps/Makefile + ]) + + GRC_BUILD_CONDITIONAL(vrt) +]) diff --git a/configure.ac b/configure.ac index 25b183027..1764b46ab 100644 --- a/configure.ac +++ b/configure.ac @@ -338,8 +338,10 @@ GRC_GNURADIO_CORE GRC_MBLOCK dnl this must come after GRC_GRUEL GRC_USRP GRC_USRP2 +GRC_VRT GRC_GR_USRP dnl this must come after GRC_USRP GRC_GR_USRP2 +GRC_GR_VRT GRC_GR_GCELL dnl this must come after GRC_GCELL and GRC_GNURADIO_CORE GRC_GR_MSDD6000 GRC_GR_AUDIO_ALSA diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index b58faa9bf..65cbd536c 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -44,6 +44,7 @@ bin_SCRIPTS = \ gr_plot_iq.py \ gr_plot_short.py \ lsusrp \ + qr_fft.py \ usrp_fft.py \ usrp_oscope.py \ usrp_print_db.py \ diff --git a/gr-utils/src/python/qr_fft.py b/gr-utils/src/python/qr_fft.py new file mode 100755 index 000000000..c2f06d715 --- /dev/null +++ b/gr-utils/src/python/qr_fft.py @@ -0,0 +1,505 @@ +#!/usr/bin/env python +# +# Copyright 2004,2005,2007,2008,2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio.wxgui import forms +from gnuradio import gr, gru +from gnuradio import vrt +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, form, slider +from gnuradio.gr import pubsub +from optparse import OptionParser +import wx +import sys +import numpy +import time + +class app_top_block(stdgui2.std_top_block, pubsub.pubsub): + def __init__(self, frame, panel, vbox, argv): + stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) + pubsub.pubsub.__init__(self) + self.frame = frame + self.panel = panel + + parser = OptionParser(option_class=eng_option) + #parser.add_option("-e", "--interface", type="string", default="eth0", + # help="select Ethernet interface, default is eth0") + #parser.add_option("-m", "--mac-addr", type="string", default="", + # help="select USRP by MAC address, default is auto-select") + #parser.add_option("-A", "--antenna", default=None, + # help="select Rx Antenna (only on RFX-series boards)") + #parser.add_option("-d", "--decim", type="int", default=16, + # help="set fgpa decimation rate to DECIM [default=%default]") + #parser.add_option("-f", "--freq", type="eng_float", default=None, + # help="set frequency to FREQ", metavar="FREQ") + #parser.add_option("-g", "--gain", type="eng_float", default=None, + # help="set gain in dB (default is midpoint)") + parser.add_option("-W", "--waterfall", action="store_true", default=False, + help="Enable waterfall display") + parser.add_option("-S", "--oscilloscope", action="store_true", default=False, + help="Enable oscilloscope display") + parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, + help="Set fftsink averaging factor, default=[%default]") + parser.add_option("", "--ref-scale", type="eng_float", default=1.0, + help="Set dBFS=0dB input value, default=[%default]") + parser.add_option("--fft-size", type="int", default=1024, + help="Set number of FFT bins [default=%default]") + parser.add_option("--samples-per-pkt", type="int", default=0, + help="Set number of SAMPLES-PER-PKT [default=%default]") + parser.add_option("", "--ip-addr", type="string", default="192.168.10.2", + help="IP address default=[%default]") + (options, args) = parser.parse_args() + if len(args) != 0: + parser.print_help() + sys.exit(1) + self.options = options + self.show_debug_info = True + + self.u = vrt.quadradio_source_32fc(options.ip_addr, + int(62.5e6), options.samples_per_pkt) + #self.u.set_decim(options.decim) + + #input_rate = self.u.adc_rate() / self.u.decim() + input_rate = int(120e6/4) + + if options.waterfall: + self.scope = \ + waterfallsink2.waterfall_sink_c (panel, fft_size=1024, sample_rate=input_rate) + elif options.oscilloscope: + self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) + else: + self.scope = fftsink2.fft_sink_c (panel, + fft_size=options.fft_size, + sample_rate=input_rate, + ref_scale=options.ref_scale, + ref_level=20.0, + y_divs = 12, + avg_alpha=options.avg_alpha) + + self.connect(self.u, self.scope) + + self._build_gui(vbox) + self._setup_events() + + # set initial values + + #if options.gain is None: + # # if no gain was specified, use the mid-point in dB + # g = self.u.gain_range() + # options.gain = float(g[0]+g[1])/2 + + #if options.freq is None: + # # if no freq was specified, use the mid-point + # r = self.u.freq_range() + # options.freq = float(r[0]+r[1])/2 + + #self.set_gain(options.gain) + + #if options.antenna is not None: + # print "Selecting antenna %s" % (options.antenna,) + # self.subdev.select_rx_antenna(options.antenna) + + if self.show_debug_info: + # self.myform['decim'].set_value(self.u.decim()) + self.myform['fs@gbe'].set_value(input_rate) + # self.myform['dbname'].set_value("0x%04X" % (self.u.daughterboard_id(),)) # FIXME: add text name + self.myform['baseband'].set_value(0) + self.myform['ddc'].set_value(0) + + #if not(self.set_freq(options.freq)): + # self._set_status_msg("Failed to set initial frequency") + + def _set_status_msg(self, msg): + self.frame.GetStatusBar().SetStatusText(msg, 0) + + def _build_gui(self, vbox): + + def _form_set_freq(kv): + return self.set_freq(kv['freq']) + + vbox.Add(self.scope.win, 10, wx.EXPAND) + + # add control area at the bottom + self.myform = myform = form.form() + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add((5,0), 0, 0) + myform['freq'] = form.float_field( + parent=self.panel, sizer=hbox, label="Center freq", weight=1, + callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg)) + + hbox.Add((5,0), 0, 0) + #g = self.u.gain_range() + + # some configurations don't have gain control + if 0 and g[1] > g[0]: + myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", + weight=3, + min=int(g[0]), max=int(g[1]), + callback=self.set_gain) + + hbox.Add((5,0), 0, 0) + vbox.Add(hbox, 0, wx.EXPAND) + + self._build_subpanel(vbox) + + def _build_subpanel(self, vbox_arg): + # build a secondary information panel (sometimes hidden) + + # FIXME figure out how to have this be a subpanel that is always + # created, but has its visibility controlled by foo.Show(True/False) + + def _form_set_decim(kv): + return self.set_decim(kv['decim']) + + if not(self.show_debug_info): + return + + panel = self.panel + vbox = vbox_arg + myform = self.myform + + #panel = wx.Panel(self.panel, -1) + #vbox = wx.BoxSizer(wx.VERTICAL) + + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add((5,0), 0) + + myform['decim'] = form.int_field( + parent=panel, sizer=hbox, label="Decim", + callback=myform.check_input_and_call(_form_set_decim, self._set_status_msg)) + + hbox.Add((5,0), 1) + myform['fs@gbe'] = form.static_float_field( + parent=panel, sizer=hbox, label="Fs@GbE") + + hbox.Add((5,0), 1) + myform['dbname'] = form.static_text_field( + parent=panel, sizer=hbox) + + hbox.Add((5,0), 1) + myform['baseband'] = form.static_float_field( + parent=panel, sizer=hbox, label="Analog BB") + + hbox.Add((5,0), 1) + myform['ddc'] = form.static_float_field( + parent=panel, sizer=hbox, label="DDC") + + hbox.Add((5,0), 0) + vbox.Add(hbox, 0, wx.EXPAND) + ##### db control stuff ##### + self.subscribe('cal_div_lo_freq', lambda x: self.u.set_lo_freq(x) and time.sleep(0.01)) + self.subscribe('cal_div_lo_freq', self.u.set_center_freq) #TODO should be combined with set lo freq + self.subscribe('cal_div_cal_freq', lambda x: self.u.set_cal_freq(x) and time.sleep(0.01)) + self.subscribe('db_ctrl_atten0', self.u.set_attenuation0) + self.subscribe('db_ctrl_atten1', self.u.set_attenuation1) + self.subscribe('sys_beaming', self.u.set_beamforming) + #self.subscribe('db_ctrl_10db', self.u.set_10dB_atten) + self.subscribe('db_ctrl_adcgain', self.u.set_adc_gain) + self.subscribe('db_ctrl_diggain', self.u.set_digital_gain) + self.subscribe('db_ctrl_dcoffset', self.u.set_dc_offset_comp) + self.subscribe('db_ctrl_bandsel', self.u.set_band_select) + self.subscribe('db_ctrl_type', self.u.select_rx_antenna) + self.subscribe('db_test_signal', self.u.set_test_signal) + self['db_ctrl_bandsel'] = 'A' + self['cal_div_lo_freq'] = 2.1e9 + self['cal_div_cal_freq'] = 2.102e9 + self['db_ctrl_atten0'] = 0 + self['db_ctrl_atten1'] = 0 + #self['db_ctrl_10db'] = False + self['db_ctrl_adcgain'] = False + self['db_ctrl_dcoffset'] = False + self['db_ctrl_diggain'] = 0.0 + self['db_ctrl_type'] = 'rf' + self['db_test_signal'] = vrt.VRT_TEST_SIG_NORMAL + self['sys_beaming'] = [16.7e6, 0, 0, 0] + #slider and box for freqs + for key, name in (('cal_div_lo_freq', 'LO Freq'), ('cal_div_cal_freq', 'Cal Freq')): + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.AddSpacer(10) + forms.text_box( + label=name, + ps=self, + key=key, + sizer=hbox, + parent=panel, + proportion=0, + converter=forms.float_converter() + ) + hbox.AddSpacer(20) + forms.slider( + ps=self, + key=key, + minimum=0, #TODO get bounds from cal_div, from vrt... + maximum=int(3.5e9), + step_size=int(5e6), + cast=float, + sizer=hbox, + parent=panel, + proportion=2, + ) + hbox.AddSpacer(10) + vbox.Add(hbox, 0, wx.EXPAND) + ############################################ + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.AddSpacer(10) + #create slider for atten + atten0_txt_box = forms.static_text( + label='Attenuation (0)', + ps=self, + key='db_ctrl_atten0', + sizer=hbox, + parent=panel, + proportion=0, + converter=forms.int_converter() + ) + hbox.AddSpacer(20) + atten0_slider = forms.slider( + ps=self, + key='db_ctrl_atten0', + minimum=0, + maximum=31, + step_size=1, + cast=int, + sizer=hbox, + parent=panel, + proportion=2, + ) + hbox.AddSpacer(10) + #create slider for atten + forms.static_text( + label='Attenuation (1)', + ps=self, + key='db_ctrl_atten1', + sizer=hbox, + parent=panel, + proportion=0, + converter=forms.int_converter() + ) + hbox.AddSpacer(20) + forms.slider( + ps=self, + key='db_ctrl_atten1', + minimum=0, + maximum=31, + step_size=1, + cast=int, + sizer=hbox, + parent=panel, + proportion=2, + ) + hbox.AddSpacer(10) + def update_atten0(*args): + for form_obj in (atten0_txt_box, atten0_slider): form_obj.Enable(self['db_ctrl_bandsel'] > 'B') + update_atten0() + self.subscribe('db_ctrl_bandsel', update_atten0) + #create checkbox for 10dB att + #forms.check_box( + # label='10dB Attenuation', + # ps=self, + # key='db_ctrl_10db', + # sizer=hbox, + # parent=panel, + # proportion=1, + #) + #hbox.AddSpacer(10) + vbox.Add(hbox, 0, wx.EXPAND) + hbox2 = wx.BoxSizer(wx.HORIZONTAL) + hbox2.AddSpacer(10) + forms.static_text( + label='ADC Controls', + ps=self, + key='db_ctrl_diggain', + sizer=hbox2, + parent=panel, + proportion=0, + converter=forms.float_converter() + ) + hbox2.AddSpacer(20) + #create checkbox for ADC digital gain + forms.slider( + #label='ADC Digital Gain', + ps=self, + minimum=0, + maximum=6, + step_size=0.5, + key='db_ctrl_diggain', + sizer=hbox2, + parent=panel, + proportion=2, + ) + hbox2.AddSpacer(10) + #create checkbox for 3.5dB ADC gain + forms.check_box( + label='3.5dB ADC Gain', + ps=self, + key='db_ctrl_adcgain', + sizer=hbox2, + parent=panel, + proportion=1, + ) + hbox2.AddSpacer(10) + #create checkbox for DC Offset Correction in ADC + forms.check_box( + label='DC Offset Correction', + ps=self, + key='db_ctrl_dcoffset', + sizer=hbox2, + parent=panel, + proportion=2, + ) + hbox2.AddSpacer(10) + vbox.Add(hbox2, 0, wx.EXPAND) + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.AddSpacer(10) + #create radio buttons for band sel + forms.radio_buttons( + label='Band Select', + ps=self, + key='db_ctrl_bandsel', + choices=['A', 'B', 'C', 'D'], + labels=['A', 'B', 'C', 'D'], + sizer=hbox, + parent=panel, + proportion=0, + ) + hbox.AddSpacer(10) + forms.radio_buttons( + label='RF Input', + ps=self, + key='db_ctrl_type', + choices=['rf', 'cal'], + labels=['Main RF', 'Calibrator'], + sizer=hbox, + parent=panel, + proportion=0, + ) + hbox.AddSpacer(10) + #create radio buttons for band sel + types = sorted( + filter(lambda x: x.startswith('VRT_TEST_SIG_'), dir(vrt)), + lambda x, y: cmp(getattr(vrt, x), getattr(vrt, y)), + ) + forms.drop_down( + label='Test Signal', + ps=self, + key='db_test_signal', + choices=map(lambda a: getattr(vrt, a), types), + labels=types, + sizer=hbox, + parent=panel, + proportion=0, + ) + hbox.AddSpacer(10) + #create radio buttons for type + forms.drop_down( + label='Beamformer', + ps=self, + key='sys_beaming', + choices=[[16.7e6, 0, 0, 0], [0, 16.7e6, 0, 0], [0, 0, 16.7e6, 0], [0, 0, 0, 16.7e6], [4.19e6]*4], + labels=['Ant0', 'Ant1', 'Ant2', 'Ant3', 'Equal Gain'], + sizer=hbox, + parent=panel, + proportion=0, + ) + hbox.AddSpacer(10) + vbox.Add(hbox, 0, wx.EXPAND) + + def set_freq(self, target_freq): + """ + Set the center frequency we're interested in. + + @param target_freq: frequency in Hz + @rypte: bool + + Tuning is a two step process. First we ask the front-end to + tune as close to the desired frequency as it can. Then we use + the result of that operation and our target_frequency to + determine the value for the digital down converter. + """ + return True + + r = self.u.set_center_freq(target_freq) + + if r: + self.myform['freq'].set_value(target_freq) # update displayed value + if self.show_debug_info: + self.myform['baseband'].set_value(r.baseband_freq) + self.myform['ddc'].set_value(r.dxc_freq) + if not self.options.oscilloscope: + self.scope.win.set_baseband_freq(target_freq) + return True + + return False + + def set_gain(self, gain): + return True + + if self.myform.has_key('gain'): + self.myform['gain'].set_value(gain) # update displayed value + self.u.set_gain(gain) + + def set_decim(self, decim): + return True + + ok = self.u.set_decim(decim) + if not ok: + print "set_decim failed" + #input_rate = self.u.adc_rate() / self.u.decim() + input_rate = 120e6/4 + self.scope.set_sample_rate(input_rate) + if self.show_debug_info: # update displayed values + self.myform['decim'].set_value(self.u.decim()) + self.myform['fs@gbe'].set_value(input_rate) + return ok + + def _setup_events(self): + if not self.options.waterfall and not self.options.oscilloscope: + self.scope.win.Bind(wx.EVT_LEFT_DCLICK, self.evt_left_dclick) + + def evt_left_dclick(self, event): + (ux, uy) = self.scope.win.GetXY(event) + if event.CmdDown(): + # Re-center on maximum power + points = self.scope.win._points + if self.scope.win.peak_hold: + if self.scope.win.peak_vals is not None: + ind = numpy.argmax(self.scope.win.peak_vals) + else: + ind = int(points.shape()[0]/2) + else: + ind = numpy.argmax(points[:,1]) + (freq, pwr) = points[ind] + target_freq = freq/self.scope.win._scale_factor + print ind, freq, pwr + self.set_freq(target_freq) + else: + # Re-center on clicked frequency + target_freq = ux/self.scope.win._scale_factor + self.set_freq(target_freq) + + +def main (): + app = stdgui2.stdapp(app_top_block, "QuadRadio FFT", nstatus=1) + app.MainLoop() + +if __name__ == '__main__': + main () diff --git a/gr-vrt/Makefile.am b/gr-vrt/Makefile.am new file mode 100644 index 000000000..96019be97 --- /dev/null +++ b/gr-vrt/Makefile.am @@ -0,0 +1,27 @@ +# +# Copyright 2001,2006,2008,2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +include $(top_srcdir)/Makefile.common + +SUBDIRS = src + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = gnuradio-vrt.pc diff --git a/gr-vrt/gnuradio-vrt.pc.in b/gr-vrt/gnuradio-vrt.pc.in new file mode 100644 index 000000000..b5f416051 --- /dev/null +++ b/gr-vrt/gnuradio-vrt.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/gnuradio + +Name: gnuradio-vrt +Description: GNU Software Radio support for Virtual Radio Transport (VRT aka VITA-49) +Requires: gnuradio-core vrt +Version: @VERSION@ +Libs: -L${libdir} -lgnuradio-vrt +Cflags: -I${includedir} diff --git a/gr-vrt/src/Makefile.am b/gr-vrt/src/Makefile.am new file mode 100644 index 000000000..671c10274 --- /dev/null +++ b/gr-vrt/src/Makefile.am @@ -0,0 +1,122 @@ +# +# Copyright 2004,2005,2006,2008,2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +include $(top_srcdir)/Makefile.common + +# ---------------------------------------------------------------------- +# Local Python files, not installed +# +# qa_vrt.py +# ---------------------------------------------------------------------- + +noinst_PYTHON = qa_vrt.py + +# ---------------------------------------------------------------------- +# Miscellaneous build operations +# ---------------------------------------------------------------------- + +EXTRA_DIST = run_tests.in +TESTS = run_tests +DISTCLEANFILES = run_tests + +# ---------------------------------------------------------------------- +# C++ block API interface librar(ies) +# +# libgnuradio_vrt.so +# ---------------------------------------------------------------------- +AM_CPPFLAGS = \ + $(STD_DEFINES_AND_INCLUDES) \ + $(GRUEL_INCLUDES) \ + $(PYTHON_CPPFLAGS) \ + $(VRT_INCLUDES) \ + $(WITH_INCLUDES) + +lib_LTLIBRARIES = libgnuradio-vrt.la + +libgnuradio_vrt_la_SOURCES = \ + missing_pkt_checker.cc \ + vrt_source_base.cc \ + vrt_source_32fc.cc \ + vrt_quadradio_source_32fc.cc + + +#libgnuradio_vrt_la_SOURCES = \ +# rx_16sc_handler.cc \ +# rx_32fc_handler.cc \ +# vrt_base.cc \ +# vrt_source_base.cc \ +# vrt_source_16sc.cc \ +# vrt_source_32fc.cc + +# vrt_sink_base.cc \ +# vrt_sink_16sc.cc \ +# vrt_sink_32fc.cc + +libgnuradio_vrt_la_LIBADD = \ + $(VRT_LA) \ + $(GNURADIO_CORE_LA) + +grinclude_HEADERS = \ + vrt_source_base.h \ + vrt_source_32fc.h \ + vrt_quadradio_source_32fc.h + +# vrt_source_16sc.h \ +# vrt_sink_base.h \ +# vrt_sink_16sc.h \ +# vrt_sink_32fc.h + +noinst_HEADERS = \ + missing_pkt_checker.h + + +# ---------------------------------------------------------------------- +# Python SWIG wrapper around C++ library +# +# vrt.py +# _vrt.so +# ---------------------------------------------------------------------- + +TOP_SWIG_IFILES = \ + vrt.i + +# Install so that they end up available as: +# import gnuradio.vrt +# This ends up at: +# ${prefix}/lib/python${python_version}/site-packages/gnuradio +vrt_pythondir_category = \ + gnuradio + +# additional arguments to the SWIG command +vrt_swig_args = \ + $(VRT_INCLUDES) + +# additional libraries for linking with the SWIG-generated library +vrt_la_swig_libadd = \ + libgnuradio-vrt.la + +include $(top_srcdir)/Makefile.swig + +# add some of the variables generated inside the Makefile.swig.gen +BUILT_SOURCES = $(swig_built_sources) + +# Do not distribute the output of SWIG +no_dist_files = $(swig_built_sources) diff --git a/gr-vrt/src/Makefile.swig.gen b/gr-vrt/src/Makefile.swig.gen new file mode 100644 index 000000000..b0a4a22fa --- /dev/null +++ b/gr-vrt/src/Makefile.swig.gen @@ -0,0 +1,259 @@ +# -*- Makefile -*- +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +# Makefile.swig.gen for vrt.i + +## Default install locations for these files: +## +## Default location for the Python directory is: +## ${prefix}/lib/python${python_version}/site-packages/[category]/vrt +## Default location for the Python exec directory is: +## ${exec_prefix}/lib/python${python_version}/site-packages/[category]/vrt +## +## The following can be overloaded to change the install location, but +## this has to be done in the including Makefile.am -before- +## Makefile.swig is included. + +vrt_pythondir_category ?= gnuradio/vrt +vrt_pylibdir_category ?= $(vrt_pythondir_category) +vrt_pythondir = $(pythondir)/$(vrt_pythondir_category) +vrt_pylibdir = $(pyexecdir)/$(vrt_pylibdir_category) + +## SWIG headers are always installed into the same directory. + +vrt_swigincludedir = $(swigincludedir) + +## This is a template file for a "generated" Makefile addition (in +## this case, "Makefile.swig.gen"). By including the top-level +## Makefile.swig, this file will be used to generate the SWIG +## dependencies. Assign the variable TOP_SWIG_FILES to be the list of +## SWIG .i files to generated wrappings for; there can be more than 1 +## so long as the names are unique (no sorting is done on the +## TOP_SWIG_FILES list). This file explicitly assumes that a SWIG .i +## file will generate .cc, .py, and possibly .h files -- meaning that +## all of these files will have the same base name (that provided for +## the SWIG .i file). +## +## This code is setup to ensure parallel MAKE ("-j" or "-jN") does the +## right thing. For more info, see < +## http://sources.redhat.com/automake/automake.html#Multiple-Outputs > + +## Stamps used to ensure parallel make does the right thing. These +## are removed by "make clean", but otherwise unused except during the +## parallel built. These will not be included in a tarball, because +## the SWIG-generated files will be removed from the distribution. + +STAMPS += $(DEPDIR)/vrt-generate-* + +## Other cleaned files: dependency files generated by SWIG or this Makefile + +MOSTLYCLEANFILES += $(DEPDIR)/*.S* + +## Add the .py and .cc files to the list of SWIG built sources. The +## .h file is sometimes built, but not always ... so that one has to +## be added manually by the including Makefile.am . + +swig_built_sources += vrt.py vrt.cc + +## Various SWIG variables. These can be overloaded in the including +## Makefile.am by setting the variable value there, then including +## Makefile.swig . + +vrt_swiginclude_HEADERS = \ + vrt.i \ + $(vrt_swiginclude_headers) + +vrt_pylib_LTLIBRARIES = \ + _vrt.la + +_vrt_la_SOURCES = \ + vrt.cc \ + $(vrt_la_swig_sources) + +_vrt_la_LIBADD = \ + $(STD_SWIG_LA_LIB_ADD) \ + $(vrt_la_swig_libadd) + +_vrt_la_LDFLAGS = \ + $(STD_SWIG_LA_LD_FLAGS) \ + $(vrt_la_swig_ldflags) + +_vrt_la_CXXFLAGS = \ + $(STD_SWIG_CXX_FLAGS) \ + $(vrt_la_swig_cxxflags) + +vrt_python_PYTHON = \ + vrt.py \ + $(vrt_python) + +## Entry rule for running SWIG + +vrt.h vrt.py vrt.cc: vrt.i +## This rule will get called only when MAKE decides that one of the +## targets needs to be created or re-created, because: +## +## * The .i file is newer than any or all of the generated files; +## +## * Any or all of the .cc, .h, or .py files does not exist and is +## needed (in the case this file is not needed, the rule for it is +## ignored); or +## +## * Some SWIG-based dependecy of the .cc file isn't met and hence the +## .cc file needs be be regenerated. Explanation: Because MAKE +## knows how to handle dependencies for .cc files (regardless of +## their name or extension), then the .cc file is used as a target +## instead of the .i file -- but with the dependencies of the .i +## file. It is this last reason why the line: +## +## if test -f $@; then :; else +## +## cannot be used in this case: If a .i file dependecy is not met, +## then the .cc file needs to be rebuilt. But if the stamp is newer +## than the .cc file, and the .cc file exists, then in the original +## version (with the 'test' above) the internal MAKE call will not +## be issued and hence the .cc file will not be rebuilt. +## +## Once execution gets to here, it should always proceed no matter the +## state of a stamp (as discussed in link above). The +## $(DEPDIR)/vrt-generate stuff is used to allow for parallel +## builds to "do the right thing". The stamp has no relationship with +## either the target files or dependency file; it is used solely for +## the protection of multiple builds during a given call to MAKE. +## +## Catch signals SIGHUP (1), SIGINT (2), SIGPIPE (13), and SIGTERM +## (15). At a caught signal, the quoted command will be issued before +## exiting. In this case, remove any stamp, whether temporary of not. +## The trap is valid until the process exits; the process includes all +## commands appended via "\"s. +## + trap 'rm -rf $(DEPDIR)/vrt-generate-*' 1 2 13 15; \ +## +## Create a temporary directory, which acts as a lock. The first +## process to create the directory will succeed and issue the MAKE +## command to do the actual work, while all subsequent processes will +## fail -- leading them to wait for the first process to finish. +## + if mkdir $(DEPDIR)/vrt-generate-lock 2>/dev/null; then \ +## +## This code is being executed by the first process to succeed in +## creating the directory lock. +## +## Remove the stamp associated with this filename. +## + rm -f $(DEPDIR)/vrt-generate-stamp; \ +## +## Tell MAKE to run the rule for creating this stamp. +## + $(MAKE) $(AM_MAKEFLAGS) $(DEPDIR)/vrt-generate-stamp WHAT=$<; \ +## +## Now that the .cc, .h, and .py files have been (re)created from the +## .i file, future checking of this rule during the same MAKE +## execution will come back that the rule doesn't need to be executed +## because none of the conditions mentioned at the start of this rule +## will be positive. Remove the the directory lock, which frees up +## any waiting process(es) to continue. +## + rmdir $(DEPDIR)/vrt-generate-lock; \ + else \ +## +## This code is being executed by any follower processes while the +## directory lock is in place. +## +## Wait until the first process is done, testing once per second. +## + while test -d $(DEPDIR)/vrt-generate-lock; do \ + sleep 1; \ + done; \ +## +## Succeed if and only if the first process succeeded; exit this +## process returning the status of the generated stamp. +## + test -f $(DEPDIR)/vrt-generate-stamp; \ + exit $$?; \ + fi; + +$(DEPDIR)/vrt-generate-stamp: +## This rule will be called only by the first process issuing the +## above rule to succeed in creating the lock directory, after +## removing the actual stamp file in order to guarantee that MAKE will +## execute this rule. +## +## Call SWIG to generate the various output files; special +## post-processing on 'mingw32' host OS for the dependency file. +## + if $(SWIG) $(STD_SWIG_PYTHON_ARGS) $(vrt_swig_args) \ + -MD -MF $(DEPDIR)/vrt.Std \ + -module vrt -o vrt.cc $(WHAT); then \ + if test $(host_os) = mingw32; then \ + $(RM) $(DEPDIR)/vrt.Sd; \ + $(SED) 's,\\\\,/,g' < $(DEPDIR)/vrt.Std \ + > $(DEPDIR)/vrt.Sd; \ + $(RM) $(DEPDIR)/vrt.Std; \ + $(MV) $(DEPDIR)/vrt.Sd $(DEPDIR)/vrt.Std; \ + fi; \ + else \ + $(RM) $(DEPDIR)/vrt.S*; exit 1; \ + fi; +## +## Mess with the SWIG output .Std dependency file, to create a +## dependecy file valid for the input .i file: Basically, simulate the +## dependency file created for libraries by GNU's libtool for C++, +## where all of the dependencies for the target are first listed, then +## each individual dependency is listed as a target with no further +## dependencies. +## +## (1) remove the current dependency file +## + $(RM) $(DEPDIR)/vrt.d +## +## (2) Copy the whole SWIG file: +## + cp $(DEPDIR)/vrt.Std $(DEPDIR)/vrt.d +## +## (3) all a carriage return to the end of the dependency file. +## + echo "" >> $(DEPDIR)/vrt.d +## +## (4) from the SWIG file, remove the first line (the target); remove +## trailing " \" and " " from each line. Append ":" to each line, +## followed by 2 carriage returns, then append this to the end of +## the dependency file. +## + $(SED) -e '1d;s, \\,,g;s, ,,g' < $(DEPDIR)/vrt.Std | \ + awk '{ printf "%s:\n\n", $$0 }' >> $(DEPDIR)/vrt.d +## +## (5) remove the SWIG-generated file +## + $(RM) $(DEPDIR)/vrt.Std +## +## Create the stamp for this filename generation, to signal success in +## executing this rule; allows other threads waiting on this process +## to continue. +## + touch $(DEPDIR)/vrt-generate-stamp + +# KLUDGE: Force runtime include of a SWIG dependency file. This is +# not guaranteed to be portable, but will probably work. If it works, +# we have accurate dependencies for our swig stuff, which is good. + +@am__include@ @am__quote@./$(DEPDIR)/vrt.d@am__quote@ + diff --git a/gr-vrt/src/missing_pkt_checker.cc b/gr-vrt/src/missing_pkt_checker.cc new file mode 100644 index 000000000..09b70fe2c --- /dev/null +++ b/gr-vrt/src/missing_pkt_checker.cc @@ -0,0 +1,47 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <missing_pkt_checker.h> + +int +missing_pkt_checker::check(const vrt::expanded_header *hdr) +{ + // FIXME assumes we're inspecting only a single stream + + int nmissing = 0; + int actual = hdr->pkt_cnt(); + int expected = (d_last_pkt_cnt + 1) & 0xf; + if (actual != expected && !d_resync){ + d_nwrong_pkt_cnt++; + if (actual > expected) + nmissing = actual - expected; + else + nmissing = actual + 16 - expected; + d_nmissing_pkt_est += nmissing; + } + d_last_pkt_cnt = actual; + d_npackets++; + d_resync = false; + return nmissing; +} diff --git a/gr-vrt/src/missing_pkt_checker.h b/gr-vrt/src/missing_pkt_checker.h new file mode 100644 index 000000000..ab171ffa3 --- /dev/null +++ b/gr-vrt/src/missing_pkt_checker.h @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef INCLUDED_MISSING_PKT_CHECKER_H +#define INCLUDED_MISSING_PKT_CHECKER_H + +#include <vrt/expanded_header.h> +#include <stdint.h> + +/*! + * \brief Check for missing packets + */ +class missing_pkt_checker +{ + // FIXME assumes we're inspecting only a single stream + + bool d_resync; + uint64_t d_npackets; //< total number of packets + int d_last_pkt_cnt; //< the last pkt_cnt we saw + uint64_t d_nwrong_pkt_cnt; //< number of incorrect pkt_cnt + uint64_t d_nmissing_pkt_est; //< estimate of total number of missing pkts + +public: + missing_pkt_checker() + : d_resync(true), d_npackets(0), d_last_pkt_cnt(0xf), d_nwrong_pkt_cnt(0), + d_nmissing_pkt_est(0) {} + + /*! + * \brief check header pkt_cnt and return 0 if OK, else estimate of number of missing packets. + */ + int check(const vrt::expanded_header *hdr); + + void resync() { d_resync = true; } + uint64_t npackets() const { return d_npackets; } + uint64_t nwrong_pkt_cnt() const { return d_nwrong_pkt_cnt; } + uint64_t nmissing_pkt_est() const { return d_nmissing_pkt_est; } +}; + + +#endif /* INCLUDED_MISSING_PKT_CHECKER_H */ diff --git a/gr-vrt/src/qa_vrt.py b/gr-vrt/src/qa_vrt.py new file mode 100755 index 000000000..9df1edd92 --- /dev/null +++ b/gr-vrt/src/qa_vrt.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# +# Copyright 2005,2008,2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr, gr_unittest +import vrt + +class qa_vrt(gr_unittest.TestCase): + + def setUp(self): + self.tb = gr.top_block() + + def tearDown(self): + self.tb = None + + def test_000_nop (self): + """Just see if we can import the module... + They may not have a VRT connected, etc. Don't try to run anything""" + pass + +if __name__ == '__main__': + gr_unittest.main () diff --git a/gr-vrt/src/run_tests.in b/gr-vrt/src/run_tests.in new file mode 100644 index 000000000..5c56c4674 --- /dev/null +++ b/gr-vrt/src/run_tests.in @@ -0,0 +1,17 @@ +#!/bin/sh + +# 1st parameter is absolute path to component source directory +# 2nd parameter is absolute path to component build directory +# 3rd parameter is path to Python QA directory + +# For OS/X +DYLD_LIBRARY_PATH=@abs_top_builddir@/vrt/host/lib/legacy:@abs_top_builddir@/vrt/host/lib/legacy/.libs:$DYLD_LIBRARY_PATH +export DYLD_LIBRARY_PATH + +# For Win32 +PATH=@abs_top_builddir@/vrt/host/lib/legacy:@abs_top_builddir@/vrt/host/lib/legacy/.libs:$PATH + +@top_builddir@/run_tests.sh \ + @abs_top_srcdir@/gr-vrt \ + @abs_top_builddir@/gr-vrt \ + @srcdir@ diff --git a/gr-vrt/src/vrt.i b/gr-vrt/src/vrt.i new file mode 100644 index 000000000..9016dc33e --- /dev/null +++ b/gr-vrt/src/vrt.i @@ -0,0 +1,64 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +%include "gnuradio.i" // the common stuff +%import <stdint.i> + +%{ +#include "vrt_quadradio_source_32fc.h" +#include <vrt/quadradio.h> +//#include "vrt_quadradio_source_16sc.h" +//#include "vrt_sink_32fc.h" +//#include "vrt_sink_16sc.h" +%} + +%template(uint32_t_vector) std::vector<uint32_t>; + +// ---------------------------------------------------------------- + +class vrt_source_base : public gr_sync_block +{ +protected: + vrt_source_base() throw (std::runtime_error); + +public: + ~vrt_source_base(); + +}; + +class vrt_source_32fc : public vrt_source_base +{ +protected: + vrt_source_32fc() throw (std::runtime_error); + +public: + ~vrt_source_32fc(); + void reset(); +}; + +// ---------------------------------------------------------------- + +GR_SWIG_BLOCK_MAGIC(vrt,quadradio_source_32fc) + +%include "vrt_quadradio_source_32fc.h" + +%include <vrt/quadradio.h> diff --git a/gr-vrt/src/vrt_quadradio_source_32fc.cc b/gr-vrt/src/vrt_quadradio_source_32fc.cc new file mode 100644 index 000000000..0321062aa --- /dev/null +++ b/gr-vrt/src/vrt_quadradio_source_32fc.cc @@ -0,0 +1,212 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <vrt_quadradio_source_32fc.h> +#include <vrt/quadradio.h> +#include <vrt/rx_packet_handler.h> +#include <cstdio> + +vrt_quadradio_source_32fc_sptr +vrt_make_quadradio_source_32fc(const std::string &ip, + size_t rx_bufsize, + size_t samples_per_pkt) +{ + return gnuradio::get_initial_sptr(new vrt_quadradio_source_32fc(ip, + rx_bufsize, + samples_per_pkt)); +} + +vrt_quadradio_source_32fc::vrt_quadradio_source_32fc(const std::string &ip, + size_t rx_bufsize, + size_t samples_per_pkt) + : vrt_source_32fc("quadradio_source_32fc"), + d_samples_per_pkt(samples_per_pkt == 0 ? 800 : samples_per_pkt), + d_qr(vrt::quadradio::sptr(new vrt::quadradio(ip, rx_bufsize))) +{ +} + +vrt_quadradio_source_32fc::~vrt_quadradio_source_32fc() +{ + d_qr->stop_streaming(); +} + +vrt::rx::sptr +vrt_quadradio_source_32fc::vrt_rx() const +{ + return d_qr->vrt_rx(); +} + +bool +vrt_quadradio_source_32fc::start() +{ + // throw away any stale packets before starting + vrt::rx_packet_handler nop; + vrt_rx()->rx_packets(&nop, true); + d_checker.resync(); + + return d_qr->start_streaming(d_samples_per_pkt); +} + +bool +vrt_quadradio_source_32fc::stop() +{ + return d_qr->stop_streaming(); +} + +bool +vrt_quadradio_source_32fc::set_dboard_pins(int which_dboard, int v) +{ + return d_qr->set_dboard_pins(which_dboard, v); +} + +bool +vrt_quadradio_source_32fc::set_center_freq(double target_freq) +{ + return d_qr->set_center_freq(target_freq); +} + +bool +vrt_quadradio_source_32fc::set_band_select(const std::string &band) +{ + return d_qr->set_band_select(band); +} + +//void +//vrt_quadradio_source_32fc::set_10dB_atten(bool on) +//{ +// return d_qr->set_10dB_atten(on); +//} + +bool +vrt_quadradio_source_32fc::select_rx_antenna(const std::string &ant) +{ + return d_qr->select_rx_antenna(ant); +} + +bool +vrt_quadradio_source_32fc::set_attenuation0(int attenuation) +{ + return d_qr->set_attenuation0(attenuation); +} + +bool +vrt_quadradio_source_32fc::set_attenuation1(int attenuation) +{ + return d_qr->set_attenuation1(attenuation); +} + +void +vrt_quadradio_source_32fc::set_adc_gain(bool on){ + d_qr->set_adc_gain(on); +} + +void +vrt_quadradio_source_32fc::set_dc_offset_comp(bool on){ + d_qr->set_dc_offset_comp(on); +} + +void +vrt_quadradio_source_32fc::set_digital_gain(float gain){ + d_qr->set_digital_gain(gain); +} + +void +vrt_quadradio_source_32fc::set_test_signal(int type){ + d_qr->set_test_signal(static_cast<vrt_test_sig_t>(type)); +} + +bool +vrt_quadradio_source_32fc::set_setting_reg(int regno, int value) +{ + return d_qr->set_setting_reg(regno, value); +} + +bool +vrt_quadradio_source_32fc::set_hsadc_conf(int which_dboard, int regno, int value) +{ + return d_qr->set_hsadc_conf(which_dboard, regno, value); +} + +bool +vrt_quadradio_source_32fc::set_lsdac(int which_dboard, int which_dac, int value) +{ + return d_qr->set_lsdac(which_dboard, which_dac, value); +} + +bool +vrt_quadradio_source_32fc::set_mem32(int addr, int value) +{ + return d_qr->set_mem32(addr, value); +} + +bool +vrt_quadradio_source_32fc::set_lo_freq(double freq) +{ + return d_qr->set_lo_freq(freq); +} + +bool +vrt_quadradio_source_32fc::set_cal_freq(double freq) +{ + return d_qr->set_cal_freq(freq); +} + +/*--------------------------------------------------------------------*/ +#define IQ_IMBAL_NUM_TAPS 30 +#define IQ_IMBAL_REG_NO 162 + +//helper function to set the iq imbalance register with a tap +static int get_iq_imbal_reg(bool real, bool init, float tap){ + int val = int(round(tap)); + val &= 0x1ffffff; //lower 25 bits for tap + val |= (real?0:1) << 30; //30th bit for filter type + val |= (init?1:0) << 31; //31st bit for initialization + printf("Reg %d Val %x\n", IQ_IMBAL_REG_NO, val); + return val; +} + +void +vrt_quadradio_source_32fc::set_iq_imbal_taps(const std::vector<gr_complex> taps){ + int i = 0; + /* set the real part of the taps */ + get_iq_imbal_reg(true, true, 0); + for (i = 0; i < IQ_IMBAL_NUM_TAPS; i++){ + set_setting_reg(IQ_IMBAL_REG_NO, get_iq_imbal_reg(true, false, taps[IQ_IMBAL_NUM_TAPS-i-1].real())); + } + get_iq_imbal_reg(false, true, 0); + /* set the imaginary part of the taps */ + for (i = 0; i < IQ_IMBAL_NUM_TAPS; i++){ + set_setting_reg(IQ_IMBAL_REG_NO, get_iq_imbal_reg(false, false, taps[IQ_IMBAL_NUM_TAPS-i-1].imag())); + } +} + +bool +vrt_quadradio_source_32fc::set_beamforming(std::vector<gr_complex> gains){ + int32_t gains_ints[8]; + for (int i = 0; i < 4; i++){ + gains_ints[2*i] = int32_t(gains[i].real()); + gains_ints[2*i+1] = int32_t(gains[i].imag()); + } + return d_qr->set_beamforming(gains_ints); +} + diff --git a/gr-vrt/src/vrt_quadradio_source_32fc.h b/gr-vrt/src/vrt_quadradio_source_32fc.h new file mode 100644 index 000000000..6ad63f7be --- /dev/null +++ b/gr-vrt/src/vrt_quadradio_source_32fc.h @@ -0,0 +1,116 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef INCLUDED_VRT_QUADRADIO_SOURCE_32FC_H +#define INCLUDED_VRT_QUADRADIO_SOURCE_32FC_H + +#include <vrt_source_32fc.h> + +namespace vrt { + class quadradio; +}; + +class vrt_quadradio_source_32fc; +typedef boost::shared_ptr<vrt_quadradio_source_32fc> vrt_quadradio_source_32fc_sptr; + +vrt_quadradio_source_32fc_sptr +vrt_make_quadradio_source_32fc(const std::string &ip, + size_t rx_bufsize = 0, + size_t samples_per_pkt = 0); + +class vrt_quadradio_source_32fc : public vrt_source_32fc +{ + size_t d_samples_per_pkt; + boost::shared_ptr<vrt::quadradio> d_qr; + + vrt_quadradio_source_32fc(const std::string &ip, size_t rx_bufsize, + size_t samples_per_pkt); + + friend vrt_quadradio_source_32fc_sptr + vrt_make_quadradio_source_32fc(const std::string &ip, size_t rx_bufsize, + size_t samples_per_pkt); + +public: + virtual ~vrt_quadradio_source_32fc(); + virtual vrt::rx::sptr vrt_rx() const; + + /*! + * \brief Called by scheduler when starting flowgraph + */ + virtual bool start(); + + /*! + * \brief Called by scheduler when stopping flowgraph + */ + virtual bool stop(); + + /*! + * \brief Set the LO frequency (actually just sets the band select for now). + */ + bool set_center_freq(double target_freq); + + /*! + * \brief Set the band select dboard bits. + * \param band "A", "B", "C", "D" + */ + bool set_band_select(const std::string &band); + + /*! + * \brief Turn the 10 dB attenuation on/off. + */ + //void set_10dB_atten(bool on); + + /*! + * \brief Set the antenna type to the main rf or calibrator. + * \param ant "rf" or "cal" + */ + bool select_rx_antenna(const std::string &ant); + + /*! + * \brief Set the attenuation. + * \param attenuation 0 to 31 in dB + */ + bool set_attenuation0(int attenuation); + bool set_attenuation1(int attenuation); + + void set_iq_imbal_taps(const std::vector<gr_complex> taps); + + void set_adc_gain(bool on); + void set_dc_offset_comp(bool on); + void set_digital_gain(float gain); + void set_test_signal(int type); + + bool set_setting_reg(int regno, int value); + + /*! + * \brief write \p v to daugherboard control setting register + */ + bool set_dboard_pins(int which_dboard, int v); + bool set_hsadc_conf(int which_dboard, int regno, int value); + bool set_lsdac(int which_dboard, int which_dac, int value); + bool set_mem32(int addr, int value); + bool set_lo_freq(double freq); + bool set_cal_freq(double freq); + bool set_beamforming(std::vector<gr_complex> gains); +}; + + + +#endif /* INCLUDED_VRT_QUADRADIO_SOURCE_32FC_H */ diff --git a/gr-vrt/src/vrt_sink_16sc.cc b/gr-vrt/src/vrt_sink_16sc.cc new file mode 100644 index 000000000..09abe29ee --- /dev/null +++ b/gr-vrt/src/vrt_sink_16sc.cc @@ -0,0 +1,73 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <vrt_sink_16sc.h> +#include <vrt/metadata.h> +#include <gr_io_signature.h> +#include <iostream> + +vrt_sink_16sc_sptr +vrt_make_sink_16sc(const std::string &ifc, const std::string &mac_addr) + throw (std::runtime_error) +{ + return gnuradio::get_initial_sptr(new vrt_sink_16sc(ifc, mac_addr)); +} + +vrt_sink_16sc::vrt_sink_16sc(const std::string &ifc, const std::string &mac_addr) + throw (std::runtime_error) + : vrt_sink_base("vrt_sink_16sc", + gr_make_io_signature(1, 1, sizeof(std::complex<int16_t>)), + ifc, mac_addr) +{ + // NOP +} + +vrt_sink_16sc::~vrt_sink_16sc() +{ + // NOP +} + +int +vrt_sink_16sc::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + std::complex<int16_t> *in = (std::complex<int16_t> *)input_items[0]; + + vrt::tx_metadata metadata; + metadata.timestamp = -1; + metadata.send_now = 1; + metadata.start_of_burst = 1; + + bool ok = d_u2->tx_16sc(0, // FIXME: someday, streams will have channel numbers + in, noutput_items, &metadata); + if (!ok){ + std::cerr << "vrt_sink_16sc: tx_16sc failed" << std::endl; + return -1; // say we're done + } + + return noutput_items; +} diff --git a/gr-vrt/src/vrt_sink_16sc.h b/gr-vrt/src/vrt_sink_16sc.h new file mode 100644 index 000000000..ba6e673be --- /dev/null +++ b/gr-vrt/src/vrt_sink_16sc.h @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_USRP2_SINK_16SC_H +#define INCLUDED_USRP2_SINK_16SC_H + +#include <vrt_sink_base.h> + +class vrt_sink_16sc; +typedef boost::shared_ptr<vrt_sink_16sc> vrt_sink_16sc_sptr; + +vrt_sink_16sc_sptr +vrt_make_sink_16sc(const std::string &ifc="eth0", + const std::string &mac="") + throw (std::runtime_error); + +class vrt_sink_16sc : public vrt_sink_base +{ +private: + friend vrt_sink_16sc_sptr + vrt_make_sink_16sc(const std::string &ifc, + const std::string &mac) + throw (std::runtime_error); + +protected: + vrt_sink_16sc(const std::string &ifc, const std::string &mac) + throw (std::runtime_error); + +public: + ~vrt_sink_16sc(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_USRP2_SINK_16SC_H */ diff --git a/gr-vrt/src/vrt_sink_32fc.cc b/gr-vrt/src/vrt_sink_32fc.cc new file mode 100644 index 000000000..a9987a361 --- /dev/null +++ b/gr-vrt/src/vrt_sink_32fc.cc @@ -0,0 +1,73 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <vrt_sink_32fc.h> +#include <vrt/metadata.h> +#include <gr_io_signature.h> +#include <iostream> + +vrt_sink_32fc_sptr +vrt_make_sink_32fc(const std::string &ifc, const std::string &mac_addr) + throw (std::runtime_error) +{ + return gnuradio::get_initial_sptr(new vrt_sink_32fc(ifc, mac_addr)); +} + +vrt_sink_32fc::vrt_sink_32fc(const std::string &ifc, const std::string &mac_addr) + throw (std::runtime_error) + : vrt_sink_base("vrt_sink_32fc", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + ifc, mac_addr) +{ + // NOP +} + +vrt_sink_32fc::~vrt_sink_32fc() +{ + // NOP +} + +int +vrt_sink_32fc::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + gr_complex *in = (gr_complex *)input_items[0]; + + vrt::tx_metadata metadata; + metadata.timestamp = -1; + metadata.send_now = 1; + metadata.start_of_burst = 1; + + bool ok = d_u2->tx_32fc(0, // FIXME: someday, streams will have channel numbers + in, noutput_items, &metadata); + if (!ok){ + std::cerr << "vrt_sink_32fc: tx_32fc failed" << std::endl; + return -1; // say we're done + } + + return noutput_items; +} diff --git a/gr-vrt/src/vrt_sink_32fc.h b/gr-vrt/src/vrt_sink_32fc.h new file mode 100644 index 000000000..55a6512f0 --- /dev/null +++ b/gr-vrt/src/vrt_sink_32fc.h @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_USRP2_SINK_32FC_H +#define INCLUDED_USRP2_SINK_32FC_H + +#include <vrt_sink_base.h> + +class vrt_sink_32fc; +typedef boost::shared_ptr<vrt_sink_32fc> vrt_sink_32fc_sptr; + +vrt_sink_32fc_sptr +vrt_make_sink_32fc(const std::string &ifc="eth0", + const std::string &mac="") + throw (std::runtime_error); + +class vrt_sink_32fc : public vrt_sink_base +{ +private: + friend vrt_sink_32fc_sptr + vrt_make_sink_32fc(const std::string &ifc, + const std::string &mac) + throw (std::runtime_error); + +protected: + vrt_sink_32fc(const std::string &ifc, const std::string &mac) + throw (std::runtime_error); + +public: + ~vrt_sink_32fc(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_USRP2_SINK_32FC_H */ diff --git a/gr-vrt/src/vrt_sink_base.cc b/gr-vrt/src/vrt_sink_base.cc new file mode 100644 index 000000000..a75024dcc --- /dev/null +++ b/gr-vrt/src/vrt_sink_base.cc @@ -0,0 +1,151 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <vrt_sink_base.h> +#include <gr_io_signature.h> +#include <iostream> + +vrt_sink_base::vrt_sink_base(const char *name, + gr_io_signature_sptr input_signature, + const std::string &ifc, + const std::string &mac) + throw (std::runtime_error) + : vrt_base(name, + input_signature, + gr_make_io_signature(0, 0, 0), + ifc, mac) +{ + // NOP +} + +vrt_sink_base::~vrt_sink_base () +{ + // NOP +} + +bool +vrt_sink_base::set_gain(double gain) +{ + return d_u2->set_tx_gain(gain); +} + +bool +vrt_sink_base::set_lo_offset(double frequency) +{ + return d_u2->set_tx_lo_offset(frequency); +} + +bool +vrt_sink_base::set_center_freq(double frequency, vrt::tune_result *tr) +{ + return d_u2->set_tx_center_freq(frequency, tr); +} + +bool +vrt_sink_base::set_interp(int interp_factor) +{ + return d_u2->set_tx_interp(interp_factor); +} + +void +vrt_sink_base::default_scale_iq(int interp_factor, int *scale_i, int *scale_q) +{ + return d_u2->default_tx_scale_iq(interp_factor, scale_i, scale_q); +} + +bool +vrt_sink_base::set_scale_iq(int scale_i, int scale_q) +{ + return d_u2->set_tx_scale_iq(scale_i, scale_q); +} + +int +vrt_sink_base::interp() +{ + return d_u2->tx_interp(); +} + +bool +vrt_sink_base::dac_rate(long *rate) +{ + return d_u2->dac_rate(rate); +} + +double +vrt_sink_base::gain_min() +{ + return d_u2->tx_gain_min(); +} + +double +vrt_sink_base::gain_max() +{ + return d_u2->tx_gain_max(); +} + +double +vrt_sink_base::gain_db_per_step() +{ + return d_u2->tx_gain_db_per_step(); +} + +double +vrt_sink_base::freq_min() +{ + return d_u2->tx_freq_min(); +} + +double +vrt_sink_base::freq_max() +{ + return d_u2->tx_freq_max(); +} + +bool +vrt_sink_base::daughterboard_id(int *dbid) +{ + return d_u2->tx_daughterboard_id(dbid); +} + +bool vrt_sink_base::set_gpio_ddr(uint16_t value, uint16_t mask) +{ + return d_u2->set_gpio_ddr(vrt::GPIO_TX_BANK, value, mask); +} + +bool vrt_sink_base::set_gpio_sels(std::string sels) +{ + return d_u2->set_gpio_sels(vrt::GPIO_TX_BANK, sels); +} + +bool vrt_sink_base::write_gpio(uint16_t value, uint16_t mask) +{ + return d_u2->write_gpio(vrt::GPIO_TX_BANK, value, mask); +} + +bool vrt_sink_base::read_gpio(uint16_t *value) +{ + return d_u2->read_gpio(vrt::GPIO_TX_BANK, value); +} diff --git a/gr-vrt/src/vrt_sink_base.h b/gr-vrt/src/vrt_sink_base.h new file mode 100644 index 000000000..5f0532d8e --- /dev/null +++ b/gr-vrt/src/vrt_sink_base.h @@ -0,0 +1,139 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_USRP2_SINK_BASE_H +#define INCLUDED_USRP2_SINK_BASE_H + +#include <vrt_base.h> + +/*! + * Base class for all USRP2 transmit blocks + */ +class vrt_sink_base : public vrt_base +{ +protected: + vrt_sink_base(const char *name, + gr_io_signature_sptr input_signature, + const std::string &ifc, + const std::string &mac) + throw (std::runtime_error); + +public: + ~vrt_sink_base(); + + /*! + * \brief Set transmitter gain + */ + bool set_gain(double gain); + + /*! + * \brief Set transmitter LO offset frequency + */ + bool set_lo_offset(double frequency); + + /*! + * \brief Set transmitter center frequency + */ + bool set_center_freq(double frequency, vrt::tune_result *tr); + + /*! + * \brief Set transmit interpolation rate + */ + bool set_interp(int interp_factor); + + /*! + * \brief Calculate default scale_iq for given interpolation factor + */ + void default_scale_iq(int interpolation_factor, int *scale_i, int *scale_q); + + /*! + * \brief Set transmit IQ scale factors + */ + bool set_scale_iq(int scale_i, int scale_q); + + /*! + * \brief Get transmit interpolation rate + */ + int interp(); + + /*! + * \brief Get DAC sample rate in Hz + */ + bool dac_rate(long *rate); + + /*! + * \brief Returns minimum Tx gain + */ + double gain_min(); + + /*! + * \brief Returns maximum Tx gain + */ + double gain_max(); + + /*! + * \brief Returns Tx gain db_per_step + */ + double gain_db_per_step(); + + /*! + * \brief Returns minimum Tx center frequency + */ + double freq_min(); + + /*! + * \brief Returns maximum Tx center frequency + */ + double freq_max(); + + /*! + * \brief Get Tx daughterboard ID + * + * \param[out] dbid returns the daughterboard id. + * + * daughterboard id >= 0 if successful, -1 if no daugherboard installed, + * -2 if invalid EEPROM on daughterboard. + */ + bool daughterboard_id(int *dbid); + + /*! + * \brief Set daughterboard GPIO data direction register. + */ + bool set_gpio_ddr(uint16_t value, uint16_t mask); + + /*! + * \brief Set daughterboard GPIO output selection register. + */ + bool set_gpio_sels(std::string sels); + + /*! + * \brief Set daughterboard GPIO pin values. + */ + bool write_gpio(uint16_t value, uint16_t mask); + + /*! + * \brief Read daughterboard GPIO pin values + */ + bool read_gpio(uint16_t *value); +}; + +#endif /* INCLUDED_USRP2_SINK_BASE_H */ diff --git a/gr-vrt/src/vrt_source_16sc.cc b/gr-vrt/src/vrt_source_16sc.cc new file mode 100644 index 000000000..f0ea35bb3 --- /dev/null +++ b/gr-vrt/src/vrt_source_16sc.cc @@ -0,0 +1,69 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <vrt_source_16sc.h> +#include <rx_16sc_handler.h> +#include <gr_io_signature.h> +#include <iostream> + +vrt_source_16sc_sptr +vrt_make_source_16sc(const std::string &ifc, const std::string &mac_addr) + throw (std::runtime_error) +{ + return gnuradio::get_initial_sptr(new vrt_source_16sc(ifc, mac_addr)); +} + +vrt_source_16sc::vrt_source_16sc(const std::string &ifc, const std::string &mac_addr) + throw (std::runtime_error) + : vrt_source_base("vrt_source_16sc", + gr_make_io_signature(1, 1, sizeof(std::complex<int16_t>)), + ifc, mac_addr) +{ + set_output_multiple(USRP2_MIN_RX_SAMPLES); +} + +vrt_source_16sc::~vrt_source_16sc() +{ + // NOP +} + +int +vrt_source_16sc::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + std::complex<int16_t> *out = (std::complex<int16_t> *)output_items[0]; + + rx_16sc_handler::sptr handler = rx_16sc_handler::make(noutput_items, USRP2_MIN_RX_SAMPLES, out); + + bool ok = d_u2->rx_samples(0, handler.get()); // FIXME: channel number instead of 0 + if (!ok){ + std::cerr << "vrt::rx_samples() failed" << std::endl; + return -1; // say we're done + } + + return handler->nsamples(); +} diff --git a/gr-vrt/src/vrt_source_16sc.h b/gr-vrt/src/vrt_source_16sc.h new file mode 100644 index 000000000..34175b3ca --- /dev/null +++ b/gr-vrt/src/vrt_source_16sc.h @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_USRP2_SOURCE_16SC_H +#define INCLUDED_USRP2_SOURCE_16SC_H + +#include <vrt_source_base.h> + +class vrt_source_16sc; +typedef boost::shared_ptr<vrt_source_16sc> vrt_source_16sc_sptr; + +vrt_source_16sc_sptr +vrt_make_source_16sc(const std::string &ifc="eth0", + const std::string &mac="") + throw (std::runtime_error); + +class vrt_source_16sc : public vrt_source_base +{ +private: + friend vrt_source_16sc_sptr + vrt_make_source_16sc(const std::string &ifc, + const std::string &mac) throw (std::runtime_error); + +protected: + vrt_source_16sc(const std::string &ifc, const std::string &mac) throw (std::runtime_error); + +public: + ~vrt_source_16sc(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_USRP2_SOURCE_16SC_H */ diff --git a/gr-vrt/src/vrt_source_32fc.cc b/gr-vrt/src/vrt_source_32fc.cc new file mode 100644 index 000000000..beb5ef26d --- /dev/null +++ b/gr-vrt/src/vrt_source_32fc.cc @@ -0,0 +1,144 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <vrt_source_32fc.h> +#include <vrt/expanded_header.h> +#include <vrt/copiers.h> +#include <gr_io_signature.h> +#include <missing_pkt_checker.h> +#include <iostream> + +#define VERBOSE 1 // define to 0 or 1 + + +class rx_32fc_handler : public vrt::rx_packet_handler +{ + int d_noutput_items; + std::complex<float> *d_out; + int *d_oo; // output index + std::vector< std::complex<float> > &d_remainder; + missing_pkt_checker &d_checker; + + +public: + + rx_32fc_handler(int noutput_items, std::complex<float> *out, + int *oo, std::vector< std::complex<float> > &remainder, + missing_pkt_checker &checker) + : d_noutput_items(noutput_items), d_out(out), + d_oo(oo), d_remainder(remainder), d_checker(checker) {} + + ~rx_32fc_handler(); + + bool operator()(const uint32_t *payload, + size_t n32_bit_words, + const vrt::expanded_header *hdr); +}; + +rx_32fc_handler::~rx_32fc_handler() +{ +} + +bool +rx_32fc_handler::operator()(const uint32_t *payload, + size_t n32_bit_words, + const vrt::expanded_header *hdr) +{ + int nmissing = d_checker.check(hdr); + if (VERBOSE && nmissing != 0){ + std::cerr << "S" << nmissing; + } + + // copy as many as will fit into the output buffer. + + size_t n = std::min(n32_bit_words, (size_t)(d_noutput_items - *d_oo)); + vrt::copy_net_16sc_to_host_32fc(n, payload, &d_out[*d_oo]); + *d_oo += n; + + // if there are any left over, copy them into remainder and tell + // our caller we're had enough for now. + + size_t r = n32_bit_words - n; + if (r > 0){ + assert(d_remainder.size() == 0); + d_remainder.resize(r); + vrt::copy_net_16sc_to_host_32fc(r, &payload[n], &d_remainder[0]); + return false; // Stop calling us. + } + + return true; // Keep calling us, we've got more room +} + + +// ------------------------------------------------------------------------ + +vrt_source_32fc::vrt_source_32fc(const char *name) + + : vrt_source_base(name, + gr_make_io_signature(1, 1, sizeof(gr_complex))) +{ +} + +vrt_source_32fc::~vrt_source_32fc() +{ + if (VERBOSE){ + std::cerr << "\nvrt_source_32fc: npackets = " << d_checker.npackets() + << " nwrong_pkt_cnt = " << d_checker.nwrong_pkt_cnt() + << " nmissing_pkt_est = " << d_checker.nmissing_pkt_est() + << std::endl; + } +} + +int +vrt_source_32fc::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + gr_complex *out = (gr_complex *)output_items[0]; + int oo = 0; + + // Handle any samples left over from the last call. + int t = std::min(noutput_items, (int)d_remainder.size()); + if (t != 0){ + for (int i = 0; i < t; i++) + out[i] = d_remainder[i]; + d_remainder.erase(d_remainder.begin(), d_remainder.begin()+t); + oo = t; + } + if (noutput_items - oo == 0) + return oo; + + // While we've got room, and there are packets, handle them + rx_32fc_handler h(noutput_items, out, &oo, d_remainder, d_checker); + bool ok = vrt_rx()->rx_packets(&h); + + if (!ok){ + std::cerr << "vrt_source_32fc: vrt::rx_packets() failed" << std::endl; + return -1; // say we're done + } + + return oo; +} diff --git a/gr-vrt/src/vrt_source_32fc.h b/gr-vrt/src/vrt_source_32fc.h new file mode 100644 index 000000000..7ca3e5fe2 --- /dev/null +++ b/gr-vrt/src/vrt_source_32fc.h @@ -0,0 +1,48 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_VRT_SOURCE_32FC_H +#define INCLUDED_VRT_SOURCE_32FC_H + +#include <vrt_source_base.h> +#include <missing_pkt_checker.h> + +class vrt_source_32fc : public vrt_source_base +{ +protected: + vrt_source_32fc(const char *name); + + std::vector< std::complex<float> > d_remainder; + missing_pkt_checker d_checker; + +public: + ~vrt_source_32fc(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + void reset() { d_remainder.clear(); } + +}; + +#endif /* INCLUDED_VRT_SOURCE_32FC_H */ diff --git a/gr-vrt/src/vrt_source_base.cc b/gr-vrt/src/vrt_source_base.cc new file mode 100644 index 000000000..40e871653 --- /dev/null +++ b/gr-vrt/src/vrt_source_base.cc @@ -0,0 +1,41 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <vrt_source_base.h> +#include <gr_io_signature.h> +#include <iostream> + +vrt_source_base::vrt_source_base(const char *name, + gr_io_signature_sptr output_signature) + : gr_sync_block(name, + gr_make_io_signature(0, 0, 0), + output_signature) +{ +} + +vrt_source_base::~vrt_source_base() +{ +} diff --git a/gr-vrt/src/vrt_source_base.h b/gr-vrt/src/vrt_source_base.h new file mode 100644 index 000000000..e67778860 --- /dev/null +++ b/gr-vrt/src/vrt_source_base.h @@ -0,0 +1,45 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_VRT_SOURCE_BASE_H +#define INCLUDED_VRT_SOURCE_BASE_H + +#include <gr_sync_block.h> +#include <vrt/rx.h> +#include <gr_io_signature.h> + +/*! + * Base class for all VRT source blocks + */ +class vrt_source_base : public gr_sync_block +{ +protected: + vrt_source_base(const char *name, + gr_io_signature_sptr output_signature); + +public: + ~vrt_source_base(); + + virtual vrt::rx::sptr vrt_rx() const = 0; +}; + +#endif /* INCLUDED_VRT_SOURCE_BASE_H */ diff --git a/vrt/Makefile.am b/vrt/Makefile.am new file mode 100644 index 000000000..791b8d65c --- /dev/null +++ b/vrt/Makefile.am @@ -0,0 +1,29 @@ +# +# Copyright 2008,2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +include $(top_srcdir)/Makefile.common + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = vrt.pc + +EXTRA_DIST = \ + vrt.pc.in + +SUBDIRS = include lib apps diff --git a/vrt/apps/Makefile.am b/vrt/apps/Makefile.am new file mode 100644 index 000000000..631d9020b --- /dev/null +++ b/vrt/apps/Makefile.am @@ -0,0 +1,36 @@ +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +include $(top_srcdir)/Makefile.common + +AM_CPPFLAGS = \ + $(VRT_INCLUDES) \ + $(STD_DEFINES_AND_INCLUDES) \ + $(CPPUNIT_INCLUDES) + +LDADD = \ + $(VRT_LA) \ + $(GRUEL_LA) + + +bin_PROGRAMS = + +noinst_PROGRAMS = \ + simple_rx_samples + +simple_rx_samples_SOURCES = simple_rx_samples.cc + diff --git a/vrt/apps/simple_rx_samples.cc b/vrt/apps/simple_rx_samples.cc new file mode 100644 index 000000000..6b09afda5 --- /dev/null +++ b/vrt/apps/simple_rx_samples.cc @@ -0,0 +1,394 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <vrt/quadradio.h> +#include <vrt/rx.h> +#include <vrt/copiers.h> + +#include <errno.h> +#include <iostream> +#include <boost/scoped_ptr.hpp> +#include <boost/shared_ptr.hpp> +#include <stdexcept> +#include <signal.h> +#include <unistd.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <gruel/realtime.h> +#include <complex> + +#define MIN_IP_LOCAL_PORT 32768 +#define MAX_IP_LOCAL_PORT 61000 + +static volatile bool signaled = false; + +static void +sig_handler(int sig) +{ + signaled = true; +} + +static void +install_sig_handler(int signum, + void (*new_handler)(int)) +{ + struct sigaction new_action; + memset (&new_action, 0, sizeof (new_action)); + + new_action.sa_handler = new_handler; + sigemptyset (&new_action.sa_mask); + new_action.sa_flags = 0; + + if (sigaction (signum, &new_action, 0) < 0){ + perror ("sigaction (install new)"); + throw std::runtime_error ("sigaction"); + } +} + +// ------------------------------------------------------------------------ + +class rx_nop_handler : public vrt::rx_packet_handler +{ +private: + uint64_t d_max_samples; + uint64_t d_max_quantum; + uint64_t d_nsamples; + uint64_t d_npackets; + int d_last_pkt_cnt; + uint64_t d_nwrong_pkt_cnt; + +protected: + bool d_err; + +public: + + // Shared pointer to an instance of this class + typedef boost::shared_ptr<rx_nop_handler> sptr; + + /*! + * Constructor + * + * \param max_samples Maximum number of samples to copy. Use zero for no maximum. + * \param max_quantum Maximum number of samples required to accept in one call. + * Use 0 to indicate no maximum. + */ + rx_nop_handler(uint64_t max_samples, uint64_t max_quantum=0) + : d_max_samples(max_samples), d_max_quantum(max_quantum), + d_nsamples(0), d_npackets(0), + d_last_pkt_cnt(0xf), d_nwrong_pkt_cnt(0), + d_err(false){} + + + ~rx_nop_handler(); + + bool operator()(const uint32_t *payload, + size_t n32_bit_words, + const vrt::expanded_header *hdr); + + /*! + * \brief Returns number of packets this copier was called with + */ + uint64_t npackets() const { return d_npackets; } + + /*! + * \brief Returns actual number of samples copied + */ + uint64_t nsamples() const { return d_nsamples; } + + /*! + * \brief Returns maximum number of samples that will be copied + */ + uint64_t max_samples() const { return d_max_samples; } + + /*! + * Returns true if an error has occurred. Derived classes must set d_err to true + * when an error occurs in the () operator + */ + bool has_errored_p() const { return d_err; } + + /*! + * \brief Returns true if this instance has reached the maximum number of samples + */ + bool has_finished_p() const + { return d_max_samples == 0 ? false : d_nsamples >= d_max_samples-d_max_quantum; } + + uint64_t nwrong_pkt_cnt() const { return d_nwrong_pkt_cnt; } + + +}; + + +rx_nop_handler::~rx_nop_handler() +{ +} + +bool +rx_nop_handler::operator()(const uint32_t *payload, + size_t n32_bit_words, + const vrt::expanded_header *hdr) +{ + if (d_npackets != 0 && hdr->pkt_cnt() != ((d_last_pkt_cnt + 1) & 0xf)){ + d_nwrong_pkt_cnt++; + fprintf(stderr, "bad cnt (pkt %lld)\n", d_npackets); + } + d_last_pkt_cnt = hdr->pkt_cnt(); + + d_nsamples += n32_bit_words; + d_npackets++; + + return !has_finished_p(); +} + +// ------------------------------------------------------------------------ + +class file_writer_16sc : public rx_nop_handler +{ + FILE *d_fp; + std::string d_filename; + +public: + + file_writer_16sc(const std::string &filename, uint64_t max_samples) + : rx_nop_handler(max_samples), d_filename(filename) + { + d_fp = fopen(filename.c_str(), "wb"); + if (d_fp == 0){ + perror(filename.c_str()); + throw std::invalid_argument(filename); + } + } + + ~file_writer_16sc(); + + bool + operator()(const uint32_t *items, size_t nitems, const vrt::expanded_header *hdr) + { + bool ok = rx_nop_handler::operator()(items, nitems, hdr); + + size_t host_nitems = nitems; + std::complex<int16_t> host_items[host_nitems]; + + vrt::copy_net_16sc_to_host_16sc(nitems, items, host_items); + + size_t n = 0; + while (n < host_nitems){ + size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems - n, d_fp); + n += r; + if (r == 0){ // out of space? + d_err = true; + perror(d_filename.c_str()); + ok = false; + break; + } + } + + return ok; + } +}; + +file_writer_16sc::~file_writer_16sc() +{ + fclose(d_fp); +} + +// ------------------------------------------------------------------------ + +class file_writer_32fc : public rx_nop_handler +{ + FILE *d_fp; + std::string d_filename; + +public: + + file_writer_32fc(const std::string &filename, uint64_t max_samples) + : rx_nop_handler(max_samples), d_filename(filename) + { + d_fp = fopen(filename.c_str(), "wb"); + if (d_fp == 0){ + perror(filename.c_str()); + throw std::invalid_argument(filename); + } + } + + ~file_writer_32fc(); + + bool + operator()(const uint32_t *items, size_t nitems, const vrt::expanded_header *hdr) + { + bool ok = rx_nop_handler::operator()(items, nitems, hdr); + + size_t host_nitems = nitems; + std::complex<float> host_items[host_nitems]; + + vrt::copy_net_16sc_to_host_32fc(nitems, items, host_items); + + size_t n = 0; + while (n < host_nitems){ + size_t r = fwrite(&host_items[n], sizeof(host_items[0]), host_nitems - n, d_fp); + n += r; + if (r == 0){ // out of space? + d_err = true; + perror(d_filename.c_str()); + ok = false; + break; + } + } + + return ok; + } +}; + +file_writer_32fc::~file_writer_32fc() +{ + fclose(d_fp); +} + +// ------------------------------------------------------------------------ + +static void +usage(const char *progname) +{ + const char *p = strrchr(progname, '/'); // drop leading directory path + if (p) + p++; + + if (strncmp(p, "lt-", 3) == 0) // drop lt- libtool prefix + p += 3; + + fprintf(stderr, "Usage: %s [options]\n\n", p); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -h show this message and exit\n"); +//fprintf(stderr, " -e ETH_INTERFACE specify ethernet interface [default=eth0]\n"); +//fprintf(stderr, " -m MAC_ADDR mac address of USRP2 HH:HH [default=first one found]\n"); +//fprintf(stderr, " -f FREQUENCY specify receive center frequency in Hz [default=0.0]\n"); +//fprintf(stderr, " -d DECIM specify receive decimation rate [default=5]\n"); +//fprintf(stderr, " -g GAIN specify receive daughterboard gain [default=0]\n"); + fprintf(stderr, " -N NSAMPLES specify number of samples to receive [default=infinite]\n"); + fprintf(stderr, " -o OUTPUT_FILENAME specify file to receive samples [default=none]\n"); + fprintf(stderr, " -s write complex<short> [default=complex<float>]\n"); + fprintf(stderr, " -S samples_per_pkt specify # of samples per pkt [default=maximum]\n"); +//fprintf(stderr, " -v verbose output\n"); +} + + +int +main(int argc, char **argv) +{ + const char *quad_radio_ip = "192.168.123.123"; + size_t rx_bufsize = 62.5e6; // sizeof memory mapped network buffer + int samples_per_pkt = 0; // use default + uint64_t nsamples = 0; + char *output_filename = 0; + bool output_shorts = false; + int t; + + int ch; + + while ((ch = getopt(argc, argv, "hN:o:sS:")) != EOF){ + switch (ch){ + case 'N': + nsamples = (uint64_t) strtod(optarg, 0); + break; + + case 'o': + output_filename = optarg; + break; + + case 's': + output_shorts = true; + break; + + case 'S': + errno = 0; + t = strtol(optarg, 0, 0); + if (errno != 0){ + usage(argv[0]); + exit(1); + } + samples_per_pkt = t; + break; + + case 'h': + default: + usage(argv[0]); + exit(1); + } + } + + + install_sig_handler(SIGINT, sig_handler); + + gruel::rt_status_t rt = gruel::enable_realtime_scheduling(); + if (rt != gruel::RT_OK) + std::cerr << "Failed to enable realtime scheduling" << std::endl; + + + vrt::quadradio::sptr qr; + try { + qr = vrt::quadradio::sptr(new vrt::quadradio(quad_radio_ip, rx_bufsize)); + } + catch (...){ + std::cerr << "Failed to create vrt::quadradio\n"; + return 1; + } + + + rx_nop_handler::sptr handler; + if (output_filename){ + if (output_shorts) + handler = rx_nop_handler::sptr(new file_writer_16sc(output_filename, nsamples)); + else + handler = rx_nop_handler::sptr(new file_writer_32fc(output_filename, nsamples)); + } + else + handler = rx_nop_handler::sptr(new rx_nop_handler(nsamples)); + + + printf("samples_per_pkt = %d\n", samples_per_pkt); + + if (!qr->start_streaming(samples_per_pkt)){ + fprintf(stderr, "failed to send_rx_command\n"); + return 1; + } + + // start receiving packets + + while(1 + && !signaled + && !handler->has_errored_p() + && !handler->has_finished_p()){ + bool ok = qr->vrt_rx()->rx_packets(handler.get()); + if (!ok){ + fprintf(stderr, "vrt->rx_packets failed\n"); + break; + } + } + + qr->stop_streaming(); + + printf("%llu packets received, %llu bad pkt_cnt field values, %llu samples\n", + handler->npackets(), handler->nwrong_pkt_cnt(), handler->nsamples()); + + //sleep(1); + + return 0; +} diff --git a/vrt/include/Makefile.am b/vrt/include/Makefile.am new file mode 100644 index 000000000..3ce6a8f32 --- /dev/null +++ b/vrt/include/Makefile.am @@ -0,0 +1,23 @@ +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +include $(top_srcdir)/Makefile.common + +SUBDIRS = vrt diff --git a/vrt/include/vrt/Makefile.am b/vrt/include/vrt/Makefile.am new file mode 100644 index 000000000..b710547d9 --- /dev/null +++ b/vrt/include/vrt/Makefile.am @@ -0,0 +1,30 @@ +# +# Copyright 2008,2009 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +include $(top_srcdir)/Makefile.common + +INCLUDES = + +vrtincludedir = $(includedir)/vrt + +vrtinclude_HEADERS = \ + bits.h \ + copiers.h \ + expanded_header.h \ + quadradio.h \ + rx.h \ + rx_packet_handler.h diff --git a/vrt/include/vrt/bits.h b/vrt/include/vrt/bits.h new file mode 100644 index 000000000..bb4227db4 --- /dev/null +++ b/vrt/include/vrt/bits.h @@ -0,0 +1,72 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INCLUDED_VRT_BITS_H +#define INCLUDED_VRT_BITS_H + +#include <stdint.h> + + +/* VRT Header bits */ + +#define VRTH_PT_MASK (0xf << 28) +#define VRTH_PT_IF_DATA_NO_SID (0x0 << 28) // IF-Data, no stream id +#define VRTH_PT_IF_DATA_WITH_SID (0x1 << 28) // IF-Data, w/ stream id +#define VRTH_PT_EXT_DATA_NO_SID (0x2 << 28) +#define VRTH_PT_EXT_DATA_WITH_SID (0x3 << 28) +#define VRTH_PT_IF_CONTEXT (0x4 << 28) +#define VRTH_PT_EXT_CONTEXT (0x5 << 28) + +#define VRTH_HAS_CLASSID (1 << 27) +#define VRTH_HAS_TRAILER (1 << 26) // Data pkts only +#define VRTH_START_OF_BURST (1 << 25) // Data (Tx) pkts only +#define VRTH_END_OF_BURST (1 << 24) // Data (Tx) pkts only +#define VRTH_TSM (1 << 24) // Context pkts only + +#define VRTH_TSI_MASK (0x3 << 22) +#define VRTH_TSI_NONE (0x0 << 22) +#define VRTH_TSI_UTC (0x1 << 22) +#define VRTH_TSI_GPS (0x2 << 22) +#define VRTH_TSI_OTHER (0x3 << 22) + +#define VRTH_TSF_MASK (0x3 << 20) +#define VRTH_TSF_NONE (0x0 << 20) +#define VRTH_TSF_SAMPLE_CNT (0x1 << 20) +#define VRTH_TSF_REAL_TIME_PS (0x2 << 20) +#define VRTH_TSF_FREE_RUNNING (0x3 << 20) + +#define VRTH_PKT_CNT_MASK (0xf << 16) +#define VRTH_PKT_SIZE_MASK 0xffff + + +static inline int +vrth_pkt_cnt(uint32_t h) +{ + return (h & VRTH_PKT_CNT_MASK) >> 16; +} + +static inline int +vrth_pkt_size(uint32_t h) +{ + return h & VRTH_PKT_SIZE_MASK; +} + +#endif /* INCLUDED_VRT_BITS_H */ diff --git a/vrt/include/vrt/copiers.h b/vrt/include/vrt/copiers.h new file mode 100644 index 000000000..990538c42 --- /dev/null +++ b/vrt/include/vrt/copiers.h @@ -0,0 +1,49 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INCLUDED_VRT_COPIERS_H +#define INCLUDED_VRT_COPIERS_H + +#include <stdint.h> +#include <stddef.h> +#include <complex> + +namespace vrt { + + /*! + * \brief Copy and convert from net format to host format + */ + void + copy_net_16sc_to_host_16sc(size_t nitems, + const uint32_t *items, + std::complex<int16_t> *host_items); + + + /*! + * \brief Copy and convert from net format to host format mapping [-32768, 32767] -> [1.0, +1.0) + */ + void + copy_net_16sc_to_host_32fc(size_t nitems, + const uint32_t *items, + std::complex<float> *host_items); +}; + +#endif /* INCLUDED_VRT_COPIERS_H */ diff --git a/vrt/include/vrt/expanded_header.h b/vrt/include/vrt/expanded_header.h new file mode 100644 index 000000000..0cfca04a1 --- /dev/null +++ b/vrt/include/vrt/expanded_header.h @@ -0,0 +1,99 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef INCLUDED_VRT_EXPANDED_HEADER_H +#define INCLUDED_VRT_EXPANDED_HEADER_H + +#include <stdint.h> +#include <stddef.h> +#include <vrt/bits.h> + +namespace vrt { + + /*! + * \brief All headers and trailer for VRT IF-Data, Extension-Data, + * IF-Context and Extension-Context packets. + * + * There are fields allocated for each possible header. Their content may + * or may not be valid. Check the header field to confirm their validity. + * All values are in host-endian format. + */ + struct expanded_header { + uint32_t header; // first word of all packets + uint32_t stream_id; // optional stream identifier + uint64_t class_id; // optional class identifier + uint32_t integer_secs; // optional integer seconds timestamp + uint64_t fractional_secs; // optional fractional seconds timestamp + uint32_t trailer; // optional trailer (only possible in data pkts) + + expanded_header() + : header(0) /*, stream_id(0), class_id(0), + integer_secs(0), fractional_secs(0), trailer(0)*/ {} + + + int pkt_type() const { + return (header & VRTH_PT_MASK) >> 28; + } + + int pkt_cnt() const { return vrth_pkt_cnt(header); } + size_t pkt_size() const { return vrth_pkt_size(header); } + + + // packet type predicates + bool if_data_p() const { return s_if_data[pkt_type()]; } + bool ext_data_p() const { return s_ext_data[pkt_type()]; } + bool if_context_p() const { return (header & VRTH_PT_MASK) == VRTH_PT_IF_CONTEXT; } + bool ext_context_p() const { return (header & VRTH_PT_MASK) == VRTH_PT_EXT_CONTEXT; } + + bool data_p() const { return s_data[pkt_type()]; } // if_data_p() || ext_data_p() + bool context_p() const { return s_context[pkt_type()]; } // if_context_p() || ext_context_p() + + // optional info predicates + bool stream_id_p() const { return s_stream_id[pkt_type()]; } + bool class_id_p() const { return (header & VRTH_HAS_CLASSID) != 0; } + bool integer_secs_p() const { return (header & VRTH_TSI_MASK) != 0; } + bool fractional_secs_p() const { return (header & VRTH_TSF_MASK) != 0; } + bool trailer_p() const { return (header & VRTH_HAS_TRAILER) != 0 && data_p(); } + + + // parser + + /*! + * \brief parse packet, fill-in expanded header, start of payload and len of payload + */ + static bool parse(const uint32_t *packet, // in + size_t n32_bit_words_packet, // in + expanded_header *hdr, // out + const uint32_t **payload, // out + size_t *n32_bit_words_payload); // out + + private: + static unsigned char s_if_data[16]; + static unsigned char s_ext_data[16]; + static unsigned char s_data[16]; + static unsigned char s_context[16]; + static unsigned char s_stream_id[16]; + + }; + +}; // vrt + + +#endif /* INCLUDED_VRT_EXPANDED_HEADER_H */ diff --git a/vrt/include/vrt/quadradio.h b/vrt/include/vrt/quadradio.h new file mode 100644 index 000000000..747ca8ef4 --- /dev/null +++ b/vrt/include/vrt/quadradio.h @@ -0,0 +1,129 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef INCLUDED_VRT_QUADRADIO_H +#define INCLUDED_VRT_QUADRADIO_H + +#include <vrt/rx.h> + +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/types.h> +#include <sys/socket.h> + +typedef enum{ + VRT_TEST_SIG_NORMAL=0, + VRT_TEST_SIG_ZEROS=1, + VRT_TEST_SIG_ONES=2, + VRT_TEST_SIG_TOGGLE=3, + VRT_TEST_SIG_RAMP=4, + VRT_TEST_SIG_CUSTOM=5, + + } vrt_test_sig_t; + +namespace vrt { + + /* + * We're not committing to this interface. It's just here so we can make progress... + * + * This implements the ad-hoc control for bringup and has-a vrt::rx + */ + class quadradio + { + int d_ctrl_fd; // socket for control + struct in_addr d_ctrl_port_inaddr; // our ip addr + int d_data_fd; // socket for data (owned by d_rx) + int d_data_port; // our data port number + vrt::rx::sptr d_rx; // has-a rx + + int d_band_select; // band select setting + int d_rx_antenna; // antenna type rf/cal + int d_attenuation0; // attenuation setting + int d_attenuation1; // attenuation setting + bool d_10dB_atten; // 10dB attenuation on/of + + static bool + open_sockets(const char *quad_radio_ip, int quad_radio_ctrl_port, + int *ctrl_fd_ptr, struct in_addr *ctrl_port_inaddr, + int *data_fd_ptr, int *data_port_ptr); + + static bool + send_rx_command(int ctrl_fd, bool start, + struct in_addr addr, int data_port, int samples_per_pkt, int siggen_param); + + static bool + send_stop_rx_command(int ctrl_fd); + + static int control_port() { return 790; } + int data_socket_fd() const { return d_data_fd; } + + bool open(const char *ip); + + void update_dboard_pins(void); + + public: + typedef boost::shared_ptr<quadradio> sptr; + + quadradio(const std::string &ip, size_t rx_bufsize = 0); + ~quadradio(); + + vrt::rx::sptr vrt_rx() const { return d_rx; } + + bool start_streaming(int samples_per_pkt = 0); + bool stop_streaming(); + + + /* convenience methods that ultimately write the dboard pins */ + bool set_center_freq(double target_freq); + bool set_band_select(const std::string &band); + //void set_10dB_atten(bool on); + bool set_attenuation0(int attenuation); + bool select_rx_antenna(const std::string &ant); + bool set_attenuation1(int attenuation); + + /* convenience methods that ultimately call set_hsadc_conf */ + void set_adc_gain(bool on); + void set_dc_offset_comp(bool on); + void set_digital_gain(float gain); + void set_test_signal(vrt_test_sig_t type); + + /* primitives */ + bool set_setting_reg(int regno, int value); + bool set_mem32(int addr, int value); // poke a 32-bit value + bool set_lo_freq(double freq); + bool set_cal_freq(double freq); + bool set_beamforming(int32_t gains[8]); + /* + * The first parameter for these is a bitmask which indicates which + * daughterboard or daughterboards to apply the operation to. + * 0x1 -> dboard 0 + * 0x2 -> dboard 1 + * 0x3 -> dboard 0 and 1... + */ + bool set_dboard_pins(int dboard_bitmask, int v); + bool set_hsadc_conf(int dboard_bitmask, int regno, int value); + bool set_lsdac(int dboard_bitmask, int which_dac, int value); + + }; + +}; + + +#endif /* INCLUDED_QUADRADIO_H */ diff --git a/vrt/include/vrt/rx.h b/vrt/include/vrt/rx.h new file mode 100644 index 000000000..ff3ce85fb --- /dev/null +++ b/vrt/include/vrt/rx.h @@ -0,0 +1,93 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef INCLUDED_VRT_RX_H +#define INCLUDED_VRT_RX_H + +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> +#include <vrt/rx_packet_handler.h> + +namespace vrt { + + class socket_rx_buffer; + + /*! + * Relatively low-level interface to receive VRT packets over a datagram socket. + * + * (We'll refactor this if/when we use a non-UDP transport.) + * No VRT control issues are addressed here. + */ + class rx : boost::noncopyable + { + int d_socket_fd; + socket_rx_buffer *d_srb; + + public: + /*! + * Shared pointer to this class + */ + typedef boost::shared_ptr<rx> sptr; + + /*! + * \brief Static function to return an instance of rx as a shared pointer. + * + * \param socket_fd file descriptor that data grams will be received from. + * It is assumed that some higher-level control software + * opened the appropriate UDP socket for us. This object + * assumes management of the socket's lifetime. The + * socket will be closed when our destructor fires. + * + * \param rx_bufsize is a hint as to the number of bytes of memory + * to allocate for received ethernet frames (0 -> reasonable default) + */ + static sptr make(int socket_fd, size_t rx_bufsize = 0); + + /*! + * \param socket_fd file descriptor that data grams will be received from. + * It is assumed that some higher-level control software + * opened the appropriate UDP socket for us. This object + * assumes management of the socket's lifetime. The + * socket will be closed when our destructor fires. + * + * \param rx_bufsize is a hint as to the number of bytes of memory + * to allocate for received ethernet frames (0 -> reasonable default) + */ + rx(int socket_fd, size_t rx_bufsize = 0); + ~rx(); + + /*! + * \brief Receive packets from the given socket file descriptor. + * + * \p handler will be invoked for all available packets. + * Unless \p dont_wait is true, this function blocks until at + * least one packet has been processed. + */ + bool rx_packets(rx_packet_handler *handler, bool dont_wait = false); + + /* + * \returns the socket_fd. Useful for select or poll. + */ + int socket_fd() const { return d_socket_fd; } + }; + +} + +#endif /* INCLUDED_VRT_RX_H */ diff --git a/vrt/include/vrt/rx_packet_handler.h b/vrt/include/vrt/rx_packet_handler.h new file mode 100644 index 000000000..ad3407813 --- /dev/null +++ b/vrt/include/vrt/rx_packet_handler.h @@ -0,0 +1,62 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef INCLUDED_VRT_RX_PACKET_HANDLER_H +#define INCLUDED_VRT_RX_PACKET_HANDLER_H + +#include <vrt/expanded_header.h> +#include <stddef.h> + +namespace vrt { + + /*! + * \brief Abstract function object called to handle received VRT packets. + * + * An object derived from this class is passed to vrt_rx_udp::rx_packets + * to process the received packets. + */ + class rx_packet_handler { + public: + virtual ~rx_packet_handler(); + + /*! + * \param payload points to the first 32-bit word of the payload field. + * \param n32_bit_words is the number of 32-bit words in the payload field. + * \param hdr is the expanded version of the mandatory and optional header fields (& trailer). + * + * \p payload points to the raw payload section of the packet received off + * the wire. The data is network-endian (aka big-endian) 32-bit integers. + * + * This is the general purpose, low level interface and relies on other + * functions to handle all required endian-swapping and format conversion + * of the payload. \sa FIXME. + * + * \returns true if the object wants to be called again with new data; + * false if no additional data is wanted. + */ + virtual bool operator()(const uint32_t *payload, + size_t n32_bit_words, + const expanded_header *hdr); + }; + +}; // vrt + + +#endif /* INCLUDED_VRT_RX_PACKET_HANDLER_H */ diff --git a/vrt/lib/Makefile.am b/vrt/lib/Makefile.am new file mode 100644 index 000000000..9832c0cd5 --- /dev/null +++ b/vrt/lib/Makefile.am @@ -0,0 +1,50 @@ +# +# Copyright 2007,2008,2009 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +include $(top_srcdir)/Makefile.common + +AM_CPPFLAGS = \ + $(VRT_INCLUDES) \ + $(BOOST_CPPFLAGS) \ + $(CPPUNIT_INCLUDES) + +bin_PROGRAMS = + +lib_LTLIBRARIES = \ + libvrt.la + +libvrt_la_SOURCES = \ + copiers.cc \ + data_handler.cc \ + expanded_header.cc \ + quadradio.cc \ + rx.cc \ + rx_packet_handler.cc \ + socket_rx_buffer.cc + +libvrt_la_LIBADD = + +# Private headers not needed for above the API development +noinst_HEADERS = \ + data_handler.h \ + expanded_header_cw_tables.h \ + expanded_header_switch_body.h \ + socket_rx_buffer.h + +EXTRA_DIST = \ + gen_cw_tables.py \ + gen_switch_body.py diff --git a/vrt/lib/copiers.cc b/vrt/lib/copiers.cc new file mode 100644 index 000000000..aa2846af5 --- /dev/null +++ b/vrt/lib/copiers.cc @@ -0,0 +1,69 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <vrt/copiers.h> +#include <arpa/inet.h> + +namespace vrt { + + void + copy_net_16sc_to_host_16sc(size_t nitems, + const uint32_t *items, + std::complex<int16_t> *host_items) + { +#ifdef WORDS_BIGENDIAN + + assert(sizeof(items[0]) == sizeof(host_items[0])); + memcpy(host_items, items, nitems * sizeof(items[0])); + +#else + + // FIXME SIMD welcome here + + for (size_t i = 0; i < nitems; i++){ + uint32_t t = ntohl(items[i]); + //printf("%9d\n", items[i]); + host_items[i] = std::complex<int16_t>((t >> 16), t & 0xffff); + } + +#endif + } + + void + copy_net_16sc_to_host_32fc(size_t nitems, + const uint32_t *items, + std::complex<float> *host_items) + { + // FIXME SIMD welcome here + + for (size_t i = 0; i < nitems; i++){ + uint32_t t = ntohl(items[i]); + int16_t re = (t >> 16) & 0xffff; + int16_t im = (t & 0xffff); + host_items[i] = std::complex<float>(re * 1.0/32768, im * 1.0/32768); + } + } + +}; + diff --git a/vrt/lib/data_handler.cc b/vrt/lib/data_handler.cc new file mode 100644 index 000000000..7d1f73a9a --- /dev/null +++ b/vrt/lib/data_handler.cc @@ -0,0 +1,32 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "data_handler.h" + +namespace vrt { + + data_handler::~data_handler() + { + // default nop destructor + } + +} + diff --git a/vrt/lib/data_handler.h b/vrt/lib/data_handler.h new file mode 100644 index 000000000..c041e48be --- /dev/null +++ b/vrt/lib/data_handler.h @@ -0,0 +1,53 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef INCLUDED_VRT_DATA_HANDLER_H +#define INCLUDED_VRT_DATA_HANDLER_H + +#include <stdint.h> +#include <stddef.h> + +namespace vrt { + + /*! + * \brief Abstract function object called to handle received data blocks. + */ + class data_handler + { + public: + + enum result_bits { + DONE = 0x0002, //< do not call this object again + }; + + typedef int result; //< bitmask of result_bits + + /*! + * \param base points to the beginning of the data + * \param len is the length in bytes of the data + * \returns bitmask composed of DONE + */ + virtual result operator()(const void *base, size_t len) = 0; + virtual ~data_handler(); + }; + +} // namespace vrt + +#endif /* INCLUDED_VRT_DATA_HANDLER_H */ diff --git a/vrt/lib/expanded_header.cc b/vrt/lib/expanded_header.cc new file mode 100644 index 000000000..d5c4ea888 --- /dev/null +++ b/vrt/lib/expanded_header.cc @@ -0,0 +1,119 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <vrt/expanded_header.h> +#include <arpa/inet.h> // needs autoconf'ing +//#include <stdio.h> + +namespace vrt { + + // lookup tables indexed by packet type + unsigned char expanded_header::s_if_data[16] = { + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + unsigned char expanded_header::s_ext_data[16] = { + 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + unsigned char expanded_header::s_data[16] = { + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + unsigned char expanded_header::s_context[16] = { + 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + unsigned char expanded_header::s_stream_id[16] = { + 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + + // dispatch codeword bits + static const int HAS_STREAM_ID = 1 << 0; + static const int HAS_CLASS_ID = 1 << 1; + static const int HAS_INTEGER_SECS = 1 << 2; + static const int HAS_FRACTIONAL_SECS = 1 << 3; + static const int HAS_TRAILER = 1 << 4; + +#include "expanded_header_cw_tables.h" + + static int + compute_codeword(const expanded_header &h) + { + int cw = 0; + if (h.stream_id_p()) cw |= HAS_STREAM_ID; + if (h.class_id_p()) cw |= HAS_CLASS_ID; + if (h.integer_secs_p()) cw |= HAS_INTEGER_SECS; + if (h.fractional_secs_p()) cw |= HAS_FRACTIONAL_SECS; + if (h.trailer_p()) cw |= HAS_TRAILER; + return cw; + } + + bool + expanded_header::parse(const uint32_t *packet, // in + size_t n32_bit_words_packet, // in + expanded_header *h, // out + const uint32_t **payload, // out + size_t *n32_bit_words_payload) // out + { + size_t len = n32_bit_words_packet; + const uint32_t *p = packet; + + *payload = 0; + *n32_bit_words_payload = 0; + + // printf("parse: n32_bit_words_packet = %zd\n", n32_bit_words_packet); + + if (len < 1){ // must have at least the header word + h->header = 0; + return false; + } + + h->header = ntohl(p[0]); + + if (h->pkt_size() > len) + return false; // VRT header says packet is bigger than what we've got + + len = h->pkt_size(); // valid length of packet + + int cw = compute_codeword(*h); + if (cw_header_len(cw) + cw_trailer_len(cw) > len) + return false; // negative payload len + + *payload = p + cw_header_len(cw); + *n32_bit_words_payload = len - (cw_header_len(cw) + cw_trailer_len(cw)); + + // printf("parse: hdr = 0x%08x, cw = 0x%02x, cw_header_len(cw) = %d, cw_trailer_len(cw) = %d\n", + // h->header, cw, cw_header_len(cw), cw_trailer_len(cw)); + + switch (cw & 0x1f){ +#include "expanded_header_switch_body.h" + } + + return true; + } + + +}; // vrt diff --git a/vrt/lib/expanded_header_cw_tables.h b/vrt/lib/expanded_header_cw_tables.h new file mode 100644 index 000000000..fbb9c6b81 --- /dev/null +++ b/vrt/lib/expanded_header_cw_tables.h @@ -0,0 +1,14 @@ +inline static size_t cw_header_len(int cw){ + static const size_t s_cw_header_len[32] = { + 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6, 4, 5, 6, 7, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6, 4, 5, 6, 7, + }; + return s_cw_header_len[cw]; +} + +inline static size_t cw_trailer_len(int cw){ + static const size_t s_cw_trailer_len[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + return s_cw_trailer_len[cw]; +} + diff --git a/vrt/lib/expanded_header_switch_body.h b/vrt/lib/expanded_header_switch_body.h new file mode 100644 index 000000000..40e575c2c --- /dev/null +++ b/vrt/lib/expanded_header_switch_body.h @@ -0,0 +1,256 @@ + case 0: + h->stream_id = 0; + h->class_id = 0; + h->integer_secs = 0; + h->fractional_secs = 0; + h->trailer = 0; + break; + + case 1: + h->stream_id = ntohl(p[1]); + h->class_id = 0; + h->integer_secs = 0; + h->fractional_secs = 0; + h->trailer = 0; + break; + + case 2: + h->stream_id = 0; + h->class_id = ((uint64_t)(ntohl(p[1])) << 32) | ntohl(p[2]); + h->integer_secs = 0; + h->fractional_secs = 0; + h->trailer = 0; + break; + + case 3: + h->stream_id = ntohl(p[1]); + h->class_id = ((uint64_t)(ntohl(p[2])) << 32) | ntohl(p[3]); + h->integer_secs = 0; + h->fractional_secs = 0; + h->trailer = 0; + break; + + case 4: + h->stream_id = 0; + h->class_id = 0; + h->integer_secs = ntohl(p[1]); + h->fractional_secs = 0; + h->trailer = 0; + break; + + case 5: + h->stream_id = ntohl(p[1]); + h->class_id = 0; + h->integer_secs = ntohl(p[2]); + h->fractional_secs = 0; + h->trailer = 0; + break; + + case 6: + h->stream_id = 0; + h->class_id = ((uint64_t)(ntohl(p[1])) << 32) | ntohl(p[2]); + h->integer_secs = ntohl(p[3]); + h->fractional_secs = 0; + h->trailer = 0; + break; + + case 7: + h->stream_id = ntohl(p[1]); + h->class_id = ((uint64_t)(ntohl(p[2])) << 32) | ntohl(p[3]); + h->integer_secs = ntohl(p[4]); + h->fractional_secs = 0; + h->trailer = 0; + break; + + case 8: + h->stream_id = 0; + h->class_id = 0; + h->integer_secs = 0; + h->fractional_secs = ((uint64_t)(ntohl(p[1])) << 32) | ntohl(p[2]); + h->trailer = 0; + break; + + case 9: + h->stream_id = ntohl(p[1]); + h->class_id = 0; + h->integer_secs = 0; + h->fractional_secs = ((uint64_t)(ntohl(p[2])) << 32) | ntohl(p[3]); + h->trailer = 0; + break; + + case 10: + h->stream_id = 0; + h->class_id = ((uint64_t)(ntohl(p[1])) << 32) | ntohl(p[2]); + h->integer_secs = 0; + h->fractional_secs = ((uint64_t)(ntohl(p[3])) << 32) | ntohl(p[4]); + h->trailer = 0; + break; + + case 11: + h->stream_id = ntohl(p[1]); + h->class_id = ((uint64_t)(ntohl(p[2])) << 32) | ntohl(p[3]); + h->integer_secs = 0; + h->fractional_secs = ((uint64_t)(ntohl(p[4])) << 32) | ntohl(p[5]); + h->trailer = 0; + break; + + case 12: + h->stream_id = 0; + h->class_id = 0; + h->integer_secs = ntohl(p[1]); + h->fractional_secs = ((uint64_t)(ntohl(p[2])) << 32) | ntohl(p[3]); + h->trailer = 0; + break; + + case 13: + h->stream_id = ntohl(p[1]); + h->class_id = 0; + h->integer_secs = ntohl(p[2]); + h->fractional_secs = ((uint64_t)(ntohl(p[3])) << 32) | ntohl(p[4]); + h->trailer = 0; + break; + + case 14: + h->stream_id = 0; + h->class_id = ((uint64_t)(ntohl(p[1])) << 32) | ntohl(p[2]); + h->integer_secs = ntohl(p[3]); + h->fractional_secs = ((uint64_t)(ntohl(p[4])) << 32) | ntohl(p[5]); + h->trailer = 0; + break; + + case 15: + h->stream_id = ntohl(p[1]); + h->class_id = ((uint64_t)(ntohl(p[2])) << 32) | ntohl(p[3]); + h->integer_secs = ntohl(p[4]); + h->fractional_secs = ((uint64_t)(ntohl(p[5])) << 32) | ntohl(p[6]); + h->trailer = 0; + break; + + case 16: + h->stream_id = 0; + h->class_id = 0; + h->integer_secs = 0; + h->fractional_secs = 0; + h->trailer = ntohl(p[len-1]); + break; + + case 17: + h->stream_id = ntohl(p[1]); + h->class_id = 0; + h->integer_secs = 0; + h->fractional_secs = 0; + h->trailer = ntohl(p[len-1]); + break; + + case 18: + h->stream_id = 0; + h->class_id = ((uint64_t)(ntohl(p[1])) << 32) | ntohl(p[2]); + h->integer_secs = 0; + h->fractional_secs = 0; + h->trailer = ntohl(p[len-1]); + break; + + case 19: + h->stream_id = ntohl(p[1]); + h->class_id = ((uint64_t)(ntohl(p[2])) << 32) | ntohl(p[3]); + h->integer_secs = 0; + h->fractional_secs = 0; + h->trailer = ntohl(p[len-1]); + break; + + case 20: + h->stream_id = 0; + h->class_id = 0; + h->integer_secs = ntohl(p[1]); + h->fractional_secs = 0; + h->trailer = ntohl(p[len-1]); + break; + + case 21: + h->stream_id = ntohl(p[1]); + h->class_id = 0; + h->integer_secs = ntohl(p[2]); + h->fractional_secs = 0; + h->trailer = ntohl(p[len-1]); + break; + + case 22: + h->stream_id = 0; + h->class_id = ((uint64_t)(ntohl(p[1])) << 32) | ntohl(p[2]); + h->integer_secs = ntohl(p[3]); + h->fractional_secs = 0; + h->trailer = ntohl(p[len-1]); + break; + + case 23: + h->stream_id = ntohl(p[1]); + h->class_id = ((uint64_t)(ntohl(p[2])) << 32) | ntohl(p[3]); + h->integer_secs = ntohl(p[4]); + h->fractional_secs = 0; + h->trailer = ntohl(p[len-1]); + break; + + case 24: + h->stream_id = 0; + h->class_id = 0; + h->integer_secs = 0; + h->fractional_secs = ((uint64_t)(ntohl(p[1])) << 32) | ntohl(p[2]); + h->trailer = ntohl(p[len-1]); + break; + + case 25: + h->stream_id = ntohl(p[1]); + h->class_id = 0; + h->integer_secs = 0; + h->fractional_secs = ((uint64_t)(ntohl(p[2])) << 32) | ntohl(p[3]); + h->trailer = ntohl(p[len-1]); + break; + + case 26: + h->stream_id = 0; + h->class_id = ((uint64_t)(ntohl(p[1])) << 32) | ntohl(p[2]); + h->integer_secs = 0; + h->fractional_secs = ((uint64_t)(ntohl(p[3])) << 32) | ntohl(p[4]); + h->trailer = ntohl(p[len-1]); + break; + + case 27: + h->stream_id = ntohl(p[1]); + h->class_id = ((uint64_t)(ntohl(p[2])) << 32) | ntohl(p[3]); + h->integer_secs = 0; + h->fractional_secs = ((uint64_t)(ntohl(p[4])) << 32) | ntohl(p[5]); + h->trailer = ntohl(p[len-1]); + break; + + case 28: + h->stream_id = 0; + h->class_id = 0; + h->integer_secs = ntohl(p[1]); + h->fractional_secs = ((uint64_t)(ntohl(p[2])) << 32) | ntohl(p[3]); + h->trailer = ntohl(p[len-1]); + break; + + case 29: + h->stream_id = ntohl(p[1]); + h->class_id = 0; + h->integer_secs = ntohl(p[2]); + h->fractional_secs = ((uint64_t)(ntohl(p[3])) << 32) | ntohl(p[4]); + h->trailer = ntohl(p[len-1]); + break; + + case 30: + h->stream_id = 0; + h->class_id = ((uint64_t)(ntohl(p[1])) << 32) | ntohl(p[2]); + h->integer_secs = ntohl(p[3]); + h->fractional_secs = ((uint64_t)(ntohl(p[4])) << 32) | ntohl(p[5]); + h->trailer = ntohl(p[len-1]); + break; + + case 31: + h->stream_id = ntohl(p[1]); + h->class_id = ((uint64_t)(ntohl(p[2])) << 32) | ntohl(p[3]); + h->integer_secs = ntohl(p[4]); + h->fractional_secs = ((uint64_t)(ntohl(p[5])) << 32) | ntohl(p[6]); + h->trailer = ntohl(p[len-1]); + break; + diff --git a/vrt/lib/gen_cw_tables.py b/vrt/lib/gen_cw_tables.py new file mode 100755 index 000000000..803a392e8 --- /dev/null +++ b/vrt/lib/gen_cw_tables.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +import sys + +# dispatch codeword bits +HAS_STREAM_ID = 1 << 0; +HAS_CLASS_ID = 1 << 1; +HAS_INTEGER_SECS = 1 << 2; +HAS_FRACTIONAL_SECS = 1 << 3; +HAS_TRAILER = 1 << 4; + +def main(): + f = sys.stdout + header_len = 32 * [0] + trailer_len = 32 * [0] + + for cw in range(32): + t = 0 + if cw & HAS_TRAILER: t += 1 + trailer_len[cw] = t + + t = 1 + if cw & HAS_STREAM_ID: t += 1 + if cw & HAS_CLASS_ID: t += 2 + if cw & HAS_INTEGER_SECS: t += 1 + if cw & HAS_FRACTIONAL_SECS: t += 2 + header_len[cw] = t + + write_table(f, "cw_header_len", header_len) + write_table(f, "cw_trailer_len", trailer_len) + +def write_table(f, name, table): + f.write("inline static size_t ") + f.write(name) + f.write("(int cw){\n") + + f.write(" static const size_t s_") + f.write(name) + f.write("[32] = {\n ") + for t in table: + f.write("%d, " % (t,)) + f.write("\n };\n") + + f.write(" return s_") + f.write(name) + f.write("[cw];\n}\n\n") + + +if __name__ == '__main__': + main() diff --git a/vrt/lib/gen_switch_body.py b/vrt/lib/gen_switch_body.py new file mode 100755 index 000000000..105fa76a7 --- /dev/null +++ b/vrt/lib/gen_switch_body.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +import sys + +# dispatch codeword bits +HAS_STREAM_ID = 1 << 0; +HAS_CLASS_ID = 1 << 1; +HAS_INTEGER_SECS = 1 << 2; +HAS_FRACTIONAL_SECS = 1 << 3; +HAS_TRAILER = 1 << 4; + +def do_case(f, cw): + + def do32(name, mask, index): + f.write(" ") + if cw & mask: + f.write("h->%s = ntohl(p[%d]);\n" % (name, index)) + return 1 + else: + f.write("h->%s = 0;\n" % (name,)) + return 0 + + def do64(name, mask, index): + f.write(" ") + if cw & mask: + f.write("h->%s = ((uint64_t)(ntohl(p[%d])) << 32) | ntohl(p[%d]);\n" % (name, index, index+1)) + return 2 + else: + f.write("h->%s = 0;\n" % (name,)) + return 0 + + def dotrailer(name, mask): + f.write(" ") + if cw & mask: + f.write("h->%s = ntohl(p[len-1]);\n" % (name,)) + return 1 + else: + f.write("h->%s = 0;\n" % (name,)) + return 0 + + f.write(" case %d:\n" % (cw,)) + + index = 1 + index += do32("stream_id", HAS_STREAM_ID, index) + index += do64("class_id", HAS_CLASS_ID, index) + index += do32("integer_secs", HAS_INTEGER_SECS, index) + index += do64("fractional_secs", HAS_FRACTIONAL_SECS, index) + dotrailer("trailer", HAS_TRAILER) + + f.write(" break;\n\n") + + +def main(): + f = sys.stdout + + for cw in range(32): + do_case(f, cw) + + +if __name__ == '__main__': + main() diff --git a/vrt/lib/quadradio.cc b/vrt/lib/quadradio.cc new file mode 100644 index 000000000..ab5de89b8 --- /dev/null +++ b/vrt/lib/quadradio.cc @@ -0,0 +1,408 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <vrt/quadradio.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <stdexcept> +#include <math.h> + +#define MIN_IP_LOCAL_PORT 32768 +#define MAX_IP_LOCAL_PORT 61000 + +#define ALL_DBOARDS 0xf + +static bool +send_and_check(int fd, void *buf, size_t len) +{ + int r = send(fd, buf, len, 0); + if (r < 0){ + perror("send"); + return false; + } + if ((size_t) r != len){ + fprintf(stderr, "send: short return value. expected %zd, got %d\n", len, r); + return false; + } + return true; +} + + +vrt::quadradio::quadradio(const std::string &ip, size_t rx_bufsize) + : d_ctrl_fd(0), d_data_fd(0), d_data_port(0), + d_band_select(0), d_rx_antenna(0), d_attenuation0(0), d_attenuation1(0)//d_10dB_atten(true) +{ + if (!open(ip.c_str())) + throw std::runtime_error("vrt::quadradio: failed to open " + ip + "\n"); + + d_rx = vrt::rx::make(data_socket_fd(), rx_bufsize); + set_test_signal(VRT_TEST_SIG_NORMAL); +} + +vrt::quadradio::~quadradio() +{ + ::close(d_ctrl_fd); +} + +bool +vrt::quadradio::open(const char *ip) +{ + return open_sockets(ip, control_port(), + &d_ctrl_fd, &d_ctrl_port_inaddr, + &d_data_fd, &d_data_port); +} + +bool +vrt::quadradio::start_streaming(int samples_per_pkt) +{ + return send_rx_command(d_ctrl_fd, true, d_ctrl_port_inaddr, + d_data_port, samples_per_pkt, 0); +} + +bool +vrt::quadradio::stop_streaming() +{ + return send_stop_rx_command(d_ctrl_fd); +} + +bool +vrt::quadradio::set_center_freq(double target_freq){ + if (target_freq < 700e6) return false; + if (target_freq <= 1.0e9) return set_band_select("A"); + if (target_freq <= 1.5e9) return set_band_select("B"); + if (target_freq <= 2.2e9) return set_band_select("C"); + if (target_freq <= 3.0e9) return set_band_select("D"); + return false; +} + +bool +vrt::quadradio::set_band_select(const std::string &band){ + if (band == "A") d_band_select = 3; + else if (band == "B") d_band_select = 2; + else if (band == "C") d_band_select = 1; + else if (band == "D") d_band_select = 0; + else return false; + update_dboard_pins(); + return true; +} + +//void +//vrt::quadradio::set_10dB_atten(bool on){ +// d_10dB_atten = on; +// update_dboard_pins(); +//} + +bool +vrt::quadradio::select_rx_antenna(const std::string &ant){ + if (ant == "rf") d_rx_antenna = 0; + else if (ant == "cal") d_rx_antenna = 1; + else return true; + update_dboard_pins(); + return true; +} + +bool +vrt::quadradio::set_attenuation0(int attenuation){ + if (attenuation < 0 || attenuation > 31) return false; + d_attenuation0 = attenuation; + update_dboard_pins(); + return true; +} + +bool +vrt::quadradio::set_attenuation1(int attenuation){ + if (attenuation < 0 || attenuation > 31) return false; + d_attenuation1 = attenuation; + update_dboard_pins(); + return true; +} + +//bit reversal, length in bits +static int reverse_bits(int input, int len){ + int reversed = 0; + for (int i = 0; i < len; i++){ + reversed += (input & (1<<i))?(1 << (len-i-1)):0; + } + return reversed; +} + +void +vrt::quadradio::update_dboard_pins(void){ + int db_ctrl = \ + ((reverse_bits(d_attenuation0, 5) & 0x1f) << 10) | \ + ((reverse_bits(~d_attenuation1, 5) & 0x1f) << 03) | \ + ((d_band_select & 0x03) << 01) | \ + ((d_rx_antenna & 0x01) << 00); + set_dboard_pins(ALL_DBOARDS, db_ctrl); // FIXME sets them all +} + +void +vrt::quadradio::set_adc_gain(bool on){ + set_hsadc_conf(ALL_DBOARDS, 0x14, on ? 0x90 : 0x80); +} + +void +vrt::quadradio::set_dc_offset_comp(bool on){ + if (on) { + set_hsadc_conf(ALL_DBOARDS, 0x1B, 0x80); + set_hsadc_conf(ALL_DBOARDS, 0x1A, 0x00); //bits 6:4 set time constant + } + else set_hsadc_conf(ALL_DBOARDS, 0x1B, 0x00); +} + +void +vrt::quadradio::set_digital_gain(float gain){ + int gain_q1 = static_cast<int>(round(gain*2.0)); + set_hsadc_conf(ALL_DBOARDS, 0x17, gain_q1); +} + +void +vrt::quadradio::set_test_signal(vrt_test_sig_t type){ + set_hsadc_conf(ALL_DBOARDS, 0x16, type); +} + +bool +vrt::quadradio::open_sockets(const char *quad_radio_ip, int quad_radio_ctrl_port, + int *ctrl_fd_ptr, struct in_addr *ctrl_port_inaddr, + int *data_fd_ptr, int *data_port_ptr) +{ + int ctrl_fd; // socket for control + int data_fd; // socket fd for data + int data_port; // our port number + + // + // create a udp socket and connect it to the quad radio control port + // + + ctrl_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (ctrl_fd == -1){ + perror("socket: ctrl_fd"); + return false; + } + + struct sockaddr_in si_other; + memset(&si_other, 0, sizeof(si_other)); + si_other.sin_family = AF_INET; + si_other.sin_port = htons(quad_radio_ctrl_port); + if (inet_pton(AF_INET, quad_radio_ip, &si_other.sin_addr) <= 0){ + perror("inet_pton"); + return false; + } + + if (connect(ctrl_fd, (struct sockaddr *) &si_other, sizeof(si_other)) != 0){ + perror("connect"); + return false; + } + + // get our ip address associated with the interface connected to the control port + + struct sockaddr_in si_me; + memset(&si_me, 0, sizeof(si_me)); + socklen_t sockname_len = sizeof(si_me); + if (getsockname(ctrl_fd, (struct sockaddr *) &si_me, &sockname_len) != 0){ + perror("getsockname"); + } + + *ctrl_port_inaddr = si_me.sin_addr; + + if (1){ + char buf[128]; + const char *s = inet_ntop(si_me.sin_family, &si_me.sin_addr, buf, sizeof(buf)); + if (s == 0){ + perror("inet_ntop"); + return false; + } + // printf("our ip addr associated with ctrl port: %s\n", s); + } + + // + // create a udp socket to use to receive data + // + + data_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (data_fd == -1){ + perror("socket: data_fd"); + return false; + } + + // bind it to a local port on the interface that connects to the ctrl port. + // FIXME this assumes that interface connected to the control port and the + // interface connected to the data port are the same. If we're using + // both ethernet ports on the quad radio, this may not be the case. + + data_port = -1; + for (int port = MIN_IP_LOCAL_PORT; port <= MAX_IP_LOCAL_PORT; port++){ + struct sockaddr_in si_me; + memset(&si_me, 0, sizeof(si_me)); + si_me.sin_family = AF_INET; + si_me.sin_port = htons(port); + si_me.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(data_fd, (struct sockaddr *) &si_me, sizeof(si_me)) == 0){ // found one! + data_port = port; + break; + } + } + + if (data_port == -1){ + fprintf(stderr, "failed to bind to a local port\n"); + return false; + } + + // printf("our data port = %d\n", data_port); + + *ctrl_fd_ptr = ctrl_fd; + *data_fd_ptr = data_fd; + *data_port_ptr = data_port; + + return true; +} + +// ------------------------------------------------------------------------ + +bool +vrt::quadradio::send_rx_command(int ctrl_fd, bool start, + struct in_addr addr, int data_port, + int samples_per_pkt, int siggen_param) +{ + uint32_t cmd[7]; + cmd[0] = htonl(0); // verb: set + cmd[1] = htonl(0); // id: rx_streaming + cmd[2] = htonl(start ? 1: 0); // start or stop? + cmd[3] = addr.s_addr; // ip address to send data to (already network endian) + cmd[4] = htonl(data_port); // port to send data to + cmd[5] = htonl(samples_per_pkt); + cmd[6] = htonl(siggen_param); + + return send_and_check(ctrl_fd, cmd, sizeof(cmd)); +} + +bool +vrt::quadradio::send_stop_rx_command(int ctrl_fd) +{ + struct in_addr in_addr; + in_addr.s_addr = 0; + return send_rx_command(ctrl_fd, false, in_addr, 0, 0, 0); +} + +bool +vrt::quadradio::set_dboard_pins(int dboard_bitmask, int v) +{ + uint32_t cmd[4]; + cmd[0] = htonl(0); // verb: set + cmd[1] = htonl(1); // id: dboard_pins + cmd[2] = htonl(dboard_bitmask); + cmd[3] = htonl(v); // value + + return send_and_check(d_ctrl_fd, cmd, sizeof(cmd)); +} + +bool +vrt::quadradio::set_setting_reg(int regno, int value) +{ + uint32_t cmd[4]; + cmd[0] = htonl(0); // verb: set + cmd[1] = htonl(2); // id: SR + cmd[2] = htonl(regno); + cmd[3] = htonl(value); + + return send_and_check(d_ctrl_fd, cmd, sizeof(cmd)); +} + +bool +vrt::quadradio::set_hsadc_conf(int dboard_bitmask, int regno, int value) +{ + uint32_t cmd[5]; + cmd[0] = htonl(0); // verb: set + cmd[1] = htonl(3); // id: HSADC_CONF + cmd[2] = htonl(dboard_bitmask); + cmd[3] = htonl(regno); + cmd[4] = htonl(value); + + return send_and_check(d_ctrl_fd, cmd, sizeof(cmd)); +} + +bool +vrt::quadradio::set_lsdac(int dboard_bitmask, int which_dac, int value) +{ + uint32_t cmd[5]; + cmd[0] = htonl(0); // verb: set + cmd[1] = htonl(4); // id: LSDAC + cmd[2] = htonl(dboard_bitmask); + cmd[3] = htonl(which_dac); + cmd[4] = htonl(value); + + return send_and_check(d_ctrl_fd, cmd, sizeof(cmd)); +} + +bool +vrt::quadradio::set_mem32(int addr, int value) +{ + uint32_t cmd[4]; + cmd[0] = htonl(0); // verb: set + cmd[1] = htonl(5); // id: MEM32 + cmd[2] = htonl(addr); + cmd[3] = htonl(value); + + return send_and_check(d_ctrl_fd, cmd, sizeof(cmd)); +} + +bool +vrt::quadradio::set_lo_freq(double freq) +{ + uint64_t lo_freq = uint64_t(freq * (uint64_t(1)<<20)); //q20 format + uint32_t cmd[4]; + cmd[0] = htonl(0); // verb: set + cmd[1] = htonl(6); // id: lo freq + cmd[2] = htonl((lo_freq >> 32) & 0xffffffff); + cmd[3] = htonl((lo_freq >> 0) & 0xffffffff); + + return send_and_check(d_ctrl_fd, cmd, sizeof(cmd)); +} + +bool +vrt::quadradio::set_cal_freq(double freq) +{ + uint64_t cal_freq = uint64_t(freq * (uint64_t(1)<<20)); //q20 format + uint32_t cmd[4]; + cmd[0] = htonl(0); // verb: set + cmd[1] = htonl(7); // id: cal freq + cmd[2] = htonl((cal_freq >> 32) & 0xffffffff); + cmd[3] = htonl((cal_freq >> 0) & 0xffffffff); + + return send_and_check(d_ctrl_fd, cmd, sizeof(cmd)); +} + +bool +vrt::quadradio::set_beamforming(int32_t gains[8]){ + uint32_t cmd[2+8]; + cmd[0] = htonl(0); // verb: set + cmd[1] = htonl(8); // id: beamformin + for (int i = 0; i < 8; i++){ + //printf("%d\n", gains[i]); + cmd[i+2] = htonl(gains[i]); + } + return send_and_check(d_ctrl_fd, cmd, sizeof(cmd)); +} + diff --git a/vrt/lib/rx.cc b/vrt/lib/rx.cc new file mode 100644 index 000000000..f75db3111 --- /dev/null +++ b/vrt/lib/rx.cc @@ -0,0 +1,120 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <vrt/rx.h> +#include <vrt/expanded_header.h> +#include "socket_rx_buffer.h" +#include "data_handler.h" +#include <unistd.h> +#include <stdio.h> +#include <stdexcept> + +static void +print_words(FILE *fp, size_t offset, uint32_t *buf, size_t n) +{ + size_t i; + for (i = 0; i < n; i++){ + if (i % 4 == 0){ + fprintf(fp, "%04zx:", i); + } + + putc(' ', fp); + fprintf(fp, "%08x", buf[i]); + if (i % 4 == 3) + putc('\n', fp); + } + + putc('\n', fp); +} + + + +namespace vrt { + + rx::sptr + rx::make(int socket_fd, size_t rx_bufsize) + { + return sptr(new rx(socket_fd, rx_bufsize)); + } + + rx::rx(int socket_fd, size_t rx_bufsize) + : d_socket_fd(socket_fd), + d_srb(new socket_rx_buffer(socket_fd, rx_bufsize)) + { + } + + rx::~rx() + { + delete d_srb; + ::close(d_socket_fd); + } + + + class vrt_data_handler : public data_handler + { + rx_packet_handler *d_handler; + + public: + vrt_data_handler(rx_packet_handler *handler) + : d_handler(handler){} + + ~vrt_data_handler(); + + result operator()(const void *base, size_t len); + }; + + vrt_data_handler::~vrt_data_handler(){} + + data_handler::result + vrt_data_handler::operator()(const void *base, size_t len) + { +#if 0 + print_words(0, (uint32_t *)base, len/(sizeof(uint32_t))); + return 0; +#else + const uint32_t *payload; + size_t n32_bit_words; + expanded_header hdr; + if (!expanded_header::parse((const uint32_t*) base, len/(sizeof(uint32_t)), + &hdr, &payload, &n32_bit_words)){ + if (1){ + fprintf(stderr, "vrt_data_handler: malformed VRT packet!\n"); + print_words(stderr, 0, (uint32_t *)base, len/(sizeof(uint32_t))); + } + return 0; + } + bool want_more = (*d_handler)(payload, n32_bit_words, &hdr); + return !want_more ? data_handler::DONE : 0; +#endif + } + + + bool + rx::rx_packets(rx_packet_handler *handler, bool dont_wait) + { + vrt_data_handler h(handler); + socket_rx_buffer::result r = d_srb->rx_frames(&h, dont_wait ? 0 : -1); + return r == socket_rx_buffer::EB_OK || r == socket_rx_buffer::EB_WOULD_BLOCK; + } + +}; // vrt diff --git a/vrt/lib/rx_packet_handler.cc b/vrt/lib/rx_packet_handler.cc new file mode 100644 index 000000000..11f90278d --- /dev/null +++ b/vrt/lib/rx_packet_handler.cc @@ -0,0 +1,41 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <vrt/rx_packet_handler.h> + +namespace vrt { + + rx_packet_handler::~rx_packet_handler(){} + + // default operator is a NOP + bool + rx_packet_handler::operator()(const uint32_t *payload, + size_t n32_bit_words, + const expanded_header *hdr) + { + return true; + } + + +}; // vrt diff --git a/vrt/lib/socket_rx_buffer.cc b/vrt/lib/socket_rx_buffer.cc new file mode 100644 index 000000000..6ed211b9a --- /dev/null +++ b/vrt/lib/socket_rx_buffer.cc @@ -0,0 +1,278 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "socket_rx_buffer.h" +#include "data_handler.h" +#include <linux/if_packet.h> +#include <sys/socket.h> +#include <sys/mman.h> +#include <sys/poll.h> +#include <iostream> +#include <cmath> +#include <errno.h> +#include <stdexcept> +#include <string.h> +#include <fcntl.h> +#include <cstdio> + + +#define SOCKET_RX_BUFFER_DEBUG 1 // define to 0 or 1 +#if SOCKET_RX_BUFFER_DEBUG +#define DEBUG_LOG(x) ::write(2, (x), 1) +#else +#define DEBUG_LOG(X) +#endif + +#define DEFAULT_MEM_SIZE 62.5e6 // ~0.5s @ 125 MB/s +#define MAX_MEM_SIZE 1000e6 // ~10.00s @ 100 MB/s. +#define MAX_SLAB_SIZE 131072 // 128 KB (FIXME fish out of /proc/slabinfo) + + +namespace vrt { + + const unsigned int socket_rx_buffer::MAX_PKTLEN = 8192; + const unsigned int socket_rx_buffer::MIN_PKTLEN = 64; + + socket_rx_buffer::socket_rx_buffer(int socket_fd, size_t rx_bufsize) + : d_fd(socket_fd), d_using_tpring(false), d_buflen(0), d_buf(0), d_frame_nr(0), + d_frame_size(0), d_head(0), d_ring(0) + { + if (rx_bufsize == 0) + d_buflen = (size_t)DEFAULT_MEM_SIZE; + else + d_buflen = std::min((size_t)MAX_MEM_SIZE, rx_bufsize); + + if (!open()){ + throw std::runtime_error("socket_rx_buffer::open failed"); + } + } + + socket_rx_buffer::~socket_rx_buffer() + { + close(); + } + + bool + socket_rx_buffer::open() + { + if (try_packet_ring()){ + d_using_tpring = true; + // fprintf(stderr, "socket_rx_buffer: using memory mapped interface\n"); + } + else { + d_using_tpring = false; + // fprintf(stderr, "socket_rx_buffer: NOT using memory mapped interface\n"); + + // Increase socket buffer if possible + + int rcvbuf_size = d_buflen; +#if defined(SO_RCVBUFFORCE) + if (setsockopt(d_fd, SOL_SOCKET, SO_RCVBUFFORCE, &rcvbuf_size, sizeof(rcvbuf_size)) != 0){ + perror("setsockopt(SO_RCVBUFFORCE)"); + fprintf(stderr, "Are you running as root? If not, please do.\n"); + } + else { + fprintf(stderr, "SO_RCVBUFFORCE = %zd\n", d_buflen); + } +#endif + } + + return true; + } + + bool + socket_rx_buffer::try_packet_ring() + { + struct tpacket_req req; + size_t page_size = getpagesize(); + + // Calculate minimum power-of-two aligned size for frames + req.tp_frame_size = + (unsigned int)rint(pow(2, ceil(log2(TPACKET_ALIGN(TPACKET_HDRLEN)+TPACKET_ALIGN(MAX_PKTLEN))))); + d_frame_size = req.tp_frame_size; + + // Calculate minimum contiguous pages needed to enclose a frame + int npages = (page_size > req.tp_frame_size) ? 1 : ((req.tp_frame_size+page_size-1)/page_size); + req.tp_block_size = page_size << (int)ceil(log2(npages)); + + // Calculate number of blocks + req.tp_block_nr = (int)(d_buflen/req.tp_block_size); + + + // Recalculate buffer length + d_buflen = req.tp_block_nr*req.tp_block_size; + + // Finally, calculate total number of frames. Since frames, blocks, + // and pages are all power-of-two aligned, frames are contiguous + req.tp_frame_nr = d_buflen/req.tp_frame_size; + d_frame_nr = req.tp_frame_nr; + +#if 0 + if (SOCKET_RX_BUFFER_DEBUG) + std::cerr << "socket_rx_buffer:" + << " frame_size=" << req.tp_frame_size + << " block_size=" << req.tp_block_size + << " block_nr=" << req.tp_block_nr + << " frame_nr=" << req.tp_frame_nr + << " buflen=" << d_buflen + << std::endl; +#endif + + // Try to get kernel shared memory buffer + if (setsockopt(d_fd, SOL_PACKET, PACKET_RX_RING, (void *)&req, sizeof(req)) != 0){ + // perror("socket_rx_buffer: setsockopt"); + return false; + } + + void *p = mmap(0, d_buflen, PROT_READ|PROT_WRITE, MAP_SHARED, d_fd, 0); + if (p == MAP_FAILED){ + perror("socket_rx_buffer: mmap"); + return false; + } + d_buf = (uint8_t *) p; + + // Initialize our pointers into the packet ring + d_ring.resize(req.tp_frame_nr); + for (unsigned int i=0; i < req.tp_frame_nr; i++) + d_ring[i] = (uint8_t *)(d_buf+i*req.tp_frame_size); + + return true; + } + + bool + socket_rx_buffer::close() + { + return true; + } + + inline bool + socket_rx_buffer::frame_available() + { + return (((tpacket_hdr *)d_ring[d_head])->tp_status != TP_STATUS_KERNEL); + } + + socket_rx_buffer::result + socket_rx_buffer::rx_frames(data_handler *f, int timeout_in_ms) + { + if (!d_using_tpring){ + + // ---------------------------------------------------------------- + // Use recv instead of kernel Rx packet ring + // ---------------------------------------------------------------- + + unsigned char buf[MAX_PKTLEN]; + bool dont_wait = timeout_in_ms == 0; // FIXME treating timeout as 0 or inf + int flags = dont_wait ? MSG_DONTWAIT : 0; + + ssize_t rr = recv(d_fd, buf, sizeof(buf), flags); + if (rr == -1){ // error? + if (errno == EAGAIN){ // non-blocking, nothing there + return EB_WOULD_BLOCK; + } + perror("rx_frames: recv"); + return EB_ERROR; + } + + // Got first packet. Call handler + + data_handler::result r = (*f)(buf, rr); + if (r & data_handler::DONE) + return EB_OK; + + // Now do as many as we can without blocking + + while (1){ + rr = recv(d_fd, buf, sizeof(buf), MSG_DONTWAIT); + if (rr == -1){ // error? + if (errno == EAGAIN) // non-blocking, nothing there + return EB_OK; // return OK; we've processed >= 1 packets + perror("rx_frames: recv"); + return EB_ERROR; + } + + r = (*f)(buf, rr); + if (r & data_handler::DONE) + break; + } + return EB_OK; + } + + // ---------------------------------------------------------------- + // Use kernel Rx packet ring + // ---------------------------------------------------------------- + + DEBUG_LOG("\n"); + + while (!frame_available()) { + if (timeout_in_ms == 0) { + DEBUG_LOG("w"); + return EB_WOULD_BLOCK; + } + + struct pollfd pfd; + pfd.fd = d_fd; + pfd.revents = 0; + pfd.events = POLLIN; + + // DEBUG_LOG("P"); + + int pres = poll(&pfd, 1, timeout_in_ms); + if (pres == -1) { + perror("poll"); + return EB_ERROR; + } + + if (pres == 0) { + DEBUG_LOG("t"); + return EB_TIMED_OUT; + } + } + + // Iterate through available packets + while (frame_available()) { + // Get start of ethernet frame and length + tpacket_hdr *hdr = (tpacket_hdr *)d_ring[d_head]; + void *base = (uint8_t *)hdr+hdr->tp_mac; + size_t len = hdr->tp_len; + + if (1) + fprintf(stderr, "socket_rx_buffer: base = %p tp_mac = %3d tp_net = %3d\n", + base, hdr->tp_mac, hdr->tp_net); + + // Invoke data handler + data_handler::result r = (*f)(base, len); + hdr->tp_status = TP_STATUS_KERNEL; // mark it free + + inc_head(); + + if (r & data_handler::DONE) + break; + } + + DEBUG_LOG("|"); + return EB_OK; + } + +} // namespace vrt diff --git a/vrt/lib/socket_rx_buffer.h b/vrt/lib/socket_rx_buffer.h new file mode 100644 index 000000000..053c30c12 --- /dev/null +++ b/vrt/lib/socket_rx_buffer.h @@ -0,0 +1,122 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef INCLUDED_VRT_SOCKET_RX_BUFFER_H +#define INCLUDED_VRT_SOCKET_RX_BUFFER_H + +#include <boost/utility.hpp> +#include <vector> +#include <memory> +#include <stdint.h> + +namespace vrt { + + class data_handler; + + /*! + * \brief high-performance interface to receive datagrams + * + * On many systems it should be possible to implement this on top of libpcap + * + * \internal + */ + class socket_rx_buffer : boost::noncopyable + { + + int d_fd; // socket file descriptor + bool d_using_tpring; // using kernel mapped packet ring + size_t d_buflen; // length of our buffer + uint8_t *d_buf; // packet ring + unsigned int d_frame_nr; // max frames on ring + size_t d_frame_size; // frame storage size + unsigned int d_head; // pointer to next frame + + std::vector<uint8_t *> d_ring; // pointers into buffer + + bool frame_available(); + + void inc_head() + { + if (d_head + 1 >= d_frame_nr) + d_head = 0; + else + d_head = d_head + 1; + } + + bool open(); + bool close(); + bool try_packet_ring(); + + public: + + enum result { + EB_OK, //< everything's fine + EB_ERROR, //< A non-recoverable error occurred + EB_WOULD_BLOCK, //< A timeout of 0 was specified and nothing was ready + EB_TIMED_OUT, //< The timeout expired before anything was ready + }; + + static const unsigned int MAX_PKTLEN; + static const unsigned int MIN_PKTLEN; + + /*! + * \param socket_fd file descriptor that corresponds to a socket + * \param rx_bufsize is a hint as to the number of bytes of memory + * to allocate for received ethernet frames (0 -> reasonable default) + */ + socket_rx_buffer(int socket_fd, size_t rx_bufsize = 0); + ~socket_rx_buffer(); + + /*! + * \brief Call \p f for each frame in the receive buffer. + * \param f is the frame data handler + * \param timeout (in ms) controls behavior when there are no frames to read + * + * If \p timeout is 0, rx_frames will not wait for frames if none are + * available, and f will not be invoked. If \p timeout is -1 (the + * default), rx_frames will block indefinitely until frames are + * available. If \p timeout is positive, it indicates the number of + * milliseconds to wait for a frame to become available. Once the + * timeout has expired, rx_frames will return, f never having been + * invoked. + * + * \p f will be called on each frame that is available. + * \p f returns a bit mask with one of the following set or cleared: + * + * data_handler::DONE - return from rx_frames now even though more frames + * might be available; otherwise continue if more + * frames are ready. + * + * \returns EB_OK if at least one frame was received + * \returns EB_WOULD_BLOCK if \p timeout is 0 and the call would have blocked + * \returns EB_TIMED_OUT if timeout occurred + * \returns EB_ERROR if there was an unrecoverable error. + */ + result rx_frames(data_handler *f, int timeout=-1); + + /* + * \brief Returns maximum possible number of frames in buffer + */ + unsigned int max_frames() const { return d_using_tpring ? d_frame_nr : 0; } + }; + +}; // namespace vrt + +#endif /* INCLUDED_VRT_SOCKET_RX_BUFFER_H */ diff --git a/vrt/vrt.pc.in b/vrt/vrt.pc.in new file mode 100644 index 000000000..0f8cb938b --- /dev/null +++ b/vrt/vrt.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: vrt +Description: Host implementation of Virtual Radio Transport (VITA-49) +Requires: +Version: @VERSION@ +Libs: -L${libdir} -lvrt +Cflags: -I${includedir} |