diff options
author | eb | 2007-09-05 01:43:43 +0000 |
---|---|---|
committer | eb | 2007-09-05 01:43:43 +0000 |
commit | b644e266dd6f5f4b6cdac126477b61debee89e26 (patch) | |
tree | ea2df43c9376b6125ae9b9bba070a3a901fc95f1 /usrp/host/apps | |
parent | 9ccd0ffb7846f7d8d82e9214bca9c2d11311b649 (diff) | |
download | gnuradio-b644e266dd6f5f4b6cdac126477b61debee89e26.tar.gz gnuradio-b644e266dd6f5f4b6cdac126477b61debee89e26.tar.bz2 gnuradio-b644e266dd6f5f4b6cdac126477b61debee89e26.zip |
Merged features/inband-usb r5224:6306 into trunk.
This is work-in-progress on inband signaling for the USRP1.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6307 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'usrp/host/apps')
-rw-r--r-- | usrp/host/apps/Makefile.am | 39 | ||||
-rw-r--r-- | usrp/host/apps/read_packets.cc | 103 | ||||
-rw-r--r-- | usrp/host/apps/test_usrp_inband_cs.cc | 478 | ||||
-rw-r--r-- | usrp/host/apps/test_usrp_inband_ping.cc | 376 | ||||
-rw-r--r-- | usrp/host/apps/test_usrp_inband_registers.cc | 436 | ||||
-rw-r--r-- | usrp/host/apps/test_usrp_inband_rx.cc | 356 | ||||
-rw-r--r-- | usrp/host/apps/test_usrp_inband_timestamps.cc | 508 | ||||
-rw-r--r-- | usrp/host/apps/test_usrp_inband_tx.cc | 409 | ||||
-rw-r--r-- | usrp/host/apps/ui_nco.h | 202 | ||||
-rw-r--r-- | usrp/host/apps/ui_sincos.c | 81 | ||||
-rw-r--r-- | usrp/host/apps/ui_sincos.h | 39 |
11 files changed, 3024 insertions, 3 deletions
diff --git a/usrp/host/apps/Makefile.am b/usrp/host/apps/Makefile.am index f920ce59a..e0f5b8cf4 100644 --- a/usrp/host/apps/Makefile.am +++ b/usrp/host/apps/Makefile.am @@ -21,7 +21,10 @@ include $(top_srcdir)/Makefile.common -INCLUDES = $(USRP_INCLUDES) $(BOOST_CFLAGS) +INCLUDES = \ + $(DEFINES) $(OMNITHREAD_INCLUDES) $(PMT_INCLUDES) $(MBLOCK_INCLUDES) \ + $(USRP_INCLUDES) $(BOOST_CFLAGS) $(CPPUNIT_INCLUDES) + bin_PROGRAMS = \ usrper \ @@ -29,11 +32,20 @@ bin_PROGRAMS = \ noinst_PROGRAMS = \ check_order_quickly \ + test_usrp_inband_cs \ + test_usrp_inband_ping \ + test_usrp_inband_registers \ + test_usrp_inband_rx \ + test_usrp_inband_tx \ + test_usrp_inband_timestamps \ test_usrp_standard_rx \ - test_usrp_standard_tx + test_usrp_standard_tx \ + read_packets noinst_HEADERS = \ - time_stuff.h + time_stuff.h \ + ui_nco.h \ + ui_sincos.h noinst_PYTHON = \ burn-db-eeprom \ @@ -53,3 +65,24 @@ usrper_LDADD = $(USRP_LA) usrp_cal_dc_offset_SOURCES = usrp_cal_dc_offset.cc usrp_cal_dc_offset_LDADD = $(USRP_LA) + +test_usrp_inband_cs_SOURCES = test_usrp_inband_cs.cc time_stuff.c ui_sincos.c +test_usrp_inband_cs_LDADD = $(USRP_LA) + +test_usrp_inband_ping_SOURCES = test_usrp_inband_ping.cc time_stuff.c +test_usrp_inband_ping_LDADD = $(USRP_LA) + +test_usrp_inband_tx_SOURCES = test_usrp_inband_tx.cc time_stuff.c ui_sincos.c +test_usrp_inband_tx_LDADD = $(USRP_LA) + +test_usrp_inband_timestamps_SOURCES = test_usrp_inband_timestamps.cc time_stuff.c ui_sincos.c +test_usrp_inband_timestamps_LDADD = $(USRP_LA) + +test_usrp_inband_registers_SOURCES = test_usrp_inband_registers.cc time_stuff.c ui_sincos.c +test_usrp_inband_registers_LDADD = $(USRP_LA) + +test_usrp_inband_rx_SOURCES = test_usrp_inband_rx.cc time_stuff.c ui_sincos.c +test_usrp_inband_rx_LDADD = $(USRP_LA) + +read_packets_SOURCES = read_packets.cc +read_packets_LDADD = $(USRP_LA) diff --git a/usrp/host/apps/read_packets.cc b/usrp/host/apps/read_packets.cc new file mode 100644 index 000000000..92d8baf0d --- /dev/null +++ b/usrp/host/apps/read_packets.cc @@ -0,0 +1,103 @@ +/* -*- 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 <iostream> +#include <usrp_inband_usb_packet.h> +#include <mb_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"); + + 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/host/apps/test_usrp_inband_cs.cc b/usrp/host/apps/test_usrp_inband_cs.cc new file mode 100644 index 000000000..1d70341fe --- /dev/null +++ b/usrp/host/apps/test_usrp_inband_cs.cc @@ -0,0 +1,478 @@ +/* -*- 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 <mb_mblock.h> +#include <mb_runtime.h> +#include <mb_runtime_nop.h> // QA only +#include <mb_protocol_class.h> +#include <mb_exception.h> +#include <mb_msg_queue.h> +#include <mb_message.h> +#include <mb_mblock_impl.h> +#include <mb_msg_accepter.h> +#include <mb_class_registry.h> +#include <pmt.h> +#include <ui_nco.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <iostream> + +#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 = false; + +class test_usrp_cs : 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_cs(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_cs(); + 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_cs::test_usrp_cs(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 * 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_CS] 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 = 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); + } + + // 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("interp-rx"), + pmt_from_long(16)); + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("boe.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); + + // FIXME need to somehow set the interp rate in the USRP. + // for now, we'll have the low-level code hardwire it. +} + +test_usrp_cs::~test_usrp_cs() +{ +} + +void +test_usrp_cs::initial_transition() +{ + open_usrp(); +} + +void +test_usrp_cs::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_CS] 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_CS] 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; + } + } + 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) + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; +} + + +void +test_usrp_cs::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_cs::close_usrp() +{ + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); + d_state = CLOSING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_CS] Closing USRP\n"; +} + +void +test_usrp_cs::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_cs::enter_receiving() +{ + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_F, + d_rx_chan)); +} + +void +test_usrp_cs::enter_transmitting() +{ + d_state = TRANSMITTING; + d_nsamples_xmitted = 0; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_CS] Beginning transmission\n"; + + sleep(1); + +// build_and_send_next_frame(); // fire off 4 to start pipeline + + build_and_send_ping(); + build_and_send_ping(); + build_and_send_ping(); + +} + +void +test_usrp_cs::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; +} + +void +test_usrp_cs::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_writeable_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 = 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_CS] Transmitted frame\n"; +} + + +void +test_usrp_cs::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_cs::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_CS] Closing channel\n"; +} + +REGISTER_MBLOCK_CLASS(test_usrp_cs); + + +// ---------------------------------------------------------------- + +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_cs", PMT_F, &result); +} diff --git a/usrp/host/apps/test_usrp_inband_ping.cc b/usrp/host/apps/test_usrp_inband_ping.cc new file mode 100644 index 000000000..a68f49272 --- /dev/null +++ b/usrp/host/apps/test_usrp_inband_ping.cc @@ -0,0 +1,376 @@ +/* -*- 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 <mb_mblock.h> +#include <mb_runtime.h> +#include <mb_runtime_nop.h> // QA only +#include <mb_protocol_class.h> +#include <mb_exception.h> +#include <mb_msg_queue.h> +#include <mb_message.h> +#include <mb_mblock_impl.h> +#include <mb_msg_accepter.h> +#include <mb_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("interp-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/host/apps/test_usrp_inband_registers.cc b/usrp/host/apps/test_usrp_inband_registers.cc new file mode 100644 index 000000000..922b6215d --- /dev/null +++ b/usrp/host/apps/test_usrp_inband_registers.cc @@ -0,0 +1,436 @@ +/* -*- 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 <mb_mblock.h> +#include <mb_runtime.h> +#include <mb_runtime_nop.h> // QA only +#include <mb_protocol_class.h> +#include <mb_exception.h> +#include <mb_msg_queue.h> +#include <mb_message.h> +#include <mb_mblock_impl.h> +#include <mb_msg_accepter.h> +#include <mb_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("boe2.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("interp-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/host/apps/test_usrp_inband_rx.cc b/usrp/host/apps/test_usrp_inband_rx.cc new file mode 100644 index 000000000..4820c2d4e --- /dev/null +++ b/usrp/host/apps/test_usrp_inband_rx.cc @@ -0,0 +1,356 @@ +/* -*- 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 <mb_mblock.h> +#include <mb_runtime.h> +#include <mb_runtime_nop.h> // QA only +#include <mb_protocol_class.h> +#include <mb_exception.h> +#include <mb_msg_queue.h> +#include <mb_message.h> +#include <mb_mblock_impl.h> +#include <mb_msg_accepter.h> +#include <mb_class_registry.h> +#include <pmt.h> +#include <stdio.h> +#include <string.h> +#include <iostream> +#include <fstream> + +// Signal set for the USRP server +static pmt_t s_cmd_allocate_channel = pmt_intern("cmd-allocate-channel"); +static pmt_t s_cmd_close = pmt_intern("cmd-close"); +static pmt_t s_cmd_deallocate_channel = pmt_intern("cmd-deallocate-channel"); +static pmt_t s_cmd_open = pmt_intern("cmd-open"); +static pmt_t s_cmd_start_recv_raw_samples = pmt_intern("cmd-start-recv-raw-samples"); +static pmt_t s_cmd_stop_recv_raw_samples = pmt_intern("cmd-stop-recv-raw-samples"); +static pmt_t s_cmd_to_control_channel = pmt_intern("cmd-to-control-channel"); +static pmt_t s_cmd_xmit_raw_frame = pmt_intern("cmd-xmit-raw-frame"); +static pmt_t s_cmd_max_capacity = pmt_intern("cmd-max-capacity"); +static pmt_t s_cmd_ntx_chan = pmt_intern("cmd-ntx-chan"); +static pmt_t s_cmd_nrx_chan = pmt_intern("cmd-nrx-chan"); +static pmt_t s_cmd_current_capacity_allocation = pmt_intern("cmd-current-capacity-allocation"); +static pmt_t s_response_allocate_channel = pmt_intern("response-allocate-channel"); +static pmt_t s_response_close = pmt_intern("response-close"); +static pmt_t s_response_deallocate_channel = pmt_intern("response-deallocate-channel"); +static pmt_t s_response_from_control_channel = pmt_intern("response-from-control-channel"); +static pmt_t s_response_open = pmt_intern("response-open"); +static pmt_t s_response_recv_raw_samples = pmt_intern("response-recv-raw-samples"); +static pmt_t s_response_xmit_raw_frame = pmt_intern("response-xmit-raw-frame"); +static pmt_t s_response_max_capacity = pmt_intern("response-max-capacity"); +static pmt_t s_response_ntx_chan = pmt_intern("response-ntx-chan"); +static pmt_t s_response_nrx_chan = pmt_intern("response-nrx-chan"); +static pmt_t s_response_current_capacity_allocation = pmt_intern("response-current-capacity-allocation"); + +static bool verbose = false; + +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 + + bool d_disk_write; + + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNEL, + RECEIVING, + CLOSING_CHANNEL, + CLOSING_USRP, + }; + + state_t d_state; + + std::ofstream d_ofile; + + 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_disk_write(false) +{ + + 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 = true; + bool fake_usrp_p = false; + + d_disk_write = true; + + // Test the TX side + + // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP + 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("tmac6.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("interp-rx"), + pmt_from_long(16)); + + define_component("server", "usrp_server", usrp_dict); + + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + + if(d_disk_write) + d_ofile.open("pdump_rx.dat",std::ios::binary|std::ios::out); +} + +test_usrp_rx::~test_usrp_rx() +{ + if(d_disk_write) + d_ofile.close(); +} + +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){ + 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_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; + + 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; + + 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_rx: 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; +} + +void +test_usrp_rx::close_usrp() +{ + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); + d_state = CLOSING_USRP; +} + +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; +} + +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)); +} + +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 properties = pmt_nth(4, data); + + size_t n_bytes; + + const char *samples = (const char *) pmt_uniform_vector_elements(v_samples, n_bytes); + + if(d_disk_write) + d_ofile.write(samples, n_bytes); + + if(verbose) + std::cout << "."; + + if (pmt_is_dict(properties)) { + // Read the RSSI + if(pmt_t rssi = pmt_dict_ref(properties, + pmt_intern("rssi"), + PMT_NIL)) { + if(!pmt_eqv(rssi, PMT_NIL)) + std::cout << "RSSI: " << rssi << std::endl; + } + } + + +} + +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)); +} + +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/host/apps/test_usrp_inband_timestamps.cc b/usrp/host/apps/test_usrp_inband_timestamps.cc new file mode 100644 index 000000000..d48c2a789 --- /dev/null +++ b/usrp/host/apps/test_usrp_inband_timestamps.cc @@ -0,0 +1,508 @@ +/* -*- 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 <mb_mblock.h> +#include <mb_runtime.h> +#include <mb_runtime_nop.h> // QA only +#include <mb_protocol_class.h> +#include <mb_exception.h> +#include <mb_msg_queue.h> +#include <mb_message.h> +#include <mb_mblock_impl.h> +#include <mb_msg_accepter.h> +#include <mb_class_registry.h> +#include <pmt.h> +#include <ui_nco.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <iostream> + +#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("interp-rx"), + pmt_from_long(16)); + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("tmac5.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_writeable_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/host/apps/test_usrp_inband_tx.cc b/usrp/host/apps/test_usrp_inband_tx.cc new file mode 100644 index 000000000..18d36213b --- /dev/null +++ b/usrp/host/apps/test_usrp_inband_tx.cc @@ -0,0 +1,409 @@ +/* -*- 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 <mb_mblock.h> +#include <mb_runtime.h> +#include <mb_runtime_nop.h> // QA only +#include <mb_protocol_class.h> +#include <mb_exception.h> +#include <mb_msg_queue.h> +#include <mb_message.h> +#include <mb_mblock_impl.h> +#include <mb_msg_accepter.h> +#include <mb_class_registry.h> +#include <pmt.h> +#include <ui_nco.h> +#include <stdio.h> +#include <string.h> +#include <iostream> + +#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 = false; + +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) 40e6), + d_nsamples_xmitted(0), + d_nframes_xmitted(0), + //d_samples_per_frame((long)(126)), + //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) +{ + // 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("boe3.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("interp-rx"), + pmt_from_long(16)); + + 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; +} + +void +test_usrp_tx::close_usrp() +{ + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); + d_state = CLOSING_USRP; +} + +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; +} + +void +test_usrp_tx::enter_transmitting() +{ + d_state = TRANSMITTING; + d_nsamples_xmitted = 0; + + // FIXME: carrier sense hack +// 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(1), +// pmt_from_long(0)))))); + + 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_writeable_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 = 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_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)); +} + +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/host/apps/ui_nco.h b/usrp/host/apps/ui_nco.h new file mode 100644 index 000000000..e6d7814ab --- /dev/null +++ b/usrp/host/apps/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/host/apps/ui_sincos.c b/usrp/host/apps/ui_sincos.c new file mode 100644 index 000000000..36ca89c7d --- /dev/null +++ b/usrp/host/apps/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/host/apps/ui_sincos.h b/usrp/host/apps/ui_sincos.h new file mode 100644 index 000000000..d2d6e4b76 --- /dev/null +++ b/usrp/host/apps/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 */ |