diff options
author | jcorgan | 2009-07-09 02:55:51 +0000 |
---|---|---|
committer | jcorgan | 2009-07-09 02:55:51 +0000 |
commit | c276a4ffee9314d2528166547abfd2c09d29713f (patch) | |
tree | 03b06ac67874342ba671a4a0405e006de1ece9ba /usrp/limbo/apps-inband | |
parent | eefb51c0c0fac68d16544e492aebd883528607e1 (diff) | |
download | gnuradio-c276a4ffee9314d2528166547abfd2c09d29713f.tar.gz gnuradio-c276a4ffee9314d2528166547abfd2c09d29713f.tar.bz2 gnuradio-c276a4ffee9314d2528166547abfd2c09d29713f.zip |
Merged r11377:11390 from jcorgan/usrp-headers in to trunk.
* Public USRP(1) header files are now in their own source directory
and install into $(includedir)/usrp. This was done to avoid name
clashes in the top-level include directory.
Only users who are developing directly to libusrp in C++ are
affected; the GNU Radio C++ and Python APIs are unchanged.
The simple change required by this update is to change:
#include <usrp_*.h>
to #include
<usrp/usrp_*.h>
...in your source code.
* Removed usrp-inband code from tree (put into limbo directory.)
This code has become unmaintained and has started to suffer
from bitrot. A checkpoint tag has been made for anyone still
needing to use it:
http://gnuradio.org/svn/gnuradio/tags/checkpoints/trunk-20090708-pre-usrp-reorg
The plan during the 3.2->3.3 development cycle is to replace the
functions done by the in-band code with extensions to the existing
gr-usrp blocks using the new message passing architecture.
The USRP hardware FPGA code that provided the inband interface
has not been removed; however, it too has become unmaintained and
will likely be rewritten/replaced during the 3.3 timeframe.
The trunk passes distcheck.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@11394 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'usrp/limbo/apps-inband')
-rw-r--r-- | usrp/limbo/apps-inband/Makefile.am | 77 | ||||
-rw-r--r-- | usrp/limbo/apps-inband/read_packets.cc | 109 | ||||
-rw-r--r-- | usrp/limbo/apps-inband/test_usrp_inband_2rx.cc | 371 | ||||
-rw-r--r-- | usrp/limbo/apps-inband/test_usrp_inband_2tx.cc | 430 | ||||
-rw-r--r-- | usrp/limbo/apps-inband/test_usrp_inband_overrun.cc | 375 | ||||
-rw-r--r-- | usrp/limbo/apps-inband/test_usrp_inband_ping.cc | 374 | ||||
-rw-r--r-- | usrp/limbo/apps-inband/test_usrp_inband_registers.cc | 435 | ||||
-rw-r--r-- | usrp/limbo/apps-inband/test_usrp_inband_rx.cc | 362 | ||||
-rw-r--r-- | usrp/limbo/apps-inband/test_usrp_inband_timestamps.cc | 506 | ||||
-rw-r--r-- | usrp/limbo/apps-inband/test_usrp_inband_tx.cc | 411 | ||||
-rw-r--r-- | usrp/limbo/apps-inband/test_usrp_inband_underrun.cc | 674 | ||||
-rw-r--r-- | usrp/limbo/apps-inband/ui_nco.h | 202 | ||||
-rw-r--r-- | usrp/limbo/apps-inband/ui_sincos.c | 81 | ||||
-rw-r--r-- | usrp/limbo/apps-inband/ui_sincos.h | 39 |
14 files changed, 4446 insertions, 0 deletions
diff --git a/usrp/limbo/apps-inband/Makefile.am b/usrp/limbo/apps-inband/Makefile.am new file mode 100644 index 000000000..0a44d8112 --- /dev/null +++ b/usrp/limbo/apps-inband/Makefile.am @@ -0,0 +1,77 @@ +# +# Copyright 2003,2006,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. +# + +include $(top_srcdir)/Makefile.common + +AM_CPPFLAGS = \ + $(DEFINES) $(OMNITHREAD_INCLUDES) $(PMT_INCLUDES) $(MBLOCK_INCLUDES) \ + $(USRP_INCLUDES) $(USRP_INBAND_INCLUDES) $(BOOST_CPPFLAGS) \ + $(CPPUNIT_INCLUDES) $(WITH_INCLUDES) -I$(top_srcdir)/mblock/src/lib + + +bin_PROGRAMS = + +noinst_PROGRAMS = \ + test_usrp_inband_ping \ + test_usrp_inband_registers \ + test_usrp_inband_rx \ + test_usrp_inband_2rx \ + test_usrp_inband_tx \ + test_usrp_inband_2tx \ + test_usrp_inband_timestamps \ + test_usrp_inband_overrun \ + test_usrp_inband_underrun \ + read_packets + +noinst_HEADERS = \ + ui_nco.h \ + ui_sincos.h + + +test_usrp_inband_ping_SOURCES = test_usrp_inband_ping.cc +test_usrp_inband_ping_LDADD = $(USRP_LA) $(USRP_INBAND_LA) + +test_usrp_inband_tx_SOURCES = test_usrp_inband_tx.cc ui_sincos.c +test_usrp_inband_tx_LDADD = $(USRP_LA) $(USRP_INBAND_LA) + +test_usrp_inband_2tx_SOURCES = test_usrp_inband_2tx.cc ui_sincos.c +test_usrp_inband_2tx_LDADD = $(USRP_LA) $(USRP_INBAND_LA) + +test_usrp_inband_timestamps_SOURCES = test_usrp_inband_timestamps.cc ui_sincos.c +test_usrp_inband_timestamps_LDADD = $(USRP_LA) $(USRP_INBAND_LA) + +test_usrp_inband_registers_SOURCES = test_usrp_inband_registers.cc ui_sincos.c +test_usrp_inband_registers_LDADD = $(USRP_LA) $(USRP_INBAND_LA) + +test_usrp_inband_overrun_SOURCES = test_usrp_inband_overrun.cc +test_usrp_inband_overrun_LDADD = $(USRP_LA) $(USRP_INBAND_LA) + +test_usrp_inband_underrun_SOURCES = test_usrp_inband_underrun.cc +test_usrp_inband_underrun_LDADD = $(USRP_LA) $(USRP_INBAND_LA) + +test_usrp_inband_rx_SOURCES = test_usrp_inband_rx.cc ui_sincos.c +test_usrp_inband_rx_LDADD = $(USRP_LA) $(USRP_INBAND_LA) + +test_usrp_inband_2rx_SOURCES = test_usrp_inband_2rx.cc ui_sincos.c +test_usrp_inband_2rx_LDADD = $(USRP_LA) $(USRP_INBAND_LA) + +read_packets_SOURCES = read_packets.cc +read_packets_LDADD = $(USRP_LA) $(USRP_INBAND_LA) diff --git a/usrp/limbo/apps-inband/read_packets.cc b/usrp/limbo/apps-inband/read_packets.cc new file mode 100644 index 000000000..24a1e88b5 --- /dev/null +++ b/usrp/limbo/apps-inband/read_packets.cc @@ -0,0 +1,109 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,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 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 <iostream> +#include <usrp_inband_usb_packet.h> +#include <mblock/class_registry.h> +#include <vector> +#include <usrp_usb_interface.h> +#include <fstream> + +typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy + +int main(int argc, char *argv[]) { + + if(argc !=2) { + std::cout << "Usage: ./read_packets <data_file>\n"; + return -1; + } + + std::ifstream infile; + std::ofstream outfile; + + unsigned int pkt_size = transport_pkt::max_pkt_size(); + unsigned int pkt_num=0; + + transport_pkt *pkt; + char pkt_data[pkt_size]; // allocate the number of bytes for a single packet + + pkt = (transport_pkt *)pkt_data; // makes operations cleaner to read + + // Open the file and read the packets, dumping information + infile.open(argv[1], std::ios::binary|std::ios::in); + if(!infile.is_open()) + exit(-1); + + //outfile.open("dump.dat",std::ios::out|std::ios::binary); + + // read 1 packet in to the memory + infile.read(pkt_data, pkt_size); + + while(!infile.eof()) { + + printf("Packet %u\n", pkt_num); + + if(pkt->start_of_burst()) + printf("\tstart of burst\n"); + + if(pkt->end_of_burst()) + printf("\tend of burst\n"); + +// if(pkt->carrier_sense()) +// printf("\tcarrier sense\n"); + + if(pkt->underrun()) + printf("\tunderrun\n"); + + if(pkt->overrun()) + printf("\toverrun\n"); + + printf("\tchannel: \t0x%x\n", pkt->chan()); + printf("\ttimestamp: \t0x%x\n", pkt->timestamp()); + //printf("\ttimestamp: \t%u\n", pkt->timestamp()); + printf("\tlength: \t%u\n", pkt->payload_len()); + printf("\trssi: \t%u\n", pkt->rssi()); + + printf("\tpayload: \n"); + for(int i=0; i < pkt->payload_len(); i++) + //for(int i=0; i < pkt->max_payload(); i++) + { + printf("\t%d\t0x%x\n", i, *(pkt->payload()+i)); + //outfile.write((const char*)(pkt->payload()+i),1); + //printf("\t\t0x%x\n", pkt->payload()+i); + + } + printf("\n\n"); + + pkt_num++; + + // read 1 packet in to the memory + infile.read(pkt_data, pkt_size); + + } + + infile.close(); + //outfile.close(); + +} diff --git a/usrp/limbo/apps-inband/test_usrp_inband_2rx.cc b/usrp/limbo/apps-inband/test_usrp_inband_2rx.cc new file mode 100644 index 000000000..c210f196a --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_2rx.cc @@ -0,0 +1,371 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,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 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 <mblock/mblock.h> +#include <mblock/runtime.h> +#include <mb_runtime_nop.h> // QA only +#include <mblock/protocol_class.h> +#include <mblock/exception.h> +#include <mblock/msg_queue.h> +#include <mblock/message.h> +#include <mb_mblock_impl.h> +#include <mblock/msg_accepter.h> +#include <mblock/class_registry.h> +#include <pmt.h> +#include <stdio.h> +#include <string.h> +#include <iostream> +#include <fstream> + +// Include the symbols needed for communication with USRP server +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_rx.h> + +static bool verbose = true; + +class test_usrp_rx : public mb_mblock +{ + mb_port_sptr d_rx; + mb_port_sptr d_cs; + pmt_t d_rx_chan0, d_rx_chan1; + + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNEL, + RECEIVING, + CLOSING_CHANNEL, + CLOSING_USRP, + }; + + state_t d_state; + + std::ofstream d_ofile; + + long d_samples_recvd; + long d_samples_to_recv; + + public: + test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_rx(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void open_usrp(); + void close_usrp(); + void allocate_channel(); + void send_packets(); + void enter_receiving(); + void build_and_send_next_frame(); + void handle_response_recv_raw_samples(pmt_t invocation_handle); + void enter_closing_channel(); +}; + +test_usrp_rx::test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_rx_chan0(PMT_NIL), d_rx_chan1(PMT_NIL), + d_samples_recvd(0), + d_samples_to_recv(20e6) +{ + d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP + pmt_t usrp_dict = pmt_make_dict(); + + // To test the application without a USRP + bool fake_usrp_p = false; + if(fake_usrp_p) { + pmt_dict_set(usrp_dict, + pmt_intern("fake-usrp"), + PMT_T); + } + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("inband_2rxhb_2tx.rbf")); + + pmt_dict_set(usrp_dict, + pmt_intern("decim-rx"), + pmt_from_long(64)); + + define_component("server", "usrp_server", usrp_dict); + + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + +} + +test_usrp_rx::~test_usrp_rx() +{ +} + +void +test_usrp_rx::initial_transition() +{ + open_usrp(); +} + +void +test_usrp_rx::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + std::string error_msg; + + switch(d_state){ + + //----------------------------- OPENING_USRP ----------------------------// + // We only expect a response from opening the USRP which should be succesful + // or failed. + case OPENING_USRP: + if (pmt_eq(event, s_response_open)){ + status = pmt_nth(1, data); + if (pmt_eq(status, PMT_T)){ + allocate_channel(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + } + goto unhandled; + + //----------------------- ALLOCATING CHANNELS --------------------// + // Allocate an RX channel to perform the overrun test. + case ALLOCATING_CHANNEL: + if (pmt_eq(event, s_response_allocate_channel)){ + status = pmt_nth(1, data); + if(pmt_eqv(d_rx_chan0, PMT_NIL)) + d_rx_chan0 = pmt_nth(2, data); + else + d_rx_chan1 = pmt_nth(2, data); + + if (pmt_eq(status, PMT_T) && !pmt_eqv(d_rx_chan1, PMT_NIL)){ + enter_receiving(); + return; + } + else if(pmt_eq(status, PMT_F)){ + error_msg = "failed to allocate channel:"; + goto bail; + } + return; + } + goto unhandled; + + //--------------------------- RECEIVING ------------------------------// + // In the receiving state, we receive samples until the specified amount + // while counting the number of overruns. + case RECEIVING: + if (pmt_eq(event, s_response_recv_raw_samples)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + handle_response_recv_raw_samples(data); + return; + } + else { + error_msg = "bad response-xmit-raw-frame:"; + goto bail; + } + } + goto unhandled; + + //------------------------- CLOSING CHANNEL ----------------------------// + // Check deallocation response for the RX channel + case CLOSING_CHANNEL: + if (pmt_eq(event, s_response_deallocate_channel)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + close_usrp(); + return; + } + else { + error_msg = "failed to deallocate channel:"; + goto bail; + } + } + + // Alternately, we ignore all response recv samples while waiting for the + // channel to actually close + if (pmt_eq(event, s_response_recv_raw_samples)) + return; + + goto unhandled; + + //--------------------------- CLOSING USRP ------------------------------// + // Once we have received a successful USRP close response, we shutdown all + // mblocks and exit. + case CLOSING_USRP: + if (pmt_eq(event, s_response_close)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + fflush(stdout); + shutdown_all(PMT_T); + return; + } + else { + error_msg = "failed to close USRP:"; + goto bail; + } + } + goto unhandled; + + default: + goto unhandled; + } + return; + + // An error occured, print it, and shutdown all m-blocks + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + // Received an unhandled message for a specific state + unhandled: + if(verbose && !pmt_eq(event, pmt_intern("%shutdown"))) + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; +} + + +void +test_usrp_rx::open_usrp() +{ + pmt_t which_usrp = pmt_from_long(0); + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp)); + d_state = OPENING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_RX] Opening the USRP\n"; +} + +void +test_usrp_rx::close_usrp() +{ + + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); + d_state = CLOSING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_RX] Closing the USRP\n"; +} + +void +test_usrp_rx::allocate_channel() +{ + long capacity = (long) 16e6; + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_state = ALLOCATING_CHANNEL; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_RX] Requesting RX channel allocation\n"; +} + +void +test_usrp_rx::enter_receiving() +{ + d_state = RECEIVING; + + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_F, + d_rx_chan0)); + + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_F, + d_rx_chan1)); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_RX] Receiving...\n"; +} + +void +test_usrp_rx::handle_response_recv_raw_samples(pmt_t data) +{ + pmt_t invocation_handle = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); + pmt_t v_samples = pmt_nth(2, data); + pmt_t timestamp = pmt_nth(3, data); + pmt_t channel = pmt_nth(4, data); + pmt_t properties = pmt_nth(5, data); + + d_samples_recvd += pmt_length(v_samples) / 4; + + // Check for overrun + if(!pmt_is_dict(properties)) { + std::cout << "[TEST_USRP_INBAND_RX] Recv samples dictionary is improper\n"; + return; + } + + // Check if the number samples we have received meets the test + if(d_samples_recvd >= d_samples_to_recv) { + d_rx->send(s_cmd_stop_recv_raw_samples, pmt_list2(PMT_NIL, d_rx_chan0)); + d_rx->send(s_cmd_stop_recv_raw_samples, pmt_list2(PMT_NIL, d_rx_chan1)); + enter_closing_channel(); + return; + } + +} + +void +test_usrp_rx::enter_closing_channel() +{ + d_state = CLOSING_CHANNEL; + + d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan0)); + d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan1)); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_RX] Deallocating RX channel\n"; +} + +REGISTER_MBLOCK_CLASS(test_usrp_rx); + + +// ---------------------------------------------------------------- + +int +main (int argc, char **argv) +{ + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_rx", PMT_F, &result); + +} diff --git a/usrp/limbo/apps-inband/test_usrp_inband_2tx.cc b/usrp/limbo/apps-inband/test_usrp_inband_2tx.cc new file mode 100644 index 000000000..11a1a491c --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_2tx.cc @@ -0,0 +1,430 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,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 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 <mblock/mblock.h> +#include <mblock/runtime.h> +#include <mb_runtime_nop.h> // QA only +#include <mblock/protocol_class.h> +#include <mblock/exception.h> +#include <mblock/msg_queue.h> +#include <mblock/message.h> +#include <mb_mblock_impl.h> +#include <mblock/msg_accepter.h> +#include <mblock/class_registry.h> +#include <pmt.h> +#include <stdio.h> +#include <string.h> +#include <iostream> + +#include <ui_nco.h> +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_tx.h> + +static bool verbose = true; + +class test_usrp_tx : public mb_mblock +{ + mb_port_sptr d_tx; + mb_port_sptr d_cs; + pmt_t d_tx_chan0, d_tx_chan1; + + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNEL, + TRANSMITTING, + CLOSING_CHANNEL, + CLOSING_USRP, + }; + + state_t d_state; + long d_nsamples_to_send; + long d_nsamples_xmitted; + long d_nframes_xmitted; + long d_samples_per_frame; + bool d_done_sending; + + // for generating sine wave output + ui_nco<float,float> d_nco; + double d_amplitude; + + public: + test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_tx(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void open_usrp(); + void close_usrp(); + void allocate_channel(); + void send_packets(); + void enter_transmitting(); + void build_and_send_next_frame(); + void handle_xmit_response(pmt_t invocation_handle); + void enter_closing_channel(); +}; + +test_usrp_tx::test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_tx_chan0(PMT_NIL), d_tx_chan1(PMT_NIL), + d_state(INIT), d_nsamples_to_send((long) 80e6), + d_nsamples_xmitted(0), + d_nframes_xmitted(0), + d_samples_per_frame((long)(126 * 4)), // full packet + d_done_sending(false), + d_amplitude(16384) +{ + // std::cout << "[TEST_USRP_TX] Initializing...\n"; + + d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + //bool fake_usrp_p = true; + bool fake_usrp_p = false; + + // Test the TX side + + pmt_t usrp_dict = pmt_make_dict(); + + if(fake_usrp_p) { + pmt_dict_set(usrp_dict, + pmt_intern("fake-usrp"), + PMT_T); + } + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("inband_2rxhb_2tx.rbf")); + + // Set TX and RX interpolations + pmt_dict_set(usrp_dict, + pmt_intern("interp-tx"), + pmt_from_long(128)); + +// pmt_dict_set(usrp_dict, +// pmt_intern("rf-freq"), +// pmt_from_long(10e6)); + + define_component("server", "usrp_server", usrp_dict); + + connect("self", "tx0", "server", "tx0"); + connect("self", "cs", "server", "cs"); + + // initialize NCO + double freq = 100e3; + int interp = 32; // 32 -> 4MS/s + double sample_rate = 128e6 / interp; + d_nco.set_freq(2*M_PI * freq/sample_rate); + + // FIXME need to somehow set the interp rate in the USRP. + // for now, we'll have the low-level code hardwire it. +} + +test_usrp_tx::~test_usrp_tx() +{ +} + +void +test_usrp_tx::initial_transition() +{ + open_usrp(); +} + +void +test_usrp_tx::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + std::string error_msg; + + //std::cout << msg << std::endl; + + switch(d_state){ + case OPENING_USRP: + if (pmt_eq(event, s_response_open)){ + status = pmt_nth(1, data); + if (pmt_eq(status, PMT_T)){ + allocate_channel(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + } + goto unhandled; + + case ALLOCATING_CHANNEL: + if (pmt_eq(event, s_response_allocate_channel)){ + status = pmt_nth(1, data); + if(pmt_eqv(d_tx_chan0, PMT_NIL)) + d_tx_chan0 = pmt_nth(2, data); + else + d_tx_chan1 = pmt_nth(2, data); + + if (pmt_eq(status, PMT_T) && !pmt_eqv(d_tx_chan1, PMT_NIL)){ + enter_transmitting(); + return; + } + else if(pmt_eq(status, PMT_F)){ + error_msg = "failed to allocate channel:"; + goto bail; + } + return; + } + goto unhandled; + + case TRANSMITTING: + if (pmt_eq(event, s_response_xmit_raw_frame)){ + handle = pmt_nth(0, data); + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + handle_xmit_response(handle); + return; + } + else { + error_msg = "bad response-xmit-raw-frame:"; + goto bail; + } + } + goto unhandled; + + case CLOSING_CHANNEL: + if (pmt_eq(event, s_response_deallocate_channel)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + close_usrp(); + return; + } + else { + error_msg = "failed to deallocate channel:"; + goto bail; + } + } + goto unhandled; + + case CLOSING_USRP: + if (pmt_eq(event, s_response_close)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + shutdown_all(PMT_T); + return; + } + else { + error_msg = "failed to close USRP:"; + goto bail; + } + } + goto unhandled; + + default: + goto unhandled; + } + return; + + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + unhandled: + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; +} + + +void +test_usrp_tx::open_usrp() +{ + pmt_t which_usrp = pmt_from_long(0); + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp)); + d_state = OPENING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Opening the USRP\n"; +} + +void +test_usrp_tx::close_usrp() +{ + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); + d_state = CLOSING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Closing the USRP\n"; +} + +void +test_usrp_tx::allocate_channel() +{ + long capacity = (long) 16e6; + + // Send two capacity requests, which will allocate us two channels + d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_state = ALLOCATING_CHANNEL; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Requesting TX channel allocation\n"; +} + +void +test_usrp_tx::enter_transmitting() +{ + d_state = TRANSMITTING; + d_nsamples_xmitted = 0; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Transmitting...\n"; + + build_and_send_next_frame(); // fire off 4 to start pipeline + build_and_send_next_frame(); + build_and_send_next_frame(); + build_and_send_next_frame(); +} + +void +test_usrp_tx::build_and_send_next_frame() +{ + // allocate the uniform vector for the samples + // FIXME perhaps hold on to this between calls + +#if 1 + long nsamples_this_frame = + std::min(d_nsamples_to_send - d_nsamples_xmitted, + d_samples_per_frame); +#else + long nsamples_this_frame = d_samples_per_frame; +#endif + + if (nsamples_this_frame == 0){ + d_done_sending = true; + return; + } + + + size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q + pmt_t uvec = pmt_make_s16vector(nshorts, 0); + size_t ignore; + int16_t *samples = pmt_s16vector_writable_elements(uvec, ignore); + + // fill in the complex sinusoid + + for (int i = 0; i < nsamples_this_frame; i++){ + + if (1){ + gr_complex s; + d_nco.sincos(&s, 1, d_amplitude); + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + else { + gr_complex s(d_amplitude, d_amplitude); + + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + } + + pmt_t tx_properties = pmt_make_dict(); + + pmt_t timestamp = pmt_from_long(0xffffffff); // NOW + d_tx->send(s_cmd_xmit_raw_frame, + pmt_list5(pmt_from_long(d_nframes_xmitted), // invocation-handle + d_tx_chan0, // channel + uvec, // the samples + timestamp, + tx_properties)); + + // Resend on channel 1 + d_tx->send(s_cmd_xmit_raw_frame, + pmt_list5(pmt_from_long(d_nframes_xmitted), // invocation-handle + d_tx_chan1, // channel + uvec, // the samples + timestamp, + tx_properties)); + + d_nsamples_xmitted += nsamples_this_frame; + d_nframes_xmitted++; + + if(verbose && 0) + std::cout << "[TEST_USRP_INBAND_TX] Transmitted frame\n"; +} + + +void +test_usrp_tx::handle_xmit_response(pmt_t handle) +{ + if (d_done_sending && + pmt_to_long(handle) == (d_nframes_xmitted - 1)){ + // We're done sending and have received all responses + enter_closing_channel(); + } + + build_and_send_next_frame(); +} + +void +test_usrp_tx::enter_closing_channel() +{ + d_state = CLOSING_CHANNEL; + + // Deallocate both channels + d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan0)); + d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan1)); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_tX] Deallocating TX channel\n"; +} + +REGISTER_MBLOCK_CLASS(test_usrp_tx); + + +// ---------------------------------------------------------------- + +int +main (int argc, char **argv) +{ + // handle any command line args here + + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_tx", PMT_F, &result); +} diff --git a/usrp/limbo/apps-inband/test_usrp_inband_overrun.cc b/usrp/limbo/apps-inband/test_usrp_inband_overrun.cc new file mode 100644 index 000000000..cd0fa525a --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_overrun.cc @@ -0,0 +1,375 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,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 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 <mblock/mblock.h> +#include <mblock/runtime.h> +#include <mblock/protocol_class.h> +#include <mblock/exception.h> +#include <mblock/msg_queue.h> +#include <mblock/message.h> +#include <mblock/msg_accepter.h> +#include <mblock/class_registry.h> +#include <pmt.h> +#include <stdio.h> +#include <string.h> +#include <iostream> +#include <fstream> + +// Include the symbols needed for communication with USRP server +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_rx.h> + +static bool verbose = true; + +class test_usrp_rx : public mb_mblock +{ + mb_port_sptr d_rx; + mb_port_sptr d_cs; + pmt_t d_rx_chan; // returned tx channel handle + + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNEL, + RECEIVING, + CLOSING_CHANNEL, + CLOSING_USRP, + }; + + state_t d_state; + + std::ofstream d_ofile; + + long d_n_overruns; + + long d_samples_recvd; + long d_samples_to_recv; + + public: + test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_rx(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void open_usrp(); + void close_usrp(); + void allocate_channel(); + void send_packets(); + void enter_receiving(); + void build_and_send_next_frame(); + void handle_response_recv_raw_samples(pmt_t invocation_handle); + void enter_closing_channel(); +}; + +test_usrp_rx::test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_n_overruns(0), + d_samples_recvd(0), + d_samples_to_recv(10e6) +{ + + d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP + pmt_t usrp_dict = pmt_make_dict(); + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("inband_1rxhb_1tx.rbf")); + + pmt_dict_set(usrp_dict, + pmt_intern("decim-rx"), + pmt_from_long(128)); + + define_component("server", "usrp_server", usrp_dict); + + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + +} + +test_usrp_rx::~test_usrp_rx() +{ +} + +void +test_usrp_rx::initial_transition() +{ + open_usrp(); +} + +void +test_usrp_rx::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + std::string error_msg; + + switch(d_state){ + + //----------------------------- OPENING_USRP ----------------------------// + // We only expect a response from opening the USRP which should be succesful + // or failed. + case OPENING_USRP: + if (pmt_eq(event, s_response_open)){ + status = pmt_nth(1, data); + if (pmt_eq(status, PMT_T)){ + allocate_channel(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + } + goto unhandled; + + //----------------------- ALLOCATING CHANNELS --------------------// + // Allocate an RX channel to perform the overrun test. + case ALLOCATING_CHANNEL: + if (pmt_eq(event, s_response_allocate_channel)){ + status = pmt_nth(1, data); + d_rx_chan = pmt_nth(2, data); + + if (pmt_eq(status, PMT_T)){ + enter_receiving(); + return; + } + else { + error_msg = "failed to allocate channel:"; + goto bail; + } + } + goto unhandled; + + //--------------------------- RECEIVING ------------------------------// + // In the receiving state, we receive samples until the specified amount + // while counting the number of overruns. + case RECEIVING: + if (pmt_eq(event, s_response_recv_raw_samples)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + handle_response_recv_raw_samples(data); + return; + } + else { + error_msg = "bad response-xmit-raw-frame:"; + goto bail; + } + } + goto unhandled; + + //------------------------- CLOSING CHANNEL ----------------------------// + // Check deallocation response for the RX channel + case CLOSING_CHANNEL: + if (pmt_eq(event, s_response_deallocate_channel)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + close_usrp(); + return; + } + else { + error_msg = "failed to deallocate channel:"; + goto bail; + } + } + + // Alternately, we ignore all response recv samples while waiting for the + // channel to actually close + if (pmt_eq(event, s_response_recv_raw_samples)) + return; + + goto unhandled; + + //--------------------------- CLOSING USRP ------------------------------// + // Once we have received a successful USRP close response, we shutdown all + // mblocks and exit. + case CLOSING_USRP: + if (pmt_eq(event, s_response_close)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + std::cout << "\nOverruns: " << d_n_overruns << std::endl; + fflush(stdout); + shutdown_all(PMT_T); + return; + } + else { + error_msg = "failed to close USRP:"; + goto bail; + } + } + goto unhandled; + + default: + goto unhandled; + } + return; + + // An error occured, print it, and shutdown all m-blocks + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + // Received an unhandled message for a specific state + unhandled: + if(verbose && !pmt_eq(event, pmt_intern("%shutdown"))) + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; +} + + +void +test_usrp_rx::open_usrp() +{ + pmt_t which_usrp = pmt_from_long(0); + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp)); + d_state = OPENING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_OVERRUN] Opening the USRP\n"; +} + +void +test_usrp_rx::close_usrp() +{ + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); + d_state = CLOSING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_OVERRUN] Closing the USRP\n"; +} + +void +test_usrp_rx::allocate_channel() +{ + long capacity = (long) 16e6; + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_state = ALLOCATING_CHANNEL; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_OVERRUN] Requesting RX channel allocation\n"; +} + +void +test_usrp_rx::enter_receiving() +{ + d_state = RECEIVING; + + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_F, + d_rx_chan)); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_OVERRUN] Receiving...\n"; +} + +void +test_usrp_rx::handle_response_recv_raw_samples(pmt_t data) +{ + pmt_t invocation_handle = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); + pmt_t v_samples = pmt_nth(2, data); + pmt_t timestamp = pmt_nth(3, data); + pmt_t channel = pmt_nth(4, data); + pmt_t properties = pmt_nth(5, data); + + d_samples_recvd += pmt_length(v_samples) / 4; + + // Check for overrun + if(!pmt_is_dict(properties)) { + std::cout << "[TEST_USRP_INBAND_OVERRUN] Recv samples dictionary is improper\n"; + return; + } + + if(pmt_t overrun = pmt_dict_ref(properties, + pmt_intern("overrun"), + PMT_NIL)) { + if(pmt_eqv(overrun, PMT_T)) { + d_n_overruns++; + + if(verbose && 0) + std::cout << "[TEST_USRP_INBAND_OVERRUN] Underrun\n"; + } + else { + if(verbose && 0) + std::cout << "[TEST_USRP_INBAND_OVERRUN] No overrun\n" << overrun <<std::endl; + } + } else { + + if(verbose && 0) + std::cout << "[TEST_USRP_INBAND_OVERRUN] No overrun\n"; + } + + // Check if the number samples we have received meets the test + if(d_samples_recvd >= d_samples_to_recv) { + d_rx->send(s_cmd_stop_recv_raw_samples, pmt_list2(PMT_NIL, d_rx_chan)); + enter_closing_channel(); + return; + } + +} + +void +test_usrp_rx::enter_closing_channel() +{ + d_state = CLOSING_CHANNEL; + + sleep(2); + + d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan)); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_OVERRUN] Deallocating RX channel\n"; +} + +REGISTER_MBLOCK_CLASS(test_usrp_rx); + + +// ---------------------------------------------------------------- + +int +main (int argc, char **argv) +{ + // handle any command line args here + + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_rx", PMT_F, &result); +} diff --git a/usrp/limbo/apps-inband/test_usrp_inband_ping.cc b/usrp/limbo/apps-inband/test_usrp_inband_ping.cc new file mode 100644 index 000000000..d779c9a64 --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_ping.cc @@ -0,0 +1,374 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,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 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 <mblock/mblock.h> +#include <mblock/runtime.h> +#include <mblock/protocol_class.h> +#include <mblock/exception.h> +#include <mblock/msg_queue.h> +#include <mblock/message.h> +#include <mblock/msg_accepter.h> +#include <mblock/class_registry.h> +#include <pmt.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <iostream> + +// Include the symbols needed for communication with USRP server +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_tx.h> +#include <symbols_usrp_rx.h> + +static bool verbose = false; + +class test_usrp_inband_ping : public mb_mblock +{ + + mb_port_sptr d_tx; // Ports connected to the USRP server + mb_port_sptr d_rx; + mb_port_sptr d_cs; + + pmt_t d_tx_chan; // Returned channel from TX allocation + pmt_t d_rx_chan; // Returned channel from RX allocation + + pmt_t d_which_usrp; // The USRP to use for the test + + long d_warm_msgs; // The number of messages to 'warm' the USRP + long d_warm_recvd; // The number of msgs received in the 'warm' state + + // Keep track of current state + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNELS, + WARMING_USRP, + PINGING, + CLOSING_CHANNELS, + CLOSING_USRP, + }; + state_t d_state; + + public: + test_usrp_inband_ping(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_inband_ping(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void opening_usrp(); + void allocating_channels(); + void enter_warming_usrp(); + void enter_pinging(); + void build_and_send_ping(); + void closing_channels(); + void closing_usrp(); +}; + + +int +main (int argc, char **argv) +{ + // handle any command line args here + + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_inband_ping", PMT_F, &result); +} + + +test_usrp_inband_ping::test_usrp_inband_ping(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_tx_chan(PMT_NIL), + d_rx_chan(PMT_NIL), + d_which_usrp(pmt_from_long(0)), + d_state(INIT) +{ + + // A dictionary is used to pass parameters to the USRP + pmt_t usrp_dict = pmt_make_dict(); + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("fixed1.rbf")); + + // Set TX and RX interpolations + pmt_dict_set(usrp_dict, + pmt_intern("interp-tx"), + pmt_from_long(128)); + + pmt_dict_set(usrp_dict, + pmt_intern("decim-rx"), + pmt_from_long(16)); + + d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL); + d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + // Create an instance of USRP server and connect ports + define_component("server", "usrp_server", usrp_dict); + connect("self", "tx0", "server", "tx0"); + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + +} + +test_usrp_inband_ping::~test_usrp_inband_ping() +{ +} + +void +test_usrp_inband_ping::initial_transition() +{ + opening_usrp(); +} + +// Handle message reads all incoming messages from USRP server which will be +// initialization and ping responses. We perform actions based on the current +// state and the event (ie, ping response) +void +test_usrp_inband_ping::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + pmt_t port_id = msg->port_id(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + std::string error_msg; + + // Dispatch based on state + switch(d_state) { + + //----------------------------- OPENING_USRP ----------------------------// + // We only expect a response from opening the USRP which should be succesful + // or failed. + case OPENING_USRP: + + if(pmt_eq(event, s_response_open)) { + + status = pmt_nth(1, data); // failed/succes + + if(pmt_eq(status, PMT_T)) { + allocating_channels(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + + } + + goto unhandled; // all other messages not handled in this state + + + //----------------------- ALLOCATING CHANNELS --------------------// + // When allocating channels, we need to wait for 2 responses from + // USRP server: one for TX and one for RX. Both are initialized to + // NIL so we know to continue to the next state once both are set. + case ALLOCATING_CHANNELS: + + // A TX allocation response + if(pmt_eq(event, s_response_allocate_channel) + && pmt_eq(d_tx->port_symbol(), port_id)) + { + status = pmt_nth(1, data); + + // If successful response, extract the channel + if(pmt_eq(status, PMT_T)) { + + d_tx_chan = pmt_nth(2, data); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Received TX allocation" + << " on channel " << d_tx_chan << std::endl; + + // If the RX has also been allocated already, we can continue + if(!pmt_eqv(d_rx_chan, PMT_NIL)) + enter_warming_usrp(); + + return; + } + else { // TX allocation failed + error_msg = "failed to allocate TX channel:"; + goto bail; + } + } + + // A RX allocation response + if(pmt_eq(event, s_response_allocate_channel) + && pmt_eq(d_rx->port_symbol(), port_id)) + { + status = pmt_nth(1, data); + + // If successful response, extract the channel + if(pmt_eq(status, PMT_T)) { + + d_rx_chan = pmt_nth(2, data); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Received RX allocation" + << " on channel " << d_rx_chan << std::endl; + + // If the TX has also been allocated already, we can continue + if(!pmt_eqv(d_tx_chan, PMT_NIL)) + enter_warming_usrp(); + + return; + } + else { // RX allocation failed + error_msg = "failed to allocate RX channel:"; + goto bail; + } + } + + goto unhandled; + + //----------------------- WARMING USRP --------------------// + // The FX2 seems to need some amount of data to be buffered + // before it begins reading. We use this state to simply + // warm up the USRP before benchmarking pings. + case WARMING_USRP: + + // We really don't care about the responses from the + // control channel in the warming stage, but once we receive + // the proper number of responses we switch states. + if(pmt_eq(event, s_response_from_control_channel) + && pmt_eq(d_rx->port_symbol(), port_id)) + { + d_warm_recvd++; + + if(d_warm_recvd > d_warm_msgs) + enter_pinging(); + + return; + } + + goto unhandled; + + case PINGING: + goto unhandled; + + case CLOSING_CHANNELS: + goto unhandled; + + case CLOSING_USRP: + goto unhandled; + + case INIT: + goto unhandled; + + } + + // An error occured, print it, and shutdown all m-blocks + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + // Received an unhandled message for a specific state + unhandled: + if(verbose) + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; + +} + + +// Sends a command to USRP server to open up a connection to the +// specified USRP, which is defaulted to USRP 0 on the system +void +test_usrp_inband_ping::opening_usrp() +{ + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Opening USRP " + << d_which_usrp << std::endl; + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, d_which_usrp)); + d_state = OPENING_USRP; +} + +// RX and TX channels must be allocated so that the USRP server can +// properly share bandwidth across multiple USRPs. No commands will be +// successful to the USRP through the USRP server on the TX or RX channels until +// a bandwidth allocation has been received. +void +test_usrp_inband_ping::allocating_channels() +{ + d_state = ALLOCATING_CHANNELS; + + long capacity = (long) 16e6; + d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); +} + +// The USRP needs some amount of initial data to pass a buffering point such +// that it begins to pull and read data from the FX2. We send an arbitrary +// amount of data to start the pipeline, which are just pings. +void +test_usrp_inband_ping::enter_warming_usrp() +{ + d_state = WARMING_USRP; + + for(int i=0; i < d_warm_msgs; i++) + build_and_send_ping(); +} + +void +test_usrp_inband_ping::enter_pinging() +{ + d_state = PINGING; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Running ping tests\n"; + +} + +// Pings are sent over the TX channel using the signal 'cmd-to-control-channel' +// to the USRP server. Within this message there can be infinite subpackets +// stored as a list (the second parameter) and sent. The only subpacket we send +// is a ping, interpreted by the 'op-ping-fixed' signal. +void +test_usrp_inband_ping::build_and_send_ping() +{ + + d_tx->send(s_cmd_to_control_channel, // USRP server signal + pmt_list2(PMT_NIL, // invocation handle + pmt_list1(pmt_list3(s_op_ping_fixed, + pmt_from_long(0), + pmt_from_long(0))))); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Ping!!" << std::endl; +} + +REGISTER_MBLOCK_CLASS(test_usrp_inband_ping); diff --git a/usrp/limbo/apps-inband/test_usrp_inband_registers.cc b/usrp/limbo/apps-inband/test_usrp_inband_registers.cc new file mode 100644 index 000000000..d9bd2db17 --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_registers.cc @@ -0,0 +1,435 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 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 <mblock/mblock.h> +#include <mblock/runtime.h> +#include <mblock/protocol_class.h> +#include <mblock/exception.h> +#include <mblock/msg_queue.h> +#include <mblock/message.h> +//#include <mb_mblock_impl.h> +#include <mblock/msg_accepter.h> +#include <mblock/class_registry.h> +#include <pmt.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <iostream> + +// Include the symbols needed for communication with USRP server +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_tx.h> +#include <symbols_usrp_rx.h> + +static bool verbose = true; + +class test_usrp_inband_registers : public mb_mblock +{ + + mb_port_sptr d_tx; // Ports connected to the USRP server + mb_port_sptr d_rx; + mb_port_sptr d_cs; + + pmt_t d_tx_chan; // Returned channel from TX allocation + pmt_t d_rx_chan; // Returned channel from RX allocation + + pmt_t d_which_usrp; // The USRP to use for the test + + long d_warm_msgs; // The number of messages to 'warm' the USRP + long d_warm_recvd; // The number of msgs received in the 'warm' state + + // Keep track of current state + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNELS, + WRITE_REGISTER, + READ_REGISTER, + CLOSING_CHANNELS, + CLOSING_USRP, + }; + state_t d_state; + + public: + test_usrp_inband_registers(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_inband_registers(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void opening_usrp(); + void allocating_channels(); + void write_register(); + void read_register(); + void closing_channels(); + void closing_usrp(); + void enter_receiving(); + void build_and_send_ping(); +}; + + +int +main (int argc, char **argv) +{ + // handle any command line args here + + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_inband_registers", PMT_F, &result); +} + + +test_usrp_inband_registers::test_usrp_inband_registers(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_tx_chan(PMT_NIL), + d_rx_chan(PMT_NIL), + d_which_usrp(pmt_from_long(0)), + d_state(INIT) +{ + + // A dictionary is used to pass parameters to the USRP + pmt_t usrp_dict = pmt_make_dict(); + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("inband_1rxhb_1tx.rbf")); + + // Set TX and RX interpolations + pmt_dict_set(usrp_dict, + pmt_intern("interp-tx"), + pmt_from_long(128)); + + pmt_dict_set(usrp_dict, + pmt_intern("decim-rx"), + pmt_from_long(16)); + + d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL); + d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + // Create an instance of USRP server and connect ports + define_component("server", "usrp_server", usrp_dict); + connect("self", "tx0", "server", "tx0"); + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + +} + +test_usrp_inband_registers::~test_usrp_inband_registers() +{ +} + +void +test_usrp_inband_registers::initial_transition() +{ + opening_usrp(); +} + +// Handle message reads all incoming messages from USRP server which will be +// initialization and ping responses. We perform actions based on the current +// state and the event (ie, ping response) +void +test_usrp_inband_registers::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + pmt_t port_id = msg->port_id(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + std::string error_msg; + + // Dispatch based on state + switch(d_state) { + + //----------------------------- OPENING_USRP ----------------------------// + // We only expect a response from opening the USRP which should be succesful + // or failed. + case OPENING_USRP: + + if(pmt_eq(event, s_response_open)) { + + status = pmt_nth(1, data); // failed/succes + + if(pmt_eq(status, PMT_T)) { + allocating_channels(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + + } + + goto unhandled; // all other messages not handled in this state + + + //----------------------- ALLOCATING CHANNELS --------------------// + // When allocating channels, we need to wait for 2 responses from + // USRP server: one for TX and one for RX. Both are initialized to + // NIL so we know to continue to the next state once both are set. + case ALLOCATING_CHANNELS: + + // A TX allocation response + if(pmt_eq(event, s_response_allocate_channel) + && pmt_eq(d_tx->port_symbol(), port_id)) + { + status = pmt_nth(1, data); + + // If successful response, extract the channel + if(pmt_eq(status, PMT_T)) { + + d_tx_chan = pmt_nth(2, data); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Received TX allocation" + << " on channel " << d_tx_chan << std::endl; + + // If the RX has also been allocated already, we can continue + if(!pmt_eqv(d_rx_chan, PMT_NIL)) { + enter_receiving(); + write_register(); + } + + return; + } + else { // TX allocation failed + error_msg = "failed to allocate TX channel:"; + goto bail; + } + } + + // A RX allocation response + if(pmt_eq(event, s_response_allocate_channel) + && pmt_eq(d_rx->port_symbol(), port_id)) + { + status = pmt_nth(1, data); + + // If successful response, extract the channel + if(pmt_eq(status, PMT_T)) { + + d_rx_chan = pmt_nth(2, data); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Received RX allocation" + << " on channel " << d_rx_chan << std::endl; + + // If the TX has also been allocated already, we can continue + if(!pmt_eqv(d_tx_chan, PMT_NIL)) { + enter_receiving(); + write_register(); + } + + return; + } + else { // RX allocation failed + error_msg = "failed to allocate RX channel:"; + goto bail; + } + } + + goto unhandled; + + //-------------------------- WRITE REGISTER ----------------------------// + // In the write register state, we do not expect to receive any messages + // since the write does not directly generate a response until the USRP + // responds. + case WRITE_REGISTER: + goto unhandled; + + //-------------------------- READ REGISTER ----------------------------// + // In the read register state, we only expect a read register response back + // that has the value we expect to have in it. We read the response, ensure + // that the read was successful and display the register value. + case READ_REGISTER: + + if(pmt_eq(event, s_response_from_control_channel) + && pmt_eq(d_tx->port_symbol(), port_id)) + { + status = pmt_nth(1, data); + + // If the read was successful, we extract the subpacket information + if(pmt_eq(status, PMT_T)) { + + pmt_t subp = pmt_nth(2, data); // subpacket should be the read reg reply + + pmt_t subp_sig = pmt_nth(0, subp); + pmt_t subp_data = pmt_nth(1, subp); + + if(!pmt_eqv(subp_sig, s_op_read_reg_reply)) { + error_msg = "received improper subpacket when expecting reg reply."; + goto bail; + } + + pmt_t rid = pmt_nth(0, subp_data); + pmt_t reg_num = pmt_nth(1, subp_data); + pmt_t reg_val = pmt_nth(2, subp_data); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_REGISTERS] Received read reg reply " + << "(" + << "RID: " << rid << ", " + << "Reg: " << reg_num << ", " + << "Val: " << reg_val + << ")\n"; + + // read_register(); FIX ME STATE TRANSITION + return; + + } else { // bail on unsuccessful write + error_msg = "failed to write to register."; + goto bail; + } + } + goto unhandled; + + case CLOSING_CHANNELS: + goto unhandled; + + case CLOSING_USRP: + goto unhandled; + + case INIT: + goto unhandled; + + } + + // An error occured, print it, and shutdown all m-blocks + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + // Received an unhandled message for a specific state + unhandled: + if(verbose && !pmt_eq(event, s_response_recv_raw_samples)) + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; + +} + + +// Sends a command to USRP server to open up a connection to the +// specified USRP, which is defaulted to USRP 0 on the system +void +test_usrp_inband_registers::opening_usrp() +{ + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Opening USRP " + << d_which_usrp << std::endl; + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, d_which_usrp)); + d_state = OPENING_USRP; +} + +// RX and TX channels must be allocated so that the USRP server can +// properly share bandwidth across multiple USRPs. No commands will be +// successful to the USRP through the USRP server on the TX or RX channels until +// a bandwidth allocation has been received. +void +test_usrp_inband_registers::allocating_channels() +{ + d_state = ALLOCATING_CHANNELS; + + long capacity = (long) 16e6; + d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); +} + +// After allocating the channels, a write register command will be sent to the +// USRP. +void +test_usrp_inband_registers::write_register() +{ + d_state = WRITE_REGISTER; + + long reg = 0; + + d_tx->send(s_cmd_to_control_channel, // C/S packet + pmt_list2(PMT_NIL, // invoc handle + pmt_list1( + pmt_list2(s_op_write_reg, + pmt_list2( + pmt_from_long(reg), + pmt_from_long(0xbeef)))))); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_REGISTERS] Writing 0xbeef to " + << reg << std::endl; + + read_register(); // immediately transition to read the register +} + +// Temporary: for testing pings +void +test_usrp_inband_registers::build_and_send_ping() +{ + + d_tx->send(s_cmd_to_control_channel, + pmt_list2(PMT_NIL, pmt_list1(pmt_list2(s_op_ping_fixed, + pmt_list2(pmt_from_long(0), + pmt_from_long(0)))))); + + std::cout << "[TEST_USRP_INBAND_CS] Ping sent" << std::endl; +} + +// After writing to the register, we want to read the value back and ensure that +// it is the same value that we wrote. +void +test_usrp_inband_registers::read_register() +{ + d_state = READ_REGISTER; + + long reg = 9; + + d_tx->send(s_cmd_to_control_channel, // C/S packet + pmt_list2(PMT_NIL, // invoc handle + pmt_list1( + pmt_list2(s_op_read_reg, + pmt_list2( + pmt_from_long(0), // rid + pmt_from_long(reg)))))); + if(verbose) + std::cout << "[TEST_USRP_INBAND_REGISTERS] Reading from register " + << reg << std::endl; +} + +// Used to enter the receiving state +void +test_usrp_inband_registers::enter_receiving() +{ + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_F, + d_rx_chan)); +} + +REGISTER_MBLOCK_CLASS(test_usrp_inband_registers); diff --git a/usrp/limbo/apps-inband/test_usrp_inband_rx.cc b/usrp/limbo/apps-inband/test_usrp_inband_rx.cc new file mode 100644 index 000000000..4f21e4afc --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_rx.cc @@ -0,0 +1,362 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 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 <mblock/mblock.h> +#include <mblock/runtime.h> +#include <mblock/protocol_class.h> +#include <mblock/exception.h> +#include <mblock/msg_queue.h> +#include <mblock/message.h> +#include <mblock/msg_accepter.h> +#include <mblock/class_registry.h> +#include <pmt.h> +#include <stdio.h> +#include <string.h> +#include <iostream> +#include <fstream> + +// Include the symbols needed for communication with USRP server +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_rx.h> + +static bool verbose = true; + +class test_usrp_rx : public mb_mblock +{ + mb_port_sptr d_rx; + mb_port_sptr d_cs; + pmt_t d_rx_chan; // returned tx channel handle + + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNEL, + RECEIVING, + CLOSING_CHANNEL, + CLOSING_USRP, + }; + + state_t d_state; + + std::ofstream d_ofile; + + long d_samples_recvd; + long d_samples_to_recv; + + public: + test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_rx(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void open_usrp(); + void close_usrp(); + void allocate_channel(); + void send_packets(); + void enter_receiving(); + void build_and_send_next_frame(); + void handle_response_recv_raw_samples(pmt_t invocation_handle); + void enter_closing_channel(); +}; + +test_usrp_rx::test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_samples_recvd(0), + d_samples_to_recv(20e6) +{ + d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP + pmt_t usrp_dict = pmt_make_dict(); + + // To test the application without a USRP + bool fake_usrp_p = false; + if(fake_usrp_p) { + pmt_dict_set(usrp_dict, + pmt_intern("fake-usrp"), + PMT_T); + } + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("inband_1rxhb_1tx.rbf")); + + pmt_dict_set(usrp_dict, + pmt_intern("decim-rx"), + pmt_from_long(64)); + +// If unspecified, chooses center frequency from range +// pmt_dict_set(usrp_dict, +// pmt_intern("rf-freq"), +// pmt_from_long(10e6)); + + define_component("server", "usrp_server", usrp_dict); + + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + +} + +test_usrp_rx::~test_usrp_rx() +{ +} + +void +test_usrp_rx::initial_transition() +{ + open_usrp(); +} + +void +test_usrp_rx::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + std::string error_msg; + + switch(d_state){ + + //----------------------------- OPENING_USRP ----------------------------// + // We only expect a response from opening the USRP which should be succesful + // or failed. + case OPENING_USRP: + if (pmt_eq(event, s_response_open)){ + status = pmt_nth(1, data); + if (pmt_eq(status, PMT_T)){ + allocate_channel(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + } + goto unhandled; + + //----------------------- ALLOCATING CHANNELS --------------------// + // Allocate an RX channel to perform the overrun test. + case ALLOCATING_CHANNEL: + if (pmt_eq(event, s_response_allocate_channel)){ + status = pmt_nth(1, data); + d_rx_chan = pmt_nth(2, data); + + if (pmt_eq(status, PMT_T)){ + enter_receiving(); + return; + } + else { + error_msg = "failed to allocate channel:"; + goto bail; + } + } + goto unhandled; + + //--------------------------- RECEIVING ------------------------------// + // In the receiving state, we receive samples until the specified amount + // while counting the number of overruns. + case RECEIVING: + if (pmt_eq(event, s_response_recv_raw_samples)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + handle_response_recv_raw_samples(data); + return; + } + else { + error_msg = "bad response-xmit-raw-frame:"; + goto bail; + } + } + goto unhandled; + + //------------------------- CLOSING CHANNEL ----------------------------// + // Check deallocation response for the RX channel + case CLOSING_CHANNEL: + if (pmt_eq(event, s_response_deallocate_channel)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + close_usrp(); + return; + } + else { + error_msg = "failed to deallocate channel:"; + goto bail; + } + } + + // Alternately, we ignore all response recv samples while waiting for the + // channel to actually close + if (pmt_eq(event, s_response_recv_raw_samples)) + return; + + goto unhandled; + + //--------------------------- CLOSING USRP ------------------------------// + // Once we have received a successful USRP close response, we shutdown all + // mblocks and exit. + case CLOSING_USRP: + if (pmt_eq(event, s_response_close)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + fflush(stdout); + shutdown_all(PMT_T); + return; + } + else { + error_msg = "failed to close USRP:"; + goto bail; + } + } + goto unhandled; + + default: + goto unhandled; + } + return; + + // An error occured, print it, and shutdown all m-blocks + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + // Received an unhandled message for a specific state + unhandled: + if(verbose && !pmt_eq(event, pmt_intern("%shutdown"))) + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; +} + + +void +test_usrp_rx::open_usrp() +{ + pmt_t which_usrp = pmt_from_long(0); + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp)); + d_state = OPENING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_RX] Opening the USRP\n"; +} + +void +test_usrp_rx::close_usrp() +{ + + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); + d_state = CLOSING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_RX] Closing the USRP\n"; +} + +void +test_usrp_rx::allocate_channel() +{ + long capacity = (long) 16e6; + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_state = ALLOCATING_CHANNEL; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_RX] Requesting RX channel allocation\n"; +} + +void +test_usrp_rx::enter_receiving() +{ + d_state = RECEIVING; + + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_F, + d_rx_chan)); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_RX] Receiving...\n"; +} + +void +test_usrp_rx::handle_response_recv_raw_samples(pmt_t data) +{ + pmt_t invocation_handle = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); + pmt_t v_samples = pmt_nth(2, data); + pmt_t timestamp = pmt_nth(3, data); + pmt_t channel = pmt_nth(4, data); + pmt_t properties = pmt_nth(5, data); + + d_samples_recvd += pmt_length(v_samples) / 4; + + // Check for overrun + if(!pmt_is_dict(properties)) { + std::cout << "[TEST_USRP_INBAND_RX] Recv samples dictionary is improper\n"; + return; + } + + // Check if the number samples we have received meets the test + if(d_samples_recvd >= d_samples_to_recv) { + d_rx->send(s_cmd_stop_recv_raw_samples, pmt_list2(PMT_NIL, d_rx_chan)); + enter_closing_channel(); + return; + } + +} + +void +test_usrp_rx::enter_closing_channel() +{ + d_state = CLOSING_CHANNEL; + + d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan)); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_RX] Deallocating RX channel\n"; +} + +REGISTER_MBLOCK_CLASS(test_usrp_rx); + + +// ---------------------------------------------------------------- + +int +main (int argc, char **argv) +{ + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_rx", PMT_F, &result); + +} diff --git a/usrp/limbo/apps-inband/test_usrp_inband_timestamps.cc b/usrp/limbo/apps-inband/test_usrp_inband_timestamps.cc new file mode 100644 index 000000000..3b874d1a5 --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_timestamps.cc @@ -0,0 +1,506 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,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 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 <mblock/mblock.h> +#include <mblock/runtime.h> +#include <mblock/protocol_class.h> +#include <mblock/exception.h> +#include <mblock/msg_queue.h> +#include <mblock/message.h> +#include <mblock/msg_accepter.h> +#include <mblock/class_registry.h> +#include <pmt.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <iostream> + +#include <ui_nco.h> +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_tx.h> +#include <symbols_usrp_rx.h> + +#define NBPING 10 + +static bool verbose = true; +bool bskip = false; +long bstep = 10000; +long bcurr = 0; +long incr = 0x500; +long ptime = 0x000; + +class test_usrp_inband_timestamps : public mb_mblock +{ + mb_port_sptr d_tx; + mb_port_sptr d_rx; + mb_port_sptr d_cs; + pmt_t d_tx_chan; // returned tx channel handle + pmt_t d_rx_chan; // returned tx channel handle + + struct timeval times[NBPING]; + + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNEL, + TRANSMITTING, + CLOSING_CHANNEL, + CLOSING_USRP, + }; + + state_t d_state; + long d_nsamples_to_send; + long d_nsamples_xmitted; + long d_nframes_xmitted; + long d_samples_per_frame; + bool d_done_sending; + + // for generating sine wave output + ui_nco<float,float> d_nco; + double d_amplitude; + + public: + test_usrp_inband_timestamps(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_inband_timestamps(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void open_usrp(); + void close_usrp(); + void allocate_channel(); + void send_packets(); + void enter_receiving(); + void enter_transmitting(); + void build_and_send_ping(); + void build_and_send_next_frame(); + void handle_xmit_response(pmt_t invocation_handle); + void enter_closing_channel(); +}; + +test_usrp_inband_timestamps::test_usrp_inband_timestamps(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_tx_chan(PMT_NIL), + d_rx_chan(PMT_NIL), + d_state(INIT), d_nsamples_to_send((long) 40e6), + d_nsamples_xmitted(0), + d_nframes_xmitted(0), + //d_samples_per_frame((long)(126)), + d_samples_per_frame((long)(126 * 2)), // non-full packet + //d_samples_per_frame((long)(126 * 3.5)), // non-full packet + //d_samples_per_frame((long)(126 * 4)), // full packet + d_done_sending(false), + d_amplitude(16384) +{ + if(verbose) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Initializing...\n"; + + d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL); + d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + bool fake_usrp_p = false; + + // Test the TX side + + pmt_t usrp_dict = pmt_make_dict(); + + if(fake_usrp_p) { + pmt_dict_set(usrp_dict, + pmt_intern("fake-usrp"), + PMT_T); + } + + // Set TX and RX interpolations + pmt_dict_set(usrp_dict, + pmt_intern("interp-tx"), + pmt_from_long(128)); + + pmt_dict_set(usrp_dict, + pmt_intern("decim-rx"), + pmt_from_long(16)); + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("inband_1rxhb_1tx.rbf")); + + define_component("server", "usrp_server", usrp_dict); + + connect("self", "tx0", "server", "tx0"); + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + + // initialize NCO + double freq = 100e3; + int interp = 32; // 32 -> 4MS/s + double sample_rate = 128e6 / interp; + d_nco.set_freq(2*M_PI * freq/sample_rate); + +} + +test_usrp_inband_timestamps::~test_usrp_inband_timestamps() +{ +} + +void +test_usrp_inband_timestamps::initial_transition() +{ + open_usrp(); +} + +void +test_usrp_inband_timestamps::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + pmt_t port_id = msg->port_id(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + std::string error_msg; + + //std::cout << msg << std::endl; + + switch(d_state){ + case OPENING_USRP: + if (pmt_eq(event, s_response_open)){ + status = pmt_nth(1, data); + if (pmt_eq(status, PMT_T)){ + allocate_channel(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + } + goto unhandled; + + case ALLOCATING_CHANNEL: + if (pmt_eq(event, s_response_allocate_channel)){ + + if(pmt_eq(d_tx->port_symbol(), port_id)) { + status = pmt_nth(1, data); + d_tx_chan = pmt_nth(2, data); + + if (pmt_eq(status, PMT_T)){ + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Received allocation for TX\n"; + + if(!pmt_eqv(d_rx_chan, PMT_NIL)) { + enter_receiving(); + enter_transmitting(); + } + return; + } + else { + error_msg = "failed to allocate channel:"; + goto bail; + } + } + + if(pmt_eq(d_rx->port_symbol(), port_id)) { + status = pmt_nth(1, data); + d_rx_chan = pmt_nth(2, data); + + if (pmt_eq(status, PMT_T)){ + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Received allocation for TX\n"; + + if(!pmt_eqv(d_tx_chan, PMT_NIL)) { + enter_receiving(); + enter_transmitting(); + } + return; + } + else { + error_msg = "failed to allocate channel:"; + goto bail; + } + } + } + goto unhandled; + + case TRANSMITTING: + if (pmt_eq(event, s_response_xmit_raw_frame)){ + handle = pmt_nth(0, data); + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + handle_xmit_response(handle); + return; + } + else { + error_msg = "bad response-xmit-raw-frame:"; + goto bail; + } + } + + if (pmt_eq(event, s_response_from_control_channel)) { + std::cout << "ping response!\n"; + } + goto unhandled; + + case CLOSING_CHANNEL: + if (pmt_eq(event, s_response_deallocate_channel)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + close_usrp(); + return; + } + else { + error_msg = "failed to deallocate channel:"; + goto bail; + } + } + goto unhandled; + + case CLOSING_USRP: + if (pmt_eq(event, s_response_close)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + shutdown_all(PMT_T); + return; + } + else { + error_msg = "failed to close USRP:"; + goto bail; + } + } + goto unhandled; + + default: + goto unhandled; + } + return; + + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + unhandled: + if(verbose && 0) + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; +} + + +void +test_usrp_inband_timestamps::open_usrp() +{ + pmt_t which_usrp = pmt_from_long(0); + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp)); + d_state = OPENING_USRP; +} + +void +test_usrp_inband_timestamps::close_usrp() +{ + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); + d_state = CLOSING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Closing USRP\n"; +} + +void +test_usrp_inband_timestamps::allocate_channel() +{ + long capacity = (long) 16e6; + d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_state = ALLOCATING_CHANNEL; +} + +void +test_usrp_inband_timestamps::enter_receiving() +{ + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_F, + d_rx_chan)); +} + +void +test_usrp_inband_timestamps::enter_transmitting() +{ + d_state = TRANSMITTING; + d_nsamples_xmitted = 0; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Beginning transmission\n"; + + sleep(1); + + build_and_send_next_frame(); + build_and_send_next_frame(); + build_and_send_next_frame(); + build_and_send_next_frame(); + +} + +void +test_usrp_inband_timestamps::build_and_send_ping() +{ + + d_tx->send(s_cmd_to_control_channel, + pmt_list2(PMT_NIL, pmt_list1(pmt_list2(s_op_ping_fixed, + pmt_list2(pmt_from_long(0), + pmt_from_long(0)))))); + if(verbose && 0) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Ping sent" << std::endl; +} + +void +test_usrp_inband_timestamps::build_and_send_next_frame() +{ + // allocate the uniform vector for the samples + // FIXME perhaps hold on to this between calls + +#if 0 + long nsamples_this_frame = + std::min(d_nsamples_to_send - d_nsamples_xmitted, + d_samples_per_frame); +#else + long nsamples_this_frame = d_samples_per_frame; +#endif + + if (nsamples_this_frame == 0){ + d_done_sending = true; + return; + } + + + size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q + pmt_t uvec = pmt_make_s16vector(nshorts, 0); + size_t ignore; + int16_t *samples = pmt_s16vector_writable_elements(uvec, ignore); + + // fill in the complex sinusoid + + for (int i = 0; i < nsamples_this_frame; i++){ + + if (1){ + gr_complex s; + d_nco.sincos(&s, 1, d_amplitude); + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + else { + gr_complex s(d_amplitude, d_amplitude); + + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + } + + pmt_t timestamp; + + if(bskip) { + timestamp = pmt_from_long(0x0); // throw away + bcurr++; + if(bcurr == bstep) { + bskip = false; + bcurr = 0; + } + } else { + timestamp = pmt_from_long(0xffffffff); // NOW + timestamp = pmt_from_long(ptime); + ptime += incr; + bcurr++; + if(bcurr == bstep) { + //bskip = true; + bcurr = 0; + } + } + + std::cout << bskip << " -- " << bcurr << std::endl; + + d_tx->send(s_cmd_xmit_raw_frame, + pmt_list4(pmt_from_long(d_nframes_xmitted), // invocation-handle + d_tx_chan, // channel + uvec, // the samples + timestamp)); + + d_nsamples_xmitted += nsamples_this_frame; + d_nframes_xmitted++; + + if(verbose && 0) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Transmitted frame\n"; + + //build_and_send_next_frame(); +} + + +void +test_usrp_inband_timestamps::handle_xmit_response(pmt_t handle) +{ + if (d_done_sending && + pmt_to_long(handle) == (d_nframes_xmitted - 1)){ + // We're done sending and have received all responses + enter_closing_channel(); + } + + build_and_send_next_frame(); + //build_and_send_ping(); +} + +void +test_usrp_inband_timestamps::enter_closing_channel() +{ + d_state = CLOSING_CHANNEL; + + d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan)); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Closing channel\n"; +} + +REGISTER_MBLOCK_CLASS(test_usrp_inband_timestamps); + + +// ---------------------------------------------------------------- + +int +main (int argc, char **argv) +{ + // handle any command line args here + + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_inband_timestamps", PMT_F, &result); +} diff --git a/usrp/limbo/apps-inband/test_usrp_inband_tx.cc b/usrp/limbo/apps-inband/test_usrp_inband_tx.cc new file mode 100644 index 000000000..9f294e770 --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_tx.cc @@ -0,0 +1,411 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,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 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 <mblock/mblock.h> +#include <mblock/runtime.h> +#include <mblock/protocol_class.h> +#include <mblock/exception.h> +#include <mblock/msg_queue.h> +#include <mblock/message.h> +#include <mblock/msg_accepter.h> +#include <mblock/class_registry.h> +#include <pmt.h> +#include <stdio.h> +#include <string.h> +#include <iostream> + +#include <ui_nco.h> +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_tx.h> + +static bool verbose = true; + +class test_usrp_tx : public mb_mblock +{ + mb_port_sptr d_tx; + mb_port_sptr d_cs; + pmt_t d_tx_chan; // returned tx channel handle + + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNEL, + TRANSMITTING, + CLOSING_CHANNEL, + CLOSING_USRP, + }; + + state_t d_state; + long d_nsamples_to_send; + long d_nsamples_xmitted; + long d_nframes_xmitted; + long d_samples_per_frame; + bool d_done_sending; + + // for generating sine wave output + ui_nco<float,float> d_nco; + double d_amplitude; + + public: + test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_tx(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void open_usrp(); + void close_usrp(); + void allocate_channel(); + void send_packets(); + void enter_transmitting(); + void build_and_send_next_frame(); + void handle_xmit_response(pmt_t invocation_handle); + void enter_closing_channel(); +}; + +test_usrp_tx::test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_state(INIT), d_nsamples_to_send((long) 80e6), + d_nsamples_xmitted(0), + d_nframes_xmitted(0), + d_samples_per_frame((long)(126 * 4)), // full packet + d_done_sending(false), + d_amplitude(16384) +{ + // std::cout << "[TEST_USRP_TX] Initializing...\n"; + + d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + //bool fake_usrp_p = true; + bool fake_usrp_p = false; + + // Test the TX side + + pmt_t usrp_dict = pmt_make_dict(); + + if(fake_usrp_p) { + pmt_dict_set(usrp_dict, + pmt_intern("fake-usrp"), + PMT_T); + } + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("inband_1rxhb_1tx.rbf")); + + // Set TX and RX interpolations + pmt_dict_set(usrp_dict, + pmt_intern("interp-tx"), + pmt_from_long(64)); + +// If unspecified, chooses center frequency from range +// pmt_dict_set(usrp_dict, +// pmt_intern("rf-freq"), +// pmt_from_long(10e6)); + + define_component("server", "usrp_server", usrp_dict); + + connect("self", "tx0", "server", "tx0"); + connect("self", "cs", "server", "cs"); + + // initialize NCO + double freq = 100e3; + int interp = 32; // 32 -> 4MS/s + double sample_rate = 128e6 / interp; + d_nco.set_freq(2*M_PI * freq/sample_rate); + + // FIXME need to somehow set the interp rate in the USRP. + // for now, we'll have the low-level code hardwire it. +} + +test_usrp_tx::~test_usrp_tx() +{ +} + +void +test_usrp_tx::initial_transition() +{ + open_usrp(); +} + +void +test_usrp_tx::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + std::string error_msg; + + //std::cout << msg << std::endl; + + switch(d_state){ + case OPENING_USRP: + if (pmt_eq(event, s_response_open)){ + status = pmt_nth(1, data); + if (pmt_eq(status, PMT_T)){ + allocate_channel(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + } + goto unhandled; + + case ALLOCATING_CHANNEL: + if (pmt_eq(event, s_response_allocate_channel)){ + status = pmt_nth(1, data); + d_tx_chan = pmt_nth(2, data); + + if (pmt_eq(status, PMT_T)){ + enter_transmitting(); + return; + } + else { + error_msg = "failed to allocate channel:"; + goto bail; + } + } + goto unhandled; + + case TRANSMITTING: + if (pmt_eq(event, s_response_xmit_raw_frame)){ + handle = pmt_nth(0, data); + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + handle_xmit_response(handle); + return; + } + else { + error_msg = "bad response-xmit-raw-frame:"; + goto bail; + } + } + goto unhandled; + + case CLOSING_CHANNEL: + if (pmt_eq(event, s_response_deallocate_channel)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + close_usrp(); + return; + } + else { + error_msg = "failed to deallocate channel:"; + goto bail; + } + } + goto unhandled; + + case CLOSING_USRP: + if (pmt_eq(event, s_response_close)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + shutdown_all(PMT_T); + return; + } + else { + error_msg = "failed to close USRP:"; + goto bail; + } + } + goto unhandled; + + default: + goto unhandled; + } + return; + + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + unhandled: + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; +} + + +void +test_usrp_tx::open_usrp() +{ + pmt_t which_usrp = pmt_from_long(0); + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp)); + d_state = OPENING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Opening the USRP\n"; +} + +void +test_usrp_tx::close_usrp() +{ + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); + d_state = CLOSING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Closing the USRP\n"; +} + +void +test_usrp_tx::allocate_channel() +{ + long capacity = (long) 16e6; + d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_state = ALLOCATING_CHANNEL; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Requesting TX channel allocation\n"; +} + +void +test_usrp_tx::enter_transmitting() +{ + d_state = TRANSMITTING; + d_nsamples_xmitted = 0; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Transmitting...\n"; + + build_and_send_next_frame(); // fire off 4 to start pipeline + build_and_send_next_frame(); + build_and_send_next_frame(); + build_and_send_next_frame(); +} + +void +test_usrp_tx::build_and_send_next_frame() +{ + // allocate the uniform vector for the samples + // FIXME perhaps hold on to this between calls + +#if 1 + long nsamples_this_frame = + std::min(d_nsamples_to_send - d_nsamples_xmitted, + d_samples_per_frame); +#else + long nsamples_this_frame = d_samples_per_frame; +#endif + + if (nsamples_this_frame == 0){ + d_done_sending = true; + return; + } + + + size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q + pmt_t uvec = pmt_make_s16vector(nshorts, 0); + size_t ignore; + int16_t *samples = pmt_s16vector_writable_elements(uvec, ignore); + + // fill in the complex sinusoid + + for (int i = 0; i < nsamples_this_frame; i++){ + + if (1){ + gr_complex s; + d_nco.sincos(&s, 1, d_amplitude); + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + else { + gr_complex s(d_amplitude, d_amplitude); + + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + } + + pmt_t tx_properties = pmt_make_dict(); + + pmt_t timestamp = pmt_from_long(0xffffffff); // NOW + d_tx->send(s_cmd_xmit_raw_frame, + pmt_list5(pmt_from_long(d_nframes_xmitted), // invocation-handle + d_tx_chan, // channel + uvec, // the samples + timestamp, + tx_properties)); + + d_nsamples_xmitted += nsamples_this_frame; + d_nframes_xmitted++; + + if(verbose && 0) + std::cout << "[TEST_USRP_INBAND_TX] Transmitted frame\n"; +} + + +void +test_usrp_tx::handle_xmit_response(pmt_t handle) +{ + if (d_done_sending && + pmt_to_long(handle) == (d_nframes_xmitted - 1)){ + // We're done sending and have received all responses + enter_closing_channel(); + } + + build_and_send_next_frame(); +} + +void +test_usrp_tx::enter_closing_channel() +{ + d_state = CLOSING_CHANNEL; + + d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan)); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_tX] Deallocating TX channel\n"; +} + +REGISTER_MBLOCK_CLASS(test_usrp_tx); + + +// ---------------------------------------------------------------- + +int +main (int argc, char **argv) +{ + // handle any command line args here + + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_tx", PMT_F, &result); +} diff --git a/usrp/limbo/apps-inband/test_usrp_inband_underrun.cc b/usrp/limbo/apps-inband/test_usrp_inband_underrun.cc new file mode 100644 index 000000000..11babb048 --- /dev/null +++ b/usrp/limbo/apps-inband/test_usrp_inband_underrun.cc @@ -0,0 +1,674 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,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 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 <mblock/mblock.h> +#include <mblock/runtime.h> +#include <mblock/protocol_class.h> +#include <mblock/exception.h> +#include <mblock/msg_queue.h> +#include <mblock/message.h> +#include <mblock/msg_accepter.h> +#include <mblock/class_registry.h> +#include <pmt.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <iostream> +#include <ui_nco.h> + +// Include the symbols needed for communication with USRP server +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_tx.h> +#include <symbols_usrp_rx.h> + +static bool verbose = true; + +class test_usrp_inband_underrun : public mb_mblock +{ + + mb_port_sptr d_tx; // Ports connected to the USRP server + mb_port_sptr d_rx; + mb_port_sptr d_cs; + + pmt_t d_tx_chan; // Returned channel from TX allocation + pmt_t d_rx_chan; // Returned channel from RX allocation + + pmt_t d_which_usrp; // The USRP to use for the test + + long d_warm_msgs; // The number of messages to 'warm' the USRP + long d_warm_recvd; // The number of msgs received in the 'warm' state + + // Keep track of current state + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNELS, + WRITE_REGISTER, + READ_REGISTER, + TRANSMITTING, + CLOSING_CHANNELS, + CLOSING_USRP, + }; + state_t d_state; + + long d_nsamples_to_send; + long d_nsamples_xmitted; + long d_nframes_xmitted; + long d_samples_per_frame; + bool d_done_sending; + + // for generating sine wave output + ui_nco<float,float> d_nco; + double d_amplitude; + + long d_n_underruns; + + public: + test_usrp_inband_underrun(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_inband_underrun(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void opening_usrp(); + void allocating_channels(); + void write_register(); + void read_register(); + void closing_channels(); + void closing_usrp(); + void enter_receiving(); + void enter_transmitting(); + void build_and_send_ping(); + void build_and_send_next_frame(); + void handle_xmit_response(pmt_t handle); + void handle_recv_response(pmt_t dict); +}; + + +int +main (int argc, char **argv) +{ + // handle any command line args here + + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_inband_underrun", PMT_F, &result); +} + + +test_usrp_inband_underrun::test_usrp_inband_underrun(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_tx_chan(PMT_NIL), + d_rx_chan(PMT_NIL), + d_which_usrp(pmt_from_long(0)), + d_state(INIT), + d_nsamples_to_send((long) 27e6), + d_nsamples_xmitted(0), + d_nframes_xmitted(0), + d_samples_per_frame(d_nsamples_to_send), // full packet + + d_done_sending(false), + d_amplitude(16384), + d_n_underruns(0) +{ + + // A dictionary is used to pass parameters to the USRP + pmt_t usrp_dict = pmt_make_dict(); + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("inband_1rxhb_1tx.rbf")); + + // Set TX and RX interpolations + pmt_dict_set(usrp_dict, + pmt_intern("interp-tx"), + pmt_from_long(64)); + + pmt_dict_set(usrp_dict, + pmt_intern("decim-rx"), + pmt_from_long(128)); + + d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL); + d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + // Create an instance of USRP server and connect ports + define_component("server", "usrp_server", usrp_dict); + connect("self", "tx0", "server", "tx0"); + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + + // initialize NCO + double freq = 100e3; + int interp = 32; // 32 -> 4MS/s + double sample_rate = 128e6 / interp; + d_nco.set_freq(2*M_PI * freq/sample_rate); +} + +test_usrp_inband_underrun::~test_usrp_inband_underrun() +{ +} + +void +test_usrp_inband_underrun::initial_transition() +{ + opening_usrp(); +} + +// Handle message reads all incoming messages from USRP server which will be +// initialization and ping responses. We perform actions based on the current +// state and the event (ie, ping response) +void +test_usrp_inband_underrun::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + pmt_t port_id = msg->port_id(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + pmt_t dict = PMT_NIL; + std::string error_msg; + + // Check the recv sample responses for underruns and count + if(pmt_eq(event, s_response_recv_raw_samples)) { + handle = pmt_nth(0, data); + status = pmt_nth(1, data); + dict = pmt_nth(4, data); + + if(pmt_eq(status, PMT_T)) { + handle_recv_response(dict); + return; + } + else { + error_msg = "error while receiving samples:"; + goto bail; + } + } + + + // Dispatch based on state + switch(d_state) { + + //----------------------------- OPENING_USRP ----------------------------// + // We only expect a response from opening the USRP which should be succesful + // or failed. + case OPENING_USRP: + + if(pmt_eq(event, s_response_open)) { + + status = pmt_nth(1, data); // failed/succes + + if(pmt_eq(status, PMT_T)) { + allocating_channels(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + + } + + goto unhandled; // all other messages not handled in this state + + + //----------------------- ALLOCATING CHANNELS --------------------// + // When allocating channels, we need to wait for 2 responses from + // USRP server: one for TX and one for RX. Both are initialized to + // NIL so we know to continue to the next state once both are set. + case ALLOCATING_CHANNELS: + + // A TX allocation response + if(pmt_eq(event, s_response_allocate_channel) + && pmt_eq(d_tx->port_symbol(), port_id)) + { + status = pmt_nth(1, data); + + // If successful response, extract the channel + if(pmt_eq(status, PMT_T)) { + + d_tx_chan = pmt_nth(2, data); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_UNDERRUN] Received TX allocation" + << " on channel " << d_tx_chan << std::endl; + + // If the RX has also been allocated already, we can continue + if(!pmt_eqv(d_rx_chan, PMT_NIL)) { + enter_receiving(); + enter_transmitting(); + } + + return; + } + else { // TX allocation failed + error_msg = "failed to allocate TX channel:"; + goto bail; + } + } + + // A RX allocation response + if(pmt_eq(event, s_response_allocate_channel) + && pmt_eq(d_rx->port_symbol(), port_id)) + { + status = pmt_nth(1, data); + + // If successful response, extract the channel + if(pmt_eq(status, PMT_T)) { + + d_rx_chan = pmt_nth(2, data); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_UNDERRUN] Received RX allocation" + << " on channel " << d_rx_chan << std::endl; + + // If the TX has also been allocated already, we can continue + if(!pmt_eqv(d_tx_chan, PMT_NIL)) { + enter_receiving(); + enter_transmitting(); + } + + return; + } + else { // RX allocation failed + error_msg = "failed to allocate RX channel:"; + goto bail; + } + } + + goto unhandled; + + case WRITE_REGISTER: + goto unhandled; + + case READ_REGISTER: + goto unhandled; + + //-------------------------- TRANSMITTING ----------------------------// + // In the transmit state we count the number of underruns received and + // ballpark the number with an expected count (something >1 for starters) + case TRANSMITTING: + + // Check that the transmits are OK + if (pmt_eq(event, s_response_xmit_raw_frame)){ + handle = pmt_nth(0, data); + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + handle_xmit_response(handle); + return; + } + else { + error_msg = "bad response-xmit-raw-frame:"; + goto bail; + } + } + + goto unhandled; + + //------------------------- CLOSING CHANNELS ----------------------------// + // Check deallocation responses, once the TX and RX channels are both + // deallocated then we close the USRP. + case CLOSING_CHANNELS: + + if (pmt_eq(event, s_response_deallocate_channel) + && pmt_eq(d_tx->port_symbol(), port_id)) + { + status = pmt_nth(1, data); + + // If successful, set the port to NIL + if(pmt_eq(status, PMT_T)) { + d_tx_chan = PMT_NIL; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_UNDERRUN] Received TX deallocation\n"; + + // If the RX is also deallocated, we can close the USRP + if(pmt_eq(d_rx_chan, PMT_NIL)) + closing_usrp(); + + return; + + } else { + + error_msg = "failed to deallocate TX channel:"; + goto bail; + + } + } + + if (pmt_eq(event, s_response_deallocate_channel) + && pmt_eq(d_rx->port_symbol(), port_id)) + { + status = pmt_nth(1, data); + + // If successful, set the port to NIL + if(pmt_eq(status, PMT_T)) { + d_rx_chan = PMT_NIL; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_UNDERRUN] Received RX deallocation\n"; + + // If the TX is also deallocated, we can close the USRP + if(pmt_eq(d_tx_chan, PMT_NIL)) + closing_usrp(); + + return; + + } else { + + error_msg = "failed to deallocate RX channel:"; + goto bail; + + } + } + + goto unhandled; + + //--------------------------- CLOSING USRP ------------------------------// + // Once we have received a successful USRP close response, we shutdown all + // mblocks and exit. + case CLOSING_USRP: + + if (pmt_eq(event, s_response_close)) { + + status = pmt_nth(1, data); + + if(pmt_eq(status, PMT_T)) { + + if(verbose) + std::cout << "[TEST_USRP_INBAND_UNDERRUN] Successfully closed USRP\n"; + + std::cout << "\nUnderruns: " << d_n_underruns << std::endl; + fflush(stdout); + + shutdown_all(PMT_T); + return; + + } else { + + error_msg = "failed to close USRP:"; + goto bail; + } + } + + goto unhandled; + + case INIT: + goto unhandled; + + } + + // An error occured, print it, and shutdown all m-blocks + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + // Received an unhandled message for a specific state + unhandled: + if(verbose && !pmt_eq(event, pmt_intern("%shutdown"))) + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; + +} + + +// Sends a command to USRP server to open up a connection to the +// specified USRP, which is defaulted to USRP 0 on the system +void +test_usrp_inband_underrun::opening_usrp() +{ + + if(verbose) + std::cout << "[TEST_USRP_INBAND_UNDERRUN] Opening USRP " + << d_which_usrp << std::endl; + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, d_which_usrp)); + d_state = OPENING_USRP; +} + +// RX and TX channels must be allocated so that the USRP server can +// properly share bandwidth across multiple USRPs. No commands will be +// successful to the USRP through the USRP server on the TX or RX channels until +// a bandwidth allocation has been received. +void +test_usrp_inband_underrun::allocating_channels() +{ + d_state = ALLOCATING_CHANNELS; + + long capacity = (long) 16e6; + d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); +} + +// After allocating the channels, a write register command will be sent to the +// USRP. +void +test_usrp_inband_underrun::write_register() +{ + d_state = WRITE_REGISTER; + + long reg = 0; + + d_tx->send(s_cmd_to_control_channel, // C/S packet + pmt_list2(PMT_NIL, // invoc handle + pmt_list1( + pmt_list2(s_op_write_reg, + pmt_list2( + pmt_from_long(reg), + pmt_from_long(0xbeef)))))); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_REGISTERS] Writing 0xbeef to " + << reg << std::endl; + + read_register(); // immediately transition to read the register +} + +// Temporary: for testing pings +void +test_usrp_inband_underrun::build_and_send_ping() +{ + + d_tx->send(s_cmd_to_control_channel, + pmt_list2(PMT_NIL, pmt_list1(pmt_list2(s_op_ping_fixed, + pmt_list2(pmt_from_long(0), + pmt_from_long(0)))))); + + std::cout << "[TEST_USRP_INBAND_UNDERRUN] Ping sent" << std::endl; +} + +// After writing to the register, we want to read the value back and ensure that +// it is the same value that we wrote. +void +test_usrp_inband_underrun::read_register() +{ + d_state = READ_REGISTER; + + long reg = 9; + + d_tx->send(s_cmd_to_control_channel, // C/S packet + pmt_list2(PMT_NIL, // invoc handle + pmt_list1( + pmt_list2(s_op_read_reg, + pmt_list2( + pmt_from_long(0), // rid + pmt_from_long(reg)))))); + if(verbose) + std::cout << "[TEST_USRP_INBAND_UNDERRUN] Reading from register " + << reg << std::endl; +} + +// Used to enter the receiving state +void +test_usrp_inband_underrun::enter_receiving() +{ + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_F, + d_rx_chan)); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_UNDERRUN] Started RX sample stream\n"; +} + +void +test_usrp_inband_underrun::enter_transmitting() +{ + d_state = TRANSMITTING; + d_nsamples_xmitted = 0; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_UNDERRUN] Entering transmit state...\n"; + + build_and_send_next_frame(); // fire off 4 to start pipeline + build_and_send_next_frame(); + build_and_send_next_frame(); + build_and_send_next_frame(); +} + +void +test_usrp_inband_underrun::build_and_send_next_frame() +{ + + long nsamples_this_frame = + std::min(d_nsamples_to_send - d_nsamples_xmitted, + d_samples_per_frame); + + if (nsamples_this_frame == 0){ + d_done_sending = true; + return; + } + + size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q + pmt_t uvec = pmt_make_s16vector(nshorts, 0); + size_t ignore; + int16_t *samples = pmt_s16vector_writable_elements(uvec, ignore); + + // fill in the complex sinusoid + + for (int i = 0; i < nsamples_this_frame; i++){ + + if (1){ + gr_complex s; + d_nco.sincos(&s, 1, d_amplitude); + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + else { + gr_complex s(d_amplitude, d_amplitude); + + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + } + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Transmitting frame...\n"; + + pmt_t timestamp = pmt_from_long(0xffffffff); // NOW + d_tx->send(s_cmd_xmit_raw_frame, + pmt_list4(pmt_from_long(d_nframes_xmitted), // invocation-handle + d_tx_chan, // channel + uvec, // the samples + timestamp)); + + d_nsamples_xmitted += nsamples_this_frame; + d_nframes_xmitted++; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Transmitted frame\n"; + +} + +void +test_usrp_inband_underrun::handle_xmit_response(pmt_t handle) +{ + if (d_done_sending && + pmt_to_long(handle) == (d_nframes_xmitted - 1)){ + // We're done sending and have received all responses + closing_channels(); + return; + } + + build_and_send_next_frame(); +} + +void +test_usrp_inband_underrun::handle_recv_response(pmt_t dict) +{ + if(!pmt_is_dict(dict)) { + std::cout << "[TEST_USRP_INBAND_UNDERRUN] Recv samples dictionary is improper\n"; + return; + } + + // Read the TX interpolations + if(pmt_t underrun = pmt_dict_ref(dict, + pmt_intern("underrun"), + PMT_NIL)) { + if(pmt_eqv(underrun, PMT_T)) { + d_n_underruns++; + + if(verbose && 0) + std::cout << "[TEST_USRP_INBAND_UNDERRUN] Underrun\n"; + } + else { + if(verbose && 0) + std::cout << "[TEST_USRP_INBAND_UNDERRUN] No underrun\n" << underrun <<std::endl; + } + } else { + + if(verbose && 0) + std::cout << "[TEST_USRP_INBAND_UNDERRUN] No underrun\n"; + } + +} + +void +test_usrp_inband_underrun::closing_channels() +{ + d_state = CLOSING_CHANNELS; + + d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan)); + d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan)); +} + +void +test_usrp_inband_underrun::closing_usrp() +{ + d_state = CLOSING_USRP; + + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); +} + +REGISTER_MBLOCK_CLASS(test_usrp_inband_underrun); diff --git a/usrp/limbo/apps-inband/ui_nco.h b/usrp/limbo/apps-inband/ui_nco.h new file mode 100644 index 000000000..e6d7814ab --- /dev/null +++ b/usrp/limbo/apps-inband/ui_nco.h @@ -0,0 +1,202 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002 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_UI_NCO_H +#define INCLUDED_UI_NCO_H + + +#include <vector> +#include <ui_sincos.h> +#include <cmath> + +#include <complex> +typedef std::complex<float> gr_complex; + + +/*! + * \brief base class template for Numerically Controlled Oscillator (NCO) + */ + + +//FIXME Eventually generalize this to fixed point + +template<class o_type, class i_type> +class ui_nco { +public: + ui_nco () : phase (0), phase_inc(0) {} + + virtual ~ui_nco () {} + + // radians + void set_phase (double angle) { + phase = angle; + } + + void adjust_phase (double delta_phase) { + phase += delta_phase; + } + + + // angle_rate is in radians / step + void set_freq (double angle_rate){ + phase_inc = angle_rate; + } + + // angle_rate is a delta in radians / step + void adjust_freq (double delta_angle_rate) + { + phase_inc += delta_angle_rate; + } + + // increment current phase angle + + void step () + { + phase += phase_inc; + if (fabs (phase) > M_PI){ + + while (phase > M_PI) + phase -= 2*M_PI; + + while (phase < -M_PI) + phase += 2*M_PI; + } + } + + void step (int n) + { + phase += phase_inc * n; + if (fabs (phase) > M_PI){ + + while (phase > M_PI) + phase -= 2*M_PI; + + while (phase < -M_PI) + phase += 2*M_PI; + } + } + + // units are radians / step + double get_phase () const { return phase; } + double get_freq () const { return phase_inc; } + + // compute sin and cos for current phase angle + void sincos (float *sinx, float *cosx) const; + + // compute cos or sin for current phase angle + float cos () const { return std::cos (phase); } + float sin () const { return std::sin (phase); } + + // compute a block at a time + void sin (float *output, int noutput_items, double ampl = 1.0); + void cos (float *output, int noutput_items, double ampl = 1.0); + void sincos (gr_complex *output, int noutput_items, double ampl = 1.0); + void sin (short *output, int noutput_items, double ampl = 1.0); + void cos (short *output, int noutput_items, double ampl = 1.0); + void sin (int *output, int noutput_items, double ampl = 1.0); + void cos (int *output, int noutput_items, double ampl = 1.0); + +protected: + double phase; + double phase_inc; +}; + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::sincos (float *sinx, float *cosx) const +{ + ui_sincosf (phase, sinx, cosx); +} + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::sin (float *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (float)(sin () * ampl); + step (); + } +} + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::cos (float *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (float)(cos () * ampl); + step (); + } +} + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::sin (short *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (short)(sin() * ampl); + step (); + } +} + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::cos (short *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (short)(cos () * ampl); + step (); + } +} + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::sin (int *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (int)(sin () * ampl); + step (); + } +} + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::cos (int *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (int)(cos () * ampl); + step (); + } +} + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::sincos (gr_complex *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + float cosx, sinx; + sincos (&sinx, &cosx); + output[i] = gr_complex(cosx * ampl, sinx * ampl); + step (); + } +} + +#endif /* INCLUDED_UI_NCO_H */ + diff --git a/usrp/limbo/apps-inband/ui_sincos.c b/usrp/limbo/apps-inband/ui_sincos.c new file mode 100644 index 000000000..27841f010 --- /dev/null +++ b/usrp/limbo/apps-inband/ui_sincos.c @@ -0,0 +1,81 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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 + +#define _GNU_SOURCE // ask for GNU extensions if available + +#include "ui_sincos.h" +#include <math.h> + +// ---------------------------------------------------------------- + +#if defined (HAVE_SINCOS) + +void +ui_sincos (double x, double *sinx, double *cosx) +{ + sincos (x, sinx, cosx); +} + +#else + +void +ui_sincos (double x, double *sinx, double *cosx) +{ + *sinx = sin (x); + *cosx = cos (x); +} + +#endif + +// ---------------------------------------------------------------- + +#if defined (HAVE_SINCOSF) + +void +ui_sincosf (float x, float *sinx, float *cosx) +{ + sincosf (x, sinx, cosx); +} + +#elif defined (HAVE_SINF) && defined (HAVE_COSF) + +void +ui_sincosf (float x, float *sinx, float *cosx) +{ + *sinx = sinf (x); + *cosx = cosf (x); +} + +#else + +void +ui_sincosf (float x, float *sinx, float *cosx) +{ + *sinx = sin (x); + *cosx = cos (x); +} + +#endif diff --git a/usrp/limbo/apps-inband/ui_sincos.h b/usrp/limbo/apps-inband/ui_sincos.h new file mode 100644 index 000000000..d2d6e4b76 --- /dev/null +++ b/usrp/limbo/apps-inband/ui_sincos.h @@ -0,0 +1,39 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2004 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_UI_SINCOS_H +#define INCLUDED_UI_SINCOS_H + +#ifdef __cplusplus +extern "C" { +#endif + +// compute sine and cosine at the same time + +void ui_sincos (double x, double *sin, double *cos); +void ui_sincosf (float x, float *sin, float *cos); + +#ifdef __cplusplus +}; +#endif + +#endif /* INCLUDED_UI_SINCOS_H */ |