diff options
64 files changed, 2755 insertions, 3612 deletions
diff --git a/mblock/src/lib/mb_message.cc b/mblock/src/lib/mb_message.cc index 0bce455ce..ce98a931e 100644 --- a/mblock/src/lib/mb_message.cc +++ b/mblock/src/lib/mb_message.cc @@ -26,12 +26,13 @@ #include <stdio.h> #include <pmt_pool.h> -static const int CACHE_LINE_SIZE = 64; // good guess - - +static const int CACHE_LINE_SIZE = 64; // good guess +static const int MAX_MESSAGES = 1024; // KLUDGE max number of messages in sys + // 0 -> no limit #if MB_MESSAGE_LOCAL_ALLOCATOR -static pmt_pool global_msg_pool(sizeof(mb_message), CACHE_LINE_SIZE); +static pmt_pool +global_msg_pool(sizeof(mb_message), CACHE_LINE_SIZE, 16*1024, MAX_MESSAGES); void * mb_message::operator new(size_t size) diff --git a/pmt/src/lib/pmt.cc b/pmt/src/lib/pmt.cc index a141224b3..537b7a05a 100644 --- a/pmt/src/lib/pmt.cc +++ b/pmt/src/lib/pmt.cc @@ -963,6 +963,12 @@ pmt_list6(pmt_t x1, pmt_t x2, pmt_t x3, pmt_t x4, pmt_t x5, pmt_t x6) } pmt_t +pmt_list_add(pmt_t list, pmt_t item) +{ + return pmt_reverse(pmt_cons(item, pmt_reverse(list))); +} + +pmt_t pmt_caar(pmt_t pair) { return (pmt_car(pmt_car(pair))); diff --git a/pmt/src/lib/pmt.h b/pmt/src/lib/pmt.h index fa368a6a1..970dd6c7d 100644 --- a/pmt/src/lib/pmt.h +++ b/pmt/src/lib/pmt.h @@ -609,6 +609,11 @@ pmt_t pmt_list5(pmt_t x1, pmt_t x2, pmt_t x3, pmt_t x4, pmt_t x5); */ pmt_t pmt_list6(pmt_t x1, pmt_t x2, pmt_t x3, pmt_t x4, pmt_t x5, pmt_t x6); +/*! + * \brief Return \p list with \p item added to it. + */ +pmt_t pmt_list_add(pmt_t list, pmt_t item); + /* * ------------------------------------------------------------------------ diff --git a/pmt/src/lib/pmt_pool.cc b/pmt/src/lib/pmt_pool.cc index 8f1329a7e..05d9c005b 100644 --- a/pmt/src/lib/pmt_pool.cc +++ b/pmt/src/lib/pmt_pool.cc @@ -32,10 +32,13 @@ ROUNDUP(size_t x, size_t stride) return ((((x) + (stride) - 1)/(stride)) * (stride)); } -pmt_pool::pmt_pool(size_t itemsize, size_t alignment, size_t allocation_size) - : d_itemsize(ROUNDUP(itemsize, alignment)), +pmt_pool::pmt_pool(size_t itemsize, size_t alignment, + size_t allocation_size, size_t max_items) + : d_cond(&d_mutex), + d_itemsize(ROUNDUP(itemsize, alignment)), d_alignment(alignment), d_allocation_size(std::max(allocation_size, 16 * itemsize)), + d_max_items(max_items), d_n_items(0), d_freelist(0) { } @@ -53,9 +56,15 @@ pmt_pool::malloc() omni_mutex_lock l(d_mutex); item *p; + if (d_max_items != 0){ + while (d_n_items >= d_max_items) + d_cond.wait(); + } + if (d_freelist){ // got something? p = d_freelist; d_freelist = p->d_next; + d_n_items++; return p; } @@ -79,6 +88,7 @@ pmt_pool::malloc() // now return the first one p = d_freelist; d_freelist = p->d_next; + d_n_items++; return p; } @@ -93,4 +103,7 @@ pmt_pool::free(void *foo) item *p = (item *) foo; p->d_next = d_freelist; d_freelist = p; + d_n_items--; + if (d_max_items != 0) + d_cond.signal(); } diff --git a/pmt/src/lib/pmt_pool.h b/pmt/src/lib/pmt_pool.h index ac0c07bb6..42276a14f 100644 --- a/pmt/src/lib/pmt_pool.h +++ b/pmt/src/lib/pmt_pool.h @@ -38,10 +38,13 @@ class pmt_pool { }; omni_mutex d_mutex; + omni_condition d_cond; size_t d_itemsize; size_t d_alignment; size_t d_allocation_size; + size_t d_max_items; + size_t d_n_items; item *d_freelist; std::vector<char *> d_allocations; @@ -50,8 +53,11 @@ public: * \param itemsize size in bytes of the items to be allocated. * \param alignment alignment in bytes of all objects to be allocated (must be power-of-2). * \param allocation_size number of bytes to allocate at a time from the underlying allocator. + * \param max_items is the maximum number of items to allocate. If this number is exceeded, + * the allocate blocks. 0 implies no limit. */ - pmt_pool(size_t itemsize, size_t alignment = 16, size_t allocation_size = 4096); + pmt_pool(size_t itemsize, size_t alignment = 16, + size_t allocation_size = 4096, size_t max_items = 0); ~pmt_pool(); void *malloc(); diff --git a/pmt/src/lib/qa_pmt_prims.cc b/pmt/src/lib/qa_pmt_prims.cc index 26b3e26d3..57db4a1a9 100644 --- a/pmt/src/lib/qa_pmt_prims.cc +++ b/pmt/src/lib/qa_pmt_prims.cc @@ -301,6 +301,20 @@ qa_pmt_prims::test_io() CPPUNIT_ASSERT_EQUAL(std::string("k0"), pmt_write_string(k0)); } +void +qa_pmt_prims::test_lists() +{ + pmt_t s0 = pmt_intern("s0"); + pmt_t s1 = pmt_intern("s1"); + pmt_t s2 = pmt_intern("s2"); + pmt_t s3 = pmt_intern("s3"); + + pmt_t l1 = pmt_list4(s0, s1, s2, s3); + pmt_t l2 = pmt_list3(s0, s1, s2); + pmt_t l3 = pmt_list_add(l2, s3); + CPPUNIT_ASSERT(pmt_equal(l1, l3)); +} + // ------------------------------------------------------------------------ // class foo is used in test_any below. diff --git a/pmt/src/lib/qa_pmt_prims.h b/pmt/src/lib/qa_pmt_prims.h index be49a30e4..919fc2dca 100644 --- a/pmt/src/lib/qa_pmt_prims.h +++ b/pmt/src/lib/qa_pmt_prims.h @@ -40,6 +40,7 @@ class qa_pmt_prims : public CppUnit::TestCase { CPPUNIT_TEST(test_dict); CPPUNIT_TEST(test_any); CPPUNIT_TEST(test_io); + CPPUNIT_TEST(test_lists); CPPUNIT_TEST(test_serialize); CPPUNIT_TEST_SUITE_END(); @@ -56,6 +57,7 @@ class qa_pmt_prims : public CppUnit::TestCase { void test_dict(); void test_any(); void test_io(); + void test_lists(); void test_serialize(); }; diff --git a/usrp/fpga/Makefile.extra b/usrp/fpga/Makefile.extra index 8154e2eb0..56df23c98 100644 --- a/usrp/fpga/Makefile.extra +++ b/usrp/fpga/Makefile.extra @@ -4,14 +4,11 @@ EXTRA_DIST = \ inband_lib/channel_demux.v \ inband_lib/channel_ram.v \ inband_lib/cmd_reader.v \ - inband_lib/data_packet_fifo.v \ inband_lib/packet_builder.v \ inband_lib/register_io.v \ inband_lib/rx_buffer_inband.v \ inband_lib/tx_buffer_inband.v \ inband_lib/tx_packer.v \ - inband_lib/usb_fifo_reader.v \ - inband_lib/usb_fifo_writer.v \ inband_lib/usb_packet_fifo.v \ megacells/accum32.bsf \ megacells/accum32.cmp \ diff --git a/usrp/fpga/inband_lib/chan_fifo_reader.v b/usrp/fpga/inband_lib/chan_fifo_reader.v index a6edf2c60..69da9ec5a 100755 --- a/usrp/fpga/inband_lib/chan_fifo_reader.v +++ b/usrp/fpga/inband_lib/chan_fifo_reader.v @@ -1,106 +1,102 @@ module chan_fifo_reader - ( reset, tx_clock, tx_strobe, adc_time, samples_format, + (reset, tx_clock, tx_strobe, timestamp_clock, samples_format, fifodata, pkt_waiting, rdreq, skip, tx_q, tx_i, underrun, tx_empty, debug, rssi, threshhold, rssi_wait) ; - input wire reset ; - input wire tx_clock ; - input wire tx_strobe ; //signal to output tx_i and tx_q - input wire [31:0] adc_time ; //current time - input wire [3:0] samples_format ;// not useful at this point - input wire [31:0] fifodata ; //the data input - input wire pkt_waiting ; //signal the next packet is ready - output reg rdreq ; //actually an ack to the current fifodata - output reg skip ; //finish reading current packet - output reg [15:0] tx_q ; //top 16 bit output of fifodata - output reg [15:0] tx_i ; //bottom 16 bit output of fifodata - output reg underrun ; - output reg tx_empty ; //cause 0 to be the output - input wire [31:0] rssi; - input wire [31:0] threshhold; - input wire [31:0] rssi_wait; + input wire reset ; + input wire tx_clock ; + input wire tx_strobe ; //signal to output tx_i and tx_q + input wire [31:0] timestamp_clock ; //current time + input wire [3:0] samples_format ;// not useful at this point + input wire [31:0] fifodata ; //the data input + input wire pkt_waiting ; //signal the next packet is ready + output reg rdreq ; //actually an ack to the current fifodata + output reg skip ; //finish reading current packet + output reg [15:0] tx_q ; //top 16 bit output of fifodata + output reg [15:0] tx_i ; //bottom 16 bit output of fifodata + output reg underrun ; + output reg tx_empty ; //cause 0 to be the output + input wire [31:0] rssi; + input wire [31:0] threshhold; + input wire [31:0] rssi_wait; - output wire [14:0] debug; - assign debug = {reader_state, trash, skip, timestamp[4:0], adc_time[4:0]}; - // Should not be needed if adc clock rate < tx clock rate - // Used only to debug - `define JITTER 5 - - //Samples format - // 16 bits interleaved complex samples - `define QI16 4'b0 + output wire [14:0] debug; + assign debug = {7'd0, rdreq, skip, reader_state, pkt_waiting, tx_strobe, tx_clock}; + + //Samples format + // 16 bits interleaved complex samples + `define QI16 4'b0 - // States - parameter IDLE = 3'd0; - parameter HEADER = 3'd1; - parameter TIMESTAMP = 3'd2; - parameter WAIT = 3'd3; - parameter WAITSTROBE = 3'd4; - parameter SEND = 3'd5; + // States + parameter IDLE = 3'd0; + parameter HEADER = 3'd1; + parameter TIMESTAMP = 3'd2; + parameter WAIT = 3'd3; + parameter WAITSTROBE = 3'd4; + parameter SEND = 3'd5; - // Header format - `define PAYLOAD 8:2 - `define ENDOFBURST 27 - `define STARTOFBURST 28 - `define RSSI_FLAG 26 + // Header format + `define PAYLOAD 8:2 + `define ENDOFBURST 27 + `define STARTOFBURST 28 + `define RSSI_FLAG 26 - /* State registers */ - reg [2:0] reader_state; - /* Local registers */ - reg [6:0] payload_len; - reg [6:0] read_len; - reg [31:0] timestamp; - reg burst; - reg trash; - reg rssi_flag; - reg [31:0] time_wait; + /* State registers */ + reg [2:0] reader_state; + /* Local registers */ + reg [6:0] payload_len; + reg [6:0] read_len; + reg [31:0] timestamp; + reg burst; + reg trash; + reg rssi_flag; + reg [31:0] time_wait; - always @(posedge tx_clock) - begin - if (reset) - begin - reader_state <= IDLE; - rdreq <= 0; - skip <= 0; - underrun <= 0; - burst <= 0; - tx_empty <= 1; - tx_q <= 0; - tx_i <= 0; - trash <= 0; - rssi_flag <= 0; - time_wait <= 0; + always @(posedge tx_clock) + begin + if (reset) + begin + reader_state <= IDLE; + rdreq <= 0; + skip <= 0; + underrun <= 0; + burst <= 0; + tx_empty <= 1; + tx_q <= 0; + tx_i <= 0; + trash <= 0; + rssi_flag <= 0; + time_wait <= 0; end else - begin + begin case (reader_state) - IDLE: + IDLE: begin - /* - * reset all the variables and wait for a tx_strobe - * it is assumed that the ram connected to this fifo_reader - * is a short hand fifo meaning that the header to the next packet - * is already available to this fifo_reader when pkt_waiting is on - */ - skip <=0; - time_wait <= 0; - if (pkt_waiting == 1) - begin - reader_state <= HEADER; - rdreq <= 1; - underrun <= 0; - end - if (burst == 1 && pkt_waiting == 0) - underrun <= 1; - - if (tx_strobe == 1) - tx_empty <= 1 ; + /* + * reset all the variables and wait for a tx_strobe + * it is assumed that the ram connected to this fifo_reader + * is a short hand fifo meaning that the header to the next packet + * is already available to this fifo_reader when pkt_waiting is on + */ + skip <=0; + time_wait <= 0; + if (pkt_waiting == 1) + begin + reader_state <= HEADER; + rdreq <= 1; + underrun <= 0; + end + if (burst == 1 && pkt_waiting == 0) + underrun <= 1; + if (tx_strobe == 1) + tx_empty <= 1 ; end - /* Process header */ + /* Process header */ HEADER: - begin + begin if (tx_strobe == 1) tx_empty <= 1 ; @@ -114,68 +110,64 @@ module chan_fifo_reader else if (fifodata[`ENDOFBURST] == 1) burst <= 0; - if (trash == 1 && fifodata[`STARTOFBURST] == 0) - begin - skip <= 1; - reader_state <= IDLE; - rdreq <= 0; - end - else - begin - payload_len <= fifodata[`PAYLOAD] ; - read_len <= 0; - rdreq <= 1; - reader_state <= TIMESTAMP; - end - end + if (trash == 1 && fifodata[`STARTOFBURST] == 0) + begin + skip <= 1; + reader_state <= IDLE; + rdreq <= 0; + end + else + begin + payload_len <= fifodata[`PAYLOAD] ; + read_len <= 0; + rdreq <= 1; + reader_state <= TIMESTAMP; + end + end TIMESTAMP: - begin + begin timestamp <= fifodata; reader_state <= WAIT; if (tx_strobe == 1) tx_empty <= 1 ; rdreq <= 0; - end + end - // Decide if we wait, send or discard samples + // Decide if we wait, send or discard samples WAIT: - begin + begin if (tx_strobe == 1) tx_empty <= 1 ; time_wait <= time_wait + 32'd1; - // Outdated - if ((timestamp < adc_time) || - (time_wait >= rssi_wait && rssi_wait != 0 && rssi_flag)) + // Outdated + if ((timestamp < timestamp_clock) || + (time_wait >= rssi_wait && rssi_wait != 0 && rssi_flag)) begin - trash <= 1; - reader_state <= IDLE; - skip <= 1; + trash <= 1; + reader_state <= IDLE; + skip <= 1; end // Let's send it - else if ((timestamp <= adc_time + `JITTER - && timestamp > adc_time) + else if (timestamp == timestamp_clock || timestamp == 32'hFFFFFFFF) - begin - if (rssi <= threshhold || rssi_flag == 0) - begin - trash <= 0; - reader_state <= WAITSTROBE; - end - else - reader_state <= WAIT; - end - else - reader_state <= WAIT; - // Wait a little bit more - //else if (timestamp > adc_time + `JITTER) - // reader_state <= WAIT; - end + begin + if (rssi <= threshhold || rssi_flag == 0) + begin + trash <= 0; + reader_state <= WAITSTROBE; + end + else + reader_state <= WAIT; + end + else + reader_state <= WAIT; + end // Wait for the transmit chain to be ready WAITSTROBE: - begin + begin // If end of payload... if (read_len == payload_len) begin @@ -189,11 +181,11 @@ module chan_fifo_reader reader_state <= SEND; rdreq <= 1; end - end + end - // Send the samples to the tx_chain + // Send the samples to the tx_chain SEND: - begin + begin reader_state <= WAITSTROBE; read_len <= read_len + 7'd1; tx_empty <= 0; @@ -213,13 +205,13 @@ module chan_fifo_reader tx_q <= fifodata[31:16]; end endcase - end + end default: - begin - //error handling + begin + //error handling reader_state <= IDLE; - end + end endcase end end diff --git a/usrp/fpga/inband_lib/channel_demux.v b/usrp/fpga/inband_lib/channel_demux.v index d46be9397..cca5cdb65 100644 --- a/usrp/fpga/inband_lib/channel_demux.v +++ b/usrp/fpga/inband_lib/channel_demux.v @@ -1,24 +1,24 @@ module channel_demux - #(parameter NUM_CHAN = 2, parameter CHAN_WIDTH = 2) ( //usb Side - input [31:0]usbdata_final, - input WR_final, - - // TX Side - input reset, - input txclk, - output reg [CHAN_WIDTH:0] WR_channel, - output reg [31:0] ram_data, - output reg [CHAN_WIDTH:0] WR_done_channel ); -/* Parse header and forward to ram */ - reg [2:0]reader_state; - reg [4:0]channel ; - reg [6:0]read_length ; + #(parameter NUM_CHAN = 2) ( //usb Side + input [31:0]usbdata_final, + input WR_final, + // TX Side + input reset, + input txclk, + output reg [NUM_CHAN:0] WR_channel, + output reg [31:0] ram_data, + output reg [NUM_CHAN:0] WR_done_channel ); + /* Parse header and forward to ram */ + + reg [2:0]reader_state; + reg [4:0]channel ; + reg [6:0]read_length ; // States - parameter IDLE = 3'd0; - parameter HEADER = 3'd1; - parameter WAIT = 3'd2; - parameter FORWARD = 3'd3; + parameter IDLE = 3'd0; + parameter HEADER = 3'd1; + parameter WAIT = 3'd2; + parameter FORWARD = 3'd3; `define CHANNEL 20:16 `define PKT_SIZE 127 @@ -27,7 +27,7 @@ module channel_demux NUM_CHAN : (usbdata_final[`CHANNEL]); always @(posedge txclk) - begin + begin if (reset) begin reader_state <= IDLE; diff --git a/usrp/fpga/inband_lib/channel_ram.v b/usrp/fpga/inband_lib/channel_ram.v index 60450f02d..9621246c5 100755 --- a/usrp/fpga/inband_lib/channel_ram.v +++ b/usrp/fpga/inband_lib/channel_ram.v @@ -1,114 +1,107 @@ module channel_ram - ( // System - input txclk, - input reset, + ( // System + input txclk, input reset, + // USB side + input [31:0] datain, input WR, input WR_done, output have_space, + // Reader side + output [31:0] dataout, input RD, input RD_done, output packet_waiting); - // USB side - input [31:0] datain, - input WR, - input WR_done, - output have_space, - - // Reader side - output [31:0] dataout, - input RD, - input RD_done, - output packet_waiting); - - reg [6:0] wr_addr, rd_addr; - reg [1:0] which_ram_wr, which_ram_rd; - reg [2:0] nb_packets; + reg [6:0] wr_addr, rd_addr; + reg [1:0] which_ram_wr, which_ram_rd; + reg [2:0] nb_packets; - reg [31:0] ram0 [0:127]; - reg [31:0] ram1 [0:127]; - reg [31:0] ram2 [0:127]; - reg [31:0] ram3 [0:127]; + reg [31:0] ram0 [0:127]; + reg [31:0] ram1 [0:127]; + reg [31:0] ram2 [0:127]; + reg [31:0] ram3 [0:127]; - reg [31:0] dataout0; - reg [31:0] dataout1; - reg [31:0] dataout2; - reg [31:0] dataout3; + reg [31:0] dataout0; + reg [31:0] dataout1; + reg [31:0] dataout2; + reg [31:0] dataout3; - wire wr_done_int; - wire rd_done_int; - wire [6:0] rd_addr_final; - wire [1:0] which_ram_rd_final; + wire wr_done_int; + wire rd_done_int; + wire [6:0] rd_addr_final; + wire [1:0] which_ram_rd_final; - // USB side - always @(posedge txclk) - if(WR & (which_ram_wr == 2'd0)) ram0[wr_addr] <= datain; + // USB side + always @(posedge txclk) + if(WR & (which_ram_wr == 2'd0)) ram0[wr_addr] <= datain; - always @(posedge txclk) - if(WR & (which_ram_wr == 2'd1)) ram1[wr_addr] <= datain; + always @(posedge txclk) + if(WR & (which_ram_wr == 2'd1)) ram1[wr_addr] <= datain; - always @(posedge txclk) - if(WR & (which_ram_wr == 2'd2)) ram2[wr_addr] <= datain; + always @(posedge txclk) + if(WR & (which_ram_wr == 2'd2)) ram2[wr_addr] <= datain; - always @(posedge txclk) - if(WR & (which_ram_wr == 2'd3)) ram3[wr_addr] <= datain; + always @(posedge txclk) + if(WR & (which_ram_wr == 2'd3)) ram3[wr_addr] <= datain; assign wr_done_int = ((WR && (wr_addr == 7'd127)) || WR_done); - always @(posedge txclk) - if(reset) - wr_addr <= 0; - else if (WR_done) - wr_addr <= 0; - else if (WR) - wr_addr <= wr_addr + 7'd1; + always @(posedge txclk) + if(reset) + wr_addr <= 0; + else if (WR_done) + wr_addr <= 0; + else if (WR) + wr_addr <= wr_addr + 7'd1; - always @(posedge txclk) - if(reset) - which_ram_wr <= 0; - else if (wr_done_int) - which_ram_wr <= which_ram_wr + 2'd1; + always @(posedge txclk) + if(reset) + which_ram_wr <= 0; + else if (wr_done_int) + which_ram_wr <= which_ram_wr + 2'd1; - assign have_space = (nb_packets < 3'd3); + assign have_space = (nb_packets < 3'd3); - // Reader side - // short hand fifo - // rd_addr_final is what rd_addr is going to be next clock cycle - // which_ram_rd_final is what which_ram_rd is going to be next clock cycle - always @(posedge txclk) dataout0 <= ram0[rd_addr_final]; - always @(posedge txclk) dataout1 <= ram1[rd_addr_final]; - always @(posedge txclk) dataout2 <= ram2[rd_addr_final]; - always @(posedge txclk) dataout3 <= ram3[rd_addr_final]; + // Reader side + // short hand fifo + // rd_addr_final is what rd_addr is going to be next clock cycle + // which_ram_rd_final is what which_ram_rd is going to be next clock cycle + always @(posedge txclk) dataout0 <= ram0[rd_addr_final]; + always @(posedge txclk) dataout1 <= ram1[rd_addr_final]; + always @(posedge txclk) dataout2 <= ram2[rd_addr_final]; + always @(posedge txclk) dataout3 <= ram3[rd_addr_final]; - assign dataout = (which_ram_rd_final[1]) ? - (which_ram_rd_final[0] ? dataout3 : dataout2) : - (which_ram_rd_final[0] ? dataout1 : dataout0); + assign dataout = (which_ram_rd_final[1]) ? + (which_ram_rd_final[0] ? dataout3 : dataout2) : + (which_ram_rd_final[0] ? dataout1 : dataout0); - //RD_done is the only way to signal the end of one packet - assign rd_done_int = RD_done; + //RD_done is the only way to signal the end of one packet + assign rd_done_int = RD_done; - always @(posedge txclk) - if (reset) - rd_addr <= 0; - else if (RD_done) - rd_addr <= 0; - else if (RD) rd_addr <= rd_addr + 7'd1; + always @(posedge txclk) + if (reset) + rd_addr <= 0; + else if (RD_done) + rd_addr <= 0; + else if (RD) + rd_addr <= rd_addr + 7'd1; - assign rd_addr_final = (reset|RD_done) ? (6'd0) : - ((RD)?(rd_addr+7'd1):rd_addr); - always @(posedge txclk) - if (reset) - which_ram_rd <= 0; - else if (rd_done_int) - which_ram_rd <= which_ram_rd + 2'd1; + assign rd_addr_final = (reset|RD_done) ? (6'd0) : + ((RD)?(rd_addr+7'd1):rd_addr); + + always @(posedge txclk) + if (reset) + which_ram_rd <= 0; + else if (rd_done_int) + which_ram_rd <= which_ram_rd + 2'd1; - assign which_ram_rd_final = (reset) ? (2'd0): + assign which_ram_rd_final = (reset) ? (2'd0): ((rd_done_int) ? (which_ram_rd + 2'd1) : which_ram_rd); - //packet_waiting is set to zero if rd_done_int is high - //because there is no guarantee that nb_packets will be pos. - //assign packet_waiting = (nb_packets != 0) & (~rd_done_int); - assign packet_waiting = (nb_packets > 1) | ((nb_packets == 1)&(~rd_done_int)); - always @(posedge txclk) - if (reset) - nb_packets <= 0; - else if (wr_done_int & ~rd_done_int) - nb_packets <= nb_packets + 3'd1; - else if (rd_done_int & ~wr_done_int) - nb_packets <= nb_packets - 3'd1; + //packet_waiting is set to zero if rd_done_int is high + //because there is no guarantee that nb_packets will be pos. + + assign packet_waiting = (nb_packets > 1) | ((nb_packets == 1)&(~rd_done_int)); + always @(posedge txclk) + if (reset) + nb_packets <= 0; + else if (wr_done_int & ~rd_done_int) + nb_packets <= nb_packets + 3'd1; + else if (rd_done_int & ~wr_done_int) + nb_packets <= nb_packets - 3'd1; -endmodule
\ No newline at end of file +endmodule diff --git a/usrp/fpga/inband_lib/cmd_reader.v b/usrp/fpga/inband_lib/cmd_reader.v index 7604321e4..b69ea02b7 100755 --- a/usrp/fpga/inband_lib/cmd_reader.v +++ b/usrp/fpga/inband_lib/cmd_reader.v @@ -1,292 +1,305 @@ -module cmd_reader( - //System - input reset, - input txclk, - input [31:0] adc_time, - //FX2 Side - output reg skip, - output reg rdreq, - input [31:0] fifodata, - input pkt_waiting, - //Rx side - input rx_WR_enabled, - output reg [15:0] rx_databus, - output reg rx_WR, - output reg rx_WR_done, - //register io - input wire [31:0] reg_data_out, - output reg [31:0] reg_data_in, - output reg [6:0] reg_addr, - output reg [1:0] reg_io_enable, - output wire [14:0] debug - ); +module cmd_reader + (//System + input reset, input txclk, input [31:0] timestamp_clock, + //FX2 Side + output reg skip, output reg rdreq, + input [31:0] fifodata, input pkt_waiting, + //Rx side + input rx_WR_enabled, output reg [15:0] rx_databus, + output reg rx_WR, output reg rx_WR_done, + //register io + input wire [31:0] reg_data_out, output reg [31:0] reg_data_in, + output reg [6:0] reg_addr, output reg [1:0] reg_io_enable, + output wire [14:0] debug, output reg stop, output reg [15:0] stop_time); - // States - parameter IDLE = 4'd0; - parameter HEADER = 4'd1; - parameter TIMESTAMP = 4'd2; - parameter WAIT = 4'd3; - parameter TEST = 4'd4; - parameter SEND = 4'd5; - parameter PING = 4'd6; - parameter WRITE_REG = 4'd7; - parameter WRITE_REG_MASKED = 4'd8; - parameter READ_REG = 4'd9; - parameter DELAY = 4'd14; + // States + parameter IDLE = 4'd0; + parameter HEADER = 4'd1; + parameter TIMESTAMP = 4'd2; + parameter WAIT = 4'd3; + parameter TEST = 4'd4; + parameter SEND = 4'd5; + parameter PING = 4'd6; + parameter WRITE_REG = 4'd7; + parameter WRITE_REG_MASKED = 4'd8; + parameter READ_REG = 4'd9; + parameter DELAY = 4'd14; - `define OP_PING_FIXED 8'd0 - `define OP_PING_FIXED_REPLY 8'd1 - `define OP_WRITE_REG 8'd2 - `define OP_WRITE_REG_MASKED 8'd3 - `define OP_READ_REG 8'd4 - `define OP_READ_REG_REPLY 8'd5 - `define OP_DELAY 8'd12 + `define OP_PING_FIXED 8'd0 + `define OP_PING_FIXED_REPLY 8'd1 + `define OP_WRITE_REG 8'd2 + `define OP_WRITE_REG_MASKED 8'd3 + `define OP_READ_REG 8'd4 + `define OP_READ_REG_REPLY 8'd5 + `define OP_DELAY 8'd12 - reg [6:0] payload; - reg [6:0] payload_read; - reg [3:0] state; - reg [15:0] high; - reg [15:0] low; - reg pending; - reg [31:0] value0; - reg [31:0] value1; - reg [31:0] value2; - reg [1:0] lines_in; - reg [1:0] lines_out; - reg [1:0] lines_out_total; + reg [6:0] payload; + reg [6:0] payload_read; + reg [3:0] state; + reg [15:0] high; + reg [15:0] low; + reg pending; + reg [31:0] value0; + reg [31:0] value1; + reg [31:0] value2; + reg [1:0] lines_in; + reg [1:0] lines_out; + reg [1:0] lines_out_total; - `define JITTER 5 - `define OP_CODE 31:24 - `define PAYLOAD 8:2 + `define JITTER 5 + `define OP_CODE 31:24 + `define PAYLOAD 8:2 - wire [7:0] ops; - assign ops = value0[`OP_CODE]; - assign debug = {state[3:0], lines_out[1:0], pending, rx_WR, rx_WR_enabled, value0[2:0], ops[2:0]}; + wire [7:0] ops; + assign ops = value0[`OP_CODE]; + assign debug = {state[3:0], lines_out[1:0], pending, rx_WR, rx_WR_enabled, value0[2:0], ops[2:0]}; - always @(posedge txclk) - if (reset) - begin - pending <= 0; - state <= IDLE; - skip <= 0; - rdreq <= 0; - rx_WR <= 0; - reg_io_enable <= 0; - reg_data_in <= 0; - reg_addr <= 0; - end - else case (state) - IDLE : begin - payload_read <= 0; - skip <= 0; - lines_in <= 0; - if (pkt_waiting) - begin - state <= HEADER; - rdreq <= 1; - end - end + always @(posedge txclk) + if (reset) + begin + pending <= 0; + state <= IDLE; + skip <= 0; + rdreq <= 0; + rx_WR <= 0; + reg_io_enable <= 0; + reg_data_in <= 0; + reg_addr <= 0; + stop <= 0; + end + else case (state) + IDLE : + begin + payload_read <= 0; + skip <= 0; + lines_in <= 0; + if(pkt_waiting) + begin + state <= HEADER; + rdreq <= 1; + end + end + + HEADER : + begin + payload <= fifodata[`PAYLOAD]; + state <= TIMESTAMP; + end + + TIMESTAMP : + begin + value0 <= fifodata; + state <= WAIT; + rdreq <= 0; + end - HEADER : begin - payload <= fifodata[`PAYLOAD]; - state <= TIMESTAMP; - end + WAIT : + begin + // Let's send it + if ((value0 <= timestamp_clock + `JITTER + && value0 > timestamp_clock) + || value0 == 32'hFFFFFFFF) + state <= TEST; + // Wait a little bit more + else if (value0 > timestamp_clock + `JITTER) + state <= WAIT; + // Outdated + else if (value0 < timestamp_clock) + begin + state <= IDLE; + skip <= 1; + end + end - TIMESTAMP : begin - value0 <= fifodata; - state <= WAIT; - rdreq <= 0; - end - - WAIT : begin - // Let's send it - if ((value0 <= adc_time + `JITTER - && value0 > adc_time) - || value0 == 32'hFFFFFFFF) - state <= TEST; - // Wait a little bit more - else if (value0 > adc_time + `JITTER) - state <= WAIT; - // Outdated - else if (value0 < adc_time) - begin - state <= IDLE; + TEST : + begin + reg_io_enable <= 0; + rx_WR <= 0; + rx_WR_done <= 1; + stop <= 0; + if (payload_read == payload) + begin + skip <= 1; + state <= IDLE; + rdreq <= 0; + end + else + begin + value0 <= fifodata; + lines_in <= 2'd1; + rdreq <= 1; + payload_read <= payload_read + 7'd1; + lines_out <= 0; + case (fifodata[`OP_CODE]) + `OP_PING_FIXED: + begin + state <= PING; + end + `OP_WRITE_REG: + begin + state <= WRITE_REG; + pending <= 1; + end + `OP_WRITE_REG_MASKED: + begin + state <= WRITE_REG_MASKED; + pending <= 1; + end + `OP_READ_REG: + begin + state <= READ_REG; + end + `OP_DELAY: + begin + state <= DELAY; + end + default: + begin + //error, skip this packet skip <= 1; - end - end - - TEST : begin - reg_io_enable <= 0; - rx_WR <= 0; - rx_WR_done <= 1; - if (payload_read == payload) - begin - skip <= 1; - state <= IDLE; - rdreq <= 0; - end - else - begin - value0 <= fifodata; - lines_in <= 2'd1; - rdreq <= 1; - payload_read <= payload_read + 7'd1; - lines_out <= 0; - case (fifodata[`OP_CODE]) - `OP_PING_FIXED: begin - state <= PING; - end - `OP_WRITE_REG: begin - state <= WRITE_REG; - pending <= 1; - end - `OP_WRITE_REG_MASKED: begin - state <= WRITE_REG_MASKED; - pending <= 1; - end - `OP_READ_REG: begin - state <= READ_REG; - end - `OP_DELAY: begin - state <= DELAY; - end - default: begin - //error, skip this packet - skip <= 1; - state <= IDLE; - end - endcase - end - end + state <= IDLE; + end + endcase + end + end - SEND: begin - rdreq <= 0; - rx_WR_done <= 0; - if (pending) - begin - rx_WR <= 1; - rx_databus <= high; - pending <= 0; - if (lines_out == lines_out_total) - state <= TEST; - else case (ops) - `OP_READ_REG: begin - state <= READ_REG; - end - default: begin - state <= TEST; - end - endcase - end - else - begin - if (rx_WR_enabled) - begin - rx_WR <= 1; - rx_databus <= low; - pending <= 1; - lines_out <= lines_out + 2'd1; - end - else - rx_WR <= 0; - end - end + SEND: + begin + rdreq <= 0; + rx_WR_done <= 0; + if (pending) + begin + rx_WR <= 1; + rx_databus <= high; + pending <= 0; + if (lines_out == lines_out_total) + state <= TEST; + else case (ops) + `OP_READ_REG: + begin + state <= READ_REG; + end + default: + begin + state <= TEST; + end + endcase + end + else + begin + if (rx_WR_enabled) + begin + rx_WR <= 1; + rx_databus <= low; + pending <= 1; + lines_out <= lines_out + 2'd1; + end + else + rx_WR <= 0; + end + end - PING: begin - rx_WR <= 0; - rdreq <= 0; - rx_WR_done <= 0; - lines_out_total <= 2'd1; - pending <= 0; - state <= SEND; - high <= {`OP_PING_FIXED_REPLY, 8'd2}; - low <= value0[15:0]; - end + PING: + begin + rx_WR <= 0; + rdreq <= 0; + rx_WR_done <= 0; + lines_out_total <= 2'd1; + pending <= 0; + state <= SEND; + high <= {`OP_PING_FIXED_REPLY, 8'd2}; + low <= value0[15:0]; + end - READ_REG: begin - rx_WR <= 0; - rx_WR_done <= 0; - rdreq <= 0; - lines_out_total <= 2'd2; - pending <= 0; - state <= SEND; - if (lines_out == 0) - begin - high <= {`OP_READ_REG_REPLY, 8'd6}; - low <= value0[15:0]; - reg_io_enable <= 2'd3; - reg_addr <= value0[6:0]; - end - else - begin - high <= reg_data_out[31:16]; - low <= reg_data_out[15:0]; - end - end + READ_REG: + begin + rx_WR <= 0; + rx_WR_done <= 0; + rdreq <= 0; + lines_out_total <= 2'd2; + pending <= 0; + state <= SEND; + if (lines_out == 0) + begin + high <= {`OP_READ_REG_REPLY, 8'd6}; + low <= value0[15:0]; + reg_io_enable <= 2'd3; + reg_addr <= value0[6:0]; + end + else + begin + high <= reg_data_out[31:16]; + low <= reg_data_out[15:0]; + end + end - WRITE_REG: begin - rx_WR <= 0; - if (pending) - pending <= 0; - else - begin - if (lines_in == 2'd1) - begin - payload_read <= payload_read + 7'd1; - lines_in <= lines_in + 2'd1; - value1 <= fifodata; - rdreq <= 0; - end - else - begin - reg_io_enable <= 2'd2; - reg_data_in <= value1; - reg_addr <= value0[6:0]; - state <= TEST; - end - end - end + WRITE_REG: + begin + rx_WR <= 0; + if (pending) + pending <= 0; + else + begin + if (lines_in == 2'd1) + begin + payload_read <= payload_read + 7'd1; + lines_in <= lines_in + 2'd1; + value1 <= fifodata; + rdreq <= 0; + end + else + begin + reg_io_enable <= 2'd2; + reg_data_in <= value1; + reg_addr <= value0[6:0]; + state <= TEST; + end + end + end - WRITE_REG_MASKED: begin - rx_WR <= 0; - if (pending) - pending <= 0; - else - begin - if (lines_in == 2'd1) - begin - rdreq <= 1; - payload_read <= payload_read + 7'd1; - lines_in <= lines_in + 2'd1; - value1 <= fifodata; - end - else if (lines_in == 2'd2) - begin - rdreq <= 0; - payload_read <= payload_read + 7'd1; - lines_in <= lines_in + 2'd1; - value2 <= fifodata; - end - else - begin - reg_io_enable <= 2'd2; - reg_data_in <= (value1 & value2); - reg_addr <= value0[6:0]; - state <= TEST; - end - end - end + WRITE_REG_MASKED: + begin + rx_WR <= 0; + if (pending) + pending <= 0; + else + begin + if (lines_in == 2'd1) + begin + rdreq <= 1; + payload_read <= payload_read + 7'd1; + lines_in <= lines_in + 2'd1; + value1 <= fifodata; + end + else if (lines_in == 2'd2) + begin + rdreq <= 0; + payload_read <= payload_read + 7'd1; + lines_in <= lines_in + 2'd1; + value2 <= fifodata; + end + else + begin + reg_io_enable <= 2'd2; + reg_data_in <= (value1 & value2); + reg_addr <= value0[6:0]; + state <= TEST; + end + end + end - DELAY : begin - rdreq <= 0; - value1 <= value1 + 32'd1; - if (value0[15:0] == value1[15:0]) - state <= TEST; - end + DELAY : + begin + rdreq <= 0; + stop <= 1; + stop_time <= value0[15:0]; + state <= TEST; + end - default : begin - //error state handling - state <= IDLE; - end - endcase -endmodule
\ No newline at end of file + default : + begin + //error state handling + state <= IDLE; + end + endcase +endmodule diff --git a/usrp/fpga/inband_lib/data_packet_fifo.v b/usrp/fpga/inband_lib/data_packet_fifo.v deleted file mode 100755 index a9bcbdae7..000000000 --- a/usrp/fpga/inband_lib/data_packet_fifo.v +++ /dev/null @@ -1,118 +0,0 @@ -module data_packet_fifo - ( input reset, - input clock, - input [31:0]ram_data_in, - input write_enable, - output reg have_space, - output reg [31:0]ram_data_out, - output reg pkt_waiting, - output reg isfull, - output reg [1:0]usb_ram_packet_out, - output reg [1:0]usb_ram_packet_in, - input read_enable, - input pkt_complete, - input skip_packet) ; - - /* Some parameters for usage later on */ - parameter DATA_WIDTH = 32 ; - parameter PKT_DEPTH = 128 ; - parameter NUM_PACKETS = 4 ; - - /* Create the RAM here */ - reg [DATA_WIDTH-1:0] usb_ram [PKT_DEPTH*NUM_PACKETS-1:0] ; - - /* Create the address signals */ - reg [6:0] usb_ram_offset_out ; - //reg [1:0] usb_ram_packet_out ; - reg [6:0] usb_ram_offset_in ; - //reg [1:0] usb_ram_packet_in ; - - wire [6-2+NUM_PACKETS:0] usb_ram_aout ; - wire [6-2+NUM_PACKETS:0] usb_ram_ain ; - //reg isfull; - - assign usb_ram_aout = {usb_ram_packet_out, usb_ram_offset_out} ; - assign usb_ram_ain = {usb_ram_packet_in, usb_ram_offset_in} ; - - // Check if there is one full packet to process - always @(usb_ram_ain, usb_ram_aout, isfull) - begin - if (usb_ram_ain == usb_ram_aout) - pkt_waiting <= isfull ; - else if (usb_ram_ain > usb_ram_aout) - pkt_waiting <= (usb_ram_ain - usb_ram_aout) >= PKT_DEPTH; - else - pkt_waiting <= (usb_ram_ain + 10'b1000000000 - usb_ram_aout) >= PKT_DEPTH; - end - - // Check if there is room - always @(usb_ram_ain, usb_ram_aout, isfull) - begin - if (usb_ram_ain == usb_ram_aout) - have_space <= ~isfull; - else if (usb_ram_ain > usb_ram_aout) - have_space <= ((usb_ram_ain - usb_ram_aout) <= PKT_DEPTH * (NUM_PACKETS - 1))? 1'b1 : 1'b0; - else - have_space <= (usb_ram_aout - usb_ram_ain) >= PKT_DEPTH; - end - - - - /* RAM Writing/Reading process */ - always @(posedge clock) - begin - if( write_enable ) - begin - usb_ram[usb_ram_ain] <= ram_data_in ; - end - ram_data_out <= usb_ram[usb_ram_aout] ; - end - - /* RAM Write/Read Address process */ - always @(posedge clock) - begin - if( reset ) - begin - usb_ram_packet_out <= 0 ; - usb_ram_offset_out <= 0 ; - usb_ram_offset_in <= 0 ; - usb_ram_packet_in <= 0 ; - isfull <= 0; - end - else - begin - if( skip_packet ) - begin - usb_ram_packet_out <= usb_ram_packet_out + 1 ; - usb_ram_offset_out <= 0 ; - isfull <= 0; - end - else if(read_enable) - begin - if( usb_ram_offset_out == 7'b1111111 ) - begin - isfull <= 0 ; - usb_ram_offset_out <= 0 ; - usb_ram_packet_out <= usb_ram_packet_out + 1 ; - end - else - usb_ram_offset_out <= usb_ram_offset_out + 1 ; - end - if( pkt_complete ) - begin - usb_ram_packet_in <= usb_ram_packet_in + 1 ; - usb_ram_offset_in <= 0 ; - if ((usb_ram_packet_in + 2'b1) == usb_ram_packet_out) - isfull <= 1 ; - end - else if( write_enable ) - begin - if (usb_ram_offset_in == 7'b1111111) - usb_ram_offset_in <= 7'b1111111 ; - else - usb_ram_offset_in <= usb_ram_offset_in + 1 ; - end - end - end - -endmodule diff --git a/usrp/fpga/inband_lib/packet_builder.v b/usrp/fpga/inband_lib/packet_builder.v index fbf0a656e..2c9122394 100755 --- a/usrp/fpga/inband_lib/packet_builder.v +++ b/usrp/fpga/inband_lib/packet_builder.v @@ -1,8 +1,8 @@ -module packet_builder #(parameter NUM_CHAN = 1)( +module packet_builder #(parameter NUM_CHAN = 2)( // System input rxclk, input reset, - input [31:0] adctime, + input [31:0] timestamp_clock, input [3:0] channels, // ADC side input [15:0]chan_fifodata, @@ -14,17 +14,17 @@ module packet_builder #(parameter NUM_CHAN = 1)( output reg WR, output reg [15:0]fifodata, input have_space, - input wire [31:0]rssi_0, input wire [31:0]rssi_1, input wire [31:0]rssi_2, - input wire [31:0]rssi_3, output wire [7:0] debugbus, - input [NUM_CHAN:0] overrun, input [NUM_CHAN:0] underrun); + input wire [31:0]rssi_0, input wire [31:0]rssi_1, input wire [31:0]rssi_2, + input wire [31:0]rssi_3, output wire [7:0] debugbus, + input [NUM_CHAN:0] underrun); // States `define IDLE 3'd0 `define HEADER1 3'd1 - `define HEADER2 3'd2 + `define HEADER2 3'd2 `define TIMESTAMP 3'd3 - `define FORWARD 3'd4 + `define FORWARD 3'd4 `define MAXPAYLOAD 504 @@ -39,51 +39,67 @@ module packet_builder #(parameter NUM_CHAN = 1)( `define UNDERRUN 14 `define OVERRUN 15 + reg [NUM_CHAN:0] overrun; reg [2:0] state; reg [8:0] read_length; reg [8:0] payload_len; - reg tstamp_complete; + reg timestamp_complete; reg [3:0] check_next; - wire [8:0] chan_used; + wire [31:0] true_rssi; - wire [4:0] true_channel; + wire [4:0] true_channel; + wire ready_to_send; + + assign debugbus = {chan_empty[0], rd_select[0], have_space, + (chan_usedw >= 10'd504), (chan_usedw ==0), + ready_to_send, state[1:0]}; - assign debugbus = {state, chan_empty[0], underrun[0], check_next[0], - have_space, rd_select[0]}; - assign chan_used = chan_usedw[8:0]; - assign true_rssi = (rd_select[1]) ? ((rd_select[0]) ? rssi_3:rssi_2) : + assign true_rssi = (rd_select[1]) ? ((rd_select[0]) ? rssi_3:rssi_2) : ((rd_select[0]) ? rssi_1:rssi_0); - assign true_channel = (check_next == 4'd0 ? 5'h1f : {1'd0, check_next - 4'd1}); + assign true_channel = (check_next == 4'd0 ? 5'h1f : {1'd0, check_next - 4'd1}); + assign ready_to_send = (chan_usedw >= 10'd504) || (chan_usedw == 0) || + ((rd_select == NUM_CHAN)&&(chan_usedw > 0)); + always @(posedge rxclk) begin if (reset) begin + overrun <= 0; WR <= 0; rd_select <= 0; chan_rdreq <= 0; - tstamp_complete <= 0; + timestamp_complete <= 0; check_next <= 0; state <= `IDLE; end else case (state) `IDLE: begin - chan_rdreq <= #1 0; - if (have_space) - begin - if(~chan_empty[check_next]) - begin - state <= #1 `HEADER1; - rd_select <= #1 check_next; - end - check_next <= #1 (check_next == channels ? 4'd0 : check_next + 4'd1); - end + chan_rdreq <= #1 0; + //check if the channel is full + if(~chan_empty[check_next]) + begin + if (have_space) + begin + //transmit if the usb buffer have space + //check if we should send + if (ready_to_send) + state <= #1 `HEADER1; + + overrun[check_next] <= 0; + end + else + begin + state <= #1 `IDLE; + overrun[check_next] <= 1; + end + rd_select <= #1 check_next; + end + check_next <= #1 (check_next == channels ? 4'd0 : check_next + 4'd1); end `HEADER1: begin - fifodata[`PAYLOAD_LEN] <= #1 (chan_used > 9'd252 - ? 9'd252 : chan_used << 1); - payload_len <= #1 (chan_used > 9'd252 - ? 9'd252 : chan_used << 1); + fifodata[`PAYLOAD_LEN] <= #1 9'd504; + payload_len <= #1 9'd504; fifodata[`TAG] <= #1 0; fifodata[`MBZ] <= #1 0; WR <= #1 1; @@ -103,13 +119,13 @@ module packet_builder #(parameter NUM_CHAN = 1)( end `TIMESTAMP: begin - fifodata <= #1 (tstamp_complete ? adctime[31:16] : adctime[15:0]); - tstamp_complete <= #1 ~tstamp_complete; + fifodata <= #1 (timestamp_complete ? timestamp_clock[31:16] : timestamp_clock[15:0]); + timestamp_complete <= #1 ~timestamp_complete; - if (~tstamp_complete) + if (~timestamp_complete) chan_rdreq <= #1 1; - state <= #1 (tstamp_complete ? `FORWARD : `TIMESTAMP); + state <= #1 (timestamp_complete ? `FORWARD : `TIMESTAMP); end `FORWARD: begin diff --git a/usrp/fpga/inband_lib/register_io.v b/usrp/fpga/inband_lib/register_io.v index b116b3ace..2b0cd1732 100755 --- a/usrp/fpga/inband_lib/register_io.v +++ b/usrp/fpga/inband_lib/register_io.v @@ -1,15 +1,38 @@ module register_io - (input clk, input reset, input wire [1:0] enable, input wire [6:0] addr, - input wire [31:0] datain, output reg [31:0] dataout, output wire [15:0] debugbus, - input wire [31:0] rssi_0, input wire [31:0] rssi_1, - input wire [31:0] rssi_2, input wire [31:0] rssi_3, - output wire [31:0] threshhold, output wire [31:0] rssi_wait); - + (clk, reset, enable, addr, datain, dataout, debugbus, addr_wr, data_wr, strobe_wr, + rssi_0, rssi_1, rssi_2, rssi_3, threshhold, rssi_wait, reg_0, reg_1, reg_2, reg_3, + debug_en, misc, txmux); + + input clk; + input reset; + input wire [1:0] enable; + input wire [6:0] addr; + input wire [31:0] datain; + output reg [31:0] dataout; + output wire [15:0] debugbus; + output reg [6:0] addr_wr; + output reg [31:0] data_wr; + output wire strobe_wr; + input wire [31:0] rssi_0; + input wire [31:0] rssi_1; + input wire [31:0] rssi_2; + input wire [31:0] rssi_3; + output wire [31:0] threshhold; + output wire [31:0] rssi_wait; + input wire [15:0] reg_0; + input wire [15:0] reg_1; + input wire [15:0] reg_2; + input wire [15:0] reg_3; + input wire [3:0] debug_en; + input wire [7:0] misc; + input wire [31:0] txmux; + reg strobe; - wire [31:0] out[7:0]; + wire [31:0] out[2:1]; assign debugbus = {clk, enable, addr[2:0], datain[4:0], dataout[4:0]}; assign threshhold = out[1]; assign rssi_wait = out[2]; + assign strobe_wr = strobe; always @(*) if (reset | ~enable[1]) @@ -22,41 +45,38 @@ module register_io if (enable[0]) begin //read - if (addr == 7'd9) - dataout <= rssi_0; - else if (addr == 7'd10) - dataout <= rssi_1; - else if (addr == 7'd11) - dataout <= rssi_2; - else if (addr == 7'd12) - dataout <= rssi_3; - else - dataout <= out[addr[2:0]]; - strobe <= 0; - end + if (addr <= 7'd52 && addr > 7'd50) + dataout <= out[addr-7'd50]; + else + dataout <= 32'hFFFFFFFF; + strobe <= 0; + end else begin //write dataout <= dataout; strobe <= 1; + data_wr <= datain; + addr_wr <= addr; end end - //register declarations - setting_reg #(0) setting_reg0(.clock(clk),.reset(reset), - .strobe(strobe),.addr(addr),.in(datain),.out(out[0])); - setting_reg #(1) setting_reg1(.clock(clk),.reset(reset), - .strobe(strobe),.addr(addr),.in(datain),.out(out[1])); - setting_reg #(2) setting_reg2(.clock(clk),.reset(reset), - .strobe(strobe),.addr(addr),.in(datain),.out(out[2])); - setting_reg #(3) setting_reg3(.clock(clk),.reset(reset), - .strobe(strobe),.addr(addr),.in(datain),.out(out[3])); - setting_reg #(4) setting_reg4(.clock(clk),.reset(reset), - .strobe(strobe),.addr(addr),.in(datain),.out(out[4])); - setting_reg #(5) setting_reg5(.clock(clk),.reset(reset), - .strobe(strobe),.addr(addr),.in(datain),.out(out[5])); - setting_reg #(6) setting_reg6(.clock(clk),.reset(reset), - .strobe(strobe),.addr(addr),.in(datain),.out(out[6])); - setting_reg #(7) setting_reg7(.clock(clk),.reset(reset), - .strobe(strobe),.addr(addr),.in(datain),.out(out[7])); -endmodule
\ No newline at end of file +//register declarations + /*setting_reg #(50) setting_reg0(.clock(clk),.reset(reset), + .strobe(strobe_wr),.addr(addr_wr),.in(data_wr),.out(out[0]));*/ + setting_reg #(51) setting_reg1(.clock(clk),.reset(reset), + .strobe(strobe_wr),.addr(addr_wr),.in(data_wr),.out(out[1])); + setting_reg #(52) setting_reg2(.clock(clk),.reset(reset), + .strobe(strobe_wr),.addr(addr_wr),.in(data_wr),.out(out[2])); + /*setting_reg #(53) setting_reg3(.clock(clk),.reset(reset), + .strobe(strobe_wr),.addr(addr_wr),.in(data_wr),.out(out[3])); + setting_reg #(54) setting_reg4(.clock(clk),.reset(reset), + .strobe(strobe_wr),.addr(addr_wr),.in(data_wr),.out(out[4])); + setting_reg #(55) setting_reg5(.clock(clk),.reset(reset), + .strobe(strobe_wr),.addr(addr_wr),.in(data_wr),.out(out[5])); + setting_reg #(56) setting_reg6(.clock(clk),.reset(reset), + .strobe(strobe_wr),.addr(addr_wr),.in(data_wr),.out(out[6])); + setting_reg #(57) setting_reg7(.clock(clk),.reset(reset), + .strobe(strobe_wr),.addr(addr_wr),.in(data_wr),.out(out[7]));*/ + +endmodule diff --git a/usrp/fpga/inband_lib/rx_buffer_inband.v b/usrp/fpga/inband_lib/rx_buffer_inband.v index 1eaecabed..cbd2d8958 100755 --- a/usrp/fpga/inband_lib/rx_buffer_inband.v +++ b/usrp/fpga/inband_lib/rx_buffer_inband.v @@ -1,179 +1,209 @@ -//`include "../../firmware/include/fpga_regs_common.v" -//`include "../../firmware/include/fpga_regs_standard.v" -module rx_buffer_inband - ( input usbclk, - input bus_reset, - input reset, // DSP side reset (used here), do not reset registers - input reset_regs, //Only reset registers - output [15:0] usbdata, - input RD, - output wire have_pkt_rdy, - output reg rx_overrun, - input wire [3:0] channels, - input wire [15:0] ch_0, - input wire [15:0] ch_1, - input wire [15:0] ch_2, - input wire [15:0] ch_3, - input wire [15:0] ch_4, - input wire [15:0] ch_5, - input wire [15:0] ch_6, - input wire [15:0] ch_7, - input rxclk, - input rxstrobe, - input clear_status, - input [6:0] serial_addr, - input [31:0] serial_data, - input serial_strobe, - output wire [15:0] debugbus, - - //Connection with tx_inband - input rx_WR, - input [15:0] rx_databus, - input rx_WR_done, - output reg rx_WR_enabled, - //signal strength - input wire [31:0] rssi_0, input wire [31:0] rssi_1, - input wire [31:0] rssi_2, input wire [31:0] rssi_3, - input wire [1:0] tx_overrun, input wire [1:0] tx_underrun - ); - - parameter NUM_CHAN = 1; - genvar i ; - - // FX2 Bug Fix - reg [8:0] read_count; - always @(negedge usbclk) - if(bus_reset) - read_count <= #1 9'd0; - else if(RD & ~read_count[8]) - read_count <= #1 read_count + 9'd1; - else - read_count <= #1 RD ? read_count : 9'b0; - - // Time counter - reg [31:0] adctime; - always @(posedge rxclk) - if (reset) - adctime <= 0; - else if (rxstrobe) - adctime <= adctime + 1; - - // USB side fifo - wire [11:0] rdusedw; - wire [11:0] wrusedw; - wire [15:0] fifodata; - wire WR; - wire have_space; - - fifo_4kx16_dc rx_usb_fifo ( - .aclr ( reset ), - .data ( fifodata ), - .rdclk ( ~usbclk ), - .rdreq ( RD & ~read_count[8] ), - .wrclk ( rxclk ), - .wrreq ( WR ), - .q ( usbdata ), - .rdempty ( ), - .rdusedw ( rdusedw ), - .wrfull ( ), - .wrusedw ( wrusedw ) ); - - assign have_pkt_rdy = (rdusedw >= 12'd256); - assign have_space = (wrusedw < 12'd760); - - // Rx side fifos - wire chan_rdreq; - wire [15:0] chan_fifodata; - wire [9:0] chan_usedw; - wire [NUM_CHAN:0] chan_empty; - wire [3:0] rd_select; - wire [NUM_CHAN:0] rx_full; - - packet_builder #(NUM_CHAN) rx_pkt_builer ( - .rxclk ( rxclk ), - .reset ( reset ), - .adctime ( adctime ), - .channels ( 4'd1 ), - .chan_rdreq ( chan_rdreq ), - .chan_fifodata ( chan_fifodata ), - .chan_empty ( chan_empty ), - .rd_select ( rd_select ), - .chan_usedw ( chan_usedw ), - .WR ( WR ), - .fifodata ( fifodata ), - .have_space ( have_space ), - .rssi_0(rssi_0), .rssi_1(rssi_1), - .rssi_2(rssi_2),.rssi_3(rssi_3), .debugbus(debug), - .overrun(tx_overrun), .underrun(tx_underrun)); - - // Detect overrun - always @(posedge rxclk) - if(reset) - rx_overrun <= 1'b0; - else if(rx_full[0]) - rx_overrun <= 1'b1; - else if(clear_status) - rx_overrun <= 1'b0; - - reg [6:0] test; - always @(posedge rxclk) - if (reset) - test <= 0; - else - test <= test + 7'd1; - - // TODO write this genericly - wire [15:0]ch[NUM_CHAN:0]; - assign ch[0] = ch_0; - - wire cmd_empty; - always @(posedge rxclk) - if(reset) - rx_WR_enabled <= 1; - else if(cmd_empty) - rx_WR_enabled <= 1; - else if(rx_WR_done) - rx_WR_enabled <= 0; - - wire [15:0] dataout [0:NUM_CHAN]; - wire [9:0] usedw [0:NUM_CHAN]; - wire empty[0:NUM_CHAN]; - - generate for (i = 0 ; i < NUM_CHAN; i = i + 1) - begin : generate_channel_fifos - wire rdreq; - - assign rdreq = (rd_select == i) & chan_rdreq; - //assign chan_empty[i] = usedw[i] < 10'd126; - fifo_1kx16 rx_chan_fifo ( - .aclr ( reset ), - .clock ( rxclk ), - .data ( ch[i] ), - .rdreq ( rdreq ), - .wrreq ( ~rx_full[i] & rxstrobe), - .empty (empty[i]), - .full (rx_full[i]), - .q ( dataout[i]), - .usedw ( usedw[i]), - .almost_empty(chan_empty[i]) - ); - end - endgenerate - wire [7:0] debug; - fifo_1kx16 rx_cmd_fifo ( - .aclr ( reset ), - .clock ( rxclk ), - .data ( rx_databus ), - .rdreq ( (rd_select == NUM_CHAN) & chan_rdreq ), - .wrreq ( rx_WR & rx_WR_enabled), - .empty ( cmd_empty), - .full ( rx_full[NUM_CHAN] ), - .q ( dataout[NUM_CHAN]), - .usedw ( usedw[NUM_CHAN] ) - ); - assign chan_empty[NUM_CHAN] = cmd_empty | rx_WR_enabled; - assign chan_fifodata = dataout[rd_select]; - assign chan_usedw = usedw[rd_select]; - assign debugbus = {rxstrobe, chan_rdreq, debug, - rx_full[0], chan_empty[0], empty[0], have_space, RD, rxclk}; -endmodule +//`include "../../firmware/include/fpga_regs_common.v"
+//`include "../../firmware/include/fpga_regs_standard.v"
+module rx_buffer_inband
+ ( input usbclk,
+ input bus_reset,
+ input reset, // DSP side reset (used here), do not reset registers
+ input reset_regs, //Only reset registers
+ output [15:0] usbdata,
+ input RD,
+ output wire have_pkt_rdy,
+ output reg rx_overrun,
+ input wire [3:0] channels,
+ input wire [15:0] ch_0,
+ input wire [15:0] ch_1,
+ input wire [15:0] ch_2,
+ input wire [15:0] ch_3,
+ input wire [15:0] ch_4,
+ input wire [15:0] ch_5,
+ input wire [15:0] ch_6,
+ input wire [15:0] ch_7,
+ input rxclk,
+ input rxstrobe,
+ input clear_status,
+ input [6:0] serial_addr,
+ input [31:0] serial_data,
+ input serial_strobe,
+ output wire [15:0] debugbus,
+
+ //Connection with tx_inband
+ input rx_WR,
+ input [15:0] rx_databus,
+ input rx_WR_done,
+ output reg rx_WR_enabled,
+ //signal strength
+ input wire [31:0] rssi_0, input wire [31:0] rssi_1,
+ input wire [31:0] rssi_2, input wire [31:0] rssi_3,
+ input wire [1:0] tx_underrun
+ );
+
+ parameter NUM_CHAN = 1;
+ genvar i ;
+
+ // FX2 Bug Fix
+ reg [8:0] read_count;
+ always @(negedge usbclk)
+ if(bus_reset)
+ read_count <= #1 9'd0;
+ else if(RD & ~read_count[8])
+ read_count <= #1 read_count + 9'd1;
+ else
+ read_count <= #1 RD ? read_count : 9'b0;
+
+ // Time counter
+ reg [31:0] timestamp_clock;
+ always @(posedge rxclk)
+ if (reset)
+ timestamp_clock <= 0;
+ else
+ timestamp_clock <= timestamp_clock + 1;
+
+ // USB side fifo
+ wire [11:0] rdusedw;
+ wire [11:0] wrusedw;
+ wire [15:0] fifodata;
+ wire [15:0] fifodata_il[0:NUM_CHAN];
+ wire WR;
+ wire have_space;
+ reg sel;
+ reg wr;
+
+ always@(posedge rxclk)
+ begin
+ if(reset)
+ begin
+ sel<=1;
+ wr<=0;
+ end
+ else if(rxstrobe)
+ begin
+ sel<=0;
+ wr<=1;
+ end
+ else if(wr&~sel)
+ sel<=1;
+ else if(wr&sel)
+ wr<=0;
+ else
+ wr<=0;
+ end
+
+ assign fifodata_il[0] = (sel)?ch_1:ch_0;
+ assign fifodata_il[1] = (sel)?ch_3:ch_2;
+
+ fifo_4kx16_dc rx_usb_fifo (
+ .aclr ( reset ),
+ .data ( fifodata ),
+ .rdclk ( ~usbclk ),
+ .rdreq ( RD & ~read_count[8] ),
+ .wrclk ( rxclk ),
+ .wrreq ( WR ),
+ .q ( usbdata ),
+ .rdempty ( ),
+ .rdusedw ( rdusedw ),
+ .wrfull ( ),
+ .wrusedw ( wrusedw ) );
+
+ assign have_pkt_rdy = (rdusedw >= 12'd256);
+ assign have_space = (wrusedw < 12'd760);
+
+ // Rx side fifos
+ // These are of size [NUM_CHAN:0] because the extra channel is used for the
+ // RX command channel. If there were no command channel, they would be
+ // NUM_CHAN-1.
+ wire chan_rdreq;
+ wire [15:0] chan_fifodata;
+ wire [9:0] chan_usedw;
+ wire [NUM_CHAN:0] chan_empty;
+ wire [3:0] rd_select;
+ wire [NUM_CHAN:0] rx_full;
+
+ packet_builder #(NUM_CHAN) rx_pkt_builer (
+ .rxclk ( rxclk ),
+ .reset ( reset ),
+ .timestamp_clock ( timestamp_clock ),
+ .channels ( NUM_CHAN ),
+ .chan_rdreq ( chan_rdreq ),
+ .chan_fifodata ( chan_fifodata ),
+ .chan_empty ( chan_empty ),
+ .rd_select ( rd_select ),
+ .chan_usedw ( chan_usedw ),
+ .WR ( WR ),
+ .fifodata ( fifodata ),
+ .have_space ( have_space ),
+ .rssi_0(rssi_0), .rssi_1(rssi_1),
+ .rssi_2(rssi_2),.rssi_3(rssi_3), .debugbus(debug),
+ .underrun(tx_underrun));
+
+ // Detect overrun
+ always @(posedge rxclk)
+ if(reset)
+ rx_overrun <= 1'b0;
+ else if(rx_full[0])
+ rx_overrun <= 1'b1;
+ else if(clear_status)
+ rx_overrun <= 1'b0;
+
+
+ // FIXME: what is the purpose of these two lines?
+ wire [15:0]ch[NUM_CHAN:0];
+ assign ch[0] = ch_0;
+
+ wire cmd_empty;
+
+ always @(posedge rxclk)
+ if(reset)
+ rx_WR_enabled <= 1;
+ else if(cmd_empty)
+ rx_WR_enabled <= 1;
+ else if(rx_WR_done)
+ rx_WR_enabled <= 0;
+
+
+ // Of Size 0:NUM_CHAN due to extra command channel.
+ wire [15:0] dataout [0:NUM_CHAN];
+ wire [9:0] usedw [0:NUM_CHAN];
+ wire empty[0:NUM_CHAN];
+
+ generate for (i = 0 ; i < NUM_CHAN; i = i + 1)
+ begin : generate_channel_fifos
+
+ wire rdreq;
+
+ assign rdreq = (rd_select == i) & chan_rdreq;
+
+ fifo_1kx16 rx_chan_fifo (
+ .aclr ( reset ),
+ .clock ( rxclk ),
+ .data ( fifodata_il[i] ),
+ .rdreq ( rdreq ),
+ .wrreq ( ~rx_full[i] & wr),
+ .empty (empty[i]),
+ .full (rx_full[i]),
+ .q ( dataout[i]),
+ .usedw ( usedw[i]),
+ .almost_empty(chan_empty[i])
+ );
+ end
+ endgenerate
+
+ wire [7:0] debug;
+
+ fifo_1kx16 rx_cmd_fifo (
+ .aclr ( reset ),
+ .clock ( rxclk ),
+ .data ( rx_databus ),
+ .rdreq ( (rd_select == NUM_CHAN) & chan_rdreq ),
+ .wrreq ( rx_WR & rx_WR_enabled),
+ .empty ( cmd_empty),
+ .full ( rx_full[NUM_CHAN] ),
+ .q ( dataout[NUM_CHAN]),
+ .usedw ( usedw[NUM_CHAN] )
+ );
+
+ assign chan_empty[NUM_CHAN] = cmd_empty | rx_WR_enabled;
+ assign chan_fifodata = dataout[rd_select];
+ assign chan_usedw = usedw[rd_select];
+ assign debugbus = {4'd0, rxclk, rxstrobe, rx_full[0], rx_full[1], sel, wr};
+
+endmodule
diff --git a/usrp/fpga/inband_lib/tx_buffer_inband.v b/usrp/fpga/inband_lib/tx_buffer_inband.v index fec9dbe31..2dd75f42f 100755 --- a/usrp/fpga/inband_lib/tx_buffer_inband.v +++ b/usrp/fpga/inband_lib/tx_buffer_inband.v @@ -1,224 +1,143 @@ module tx_buffer_inband - ( usbclk, bus_reset, reset, usbdata, WR, have_space, - channels, tx_i_0, tx_q_0, tx_i_1, tx_q_1, - tx_i_2, tx_q_2, tx_i_3, tx_q_3, txclk, txstrobe, - clear_status, tx_empty, debugbus, - rx_databus, rx_WR, rx_WR_done, rx_WR_enabled, reg_io_enable, - reg_data_in, reg_data_out, reg_addr, rssi_0, rssi_1, rssi_2, - rssi_3, rssi_wait, threshhold, tx_underrun - ); + ( //System + input wire usbclk, input wire bus_reset, input wire reset, + input wire [15:0] usbdata, output wire have_space, input wire [3:0] channels, + //output transmit signals + output wire [15:0] tx_i_0, output wire [15:0] tx_q_0, + output wire [15:0] tx_i_1, output wire [15:0] tx_q_1, + output wire [15:0] tx_i_2, output wire [15:0] tx_q_2, + output wire [15:0] tx_i_3, output wire [15:0] tx_q_3, + input wire txclk, input wire txstrobe, input wire WR, + input wire clear_status, output wire tx_empty, output wire [15:0] debugbus, + //command reader io + output wire [15:0] rx_databus, output wire rx_WR, output wire rx_WR_done, + input wire rx_WR_enabled, + //register io + output wire [1:0] reg_io_enable, output wire [31:0] reg_data_in, output wire [6:0] reg_addr, + input wire [31:0] reg_data_out, + //input characteristic signals + input wire [31:0] rssi_0, input wire [31:0] rssi_1, input wire [31:0] rssi_2, + input wire [31:0] rssi_3, input wire [31:0] rssi_wait, input wire [31:0] threshhold, + output wire [1:0] tx_underrun, + //system stop + output wire stop, output wire [15:0] stop_time); - parameter NUM_CHAN = 2 ; - /* Debug paramters */ - parameter STROBE_RATE_0 = 8'd1 ; - parameter STROBE_RATE_1 = 8'd2 ; + parameter NUM_CHAN = 1 ; - input wire usbclk ; - input wire bus_reset ; // Used here for the 257-Hack to fix the FX2 bug - input wire reset ; // standard DSP-side reset - input wire [15:0] usbdata ; - input wire WR ; - input wire txclk ; - input wire txstrobe ; - input wire rx_WR_enabled; - /* Not used yet */ - input wire [3:0] channels ; - input wire clear_status ; - /*register io*/ - input wire [31:0]reg_data_out; - // rssi - input wire [31:0]rssi_0; - input wire [31:0]rssi_1; - input wire [31:0]rssi_2; - input wire [31:0]rssi_3; - input wire [31:0]threshhold; - input wire [31:0]rssi_wait; - - output wire have_space ; - output wire tx_empty ; - output wire [15:0] tx_i_0 ; - output wire [15:0] tx_q_0 ; - output wire [15:0] tx_i_1 ; - output wire [15:0] tx_q_1 ; - output wire [15:0] debugbus ; - /* Not used yet */ - output wire [15:0] tx_i_2 ; - output wire [15:0] tx_q_2 ; - output wire [15:0] tx_i_3 ; - output wire [15:0] tx_q_3 ; - - output wire [15:0] rx_databus ; - output wire rx_WR; - output wire rx_WR_done; - /* reg_io */ - output wire [31:0] reg_data_in; - output wire [6:0] reg_addr; - output wire [1:0] reg_io_enable; - output wire [NUM_CHAN-1:0] tx_underrun; - - /* To generate channel readers */ - genvar i ; + /* To generate channel readers */ + genvar i ; - /* These will eventually be external register */ - reg [31:0] adc_time ; - wire [7:0] txstrobe_rate [NUM_CHAN-1:0] ; - wire [31:0] rssi [3:0]; - assign rssi[0] = rssi_0; - assign rssi[1] = rssi_1; - assign rssi[2] = rssi_2; - assign rssi[3] = rssi_3; + /* These will eventually be external register */ + reg [31:0] timestamp_clock ; + wire [7:0] txstrobe_rate [NUM_CHAN-1:0] ; + wire [31:0] rssi [3:0]; + assign rssi[0] = rssi_0; + assign rssi[1] = rssi_1; + assign rssi[2] = rssi_2; + assign rssi[3] = rssi_3; - always @(posedge txclk) - if (reset) - adc_time <= 0; - else if (txstrobe) - adc_time <= adc_time + 1; + always @(posedge txclk) + if (reset) + timestamp_clock <= 0; + else + timestamp_clock <= timestamp_clock + 1; /* Connections between tx_usb_fifo_reader and cnannel/command processing blocks */ - wire [31:0] tx_data_bus ; - wire [NUM_CHAN:0] chan_WR ; - wire [NUM_CHAN:0] chan_done ; + wire [31:0] tx_data_bus ; + wire [NUM_CHAN:0] chan_WR ; + wire [NUM_CHAN:0] chan_done ; /* Connections between data block and the FX2/TX chains */ - wire [NUM_CHAN:0] chan_underrun ; - wire [NUM_CHAN:0] chan_txempty ; + wire [NUM_CHAN:0] chan_underrun; + wire [NUM_CHAN:0] chan_txempty; - /* Conections between tx_data_packet_fifo and + /* Conections between tx_data_packet_fifo and its reader + strobe generator */ - wire [31:0] chan_fifodata [NUM_CHAN:0] ; - wire chan_pkt_waiting [NUM_CHAN:0] ; - wire chan_rdreq [NUM_CHAN:0] ; - wire chan_skip [NUM_CHAN:0] ; - wire [NUM_CHAN:0] chan_have_space ; - wire chan_txstrobe [NUM_CHAN-1:0] ; + wire [31:0] chan_fifodata [NUM_CHAN:0] ; + wire chan_pkt_waiting [NUM_CHAN:0] ; + wire chan_rdreq [NUM_CHAN:0] ; + wire chan_skip [NUM_CHAN:0] ; + wire chan_have_space [NUM_CHAN:0] ; - wire [14:0] debug; + wire [14:0] debug [NUM_CHAN:0]; - /* Outputs to transmit chains */ - wire [15:0] tx_i [NUM_CHAN-1:0] ; - wire [15:0] tx_q [NUM_CHAN-1:0] ; + /* Outputs to transmit chains */ + wire [15:0] tx_i [NUM_CHAN:0] ; + wire [15:0] tx_q [NUM_CHAN:0] ; + + assign tx_i[NUM_CHAN] = 0; + assign tx_q[NUM_CHAN] = 0; - /* TODO: Figure out how to write this genericly */ - assign have_space = chan_have_space[0] & chan_have_space[1]; - assign tx_empty = chan_txempty[0] & chan_txempty[1] ; - assign tx_i_0 = chan_txempty[0] ? 16'b0 : tx_i[0] ; - assign tx_q_0 = chan_txempty[0] ? 16'b0 : tx_q[0] ; - assign tx_i_1 = chan_txempty[1] ? 16'b0 : tx_i[1] ; - assign tx_q_1 = chan_txempty[1] ? 16'b0 : tx_q[1] ; + assign have_space = chan_have_space[0] & chan_have_space[1]; + assign tx_empty = chan_txempty[0] & chan_txempty[1] ; + + assign tx_i_0 = chan_txempty[0] ? 16'b0 : tx_i[0] ; + assign tx_q_0 = chan_txempty[0] ? 16'b0 : tx_q[0] ; + assign tx_i_1 = chan_txempty[1] ? 16'b0 : tx_i[1] ; + assign tx_q_1 = chan_txempty[1] ? 16'b0 : tx_q[1] ; - /* Debug statement */ - assign txstrobe_rate[0] = STROBE_RATE_0 ; - assign txstrobe_rate[1] = STROBE_RATE_1 ; - assign tx_q_2 = 16'b0 ; - assign tx_i_2 = 16'b0 ; - assign tx_q_3 = 16'b0 ; - assign tx_i_3 = 16'b0 ; - assign tx_i_3 = 16'b0 ; + assign tx_q_2 = 16'b0 ; + assign tx_i_2 = 16'b0 ; + assign tx_q_3 = 16'b0 ; + assign tx_i_3 = 16'b0 ; + assign tx_i_3 = 16'b0 ; - assign debugbus = {debug, txclk}; + assign debugbus = {have_space, txclk, WR, WR_final, chan_WR, chan_done, + chan_pkt_waiting[0], chan_pkt_waiting[1], + chan_rdreq[0], chan_rdreq[1], chan_txempty[0], chan_txempty[1]}; - wire [31:0] usbdata_final; - wire WR_final; + wire [31:0] usbdata_final; + wire WR_final; - tx_packer tx_usb_packer - ( - .bus_reset (bus_reset), - .usbclk (usbclk), - .WR_fx2 (WR), - .usbdata (usbdata), - .reset (reset), - .txclk (txclk), - .usbdata_final (usbdata_final), - .WR_final (WR_final) - ); + tx_packer tx_usb_packer + (.bus_reset(bus_reset), .usbclk(usbclk), .WR_fx2(WR), + .usbdata(usbdata), .reset(reset), .txclk(txclk), + .usbdata_final(usbdata_final), .WR_final(WR_final)); - channel_demux channel_demuxer - ( - .usbdata_final (usbdata_final), - .WR_final (WR_final), - .reset (reset), - .txclk (txclk), - .WR_channel (chan_WR), - .WR_done_channel (chan_done), - .ram_data (tx_data_bus) - ); + channel_demux #(NUM_CHAN) channel_demuxer + (.usbdata_final(usbdata_final), .WR_final(WR_final), + .reset(reset), .txclk(txclk), .WR_channel(chan_WR), + .WR_done_channel(chan_done), .ram_data(tx_data_bus)); - generate for (i = 0 ; i < NUM_CHAN; i = i + 1) - begin : generate_channel_readers - assign tx_underrun[i] = chan_underrun[i]; - channel_ram tx_data_packet_fifo - ( .reset (reset), - .txclk (txclk), - .datain (tx_data_bus), - .WR (chan_WR[i]), - .WR_done (chan_done[i]), - .have_space (chan_have_space[i]), - .dataout (chan_fifodata[i]), - .packet_waiting (chan_pkt_waiting[i]), - .RD (chan_rdreq[i]), - .RD_done (chan_skip[i]) - ); + generate for (i = 0 ; i < NUM_CHAN; i = i + 1) + begin : generate_channel_readers + assign tx_underrun[i] = chan_underrun[i]; - chan_fifo_reader tx_chan_reader - ( .reset (reset), - .tx_clock (txclk), - .tx_strobe (txstrobe), - .adc_time (adc_time), - .samples_format (4'b0), - .tx_q (tx_q[i]), - .tx_i (tx_i[i]), - .underrun (chan_underrun[i]), - .skip (chan_skip[i]), - .rdreq (chan_rdreq[i]), - .fifodata (chan_fifodata[i]), - .pkt_waiting (chan_pkt_waiting[i]), - .tx_empty (chan_txempty[i]), - .rssi (rssi[i]), - .threshhold (threshhold), - .rssi_wait (rssi_wait) - ); - + channel_ram tx_data_packet_fifo + (.reset(reset), .txclk(txclk), .datain(tx_data_bus), + .WR(chan_WR[i]), .WR_done(chan_done[i]), + .have_space(chan_have_space[i]), .dataout(chan_fifodata[i]), + .packet_waiting(chan_pkt_waiting[i]), .RD(chan_rdreq[i]), + .RD_done(chan_skip[i])); + + chan_fifo_reader tx_chan_reader + (.reset(reset), .tx_clock(txclk), .tx_strobe(txstrobe), + .timestamp_clock(timestamp_clock), .samples_format(4'b0), + .tx_q(tx_q[i]), .tx_i(tx_i[i]), .underrun(chan_underrun[i]), + .skip(chan_skip[i]), .rdreq(chan_rdreq[i]), + .fifodata(chan_fifodata[i]), .pkt_waiting(chan_pkt_waiting[i]), + .tx_empty(chan_txempty[i]), .rssi(rssi[i]), .debug(debug[i]), + .threshhold(threshhold), .rssi_wait(rssi_wait)); end endgenerate - channel_ram tx_cmd_packet_fifo - ( .reset (reset), - .txclk (txclk), - .datain (tx_data_bus), - .WR (chan_WR[NUM_CHAN]), - .WR_done (chan_done[NUM_CHAN]), - .have_space (chan_have_space[NUM_CHAN]), - .dataout (chan_fifodata[NUM_CHAN]), - .packet_waiting (chan_pkt_waiting[NUM_CHAN]), - .RD (chan_rdreq[NUM_CHAN]), - .RD_done (chan_skip[NUM_CHAN]) - ); + channel_ram tx_cmd_packet_fifo + (.reset(reset), .txclk(txclk), .datain(tx_data_bus), .WR(chan_WR[NUM_CHAN]), + .WR_done(chan_done[NUM_CHAN]), .have_space(chan_have_space[NUM_CHAN]), + .dataout(chan_fifodata[NUM_CHAN]), .packet_waiting(chan_pkt_waiting[NUM_CHAN]), + .RD(chan_rdreq[NUM_CHAN]), .RD_done(chan_skip[NUM_CHAN])); - - cmd_reader tx_cmd_reader - ( .reset (reset), - .txclk (txclk), - .adc_time (adc_time), - .skip (chan_skip[NUM_CHAN]), - .rdreq (chan_rdreq[NUM_CHAN]), - .fifodata (chan_fifodata[NUM_CHAN]), - .pkt_waiting (chan_pkt_waiting[NUM_CHAN]), - .rx_databus (rx_databus), - .rx_WR (rx_WR), - .rx_WR_done (rx_WR_done), - .rx_WR_enabled (rx_WR_enabled), - .reg_data_in (reg_data_in), - .reg_data_out (reg_data_out), - .reg_addr (reg_addr), - .reg_io_enable (reg_io_enable), - .debug (debug) - ); - - - + cmd_reader tx_cmd_reader + (.reset(reset), .txclk(txclk), .timestamp_clock(timestamp_clock), .skip(chan_skip[NUM_CHAN]), + .rdreq(chan_rdreq[NUM_CHAN]), .fifodata(chan_fifodata[NUM_CHAN]), + .pkt_waiting(chan_pkt_waiting[NUM_CHAN]), .rx_databus(rx_databus), + .rx_WR(rx_WR), .rx_WR_done(rx_WR_done), .rx_WR_enabled(rx_WR_enabled), + .reg_data_in(reg_data_in), .reg_data_out(reg_data_out), .reg_addr(reg_addr), + .reg_io_enable(reg_io_enable), .debug(debug[NUM_CHAN]), .stop(stop), .stop_time(stop_time)); + endmodule // tx_buffer diff --git a/usrp/fpga/inband_lib/usb_fifo_reader.v b/usrp/fpga/inband_lib/usb_fifo_reader.v deleted file mode 100755 index d002d90ff..000000000 --- a/usrp/fpga/inband_lib/usb_fifo_reader.v +++ /dev/null @@ -1,25 +0,0 @@ -module usb_fifo_reader ( - input usbclk, - input bus_reset, - input RD, - output rdreq, - ); - - // FX2 Bug Fix - reg [8:0] read_count; - always @(negedge usbclk) - if(bus_reset) - read_count <= #1 9'd0; - else if(RD & ~read_count[8]) - read_count <= #1 read_count + 9'd1; - else - read_count <= #1 RD ? read_count : 9'b0; - - assign rdreq = RD & ~read_count[8]; - - - -endmodule - - -
\ No newline at end of file diff --git a/usrp/fpga/inband_lib/usb_fifo_writer.v b/usrp/fpga/inband_lib/usb_fifo_writer.v deleted file mode 100755 index abe1dd567..000000000 --- a/usrp/fpga/inband_lib/usb_fifo_writer.v +++ /dev/null @@ -1,183 +0,0 @@ - -module usb_fifo_writer - #(parameter BUS_WIDTH = 16, - parameter NUM_CHAN = 2, - parameter FIFO_WIDTH = 32) - ( //FX2 Side - input bus_reset, - input usbclk, - input WR_fx2, - input [15:0]usbdata, - - // TX Side - input reset, - input txclk, - output reg [NUM_CHAN:0] WR_channel, - output reg [FIFO_WIDTH-1:0] ram_data, - output reg [NUM_CHAN:0] WR_done_channel ); - - - reg [8:0] write_count; - - /* Fix FX2 bug */ - always @(posedge usbclk) - if(bus_reset) // Use bus reset because this is on usbclk - write_count <= #1 0; - else if(WR_fx2 & ~write_count[8]) - write_count <= #1 write_count + 9'd1; - else - write_count <= #1 WR_fx2 ? write_count : 9'b0; - - reg WR_fx2_fixed; - reg [15:0]usbdata_fixed; - - always @(posedge usbclk) - begin - WR_fx2_fixed <= WR_fx2 & ~write_count[8]; - usbdata_fixed <= usbdata; - end - - /* Used to convert 16 bits bus_data to the 32 bits wide fifo */ - reg word_complete ; - reg [BUS_WIDTH-1:0] usbdata_delayed ; - reg writing ; - wire [FIFO_WIDTH-1:0] usbdata_packed ; - wire WR_packed ; - - always @(posedge usbclk) - begin - if (bus_reset) - begin - word_complete <= 0 ; - writing <= 0 ; - end - else if (WR_fx2_fixed) - begin - writing <= 1 ; - if (word_complete) - word_complete <= 0 ; - else - begin - usbdata_delayed <= usbdata_fixed ; - word_complete <= 1 ; - end - end - else - writing <= 0 ; - end - - assign usbdata_packed = {usbdata_fixed, usbdata_delayed} ; - assign WR_packed = word_complete & writing ; - - /* Make sure data are sync with usbclk */ - reg [31:0]usbdata_usbclk; - reg WR_usbclk; - - always @(posedge usbclk) - begin - if (WR_packed) - usbdata_usbclk <= usbdata_packed; - WR_usbclk <= WR_packed; - end - - /* Cross clock boundaries */ - reg [FIFO_WIDTH-1:0] usbdata_tx ; - reg WR_tx; - reg WR_1; - reg WR_2; - reg [31:0] usbdata_final; - reg WR_final; - - always @(posedge txclk) usbdata_tx <= usbdata_usbclk; - - always @(posedge txclk) - if (reset) - WR_1 <= 0; - else - WR_1 <= WR_usbclk; - - always @(posedge txclk) - if (reset) - WR_2 <= 0; - else - WR_2 <= WR_1; - - always @(posedge txclk) - begin - if (reset) - WR_tx <= 0; - else - WR_tx <= WR_1 & ~WR_2; - end - - always @(posedge txclk) - begin - if (reset) - WR_final <= 0; - else - begin - WR_final <= WR_tx; - if (WR_tx) - usbdata_final <= usbdata_tx; - end - end - - /* Parse header and forward to ram */ - reg [3:0]reader_state; - reg [4:0]channel ; - reg [9:0]read_length ; - - parameter IDLE = 4'd0; - parameter HEADER = 4'd1; - parameter WAIT = 4'd2; - parameter FORWARD = 4'd3; - - `define CHANNEL 20:16 - `define PKT_SIZE 512 - - always @(posedge txclk) - begin - if (reset) - begin - reader_state <= 0; - WR_channel <= 0; - WR_done_channel <= 0; - end - else - case (reader_state) - IDLE: begin - if (WR_final) - reader_state <= HEADER; - end - - // Store channel and forware header - HEADER: begin - channel <= (usbdata_final[`CHANNEL] == 5'h1f ? NUM_CHAN : usbdata_final[`CHANNEL]) ; - WR_channel[(usbdata_final[`CHANNEL] == 5'h1f ? NUM_CHAN : usbdata_final[`CHANNEL])] <= 1; - //channel <= usbdata_final[`CHANNEL] ; - //WR_channel[usbdata_final[`CHANNEL]] <= 1; - ram_data <= usbdata_final; - read_length <= 10'd4 ; - - reader_state <= WAIT; - end - - WAIT: begin - WR_channel[channel] <= 0; - - if (read_length == `PKT_SIZE) - reader_state <= IDLE; - else if (WR_final) - reader_state <= FORWARD; - end - - FORWARD: begin - WR_channel[channel] <= 1; - ram_data <= usbdata_final; - read_length <= read_length + 10'd4; - - reader_state <= WAIT; - end - endcase - end -endmodule
\ No newline at end of file diff --git a/usrp/fpga/megacells/fifo_1kx16.bsf b/usrp/fpga/megacells/fifo_1kx16.bsf index 329be2d44..2de80816f 100755 --- a/usrp/fpga/megacells/fifo_1kx16.bsf +++ b/usrp/fpga/megacells/fifo_1kx16.bsf @@ -95,7 +95,7 @@ applicable agreement for further details. )
(drawing
(text "16 bits x 1024 words" (rect 58 132 144 144)(font "Arial" ))
- (text "almost_empty < 126" (rect 58 122 144 134)(font "Arial" ))
+ (text "almost_empty < 504" (rect 58 122 144 134)(font "Arial" ))
(line (pt 16 16)(pt 144 16)(line_width 1))
(line (pt 144 16)(pt 144 144)(line_width 1))
(line (pt 144 144)(pt 16 144)(line_width 1))
diff --git a/usrp/fpga/megacells/fifo_1kx16.v b/usrp/fpga/megacells/fifo_1kx16.v index e22b416e5..4f7e94ef5 100755 --- a/usrp/fpga/megacells/fifo_1kx16.v +++ b/usrp/fpga/megacells/fifo_1kx16.v @@ -86,7 +86,7 @@ module fifo_1kx16 ( );
defparam
scfifo_component.add_ram_output_register = "OFF",
- scfifo_component.almost_empty_value = 126,
+ scfifo_component.almost_empty_value = 504,
scfifo_component.intended_device_family = "Cyclone",
scfifo_component.lpm_hint = "RAM_BLOCK_TYPE=M4K",
scfifo_component.lpm_numwords = 1024,
@@ -105,7 +105,7 @@ endmodule // CNX file retrieval info
// ============================================================
// Retrieval info: PRIVATE: AlmostEmpty NUMERIC "1"
-// Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "126"
+// Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "504"
// Retrieval info: PRIVATE: AlmostFull NUMERIC "0"
// Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1"
// Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0"
@@ -133,7 +133,7 @@ endmodule // Retrieval info: PRIVATE: wsFull NUMERIC "1"
// Retrieval info: PRIVATE: wsUsedW NUMERIC "0"
// Retrieval info: CONSTANT: ADD_RAM_OUTPUT_REGISTER STRING "OFF"
-// Retrieval info: CONSTANT: ALMOST_EMPTY_VALUE NUMERIC "126"
+// Retrieval info: CONSTANT: ALMOST_EMPTY_VALUE NUMERIC "504"
// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone"
// Retrieval info: CONSTANT: LPM_HINT STRING "RAM_BLOCK_TYPE=M4K"
// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "1024"
diff --git a/usrp/fpga/megacells/fifo_1kx16_bb.v b/usrp/fpga/megacells/fifo_1kx16_bb.v index 283aada81..9d9912bc2 100755 --- a/usrp/fpga/megacells/fifo_1kx16_bb.v +++ b/usrp/fpga/megacells/fifo_1kx16_bb.v @@ -57,7 +57,7 @@ endmodule // CNX file retrieval info
// ============================================================
// Retrieval info: PRIVATE: AlmostEmpty NUMERIC "1"
-// Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "126"
+// Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "504"
// Retrieval info: PRIVATE: AlmostFull NUMERIC "0"
// Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1"
// Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0"
@@ -85,7 +85,7 @@ endmodule // Retrieval info: PRIVATE: wsFull NUMERIC "1"
// Retrieval info: PRIVATE: wsUsedW NUMERIC "0"
// Retrieval info: CONSTANT: ADD_RAM_OUTPUT_REGISTER STRING "OFF"
-// Retrieval info: CONSTANT: ALMOST_EMPTY_VALUE NUMERIC "126"
+// Retrieval info: CONSTANT: ALMOST_EMPTY_VALUE NUMERIC "504"
// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone"
// Retrieval info: CONSTANT: LPM_HINT STRING "RAM_BLOCK_TYPE=M4K"
// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "1024"
diff --git a/usrp/fpga/rbf/Makefile.am b/usrp/fpga/rbf/Makefile.am index 49d2f2592..c7c9ce670 100644 --- a/usrp/fpga/rbf/Makefile.am +++ b/usrp/fpga/rbf/Makefile.am @@ -26,8 +26,12 @@ datadir = $(prefix)/share/usrp rbfs = \ rev2/std_2rxhb_2tx.rbf \ rev2/std_4rx_0tx.rbf \ + rev2/inband_1rxhb_1tx.rbf \ + rev2/inband_2rxhb_2tx.rbf \ rev4/std_2rxhb_2tx.rbf \ rev4/std_4rx_0tx.rbf \ + rev4/inband_1rxhb_1tx.rbf \ + rev4/inband_2rxhb_2tx.rbf \ rev2/multi_2rxhb_2tx.rbf \ rev4/multi_2rxhb_2tx.rbf diff --git a/usrp/fpga/rbf/rev2/inband_1rxhb_1tx.rbf b/usrp/fpga/rbf/rev2/inband_1rxhb_1tx.rbf Binary files differnew file mode 100755 index 000000000..c1c9af2ce --- /dev/null +++ b/usrp/fpga/rbf/rev2/inband_1rxhb_1tx.rbf diff --git a/usrp/fpga/rbf/rev2/inband_2rxhb_2tx.rbf b/usrp/fpga/rbf/rev2/inband_2rxhb_2tx.rbf Binary files differnew file mode 100755 index 000000000..ca1a0f92b --- /dev/null +++ b/usrp/fpga/rbf/rev2/inband_2rxhb_2tx.rbf diff --git a/usrp/fpga/rbf/rev4/inband_1rxhb_1tx.rbf b/usrp/fpga/rbf/rev4/inband_1rxhb_1tx.rbf Binary files differnew file mode 100755 index 000000000..c1c9af2ce --- /dev/null +++ b/usrp/fpga/rbf/rev4/inband_1rxhb_1tx.rbf diff --git a/usrp/fpga/rbf/rev4/inband_2rxhb_2tx.rbf b/usrp/fpga/rbf/rev4/inband_2rxhb_2tx.rbf Binary files differnew file mode 100755 index 000000000..ca1a0f92b --- /dev/null +++ b/usrp/fpga/rbf/rev4/inband_2rxhb_2tx.rbf diff --git a/usrp/fpga/toplevel/usrp_inband_usb/config.vh b/usrp/fpga/toplevel/usrp_inband_usb/config.vh index 3291dc10b..007a529e3 100644 --- a/usrp/fpga/toplevel/usrp_inband_usb/config.vh +++ b/usrp/fpga/toplevel/usrp_inband_usb/config.vh @@ -34,7 +34,7 @@ `include "../include/common_config_1rxhb_1tx.vh" // Uncomment this for 2 rx channels (w/ halfband) & 2 transmit channels -//`include "../include/common_config_2rxhb_2tx.vh" +// `include "../include/common_config_2rxhb_2tx.vh" // Uncomment this for 4 rx channels (w/o halfband) & 0 transmit channels //`include "../include/common_config_4rx_0tx.vh" diff --git a/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.qsf b/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.qsf index c9eebc1ad..ae0807f6f 100644 --- a/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.qsf +++ b/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.qsf @@ -27,7 +27,7 @@ # ======================== set_global_assignment -name ORIGINAL_QUARTUS_VERSION 3.0 set_global_assignment -name PROJECT_CREATION_TIME_DATE "00:14:04 JULY 13, 2003" -set_global_assignment -name LAST_QUARTUS_VERSION "5.1 SP1" +set_global_assignment -name LAST_QUARTUS_VERSION "7.2 SP2" # Pin & Location Assignments # ========================== @@ -392,7 +392,6 @@ set_global_assignment -name VERILOG_FILE ../../sdr_lib/hb/ram16_2sum.v set_global_assignment -name VERILOG_FILE ../../sdr_lib/hb/coeff_rom.v set_global_assignment -name VERILOG_FILE ../../sdr_lib/hb/halfband_decim.v set_global_assignment -name VERILOG_FILE ../../sdr_lib/hb/mac.v -set_global_assignment -name VERILOG_FILE ../../sdr_lib/hb/coeff_ram.v set_global_assignment -name VERILOG_FILE ../../sdr_lib/tx_chain.v set_global_assignment -name VERILOG_FILE ../../sdr_lib/rx_dcoffset.v set_global_assignment -name VERILOG_FILE ../../sdr_lib/adc_interface.v @@ -419,4 +418,6 @@ set_global_assignment -name VERILOG_FILE ../../sdr_lib/serial_io.v set_global_assignment -name VERILOG_FILE ../../sdr_lib/strobe_gen.v set_global_assignment -name VERILOG_FILE ../../sdr_lib/sign_extend.v set_global_assignment -name VERILOG_FILE ../../inband_lib/channel_ram.v -set_global_assignment -name VERILOG_FILE ../../inband_lib/register_io.v
\ No newline at end of file +set_global_assignment -name VERILOG_FILE ../../inband_lib/register_io.v +set_global_assignment -name LL_ROOT_REGION ON -section_id "Root Region" +set_global_assignment -name LL_MEMBER_STATE LOCKED -section_id "Root Region"
\ No newline at end of file diff --git a/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.v b/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.v index cc625b0e7..79f0dfa4a 100644 --- a/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.v +++ b/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.v @@ -97,8 +97,6 @@ module usrp_inband_usb // Tri-state bus macro bustri bustri( .data(usbdata_out),.enabledt(OE),.tridata(usbdata) ); - assign clk64 = master_clk; - wire [15:0] ch0tx,ch1tx,ch2tx,ch3tx; //,ch4tx,ch5tx,ch6tx,ch7tx; wire [15:0] ch0rx,ch1rx,ch2rx,ch3rx,ch4rx,ch5rx,ch6rx,ch7rx; @@ -129,19 +127,7 @@ module usrp_inband_usb assign bb_tx_q0 = ch1tx; assign bb_tx_i1 = ch2tx; assign bb_tx_q1 = ch3tx; - -wire [6:0] reg_addr; -wire [31:0] reg_data_out; -wire [31:0] reg_data_in; -wire [1:0] reg_io_enable; -wire [31:0] rssi_threshhold; -wire [31:0] rssi_wait; - -register_io register_control -(.clk(clk64),.reset(1'b0),.enable(reg_io_enable),.addr(reg_addr),.datain(reg_data_in), - .dataout(reg_data_out),.rssi_0(rssi_0), .rssi_1(rssi_1), .rssi_2(rssi_2), - .rssi_3(rssi_3), .threshhold(rssi_threshhold), .rssi_wait(rssi_wait)); -wire [1:0] tx_overrun; + wire [1:0] tx_underrun; `ifdef TX_IN_BAND @@ -164,9 +150,15 @@ wire [1:0] tx_underrun; .reg_data_out(reg_data_out), .reg_data_in(reg_data_in), .reg_io_enable(reg_io_enable), - .debugbus(), + .debugbus(rx_debugbus), .rssi_0(rssi_0), .rssi_1(rssi_1), .rssi_2(rssi_2), - .rssi_3(rssi_3), .threshhold(rssi_threshhold), .rssi_wait(rssi_wait)); + .rssi_3(rssi_3), .threshhold(rssi_threshhold), .rssi_wait(rssi_wait), + .stop(stop), .stop_time(stop_time)); + + `ifdef TX_DUAL + defparam tx_buffer.NUM_CHAN=2; + `endif + `else tx_buffer tx_buffer ( .usbclk(usbclk),.bus_reset(tx_bus_reset),.reset(tx_dsp_reset), @@ -276,14 +268,18 @@ wire [1:0] tx_underrun; .ch_6(ch6rx),.ch_7(ch7rx), .rxclk(clk64),.rxstrobe(hb_strobe), .clear_status(clear_status), - .serial_addr(serial_addr),.serial_data(serial_data),.serial_strobe(serial_strobe), .rx_WR(rx_WR), .rx_databus(rx_databus), .rx_WR_done(rx_WR_done), .rx_WR_enabled(rx_WR_enabled), .debugbus(tx_debugbus), .rssi_0(rssi_0), .rssi_1(rssi_1), .rssi_2(rssi_2), .rssi_3(rssi_3), - .tx_overrun(tx_overrun), .tx_underrun(tx_underrun)); + .tx_underrun(tx_underrun)); + + `ifdef RX_DUAL + defparam rx_buffer.NUM_CHAN=2; + `endif + `else rx_buffer rx_buffer ( .usbclk(usbclk),.bus_reset(rx_bus_reset),.reset(rx_dsp_reset), @@ -357,11 +353,52 @@ wire [1:0] tx_underrun; serial_io serial_io ( .master_clk(clk64),.serial_clock(SCLK),.serial_data_in(SDI), .enable(SEN_FPGA),.reset(1'b0),.serial_data_out(SDO), - .serial_addr(serial_addr),.serial_data(serial_data),.serial_strobe(serial_strobe), + .serial_addr(addr_db),.serial_data(data_db),.serial_strobe(strobe_db), .readback_0({io_rx_a,io_tx_a}),.readback_1({io_rx_b,io_tx_b}),.readback_2(capabilities),.readback_3(32'hf0f0931a), .readback_4(rssi_0),.readback_5(rssi_1),.readback_6(rssi_2),.readback_7(rssi_3) ); + wire [6:0] reg_addr; + wire [31:0] reg_data_out; + wire [31:0] reg_data_in; + wire [1:0] reg_io_enable; + wire [31:0] rssi_threshhold; + wire [31:0] rssi_wait; + wire [6:0] addr_wr; + wire [31:0] data_wr; + wire strobe_wr; + wire [6:0] addr_db; + wire [31:0] data_db; + wire strobe_db; + assign serial_strobe = strobe_db | strobe_wr; + assign serial_addr = (strobe_db)? (addr_db) : (addr_wr); + assign serial_data = (strobe_db)? (data_db) : (data_wr); + //assign serial_strobe = strobe_wr; + //assign serial_data = data_wr; + //assign serial_addr = addr_wr; + + register_io register_control + (.clk(clk64),.reset(1'b0),.enable(reg_io_enable),.addr(reg_addr),.datain(reg_data_in), + .dataout(reg_data_out), .addr_wr(addr_wr), .data_wr(data_wr), .strobe_wr(strobe_wr), + .rssi_0(rssi_0), .rssi_1(rssi_1), .rssi_2(rssi_2), + .rssi_3(rssi_3), .threshhold(rssi_threshhold), .rssi_wait(rssi_wait), + .reg_0(reg_0),.reg_1(reg_1),.reg_2(reg_2),.reg_3(reg_3), + .debug_en(debug_en), .misc(settings), + .txmux({dac3mux,dac2mux,dac1mux,dac0mux,tx_realsignals,tx_numchan})); + + + //implementing freeze mode + reg [15:0] timestop; + wire stop; + wire [15:0] stop_time; + assign clk64 = (timestop == 0) ? master_clk : 0; + always @(posedge master_clk) + if (timestop[15:0] != 0) + timestop <= timestop - 16'd1; + else if (stop) + timestop <= stop_time; + + wire [15:0] reg_0,reg_1,reg_2,reg_3; master_control master_control ( .master_clk(clk64),.usbclk(usbclk), @@ -374,8 +411,8 @@ wire [1:0] tx_underrun; .rx_sample_strobe(rx_sample_strobe),.strobe_decim(strobe_decim), .tx_empty(tx_empty), //.debug_0(rx_a_a),.debug_1(ddc0_in_i), - .debug_0(tx_debugbus),.debug_1(tx_debugbus), - .debug_2({rx_sample_strobe,strobe_decim,serial_strobe,serial_addr}),.debug_3({rx_dsp_reset,tx_dsp_reset,rx_bus_reset,tx_bus_reset,enable_rx,(tx_underrun == 0),rx_overrun,decim_rate}), + .debug_0(rx_debugbus),.debug_1(ddc0_in_i), + .debug_2({rx_sample_strobe,strobe_decim,serial_strobe,serial_addr}),.debug_3({rx_dsp_reset,tx_dsp_reset,rx_bus_reset,tx_bus_reset,enable_rx,tx_underrun,rx_overrun,decim_rate}), .reg_0(reg_0),.reg_1(reg_1),.reg_2(reg_2),.reg_3(reg_3) ); io_pins io_pins diff --git a/usrp/host/apps-inband/Makefile.am b/usrp/host/apps-inband/Makefile.am index 86bb40618..f231b57f7 100644 --- a/usrp/host/apps-inband/Makefile.am +++ b/usrp/host/apps-inband/Makefile.am @@ -30,46 +30,31 @@ AM_CPPFLAGS = \ bin_PROGRAMS = noinst_PROGRAMS = \ - test_usrp_inband_cs \ 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 \ - test_gmac_tx \ read_packets noinst_HEADERS = \ ui_nco.h \ - ui_sincos.h \ - gmac.h \ - gmac_symbols.h + ui_sincos.h -EXTRA_DIST = \ - gmac.mbh - -#------------------------------------------------------------------ -# Build gmac sources - -BUILT_SOURCES = \ - gmac_mbh.cc - -gmac_mbh.cc : gmac.mbh - $(COMPILE_MBH) $(srcdir)/gmac.mbh gmac_mbh.cc - - -test_usrp_inband_cs_SOURCES = test_usrp_inband_cs.cc ui_sincos.c -test_usrp_inband_cs_LDADD = $(USRP_LA) $(USRP_INBAND_LA) - 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) @@ -85,8 +70,8 @@ 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_gmac_tx_SOURCES = test_gmac_tx.cc gmac.cc gmac_mbh.cc ui_sincos.c -test_gmac_tx_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/host/apps-inband/gmac.cc b/usrp/host/apps-inband/gmac.cc deleted file mode 100644 index 107582e12..000000000 --- a/usrp/host/apps-inband/gmac.cc +++ /dev/null @@ -1,690 +0,0 @@ -/* -*- 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 <gmac.h> - -#include <mb_mblock.h> -#include <mb_runtime.h> -#include <mb_protocol_class.h> -#include <mb_exception.h> -#include <mb_msg_queue.h> -#include <mb_message.h> -#include <mb_msg_accepter.h> -#include <mb_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> -#include <symbols_usrp_rx.h> - -#include <gmac_symbols.h> - -static bool verbose = true; - -gmac::gmac(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg) - : mb_mblock(rt, instance_name, user_arg), - d_us_rx_chan(PMT_NIL), d_us_tx_chan(PMT_NIL) -{ - - // When the MAC layer is initialized, we must connect to the USRP and setup - // channels. We begin by defining ports to connect to the 'usrp_server' block - // and then initialize the USRP by opening it through the 'usrp_server.' - - // Initialize the ports - define_ports(); - - // Initialize the connection to the USRP - initialize_usrp(); - -} - -gmac::~gmac() -{ -} - -// The full functionality of GMAC is based on messages passed back and forth -// between the application and a physical layer and/or usrp_server. Each -// message triggers additional events, states, and messages to be sent. -void gmac::handle_message(mb_message_sptr msg) -{ - - // The MAC functionality is dispatched based on the event, which is the - // driving force of the MAC. The event can be anything from incoming samples - // to a message to change the carrier sense threshold. - 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; - - switch(d_state) { - - //---------------------------- INIT ------------------------------------// - // In the INIT state, there should be no messages across the ports. - case INIT: - error_msg = "no messages should be passed during the INIT state:"; - goto unhandled; - - //-------------------------- OPENING USRP -------------------------------// - // In this state we expect a response from usrp_server over the CS channel - // as to whether or not the opening of the USRP was successful. If so, we - // switch states to allocating the channels for use. - case OPENING_USRP: - - if(pmt_eq(event, s_response_open) - && pmt_eq(d_us_cs->port_symbol(), port_id)) { - - status = pmt_nth(1, data); // PMT_T or PMT_F - - if(pmt_eq(status, PMT_T)) { // on success, allocate channels! - allocate_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: - - // ************* TX ALLOCATION RESPONSE ***************** // - if(pmt_eq(event, s_response_allocate_channel) - && pmt_eq(d_us_tx->port_symbol(), port_id)) - { - status = pmt_nth(1, data); - - if(pmt_eq(status, PMT_T)) { // extract channel on success - d_us_tx_chan = pmt_nth(2, data); - - if(verbose) - std::cout << "[GMAC] Received TX allocation" - << " on channel " << d_us_tx_chan << std::endl; - - // If the RX has also been allocated already, we can continue - if(!pmt_eqv(d_us_rx_chan, PMT_NIL)) { - //enter_receiving(); - initialize_gmac(); - } - - return; - } - else { // TX allocation failed - error_msg = "failed to allocate TX channel:"; - goto bail; - } - } - - // ************* RX ALLOCATION RESPONSE ****************// - if(pmt_eq(event, s_response_allocate_channel) - && pmt_eq(d_us_rx->port_symbol(), port_id)) - { - status = pmt_nth(1, data); - - if(pmt_eq(status, PMT_T)) { - - d_us_rx_chan = pmt_nth(2, data); - - if(verbose) - std::cout << "[GMAC] Received RX allocation" - << " on channel " << d_us_rx_chan << std::endl; - - // If the TX has also been allocated already, we can continue - if(!pmt_eqv(d_us_tx_chan, PMT_NIL)) { - //enter_receiving(); - initialize_gmac(); - } - - return; - } - else { // RX allocation failed - error_msg = "failed to allocate RX channel:"; - goto bail; - } - } - - goto unhandled; - - //----------------------------- INIT GMAC --------------------------------// - // In the INIT_GMAC state, now that the USRP is initialized we can do things - // like right the carrier sense threshold to the FPGA register. - case INIT_GMAC: - goto unhandled; - - - //----------------------------- IDLE ------------------------------------// - // In the idle state the MAC is not quite 'idle', it is just not doing - // anything specific. It is still being passive with data between the - // application and the lower layer. - case IDLE: - - //-------- TX PORT ----------------------------------------------------// - if(pmt_eq(d_tx->port_symbol(), port_id)) { - - //-------- INCOMING PACKET ------------------------------------------// - if(pmt_eq(event, s_cmd_tx_pkt)) { - handle_cmd_tx_pkt(data); - return; - } - - } - - //--------- USRP TX PORT ----------------------------------------------// - if(pmt_eq(d_us_tx->port_symbol(), port_id)) { - - //-------- INCOMING PACKET RESPONSE ---------------------------------// - if(pmt_eq(event, s_response_xmit_raw_frame)) { - handle_response_xmit_raw_frame(data); - return; - } - - } - - //--------- CS PORT ---------------------------------------------------// - if(pmt_eq(d_cs->port_symbol(), port_id)) { - - //------- ENABLE CARRIER SENSE --------------------------------------// - if(pmt_eq(event, s_cmd_carrier_sense_enable)) { - handle_cmd_carrier_sense_enable(data); - return; - } - - //------- CARRIER SENSE THRESHOLD -----------------------------------// - if(pmt_eq(event, s_cmd_carrier_sense_threshold)) { - handle_cmd_carrier_sense_threshold(data); - return; - } - - //------- CARRIER SENSE DEADLINE ------------------------------------// - if(pmt_eq(event, s_cmd_carrier_sense_deadline)) { - handle_cmd_carrier_sense_deadline(data); - return; - } - - //------- DISABLE CARRIER SENSE -------------------------------------// - if(pmt_eq(event, s_cmd_carrier_sense_disable)) { - handle_cmd_carrier_sense_disable(data); - return; - } - - } - - goto unhandled; - - //------------------------ CLOSING CHANNELS -----------------------------// - case CLOSING_CHANNELS: - - if (pmt_eq(event, s_response_deallocate_channel) - && pmt_eq(d_us_tx->port_symbol(), port_id)) - { - status = pmt_nth(1, data); - - if(pmt_eq(status, PMT_T)) { - d_us_tx_chan = PMT_NIL; - - if(verbose) - std::cout << "[GMAC] Received TX deallocation\n"; - - // If the RX is also deallocated, we can close the USRP - if(pmt_eq(d_us_rx_chan, PMT_NIL)) - close_usrp(); - - return; - - } else { - - error_msg = "failed to deallocate TX channel:"; - goto bail; - - } - } - - if (pmt_eq(event, s_response_deallocate_channel) - && pmt_eq(d_us_rx->port_symbol(), port_id)) - { - status = pmt_nth(1, data); - - // If successful, set the port to NIL - if(pmt_eq(status, PMT_T)) { - d_us_rx_chan = PMT_NIL; - - if(verbose) - std::cout << "[GMAC] Received RX deallocation\n"; - - // If the TX is also deallocated, we can close the USRP - if(pmt_eq(d_us_tx_chan, PMT_NIL)) - close_usrp(); - - return; - - } else { - - error_msg = "failed to deallocate RX channel:"; - goto bail; - - } - } - - goto unhandled; - - //-------------------------- CLOSING USRP -------------------------------// - case CLOSING_USRP: - 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(0 && verbose && !pmt_eq(event, pmt_intern("%shutdown"))) - std::cout << "[GMAC] unhandled msg: " << msg - << "in state "<< d_state << std::endl; -} - -// The MAC layer connects to 'usrp_server' which has a control/status channel, -// a TX, and an RX port. The MAC layer can then relay TX/RX data back and -// forth to the application, or a physical layer once available. -void gmac::define_ports() -{ - // Ports we use to connect to usrp_server - d_us_tx = define_port("us-tx0", "usrp-tx", false, mb_port::INTERNAL); - d_us_rx = define_port("us-rx0", "usrp-rx", false, mb_port::INTERNAL); - d_us_cs = define_port("us-cs", "usrp-server-cs", false, mb_port::INTERNAL); - - // Ports applications used to connect to us - d_tx = define_port("tx0", "gmac-tx", true, mb_port::EXTERNAL); - d_rx = define_port("rx0", "gmac-rx", true, mb_port::EXTERNAL); - d_cs = define_port("cs", "gmac-cs", true, mb_port::EXTERNAL); -} - -// To initialize the USRP we must pass several parameters to 'usrp_server' such -// as the RBF to use, and the interpolation/decimation rate. The MAC layer will -// then pass these parameters to the block with a message to establish the -// connection to the USRP. -void gmac::initialize_usrp() -{ - - if(verbose) - std::cout << "[GMAC] Initializing USRP\n"; - - // The initialization parameters are passed to usrp_server via a PMT - // dictionary. - pmt_t usrp_dict = pmt_make_dict(); - - // Specify the RBF to use - pmt_dict_set(usrp_dict, - pmt_intern("rbf"), - pmt_intern("test2.rbf")); - - 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)); - - // Center frequency - pmt_dict_set(usrp_dict, - pmt_intern("rf-freq"), - pmt_from_long((long)10e6)); - - // Default is to use USRP considered '0' (incase of multiple) - d_which_usrp = pmt_from_long(0); - - define_component("USRP-SERVER", "usrp_server", usrp_dict); - - connect("self", "us-tx0", "USRP-SERVER", "tx0"); - connect("self", "us-rx0", "USRP-SERVER", "rx0"); - connect("self", "us-cs", "USRP-SERVER", "cs"); - - // Finally, enter the OPENING_USRP state by sending a request to open the - // USRP. - open_usrp(); - -} - -// In the initialization state of the MAC layer we set default values for -// several functionalities. -void gmac::initialize_gmac() -{ - - // The initial state is the INIT state. - d_state = INIT_GMAC; - - // Set carrier sense to enabled by default with the specified threshold and - // the deadline to 0 -- which is wait forever. - set_carrier_sense(true, 25, 0, PMT_NIL); - - // Can now notify the application that we are initialized - d_cs->send(s_response_gmac_initialized, - pmt_list2(PMT_NIL, PMT_T)); - - // The MAC enters an IDLE state where it waits for messages and dispatches - // based on them - enter_idle(); -} - -// Method for setting the carrier sense and an associated threshold which is -// written to a register on the FPGA, which it will read if the CS flag is set -// and perform carrier sense based on. -// -// We currently do not wait for the successful response for the write to -// register command, we assume it will succeed else the MAC must -void gmac::set_carrier_sense(bool toggle, long threshold, long deadline, pmt_t invocation) -{ - d_carrier_sense = toggle; - - // Only waste the bandwidth and processing of a C/S packet if needed - if(threshold != d_cs_thresh) { - d_us_tx->send(s_cmd_to_control_channel, // C/S packet - pmt_list2(invocation, // invoc handle - pmt_list1( - pmt_list2(s_op_write_reg, - pmt_list2( - pmt_from_long(REG_CS_THRESH), - pmt_from_long(threshold)))))); - d_cs_thresh = threshold; - - if(verbose) - std::cout << "[GMAC] Changing CS threshold: " << d_cs_thresh << std::endl; - } - - if(deadline != d_cs_deadline) { - d_us_tx->send(s_cmd_to_control_channel, // C/S packet - pmt_list2(invocation, // invoc handle - pmt_list1( - pmt_list2(s_op_write_reg, - pmt_list2( - pmt_from_long(REG_CS_DEADLINE), - pmt_from_long(deadline)))))); - d_cs_deadline = deadline; - - if(verbose) - std::cout << "[GMAC] Changing CS deadline: " << d_cs_deadline << std::endl; - } - - if(verbose) - std::cout << "[GMAC] Setting carrier sense to " << toggle << std::endl; -} - -// The following sends a command to open the USRP, which will upload the -// specified RBF when creating the instance of the USRP server and set all other -// relevant parameters. -void gmac::open_usrp() -{ - d_state = OPENING_USRP; - - d_us_cs->send(s_cmd_open, pmt_list2(PMT_NIL, d_which_usrp)); - - if(verbose) - std::cout << "[GMAC] Opening USRP " - << d_which_usrp << std::endl; -} - -// Before sending the close to the USRP we wait a couple seconds to let any data -// through the USB exit, else a bug in the driver will kick an error and cause -// an abnormal termination. -void gmac::close_usrp() -{ - d_state = CLOSING_USRP; - - sleep(2); - - d_us_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); -} - -// 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 gmac::allocate_channels() -{ - d_state = ALLOCATING_CHANNELS; - - if(verbose) - std::cout << "[GMAC] Sending channel allocation requests\n"; - - long capacity = (long) 16e6; - d_us_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); - d_us_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); - -} - -// Before closing the USRP connection, we deallocate our channels so that the -// capacity can be reused. -void gmac::close_channels() -{ - d_state = CLOSING_CHANNELS; - - d_us_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_us_tx_chan)); - d_us_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_us_rx_chan)); - - if(verbose) - std::cout << "[GMAC] Closing channels...\n"; -} - -// Used to enter the receiving state -void gmac::enter_receiving() -{ - d_us_rx->send(s_cmd_start_recv_raw_samples, - pmt_list2(PMT_F, - d_us_rx_chan)); - - if(verbose) - std::cout << "[GMAC] Started RX sample stream\n"; -} - -// A simple idle state, nothing more to it. -void gmac::enter_idle() -{ - d_state = IDLE; -} - -// Handles the transmission of a pkt from the application. The invocation -// handle is passed on but a response is not given back to the application until -// the response is passed from usrp_server. This ensures that the MAC passes -// back the success or failure. Furthermore, the MAC could decide to retransmit -// on a failure based on the result of the packet transmission. -// -// This should eventually be connected to a physically layer rather than -// directly to usrp_server. (d_us_tx should be replaced with a different -// connection) -void gmac::handle_cmd_tx_pkt(pmt_t data) -{ - pmt_t invocation_handle = pmt_nth(0, data); - pmt_t dst = pmt_nth(1, data); - pmt_t samples = pmt_nth(2, data); - pmt_t pkt_properties = pmt_nth(3, data); - - pmt_t us_tx_properties = pmt_make_dict(); - - // Set the packet to be carrier sensed? - if(carrier_sense_pkt(pkt_properties)) - pmt_dict_set(us_tx_properties, - pmt_intern("carrier-sense"), - PMT_T); - - pmt_t timestamp = pmt_from_long(0xffffffff); // NOW - - // Construct the proper message for USRP server - d_us_tx->send(s_cmd_xmit_raw_frame, - pmt_list5(invocation_handle, - d_us_tx_chan, - samples, - timestamp, - us_tx_properties)); - - if(verbose && 0) - std::cout << "[GMAC] Transmitted packet\n"; -} - -// Handles a response from the USRP server about the transmission of a frame, -// whether it was successful or failed. This should eventually be replaced with -// a response from the PHY layer. This is where a retransmit could be -// implemented. -void gmac::handle_response_xmit_raw_frame(pmt_t data) -{ - pmt_t invocation_handle = pmt_nth(0, data); - pmt_t status = pmt_nth(1, data); - - d_tx->send(s_response_tx_pkt, - pmt_list2(invocation_handle, - status)); -} - -// This method determines whether carrier sense should be enabled based on two -// properties. The first is the MAC setting, which the user can set to carrier -// sense packets by default or not. The second is a per packet setting, which -// can be used to override the MAC setting for the given packet only. -bool gmac::carrier_sense_pkt(pmt_t pkt_properties) -{ - // First we extract the per packet properties to check the per packet setting - // if it exists - if(pmt_is_dict(pkt_properties)) { - - if(pmt_t pkt_cs = pmt_dict_ref(pkt_properties, - pmt_intern("carrier-sense"), - PMT_NIL)) { - // If the per packet property says true, enable carrier sense regardless - // of the MAC setting - if(pmt_eqv(pkt_cs, PMT_T)) - return true; - // If the per packet setting says false, disable carrier sense regardless - // of the MAC setting - else if(pmt_eqv(pkt_cs, PMT_F)) - return false; - } - } - - // If we've hit this point, the packet properties did not state whether - // carrier sense should be used or not, so we use the MAC setting - if(d_carrier_sense) - return true; - else - return false; - -} - -// This method is envoked by an incoming cmd-enable-carrier-sense signal on the -// C/S port. It can be used to re-adjust the threshold or simply enabled -// carrier sense. When a threshold is not provided, the MAC will use an -// averaging algorithm to determine the threshold (in the future). -void gmac::handle_cmd_carrier_sense_enable(pmt_t data) -{ - pmt_t invocation_handle = pmt_nth(0, data); - pmt_t threshold = pmt_nth(1, data); - pmt_t deadline = pmt_nth(2, data); - long l_threshold, l_deadline; - - // FIXME: for now, if threshold is NIL, we do not change the threshold. - // This should be replaced with an averaging algorithm - if(pmt_eqv(threshold, PMT_NIL)) - l_threshold = d_cs_thresh; - else - l_threshold = pmt_to_long(threshold); - - // If the deadline is NIL, we do not change the value - if(pmt_eqv(threshold, PMT_NIL)) - l_deadline = d_cs_deadline; - else - l_deadline = pmt_to_long(deadline); - - set_carrier_sense(true, l_threshold, l_deadline, invocation_handle); -} - -// This method is called when an incoming disable carrier sense command is sent -// over the control status channel. It so far does not ellicit a response, this -// needs to be added correctly. It needs to wait for the response for the C/S -// packet from usrp_server. -void gmac::handle_cmd_carrier_sense_disable(pmt_t data) -{ - pmt_t invocation_handle = pmt_nth(0, data); - - // We don't change the threshold, we leave it as is because the application - // did not request that it changes, only to disable carrier sense. - set_carrier_sense(false, d_cs_thresh, d_cs_deadline, invocation_handle); -} - -// When the app requests that the threshold changes, the state of the carrier -// sense should not change. If it was enabled, it should remain enabled. -// Likewise if it was disabled. The deadline value should also remain -// unchanged. -void gmac::handle_cmd_carrier_sense_threshold(pmt_t data) -{ - pmt_t invocation_handle = pmt_nth(0, data); - pmt_t threshold = pmt_nth(1, data); - long l_threshold; - - // FIXME: for now, if threshold is NIL, we do not change the threshold. - // This should be replaced with an averaging algorithm - if(pmt_eqv(threshold, PMT_NIL)) - l_threshold = d_cs_thresh; - else - l_threshold = pmt_to_long(threshold); - - set_carrier_sense(d_carrier_sense, l_threshold, d_cs_deadline, invocation_handle); -} - -// Ability to change the deadline using a C/S packet. The state of all other -// carrier sense parameters should not change. -void gmac::handle_cmd_carrier_sense_deadline(pmt_t data) -{ - pmt_t invocation_handle = pmt_nth(0, data); - pmt_t deadline = pmt_nth(1, data); - long l_deadline; - - // If the deadline passed is NIL, do *not* change the value. - if(pmt_eqv(deadline, PMT_NIL)) - l_deadline = d_cs_deadline; - else - l_deadline = pmt_to_long(deadline); - - set_carrier_sense(d_carrier_sense, d_cs_thresh, l_deadline, invocation_handle); -} - -REGISTER_MBLOCK_CLASS(gmac); diff --git a/usrp/host/apps-inband/gmac.h b/usrp/host/apps-inband/gmac.h deleted file mode 100644 index a6d0bcb12..000000000 --- a/usrp/host/apps-inband/gmac.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -*- 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. - */ - -#ifndef INCLUDED_GMAC_H -#define INCLUDED_GMAC_H - -#include <mb_mblock.h> - -class gmac; - -class gmac : public mb_mblock -{ - - // The state is used to determine how to handle incoming messages and of - // course, the state of the MAC protocol. - enum state_t { - INIT, - OPENING_USRP, - ALLOCATING_CHANNELS, - INIT_GMAC, - IDLE, - CLOSING_CHANNELS, - CLOSING_USRP, - }; - state_t d_state; - - // Ports used for applications to connect to this block - mb_port_sptr d_tx, d_rx, d_cs; - - // Ports to connect to usrp_server (us) - mb_port_sptr d_us_tx, d_us_rx, d_us_cs; - - // The channel numbers assigned for use - pmt_t d_us_rx_chan, d_us_tx_chan; - - pmt_t d_which_usrp; - - bool d_carrier_sense; - long d_cs_thresh; - long d_cs_deadline; - - enum FPGA_REGISTERS { - REG_CS_THRESH = 1, - REG_CS_DEADLINE = 2 - }; - - public: - gmac(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg); - ~gmac(); - void handle_message(mb_message_sptr msg); - - private: - void define_ports(); - void initialize_usrp(); - void initialize_gmac(); - void set_carrier_sense(bool toggle, long threshold, long deadline, pmt_t invocation); - void allocate_channels(); - void enter_receiving(); - void enter_idle(); - void close_channels(); - void open_usrp(); - void close_usrp(); - void handle_cmd_tx_pkt(pmt_t data); - void handle_response_xmit_raw_frame(pmt_t data); - bool carrier_sense_pkt(pmt_t pkt_properties); - void handle_cmd_carrier_sense_enable(pmt_t data); - void handle_cmd_carrier_sense_threshold(pmt_t data); - void handle_cmd_carrier_sense_disable(pmt_t data); - void handle_cmd_carrier_sense_deadline(pmt_t data); - -}; - -#endif // INCLUDED_GMAC_H diff --git a/usrp/host/apps-inband/gmac.mbh b/usrp/host/apps-inband/gmac.mbh deleted file mode 100644 index 4fa9a062f..000000000 --- a/usrp/host/apps-inband/gmac.mbh +++ /dev/null @@ -1,146 +0,0 @@ -;; -*- scheme -*- ; not really, but tells emacs how to format this -;; -;; 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 2, 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. -;; - -;; ---------------------------------------------------------------- -;; This is an mblock header file -;; -;; The format is very much a work-in-progress. -;; It'll be compiled to C++. -;; ---------------------------------------------------------------- - -;; In the outgoing messages described below, invocation-handle is an -;; identifier provided by the client to tag the method invocation. -;; The identifier will be returned with the response, to provide the -;; client with a mechanism to match asynchronous responses with the -;; commands that generate them. The value of the invocation-handle is -;; opaque the the server, and is not required by the server to be -;; unique. -;; -;; In the incoming messages described below, invocation-handle is the -;; identifier provided by the client in the prompting invocation. The -;; identifier is returned with the response, so that the client has a -;; mechanism to match asynchronous responses with the commands that -;; generated them. -;; -;; status is either #t, indicating success, or a symbol indicating an error. -;; All symbol's names shall begin with %error- - - -;; ---------------------------------------------------------------- -;; gmac-tx -;; -;; The protocol class is defined from the client's point-of-view. -;; (The client port is unconjugated, the server port is conjugated.) - -(define-protocol-class gmac-tx - - (:outgoing - - ;; Transmitting packets can carry an invocation handle so the application - ;; can get TX results on specific packets, such as whether a packet tagged - ;; as #1 was successfully transmitted or not. This would allow the - ;; application to implement something sliding window like. - ;; - ;; 'dst' is the destination MAC address (given a MAC addressing scheme) - ;; - ;; 'data' will be treated transparently and passed on as samples. - ;; - ;; 'properties' can be used in the future to set per-packet options such as - ;; carrier sense overriding functionality. - (cmd-tx-pkt invocation-handle dst data properties) - - ) - - (:incoming - - ;; The response will carry the same invocation-handle passed with cmd-tx-pkt - (response-tx-pkt invocation-handle status) - - ) - ) - -;; ---------------------------------------------------------------- -;; gmac-rx -;; -;; The protocol class is defined from the client's point-of-view. -;; (The client port is unconjugated, the server port is conjugated.) - -(define-protocol-class gmac-rx - - (:outgoing - - ;; There are currently no outgoing commands, I believe that the RX - ;; should always be enabled, there is no point in having an enable/disable - ;; that I can see. - - ) - - (:incoming - - ;; Contains packets decoded by the MAC destined for this machine, sent by - ;; the specified address. - (response-rx-pkt invocation-handle src data) - - ) - ) - - -;; ---------------------------------------------------------------- -;; gmac-cs -;; -;; The protocol class is defined from the client's point-of-view. -;; (The client port is unconjugated, the server port is conjugated.) -;; -;; This defines a control/status interface to the MAC layer, for control over -;; functionality such as carrier sense and future functionality such as channel -;; hopping. - - -(define-protocol-class gmac-cs - - (:outgoing - - ;; Threshold represents the carrier sense threshold based on the digital - ;; reading out of the DAC. If the threshold is set to PMT_NIL then the - ;; MAC will use averaging to determine an appropriate threshold. - (cmd-carrier-sense-enable invocation-handle threshold deadline) - (cmd-carrier-sense-threshold invocation-handle threshold) - (cmd-carrier-sense-disable invocation-handle) - - ;; Setting the number of fast transmission retries on a failure before - ;; reporting a loss back to the application. - (cmd-set-tx-retries invocation-handle retries) - - ) - - (:incoming - - (response-gmac-initialized invocation-handle status) - - (response-carrier-sense-enable invocation-handle status) - (response-carrier-sense-threshold invocation-handle status) - (response-carrier-sense-deadline invocation-handle status) - (response-carrier-sense-disable invocation-handle status) - - (response-set-tx-retries invocation-handle status) - - ) - ) diff --git a/usrp/host/apps-inband/gmac_symbols.h b/usrp/host/apps-inband/gmac_symbols.h deleted file mode 100644 index 0d7804be1..000000000 --- a/usrp/host/apps-inband/gmac_symbols.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- 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. - */ - -#ifndef INCLUDED_GMAC_SYMBOLS_H -#define INCLUDED_GMAC_SYMBOLS_H - -#include <pmt.h> - -// TX -static pmt_t s_cmd_tx_pkt = pmt_intern("cmd-tx-pkt"); -static pmt_t s_response_tx_pkt = pmt_intern("response-tx-pkt"); - -// RX -static pmt_t s_response_rx_pkt = pmt_intern("response-rx-pkt"); - -// CS -static pmt_t s_cmd_carrier_sense_enable = pmt_intern("cmd-carrier-sense-enable"); -static pmt_t s_cmd_carrier_sense_threshold = pmt_intern("cmd-carrier-sense-threshold"); -static pmt_t s_cmd_carrier_sense_deadline = pmt_intern("cmd-carrier-sense-deadline"); -static pmt_t s_cmd_carrier_sense_disable = pmt_intern("cmd-carrier-sense-disable"); -static pmt_t s_cmd_set_tx_retries = pmt_intern("cmd-set-tx-retries"); -static pmt_t s_response_gmac_initialized = pmt_intern("response-gmac-initialized"); -static pmt_t s_response_carrier_sense_enable = pmt_intern("response-carrier-sense-enable"); -static pmt_t s_response_carrier_sense_treshold = pmt_intern("response-carrier-sense-threshold"); -static pmt_t s_response_carrier_sense_deadline = pmt_intern("response-carrier-sense-deadline"); -static pmt_t s_response_carrier_sense_disable = pmt_intern("response-carrier-sense-disable"); -static pmt_t s_response_set_tx_retries = pmt_intern("response-set-tx-retries"); - -#endif // INCLUDED_GMAC_SYMBOLS_H diff --git a/usrp/host/apps-inband/test_gmac_tx.cc b/usrp/host/apps-inband/test_gmac_tx.cc deleted file mode 100644 index 74f16c669..000000000 --- a/usrp/host/apps-inband/test_gmac_tx.cc +++ /dev/null @@ -1,330 +0,0 @@ -/* -*- 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_protocol_class.h> -#include <mb_exception.h> -#include <mb_msg_queue.h> -#include <mb_message.h> -#include <mb_msg_accepter.h> -#include <mb_class_registry.h> -#include <pmt.h> -#include <stdio.h> -#include <string.h> -#include <iostream> - -#include <ui_nco.h> -#include <gmac.h> -#include <gmac_symbols.h> - -static bool verbose = true; - -class test_gmac_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, - TRANSMITTING, - }; - - 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_gmac_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); - ~test_gmac_tx(); - 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_gmac_tx::test_gmac_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 * 4)), // full packet - d_done_sending(false), - d_amplitude(16384) -{ - - define_component("GMAC", "gmac", PMT_NIL); - d_tx = define_port("tx0", "gmac-tx", false, mb_port::INTERNAL); - d_cs = define_port("cs", "gmac-cs", false, mb_port::INTERNAL); - - connect("self", "tx0", "GMAC", "tx0"); - connect("self", "cs", "GMAC", "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_gmac_tx::~test_gmac_tx() -{ -} - -void -test_gmac_tx::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; - - // Dispatch based on state - switch(d_state) { - - //------------------------------ INIT ---------------------------------// - // When GMAC is done initializing, it will send a response - case INIT: - - if(pmt_eq(event, s_response_gmac_initialized)) { - handle = pmt_nth(0, data); - status = pmt_nth(1, data); - - if(pmt_eq(status, PMT_T)) { - enter_transmitting(); - return; - } - else { - error_msg = "error initializing gmac:"; - goto bail; - } - } - 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_tx_pkt)){ - 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-tx-pkt:"; - goto bail; - } - } - - 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_GMAC_TX] unhandled msg: " << msg - << "in state "<< d_state << std::endl; -} - -void -test_gmac_tx::enter_transmitting() -{ - d_state = TRANSMITTING; - d_nsamples_xmitted = 0; - - d_cs->send(s_cmd_carrier_sense_deadline, - pmt_list2(PMT_NIL, - pmt_from_long(50000000))); - - 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_gmac_tx::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(); - } - } - - // Per packet properties - pmt_t tx_properties = pmt_make_dict(); - - if(d_nframes_xmitted > 25000) { - pmt_dict_set(tx_properties, - pmt_intern("carrier-sense"), - PMT_F); - } - - if(d_nframes_xmitted > 35000) { - pmt_dict_set(tx_properties, - pmt_intern("carrier-sense"), - PMT_NIL); - } - - if(d_nframes_xmitted == 45000) { - d_cs->send(s_cmd_carrier_sense_threshold, - pmt_list2(PMT_NIL, - pmt_from_long(100))); - } - - if(d_nframes_xmitted == 60000) { - d_cs->send(s_cmd_carrier_sense_threshold, - pmt_list2(PMT_NIL, - pmt_from_long(25))); - } - - if(d_nframes_xmitted == 75000) { - d_cs->send(s_cmd_carrier_sense_disable, - pmt_list1(PMT_NIL)); - } - - if(d_nframes_xmitted > 90000 && d_nframes_xmitted < 110000) { - pmt_dict_set(tx_properties, - pmt_intern("carrier-sense"), - PMT_T); - } - - if(d_nframes_xmitted > 110000) { - - if(d_nframes_xmitted % 100 == 0) - pmt_dict_set(tx_properties, - pmt_intern("carrier-sense"), - PMT_T); -} - - pmt_t timestamp = pmt_from_long(0xffffffff); // NOW - d_tx->send(s_cmd_tx_pkt, - pmt_list4(PMT_NIL, // invocation-handle - PMT_NIL, // destination - uvec, // the samples - tx_properties)); // per pkt properties - - d_nsamples_xmitted += nsamples_this_frame; - d_nframes_xmitted++; - - if(verbose && 0) - std::cout << "[TEST_GMAC_TX] Transmitted frame\n"; -} - - -void -test_gmac_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 - } - - build_and_send_next_frame(); -} - -REGISTER_MBLOCK_CLASS(test_gmac_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("test_gmac_tx", "test_gmac_tx", PMT_F, &result); -} diff --git a/usrp/host/apps-inband/test_usrp_inband_2rx.cc b/usrp/host/apps-inband/test_usrp_inband_2rx.cc new file mode 100644 index 000000000..da8d7271c --- /dev/null +++ b/usrp/host/apps-inband/test_usrp_inband_2rx.cc @@ -0,0 +1,371 @@ +/* -*- 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> + +// 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/host/apps-inband/test_usrp_inband_cs.cc b/usrp/host/apps-inband/test_usrp_inband_2tx.cc index 2497f8d5c..5ab9be06a 100644 --- a/usrp/host/apps-inband/test_usrp_inband_cs.cc +++ b/usrp/host/apps-inband/test_usrp_inband_2tx.cc @@ -25,16 +25,17 @@ #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 <ui_nco.h> @@ -42,21 +43,14 @@ #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; -static bool verbose = false; - -class test_usrp_cs : public mb_mblock +class test_usrp_tx : 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]; + pmt_t d_tx_chan0, d_tx_chan1; enum state_t { INIT, @@ -79,8 +73,8 @@ class test_usrp_cs : public mb_mblock double d_amplitude; public: - test_usrp_cs(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); - ~test_usrp_cs(); + 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); @@ -89,32 +83,25 @@ class test_usrp_cs : public mb_mblock 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) +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_chan(PMT_NIL), - d_rx_chan(PMT_NIL), - d_state(INIT), d_nsamples_to_send((long) 40e6), + 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)), - //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"; + // std::cout << "[TEST_USRP_TX] 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; @@ -129,6 +116,11 @@ test_usrp_cs::test_usrp_cs(mb_runtime *runtime, const std::string &instance_name 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, @@ -136,18 +128,12 @@ test_usrp_cs::test_usrp_cs(mb_runtime *runtime, const std::string &instance_name 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("boe.rbf")); + pmt_intern("rf-freq"), + pmt_from_long(10e6)); define_component("server", "usrp_server", usrp_dict); connect("self", "tx0", "server", "tx0"); - connect("self", "rx0", "server", "rx0"); connect("self", "cs", "server", "cs"); // initialize NCO @@ -160,22 +146,21 @@ test_usrp_cs::test_usrp_cs(mb_runtime *runtime, const std::string &instance_name // for now, we'll have the low-level code hardwire it. } -test_usrp_cs::~test_usrp_cs() +test_usrp_tx::~test_usrp_tx() { } void -test_usrp_cs::initial_transition() +test_usrp_tx::initial_transition() { open_usrp(); } void -test_usrp_cs::handle_message(mb_message_sptr msg) +test_usrp_tx::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; @@ -200,48 +185,21 @@ test_usrp_cs::handle_message(mb_message_sptr msg) 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(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(status, PMT_T) && !pmt_eqv(d_tx_chan1, PMT_NIL)){ + enter_transmitting(); + return; } - - 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; - } + else if(pmt_eq(status, PMT_F)){ + error_msg = "failed to allocate channel:"; + goto bail; } + return; } goto unhandled; @@ -303,81 +261,64 @@ test_usrp_cs::handle_message(mb_message_sptr msg) return; unhandled: - if(verbose) - std::cout << "test_usrp_inband_tx: unhandled msg: " << msg - << "in state "<< d_state << std::endl; + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; } void -test_usrp_cs::open_usrp() +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_cs::close_usrp() +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_CS] Closing USRP\n"; + std::cout << "[TEST_USRP_INBAND_TX] Closing the USRP\n"; } void -test_usrp_cs::allocate_channel() +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_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_TX] Requesting TX channel allocation\n"; } 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() +test_usrp_tx::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() -{ + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Transmitting...\n"; - 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; + 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_cs::build_and_send_next_frame() +test_usrp_tx::build_and_send_next_frame() { // allocate the uniform vector for the samples // FIXME perhaps hold on to this between calls @@ -421,23 +362,34 @@ test_usrp_cs::build_and_send_next_frame() } } + pmt_t tx_properties = pmt_make_dict(); + 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 + pmt_list5(pmt_from_long(d_nframes_xmitted), // invocation-handle + d_tx_chan0, // channel uvec, // the samples - timestamp)); + 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) - std::cout << "[TEST_USRP_INBAND_CS] Transmitted frame\n"; + if(verbose && 0) + std::cout << "[TEST_USRP_INBAND_TX] Transmitted frame\n"; } void -test_usrp_cs::handle_xmit_response(pmt_t handle) +test_usrp_tx::handle_xmit_response(pmt_t handle) { if (d_done_sending && pmt_to_long(handle) == (d_nframes_xmitted - 1)){ @@ -445,21 +397,23 @@ test_usrp_cs::handle_xmit_response(pmt_t handle) enter_closing_channel(); } - //build_and_send_next_frame(); + build_and_send_next_frame(); } void -test_usrp_cs::enter_closing_channel() +test_usrp_tx::enter_closing_channel() { d_state = CLOSING_CHANNEL; - d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan)); - + // 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_CS] Closing channel\n"; + std::cout << "[TEST_USRP_INBAND_tX] Deallocating TX channel\n"; } -REGISTER_MBLOCK_CLASS(test_usrp_cs); +REGISTER_MBLOCK_CLASS(test_usrp_tx); // ---------------------------------------------------------------- @@ -472,5 +426,5 @@ main (int argc, char **argv) mb_runtime_sptr rt = mb_make_runtime(); pmt_t result = PMT_NIL; - rt->run("top", "test_usrp_cs", PMT_F, &result); + rt->run("top", "test_usrp_tx", PMT_F, &result); } diff --git a/usrp/host/apps-inband/test_usrp_inband_overrun.cc b/usrp/host/apps-inband/test_usrp_inband_overrun.cc index 9041a0984..107668b89 100644 --- a/usrp/host/apps-inband/test_usrp_inband_overrun.cc +++ b/usrp/host/apps-inband/test_usrp_inband_overrun.cc @@ -102,7 +102,7 @@ test_usrp_rx::test_usrp_rx(mb_runtime *runtime, const std::string &instance_name // Specify the RBF to use pmt_dict_set(usrp_dict, pmt_intern("rbf"), - pmt_intern("nanocell9.rbf")); + pmt_intern("inband_1rxhb_1tx.rbf")); pmt_dict_set(usrp_dict, pmt_intern("decim-rx"), @@ -306,7 +306,8 @@ test_usrp_rx::handle_response_recv_raw_samples(pmt_t 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); + pmt_t channel = pmt_nth(4, data); + pmt_t properties = pmt_nth(5, data); d_samples_recvd += pmt_length(v_samples) / 4; diff --git a/usrp/host/apps-inband/test_usrp_inband_registers.cc b/usrp/host/apps-inband/test_usrp_inband_registers.cc index 017ccdbf5..a1d9cc141 100644 --- a/usrp/host/apps-inband/test_usrp_inband_registers.cc +++ b/usrp/host/apps-inband/test_usrp_inband_registers.cc @@ -118,7 +118,7 @@ test_usrp_inband_registers::test_usrp_inband_registers(mb_runtime *runtime, cons // Specify the RBF to use pmt_dict_set(usrp_dict, pmt_intern("rbf"), - pmt_intern("boe2.rbf")); + pmt_intern("inband_1rxhb_1tx.rbf")); // Set TX and RX interpolations pmt_dict_set(usrp_dict, diff --git a/usrp/host/apps-inband/test_usrp_inband_rx.cc b/usrp/host/apps-inband/test_usrp_inband_rx.cc index 0429951f3..cff2aa723 100644 --- a/usrp/host/apps-inband/test_usrp_inband_rx.cc +++ b/usrp/host/apps-inband/test_usrp_inband_rx.cc @@ -87,23 +87,30 @@ class test_usrp_rx : public mb_mblock 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(5e6) + 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("nanocell9.rbf")); + pmt_intern("inband_1rxhb_1tx.rbf")); pmt_dict_set(usrp_dict, pmt_intern("decim-rx"), - pmt_from_long(128)); + pmt_from_long(64)); define_component("server", "usrp_server", usrp_dict); @@ -264,6 +271,7 @@ test_usrp_rx::open_usrp() void test_usrp_rx::close_usrp() { + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); d_state = CLOSING_USRP; @@ -302,7 +310,8 @@ test_usrp_rx::handle_response_recv_raw_samples(pmt_t 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); + pmt_t channel = pmt_nth(4, data); + pmt_t properties = pmt_nth(5, data); d_samples_recvd += pmt_length(v_samples) / 4; @@ -325,9 +334,7 @@ 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) @@ -342,10 +349,9 @@ 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-inband/test_usrp_inband_timestamps.cc b/usrp/host/apps-inband/test_usrp_inband_timestamps.cc index 8824a72fe..297c7126a 100644 --- a/usrp/host/apps-inband/test_usrp_inband_timestamps.cc +++ b/usrp/host/apps-inband/test_usrp_inband_timestamps.cc @@ -147,7 +147,7 @@ test_usrp_inband_timestamps::test_usrp_inband_timestamps(mb_runtime *runtime, co // Specify the RBF to use pmt_dict_set(usrp_dict, pmt_intern("rbf"), - pmt_intern("tmac5.rbf")); + pmt_intern("inband_1rxhb_1tx.rbf")); define_component("server", "usrp_server", usrp_dict); diff --git a/usrp/host/apps-inband/test_usrp_inband_tx.cc b/usrp/host/apps-inband/test_usrp_inband_tx.cc index 7118d2d0f..7f894a4c3 100644 --- a/usrp/host/apps-inband/test_usrp_inband_tx.cc +++ b/usrp/host/apps-inband/test_usrp_inband_tx.cc @@ -42,7 +42,7 @@ #include <symbols_usrp_low_level_cs.h> #include <symbols_usrp_tx.h> -static bool verbose = false; +static bool verbose = true; class test_usrp_tx : public mb_mblock { @@ -89,11 +89,9 @@ class test_usrp_tx : public mb_mblock 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_state(INIT), d_nsamples_to_send((long) 80e6), 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) @@ -119,18 +117,14 @@ test_usrp_tx::test_usrp_tx(mb_runtime *runtime, const std::string &instance_name // Specify the RBF to use pmt_dict_set(usrp_dict, pmt_intern("rbf"), - pmt_intern("cs1.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_from_long(64)); pmt_dict_set(usrp_dict, - pmt_intern("decim-rx"), - pmt_from_long(16)); - - pmt_dict_set(usrp_dict, pmt_intern("rf-freq"), pmt_from_long(10e6)); @@ -176,12 +170,12 @@ test_usrp_tx::handle_message(mb_message_sptr msg) if (pmt_eq(event, s_response_open)){ status = pmt_nth(1, data); if (pmt_eq(status, PMT_T)){ - allocate_channel(); - return; + allocate_channel(); + return; } else { - error_msg = "failed to open usrp:"; - goto bail; + error_msg = "failed to open usrp:"; + goto bail; } } goto unhandled; @@ -192,12 +186,12 @@ test_usrp_tx::handle_message(mb_message_sptr msg) d_tx_chan = pmt_nth(2, data); if (pmt_eq(status, PMT_T)){ - enter_transmitting(); - return; + enter_transmitting(); + return; } else { - error_msg = "failed to allocate channel:"; - goto bail; + error_msg = "failed to allocate channel:"; + goto bail; } } goto unhandled; @@ -208,12 +202,12 @@ test_usrp_tx::handle_message(mb_message_sptr msg) status = pmt_nth(1, data); if (pmt_eq(status, PMT_T)){ - handle_xmit_response(handle); - return; + handle_xmit_response(handle); + return; } else { - error_msg = "bad response-xmit-raw-frame:"; - goto bail; + error_msg = "bad response-xmit-raw-frame:"; + goto bail; } } goto unhandled; @@ -223,12 +217,12 @@ test_usrp_tx::handle_message(mb_message_sptr msg) status = pmt_nth(1, data); if (pmt_eq(status, PMT_T)){ - close_usrp(); - return; + close_usrp(); + return; } else { - error_msg = "failed to deallocate channel:"; - goto bail; + error_msg = "failed to deallocate channel:"; + goto bail; } } goto unhandled; @@ -238,12 +232,12 @@ test_usrp_tx::handle_message(mb_message_sptr msg) status = pmt_nth(1, data); if (pmt_eq(status, PMT_T)){ - shutdown_all(PMT_T); - return; + shutdown_all(PMT_T); + return; } else { - error_msg = "failed to close USRP:"; - goto bail; + error_msg = "failed to close USRP:"; + goto bail; } } goto unhandled; @@ -272,6 +266,9 @@ test_usrp_tx::open_usrp() 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 @@ -279,6 +276,9 @@ 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 @@ -287,6 +287,9 @@ 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 @@ -295,15 +298,9 @@ 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(21)))))); - + 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(); @@ -356,9 +353,6 @@ test_usrp_tx::build_and_send_next_frame() } pmt_t tx_properties = pmt_make_dict(); - pmt_dict_set(tx_properties, - pmt_intern("carrier-sense"), - PMT_T); pmt_t timestamp = pmt_from_long(0xffffffff); // NOW d_tx->send(s_cmd_xmit_raw_frame, @@ -371,7 +365,7 @@ test_usrp_tx::build_and_send_next_frame() d_nsamples_xmitted += nsamples_this_frame; d_nframes_xmitted++; - if(verbose) + if(verbose && 0) std::cout << "[TEST_USRP_INBAND_TX] Transmitted frame\n"; } @@ -394,6 +388,9 @@ 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); diff --git a/usrp/host/apps-inband/test_usrp_inband_underrun.cc b/usrp/host/apps-inband/test_usrp_inband_underrun.cc index 0404208b4..c9630cec2 100644 --- a/usrp/host/apps-inband/test_usrp_inband_underrun.cc +++ b/usrp/host/apps-inband/test_usrp_inband_underrun.cc @@ -127,7 +127,7 @@ test_usrp_inband_underrun::test_usrp_inband_underrun(mb_runtime *runtime, const d_rx_chan(PMT_NIL), d_which_usrp(pmt_from_long(0)), d_state(INIT), - d_nsamples_to_send((long) 20e6), + d_nsamples_to_send((long) 27e6), d_nsamples_xmitted(0), d_nframes_xmitted(0), d_samples_per_frame(d_nsamples_to_send), // full packet @@ -143,12 +143,12 @@ test_usrp_inband_underrun::test_usrp_inband_underrun(mb_runtime *runtime, const // Specify the RBF to use pmt_dict_set(usrp_dict, pmt_intern("rbf"), - pmt_intern("nanocell9.rbf")); + pmt_intern("inband_1rxhb_1tx.rbf")); // Set TX and RX interpolations pmt_dict_set(usrp_dict, pmt_intern("interp-tx"), - pmt_from_long(8)); + pmt_from_long(64)); pmt_dict_set(usrp_dict, pmt_intern("decim-rx"), @@ -668,8 +668,6 @@ test_usrp_inband_underrun::closing_usrp() { d_state = CLOSING_USRP; - sleep(2); - d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); } diff --git a/usrp/host/lib/inband/Makefile.am b/usrp/host/lib/inband/Makefile.am index 77d1f6699..a41ac18b8 100644 --- a/usrp/host/lib/inband/Makefile.am +++ b/usrp/host/lib/inband/Makefile.am @@ -76,7 +76,6 @@ include_HEADERS = \ usrp_usb_interface.h noinst_HEADERS = \ - fake_usrp.h \ qa_inband.h \ qa_inband_packet_prims.h \ qa_inband_usrp_server.h \ @@ -109,14 +108,10 @@ libusrp_inband_qa_la_LIBADD = \ # ------------------------------------------------------------------------ noinst_PROGRAMS = \ - test_inband \ - test_usrp_inband + test_inband test_inband_SOURCES = test_inband.cc test_inband_LDADD = libusrp_inband-qa.la -test_usrp_inband_SOURCES = test_usrp_inband.cc -test_usrp_inband_LDADD = libusrp_inband-qa.la - MOSTLYCLEANFILES = \ $(BUILT_SOURCES) *~ *.pyc diff --git a/usrp/host/lib/inband/fake_usrp.cc b/usrp/host/lib/inband/fake_usrp.cc deleted file mode 100644 index 8a66d5c18..000000000 --- a/usrp/host/lib/inband/fake_usrp.cc +++ /dev/null @@ -1,135 +0,0 @@ -/* -*- 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 <fake_usrp.h> -#include <iostream> -#include <usrp_inband_usb_packet.h> -#include <mb_class_registry.h> -#include <vector> - -typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy - -fake_usrp::fake_usrp() -{ - std::cout << "[fake_usrp] Initializing...\n"; -} - -fake_usrp::~fake_usrp() {} - -long -fake_usrp::write_bus(transport_pkt *pkts, long n_bytes) -{ - std::cout << "[fake_usrp] Bytes over bus: " << n_bytes << "\n"; - - // I'm assuming that a control packet cannot exist in a burst of data packets, - // therefore i read only the first packet's channel in the current burst - if(pkts[0].chan() == 0x1f) { - return control_block(pkts, n_bytes); - } else { - return data_block(pkts, n_bytes); - } - -} - -long -fake_usrp::data_block(transport_pkt *pkts, long n_bytes) -{ - std::cout << "[fake_usrp] Entering data block\n"; - - // Infer the number of packets from the byte count to do logical tests - long n_pkts = static_cast<long>(std::ceil(n_bytes / (double)transport_pkt::max_pkt_size())); - - std::cout << "[fake_usrp] Number of packets: " << n_pkts << "\n"; - - // The first packet should have the start of burst, and the last packet should have end of burst - if(pkts[0].start_of_burst() && pkts[n_pkts-1].end_of_burst()) { - std::cout << "[fake_usrp] Correct burst flags set\n"; - } else { - std::cout << "[fake_usrp] Incorrect burst flags set!\n"; - return 0; - } - - // All other flags should be set to 0 (e.g., overrun should not be set yet) on ALL packets - for(int i=0; i < n_pkts; i++) { - if(pkts[i].overrun()) { - std::cout << "[fake_usrp] Incorrect set of overrun flag on transmit\n"; - return 0; - } else if(pkts[i].underrun()) { - std::cout << "[fake_usrp] Incorrect set of underrun flag on transmit\n"; - return 0; - } else if(pkts[i].dropped()) { - std::cout << "[fake_usrp] Incorrect set of drop flag on transmit\n"; - return 0; - } - } - std::cout << "[fake_usrp] Correct overrun, underrun, and drop flags on transmit (initialized to 0)\n"; - - // The first packet should have a timestamp, other packets should have "NOW" - if(pkts[0].timestamp() != 0xffffffff) { - std::cout << "[fake_usrp] Correct timestamp on first packet\n"; - } else { - std::cout << "[fake_usrp] Initial packet should not have the 0xffffffff timestamp\n"; - return 0; - } - - // Check that all of the other packets include the NOW timestamp - int check_stamps=1; - for(int i=1; i < n_pkts; i++) // start at 1 to skip the first packet - if(pkts[i].timestamp() != 0xffffffff) - check_stamps=0; - - if(check_stamps) { - std::cout << "[fake_usrp] Correct NOW timestamps (0xffffffff) on intermediate burst packets\n"; - } else { - std::cout << "[fake_usrp] Incorrect timestamps on intermediate burst packets\n"; - return 0; - } - - // Since we are being transparent about samples, we do not ensure the payload is correct, however - // it should be the case that if there are >1 packets, all packets except the last packet should - // have a full payload size - if(n_pkts > 1) { - int check_size=1; - for(int i=0; i < n_pkts-1; i++) - if(pkts[i].payload_len() != transport_pkt::max_payload()) - check_size=0; - - if(check_size) { - std::cout << "[fake_usrp] Correct payload size sanity check on packets\n"; - } else { - std::cout << "[fake_usrp] Failed payload size sanity check\n"; - return 0; - } - } - - return 1; -} - -long -fake_usrp::control_block(transport_pkt *pkts, long n_bytes) -{ - std::cout << "[fake_usrp] Entering control block\n"; - - return 1; -} diff --git a/usrp/host/lib/inband/fake_usrp.h b/usrp/host/lib/inband/fake_usrp.h deleted file mode 100644 index 818c5a506..000000000 --- a/usrp/host/lib/inband/fake_usrp.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- 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. - */ -#ifndef INCLUDED_FAKE_USRP_H -#define INCLUDED_FAKE_USRP_H - -#include <usrp_inband_usb_packet.h> -typedef usrp_inband_usb_packet transport_pkt; - -/*! - * \brief Implements a fake USRP for testing without hardware - */ -class fake_usrp -{ - public: - fake_usrp(); - ~fake_usrp(); - long write_bus(transport_pkt *pkts, long n_bytes); - - protected: - long data_block(transport_pkt *pkts, long n_bytes); - long control_block(transport_pkt *pkts, long n_bytes); -}; - -#endif /* INCLUDED_FAKE_USRP_H */ - diff --git a/usrp/host/lib/inband/qa_inband_usrp_server.cc b/usrp/host/lib/inband/qa_inband_usrp_server.cc index b01e74e00..e457e8d64 100644 --- a/usrp/host/lib/inband/qa_inband_usrp_server.cc +++ b/usrp/host/lib/inband/qa_inband_usrp_server.cc @@ -46,6 +46,8 @@ typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit e static bool verbose = false; +static pmt_t s_timeout = pmt_intern("%timeout"); + // ---------------------------------------------------------------------------------------------- class qa_alloc_top : public mb_mblock @@ -903,10 +905,10 @@ class qa_rx_top : public mb_mblock long d_rx_chan; - long d_got_response_recv; + bool d_got_response_recv; - long d_nmsg_to_recv; - long d_nmsg_recvd; + mb_time d_t0; + double d_delta_t; public: qa_rx_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); @@ -927,18 +929,19 @@ qa_rx_top::qa_rx_top(mb_runtime *runtime, const std::string &instance_name, pmt_ d_got_response_recv(false) { - d_nmsg_to_recv=12; - d_nmsg_recvd=0; - d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); // Use the stub with the usrp_server - pmt_t usrp_server_dict = pmt_make_dict(); - pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"), PMT_T); + pmt_t usrp_dict = pmt_make_dict(); + // Set TX and RX interpolations + pmt_dict_set(usrp_dict, + pmt_intern("decim-rx"), + pmt_from_long(128)); + pmt_dict_set(usrp_dict, pmt_intern("fake-usrp"), PMT_T); // Test the TX side - define_component("server", "usrp_server", usrp_server_dict); + define_component("server", "usrp_server", usrp_dict); connect("self", "rx0", "server", "rx0"); connect("self", "cs", "server", "cs"); } @@ -967,17 +970,10 @@ qa_rx_top::run_tests() pmt_list2(PMT_NIL, pmt_from_long(0))); - // A small sleep is used to ensure, if working properly, a recv - // response comes through successfully before the close gets - // through - usleep(1000); - - d_rx->send(s_cmd_stop_recv_raw_samples, - pmt_list2(PMT_NIL, - pmt_from_long(0))); - - d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T))); - + // Schedule a small timeout in which we expect to have received at least one + // packet worth of samples from the stub + d_t0 = mb_time::time(); + schedule_one_shot_timeout(d_t0 + 0.01, PMT_NIL); } @@ -992,26 +988,37 @@ qa_rx_top::handle_message(mb_message_sptr msg) pmt_t expected = pmt_nth(0, data); pmt_t status = pmt_nth(1, data); + + // If we get a timeout we shutdown + if(pmt_eq(event, s_timeout)) { + if(verbose) + std::cout << "[qa_rx_top] Got timeout\n"; + d_rx->send(s_cmd_stop_recv_raw_samples, + pmt_list2(PMT_NIL, + pmt_from_long(0))); + + d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T))); + return; + } // For testing RX, an invocation handle is not generated by the stub, // therefore the same approach for testing is not used. We simply // expect all responses to be true. if(pmt_eq(event, s_response_recv_raw_samples)) { - if(!pmt_eqv(status, PMT_T)) { - if(verbose) - std::cout << "Got: " << status << " Expected: " << PMT_T << "\n"; - shutdown_all(PMT_F); - return; - } - else { + if(pmt_eqv(status, PMT_T)) { + if(verbose) std::cout << "[qa_rx_top] Received expected response for message " - << d_nmsg_recvd << " (" << event << ")\n"; // All we want is 1 response receive! Can't guarantee exact numbers d_got_response_recv = true; } + else { + if(verbose) + std::cout << "Got: " << status << " Expected: " << PMT_T << "\n"; + shutdown_all(PMT_F); + } return; } @@ -1026,8 +1033,7 @@ qa_rx_top::handle_message(mb_message_sptr msg) } else { if(verbose) std::cout << "[qa_rx_top] Received expected response for message " - << d_nmsg_recvd - << " (" << event << ")\n"; + << " (" << event << ")\n"; } if (pmt_eq(msg->port_id(), d_rx->port_symbol())) { @@ -1051,12 +1057,7 @@ qa_rx_top::handle_message(mb_message_sptr msg) std::cout << "[qa_rx_top] No response message before close\n"; return; } - } - - - d_nmsg_recvd++; - } @@ -1079,6 +1080,160 @@ qa_rx_top::check_allocation(mb_message_sptr msg) REGISTER_MBLOCK_CLASS(qa_rx_top); +// ---------------------------------------------------------------------------------------------- + +class qa_rid_top : public mb_mblock +{ + mb_port_sptr d_tx; + mb_port_sptr d_rx; + mb_port_sptr d_cs; + + long d_npongs; + long d_tcycles; + long d_cycles; + long d_max_rid; + + mb_time d_t0; + double d_delta_t; + + public: + qa_rid_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~qa_rid_top(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void run_tests(); + void send_max_pings(); +}; + +qa_rid_top::qa_rid_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg) +{ + d_npongs = 0; + d_tcycles = 3; + d_cycles = d_tcycles; + d_max_rid = usrp_server::D_MAX_RID; + d_delta_t = 0.1; + + + d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); + d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + // Use the stub with the usrp_server + pmt_t usrp_server_dict = pmt_make_dict(); + pmt_dict_set(usrp_server_dict, pmt_intern("fake-usrp"),PMT_T); + + // Test the TX side + define_component("server", "usrp_server", usrp_server_dict); + connect("self", "tx0", "server", "tx0"); + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + +} + +qa_rid_top::~qa_rid_top(){} + +void +qa_rid_top::initial_transition() +{ + run_tests(); +} + +void +qa_rid_top::run_tests() +{ + if(verbose) + std::cout << "[qa_rid_top] Starting tests...\n"; + + // Retrieve information about the USRP, then run tests + d_cs->send(s_cmd_open, + pmt_list2(pmt_list2(s_response_open, PMT_T), + pmt_from_long(0))); + + // should be able to allocate 1 byte + d_tx->send(s_cmd_allocate_channel, + pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T), + pmt_from_long(1))); + + d_rx->send(s_cmd_allocate_channel, + pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T), + pmt_from_long(1))); + + // Need to start receiving to read from the USRP to get C/S responses + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_NIL, + pmt_from_long(0))); + + // Build a subpacket of MAX_RID pings and wait a small amount for all of the + // responses and fire off another MAX_RID. If MAX_RID*2 responses are + // received, the RID recycling is working correctly. + // Schedule a timer in which we expect to have received all of the responses, + // which will send off another MAX_RID worth. + send_max_pings(); + d_t0 = mb_time::time(); + schedule_one_shot_timeout(d_t0 + d_delta_t, PMT_NIL); +} + +void +qa_rid_top::send_max_pings() +{ + pmt_t ping = pmt_list2(s_op_ping_fixed, + pmt_list2(pmt_from_long(0), + pmt_from_long(0))); + + pmt_t sub_packets = PMT_NIL; + + for(int i=0; i<d_max_rid; i++) + sub_packets = pmt_list_add(sub_packets, ping); + + d_tx->send(s_cmd_to_control_channel, + pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T), + sub_packets)); +} + +void +qa_rid_top::handle_message(mb_message_sptr msg) +{ + pmt_t data = msg->data(); + pmt_t event = msg->signal(); + + // If we get a timeout we ensure we got a maximum RID number of responses. + if(pmt_eq(event, s_timeout)) { + if(verbose) + std::cout << "[qa_rid_top] Got timeout, received so far: " + << d_npongs << "\n"; + + d_cycles--; + + if(d_cycles==0 && d_npongs == d_max_rid*d_tcycles) { + shutdown_all(PMT_T); + } + else if(d_cycles==0) { + + std::cout << "[qa_rid_top] d_npongs: " << d_npongs + << " expected: " << d_max_rid*d_tcycles + << std::endl; + + shutdown_all(PMT_F); + } + else { + send_max_pings(); + d_t0 = mb_time::time(); + schedule_one_shot_timeout(d_t0 + d_delta_t, PMT_NIL); + } + + } + else if(pmt_eq(event, s_response_from_control_channel)) + { + d_npongs++; + } + +} + +REGISTER_MBLOCK_CLASS(qa_rid_top); + // ---------------------------------------------------------------------------------------------- @@ -1398,3 +1553,17 @@ qa_inband_usrp_server::test_cs() CPPUNIT_ASSERT(pmt_equal(PMT_T, result)); } + +void +qa_inband_usrp_server::test_rid() +{ + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_T; + + // std::cout << "\n\n-----------------\n"; + // std::cout << " RUNNING RID TESTS \n"; + + rt->run("top", "qa_rid_top", PMT_F, &result); + + CPPUNIT_ASSERT(pmt_equal(PMT_T, result)); +} diff --git a/usrp/host/lib/inband/qa_inband_usrp_server.h b/usrp/host/lib/inband/qa_inband_usrp_server.h index 5db57c3ed..52a4a0b06 100644 --- a/usrp/host/lib/inband/qa_inband_usrp_server.h +++ b/usrp/host/lib/inband/qa_inband_usrp_server.h @@ -34,6 +34,7 @@ class qa_inband_usrp_server : public CppUnit::TestCase { CPPUNIT_TEST(test_tx); CPPUNIT_TEST(test_rx); CPPUNIT_TEST(test_cs); + CPPUNIT_TEST(test_rid); CPPUNIT_TEST_SUITE_END(); private: @@ -43,6 +44,7 @@ class qa_inband_usrp_server : public CppUnit::TestCase { void test_tx(); void test_rx(); void test_cs(); + void test_rid(); }; #endif /* INCLUDED_QA_INBAND_USRP_SERVER_H */ diff --git a/usrp/host/lib/inband/test_usrp_inband.cc b/usrp/host/lib/inband/test_usrp_inband.cc deleted file mode 100644 index 64fbf3a97..000000000 --- a/usrp/host/lib/inband/test_usrp_inband.cc +++ /dev/null @@ -1,298 +0,0 @@ -/* -*- 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 <stdio.h> -#include <string.h> -#include <iostream> -#include <usrp_inband_usb_packet.h> -#include <mb_mblock.h> -#include <mb_runtime.h> -#include <mb_protocol_class.h> -#include <mb_class_registry.h> -#include <pmt.h> -#include "usrp_standard.h" - -typedef usrp_inband_usb_packet transport_pkt; - -// Signal set for the USRP server -static pmt_t s_cmd_open = pmt_intern("cmd-open"); -static pmt_t s_response_open = pmt_intern("response-open"); -static pmt_t s_cmd_close = pmt_intern("cmd-close"); -static pmt_t s_response_close = pmt_intern("response-close"); -static pmt_t s_cmd_allocate_channel = pmt_intern("cmd-allocate-channel"); -static pmt_t s_response_allocate_channel = pmt_intern("response-allocate-channel"); -static pmt_t s_send_allocate_channel = pmt_intern("send-allocate-channel"); -static pmt_t s_cmd_deallocate_channel = pmt_intern("cmd-deallocate-channel"); -static pmt_t s_response_deallocate_channel = pmt_intern("response-deallocate-channel"); -static pmt_t s_send_deallocate_channel = pmt_intern("send-deallocate-channel"); -static pmt_t s_cmd_max_capacity = pmt_intern("cmd-max-capacity"); -static pmt_t s_response_max_capacity = pmt_intern("response-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_response_ntx_chan = pmt_intern("response-ntx-chan"); -static pmt_t s_response_nrx_chan = pmt_intern("response-nrx-chan"); -static pmt_t s_cmd_current_capacity_allocation = pmt_intern("cmd-current-capacity-allocation"); -static pmt_t s_response_current_capacity_allocation = pmt_intern("response-current-capacity-allocation"); -static pmt_t s_cmd_xmit_raw_frame = pmt_intern("cmd-xmit-raw-frame"); -static pmt_t s_response_xmit_raw_frame = pmt_intern("response-xmit-raw-frame"); - -bool loopback_p = false; -bool counting_p = false; -bool fake_usrp_p = false; -char *prog_name; - -static void -set_progname (char *path) -{ - char *p = strrchr (path, '/'); - if (p != 0) - prog_name = p+1; - else - prog_name = path; -} - -static void -usage() -{ - fprintf (stderr, "usage: %s [-l]\n", prog_name); - fprintf (stderr, " [-l] digital loopback in FPGA\n"); - fprintf (stderr, " [-c] counting in FPGA\n"); - fprintf (stderr, " [-f] fake usrp\n"); - - exit(1); -} - -int -main(int argc, char **argv) -{ - int ch; - - set_progname(argv[0]); - - mb_runtime_sptr rt = mb_make_runtime(); - pmt_t result = PMT_T; - - while ((ch = getopt(argc, argv, "flc")) != EOF) { - switch(ch) { - - case 'l': - loopback_p = true; - break; - - case 'c': - counting_p = true; - break; - - case 'f': - fake_usrp_p = true; - break; - - default: - usage(); - } - } - - - std::cout << "[test_usrp_inband] Starting...\n"; - - rt->run("top", "test_usrp_inband_top", PMT_F, &result); -} - -class test_usrp_inband_top : public mb_mblock -{ - mb_port_sptr d_tx; - mb_port_sptr d_cs; - - long d_tx_chan; - - public: - test_usrp_inband_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); - ~test_usrp_inband_top(); - void initial_transition(); - void handle_message(mb_message_sptr msg); - - protected: - void open_usrp(); - void close_usrp(); - void check_message(mb_message_sptr msg); - void allocate_channel(); - void send_packets(); -}; - -test_usrp_inband_top::test_usrp_inband_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) - : mb_mblock(runtime, instance_name, user_arg) -{ - std::cout << "[TEST_USRP_INBAND_TOP] 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); - - // Test the TX side - - // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP - pmt_t usrp_server_dict = pmt_make_dict(); - - if(fake_usrp_p) - pmt_dict_set(usrp_server_dict, pmt_intern("usrp-interface"), pmt_intern("usrp_usb_interface_stub")); - - define_component("server", "usrp_server", usrp_server_dict); - connect("self", "tx0", "server", "tx0"); - connect("self", "cs", "server", "cs"); -} - -test_usrp_inband_top::~test_usrp_inband_top() -{ -} - -void -test_usrp_inband_top::initial_transition() -{ - open_usrp(); -} - -void -test_usrp_inband_top::handle_message(mb_message_sptr msg) -{ - pmt_t event = msg->signal(); // the "name" of the message - pmt_t port_id = msg->port_id(); // which port it came in on - pmt_t data = msg->data(); - pmt_t metadata = msg->metadata(); - pmt_t status; - - if (pmt_eq(port_id, d_cs->port_symbol())) { // message came in on our control/status port - - //---------- OPEN RESPONSE ----------// - if (pmt_eq(event, s_response_open)) { - status = pmt_nth(1, data); - - if(pmt_eq(status, PMT_T)) { - std::cout << "[TEST_USRP_INBAND_TOP] Success opening USRP\n"; - } - else { - std::cout << "[TEST_USRP_INBAND_TOP] Received error message opening USRP\n"; - shutdown_all(PMT_F); - } - - allocate_channel(); - - return; - } - //--------- CLOSE RESPONSE -----------// - else if (pmt_eq(event, s_response_close)) { - status = pmt_nth(1, data); - - if(pmt_eq(status, PMT_T)) { - std::cout << "[TEST_USRP_INBAND_TOP] Successfully closed USRP\n"; - } - else { - std::cout << "[TEST_USRP_INBAND_TOP] Received error message closing USRP\n"; - shutdown_all(PMT_F); - } - - shutdown_all(PMT_T); - - return; - } - } - - if (pmt_eq(port_id, d_tx->port_symbol())) { - - //---------- ALLOCATE RESPONSE ---------// - if(pmt_eq(event, s_response_allocate_channel)) { - status = pmt_nth(1, data); - pmt_t channel = pmt_nth(2, data); - - if(pmt_eq(status, PMT_T)) { - d_tx_chan = pmt_to_long(channel); - std::cout << "[TEST_USRP_INBAND_TOP] Received allocation on channel " << d_tx_chan << "\n"; - } - else { - std::cout << "[TEST_USRP_INBAND_TOP] Error allocating channel\n"; - shutdown_all(PMT_F); - } - - send_packets(); - - return; - } - //----------- XMIT RESPONSE ------------// - else if(pmt_eq(event, s_response_xmit_raw_frame)) { - status = pmt_nth(1, data); - - if(pmt_eq(status, PMT_T)) { - std::cout << "[TEST_USRP_INBAND_TOP] Transmission successful\n"; - } - else { - std::cout << "[TEST_USRP_INBAND_TOP] Failed transmission\n"; - shutdown_all(PMT_F); - } - - close_usrp(); - - return; - } - } - - std::cout << "[TEST_USRP_INBAND_TOP] Received unhandled message: " << event << "\n"; -} - -void -test_usrp_inband_top::allocate_channel() -{ - std::cout << "[TEST_USRP_INBAND_TOP] Requesting channel allocation...\n"; - - d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1))); -} - -void -test_usrp_inband_top::send_packets() -{ - std::cout << "[TEST_USRP_INBAND_TOP] Sending single packet..\n"; - d_tx->send(s_cmd_xmit_raw_frame, pmt_list4(pmt_from_long(1), pmt_from_long(d_tx_chan), pmt_make_u32vector(transport_pkt::max_payload()/4, 0), pmt_from_long(0))); - -} - -void -test_usrp_inband_top::open_usrp() -{ - pmt_t usrp = pmt_from_long(0); - - long rx_mode = 0; - - if(loopback_p) - rx_mode |= usrp_standard_rx::FPGA_MODE_LOOPBACK; - if(counting_p) - rx_mode |= usrp_standard_rx::FPGA_MODE_COUNTING; - - d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, usrp)); -} - -void -test_usrp_inband_top::close_usrp() -{ - d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); -} - -REGISTER_MBLOCK_CLASS(test_usrp_inband_top); diff --git a/usrp/host/lib/inband/usrp_inband_usb_packet.cc b/usrp/host/lib/inband/usrp_inband_usb_packet.cc index ee4cb22f3..2f02ecc3f 100644 --- a/usrp/host/lib/inband/usrp_inband_usb_packet.cc +++ b/usrp/host/lib/inband/usrp_inband_usb_packet.cc @@ -30,6 +30,14 @@ #include <stdio.h> #include <string.h> +/*! + * \brief Aligns the packet payload on a 32 bit boundary. This is essential to + * all control/status packets so that the inband FPGA code can parse them + * easily. + * + * \returns true if successful or if the packet was already aligned; false if it + * cannot be aligned. + */ bool usrp_inband_usb_packet::align32() { int p_len = payload_len(); @@ -44,18 +52,20 @@ bool usrp_inband_usb_packet::align32() if((MAX_PAYLOAD - p_len) < bytes_needed) return false; - p_len += bytes_needed; - - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = p_len; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(bytes_needed); return true; } +/*! + * \brief Adds a ping command to the current control packet. + * + * The \p rid is the rid to be associated with the ping response and \p ping_val + * is currently unused. + * + * \returns true if adding the ping command was successful, false otherwise + * (i.e. no space in the current packet). + */ bool usrp_inband_usb_packet::cs_ping(long rid, long ping_val) { if(!align32()) @@ -78,17 +88,20 @@ bool usrp_inband_usb_packet::cs_ping(long rid, long ping_val) *payload = host_to_usrp_u32(ping); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_PING_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_PING_LEN); return true; } - +/*! + * \brief Adds a ping response to the packet. This is used by the fake USRP + * code to generate fake responses for pings. + * + * The \p rid is the RID to be associated with the response and \p ping_val is + * currently unused. + * + * \returns true if the ping reply was added successfully, false otherwise. + */ bool usrp_inband_usb_packet::cs_ping_reply(long rid, long ping_val) { if(!align32()) @@ -111,16 +124,20 @@ bool usrp_inband_usb_packet::cs_ping_reply(long rid, long ping_val) *payload = host_to_usrp_u32(ping); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_PING_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_PING_LEN); return true; } +/*! + * \brief Adds a write register command to the packet. + * + * The \p reg_num is the register number for which the value \p val will be + * written to. + * + * \returns true if the command was added to the packet successfully, false + * otherwise. + */ bool usrp_inband_usb_packet::cs_write_reg(long reg_num, long val) { if(!align32()) @@ -149,16 +166,19 @@ bool usrp_inband_usb_packet::cs_write_reg(long reg_num, long val) *payload = host_to_usrp_u32((uint32_t) val); // Rebuild the header to update the payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_WRITEREG_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_WRITEREG_LEN); return true; } +/*! + * \brief Adds a write register masked command to the packet. + * + * The \p reg_num is the register number for which the value \p val will be + * written, masked by \p mask + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_write_reg_masked(long reg_num, long val, long mask) { if(!align32()) @@ -190,16 +210,19 @@ bool usrp_inband_usb_packet::cs_write_reg_masked(long reg_num, long val, long ma *payload = host_to_usrp_u32((uint32_t) mask); // Rebuild the header to update the payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_WRITEREGMASKED_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_WRITEREGMASKED_LEN); return true; } +/*! + * \brief Adds a read register message to the packet. + * + * The \p rid will be the associated RID returned with the response, and \p + * reg_num is the register to be read. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_read_reg(long rid, long reg_num) { if(!align32()) @@ -222,16 +245,22 @@ bool usrp_inband_usb_packet::cs_read_reg(long rid, long reg_num) *payload = host_to_usrp_u32(read_reg); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_READREG_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_READREG_LEN); return true; } +/*! + * \brief Adds a read register reply response to the current packet. This is + * used by the fake USRP code to generate fake register read responses for + * testing. + * + * The \p rid is the associated RID to be included in the response, \p reg_num + * is the register the read is coming from, and \p reg_val is the value of the + * read. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_read_reg_reply(long rid, long reg_num, long reg_val) { if(!align32()) @@ -258,16 +287,19 @@ bool usrp_inband_usb_packet::cs_read_reg_reply(long rid, long reg_num, long reg_ *payload = host_to_usrp_u32((uint32_t) reg_val); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_READREGREPLY_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_READREGREPLY_LEN); return true; } +/*! + * \brief Adds a delay command to the current packet. + * + * The \p ticks parameter is the number of clock ticks the FPGA should delay + * parsing for, which is added to the packet. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_delay(long ticks) { if(!align32()) @@ -289,16 +321,16 @@ bool usrp_inband_usb_packet::cs_delay(long ticks) *payload = host_to_usrp_u32(delay); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_DELAY_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_DELAY_LEN); return true; } +/*! + * \brief + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_i2c_write(long i2c_addr, uint8_t *i2c_data, size_t data_len) { if(!align32()) @@ -328,16 +360,20 @@ bool usrp_inband_usb_packet::cs_i2c_write(long i2c_addr, uint8_t *i2c_data, size memcpy(payload, i2c_data, data_len); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + i2c_len; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + i2c_len); return true; } +/*! + * \brief Adds an I2C read command to the current packet. + * + * The \p rid is the associated RID to return with the read response, \p + * i2c_addr is the address to read from on the I2C bus, and \p n_bytes is the + * number of bytes to be read from the bus. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_i2c_read(long rid, long i2c_addr, long n_bytes) { if(!align32()) @@ -367,16 +403,20 @@ bool usrp_inband_usb_packet::cs_i2c_read(long rid, long i2c_addr, long n_bytes) *payload = host_to_usrp_u32(word1); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_I2CREAD_LEN; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + CS_I2CREAD_LEN); return true; } +/*! + * \brief Adds an I2C read reply response to the current packet. This is used + * by the fake USRP code to generate fake I2C responses. + * + * The \p rid is the RID to be associated with the response, \p i2c_addr is the + * address on the I2C bus that the \p i2c_data of \p i2c_data_len was read from. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_i2c_read_reply(long rid, long i2c_addr, uint8_t *i2c_data, long i2c_data_len) { if(!align32()) @@ -406,16 +446,16 @@ bool usrp_inband_usb_packet::cs_i2c_read_reply(long rid, long i2c_addr, uint8_t memcpy(payload, i2c_data, i2c_data_len); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + i2c_len; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + i2c_len); return true; } +/*! + * \brief Adds a SPI write command to the current packet. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_spi_write(long enables, long format, long opt_header_bytes, uint8_t *spi_data, long spi_data_len) { if(!align32()) @@ -454,16 +494,16 @@ bool usrp_inband_usb_packet::cs_spi_write(long enables, long format, long opt_he memcpy(payload, spi_data, spi_data_len); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + spi_len; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + spi_len); return true; } +/*! + * \brief Adds a SPI bus read command to the packet. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_spi_read(long rid, long enables, long format, long opt_header_bytes, long n_bytes) { if(!align32()) @@ -508,16 +548,17 @@ bool usrp_inband_usb_packet::cs_spi_read(long rid, long enables, long format, lo *payload = host_to_usrp_u32(word); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + CS_SPIREAD_LEN; + incr_header_len(CS_FIXED_LEN + CS_SPIREAD_LEN); - set_header(h_flags, h_chan, h_tag, h_payload_len); - return true; } +/*! + * \brief Adds an SPI read reply to the current packet. This is used by the + * fake USRP code to generate fake responses for SPI reads. + * + * \returns true if the command was added to the packet, false otherwise. + */ bool usrp_inband_usb_packet::cs_spi_read_reply(long rid, uint8_t *spi_data, long spi_data_len) { if(!align32()) @@ -546,30 +587,32 @@ bool usrp_inband_usb_packet::cs_spi_read_reply(long rid, uint8_t *spi_data, long memcpy(payload, spi_data, spi_data_len); // Update payload length - int h_flags = flags(); - int h_chan = chan(); - int h_tag = tag(); - int h_payload_len = payload_len() + CS_FIXED_LEN + spi_len; - - set_header(h_flags, h_chan, h_tag, h_payload_len); + incr_header_len(CS_FIXED_LEN + spi_len); return true; } -// Takes an offset to the beginning of a subpacket and extracts the -// length of the subpacket +/*! + * \brief Since all control packets contain subpackets which have the length of + * the subpacket at a uniform location in the subpacket, this will return the + * subpacket length given a byte offset of the start of the subpacket from the beginning of the packet. + * + * \returns the length of the subpacket + */ int usrp_inband_usb_packet::cs_len(int payload_offset) { uint32_t subpkt = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset))); return (subpkt >> CS_LEN_SHIFT) & CS_LEN_MASK; } -// The following method takes an offset within the packet payload to extract -// a control/status subpacket and construct a pmt response which includes the -// proper signal and arguments specified by usrp-low-level-cs. The USRP -// server could therefore use this to read subpackets and pass them responses -// back up to the application. It's arguable that only reply packets should -// be parsed here, however we parse others for use in debugging or failure -// reporting on the transmit side of packets. +/*! + * \brief The following method takes an offset within the packet payload to + * extract a control/status subpacket and constructs a pmt response which + * includes the proper signal and arguments specified by usrp-low-level-cs. The + * USRP server could therefore use this to read subpackets and pass them + * responses back up to the application. It's arguable that only reply packets + * should be parsed here, however we parse others for use in debugging or + * failure reporting on the transmit side of packets. + */ pmt_t usrp_inband_usb_packet::read_subpacket(int payload_offset) { uint32_t subpkt = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset))); diff --git a/usrp/host/lib/inband/usrp_inband_usb_packet.h b/usrp/host/lib/inband/usrp_inband_usb_packet.h index 8c19b1aeb..8f59d1b65 100644 --- a/usrp/host/lib/inband/usrp_inband_usb_packet.h +++ b/usrp/host/lib/inband/usrp_inband_usb_packet.h @@ -31,6 +31,7 @@ static const int USB_PKT_SIZE = 512; // bytes static const int MAX_PAYLOAD = USB_PKT_SIZE-2*sizeof(uint32_t); +static const int CONTROL_CHAN = 0x1f; class usrp_inband_usb_packet { // @@ -150,6 +151,10 @@ public: | ((payload_len & PAYLOAD_LEN_MASK) << PAYLOAD_LEN_SHIFT)); d_word0 = host_to_usrp_u32(word0); } + + void incr_header_len(int val) { + set_header(flags(), chan(), tag(), payload_len() + val); + } uint32_t timestamp() const { return usrp_to_host_u32(d_timestamp); diff --git a/usrp/host/lib/inband/usrp_rx.cc b/usrp/host/lib/inband/usrp_rx.cc index caa2d7175..71c042a50 100644 --- a/usrp/host/lib/inband/usrp_rx.cc +++ b/usrp/host/lib/inband/usrp_rx.cc @@ -40,25 +40,30 @@ typedef usrp_inband_usb_packet transport_pkt; static const bool verbose = false; +bool usrp_rx_stop; + usrp_rx::usrp_rx(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg) : mb_mblock(rt, instance_name, user_arg), - d_disk_write(false) + d_disk_write(false), + d_disk_write_pkt(false) // if true, writes full packet, else just the payload { d_cs = define_port("cs", "usrp-rx-cs", true, mb_port::EXTERNAL); - //d_disk_write=true; - if(d_disk_write) { - d_ofile.open("rx_data.dat",std::ios::binary|std::ios::out); + d_ofile0.open("rx_data_chan0.dat",std::ios::binary|std::ios::out); + d_ofile1.open("rx_data_chan1.dat",std::ios::binary|std::ios::out); d_cs_ofile.open("rx_cs.dat",std::ios::binary|std::ios::out); } + + usrp_rx_stop = false; } usrp_rx::~usrp_rx() { if(d_disk_write) { - d_ofile.close(); + d_ofile0.close(); + d_ofile1.close(); d_cs_ofile.close(); } } @@ -69,6 +74,12 @@ usrp_rx::initial_transition() } +/*! + * \brief Handles incoming signals to to the m-block, wihch should only ever be + * a single message: cmd-usrrp-rx-start-reading. There is no signal to stop + * reading as the m-block goes in to a forever loop to read inband packets from + * the bus. + */ void usrp_rx::handle_message(mb_message_sptr msg) { @@ -85,6 +96,17 @@ usrp_rx::handle_message(mb_message_sptr msg) } } +/*! + * \brief Performs the actual reading of data from the USB bus, called by + * handle_message() when a cmd-usrp-rx-start-reading signal is received. + * + * The method enters a forever loop where it continues to read data from the bus + * and generate read responses to the higher layer. Currently, shared memory is + * used to exit this loop. + * + * The \p data parameter is a PMT list which contains only a single element, an + * invocation handle which will be returned with all read respones. + */ void usrp_rx::read_and_respond(pmt_t data) { @@ -104,7 +126,7 @@ usrp_rx::read_and_respond(pmt_t data) std::cout << "[usrp_rx] Waiting for packets..\n"; // Read by 512 which is packet size and send them back up - while(1) { + while(!usrp_rx_stop) { pmt_t v_pkt = pmt_make_u8vector(pkt_size, 0); transport_pkt *pkt = @@ -124,19 +146,38 @@ usrp_rx::read_and_respond(pmt_t data) d_cs->send(s_response_usrp_rx_read, pmt_list3(PMT_NIL, PMT_T, v_pkt)); - if(verbose) + if(verbose && 0) std::cout << "[usrp_rx] Read 1 packet\n"; if(d_disk_write) { - if(pkt->chan() == 0x1f) + if(pkt->chan() == CONTROL_CHAN) d_cs_ofile.write((const char *)pkt, transport_pkt::max_pkt_size()); - else - d_ofile.write((const char *)pkt, transport_pkt::max_pkt_size()); + else { + if(d_disk_write_pkt) { + if(pkt->chan() == 0) + d_ofile0.write((const char *)pkt, transport_pkt::max_pkt_size()); + else if(pkt->chan() == 1) + d_ofile1.write((const char *)pkt, transport_pkt::max_pkt_size()); + } else { + if(pkt->chan() == 0) + d_ofile0.write((const char *)pkt->payload(), transport_pkt::max_payload()); + else if(pkt->chan() == 1) + d_ofile1.write((const char *)pkt->payload(), transport_pkt::max_payload()); + } + } d_cs_ofile.flush(); - d_ofile.flush(); + d_ofile0.flush(); + d_ofile1.flush(); } } + + usrp_rx_stop = false; + + if(verbose) { + std::cout << "[USRP_RX] Stopping...\n"; + fflush(stdout); + } } REGISTER_MBLOCK_CLASS(usrp_rx); diff --git a/usrp/host/lib/inband/usrp_rx.h b/usrp/host/lib/inband/usrp_rx.h index e1a90a781..10104bd66 100644 --- a/usrp/host/lib/inband/usrp_rx.h +++ b/usrp/host/lib/inband/usrp_rx.h @@ -26,6 +26,8 @@ class usrp_standard_rx; +extern bool usrp_rx_stop; // used to communicate a 'stop' to the RX stub + /*! * \brief Implements the low level usb interface to the USRP */ @@ -35,7 +37,9 @@ class usrp_rx : public mb_mblock usrp_standard_rx *d_urx; bool d_disk_write; - std::ofstream d_ofile; + bool d_disk_write_pkt; + std::ofstream d_ofile0; + std::ofstream d_ofile1; std::ofstream d_cs_ofile; public: diff --git a/usrp/host/lib/inband/usrp_rx_stub.cc b/usrp/host/lib/inband/usrp_rx_stub.cc index 4bdb106b1..1c96b7a7a 100644 --- a/usrp/host/lib/inband/usrp_rx_stub.cc +++ b/usrp/host/lib/inband/usrp_rx_stub.cc @@ -43,7 +43,7 @@ typedef usrp_inband_usb_packet transport_pkt; static const bool verbose = false; -bool usrp_rx_stop; +bool usrp_rx_stop_stub; // Used for the fake control packet response code to send the responses back up // the RX. The TX stub dumps responses in to this queue. @@ -52,15 +52,32 @@ std::queue<pmt_t> d_cs_queue; usrp_rx_stub::usrp_rx_stub(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg) : mb_mblock(rt, instance_name, user_arg), d_samples_per_frame((long)(126)), + d_decim_rx(128), d_amplitude(16384), d_disk_write(false) { + + // Information about the rates are passed all the way from the app in the form + // of a dictionary. We use this to read the RX decimation rate and compute + // the approximate number of MS/s as a form of flow control for the stub. + pmt_t usrp_dict = user_arg; + + if (pmt_is_dict(usrp_dict)) { + // Read the RX decimation rate + if(pmt_t decim_rx = pmt_dict_ref(usrp_dict, + pmt_intern("decim-rx"), + PMT_NIL)) { + if(!pmt_eqv(decim_rx, PMT_NIL)) + d_decim_rx = pmt_to_long(decim_rx); + } + } + d_cs = define_port("cs", "usrp-rx-cs", true, mb_port::EXTERNAL); // initialize NCO double freq = 100e3; int interp = 32; // 32 -> 4MS/s - double sample_rate = 128e6 / interp; + double sample_rate = 64e6 / interp; d_nco.set_freq(2*M_PI * freq/sample_rate); //d_disk_write = true; @@ -68,7 +85,7 @@ usrp_rx_stub::usrp_rx_stub(mb_runtime *rt, const std::string &instance_name, pmt if(d_disk_write) d_ofile.open("raw_rx.dat",std::ios::binary|std::ios::out); - usrp_rx_stop = false; + usrp_rx_stop_stub = false; } usrp_rx_stub::~usrp_rx_stub() @@ -80,7 +97,6 @@ usrp_rx_stub::~usrp_rx_stub() void usrp_rx_stub::initial_transition() { - } void @@ -90,94 +106,121 @@ usrp_rx_stub::handle_message(mb_message_sptr msg) pmt_t port_id = msg->port_id(); pmt_t data = msg->data(); + if (pmt_eq(msg->signal(), s_timeout) + && !pmt_eq(msg->data(), s_done)) { + + if(!usrp_rx_stop_stub) + read_and_respond(); + else { // requested to stop + cancel_timeout(msg->metadata()); + usrp_rx_stop_stub=false; + if(verbose) + std::cout << "[USRP_RX_STUB] Stopping RX stub\n"; + } + + } + // Theoretically only have 1 message to ever expect, but // want to make sure its at least what we want - if(pmt_eq(port_id, d_cs->port_symbol())) { + if(pmt_eq(port_id, d_cs->port_symbol()) + && pmt_eqv(event, s_cmd_usrp_rx_start_reading)) { if(verbose) - std::cout << "[USRP_RX_STUB] Starting...\n"; + std::cout << "[USRP_RX_STUB] Starting with decim @ " + << d_decim_rx << std::endl; - if(pmt_eqv(event, s_cmd_usrp_rx_start_reading)) - read_and_respond(data); + start_packet_timer(); } } +// Setup a periodic timer which will drive packet generation void -usrp_rx_stub::read_and_respond(pmt_t data) +usrp_rx_stub::start_packet_timer() { + d_t0 = mb_time::time(); // current time + + // Calculate the inter-packet arrival time. + double samples_per_sec = (64.0/(double)d_decim_rx)*1000000.0; + double frames_per_sec = samples_per_sec / (double)d_samples_per_frame; + double frame_rate = 1.0 / frames_per_sec; + + if(verbose) { + std::cout << "[USRP_RX_STUB] Scheduling periodic packet generator\n"; + std::cout << "\tsamples_per_sec: " << samples_per_sec << std::endl; + std::cout << "\tframes_per_sec: " << frames_per_sec << std::endl; + std::cout << "\tframe_rate: " << frame_rate << std::endl; + } - while(!usrp_rx_stop) { + schedule_periodic_timeout(d_t0 + frame_rate, mb_time(frame_rate), PMT_T); +} - long nsamples_this_frame = d_samples_per_frame; +void +usrp_rx_stub::read_and_respond() +{ - size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q - long channel = 0; - long n_bytes = nshorts*2; - pmt_t uvec = pmt_make_s16vector(nshorts, 0); - size_t ignore; - int16_t *samples = pmt_s16vector_writeable_elements(uvec, ignore); + long nsamples_this_frame = d_samples_per_frame; - // fill in the complex sinusoid + size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q + long channel = 0; + long n_bytes = nshorts*2; + pmt_t uvec = pmt_make_s16vector(nshorts, 0); + size_t ignore; + int16_t *samples = pmt_s16vector_writeable_elements(uvec, ignore); - for (int i = 0; i < nsamples_this_frame; i++){ + // fill in the complex sinusoid - 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); + for (int i = 0; i < nsamples_this_frame; i++){ - // write 16-bit i & q - samples[2*i] = (int16_t) s.real(); - samples[2*i+1] = (int16_t) s.imag(); - } + 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(); } - - if(d_disk_write) - d_ofile.write((const char *)samples, n_bytes); - - pmt_t v_pkt = pmt_make_u8vector(sizeof(transport_pkt), 0); - transport_pkt *pkt = - (transport_pkt *) pmt_u8vector_writeable_elements(v_pkt, ignore); + else { + gr_complex s(d_amplitude, d_amplitude); - pkt->set_header(0, channel, 0, n_bytes); - pkt->set_timestamp(0xffffffff); - memcpy(pkt->payload(), samples, n_bytes); - - d_cs->send(s_response_usrp_rx_read, pmt_list3(PMT_NIL, PMT_T, v_pkt)); - - // Now lets check the shared CS queue between the TX and RX stub. Each - // element in a queue is a list where the first element is an invocation - // handle and the second element is a PMT u8 vect representation of the - // CS packet response which can just be passed transparently. - while(!d_cs_queue.empty()) { - - pmt_t cs_pkt = d_cs_queue.front(); - d_cs_queue.pop(); - - pmt_t invocation_handle = pmt_nth(0, cs_pkt); - pmt_t v_pkt = pmt_nth(1, cs_pkt); - - d_cs->send(s_response_usrp_rx_read, - pmt_list3(invocation_handle, - PMT_T, - v_pkt)); // Take the front CS pkt - - - if(verbose) - std::cout << "[USRP_RX_STUB] Received CS response from TX stub\n"; + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); } - } - usrp_rx_stop = false; + if(d_disk_write) + d_ofile.write((const char *)samples, n_bytes); + + pmt_t v_pkt = pmt_make_u8vector(sizeof(transport_pkt), 0); + transport_pkt *pkt = + (transport_pkt *) pmt_u8vector_writeable_elements(v_pkt, ignore); + + pkt->set_header(0, channel, 0, n_bytes); + pkt->set_timestamp(0xffffffff); + memcpy(pkt->payload(), samples, n_bytes); + + d_cs->send(s_response_usrp_rx_read, pmt_list3(PMT_NIL, PMT_T, v_pkt)); - if(verbose) - std::cout << "[USRP_RX_STUB] Got fake RX stop\n"; + // Now lets check the shared CS queue between the TX and RX stub. Each + // element in a queue is a list where the first element is an invocation + // handle and the second element is a PMT u8 vect representation of the + // CS packet response which can just be passed transparently. + while(!d_cs_queue.empty()) { + + pmt_t cs_pkt = d_cs_queue.front(); + d_cs_queue.pop(); + + pmt_t invocation_handle = pmt_nth(0, cs_pkt); + pmt_t v_pkt = pmt_nth(1, cs_pkt); + + d_cs->send(s_response_usrp_rx_read, + pmt_list3(invocation_handle, + PMT_T, + v_pkt)); // Take the front CS pkt + + + if(verbose) + std::cout << "[USRP_RX_STUB] Received CS response from TX stub\n"; + } } diff --git a/usrp/host/lib/inband/usrp_rx_stub.h b/usrp/host/lib/inband/usrp_rx_stub.h index 5a75bf00a..9cf308a99 100644 --- a/usrp/host/lib/inband/usrp_rx_stub.h +++ b/usrp/host/lib/inband/usrp_rx_stub.h @@ -31,9 +31,12 @@ typedef usrp_inband_usb_packet transport_pkt; -extern bool usrp_rx_stop; // used to communicate a 'stop' to the RX stub +extern bool usrp_rx_stop_stub; // used to communicate a 'stop' to the RX stub extern std::queue<pmt_t> d_cs_queue; +static pmt_t s_timeout = pmt_intern("%timeout"); +static pmt_t s_done = pmt_intern("done"); + /*! * \brief Implements the low level usb interface to the USRP */ @@ -45,6 +48,10 @@ class usrp_rx_stub : public mb_mblock usrp_standard_rx* d_urx; long d_samples_per_frame; + long d_decim_rx; + + mb_time d_t0; + double d_delta_t; // for generating sine wave output ui_nco<float,float> d_nco; @@ -61,8 +68,9 @@ class usrp_rx_stub : public mb_mblock void handle_message(mb_message_sptr msg); private: - void read_and_respond(pmt_t data); + void read_and_respond(); void read_data(); + void start_packet_timer(); }; diff --git a/usrp/host/lib/inband/usrp_server.cc b/usrp/host/lib/inband/usrp_server.cc index 1948a43b2..6a3643e56 100644 --- a/usrp/host/lib/inband/usrp_server.cc +++ b/usrp/host/lib/inband/usrp_server.cc @@ -29,6 +29,8 @@ #include <vector> #include <usrp_usb_interface.h> #include <string.h> +#include <fpga_regs_common.h> +#include <fpga_regs_standard.h> #include <symbols_usrp_server_cs.h> #include <symbols_usrp_channel.h> @@ -53,13 +55,42 @@ str(long x) usrp_server::usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg) : mb_mblock(rt, instance_name, user_arg), + d_fpga_debug(false), + d_interp_tx(128), // these should match the lower level defaults (rx also) + d_decim_rx(128), d_fake_rx(false) { if(verbose) std::cout << "[USRP_SERVER] Initializing...\n"; // Dictionary for arguments to all of the components - pmt_t usrp_dict = user_arg; + d_usrp_dict = user_arg; + + if (pmt_is_dict(d_usrp_dict)) { + + if(pmt_t fpga_debug = pmt_dict_ref(d_usrp_dict, + pmt_intern("fpga-debug"), + PMT_NIL)) { + if(pmt_eqv(fpga_debug, PMT_T)) + d_fpga_debug=true; + } + + // Read the TX interpolations + if(pmt_t interp_tx = pmt_dict_ref(d_usrp_dict, + pmt_intern("interp-tx"), + PMT_NIL)) { + if(!pmt_eqv(interp_tx, PMT_NIL)) + d_interp_tx = pmt_to_long(interp_tx); + } + + // Read the RX decimation rate + if(pmt_t decim_rx = pmt_dict_ref(d_usrp_dict, + pmt_intern("decim-rx"), + PMT_NIL)) { + if(!pmt_eqv(decim_rx, PMT_NIL)) + d_decim_rx = pmt_to_long(decim_rx); + } + } // control & status port d_cs = define_port("cs", "usrp-server-cs", true, mb_port::EXTERNAL); @@ -82,7 +113,7 @@ usrp_server::usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t mb_port::EXTERNAL)); } - define_component("usrp", "usrp_usb_interface", usrp_dict); + define_component("usrp", "usrp_usb_interface", d_usrp_dict); connect("self", "cs_usrp", "usrp", "cs"); d_defer=false; @@ -108,6 +139,10 @@ usrp_server::usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t //d_fake_rx=true; } +/*! + * \brief resets the assigned capacity and owners of each RX and TX channel from + * allocations. + */ void usrp_server::reset_channels() { @@ -136,6 +171,11 @@ usrp_server::initial_transition() // the initial transition } +/*! + * \brief Reads all incoming messages to USRP server from the TX, RX, and the CS + * ports. This drives the state of USRP server and dispatches based on the + * message. + */ void usrp_server::handle_message(mb_message_sptr msg) { @@ -178,6 +218,9 @@ usrp_server::handle_message(mb_message_sptr msg) pmt_t status = pmt_nth(1, data); d_cs->send(s_response_open, pmt_list2(invocation_handle, status)); + //reset_all_registers(); + //initialize_registers(); + if(pmt_eqv(status,PMT_T)) { d_opened = true; d_defer = false; @@ -209,7 +252,7 @@ usrp_server::handle_message(mb_message_sptr msg) // Do not report back responses if they were generated from a // command packet - if(channel == 0x1f) + if(channel == CONTROL_CHAN) return; // Find the port through the owner of the channel @@ -470,7 +513,14 @@ usrp_server::handle_message(mb_message_sptr msg) std::cout << "[USRP_SERVER] unhandled msg: " << msg << std::endl; } -// Return -1 if it is not an RX port, or an index +/*! + * \brief Takes a port_symbol() as parameter \p port_id and is used to determine + * if the port is a TX port, or to find an index in the d_tx vector which stores + * the port. + * + * \returns -1 if \p port_id is not in the d_tx vector (i.e., it's not a TX + * port), otherwise returns an index in the d_tx vector which stores the port. + */ int usrp_server::tx_port_index(pmt_t port_id) { for(int i=0; i < (int) d_tx.size(); i++) @@ -480,7 +530,14 @@ int usrp_server::tx_port_index(pmt_t port_id) { return -1; } -// Return -1 if it is not an RX port, or an index +/*! + * \brief Takes a port_symbol() as parameter \p port_id and is used to determine + * if the port is an RX port, or to find an index in the d_rx vector which + * stores the port. + * + * \returns -1 if \p port_id is not in the d_rx vector (i.e., it's not an RX + * port), otherwise returns an index in the d_rx vector which stores the port. + */ int usrp_server::rx_port_index(pmt_t port_id) { for(int i=0; i < (int) d_rx.size(); i++) @@ -490,8 +547,12 @@ int usrp_server::rx_port_index(pmt_t port_id) { return -1; } -// Go through all TX and RX channels, sum up the assigned capacity -// and return it +/*! + * \brief Determines the current total capacity allocated by all RX and TX + * channels. + * + * \returns the total allocated capacity + */ long usrp_server::current_capacity_allocation() { long capacity = 0; @@ -504,6 +565,14 @@ long usrp_server::current_capacity_allocation() { return capacity; } + +/*! + * \brief Called by the handle_message() method if the incoming message to + * usrp_server is to allocate a channel (cmd-allocate-channel). The method + * checks if the requested capacity exists and if so it will reserve it for the + * caller on the channel that is returned via a response-allocate-channel + * signal. + */ void usrp_server::handle_cmd_allocate_channel( mb_port_sptr port, @@ -564,9 +633,13 @@ usrp_server::handle_cmd_allocate_channel( return; } -// Check the port type and deallocate assigned capacity based on this, ensuring -// that the owner of the method invocation is the owner of the port and that the -// channel number is valid. +/*! + * \brief Called by the handle_message() method if the incoming message to + * usrp_server is to deallocate a channel (cmd-deallocate-channel). The method + * ensures that the sender of the signal owns the channel and that the channel + * number is valid. A response-deallocate-channel signal is sent back with the + * result of the deallocation. + */ void usrp_server::handle_cmd_deallocate_channel( mb_port_sptr port, @@ -591,8 +664,26 @@ usrp_server::handle_cmd_deallocate_channel( return; } -void usrp_server::handle_cmd_xmit_raw_frame(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data) { - +/*! + * \brief Called by the handle_message() method if the incoming message to + * usrp_server is to transmit a frame (cmd-xmit-raw-frame). The method + * allocates enough memory to support a burst of packets which contain the frame + * over the bus of the frame, sets the packet headers, and sends a signal to the + * lower block for the data (packets) to be written to the bus. + * + * The \p port the command was sent on and the channel info (\p chan_info) of + * the channel the frame is to be transmitted on are passed to ensure that the + * caller owns the channel. + * + * The \p data parameter is in the format of a cmd-xmit-raw-frame signal. + * + * The properties + */ +void usrp_server::handle_cmd_xmit_raw_frame( + mb_port_sptr port, + std::vector<struct channel_info> &chan_info, + pmt_t data) +{ size_t n_bytes, psize; long max_payload_len = transport_pkt::max_payload(); @@ -667,7 +758,8 @@ void usrp_server::handle_cmd_xmit_raw_frame(mb_port_sptr port, std::vector<struc << invocation_handle << std::endl; // The actual response to the write will be generated by a - // s_response_usrp_write + // s_response_usrp_write since we cannot determine whether to transmit was + // successful until we hear from the lower layers. d_cs_usrp->send(s_cmd_usrp_write, pmt_list3(invocation_handle, pmt_from_long(channel), @@ -676,7 +768,29 @@ void usrp_server::handle_cmd_xmit_raw_frame(mb_port_sptr port, std::vector<struc return; } -void usrp_server::handle_cmd_to_control_channel(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data) +/*! + * \brief Called by the handle_message() method to parse incoming control/status + * signals (cmd-to-control-channel). + * + * The \p port the command was sent on and the channel info (\p chan_info) of + * the channel are passed to ensure that the caller owns the channel. + * + * The \p data parameter is in the format of a PMT list, where each element + * follows the format of a control/status signal (i.e. op-ping-fixed). + * + * The method will parse all of the C/S commands included in \p data and place + * the commands in to a lower level packet sent to the control channel. The + * method will pack as many commands as possible in t oa single packet, and once + * it is fill generate as many lower level packets as needed. + * + * Anything that needs to be returned to the sender of the signal (i.e. the + * value of a register) will be generated by the parse_control_pkt() method as + * the responses to the commands are read back from the USRP. + */ +void usrp_server::handle_cmd_to_control_channel( + mb_port_sptr port, + std::vector<struct channel_info> &chan_info, + pmt_t data) { pmt_t invocation_handle = pmt_nth(0, data); @@ -687,7 +801,10 @@ void usrp_server::handle_cmd_to_control_channel(mb_port_sptr port, std::vector<s size_t psize; long payload_len = 0; - long channel = 0x1f; + long channel = CONTROL_CHAN; + + if(verbose) + std::cout << "[USRP_SERVER] Handling " << n_subpkts << " commands\n"; // The design of the following code is optimized for simplicity, not // performance. To performance optimize this code, the total size in bytes @@ -990,8 +1107,22 @@ void usrp_server::handle_cmd_to_control_channel(mb_port_sptr port, std::vector<s return; } +/*! + * \brief Called by the handle_message() method when the incoming signal is a + * command to start reading samples from the USRP (cmd-start-recv-raw-samples). + * + * The \p port the command was sent on and the channel info (\p chan_info) of + * the channel are passed to ensure that the caller owns the channel. + * + * The \p data parameter should be in the format of a cmd-start-recv-raw-samples + * command where the first element in the list is an invocation handle, and the + * second is the channel the signal generator wants to receive the samples on. + */ void -usrp_server::handle_cmd_start_recv_raw_samples(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data) +usrp_server::handle_cmd_start_recv_raw_samples( + mb_port_sptr port, + std::vector<struct channel_info> &chan_info, + pmt_t data) { pmt_t invocation_handle = pmt_nth(0, data); long channel = pmt_to_long(pmt_nth(1, data)); @@ -1032,6 +1163,18 @@ usrp_server::handle_cmd_start_recv_raw_samples(mb_port_sptr port, std::vector<st return; } +/*! + * \brief Called by the handle_message() method when the incoming signal is to + * stop receiving samples from the USRP (cmd-stop-recv-raw-samples). + * + * The \p port the command was sent on and the channel info (\p chan_info) of + * the channel are passed to ensure that the caller owns the channel. + * + * The \p data parameter should be in the format of a cmd-stop-recv-raw-samples + * command where the first element in the list is an invocation handle, and the + * second is the channel the signal generator wants to stop receiving the + * samples from. + */ void usrp_server::handle_cmd_stop_recv_raw_samples( mb_port_sptr port, @@ -1067,7 +1210,22 @@ usrp_server::handle_cmd_stop_recv_raw_samples( return; } -// Read the packet header, determine the port by the channel owner +/*! + * \brief Called by the handle_message() method when an incoming signal is + * generated to USRP server that contains raw samples from the USRP. This + * method generates the response-recv-raw-samples signals that are the result of + * a cmd-start-recv-raw-samples signal. + * + * The raw lower-level packet is extracted from \p data, where the format for \p + * data is a PMT list. The PMT \p data list should contain an invocation handle + * as the first element, the status of the lower-level read as the second + * element, and a uniform vector representation of the packets as the third + * element. + * + * The packet contains a channel field that the samples are destined to, and the + * method determines where to send the samples based on this channel since each + * channel has an associated port which allocated it. + */ void usrp_server::handle_response_usrp_read(pmt_t data) { @@ -1106,7 +1264,7 @@ usrp_server::handle_response_usrp_read(pmt_t data) return; // If the packet is a C/S packet, parse it separately - if(channel == 0x1f) { + if(channel == CONTROL_CHAN) { parse_control_pkt(invocation_handle, pkt); return; } @@ -1137,14 +1295,28 @@ usrp_server::handle_response_usrp_read(pmt_t data) PMT_T); d_rx[port]->send(s_response_recv_raw_samples, - pmt_list5(invocation_handle, + pmt_list6(invocation_handle, status, v_samples, pmt_from_long(pkt->timestamp()), + pmt_from_long(channel), properties)); return; } +/*! + * \brief Called by handle_response_usrp_read() when the incoming packet has a + * channel of CONTROL_CHAN. This means that the incoming packet contains a + * response for a command sent to the control channel, which this method will + * parse. + * + * The \p pkt parameter is a pointer to the full packet (transport_pkt) in + * memory. + * + * Given that all commands sent to the control channel that require responses + * will carry an RID (request ID), the method will use the RID passed back with + * the response to determine which port the response should be sent on. + */ void usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt) { @@ -1190,6 +1362,9 @@ usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt) return; pmt_t owner = d_rids[srid].owner; + + // Return the RID + d_rids[srid].owner = PMT_NIL; // FIXME: should be 1 response for all subpackets here ? if((port = tx_port_index(owner)) != -1) @@ -1225,6 +1400,9 @@ usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt) return; pmt_t owner = d_rids[srid].owner; + + // Return the RID + d_rids[srid].owner = PMT_NIL; // FIXME: should be 1 response for all subpackets here ? if((port = tx_port_index(owner)) != -1) @@ -1261,6 +1439,9 @@ usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt) return; pmt_t owner = d_rids[srid].owner; + + // Return the RID + d_rids[srid].owner = PMT_NIL; if((port = tx_port_index(owner)) != -1) d_tx[port]->send(s_response_from_control_channel, @@ -1294,6 +1475,9 @@ usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt) return; pmt_t owner = d_rids[srid].owner; + + // Return the RID + d_rids[srid].owner = PMT_NIL; if((port = tx_port_index(owner)) != -1) d_tx[port]->send(s_response_from_control_channel, @@ -1317,6 +1501,10 @@ usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt) } } +/*! + * \brief Used to recall all incoming signals that were deferred when USRP + * server was in the initialization state. + */ void usrp_server::recall_defer_queue() { @@ -1335,6 +1523,25 @@ usrp_server::recall_defer_queue() return; } +/*! + * \brief Commonly called by any method which handles outgoing frames or control + * packets to the USRP to check if the port on which the signal was sent owns + * the channel the outgoing packet will be associated with. This helps ensure + * that applications do not send data on other application's ports. + * + * The \p port parameter is the port symbol that the caller wishes to determine + * owns the channel specified by \p chan_info. + * + * The \p signal_info parameter is a PMT list containing two elements: the + * response signal to use if the permissions are invalid, and the invocation + * handle that was passed. This allows the method to generate detailed failure + * responses to signals without having to return some sort of structured + * information which the caller must then parse and interpret to determine the + * failure type. + * + * \returns true if \p port owns the channel specified by \p chan_info, false + * otherwise. + */ bool usrp_server::check_valid(mb_port_sptr port, long channel, @@ -1346,7 +1553,7 @@ usrp_server::check_valid(mb_port_sptr port, pmt_t invocation_handle = pmt_nth(1, signal_info); // not a valid channel number? - if(channel >= (long)chan_info.size() && channel != 0x1f) { + if(channel >= (long)chan_info.size() && channel != CONTROL_CHAN) { port->send(response_signal, pmt_list2(invocation_handle, s_err_channel_invalid)); @@ -1377,8 +1584,12 @@ usrp_server::check_valid(mb_port_sptr port, return true; } -// Goes through the vector of RIDs and retreieves an -// available one for use +/*! + * \brief Finds the next available RID for internal USRP server use with control + * and status packets. + * + * \returns the next valid RID or -1 if no more RIDs are available. + */ long usrp_server::next_rid() { @@ -1386,7 +1597,264 @@ usrp_server::next_rid() if(pmt_eqv(d_rids[i].owner, PMT_NIL)) return i; + if(verbose) + std::cout << "[USRP_SERVER] No RIDs left\n"; return -1; } +/*! + * \brief Called by handle_message() when USRP server gets a response that the + * USRP was opened successfully to initialize the registers using the new + * register read/write control packets. + */ +void +usrp_server::initialize_registers() +{ + // We use handle_cmd_to_control_channel() to create the register writes using + // PMT_NIL as the response port to tell usrp_server not to pass the response + // up to any application. + if(verbose) + std::cout << "[USRP_SERVER] Initializing registers...\n"; + + // RX mode to normal (0) + set_register(FR_MODE, 0); + + // FPGA debugging? + if(d_fpga_debug) { + set_register(FR_DEBUG_EN, 1); + // FIXME: need to figure out exact register writes to control daughterboard + // pins that need to be written to + } else { + set_register(FR_DEBUG_EN, 0); + } + + // Set the transmit sample rate divisor, which is 4-1 + set_register(FR_TX_SAMPLE_RATE_DIV, 3); + + // Dboard IO buffer and register settings + set_register(FR_OE_0, (0xffff << 16) | 0x0000); + set_register(FR_IO_0, (0xffff << 16) | 0x0000); + set_register(FR_OE_1, (0xffff << 16) | 0x0000); + set_register(FR_IO_1, (0xffff << 16) | 0x0000); + set_register(FR_OE_2, (0xffff << 16) | 0x0000); + set_register(FR_IO_2, (0xffff << 16) | 0x0000); + set_register(FR_OE_3, (0xffff << 16) | 0x0000); + set_register(FR_IO_3, (0xffff << 16) | 0x0000); + + // zero Tx side Auto Transmit/Receive regs + set_register(FR_ATR_MASK_0, 0); + set_register(FR_ATR_TXVAL_0, 0); + set_register(FR_ATR_RXVAL_0, 0); + set_register(FR_ATR_MASK_1, 0); + set_register(FR_ATR_TXVAL_1, 0); + set_register(FR_ATR_RXVAL_1, 0); + set_register(FR_ATR_MASK_2, 0); + set_register(FR_ATR_TXVAL_2, 0); + set_register(FR_ATR_RXVAL_2, 0); + set_register(FR_ATR_MASK_3, 0); + set_register(FR_ATR_TXVAL_3, 0); + set_register(FR_ATR_RXVAL_3, 0); + + // Configure TX mux, this is a hacked value + set_register(FR_TX_MUX, 0x00000081); + + // Set the interpolation rate, which is the rate divided by 4, minus 1 + set_register(FR_INTERP_RATE, (d_interp_tx/4)-1); + + // Apparently this register changes again + set_register(FR_TX_MUX, 0x00000981); + + // Set the receive sample rate divisor, which is 2-1 + set_register(FR_RX_SAMPLE_RATE_DIV, 1); + + // DC offset + set_register(FR_DC_OFFSET_CL_EN, 0x0000000f); + + // Reset the DC correction offsets + set_register(FR_ADC_OFFSET_0, 0); + set_register(FR_ADC_OFFSET_1, 0); + + // Some hard-coded RX configuration + set_register(FR_RX_FORMAT, 0x00000300); + set_register(FR_RX_MUX, 1); + + // RX decimation rate is divided by two, then subtract 1 + set_register(FR_DECIM_RATE, (d_decim_rx/2)-1); + + // More hard coding + set_register(FR_RX_MUX, 0x000e4e41); + + // Resetting RX registers + set_register(FR_RX_PHASE_0, 0); + set_register(FR_RX_PHASE_1, 0); + set_register(FR_RX_PHASE_2, 0); + set_register(FR_RX_PHASE_3, 0); + set_register(FR_RX_FREQ_0, 0x28000000); + set_register(FR_RX_FREQ_1, 0); + set_register(FR_RX_FREQ_2, 0); + set_register(FR_RX_FREQ_3, 0); + + // Enable debug bus + set_register(FR_DEBUG_EN, 0xf); + set_register(FR_OE_0, -1); + set_register(FR_OE_1, -1); + set_register(FR_OE_2, -1); + set_register(FR_OE_3, -1); + + // DEBUGGING + //check_register_initialization(); +} + +// FIXME: used for debugging to determine if all the registers are actually +// being set correctly +void +usrp_server::check_register_initialization() +{ + // RX mode to normal (0) + read_register(FR_MODE); + + // FPGA debugging? + if(d_fpga_debug) { + read_register(FR_DEBUG_EN); + // FIXME: need to figure out exact register writes to control daughterboard + // pins that need to be written to + } else { + read_register(FR_DEBUG_EN); + } + + // Set the transmit sample rate divisor, which is 4-1 + read_register(FR_TX_SAMPLE_RATE_DIV); + + // Dboard IO buffer and register settings + read_register(FR_OE_0); + read_register(FR_IO_0); + read_register(FR_OE_1); + read_register(FR_IO_1); + read_register(FR_OE_2); + read_register(FR_IO_2); + read_register(FR_OE_3); + read_register(FR_IO_3); + + // zero Tx side Auto Transmit/Receive regs + read_register(FR_ATR_MASK_0); + read_register(FR_ATR_TXVAL_0); + read_register(FR_ATR_RXVAL_0); + read_register(FR_ATR_MASK_1); + read_register(FR_ATR_TXVAL_1); + read_register(FR_ATR_RXVAL_1); + read_register(FR_ATR_MASK_2); + read_register(FR_ATR_TXVAL_2); + read_register(FR_ATR_RXVAL_2); + read_register(FR_ATR_MASK_3); + read_register(FR_ATR_TXVAL_3); + read_register(FR_ATR_RXVAL_3); + + // Configure TX mux, this is a hacked value + read_register(FR_TX_MUX); + + // Set the interpolation rate, which is the rate divided by 4, minus 1 + read_register(FR_INTERP_RATE); + + // Apparently this register changes again + read_register(FR_TX_MUX); + + // Set the receive sample rate divisor, which is 2-1 + read_register(FR_RX_SAMPLE_RATE_DIV); + + // DC offset + read_register(FR_DC_OFFSET_CL_EN); + + // Reset the DC correction offsets + read_register(FR_ADC_OFFSET_0); + read_register(FR_ADC_OFFSET_1); + + // Some hard-coded RX configuration + read_register(FR_RX_FORMAT); + read_register(FR_RX_MUX); + + // RX decimation rate is divided by two, then subtract 1 + read_register(FR_DECIM_RATE); + + // More hard coding + read_register(FR_RX_MUX); + + // Resetting RX registers + read_register(FR_RX_PHASE_0); + read_register(FR_RX_PHASE_1); + read_register(FR_RX_PHASE_2); + read_register(FR_RX_PHASE_3); + read_register(FR_RX_FREQ_0); + read_register(FR_RX_FREQ_1); + read_register(FR_RX_FREQ_2); + read_register(FR_RX_FREQ_3); +} + +/*! + * \brief Used to generate FPGA register write commands to reset all of the FPGA + * registers to a value of 0. + */ +void +usrp_server::reset_all_registers() +{ + for(int i=0; i<64; i++) + set_register(i, 0); +} + +/*! + * \brief Used internally by USRP server to generate a control/status packet + * which contains a register write. + * + * The \p reg parameter is the register number that the value \p val will be + * written to. + */ +void +usrp_server::set_register(long reg, long val) +{ + size_t psize; + long payload_len = 0; + + pmt_t v_packet = pmt_make_u8vector(sizeof(transport_pkt), 0); + transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writeable_elements(v_packet, psize); + + pkt->set_header(0, CONTROL_CHAN, 0, payload_len); + pkt->set_timestamp(0xffffffff); + + pkt->cs_write_reg(reg, val); + + d_cs_usrp->send(s_cmd_usrp_write, + pmt_list3(PMT_NIL, + pmt_from_long(CONTROL_CHAN), + v_packet)); +} + +/*! + * \brief Used internally by USRP server to generate a control/status packet + * which contains a register read. This is important to use internally so that + * USRP server can bypass the use of RIDs with register reads, as they are not + * needed and it would use up the finite number of RIDs available for use for + * applications to receive responses. + * + * The \p reg parameter is the register number that the value should be read + * from. + */ +void +usrp_server::read_register(long reg) +{ + size_t psize; + long payload_len = 0; + + pmt_t v_packet = pmt_make_u8vector(sizeof(transport_pkt), 0); + transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writeable_elements(v_packet, psize); + + pkt->set_header(0, CONTROL_CHAN, 0, payload_len); + pkt->set_timestamp(0xffffffff); + + pkt->cs_read_reg(0, reg); + + d_cs_usrp->send(s_cmd_usrp_write, + pmt_list3(PMT_NIL, + pmt_from_long(CONTROL_CHAN), + v_packet)); +} + REGISTER_MBLOCK_CLASS(usrp_server); diff --git a/usrp/host/lib/inband/usrp_server.h b/usrp/host/lib/inband/usrp_server.h index 81dceb1f4..09c82faac 100644 --- a/usrp/host/lib/inband/usrp_server.h +++ b/usrp/host/lib/inband/usrp_server.h @@ -51,6 +51,13 @@ public: long d_ntx_chan; long d_nrx_chan; + pmt_t d_usrp_dict; + + bool d_fpga_debug; + + long d_interp_tx; + long d_decim_rx; + // Keep track of the request IDs struct rid_info { pmt_t owner; @@ -114,6 +121,11 @@ private: bool check_valid(mb_port_sptr port, long channel, std::vector<struct channel_info> &chan_info, pmt_t signal_info); void parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt); long next_rid(); + void initialize_registers(); + void set_register(long reg, long val); + void read_register(long reg); + void check_register_initialization(); + void reset_all_registers(); }; #endif /* INCLUDED_USRP_SERVER_H */ diff --git a/usrp/host/lib/inband/usrp_server.mbh b/usrp/host/lib/inband/usrp_server.mbh index 3fd0db139..ed7943fc3 100644 --- a/usrp/host/lib/inband/usrp_server.mbh +++ b/usrp/host/lib/inband/usrp_server.mbh @@ -202,7 +202,7 @@ (:incoming - (response-recv-raw-samples invocation-handle status samples timestamp properties) + (response-recv-raw-samples invocation-handle status samples timestamp channel properties) ;; samples is a uniform numeric vector. The contents of the sample ;; vector is treated as opaque and is passed from the FPGA diff --git a/usrp/host/lib/inband/usrp_tx.cc b/usrp/host/lib/inband/usrp_tx.cc index a7a5e4a89..da8777513 100644 --- a/usrp/host/lib/inband/usrp_tx.cc +++ b/usrp/host/lib/inband/usrp_tx.cc @@ -66,6 +66,10 @@ usrp_tx::initial_transition() } +/*! + * \brief Handles incoming signals to to the m-block, wihch should only ever be + * a single message: cmd-usrp-tx-write. + */ void usrp_tx::handle_message(mb_message_sptr msg) { @@ -82,6 +86,14 @@ usrp_tx::handle_message(mb_message_sptr msg) } } +/*! + * \brief Performs the actual writing of data to the USB bus, called by + * handle_message() when a cmd-usrp-tx-write signal is received. + * + * The \p data parameter is a PMT list which contains three mandatory elements, + * in the following order: an invocation handle, a channel, and a uniform vector + * of memory which contains the packets to be written to the bus. + */ void usrp_tx::write(pmt_t data) { @@ -121,7 +133,7 @@ usrp_tx::write(pmt_t data) for(int i=0; i < n_packets; i++) { if(d_disk_write) { - if(pkts[i].chan() == 0x1f) + if(pkts[i].chan() == CONTROL_CHAN) d_cs_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size()); else d_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size()); diff --git a/usrp/host/lib/inband/usrp_tx_stub.cc b/usrp/host/lib/inband/usrp_tx_stub.cc index 7a9876322..6cff3b4ee 100644 --- a/usrp/host/lib/inband/usrp_tx_stub.cc +++ b/usrp/host/lib/inband/usrp_tx_stub.cc @@ -103,7 +103,7 @@ usrp_tx_stub::write(pmt_t data) for(long i=0; i<n_packets; i++) { if(d_disk_write) { - if(pkts[i].chan() == 0x1f) + if(pkts[i].chan() == CONTROL_CHAN) d_cs_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size()); else d_ofile.write((const char *)&pkts[i], transport_pkt::max_pkt_size()); @@ -112,7 +112,7 @@ usrp_tx_stub::write(pmt_t data) d_ofile.flush(); } - if(pkts[i].chan() == 0x1f) + if(pkts[i].chan() == CONTROL_CHAN) parse_cs(invocation_handle, pkts[i]); } @@ -140,7 +140,7 @@ usrp_tx_stub::parse_cs(pmt_t invocation_handle, transport_pkt pkt) transport_pkt *q_pkt = (transport_pkt *) pmt_u8vector_writeable_elements(v_pkt, ignore); - q_pkt->set_header(0, 0x1f, 0, 0); + q_pkt->set_header(0, CONTROL_CHAN, 0, 0); q_pkt->set_timestamp(0xffffffff); // We dispatch based on the control packet type, however we can extract the diff --git a/usrp/host/lib/inband/usrp_usb_interface.cc b/usrp/host/lib/inband/usrp_usb_interface.cc index 269ed2706..51b6d4646 100644 --- a/usrp/host/lib/inband/usrp_usb_interface.cc +++ b/usrp/host/lib/inband/usrp_usb_interface.cc @@ -47,12 +47,16 @@ static pmt_t s_shutdown = pmt_intern("%shutdown"); static const bool verbose = false; - -// need to take number of TX and RX channels as parameter +/*! + * \brief Initializes the USB interface m-block. + * + * The \p user_arg should be a PMT dictionary which can contain optional + * arguments for the block, such as the decimatoin and interpolation rate. + */ usrp_usb_interface::usrp_usb_interface(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg) : mb_mblock(rt, instance_name, user_arg), - d_fpga_debug(false), d_fake_usrp(false), + d_rx_reading(false), d_interp_tx(128), d_decim_rx(128), d_rf_freq(10e6), @@ -86,7 +90,7 @@ usrp_usb_interface::usrp_usb_interface(mb_runtime *rt, const std::string &instan d_interp_tx = pmt_to_long(interp_tx); } - // Read the RX interpolations + // Read the RX decimation rate if(pmt_t decim_rx = pmt_dict_ref(usrp_dict, pmt_intern("decim-rx"), PMT_NIL)) { @@ -134,8 +138,8 @@ usrp_usb_interface::usrp_usb_interface(mb_runtime *rt, const std::string &instan d_tx_cs = define_port("tx_cs", "usrp-tx-cs", false, mb_port::INTERNAL); // Connect to TX and RX - define_component("tx", tx_interface, PMT_F); - define_component("rx", rx_interface, PMT_F); + define_component("tx", tx_interface, usrp_dict); + define_component("rx", rx_interface, usrp_dict); connect("self", "rx_cs", "rx", "cs"); connect("self", "tx_cs", "tx", "cs"); @@ -146,8 +150,6 @@ usrp_usb_interface::usrp_usb_interface(mb_runtime *rt, const std::string &instan d_utx = NULL; d_urx = NULL; - d_fpga_debug=true; // WARNING: DO NOT ENABLE WITH D'BOARDS OTHER THAN BASIC TX/RX - } usrp_usb_interface::~usrp_usb_interface() @@ -161,6 +163,10 @@ usrp_usb_interface::initial_transition() } +/*! + * \brief Handles all incoming signals to the block from the lowest m-blocks + * which read/write to the bus, or the higher m-block which is the USRP server. + */ void usrp_usb_interface::handle_message(mb_message_sptr msg) { @@ -256,6 +262,13 @@ usrp_usb_interface::handle_message(mb_message_sptr msg) std::cout << "[USRP_USB_INTERFACE] unhandled msg: " << msg << std::endl; } +/*! + * \brief Called by the handle_message() method when the incoming signal is to + * open a USB connection to the USRP (cmd-usrp-open). + * + * The \p data parameter is a PMT list, where the elements are an invocation + * handle and the USRP number. + */ void usrp_usb_interface::handle_cmd_open(pmt_t data) { @@ -290,7 +303,7 @@ usrp_usb_interface::handle_cmd_open(pmt_t data) return; } - if(!d_utx->set_tx_freq (0,d_rf_freq)) { // try setting center freq to 0 + if(!d_utx->set_tx_freq (0,d_rf_freq) || !d_utx->set_tx_freq(1,d_rf_freq)) { // try setting center freq to 0 if (verbose) std::cout << "[USRP_USB_INTERFACE] Failed to set center frequency on TX\n"; reply_data = pmt_list2(invocation_handle, PMT_F); @@ -298,6 +311,14 @@ usrp_usb_interface::handle_cmd_open(pmt_t data) return; } + if(!d_utx->set_mux(0xBA98)) { + if (verbose) + std::cout << "[USRP_USB_INTERFACE] Failed to set TX mux\n"; + reply_data = pmt_list2(invocation_handle, PMT_F); + d_cs->send(s_response_usrp_open, reply_data); + return; + } + d_utx->start(); if (verbose) @@ -321,33 +342,44 @@ usrp_usb_interface::handle_cmd_open(pmt_t data) return; } - if(!d_urx->set_rx_freq (0, d_rf_freq)) { + if(!d_urx->set_rx_freq (0, -d_rf_freq) || !d_urx->set_rx_freq(1, -d_rf_freq)) { if (verbose) std::cout << "[usrp_server] Failed to set center frequency on RX\n"; reply_data = pmt_list2(invocation_handle, PMT_F); d_cs->send(s_response_usrp_open, reply_data); return; } - - if(d_fpga_debug) { - d_utx->_write_fpga_reg(FR_DEBUG_EN,0xf); - d_utx->_write_oe(0, 0xffff, 0xffff); - d_urx->_write_oe(0, 0xffff, 0xffff); - d_utx->_write_oe(1, 0xffff, 0xffff); - d_urx->_write_oe(1, 0xffff, 0xffff); - -// while(1){ -// for(int i=0; i<0xffff; i++) -// d_urx->write_io(0, i, 0xffff); -// } - } + // Two channels ... this really needs to end up being set correctly by + // querying for what dboards are connected + if(!d_urx->set_mux(0x32103210)) { + if (verbose) + std::cout << "[USRP_USB_INTERFACE] Failed to set RX mux\n"; + reply_data = pmt_list2(invocation_handle, PMT_F); + d_cs->send(s_response_usrp_open, reply_data); + return; + } + if (verbose) std::cout << "[USRP_USB_INTERFACE] Setup RX channel\n"; + +// d_utx->_write_fpga_reg(FR_DEBUG_EN,0xf); +// d_utx->_write_oe(0, 0xffff, 0xffff); +// d_urx->_write_oe(0, 0xffff, 0xffff); +// d_utx->_write_oe(1, 0xffff, 0xffff); +// d_urx->_write_oe(1, 0xffff, 0xffff); d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T)); } +/*! + * \brief Called by the handle_message() method when the incoming signal is to + * write data to the USB bus (cmd-usrp-write). + * + * The \p data parameter is a PMT list containing 3 mandatory elements in the + * following order: an invocation handle, channel, and a uniform vector + * representation of the packets. + */ void usrp_usb_interface::handle_cmd_write(pmt_t data) { @@ -366,6 +398,13 @@ usrp_usb_interface::handle_cmd_write(pmt_t data) return; } +/*! + * \brief Called by the handle_message() method when the incoming signal is to + * start reading data from the USB bus (cmd-usrp-start-reading). + * + * The \p data parameter is a PMT list with a single element: an invocation + * handle which can be returned with the response. + */ void usrp_usb_interface::handle_cmd_start_reading(pmt_t data) { @@ -381,9 +420,18 @@ usrp_usb_interface::handle_cmd_start_reading(pmt_t data) d_rx_cs->send(s_cmd_usrp_rx_start_reading, pmt_list2(PMT_NIL, rx_handle)); + d_rx_reading = true; + return; } +/*! + * \brief Called by the handle_message() method when the incoming signal is to + * stop reading data from the USB bus (cmd-usrp-stop-reading). + * + * The \p data parameter is a PMT list with a single element: an invocation + * handle which can be returned with the response. + */ void usrp_usb_interface::handle_cmd_stop_reading(pmt_t data) { @@ -392,22 +440,40 @@ usrp_usb_interface::handle_cmd_stop_reading(pmt_t data) if(!d_fake_usrp) { if(verbose) std::cout << "[USRP_USB_INTERFACE] Stopping RX...\n"; + usrp_rx_stop = true; + + // Used to allow a read() being called by a lower layer to complete before + // stopping, else there can be partial data left on the bus and can generate + // errors. + while(usrp_rx_stop) {usleep(1);} d_urx->stop(); } else { if(verbose) std::cout << "[USRP_USB_INTERFACE] Stopping fake RX...\n"; - usrp_rx_stop = true; // extern to communicate with stub to wait + usrp_rx_stop_stub = true; // extern to communicate with stub to wait } + d_rx_reading = false; + return; } +/*! + * \brief Called by the handle_message() method when the incoming signal is to + * close the USB connection to the USRP. + * + * The \p data parameter is a PMT list with a single element: an invocation + * handle which can be returned with the response. + */ void usrp_usb_interface::handle_cmd_close(pmt_t data) { pmt_t invocation_handle = pmt_nth(0, data); + if(d_rx_reading) + handle_cmd_stop_reading(PMT_NIL); + if(d_fake_usrp) { d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T)); return; diff --git a/usrp/host/lib/inband/usrp_usb_interface.h b/usrp/host/lib/inband/usrp_usb_interface.h index 8efce2ff6..6c2c15768 100644 --- a/usrp/host/lib/inband/usrp_usb_interface.h +++ b/usrp/host/lib/inband/usrp_usb_interface.h @@ -42,10 +42,10 @@ class usrp_usb_interface : public mb_mblock long d_ntx_chan; long d_nrx_chan; - long d_fpga_debug; - bool d_fake_usrp; + bool d_rx_reading; + long d_interp_tx; long d_decim_rx; diff --git a/usrp/host/lib/legacy/fusb_linux.cc b/usrp/host/lib/legacy/fusb_linux.cc index 60687a149..6dce8d9e0 100644 --- a/usrp/host/lib/legacy/fusb_linux.cc +++ b/usrp/host/lib/legacy/fusb_linux.cc @@ -386,14 +386,6 @@ fusb_ephandle_linux::stop () { if (!d_started) return true; - - d_devhandle->_cancel_pending_rqsts (this); - d_devhandle->_reap (false); - - - usbdevfs_urb *urb; - while ((urb = completed_list_get ()) != 0) - free_list_add (urb); if (d_write_work_in_progress){ free_list_add (d_write_work_in_progress); @@ -407,11 +399,19 @@ fusb_ephandle_linux::stop () d_read_buffer_end = 0; } - if (d_free_list.size () != (unsigned) d_nblocks) - fprintf (stderr, "d_free_list.size () = %d, d_nblocks = %d\n", - d_free_list.size (), d_nblocks); - - assert (d_free_list.size () == (unsigned) d_nblocks); + d_devhandle->_cancel_pending_rqsts (this); + d_devhandle->_reap (false); + + while (1){ + usbdevfs_urb *urb; + while ((urb = completed_list_get ()) != 0) + free_list_add (urb); + + if (d_free_list.size () == (unsigned) d_nblocks) + break; + + d_devhandle->_reap(true); + } d_started = false; return true; |