diff options
76 files changed, 11215 insertions, 1279 deletions
diff --git a/Makefile.common b/Makefile.common index 2976e36dc..33a3a7c2a 100644 --- a/Makefile.common +++ b/Makefile.common @@ -76,7 +76,9 @@ GNURADIO_I = $(top_srcdir)/gnuradio-core/src/lib/swig/gnuradio.i USRP_INCLUDES = -I$(top_srcdir)/usrp/host/lib/legacy \ -I$(top_srcdir)/usrp/host/lib/inband \ -I$(top_srcdir)/usrp/firmware/include -USRP_LA = $(top_builddir)/usrp/host/lib/legacy/libusrp.la +USRP_LA = \ + $(top_builddir)/usrp/host/lib/legacy/libusrp.la \ + $(top_builddir)/usrp/host/lib/inband/libusrp_inband.la # How to link the PMT library from inside the tree PMT_INCLUDES = -I$(top_srcdir)/pmt/src/lib diff --git a/pmt/src/lib/pmt.cc b/pmt/src/lib/pmt.cc index b896adaa2..b2c04b390 100644 --- a/pmt/src/lib/pmt.cc +++ b/pmt/src/lib/pmt.cc @@ -748,7 +748,19 @@ pmt_length(pmt_t x) if (x->is_uniform_vector()) return _uniform_vector(x)->length(); - // FIXME list length + if (x->is_pair() || x->is_null()) { + size_t length=0; + while (pmt_is_pair(x)){ + length++; + x = pmt_cdr(x); + } + if (pmt_is_null(x)) + return length; + + // not a proper list + throw pmt_wrong_type("pmt_length", x); + } + // FIXME dictionary length (number of entries) throw pmt_wrong_type("pmt_length", x); @@ -938,6 +950,18 @@ pmt_list4(pmt_t x1, pmt_t x2, pmt_t x3, pmt_t x4) } pmt_t +pmt_list5(pmt_t x1, pmt_t x2, pmt_t x3, pmt_t x4, pmt_t x5) +{ + return pmt_cons(x1, pmt_cons(x2, pmt_cons(x3, pmt_cons(x4, pmt_cons(x5, PMT_NIL))))); +} + +pmt_t +pmt_list6(pmt_t x1, pmt_t x2, pmt_t x3, pmt_t x4, pmt_t x5, pmt_t x6) +{ + return pmt_cons(x1, pmt_cons(x2, pmt_cons(x3, pmt_cons(x4, pmt_cons(x5, pmt_cons(x6, PMT_NIL)))))); +} + +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 6aeae773b..fa368a6a1 100644 --- a/pmt/src/lib/pmt.h +++ b/pmt/src/lib/pmt.h @@ -598,6 +598,18 @@ pmt_t pmt_list3(pmt_t x1, pmt_t x2, pmt_t x3); */ pmt_t pmt_list4(pmt_t x1, pmt_t x2, pmt_t x3, pmt_t x4); +/*! + * \brief Return a list of length 5 containing \p x1, \p x2, \p x3, \p x4, \p x5 + */ +pmt_t pmt_list5(pmt_t x1, pmt_t x2, pmt_t x3, pmt_t x4, pmt_t x5); + +/*! + * \brief Return a list of length 6 containing \p x1, \p x2, \p x3, \p x4, \p + * x5, \p x6 + */ +pmt_t pmt_list6(pmt_t x1, pmt_t x2, pmt_t x3, pmt_t x4, pmt_t x5, pmt_t x6); + + /* * ------------------------------------------------------------------------ * read / write diff --git a/pmt/src/lib/qa_pmt_prims.cc b/pmt/src/lib/qa_pmt_prims.cc index c36a5e972..26b3e26d3 100644 --- a/pmt/src/lib/qa_pmt_prims.cc +++ b/pmt/src/lib/qa_pmt_prims.cc @@ -138,11 +138,17 @@ qa_pmt_prims::test_pairs() pmt_t s2 = pmt_string_to_symbol("s2"); pmt_t s3 = pmt_string_to_symbol("s3"); + + CPPUNIT_ASSERT_EQUAL((size_t)0, pmt_length(PMT_NIL)); + CPPUNIT_ASSERT_THROW(pmt_length(s1), pmt_wrong_type); + CPPUNIT_ASSERT_THROW(pmt_length(pmt_from_double(42)), pmt_wrong_type); + pmt_t c1 = pmt_cons(s1, PMT_NIL); CPPUNIT_ASSERT(pmt_is_pair(c1)); CPPUNIT_ASSERT(!pmt_is_pair(s1)); CPPUNIT_ASSERT_EQUAL(s1, pmt_car(c1)); CPPUNIT_ASSERT_EQUAL(PMT_NIL, pmt_cdr(c1)); + CPPUNIT_ASSERT_EQUAL((size_t) 1, pmt_length(c1)); pmt_t c3 = pmt_cons(s3, PMT_NIL); pmt_t c2 = pmt_cons(s2, c3); @@ -150,7 +156,9 @@ qa_pmt_prims::test_pairs() CPPUNIT_ASSERT_EQUAL(c2, pmt_cdr(c1)); pmt_set_car(c1, s3); CPPUNIT_ASSERT_EQUAL(s3, pmt_car(c1)); - + CPPUNIT_ASSERT_EQUAL((size_t)1, pmt_length(c3)); + CPPUNIT_ASSERT_EQUAL((size_t)2, pmt_length(c2)); + CPPUNIT_ASSERT_THROW(pmt_cdr(PMT_NIL), pmt_wrong_type); CPPUNIT_ASSERT_THROW(pmt_car(PMT_NIL), pmt_wrong_type); CPPUNIT_ASSERT_THROW(pmt_set_car(s1, PMT_NIL), pmt_wrong_type); @@ -228,8 +236,6 @@ qa_pmt_prims::test_equivalence() void qa_pmt_prims::test_misc() { - CPPUNIT_ASSERT_THROW(pmt_length(PMT_NIL), pmt_wrong_type); - pmt_t k0 = pmt_string_to_symbol("k0"); pmt_t k1 = pmt_string_to_symbol("k1"); pmt_t k2 = pmt_string_to_symbol("k2"); diff --git a/usrp/fpga/inband_lib/chan_fifo_reader.v b/usrp/fpga/inband_lib/chan_fifo_reader.v index 2b3178da7..9392bf151 100755 --- a/usrp/fpga/inband_lib/chan_fifo_reader.v +++ b/usrp/fpga/inband_lib/chan_fifo_reader.v @@ -1,197 +1,219 @@ module chan_fifo_reader - ( input reset, - input tx_clock, - input tx_strobe, - input [31:0]adc_clock, - input [3:0] samples_format, - input [15:0] fifodata, - input pkt_waiting, - output reg rdreq, - output reg skip, - output reg [15:0]tx_q, - output reg [15:0]tx_i, - output reg overrun, - output reg underrun) ; - + ( reset, tx_clock, tx_strobe, adc_time, samples_format, + fifodata, pkt_waiting, rdreq, skip, tx_q, tx_i, + underrun, tx_empty, debug, rssi, threshhold) ; + + 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; + + 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 - `define JITTER 5 + // Used only to debug + `define JITTER 5 //Samples format // 16 bits interleaved complex samples - `define QI16 4'b0 + `define QI16 4'b0 // States - `define IDLE 4'd0 - `define READ 4'd1 - `define HEADER1 4'd2 - `define HEADER2 4'd3 - `define TIMESTAMP1 4'd4 - `define TIMESTAMP2 4'd5 - `define WAIT 4'd6 - `define WAITSTROBE 4'd7 - `define SENDWAIT 4'd8 - `define SEND 4'd9 - `define FEED 4'd10 - `define DISCARD 4'd11 + parameter IDLE = 3'd0; + parameter HEADER = 3'd1; + parameter TIMESTAMP = 3'd2; + parameter WAIT = 3'd3; + parameter WAITSTROBE = 3'd4; + parameter SEND = 3'd5; - // State registers - reg[3:0] reader_state; - reg[3:0] reader_next_state; + // Header format + `define PAYLOAD 8:2 + `define ENDOFBURST 27 + `define STARTOFBURST 28 + `define RSSI_FLAG 15 + + + /* State registers */ + reg [2:0] reader_state; + + reg [6:0] payload_len; + reg [6:0] read_len; + reg [31:0] timestamp; + reg burst; + reg trash; + reg rssi_flag; - //Variables - reg[8:0] payload_len; - reg[8:0] read_len; - reg[31:0] timestamp; - reg burst; - reg qsample; - always @(posedge tx_clock) - begin - if (reset) + always @(posedge tx_clock) + begin + if (reset) begin - reader_state <= `IDLE; - reader_next_state <= `IDLE; - rdreq <= 0; - skip <= 0; - overrun <= 0; - underrun <= 0; - burst <= 0; - qsample <= 1; - end + 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; + end else - begin - reader_state = reader_next_state; + begin case (reader_state) - `IDLE: - begin - if (pkt_waiting == 1) - begin - reader_next_state <= `READ; - rdreq <= 1; - underrun <= 0; - end - else if (burst == 1) + 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; + if (pkt_waiting == 1) + begin + reader_state <= HEADER; + rdreq <= 1; + underrun <= 0; + end + else if (burst == 1) underrun <= 1; - end - - // Just wait for the fifo data to arrive - `READ: - begin - reader_next_state <= `HEADER1; - end - - // First part of the header - `HEADER1: - begin - reader_next_state <= `HEADER2; - - //Check Start burst flag - if (fifodata[3] == 1) - burst <= 1; - if (fifodata[4] == 1) - burst <= 0; - end + if (tx_strobe == 1) + tx_empty <= 1 ; + end - // Read payload length - `HEADER2: - begin - payload_len <= (fifodata & 16'h1FF); - read_len <= 9'd0; - reader_next_state <= `TIMESTAMP1; - end + /* Process header */ + HEADER: + begin + if (tx_strobe == 1) + tx_empty <= 1 ; + + rssi_flag <= fifodata[`RSSI_FLAG]&fifodata[`STARTOFBURST]; + //Check Start/End burst flag + if (fifodata[`STARTOFBURST] == 1 + && fifodata[`ENDOFBURST] == 1) + burst <= 0; + else if (fifodata[`STARTOFBURST] == 1) + burst <= 1; + else if (fifodata[`ENDOFBURST] == 1) + burst <= 0; - `TIMESTAMP1: - begin - timestamp <= {fifodata, 16'b0}; - rdreq <= 0; - reader_next_state <= `TIMESTAMP2; - end - - `TIMESTAMP2: - begin - timestamp <= timestamp + fifodata; - reader_next_state <= `WAIT; - 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 + timestamp <= fifodata; + reader_state <= WAIT; + if (tx_strobe == 1) + tx_empty <= 1 ; + rdreq <= 0; + end - // Decide if we wait, send or discard samples - `WAIT: - begin - // Wait a little bit more - if (timestamp > adc_clock + `JITTER) - reader_next_state <= `WAIT; + // Decide if we wait, send or discard samples + WAIT: + begin + if (tx_strobe == 1) + tx_empty <= 1 ; + // Let's send it - else if ((timestamp < adc_clock + `JITTER - && timestamp > adc_clock) - || timestamp == 32'hFFFFFFFF) - begin - reader_next_state <= `WAITSTROBE; - end + if ((timestamp <= adc_time + `JITTER + && timestamp > adc_time) + || timestamp == 32'hFFFFFFFF) + begin + if (rssi <= threshhold || rssi_flag == 0) + begin + trash <= 0; + reader_state <= WAITSTROBE; + end + else + reader_state <= WAIT; + end + // Wait a little bit more + else if (timestamp > adc_time + `JITTER) + reader_state <= WAIT; // Outdated - else if (timestamp < adc_clock) - begin - reader_next_state <= `DISCARD; - skip <= 1; + else if (timestamp < adc_time) + begin + trash <= 1; + reader_state <= IDLE; + skip <= 1; end - end + end - // Wait for the transmit chain to be ready - `WAITSTROBE: - begin - // If end of payload... - if (read_len == payload_len) + // Wait for the transmit chain to be ready + WAITSTROBE: + begin + // If end of payload... + if (read_len == payload_len) + begin + reader_state <= IDLE; + skip <= 1; + if (tx_strobe == 1) + tx_empty <= 1 ; + end + else if (tx_strobe == 1) + begin + reader_state <= SEND; + rdreq <= 1; + end + end + + // Send the samples to the tx_chain + SEND: + begin + reader_state <= WAITSTROBE; + read_len <= read_len + 7'd1; + tx_empty <= 0; + rdreq <= 0; + + case(samples_format) + `QI16: begin - reader_next_state <= `DISCARD; - skip <= (payload_len < 508); + tx_i <= fifodata[15:0]; + tx_q <= fifodata[31:16]; end - - if (tx_strobe == 1) - reader_next_state <= `SENDWAIT; - end - - `SENDWAIT: - begin - rdreq <= 1; - reader_next_state <= `SEND; - end - - // Send the samples to the tx_chain - `SEND: - begin - reader_next_state <= `WAITSTROBE; - rdreq <= 0; - read_len <= read_len + 2; - case(samples_format) - `QI16: - begin - tx_q <= qsample ? fifodata : 16'bZ; - tx_i <= ~qsample ? fifodata : 16'bZ; - qsample <= ~ qsample; - end + + // Assume 16 bits complex samples by default default: - begin - // Assume 16 bits complex samples by default - $display ("Error unknown samples format"); - tx_q <= qsample ? fifodata : 16'bZ; - tx_i <= ~qsample ? fifodata : 16'bZ; - qsample <= ~ qsample; - end - endcase - end - - `DISCARD: - begin - skip <= 0; - reader_next_state <= `IDLE; - end + begin + tx_i <= fifodata[15:0]; + tx_q <= fifodata[31:16]; + end + endcase + end default: - begin - $display ("Error unknown state"); - reader_state <= `IDLE; - reader_next_state <= `IDLE; - end + begin + //error handling + reader_state <= IDLE; + end endcase end end -endmodule
\ No newline at end of file +endmodule diff --git a/usrp/fpga/inband_lib/channel_demux.v b/usrp/fpga/inband_lib/channel_demux.v new file mode 100644 index 000000000..d46be9397 --- /dev/null +++ b/usrp/fpga/inband_lib/channel_demux.v @@ -0,0 +1,78 @@ +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 ; + + // States + parameter IDLE = 3'd0; + parameter HEADER = 3'd1; + parameter WAIT = 3'd2; + parameter FORWARD = 3'd3; + + `define CHANNEL 20:16 + `define PKT_SIZE 127 + wire [4:0] true_channel; + assign true_channel = (usbdata_final[`CHANNEL] == 5'h1f) ? + NUM_CHAN : (usbdata_final[`CHANNEL]); + + always @(posedge txclk) + begin + if (reset) + begin + reader_state <= IDLE; + 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 <= true_channel; + WR_channel[true_channel] <= 1; + ram_data <= usbdata_final; + read_length <= 7'd0 ; + + 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 + 7'd1; + + reader_state <= WAIT; + end + + default: + begin + //error handling + reader_state <= IDLE; + end + endcase + end +endmodule diff --git a/usrp/fpga/inband_lib/channel_ram.v b/usrp/fpga/inband_lib/channel_ram.v new file mode 100755 index 000000000..40e0efc01 --- /dev/null +++ b/usrp/fpga/inband_lib/channel_ram.v @@ -0,0 +1,114 @@ +module channel_ram + ( // 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); + + 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] 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; + + // 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'd2)) ram2[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) + which_ram_wr <= 0; + else if (wr_done_int) + which_ram_wr <= which_ram_wr + 2'd1; + + 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]; + + 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; + + 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 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); + + 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 diff --git a/usrp/fpga/inband_lib/cmd_reader.v b/usrp/fpga/inband_lib/cmd_reader.v new file mode 100755 index 000000000..7604321e4 --- /dev/null +++ b/usrp/fpga/inband_lib/cmd_reader.v @@ -0,0 +1,292 @@ +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 + ); + + // 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 + + 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 + + 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 + + HEADER : begin + payload <= fifodata[`PAYLOAD]; + state <= TIMESTAMP; + 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; + 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 + + 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 + + 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_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 + + default : begin + //error state handling + state <= IDLE; + end + endcase +endmodule
\ No newline at end of file diff --git a/usrp/fpga/inband_lib/data_packet_fifo.v b/usrp/fpga/inband_lib/data_packet_fifo.v index 5b37b14ea..a9bcbdae7 100755 --- a/usrp/fpga/inband_lib/data_packet_fifo.v +++ b/usrp/fpga/inband_lib/data_packet_fifo.v @@ -1,128 +1,118 @@ module data_packet_fifo ( input reset, input clock, - input [15:0]ram_data_in, + input [31:0]ram_data_in, input write_enable, output reg have_space, - output reg [15:0]ram_data_out, + 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 = 16 ; + parameter DATA_WIDTH = 32 ; + parameter PKT_DEPTH = 128 ; parameter NUM_PACKETS = 4 ; /* Create the RAM here */ - reg [DATA_WIDTH-1:0] usb_ram [256*NUM_PACKETS-1:0] ; + reg [DATA_WIDTH-1:0] usb_ram [PKT_DEPTH*NUM_PACKETS-1:0] ; /* Create the address signals */ - reg [7:0] usb_ram_offset_out ; - reg [1:0] usb_ram_packet_out ; - reg [7:0] usb_ram_offset_in ; - reg [1:0] usb_ram_packet_in ; + 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 [7-2+NUM_PACKETS:0] usb_ram_aout ; - wire [7-2+NUM_PACKETS:0] usb_ram_ain ; - reg isfull; + 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) + always @(usb_ram_ain, usb_ram_aout, isfull) begin - if (reset) - pkt_waiting <= 0; - else if (usb_ram_ain >= usb_ram_aout) - pkt_waiting <= usb_ram_ain - usb_ram_aout >= 256; + 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'b1111111111 - usb_ram_aout) >= 256; + 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) + always @(usb_ram_ain, usb_ram_aout, isfull) begin - if (reset) - have_space <= 1; - else if (usb_ram_ain == usb_ram_aout) + 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) <= 256 * (NUM_PACKETS - 1); + 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) >= 256; + have_space <= (usb_ram_aout - usb_ram_ain) >= PKT_DEPTH; end - /* RAM Write Address process */ - always @(posedge clock) - begin - if( reset ) - begin - usb_ram_offset_in <= 0 ; - usb_ram_packet_in <= 0 ; - end - else - if( pkt_complete ) - begin - usb_ram_packet_in <= usb_ram_packet_in + 1; - usb_ram_offset_in <= 0; - end - else if( write_enable ) - begin - if (usb_ram_offset_in == 8'b11111111) - begin - usb_ram_offset_in <= 0; - usb_ram_packet_in <= usb_ram_packet_in + 1; - end - else - usb_ram_offset_in <= usb_ram_offset_in + 1 ; - if (usb_ram_ain + 1 == usb_ram_aout) - isfull <= 1; - end - end - /* RAM Writing process */ + + /* 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 Read Address process */ + /* 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 == 8'b11111111 ) + 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 (usb_ram_ain == usb_ram_aout) - isfull <= 0; - end - - /* RAM Reading Process */ - always @(posedge clock) - begin - ram_data_out <= usb_ram[usb_ram_aout] ; + 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 new file mode 100755 index 000000000..205293479 --- /dev/null +++ b/usrp/fpga/inband_lib/packet_builder.v @@ -0,0 +1,132 @@ +module packet_builder #(parameter NUM_CHAN = 1)( + // System + input rxclk, + input reset, + input [31:0] adctime, + input [3:0] channels, + // ADC side + input [15:0]chan_fifodata, + input [NUM_CHAN:0]chan_empty, + input [9:0]chan_usedw, + output reg [3:0]rd_select, + output reg chan_rdreq, + // FX2 side + 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); + + + // States + `define IDLE 3'd0 + `define HEADER1 3'd1 + `define HEADER2 3'd2 + `define TIMESTAMP 3'd3 + `define FORWARD 3'd4 + + `define MAXPAYLOAD 504 + + `define PAYLOAD_LEN 8:0 + `define TAG 12:9 + `define MBZ 15:13 + + `define CHAN 4:0 + `define RSSI 10:5 + `define BURST 12:11 + `define DROPPED 13 + `define UNDERRUN 14 + `define OVERRUN 15 + + reg [2:0] state; + reg [8:0] read_length; + reg [8:0] payload_len; + reg tstamp_complete; + reg [3:0] check_next; + wire [8:0] chan_used; + wire [31:0] true_rssi; + + assign debugbus = {state, chan_empty[0], chan_empty[1], 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) : + ((rd_select[0]) ? rssi_1:rssi_0); + always @(posedge rxclk) + begin + if (reset) + begin + WR <= 0; + rd_select <= 0; + chan_rdreq <= 0; + tstamp_complete <= 0; + check_next <= 0; + state <= `IDLE; + end + else case (state) + `IDLE: begin + 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 + 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[`TAG] <= #1 0; + fifodata[`MBZ] <= #1 0; + WR <= #1 1; + + state <= #1 `HEADER2; + read_length <= #1 0; + end + + `HEADER2: begin + fifodata[`CHAN] <= #1 (check_next == 4'd0 ? 5'h1f : {1'd0, check_next - 4'd1}); + fifodata[`RSSI] <= #1 true_rssi[5:0]; + fifodata[`BURST] <= #1 0; + fifodata[`DROPPED] <= #1 0; + fifodata[`UNDERRUN] <= #1 0; + fifodata[`OVERRUN] <= #1 0; + + state <= #1 `TIMESTAMP; + end + + `TIMESTAMP: begin + fifodata <= #1 (tstamp_complete ? adctime[31:16] : adctime[15:0]); + tstamp_complete <= #1 ~tstamp_complete; + + if (~tstamp_complete) + chan_rdreq <= #1 1; + + state <= #1 (tstamp_complete ? `FORWARD : `TIMESTAMP); + end + + `FORWARD: begin + read_length <= #1 read_length + 9'd2; + fifodata <= #1 (read_length >= payload_len ? 16'hDEAD : chan_fifodata); + + if (read_length >= `MAXPAYLOAD) + begin + WR <= #1 0; + state <= #1 `IDLE; + end + else if (read_length == payload_len - 4) + chan_rdreq <= #1 0; + end + + default: begin + //handling error state + state <= `IDLE; + end + endcase + end +endmodule + diff --git a/usrp/fpga/inband_lib/register_io.v b/usrp/fpga/inband_lib/register_io.v new file mode 100755 index 000000000..63a26549c --- /dev/null +++ b/usrp/fpga/inband_lib/register_io.v @@ -0,0 +1,60 @@ +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); + + reg strobe; + wire [31:0] out[7:0]; + assign debugbus = {clk, enable, addr[2:0], datain[4:0], dataout[4:0]}; + assign threshhold = out[1]; + + always @(*) + if (reset | ~enable[1]) + begin + strobe <= 0; + dataout <= 0; + end + else + begin + 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 + else + begin + //write + dataout <= dataout; + strobe <= 1; + 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 diff --git a/usrp/fpga/inband_lib/rx_buffer_inband.v b/usrp/fpga/inband_lib/rx_buffer_inband.v new file mode 100755 index 000000000..c23ce09b7 --- /dev/null +++ b/usrp/fpga/inband_lib/rx_buffer_inband.v @@ -0,0 +1,175 @@ +//`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
+ );
+
+ 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));
+
+ // 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];
+
+ 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_2kx16 rx_chan_fifo (
+ .aclr ( reset ),
+ .clock ( rxclk ),
+ .data ( ch[i] ),
+ .rdreq ( rdreq ),
+ .wrreq ( ~rx_full[i] & rxstrobe),
+ .empty ( ),
+ .full ( rx_full[i] ),
+ .q ( dataout[i]),
+ .usedw ( usedw[i] )
+ );
+ end
+ endgenerate
+ wire [7:0] debug;
+ fifo_2kx16 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 = {wrusedw, have_space, RD, read_count[8], rxclk};
+endmodule
diff --git a/usrp/fpga/inband_lib/tx_buffer_inband.v b/usrp/fpga/inband_lib/tx_buffer_inband.v index 56c07807a..af7ed394a 100755 --- a/usrp/fpga/inband_lib/tx_buffer_inband.v +++ b/usrp/fpga/inband_lib/tx_buffer_inband.v @@ -1,183 +1,227 @@ module tx_buffer_inband - ( input usbclk, - input bus_reset, // Used here for the 257-Hack to fix the FX2 bug - input reset, // standard DSP-side reset - input [15:0] usbdata, - input wire WR, - output wire have_space, - output reg tx_underrun, - input wire [3:0] channels, - output [15:0] tx_i_0, - output [15:0] tx_q_0, - output [15:0] tx_i_1, - output [15:0] tx_q_1, - //NOT USED - output reg [15:0] tx_i_2, - output reg [15:0] tx_q_2, - output reg [15:0] tx_i_3, - output reg [15:0] tx_q_3, - input txclk, - input txstrobe, - input clear_status, - output wire tx_empty, - output [11:0] debugbus - ); + ( usbclk, bus_reset, reset, usbdata, WR, have_space, + tx_underrun, 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, threshhold + ); - wire [15:0] tx_data_bus; + //CHAN_WIDTH is the width of the channel + //NUM_CHAN is the number of data channel (index from 0 to NUM_CHAN-1) + //index NUM_CHAN is reserved for command + + parameter CHAN_WIDTH = 2 ; + parameter NUM_CHAN = 2 ; + /* Debug paramters */ + parameter STROBE_RATE_0 = 8'd1 ; + parameter STROBE_RATE_1 = 8'd2 ; + + 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; - wire WR_chan_0; - wire chan_0_done; - wire OR0; - wire UR0; - - wire WR_chan_1; - wire chan_1_done; - wire OR1; - wire UR1; - - // NOT USED yet - wire WR_cmd; - wire cmd_done; - - //EXTERNAL REGISTER - //TODO: increment it - reg [31:0] time_counter; - reg [7:0] txstrobe_rate_0; - reg [7:0] txstrobe_rate_1; - - - //Usb block - wire [15:0] tupf_fifodata; - wire tupf_pkt_waiting; - wire tupf_rdreq; - wire tupf_skip; - wire tupf_have_space; + output wire have_space ; + output wire tx_underrun ; + 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; + + /* To generate channel readers */ + genvar i ; + + /* These will eventually be external register */ + reg [31:0] adc_time ; + wire [7:0] txstrobe_rate [CHAN_WIDTH-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; - usb_packet_fifo2 tx_usb_packet_fifo - ( .reset (reset), - .usb_clock (usbclk), - .fpga_clock (txclk), - .write_data (usbdata), - .write_enable (WR), - .read_data (tupf_fifodata), - .pkt_waiting (tupf_pkt_waiting), - .read_enable (tupf_rdreq), - .skip_packet (tupf_skip), - .have_space (tupf_have_space), - .tx_empty (tx_empty) - ); + always @(posedge txclk) + if (reset) + adc_time <= 0; + else if (txstrobe) + adc_time <= adc_time + 1; + + + /* Connections between tx_usb_fifo_reader and + cnannel/command processing blocks */ + wire [31:0] tx_data_bus ; + wire [CHAN_WIDTH:0] chan_WR ; + wire [CHAN_WIDTH:0] chan_done ; + + /* Connections between data block and the + FX2/TX chains */ + wire [CHAN_WIDTH:0] chan_underrun ; + wire [CHAN_WIDTH:0] chan_txempty ; - usb_fifo_reader tx_usb_packet_reader ( - .reset(reset), - .tx_clock(txclk), - .tx_data_bus(tx_data_bus), - .WR_chan_0(WR_chan_0), - .WR_chan_1(WR_chan_1), - .WR_cmd(WR_cmd), - .chan_0_done(chan_0_done), - .chan_1_done(chan_1_done), - .cmd_done(cmd_done), - .rdreq(tupf_rdreq), - .skip(tupf_skip), - .pkt_waiting(tupf_pkt_waiting), - .fifodata(tupf_fifodata) + /* Conections between tx_data_packet_fifo and + its reader + strobe generator */ + wire [31:0] chan_fifodata [CHAN_WIDTH:0] ; + wire chan_pkt_waiting [CHAN_WIDTH:0] ; + wire chan_rdreq [CHAN_WIDTH:0] ; + wire chan_skip [CHAN_WIDTH:0] ; + wire [CHAN_WIDTH:0] chan_have_space ; + wire chan_txstrobe [CHAN_WIDTH-1:0] ; + + wire [14:0] debug; + + /* Outputs to transmit chains */ + wire [15:0] tx_i [CHAN_WIDTH-1:0] ; + wire [15:0] tx_q [CHAN_WIDTH-1: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_underrun = chan_underrun[0] | chan_underrun[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 debugbus = {debug, txclk}; + + 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) + ); + + 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) ); + + generate for (i = 0 ; i < NUM_CHAN; i = i + 1) + begin : generate_channel_readers + 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), + .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) + ); + + end + endgenerate - //Channel 0 block - wire [15:0] tdpf_fifodata_0; - wire tdpf_pkt_waiting_0; - wire tdpf_rdreq_0; - wire tdpf_skip_0; - wire tdpf_have_space_0; - wire txstrobe_chan_0; - data_packet_fifo tx_data_packet_fifo_0 - ( .reset(reset), - .clock(txclk), - .ram_data_in(tx_data_bus), - .write_enable(WR_chan_0), - .ram_data_out(tdpf_fifodata_0), - .pkt_waiting(tdpf_pkt_waiting_0), - .read_enable(tdpf_rdreq_0), - .pkt_complete(chan_0_done), - .skip_packet(tdpf_skip_0), - .have_space(tdpf_have_space_0) - ); - - strobe_gen strobe_gen_0 - ( .clock(txclk), - .reset(reset), - .enable(1'b1), - .rate(txstrobe_rate_0), - .strobe_in(txstrobe), - .strobe(txstrobe_chan_0) - ); - - chan_fifo_reader tx_chan_0_reader ( - .reset(reset), - .tx_clock(txclk), - .tx_strobe(txstrobe), - //.tx_strobe(txstrobe_chan_0), - .adc_clock(time_counter), - .samples_format(4'b0), - .tx_q(tx_q_0), - .tx_i(tx_i_0), - .overrun(OR0), - .underrun(UR0), - .skip(tdpf_skip_0), - .rdreq(tdpf_rdreq_0), - .fifodata(tdpf_fifodata_0), - .pkt_waiting(tdpf_pkt_waiting_0) - ); - - - //Channel 1 block - wire [15:0] tdpf_fifodata_1; - wire tdpf_pkt_waiting_1; - wire tdpf_rdreq_1; - wire tdpf_skip_1; - wire tdpf_have_space_1; - wire txstrobe_chan_1; - - data_packet_fifo tx_data_packet_fifo_1 - ( .reset(reset), - .clock(txclk), - .ram_data_in(tx_data_bus), - .write_enable(WR_chan_1), - .ram_data_out(tdpf_fifodata_1), - .pkt_waiting(tdpf_pkt_waiting_1), - .read_enable(tdpf_rdreq_1), - .pkt_complete(chan_1_done), - .skip_packet(tdpf_skip_1), - .have_space(tdpf_have_space_1) - ); - - strobe_gen strobe_gen_1 - ( .clock(txclk), - .reset(reset), - .enable(1'b1), - .rate(txstrobe_rate_1), - .strobe_in(txstrobe), - .strobe(txstrobe_chan_1) - ); - - chan_fifo_reader tx_chan_1_reader ( - .reset(reset), - .tx_clock(txclk), - .tx_strobe(txstrobe), - //.tx_strobe(txstrobe_chan_1), - .adc_clock(time_counter), - .samples_format(4'b0), - .tx_q(tx_q_1), - .tx_i(tx_i_1), - .overrun(OR1), - .underrun(UR1), - .skip(tdpf_skip_1), - .rdreq(tdpf_rdreq_1), - .fifodata(tdpf_fifodata_1), - .pkt_waiting(tdpf_pkt_waiting_1) - ); + 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) + ); + + endmodule // tx_buffer diff --git a/usrp/fpga/inband_lib/tx_packer.v b/usrp/fpga/inband_lib/tx_packer.v new file mode 100644 index 000000000..2f19b21f3 --- /dev/null +++ b/usrp/fpga/inband_lib/tx_packer.v @@ -0,0 +1,119 @@ +module tx_packer + ( //FX2 Side + input bus_reset, + input usbclk, + input WR_fx2, + input [15:0]usbdata, + + // TX Side + input reset, + input txclk, + output reg [31:0] usbdata_final, + output reg WR_final); + + reg [8:0] write_count; + + /* Fix FX2 bug */ + always @(posedge usbclk) + begin + 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; + end + + 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 [15:0] usbdata_delayed ; + reg writing ; + wire [31: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 [31:0] usbdata_tx ; + reg WR_tx; + reg WR_1; + reg WR_2; + + 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 + +endmodule diff --git a/usrp/fpga/inband_lib/usb_fifo_reader.v b/usrp/fpga/inband_lib/usb_fifo_reader.v index 170c70fd4..d002d90ff 100755 --- a/usrp/fpga/inband_lib/usb_fifo_reader.v +++ b/usrp/fpga/inband_lib/usb_fifo_reader.v @@ -1,134 +1,24 @@ -module usb_fifo_reader (tx_clock, fifodata, pkt_waiting, reset, - rdreq, skip, done_chan, WR_chan, tx_data_bus); +module usb_fifo_reader ( + input usbclk, + input bus_reset, + input RD, + output rdreq, + ); - /* Module parameters */ - parameter NUM_CHAN = 2 ; - parameter WIDTH = 32 ; + // 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]; - input wire tx_clock ; - input wire reset ; - input wire [WIDTH-1:0] fifodata ; - input wire pkt_waiting ; - output reg rdreq ; - output reg skip ; - output reg [NUM_CHAN:0] done_chan ; - output reg [NUM_CHAN:0] WR_chan ; - output reg [WIDTH-1:0] tx_data_bus ; - - - - /* States definition */ - `define IDLE 3'd0 - `define WAIT 3'd1 - `define READ_HEADER 3'd2 - `define FORWARD_DATA 3'd3 - `define SKIP_REST 3'd4 - - /* Channel Ids */ - `define TXCHAN0 5'h0 - `define TXCHAN1 5'h1 - `define TXCMD 5'h1F - - /* Local registers */ - reg [2:0] reader_state ; - reg [2:0] reader_next_state ; - reg [4:0] channel ; - reg [8:0] pkt_length ; - reg [8:0] read_length ; - /* State Machine */ - always @(posedge tx_clock) - begin - if (reset) - begin - reader_state <= `IDLE ; - reader_next_state <= `IDLE ; - rdreq <= 0 ; - skip <= 0 ; - WR_chan <= {NUM_CHAN+1{1'b0}} ; - done_chan <= {NUM_CHAN+1{1'b0}} ; - end - else - begin - reader_state = reader_next_state ; - - case(reader_state) - `IDLE: - begin - reader_next_state <= pkt_waiting ? `WAIT : `IDLE ; - rdreq <= pkt_waiting ; - end - - /* Wait for the fifo's data to show up */ - `WAIT: - begin - reader_next_state <= `READ_HEADER ; - end - - `READ_HEADER: - begin - reader_next_state <= `FORWARD_DATA ; - - /* Read header fields */ - channel <= (fifodata & 32'h1F0000) ; - pkt_length <= (fifodata & 16'h1FF) + 4 ; - read_length <= 9'd0 ; - - /* Forward data */ - case (channel) - `TXCHAN0: WR_chan[0] <= 1 ; - `TXCHAN1: WR_chan[1] <= 1 ; - `TXCMD: WR_chan[2] <= 1 ; - default: WR_chan <= 1 ; - endcase - tx_data_bus <= fifodata ; - end - - `FORWARD_DATA: - begin - read_length <= read_length + 4 ; - - // If end of payload... - if (read_length == pkt_length) - begin - reader_next_state <= `SKIP_REST ; - /* If the packet is 512 bytes, don't skip */ - skip <= pkt_length < 506 ; - - /* Data pushing done */ - WR_chan <= {NUM_CHAN+1{1'b0}} ; - - /* Notify next block */ - case (channel) - `TXCHAN0: done_chan[0] <= 1 ; - `TXCHAN1: done_chan[1] <= 1 ; - `TXCMD: done_chan[2] <= 1 ; - default: done_chan[0] <= 1 ; - endcase - end - else if (read_length == pkt_length - 4) - rdreq <= 0 ; - - /* Forward data */ - tx_data_bus <= fifodata ; - end - - `SKIP_REST: - begin - reader_next_state <= pkt_waiting ? `READ_HEADER : `IDLE ; - done_chan <= {NUM_CHAN+1{1'b0}} ; - rdreq <= pkt_waiting ; - skip <= 0 ; - end - - default: - begin - reader_state <= `IDLE; - reader_next_state <= `IDLE; - end - endcase - end - end + endmodule diff --git a/usrp/fpga/inband_lib/usb_fifo_writer.v b/usrp/fpga/inband_lib/usb_fifo_writer.v new file mode 100755 index 000000000..abe1dd567 --- /dev/null +++ b/usrp/fpga/inband_lib/usb_fifo_writer.v @@ -0,0 +1,183 @@ + +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/inband_lib/usb_packet_fifo2.v b/usrp/fpga/inband_lib/usb_packet_fifo2.v deleted file mode 100755 index d815e4e37..000000000 --- a/usrp/fpga/inband_lib/usb_packet_fifo2.v +++ /dev/null @@ -1,119 +0,0 @@ -`default_nettype none - -module usb_packet_fifo2(reset, usb_clock, fpga_clock, write_enable, write_data, - read_enable, skip_packet, read_data, have_space, pkt_waiting, tx_empty) ; - - /* Module parameters */ - parameter LOG2_N = 2 ; - parameter BUS_WIDTH = 16 ; - parameter FIFO_WIDTH = 32 ; - - input wire reset; - input wire usb_clock ; - input wire fpga_clock ; - input wire write_enable ; - input wire [BUS_WIDTH-1:0] write_data ; - input wire read_enable ; - input wire skip_packet ; - output wire [FIFO_WIDTH-1:0] read_data ; - output wire have_space ; - output wire pkt_waiting ; - output wire tx_empty; - - - /* Variable for generate statement */ - genvar i ; - - /* Local wires for FIFO connections */ - wire [2**LOG2_N-1:0] fifo_resets ; - reg [2**LOG2_N-1:0] fifo_we ; - wire [2**LOG2_N-1:0] fifo_re ; - reg [FIFO_WIDTH-1:0] fifo_wdata[2**LOG2_N-1:0] ; - wire [FIFO_WIDTH-1:0] fifo_rdata[2**LOG2_N-1:0] ; - wire [2**LOG2_N-1:0] fifo_rempty ; - wire [2**LOG2_N-1:0] fifo_rfull ; - wire [2**LOG2_N-1:0] fifo_wempty ; - wire [2**LOG2_N-1:0] fifo_wfull ; - - /* FIFO Select for read and write ports */ - reg [LOG2_N-1:0] fifo_rselect ; - reg [LOG2_N-1:0] fifo_wselect ; - - /* Used to convert 16 bits usbdata to the 32 bits wide fifo */ - reg word_complete ; - reg [BUS_WIDTH-1:0] write_data_delayed ; - - /* Assign have_space to empty flag of currently selected write FIFO */ - assign have_space = fifo_wempty[fifo_wselect] ; - - /* Assign pkt_waiting to full flag of currently selected read FIFO */ - assign pkt_waiting = fifo_rfull[fifo_rselect] ; - - /* Assign the read_data to the output of the currently selected FIFO */ - assign read_data = fifo_rdata[fifo_rselect] ; - - /* Figure out if we're all empty */ - assign tx_empty = !(~fifo_rempty) ; - - /* Increment fifo_rselect here */ - always @(posedge fpga_clock) - begin - if (reset) - fifo_rselect <= {2**LOG2_N{1'b0}} ; - - if (fifo_rempty[fifo_rselect]) - fifo_rselect <= fifo_rselect + 1 ; - - if (skip_packet) - fifo_rselect <= fifo_rselect + 1 ; - end - - /* Increment fifo_wselect and pack data into 32 bits block */ - always @(posedge usb_clock, reset) - begin - if (reset) - begin - fifo_wselect <= {2**LOG2_N{1'b0}} ; - word_complete <= 0; - end - - if (fifo_wfull[fifo_wselect]) - fifo_wselect <= fifo_wselect + 1 ; - - if (write_enable) - begin - word_complete <= ~word_complete ; - - if (word_complete) - fifo_wdata[fifo_wselect] <= {write_data_delayed, write_data} ; - else - write_data_delayed <= write_data ; - - /* Avoid to continue to write in the previous fifo when we have - just swichted to the next one */ - fifo_we[fifo_wselect-1] <= 0 ; - - fifo_we[fifo_wselect] <= write_enable & word_complete ; - end - end - - /* Generate all the single packet FIFOs */ - generate - for( i = 0 ; i < 2**LOG2_N ; i = i + 1 ) - begin : generate_single_packet_fifos - assign fifo_re[i] = (fifo_rselect == i) ? read_enable : 1'b0 ; - assign fifo_resets[i] = (fifo_rselect == i) ? skip_packet : 1'b0 ; - fifo_512 single_packet_fifo(.wrclk ( usb_clock ), - .rdclk ( fpga_clock ), - .aclr ( fifo_resets[i] ), - .wrreq ( fifo_we[i] ), - .data ( fifo_wdata[i] ), - .rdreq ( fifo_re[i] ), - .q ( fifo_rdata[i] ), - .rdfull ( fifo_rfull[i] ), - .rdempty( fifo_rempty[i] ), - .wrfull ( fifo_wfull[i] ), - .wrempty( fifo_wempty[i] ) ) ; - end - endgenerate -endmodule
\ No newline at end of file diff --git a/usrp/fpga/megacells/fifo_512.v b/usrp/fpga/megacells/fifo_2k_1clk.v index b034b4ddc..095615bb8 100755 --- a/usrp/fpga/megacells/fifo_512.v +++ b/usrp/fpga/megacells/fifo_2k_1clk.v @@ -1,12 +1,12 @@ // megafunction wizard: %LPM_FIFO+%
// GENERATION: STANDARD
// VERSION: WM1.0
-// MODULE: dcfifo
+// MODULE: scfifo
// ============================================================
-// File Name: fifo_512.v
+// File Name: fifo_2k_1clk.v
// Megafunction Name(s):
-// dcfifo
+// scfifo
// ============================================================
// ************************************************************
// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
@@ -33,73 +33,65 @@ // synopsys translate_off
`timescale 1 ps / 1 ps
// synopsys translate_on
-module fifo_512 (
+module fifo_2k_1clk (
aclr,
+ clock,
data,
- rdclk,
rdreq,
- wrclk,
wrreq,
+ empty,
+ full,
q,
- rdempty,
- rdfull,
- wrempty,
- wrfull);
+ usedw);
input aclr;
- input [31:0] data;
- input rdclk;
+ input clock;
+ input [15:0] data;
input rdreq;
- input wrclk;
input wrreq;
- output [31:0] q;
- output rdempty;
- output rdfull;
- output wrempty;
- output wrfull;
+ output empty;
+ output full;
+ output [15:0] q;
+ output [9:0] usedw;
- wire sub_wire0;
+ wire [9:0] sub_wire0;
wire sub_wire1;
- wire sub_wire2;
+ wire [15:0] sub_wire2;
wire sub_wire3;
- wire [31:0] sub_wire4;
- wire rdfull = sub_wire0;
- wire rdempty = sub_wire1;
- wire wrfull = sub_wire2;
- wire wrempty = sub_wire3;
- wire [31:0] q = sub_wire4[31:0];
+ wire [9:0] usedw = sub_wire0[9:0];
+ wire empty = sub_wire1;
+ wire [15:0] q = sub_wire2[15:0];
+ wire full = sub_wire3;
- dcfifo dcfifo_component (
- .wrclk (wrclk),
+ scfifo scfifo_component (
.rdreq (rdreq),
.aclr (aclr),
- .rdclk (rdclk),
+ .clock (clock),
.wrreq (wrreq),
.data (data),
- .rdfull (sub_wire0),
- .rdempty (sub_wire1),
- .wrfull (sub_wire2),
- .wrempty (sub_wire3),
- .q (sub_wire4)
+ .usedw (sub_wire0),
+ .empty (sub_wire1),
+ .q (sub_wire2),
+ .full (sub_wire3)
// synopsys translate_off
,
- .rdusedw (),
- .wrusedw ()
+ .almost_empty (),
+ .sclr (),
+ .almost_full ()
// synopsys translate_on
);
defparam
- dcfifo_component.add_ram_output_register = "OFF",
- dcfifo_component.clocks_are_synchronized = "FALSE",
- dcfifo_component.intended_device_family = "Cyclone",
- dcfifo_component.lpm_hint = "RAM_BLOCK_TYPE=M4K",
- dcfifo_component.lpm_numwords = 128,
- dcfifo_component.lpm_showahead = "OFF",
- dcfifo_component.lpm_type = "dcfifo",
- dcfifo_component.lpm_width = 32,
- dcfifo_component.lpm_widthu = 7,
- dcfifo_component.overflow_checking = "ON",
- dcfifo_component.underflow_checking = "ON",
- dcfifo_component.use_eab = "ON";
+ scfifo_component.add_ram_output_register = "OFF",
+ scfifo_component.intended_device_family = "Cyclone",
+ scfifo_component.lpm_hint = "RAM_BLOCK_TYPE=M4K",
+ scfifo_component.lpm_numwords = 1024,
+ scfifo_component.lpm_showahead = "OFF",
+ scfifo_component.lpm_type = "scfifo",
+ scfifo_component.lpm_width = 16,
+ scfifo_component.lpm_widthu = 10,
+ scfifo_component.overflow_checking = "ON",
+ scfifo_component.underflow_checking = "ON",
+ scfifo_component.use_eab = "ON";
endmodule
@@ -112,8 +104,8 @@ endmodule // Retrieval info: PRIVATE: AlmostFull NUMERIC "0"
// Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1"
// Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0"
-// Retrieval info: PRIVATE: Clock NUMERIC "4"
-// Retrieval info: PRIVATE: Depth NUMERIC "128"
+// Retrieval info: PRIVATE: Clock NUMERIC "0"
+// Retrieval info: PRIVATE: Depth NUMERIC "1024"
// Retrieval info: PRIVATE: Empty NUMERIC "1"
// Retrieval info: PRIVATE: Full NUMERIC "1"
// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone"
@@ -125,56 +117,51 @@ endmodule // Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "2"
// Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0"
// Retrieval info: PRIVATE: UsedW NUMERIC "1"
-// Retrieval info: PRIVATE: Width NUMERIC "32"
-// Retrieval info: PRIVATE: dc_aclr NUMERIC "1"
+// Retrieval info: PRIVATE: Width NUMERIC "16"
+// Retrieval info: PRIVATE: dc_aclr NUMERIC "0"
// Retrieval info: PRIVATE: rsEmpty NUMERIC "1"
-// Retrieval info: PRIVATE: rsFull NUMERIC "1"
+// Retrieval info: PRIVATE: rsFull NUMERIC "0"
// Retrieval info: PRIVATE: rsUsedW NUMERIC "0"
-// Retrieval info: PRIVATE: sc_aclr NUMERIC "0"
+// Retrieval info: PRIVATE: sc_aclr NUMERIC "1"
// Retrieval info: PRIVATE: sc_sclr NUMERIC "0"
-// Retrieval info: PRIVATE: wsEmpty NUMERIC "1"
+// Retrieval info: PRIVATE: wsEmpty NUMERIC "0"
// Retrieval info: PRIVATE: wsFull NUMERIC "1"
// Retrieval info: PRIVATE: wsUsedW NUMERIC "0"
// Retrieval info: CONSTANT: ADD_RAM_OUTPUT_REGISTER STRING "OFF"
-// Retrieval info: CONSTANT: CLOCKS_ARE_SYNCHRONIZED STRING "FALSE"
// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone"
// Retrieval info: CONSTANT: LPM_HINT STRING "RAM_BLOCK_TYPE=M4K"
-// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "128"
+// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "1024"
// Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "OFF"
-// Retrieval info: CONSTANT: LPM_TYPE STRING "dcfifo"
-// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "32"
-// Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "7"
+// Retrieval info: CONSTANT: LPM_TYPE STRING "scfifo"
+// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "16"
+// Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "10"
// Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON"
// Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON"
// Retrieval info: CONSTANT: USE_EAB STRING "ON"
-// Retrieval info: USED_PORT: aclr 0 0 0 0 INPUT GND aclr
-// Retrieval info: USED_PORT: data 0 0 32 0 INPUT NODEFVAL data[31..0]
-// Retrieval info: USED_PORT: q 0 0 32 0 OUTPUT NODEFVAL q[31..0]
-// Retrieval info: USED_PORT: rdclk 0 0 0 0 INPUT NODEFVAL rdclk
-// Retrieval info: USED_PORT: rdempty 0 0 0 0 OUTPUT NODEFVAL rdempty
-// Retrieval info: USED_PORT: rdfull 0 0 0 0 OUTPUT NODEFVAL rdfull
+// Retrieval info: USED_PORT: aclr 0 0 0 0 INPUT NODEFVAL aclr
+// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL clock
+// Retrieval info: USED_PORT: data 0 0 16 0 INPUT NODEFVAL data[15..0]
+// Retrieval info: USED_PORT: empty 0 0 0 0 OUTPUT NODEFVAL empty
+// Retrieval info: USED_PORT: full 0 0 0 0 OUTPUT NODEFVAL full
+// Retrieval info: USED_PORT: q 0 0 16 0 OUTPUT NODEFVAL q[15..0]
// Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL rdreq
-// Retrieval info: USED_PORT: wrclk 0 0 0 0 INPUT NODEFVAL wrclk
-// Retrieval info: USED_PORT: wrempty 0 0 0 0 OUTPUT NODEFVAL wrempty
-// Retrieval info: USED_PORT: wrfull 0 0 0 0 OUTPUT NODEFVAL wrfull
+// Retrieval info: USED_PORT: usedw 0 0 10 0 OUTPUT NODEFVAL usedw[9..0]
// Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL wrreq
-// Retrieval info: CONNECT: @data 0 0 32 0 data 0 0 32 0
-// Retrieval info: CONNECT: q 0 0 32 0 @q 0 0 32 0
+// Retrieval info: CONNECT: @data 0 0 16 0 data 0 0 16 0
+// Retrieval info: CONNECT: q 0 0 16 0 @q 0 0 16 0
// Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0
// Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0
-// Retrieval info: CONNECT: @rdclk 0 0 0 0 rdclk 0 0 0 0
-// Retrieval info: CONNECT: @wrclk 0 0 0 0 wrclk 0 0 0 0
-// Retrieval info: CONNECT: rdfull 0 0 0 0 @rdfull 0 0 0 0
-// Retrieval info: CONNECT: rdempty 0 0 0 0 @rdempty 0 0 0 0
-// Retrieval info: CONNECT: wrfull 0 0 0 0 @wrfull 0 0 0 0
-// Retrieval info: CONNECT: wrempty 0 0 0 0 @wrempty 0 0 0 0
+// Retrieval info: CONNECT: @clock 0 0 0 0 clock 0 0 0 0
+// Retrieval info: CONNECT: full 0 0 0 0 @full 0 0 0 0
+// Retrieval info: CONNECT: empty 0 0 0 0 @empty 0 0 0 0
+// Retrieval info: CONNECT: usedw 0 0 10 0 @usedw 0 0 10 0
// Retrieval info: CONNECT: @aclr 0 0 0 0 aclr 0 0 0 0
// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.v TRUE
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.inc TRUE
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.cmp TRUE
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.bsf TRUE
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_inst.v TRUE
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_bb.v TRUE
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_waveforms.html TRUE
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_wave*.jpg FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2k_1clk.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2k_1clk.inc TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2k_1clk.cmp TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2k_1clk.bsf TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2k_1clk_inst.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2k_1clk_bb.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2k_1clk_waveforms.html FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2k_1clk_wave*.jpg FALSE
diff --git a/usrp/fpga/megacells/fifo_2kx16.bsf b/usrp/fpga/megacells/fifo_2kx16.bsf new file mode 100755 index 000000000..1067991fb --- /dev/null +++ b/usrp/fpga/megacells/fifo_2kx16.bsf @@ -0,0 +1,99 @@ +/*
+WARNING: Do NOT edit the input and output ports in this file in a text
+editor if you plan to continue editing the block that represents it in
+the Block Editor! File corruption is VERY likely to occur.
+*/
+/*
+Copyright (C) 1991-2006 Altera Corporation
+Your use of Altera Corporation's design tools, logic functions
+and other software and tools, and its AMPP partner logic
+functions, and any output files any of the foregoing
+(including device programming or simulation files), and any
+associated documentation or information are expressly subject
+to the terms and conditions of the Altera Program License
+Subscription Agreement, Altera MegaCore Function License
+Agreement, or other applicable license agreement, including,
+without limitation, that your use is for the sole purpose of
+programming logic devices manufactured by Altera and sold by
+Altera or its authorized distributors. Please refer to the
+applicable agreement for further details.
+*/
+(header "symbol" (version "1.1"))
+(symbol
+ (rect 0 0 160 144)
+ (text "fifo_2kx16" (rect 51 1 119 17)(font "Arial" (font_size 10)))
+ (text "inst" (rect 8 128 25 140)(font "Arial" ))
+ (port
+ (pt 0 32)
+ (input)
+ (text "data[15..0]" (rect 0 0 60 14)(font "Arial" (font_size 8)))
+ (text "data[15..0]" (rect 20 26 71 39)(font "Arial" (font_size 8)))
+ (line (pt 0 32)(pt 16 32)(line_width 3))
+ )
+ (port
+ (pt 0 56)
+ (input)
+ (text "wrreq" (rect 0 0 35 14)(font "Arial" (font_size 8)))
+ (text "wrreq" (rect 20 50 45 63)(font "Arial" (font_size 8)))
+ (line (pt 0 56)(pt 16 56)(line_width 1))
+ )
+ (port
+ (pt 0 72)
+ (input)
+ (text "rdreq" (rect 0 0 30 14)(font "Arial" (font_size 8)))
+ (text "rdreq" (rect 20 66 44 79)(font "Arial" (font_size 8)))
+ (line (pt 0 72)(pt 16 72)(line_width 1))
+ )
+ (port
+ (pt 0 96)
+ (input)
+ (text "clock" (rect 0 0 29 14)(font "Arial" (font_size 8)))
+ (text "clock" (rect 26 90 49 103)(font "Arial" (font_size 8)))
+ (line (pt 0 96)(pt 16 96)(line_width 1))
+ )
+ (port
+ (pt 0 120)
+ (input)
+ (text "aclr" (rect 0 0 21 14)(font "Arial" (font_size 8)))
+ (text "aclr" (rect 20 114 37 127)(font "Arial" (font_size 8)))
+ (line (pt 0 120)(pt 16 120)(line_width 1))
+ )
+ (port
+ (pt 160 32)
+ (output)
+ (text "q[15..0]" (rect 0 0 42 14)(font "Arial" (font_size 8)))
+ (text "q[15..0]" (rect 105 26 141 39)(font "Arial" (font_size 8)))
+ (line (pt 160 32)(pt 144 32)(line_width 3))
+ )
+ (port
+ (pt 160 56)
+ (output)
+ (text "full" (rect 0 0 16 14)(font "Arial" (font_size 8)))
+ (text "full" (rect 127 50 142 63)(font "Arial" (font_size 8)))
+ (line (pt 160 56)(pt 144 56)(line_width 1))
+ )
+ (port
+ (pt 160 72)
+ (output)
+ (text "empty" (rect 0 0 34 14)(font "Arial" (font_size 8)))
+ (text "empty" (rect 112 66 141 79)(font "Arial" (font_size 8)))
+ (line (pt 160 72)(pt 144 72)(line_width 1))
+ )
+ (port
+ (pt 160 88)
+ (output)
+ (text "usedw[10..0]" (rect 0 0 75 14)(font "Arial" (font_size 8)))
+ (text "usedw[10..0]" (rect 77 82 136 95)(font "Arial" (font_size 8)))
+ (line (pt 160 88)(pt 144 88)(line_width 3))
+ )
+ (drawing
+ (text "16 bits x 2048 words" (rect 58 116 144 128)(font "Arial" ))
+ (line (pt 16 16)(pt 144 16)(line_width 1))
+ (line (pt 144 16)(pt 144 128)(line_width 1))
+ (line (pt 144 128)(pt 16 128)(line_width 1))
+ (line (pt 16 128)(pt 16 16)(line_width 1))
+ (line (pt 16 108)(pt 144 108)(line_width 1))
+ (line (pt 16 90)(pt 22 96)(line_width 1))
+ (line (pt 22 96)(pt 16 102)(line_width 1))
+ )
+)
diff --git a/usrp/fpga/megacells/fifo_512.cmp b/usrp/fpga/megacells/fifo_2kx16.cmp index 86fc07846..96c34d8d7 100755 --- a/usrp/fpga/megacells/fifo_512.cmp +++ b/usrp/fpga/megacells/fifo_2kx16.cmp @@ -13,19 +13,17 @@ --applicable agreement for further details.
-component fifo_512
+component fifo_2kx16
PORT
(
- aclr : IN STD_LOGIC := '0';
- data : IN STD_LOGIC_VECTOR (31 DOWNTO 0);
- rdclk : IN STD_LOGIC ;
+ aclr : IN STD_LOGIC ;
+ clock : IN STD_LOGIC ;
+ data : IN STD_LOGIC_VECTOR (15 DOWNTO 0);
rdreq : IN STD_LOGIC ;
- wrclk : IN STD_LOGIC ;
wrreq : IN STD_LOGIC ;
- q : OUT STD_LOGIC_VECTOR (31 DOWNTO 0);
- rdempty : OUT STD_LOGIC ;
- rdfull : OUT STD_LOGIC ;
- wrempty : OUT STD_LOGIC ;
- wrfull : OUT STD_LOGIC
+ empty : OUT STD_LOGIC ;
+ full : OUT STD_LOGIC ;
+ q : OUT STD_LOGIC_VECTOR (15 DOWNTO 0);
+ usedw : OUT STD_LOGIC_VECTOR (10 DOWNTO 0)
);
end component;
diff --git a/usrp/fpga/megacells/fifo_512.inc b/usrp/fpga/megacells/fifo_2kx16.inc index 9ae1e3af4..3d72c6601 100755 --- a/usrp/fpga/megacells/fifo_512.inc +++ b/usrp/fpga/megacells/fifo_2kx16.inc @@ -13,20 +13,18 @@ --applicable agreement for further details.
-FUNCTION fifo_512
+FUNCTION fifo_2kx16
(
aclr,
- data[31..0],
- rdclk,
+ clock,
+ data[15..0],
rdreq,
- wrclk,
wrreq
)
RETURNS (
- q[31..0],
- rdempty,
- rdfull,
- wrempty,
- wrfull
+ empty,
+ full,
+ q[15..0],
+ usedw[10..0]
);
diff --git a/usrp/fpga/megacells/fifo_2kx16.v b/usrp/fpga/megacells/fifo_2kx16.v new file mode 100755 index 000000000..eb229769d --- /dev/null +++ b/usrp/fpga/megacells/fifo_2kx16.v @@ -0,0 +1,167 @@ +// megafunction wizard: %FIFO%
+// GENERATION: STANDARD
+// VERSION: WM1.0
+// MODULE: scfifo
+
+// ============================================================
+// File Name: fifo_2kx16.v
+// Megafunction Name(s):
+// scfifo
+// ============================================================
+// ************************************************************
+// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+//
+// 5.1 Build 213 01/19/2006 SP 1 SJ Web Edition
+// ************************************************************
+
+
+//Copyright (C) 1991-2006 Altera Corporation
+//Your use of Altera Corporation's design tools, logic functions
+//and other software and tools, and its AMPP partner logic
+//functions, and any output files any of the foregoing
+//(including device programming or simulation files), and any
+//associated documentation or information are expressly subject
+//to the terms and conditions of the Altera Program License
+//Subscription Agreement, Altera MegaCore Function License
+//Agreement, or other applicable license agreement, including,
+//without limitation, that your use is for the sole purpose of
+//programming logic devices manufactured by Altera and sold by
+//Altera or its authorized distributors. Please refer to the
+//applicable agreement for further details.
+
+
+// synopsys translate_off
+`timescale 1 ps / 1 ps
+// synopsys translate_on
+module fifo_2kx16 (
+ aclr,
+ clock,
+ data,
+ rdreq,
+ wrreq,
+ empty,
+ full,
+ q,
+ usedw);
+
+ input aclr;
+ input clock;
+ input [15:0] data;
+ input rdreq;
+ input wrreq;
+ output empty;
+ output full;
+ output [15:0] q;
+ output [10:0] usedw;
+
+ wire [10:0] sub_wire0;
+ wire sub_wire1;
+ wire [15:0] sub_wire2;
+ wire sub_wire3;
+ wire [10:0] usedw = sub_wire0[10:0];
+ wire empty = sub_wire1;
+ wire [15:0] q = sub_wire2[15:0];
+ wire full = sub_wire3;
+
+ scfifo scfifo_component (
+ .rdreq (rdreq),
+ .aclr (aclr),
+ .clock (clock),
+ .wrreq (wrreq),
+ .data (data),
+ .usedw (sub_wire0),
+ .empty (sub_wire1),
+ .q (sub_wire2),
+ .full (sub_wire3)
+ // synopsys translate_off
+ ,
+ .almost_empty (),
+ .sclr (),
+ .almost_full ()
+ // synopsys translate_on
+ );
+ defparam
+ scfifo_component.add_ram_output_register = "OFF",
+ scfifo_component.intended_device_family = "Cyclone",
+ scfifo_component.lpm_hint = "RAM_BLOCK_TYPE=M4K",
+ scfifo_component.lpm_numwords = 2048,
+ scfifo_component.lpm_showahead = "OFF",
+ scfifo_component.lpm_type = "scfifo",
+ scfifo_component.lpm_width = 16,
+ scfifo_component.lpm_widthu = 11,
+ scfifo_component.overflow_checking = "ON",
+ scfifo_component.underflow_checking = "ON",
+ scfifo_component.use_eab = "ON";
+
+
+endmodule
+
+// ============================================================
+// CNX file retrieval info
+// ============================================================
+// Retrieval info: PRIVATE: AlmostEmpty NUMERIC "0"
+// Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "-1"
+// Retrieval info: PRIVATE: AlmostFull NUMERIC "0"
+// Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1"
+// Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0"
+// Retrieval info: PRIVATE: Clock NUMERIC "0"
+// Retrieval info: PRIVATE: Depth NUMERIC "2048"
+// Retrieval info: PRIVATE: Empty NUMERIC "1"
+// Retrieval info: PRIVATE: Full NUMERIC "1"
+// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone"
+// Retrieval info: PRIVATE: LE_BasedFIFO NUMERIC "0"
+// Retrieval info: PRIVATE: LegacyRREQ NUMERIC "1"
+// Retrieval info: PRIVATE: MAX_DEPTH_BY_9 NUMERIC "0"
+// Retrieval info: PRIVATE: OVERFLOW_CHECKING NUMERIC "0"
+// Retrieval info: PRIVATE: Optimize NUMERIC "2"
+// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "2"
+// Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0"
+// Retrieval info: PRIVATE: UsedW NUMERIC "1"
+// Retrieval info: PRIVATE: Width NUMERIC "16"
+// Retrieval info: PRIVATE: dc_aclr NUMERIC "0"
+// Retrieval info: PRIVATE: rsEmpty NUMERIC "1"
+// Retrieval info: PRIVATE: rsFull NUMERIC "0"
+// Retrieval info: PRIVATE: rsUsedW NUMERIC "0"
+// Retrieval info: PRIVATE: sc_aclr NUMERIC "1"
+// Retrieval info: PRIVATE: sc_sclr NUMERIC "0"
+// Retrieval info: PRIVATE: wsEmpty NUMERIC "0"
+// Retrieval info: PRIVATE: wsFull NUMERIC "1"
+// Retrieval info: PRIVATE: wsUsedW NUMERIC "0"
+// Retrieval info: CONSTANT: ADD_RAM_OUTPUT_REGISTER STRING "OFF"
+// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone"
+// Retrieval info: CONSTANT: LPM_HINT STRING "RAM_BLOCK_TYPE=M4K"
+// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "2048"
+// Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "OFF"
+// Retrieval info: CONSTANT: LPM_TYPE STRING "scfifo"
+// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "16"
+// Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "11"
+// Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON"
+// Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON"
+// Retrieval info: CONSTANT: USE_EAB STRING "ON"
+// Retrieval info: USED_PORT: aclr 0 0 0 0 INPUT NODEFVAL aclr
+// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL clock
+// Retrieval info: USED_PORT: data 0 0 16 0 INPUT NODEFVAL data[15..0]
+// Retrieval info: USED_PORT: empty 0 0 0 0 OUTPUT NODEFVAL empty
+// Retrieval info: USED_PORT: full 0 0 0 0 OUTPUT NODEFVAL full
+// Retrieval info: USED_PORT: q 0 0 16 0 OUTPUT NODEFVAL q[15..0]
+// Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL rdreq
+// Retrieval info: USED_PORT: usedw 0 0 11 0 OUTPUT NODEFVAL usedw[10..0]
+// Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL wrreq
+// Retrieval info: CONNECT: @data 0 0 16 0 data 0 0 16 0
+// Retrieval info: CONNECT: q 0 0 16 0 @q 0 0 16 0
+// Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0
+// Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0
+// Retrieval info: CONNECT: @clock 0 0 0 0 clock 0 0 0 0
+// Retrieval info: CONNECT: full 0 0 0 0 @full 0 0 0 0
+// Retrieval info: CONNECT: empty 0 0 0 0 @empty 0 0 0 0
+// Retrieval info: CONNECT: usedw 0 0 11 0 @usedw 0 0 11 0
+// Retrieval info: CONNECT: @aclr 0 0 0 0 aclr 0 0 0 0
+// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16.inc TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16.cmp TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16.bsf TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16_inst.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16_bb.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16_waveforms.html TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16_wave*.jpg FALSE
diff --git a/usrp/fpga/megacells/fifo_512_bb.v b/usrp/fpga/megacells/fifo_2kx16_bb.v index b11803159..507bac073 100755 --- a/usrp/fpga/megacells/fifo_512_bb.v +++ b/usrp/fpga/megacells/fifo_2kx16_bb.v @@ -1,12 +1,12 @@ -// megafunction wizard: %LPM_FIFO+%VBB%
+// megafunction wizard: %FIFO%VBB%
// GENERATION: STANDARD
// VERSION: WM1.0
-// MODULE: dcfifo
+// MODULE: scfifo
// ============================================================
-// File Name: fifo_512.v
+// File Name: fifo_2kx16.v
// Megafunction Name(s):
-// dcfifo
+// scfifo
// ============================================================
// ************************************************************
// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
@@ -28,30 +28,26 @@ //Altera or its authorized distributors. Please refer to the
//applicable agreement for further details.
-module fifo_512 (
+module fifo_2kx16 (
aclr,
+ clock,
data,
- rdclk,
rdreq,
- wrclk,
wrreq,
+ empty,
+ full,
q,
- rdempty,
- rdfull,
- wrempty,
- wrfull);
+ usedw);
input aclr;
- input [31:0] data;
- input rdclk;
+ input clock;
+ input [15:0] data;
input rdreq;
- input wrclk;
input wrreq;
- output [31:0] q;
- output rdempty;
- output rdfull;
- output wrempty;
- output wrfull;
+ output empty;
+ output full;
+ output [15:0] q;
+ output [10:0] usedw;
endmodule
@@ -63,8 +59,8 @@ endmodule // Retrieval info: PRIVATE: AlmostFull NUMERIC "0"
// Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1"
// Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0"
-// Retrieval info: PRIVATE: Clock NUMERIC "4"
-// Retrieval info: PRIVATE: Depth NUMERIC "128"
+// Retrieval info: PRIVATE: Clock NUMERIC "0"
+// Retrieval info: PRIVATE: Depth NUMERIC "2048"
// Retrieval info: PRIVATE: Empty NUMERIC "1"
// Retrieval info: PRIVATE: Full NUMERIC "1"
// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone"
@@ -76,56 +72,51 @@ endmodule // Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "2"
// Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0"
// Retrieval info: PRIVATE: UsedW NUMERIC "1"
-// Retrieval info: PRIVATE: Width NUMERIC "32"
-// Retrieval info: PRIVATE: dc_aclr NUMERIC "1"
+// Retrieval info: PRIVATE: Width NUMERIC "16"
+// Retrieval info: PRIVATE: dc_aclr NUMERIC "0"
// Retrieval info: PRIVATE: rsEmpty NUMERIC "1"
-// Retrieval info: PRIVATE: rsFull NUMERIC "1"
+// Retrieval info: PRIVATE: rsFull NUMERIC "0"
// Retrieval info: PRIVATE: rsUsedW NUMERIC "0"
-// Retrieval info: PRIVATE: sc_aclr NUMERIC "0"
+// Retrieval info: PRIVATE: sc_aclr NUMERIC "1"
// Retrieval info: PRIVATE: sc_sclr NUMERIC "0"
-// Retrieval info: PRIVATE: wsEmpty NUMERIC "1"
+// Retrieval info: PRIVATE: wsEmpty NUMERIC "0"
// Retrieval info: PRIVATE: wsFull NUMERIC "1"
// Retrieval info: PRIVATE: wsUsedW NUMERIC "0"
// Retrieval info: CONSTANT: ADD_RAM_OUTPUT_REGISTER STRING "OFF"
-// Retrieval info: CONSTANT: CLOCKS_ARE_SYNCHRONIZED STRING "FALSE"
// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone"
// Retrieval info: CONSTANT: LPM_HINT STRING "RAM_BLOCK_TYPE=M4K"
-// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "128"
+// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "2048"
// Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "OFF"
-// Retrieval info: CONSTANT: LPM_TYPE STRING "dcfifo"
-// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "32"
-// Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "7"
+// Retrieval info: CONSTANT: LPM_TYPE STRING "scfifo"
+// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "16"
+// Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "11"
// Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON"
// Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON"
// Retrieval info: CONSTANT: USE_EAB STRING "ON"
-// Retrieval info: USED_PORT: aclr 0 0 0 0 INPUT GND aclr
-// Retrieval info: USED_PORT: data 0 0 32 0 INPUT NODEFVAL data[31..0]
-// Retrieval info: USED_PORT: q 0 0 32 0 OUTPUT NODEFVAL q[31..0]
-// Retrieval info: USED_PORT: rdclk 0 0 0 0 INPUT NODEFVAL rdclk
-// Retrieval info: USED_PORT: rdempty 0 0 0 0 OUTPUT NODEFVAL rdempty
-// Retrieval info: USED_PORT: rdfull 0 0 0 0 OUTPUT NODEFVAL rdfull
+// Retrieval info: USED_PORT: aclr 0 0 0 0 INPUT NODEFVAL aclr
+// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL clock
+// Retrieval info: USED_PORT: data 0 0 16 0 INPUT NODEFVAL data[15..0]
+// Retrieval info: USED_PORT: empty 0 0 0 0 OUTPUT NODEFVAL empty
+// Retrieval info: USED_PORT: full 0 0 0 0 OUTPUT NODEFVAL full
+// Retrieval info: USED_PORT: q 0 0 16 0 OUTPUT NODEFVAL q[15..0]
// Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL rdreq
-// Retrieval info: USED_PORT: wrclk 0 0 0 0 INPUT NODEFVAL wrclk
-// Retrieval info: USED_PORT: wrempty 0 0 0 0 OUTPUT NODEFVAL wrempty
-// Retrieval info: USED_PORT: wrfull 0 0 0 0 OUTPUT NODEFVAL wrfull
+// Retrieval info: USED_PORT: usedw 0 0 11 0 OUTPUT NODEFVAL usedw[10..0]
// Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL wrreq
-// Retrieval info: CONNECT: @data 0 0 32 0 data 0 0 32 0
-// Retrieval info: CONNECT: q 0 0 32 0 @q 0 0 32 0
+// Retrieval info: CONNECT: @data 0 0 16 0 data 0 0 16 0
+// Retrieval info: CONNECT: q 0 0 16 0 @q 0 0 16 0
// Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0
// Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0
-// Retrieval info: CONNECT: @rdclk 0 0 0 0 rdclk 0 0 0 0
-// Retrieval info: CONNECT: @wrclk 0 0 0 0 wrclk 0 0 0 0
-// Retrieval info: CONNECT: rdfull 0 0 0 0 @rdfull 0 0 0 0
-// Retrieval info: CONNECT: rdempty 0 0 0 0 @rdempty 0 0 0 0
-// Retrieval info: CONNECT: wrfull 0 0 0 0 @wrfull 0 0 0 0
-// Retrieval info: CONNECT: wrempty 0 0 0 0 @wrempty 0 0 0 0
+// Retrieval info: CONNECT: @clock 0 0 0 0 clock 0 0 0 0
+// Retrieval info: CONNECT: full 0 0 0 0 @full 0 0 0 0
+// Retrieval info: CONNECT: empty 0 0 0 0 @empty 0 0 0 0
+// Retrieval info: CONNECT: usedw 0 0 11 0 @usedw 0 0 11 0
// Retrieval info: CONNECT: @aclr 0 0 0 0 aclr 0 0 0 0
// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.v TRUE
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.inc TRUE
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.cmp TRUE
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512.bsf TRUE
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_inst.v TRUE
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_bb.v TRUE
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_waveforms.html TRUE
-// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_512_wave*.jpg FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16.inc TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16.cmp TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16.bsf TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16_inst.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16_bb.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16_waveforms.html TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_2kx16_wave*.jpg FALSE
diff --git a/usrp/fpga/megacells/fifo_2kx16_inst.v b/usrp/fpga/megacells/fifo_2kx16_inst.v new file mode 100755 index 000000000..6185c6fe6 --- /dev/null +++ b/usrp/fpga/megacells/fifo_2kx16_inst.v @@ -0,0 +1,11 @@ +fifo_2kx16 fifo_2kx16_inst (
+ .aclr ( aclr_sig ),
+ .clock ( clock_sig ),
+ .data ( data_sig ),
+ .rdreq ( rdreq_sig ),
+ .wrreq ( wrreq_sig ),
+ .empty ( empty_sig ),
+ .full ( full_sig ),
+ .q ( q_sig ),
+ .usedw ( usedw_sig )
+ );
diff --git a/usrp/fpga/megacells/fifo_4kx16.bsf b/usrp/fpga/megacells/fifo_4kx16.bsf new file mode 100755 index 000000000..4d988c5e9 --- /dev/null +++ b/usrp/fpga/megacells/fifo_4kx16.bsf @@ -0,0 +1,99 @@ +/*
+WARNING: Do NOT edit the input and output ports in this file in a text
+editor if you plan to continue editing the block that represents it in
+the Block Editor! File corruption is VERY likely to occur.
+*/
+/*
+Copyright (C) 1991-2006 Altera Corporation
+Your use of Altera Corporation's design tools, logic functions
+and other software and tools, and its AMPP partner logic
+functions, and any output files any of the foregoing
+(including device programming or simulation files), and any
+associated documentation or information are expressly subject
+to the terms and conditions of the Altera Program License
+Subscription Agreement, Altera MegaCore Function License
+Agreement, or other applicable license agreement, including,
+without limitation, that your use is for the sole purpose of
+programming logic devices manufactured by Altera and sold by
+Altera or its authorized distributors. Please refer to the
+applicable agreement for further details.
+*/
+(header "symbol" (version "1.1"))
+(symbol
+ (rect 0 0 160 144)
+ (text "fifo_4kx16" (rect 51 1 119 17)(font "Arial" (font_size 10)))
+ (text "inst" (rect 8 128 25 140)(font "Arial" ))
+ (port
+ (pt 0 32)
+ (input)
+ (text "data[15..0]" (rect 0 0 60 14)(font "Arial" (font_size 8)))
+ (text "data[15..0]" (rect 20 26 71 39)(font "Arial" (font_size 8)))
+ (line (pt 0 32)(pt 16 32)(line_width 3))
+ )
+ (port
+ (pt 0 56)
+ (input)
+ (text "wrreq" (rect 0 0 35 14)(font "Arial" (font_size 8)))
+ (text "wrreq" (rect 20 50 45 63)(font "Arial" (font_size 8)))
+ (line (pt 0 56)(pt 16 56)(line_width 1))
+ )
+ (port
+ (pt 0 72)
+ (input)
+ (text "rdreq" (rect 0 0 30 14)(font "Arial" (font_size 8)))
+ (text "rdreq" (rect 20 66 44 79)(font "Arial" (font_size 8)))
+ (line (pt 0 72)(pt 16 72)(line_width 1))
+ )
+ (port
+ (pt 0 96)
+ (input)
+ (text "clock" (rect 0 0 29 14)(font "Arial" (font_size 8)))
+ (text "clock" (rect 26 90 49 103)(font "Arial" (font_size 8)))
+ (line (pt 0 96)(pt 16 96)(line_width 1))
+ )
+ (port
+ (pt 0 120)
+ (input)
+ (text "aclr" (rect 0 0 21 14)(font "Arial" (font_size 8)))
+ (text "aclr" (rect 20 114 37 127)(font "Arial" (font_size 8)))
+ (line (pt 0 120)(pt 16 120)(line_width 1))
+ )
+ (port
+ (pt 160 32)
+ (output)
+ (text "q[15..0]" (rect 0 0 42 14)(font "Arial" (font_size 8)))
+ (text "q[15..0]" (rect 105 26 141 39)(font "Arial" (font_size 8)))
+ (line (pt 160 32)(pt 144 32)(line_width 3))
+ )
+ (port
+ (pt 160 56)
+ (output)
+ (text "full" (rect 0 0 16 14)(font "Arial" (font_size 8)))
+ (text "full" (rect 127 50 142 63)(font "Arial" (font_size 8)))
+ (line (pt 160 56)(pt 144 56)(line_width 1))
+ )
+ (port
+ (pt 160 72)
+ (output)
+ (text "empty" (rect 0 0 34 14)(font "Arial" (font_size 8)))
+ (text "empty" (rect 112 66 141 79)(font "Arial" (font_size 8)))
+ (line (pt 160 72)(pt 144 72)(line_width 1))
+ )
+ (port
+ (pt 160 88)
+ (output)
+ (text "usedw[11..0]" (rect 0 0 75 14)(font "Arial" (font_size 8)))
+ (text "usedw[11..0]" (rect 77 82 136 95)(font "Arial" (font_size 8)))
+ (line (pt 160 88)(pt 144 88)(line_width 3))
+ )
+ (drawing
+ (text "16 bits x 4096 words" (rect 58 116 144 128)(font "Arial" ))
+ (line (pt 16 16)(pt 144 16)(line_width 1))
+ (line (pt 144 16)(pt 144 128)(line_width 1))
+ (line (pt 144 128)(pt 16 128)(line_width 1))
+ (line (pt 16 128)(pt 16 16)(line_width 1))
+ (line (pt 16 108)(pt 144 108)(line_width 1))
+ (line (pt 16 90)(pt 22 96)(line_width 1))
+ (line (pt 22 96)(pt 16 102)(line_width 1))
+ )
+)
diff --git a/usrp/fpga/megacells/fifo_4kx16.cmp b/usrp/fpga/megacells/fifo_4kx16.cmp new file mode 100755 index 000000000..7bc6941d7 --- /dev/null +++ b/usrp/fpga/megacells/fifo_4kx16.cmp @@ -0,0 +1,29 @@ +--Copyright (C) 1991-2006 Altera Corporation
+--Your use of Altera Corporation's design tools, logic functions
+--and other software and tools, and its AMPP partner logic
+--functions, and any output files any of the foregoing
+--(including device programming or simulation files), and any
+--associated documentation or information are expressly subject
+--to the terms and conditions of the Altera Program License
+--Subscription Agreement, Altera MegaCore Function License
+--Agreement, or other applicable license agreement, including,
+--without limitation, that your use is for the sole purpose of
+--programming logic devices manufactured by Altera and sold by
+--Altera or its authorized distributors. Please refer to the
+--applicable agreement for further details.
+
+
+component fifo_4kx16
+ PORT
+ (
+ aclr : IN STD_LOGIC ;
+ clock : IN STD_LOGIC ;
+ data : IN STD_LOGIC_VECTOR (15 DOWNTO 0);
+ rdreq : IN STD_LOGIC ;
+ wrreq : IN STD_LOGIC ;
+ empty : OUT STD_LOGIC ;
+ full : OUT STD_LOGIC ;
+ q : OUT STD_LOGIC_VECTOR (15 DOWNTO 0);
+ usedw : OUT STD_LOGIC_VECTOR (11 DOWNTO 0)
+ );
+end component;
diff --git a/usrp/fpga/megacells/fifo_4kx16.inc b/usrp/fpga/megacells/fifo_4kx16.inc new file mode 100755 index 000000000..db5d4f29e --- /dev/null +++ b/usrp/fpga/megacells/fifo_4kx16.inc @@ -0,0 +1,30 @@ +--Copyright (C) 1991-2006 Altera Corporation
+--Your use of Altera Corporation's design tools, logic functions
+--and other software and tools, and its AMPP partner logic
+--functions, and any output files any of the foregoing
+--(including device programming or simulation files), and any
+--associated documentation or information are expressly subject
+--to the terms and conditions of the Altera Program License
+--Subscription Agreement, Altera MegaCore Function License
+--Agreement, or other applicable license agreement, including,
+--without limitation, that your use is for the sole purpose of
+--programming logic devices manufactured by Altera and sold by
+--Altera or its authorized distributors. Please refer to the
+--applicable agreement for further details.
+
+
+FUNCTION fifo_4kx16
+(
+ aclr,
+ clock,
+ data[15..0],
+ rdreq,
+ wrreq
+)
+
+RETURNS (
+ empty,
+ full,
+ q[15..0],
+ usedw[11..0]
+);
diff --git a/usrp/fpga/megacells/fifo_4kx16.v b/usrp/fpga/megacells/fifo_4kx16.v new file mode 100755 index 000000000..c5ecfbae7 --- /dev/null +++ b/usrp/fpga/megacells/fifo_4kx16.v @@ -0,0 +1,167 @@ +// megafunction wizard: %FIFO%
+// GENERATION: STANDARD
+// VERSION: WM1.0
+// MODULE: scfifo
+
+// ============================================================
+// File Name: fifo_4kx16.v
+// Megafunction Name(s):
+// scfifo
+// ============================================================
+// ************************************************************
+// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+//
+// 5.1 Build 213 01/19/2006 SP 1 SJ Web Edition
+// ************************************************************
+
+
+//Copyright (C) 1991-2006 Altera Corporation
+//Your use of Altera Corporation's design tools, logic functions
+//and other software and tools, and its AMPP partner logic
+//functions, and any output files any of the foregoing
+//(including device programming or simulation files), and any
+//associated documentation or information are expressly subject
+//to the terms and conditions of the Altera Program License
+//Subscription Agreement, Altera MegaCore Function License
+//Agreement, or other applicable license agreement, including,
+//without limitation, that your use is for the sole purpose of
+//programming logic devices manufactured by Altera and sold by
+//Altera or its authorized distributors. Please refer to the
+//applicable agreement for further details.
+
+
+// synopsys translate_off
+`timescale 1 ps / 1 ps
+// synopsys translate_on
+module fifo_4kx16 (
+ aclr,
+ clock,
+ data,
+ rdreq,
+ wrreq,
+ empty,
+ full,
+ q,
+ usedw);
+
+ input aclr;
+ input clock;
+ input [15:0] data;
+ input rdreq;
+ input wrreq;
+ output empty;
+ output full;
+ output [15:0] q;
+ output [11:0] usedw;
+
+ wire [11:0] sub_wire0;
+ wire sub_wire1;
+ wire [15:0] sub_wire2;
+ wire sub_wire3;
+ wire [11:0] usedw = sub_wire0[11:0];
+ wire empty = sub_wire1;
+ wire [15:0] q = sub_wire2[15:0];
+ wire full = sub_wire3;
+
+ scfifo scfifo_component (
+ .rdreq (rdreq),
+ .aclr (aclr),
+ .clock (clock),
+ .wrreq (wrreq),
+ .data (data),
+ .usedw (sub_wire0),
+ .empty (sub_wire1),
+ .q (sub_wire2),
+ .full (sub_wire3)
+ // synopsys translate_off
+ ,
+ .almost_empty (),
+ .sclr (),
+ .almost_full ()
+ // synopsys translate_on
+ );
+ defparam
+ scfifo_component.add_ram_output_register = "OFF",
+ scfifo_component.intended_device_family = "Cyclone",
+ scfifo_component.lpm_hint = "RAM_BLOCK_TYPE=M4K",
+ scfifo_component.lpm_numwords = 4096,
+ scfifo_component.lpm_showahead = "OFF",
+ scfifo_component.lpm_type = "scfifo",
+ scfifo_component.lpm_width = 16,
+ scfifo_component.lpm_widthu = 12,
+ scfifo_component.overflow_checking = "ON",
+ scfifo_component.underflow_checking = "ON",
+ scfifo_component.use_eab = "ON";
+
+
+endmodule
+
+// ============================================================
+// CNX file retrieval info
+// ============================================================
+// Retrieval info: PRIVATE: AlmostEmpty NUMERIC "0"
+// Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "-1"
+// Retrieval info: PRIVATE: AlmostFull NUMERIC "0"
+// Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1"
+// Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0"
+// Retrieval info: PRIVATE: Clock NUMERIC "0"
+// Retrieval info: PRIVATE: Depth NUMERIC "4096"
+// Retrieval info: PRIVATE: Empty NUMERIC "1"
+// Retrieval info: PRIVATE: Full NUMERIC "1"
+// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone"
+// Retrieval info: PRIVATE: LE_BasedFIFO NUMERIC "0"
+// Retrieval info: PRIVATE: LegacyRREQ NUMERIC "1"
+// Retrieval info: PRIVATE: MAX_DEPTH_BY_9 NUMERIC "0"
+// Retrieval info: PRIVATE: OVERFLOW_CHECKING NUMERIC "0"
+// Retrieval info: PRIVATE: Optimize NUMERIC "2"
+// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "2"
+// Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0"
+// Retrieval info: PRIVATE: UsedW NUMERIC "1"
+// Retrieval info: PRIVATE: Width NUMERIC "16"
+// Retrieval info: PRIVATE: dc_aclr NUMERIC "0"
+// Retrieval info: PRIVATE: rsEmpty NUMERIC "1"
+// Retrieval info: PRIVATE: rsFull NUMERIC "0"
+// Retrieval info: PRIVATE: rsUsedW NUMERIC "0"
+// Retrieval info: PRIVATE: sc_aclr NUMERIC "1"
+// Retrieval info: PRIVATE: sc_sclr NUMERIC "0"
+// Retrieval info: PRIVATE: wsEmpty NUMERIC "0"
+// Retrieval info: PRIVATE: wsFull NUMERIC "1"
+// Retrieval info: PRIVATE: wsUsedW NUMERIC "0"
+// Retrieval info: CONSTANT: ADD_RAM_OUTPUT_REGISTER STRING "OFF"
+// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone"
+// Retrieval info: CONSTANT: LPM_HINT STRING "RAM_BLOCK_TYPE=M4K"
+// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "4096"
+// Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "OFF"
+// Retrieval info: CONSTANT: LPM_TYPE STRING "scfifo"
+// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "16"
+// Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "12"
+// Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON"
+// Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON"
+// Retrieval info: CONSTANT: USE_EAB STRING "ON"
+// Retrieval info: USED_PORT: aclr 0 0 0 0 INPUT NODEFVAL aclr
+// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL clock
+// Retrieval info: USED_PORT: data 0 0 16 0 INPUT NODEFVAL data[15..0]
+// Retrieval info: USED_PORT: empty 0 0 0 0 OUTPUT NODEFVAL empty
+// Retrieval info: USED_PORT: full 0 0 0 0 OUTPUT NODEFVAL full
+// Retrieval info: USED_PORT: q 0 0 16 0 OUTPUT NODEFVAL q[15..0]
+// Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL rdreq
+// Retrieval info: USED_PORT: usedw 0 0 12 0 OUTPUT NODEFVAL usedw[11..0]
+// Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL wrreq
+// Retrieval info: CONNECT: @data 0 0 16 0 data 0 0 16 0
+// Retrieval info: CONNECT: q 0 0 16 0 @q 0 0 16 0
+// Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0
+// Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0
+// Retrieval info: CONNECT: @clock 0 0 0 0 clock 0 0 0 0
+// Retrieval info: CONNECT: full 0 0 0 0 @full 0 0 0 0
+// Retrieval info: CONNECT: empty 0 0 0 0 @empty 0 0 0 0
+// Retrieval info: CONNECT: usedw 0 0 12 0 @usedw 0 0 12 0
+// Retrieval info: CONNECT: @aclr 0 0 0 0 aclr 0 0 0 0
+// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16.inc TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16.cmp TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16.bsf TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16_inst.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16_bb.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16_waveforms.html TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16_wave*.jpg FALSE
diff --git a/usrp/fpga/megacells/fifo_4kx16_bb.v b/usrp/fpga/megacells/fifo_4kx16_bb.v new file mode 100755 index 000000000..d41e9f090 --- /dev/null +++ b/usrp/fpga/megacells/fifo_4kx16_bb.v @@ -0,0 +1,122 @@ +// megafunction wizard: %FIFO%VBB%
+// GENERATION: STANDARD
+// VERSION: WM1.0
+// MODULE: scfifo
+
+// ============================================================
+// File Name: fifo_4kx16.v
+// Megafunction Name(s):
+// scfifo
+// ============================================================
+// ************************************************************
+// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+//
+// 5.1 Build 213 01/19/2006 SP 1 SJ Web Edition
+// ************************************************************
+
+//Copyright (C) 1991-2006 Altera Corporation
+//Your use of Altera Corporation's design tools, logic functions
+//and other software and tools, and its AMPP partner logic
+//functions, and any output files any of the foregoing
+//(including device programming or simulation files), and any
+//associated documentation or information are expressly subject
+//to the terms and conditions of the Altera Program License
+//Subscription Agreement, Altera MegaCore Function License
+//Agreement, or other applicable license agreement, including,
+//without limitation, that your use is for the sole purpose of
+//programming logic devices manufactured by Altera and sold by
+//Altera or its authorized distributors. Please refer to the
+//applicable agreement for further details.
+
+module fifo_4kx16 (
+ aclr,
+ clock,
+ data,
+ rdreq,
+ wrreq,
+ empty,
+ full,
+ q,
+ usedw);
+
+ input aclr;
+ input clock;
+ input [15:0] data;
+ input rdreq;
+ input wrreq;
+ output empty;
+ output full;
+ output [15:0] q;
+ output [11:0] usedw;
+
+endmodule
+
+// ============================================================
+// CNX file retrieval info
+// ============================================================
+// Retrieval info: PRIVATE: AlmostEmpty NUMERIC "0"
+// Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "-1"
+// Retrieval info: PRIVATE: AlmostFull NUMERIC "0"
+// Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1"
+// Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0"
+// Retrieval info: PRIVATE: Clock NUMERIC "0"
+// Retrieval info: PRIVATE: Depth NUMERIC "4096"
+// Retrieval info: PRIVATE: Empty NUMERIC "1"
+// Retrieval info: PRIVATE: Full NUMERIC "1"
+// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone"
+// Retrieval info: PRIVATE: LE_BasedFIFO NUMERIC "0"
+// Retrieval info: PRIVATE: LegacyRREQ NUMERIC "1"
+// Retrieval info: PRIVATE: MAX_DEPTH_BY_9 NUMERIC "0"
+// Retrieval info: PRIVATE: OVERFLOW_CHECKING NUMERIC "0"
+// Retrieval info: PRIVATE: Optimize NUMERIC "2"
+// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "2"
+// Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0"
+// Retrieval info: PRIVATE: UsedW NUMERIC "1"
+// Retrieval info: PRIVATE: Width NUMERIC "16"
+// Retrieval info: PRIVATE: dc_aclr NUMERIC "0"
+// Retrieval info: PRIVATE: rsEmpty NUMERIC "1"
+// Retrieval info: PRIVATE: rsFull NUMERIC "0"
+// Retrieval info: PRIVATE: rsUsedW NUMERIC "0"
+// Retrieval info: PRIVATE: sc_aclr NUMERIC "1"
+// Retrieval info: PRIVATE: sc_sclr NUMERIC "0"
+// Retrieval info: PRIVATE: wsEmpty NUMERIC "0"
+// Retrieval info: PRIVATE: wsFull NUMERIC "1"
+// Retrieval info: PRIVATE: wsUsedW NUMERIC "0"
+// Retrieval info: CONSTANT: ADD_RAM_OUTPUT_REGISTER STRING "OFF"
+// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone"
+// Retrieval info: CONSTANT: LPM_HINT STRING "RAM_BLOCK_TYPE=M4K"
+// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "4096"
+// Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "OFF"
+// Retrieval info: CONSTANT: LPM_TYPE STRING "scfifo"
+// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "16"
+// Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "12"
+// Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON"
+// Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON"
+// Retrieval info: CONSTANT: USE_EAB STRING "ON"
+// Retrieval info: USED_PORT: aclr 0 0 0 0 INPUT NODEFVAL aclr
+// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL clock
+// Retrieval info: USED_PORT: data 0 0 16 0 INPUT NODEFVAL data[15..0]
+// Retrieval info: USED_PORT: empty 0 0 0 0 OUTPUT NODEFVAL empty
+// Retrieval info: USED_PORT: full 0 0 0 0 OUTPUT NODEFVAL full
+// Retrieval info: USED_PORT: q 0 0 16 0 OUTPUT NODEFVAL q[15..0]
+// Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL rdreq
+// Retrieval info: USED_PORT: usedw 0 0 12 0 OUTPUT NODEFVAL usedw[11..0]
+// Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL wrreq
+// Retrieval info: CONNECT: @data 0 0 16 0 data 0 0 16 0
+// Retrieval info: CONNECT: q 0 0 16 0 @q 0 0 16 0
+// Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0
+// Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0
+// Retrieval info: CONNECT: @clock 0 0 0 0 clock 0 0 0 0
+// Retrieval info: CONNECT: full 0 0 0 0 @full 0 0 0 0
+// Retrieval info: CONNECT: empty 0 0 0 0 @empty 0 0 0 0
+// Retrieval info: CONNECT: usedw 0 0 12 0 @usedw 0 0 12 0
+// Retrieval info: CONNECT: @aclr 0 0 0 0 aclr 0 0 0 0
+// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16.inc TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16.cmp TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16.bsf TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16_inst.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16_bb.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16_waveforms.html TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL fifo_4kx16_wave*.jpg FALSE
diff --git a/usrp/fpga/megacells/fifo_4kx16_inst.v b/usrp/fpga/megacells/fifo_4kx16_inst.v new file mode 100755 index 000000000..eb260acaa --- /dev/null +++ b/usrp/fpga/megacells/fifo_4kx16_inst.v @@ -0,0 +1,11 @@ +fifo_4kx16 fifo_4kx16_inst (
+ .aclr ( aclr_sig ),
+ .clock ( clock_sig ),
+ .data ( data_sig ),
+ .rdreq ( rdreq_sig ),
+ .wrreq ( wrreq_sig ),
+ .empty ( empty_sig ),
+ .full ( full_sig ),
+ .q ( q_sig ),
+ .usedw ( usedw_sig )
+ );
diff --git a/usrp/fpga/megacells/fifo_512.bsf b/usrp/fpga/megacells/fifo_512.bsf deleted file mode 100755 index a955b5655..000000000 --- a/usrp/fpga/megacells/fifo_512.bsf +++ /dev/null @@ -1,116 +0,0 @@ -/*
-WARNING: Do NOT edit the input and output ports in this file in a text
-editor if you plan to continue editing the block that represents it in
-the Block Editor! File corruption is VERY likely to occur.
-*/
-/*
-Copyright (C) 1991-2006 Altera Corporation
-Your use of Altera Corporation's design tools, logic functions
-and other software and tools, and its AMPP partner logic
-functions, and any output files any of the foregoing
-(including device programming or simulation files), and any
-associated documentation or information are expressly subject
-to the terms and conditions of the Altera Program License
-Subscription Agreement, Altera MegaCore Function License
-Agreement, or other applicable license agreement, including,
-without limitation, that your use is for the sole purpose of
-programming logic devices manufactured by Altera and sold by
-Altera or its authorized distributors. Please refer to the
-applicable agreement for further details.
-*/
-(header "symbol" (version "1.1"))
-(symbol
- (rect 0 0 160 184)
- (text "fifo_512" (rect 58 1 109 17)(font "Arial" (font_size 10)))
- (text "inst" (rect 8 168 25 180)(font "Arial" ))
- (port
- (pt 0 32)
- (input)
- (text "data[31..0]" (rect 0 0 60 14)(font "Arial" (font_size 8)))
- (text "data[31..0]" (rect 20 26 71 39)(font "Arial" (font_size 8)))
- (line (pt 0 32)(pt 16 32)(line_width 3))
- )
- (port
- (pt 0 56)
- (input)
- (text "wrreq" (rect 0 0 35 14)(font "Arial" (font_size 8)))
- (text "wrreq" (rect 20 50 45 63)(font "Arial" (font_size 8)))
- (line (pt 0 56)(pt 16 56)(line_width 1))
- )
- (port
- (pt 0 72)
- (input)
- (text "wrclk" (rect 0 0 31 14)(font "Arial" (font_size 8)))
- (text "wrclk" (rect 26 66 48 79)(font "Arial" (font_size 8)))
- (line (pt 0 72)(pt 16 72)(line_width 1))
- )
- (port
- (pt 0 104)
- (input)
- (text "rdreq" (rect 0 0 30 14)(font "Arial" (font_size 8)))
- (text "rdreq" (rect 20 98 44 111)(font "Arial" (font_size 8)))
- (line (pt 0 104)(pt 16 104)(line_width 1))
- )
- (port
- (pt 0 120)
- (input)
- (text "rdclk" (rect 0 0 27 14)(font "Arial" (font_size 8)))
- (text "rdclk" (rect 26 114 47 127)(font "Arial" (font_size 8)))
- (line (pt 0 120)(pt 16 120)(line_width 1))
- )
- (port
- (pt 0 160)
- (input)
- (text "aclr" (rect 0 0 21 14)(font "Arial" (font_size 8)))
- (text "aclr" (rect 20 154 37 167)(font "Arial" (font_size 8)))
- (line (pt 0 160)(pt 16 160)(line_width 1))
- )
- (port
- (pt 160 40)
- (output)
- (text "wrfull" (rect 0 0 33 14)(font "Arial" (font_size 8)))
- (text "wrfull" (rect 113 34 138 47)(font "Arial" (font_size 8)))
- (line (pt 160 40)(pt 144 40)(line_width 1))
- )
- (port
- (pt 160 56)
- (output)
- (text "wrempty" (rect 0 0 50 14)(font "Arial" (font_size 8)))
- (text "wrempty" (rect 98 50 137 63)(font "Arial" (font_size 8)))
- (line (pt 160 56)(pt 144 56)(line_width 1))
- )
- (port
- (pt 160 96)
- (output)
- (text "q[31..0]" (rect 0 0 42 14)(font "Arial" (font_size 8)))
- (text "q[31..0]" (rect 105 90 141 103)(font "Arial" (font_size 8)))
- (line (pt 160 96)(pt 144 96)(line_width 3))
- )
- (port
- (pt 160 120)
- (output)
- (text "rdfull" (rect 0 0 28 14)(font "Arial" (font_size 8)))
- (text "rdfull" (rect 117 114 141 127)(font "Arial" (font_size 8)))
- (line (pt 160 120)(pt 144 120)(line_width 1))
- )
- (port
- (pt 160 136)
- (output)
- (text "rdempty" (rect 0 0 46 14)(font "Arial" (font_size 8)))
- (text "rdempty" (rect 102 130 140 143)(font "Arial" (font_size 8)))
- (line (pt 160 136)(pt 144 136)(line_width 1))
- )
- (drawing
- (text "32 bits x 128 words" (rect 63 156 144 168)(font "Arial" ))
- (line (pt 16 16)(pt 144 16)(line_width 1))
- (line (pt 144 16)(pt 144 168)(line_width 1))
- (line (pt 144 168)(pt 16 168)(line_width 1))
- (line (pt 16 168)(pt 16 16)(line_width 1))
- (line (pt 16 84)(pt 144 84)(line_width 1))
- (line (pt 16 148)(pt 144 148)(line_width 1))
- (line (pt 16 66)(pt 22 72)(line_width 1))
- (line (pt 22 72)(pt 16 78)(line_width 1))
- (line (pt 16 114)(pt 22 120)(line_width 1))
- (line (pt 22 120)(pt 16 126)(line_width 1))
- )
-)
diff --git a/usrp/fpga/toplevel/usrp_inband_usb/config.vh b/usrp/fpga/toplevel/usrp_inband_usb/config.vh index 2d1929439..3291dc10b 100644 --- a/usrp/fpga/toplevel/usrp_inband_usb/config.vh +++ b/usrp/fpga/toplevel/usrp_inband_usb/config.vh @@ -1,4 +1,4 @@ -// -*- verilog -*- + // -*- verilog -*- // // USRP - Universal Software Radio Peripheral // 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 8296a453e..6b4764078 100644 --- a/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.qsf +++ b/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.qsf @@ -372,11 +372,16 @@ set_instance_assignment -name CLOCK_SETTINGS master_clk -to master_clk set_instance_assignment -name PARTITION_HIERARCHY no_file_for_top_partition -to | -section_id Top set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top set_global_assignment -name FITTER_AUTO_EFFORT_DESIRED_SLACK_MARGIN "100 ps" +set_global_assignment -name VERILOG_FILE ../../inband_lib/channel_demux.v +set_global_assignment -name VERILOG_FILE ../../inband_lib/tx_packer.v +set_global_assignment -name VERILOG_FILE ../../inband_lib/cmd_reader.v +set_global_assignment -name VERILOG_FILE ../../megacells/fifo_2k_1clk.v +set_global_assignment -name VERILOG_FILE ../../inband_lib/packet_builder.v +set_global_assignment -name VERILOG_FILE ../../inband_lib/rx_buffer_inband.v +set_global_assignment -name VERILOG_FILE ../../sdr_lib/atr_delay.v +set_global_assignment -name VERILOG_FILE ../../megacells/fifo_1k.v set_global_assignment -name VERILOG_FILE ../../inband_lib/tx_buffer_inband.v -set_global_assignment -name VERILOG_FILE ../../inband_lib/usb_packet_fifo.v set_global_assignment -name VERILOG_FILE ../../inband_lib/chan_fifo_reader.v -set_global_assignment -name VERILOG_FILE ../../inband_lib/data_packet_fifo.v -set_global_assignment -name VERILOG_FILE ../../inband_lib/usb_fifo_reader.v set_global_assignment -name VERILOG_FILE ../../sdr_lib/cic_dec_shifter.v set_global_assignment -name VERILOG_FILE ../../sdr_lib/rssi.v set_global_assignment -name VERILOG_FILE ../../sdr_lib/ram16.v @@ -412,4 +417,6 @@ set_global_assignment -name VERILOG_FILE usrp_inband_usb.v set_global_assignment -name VERILOG_FILE ../../sdr_lib/clk_divider.v 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
\ No newline at end of file +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 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 cc7490c5a..3bfdda56b 100644 --- a/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.v +++ b/usrp/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.v @@ -19,7 +19,8 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA // -`define IN_BAND +`define TX_IN_BAND +`define RX_IN_BAND `include "config.vh" `include "../../../firmware/include/fpga_regs_common.v" @@ -115,6 +116,12 @@ module usrp_inband_usb reg [15:0] debug_counter; reg [15:0] loopback_i_0,loopback_q_0; + + //Connection RX inband <-> TX inband + wire rx_WR; + wire [15:0] rx_databus; + wire rx_WR_done; + wire rx_WR_enabled; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Transmit Side `ifdef TX_ON @@ -123,7 +130,17 @@ module usrp_inband_usb assign bb_tx_i1 = ch2tx; assign bb_tx_q1 = ch3tx; -`ifdef IN_BAND +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; +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)); + +`ifdef TX_IN_BAND tx_buffer_inband tx_buffer ( .usbclk(usbclk),.bus_reset(tx_bus_reset),.reset(tx_dsp_reset), .usbdata(usbdata),.WR(WR),.have_space(have_space),.tx_underrun(tx_underrun), @@ -135,7 +152,17 @@ module usrp_inband_usb .txclk(clk64),.txstrobe(strobe_interp), .clear_status(clear_status), .tx_empty(tx_empty), - .debugbus(tx_debugbus) ); + .rx_WR(rx_WR), + .rx_databus(rx_databus), + .rx_WR_done(rx_WR_done), + .rx_WR_enabled(rx_WR_enabled), + .reg_addr(reg_addr), + .reg_data_out(reg_data_out), + .reg_data_in(reg_data_in), + .reg_io_enable(reg_io_enable), + .debugbus(tx_debugbus), + .rssi_0(rssi_0), .rssi_1(rssi_1), .rssi_2(rssi_2), + .rssi_3(rssi_3), .threshhold(rssi_threshhold)); `else tx_buffer tx_buffer ( .usbclk(usbclk),.bus_reset(tx_bus_reset),.reset(tx_dsp_reset), @@ -147,8 +174,7 @@ module usrp_inband_usb .tx_i_3(),.tx_q_3(), .txclk(clk64),.txstrobe(strobe_interp), .clear_status(clear_status), - .tx_empty(tx_empty), - .debugbus(tx_debugbus) ); + .tx_empty(tx_empty)); `endif `ifdef TX_EN_0 @@ -226,7 +252,6 @@ module usrp_inband_usb wire [15:0] ddc0_in_i,ddc0_in_q,ddc1_in_i,ddc1_in_q,ddc2_in_i,ddc2_in_q,ddc3_in_i,ddc3_in_q; wire [31:0] rssi_0,rssi_1,rssi_2,rssi_3; - adc_interface adc_interface(.clock(clk64),.reset(rx_dsp_reset),.enable(1'b1), .serial_addr(serial_addr),.serial_data(serial_data),.serial_strobe(serial_strobe), .rx_a_a(rx_a_a),.rx_b_a(rx_b_a),.rx_a_b(rx_a_b),.rx_b_b(rx_b_b), @@ -234,9 +259,9 @@ module usrp_inband_usb .ddc0_in_i(ddc0_in_i),.ddc0_in_q(ddc0_in_q), .ddc1_in_i(ddc1_in_i),.ddc1_in_q(ddc1_in_q), .ddc2_in_i(ddc2_in_i),.ddc2_in_q(ddc2_in_q), - .ddc3_in_i(ddc3_in_i),.ddc3_in_q(ddc3_in_q),.rx_numchan(rx_numchan) ); - - rx_buffer rx_buffer + .ddc3_in_i(ddc3_in_i),.ddc3_in_q(ddc3_in_q),.rx_numchan(rx_numchan)); + `ifdef RX_IN_BAND + rx_buffer_inband rx_buffer ( .usbclk(usbclk),.bus_reset(rx_bus_reset),.reset(rx_dsp_reset), .reset_regs(rx_dsp_reset), .usbdata(usbdata_out),.RD(RD),.have_pkt_rdy(have_pkt_rdy),.rx_overrun(rx_overrun), @@ -248,7 +273,27 @@ module usrp_inband_usb .rxclk(clk64),.rxstrobe(hb_strobe), .clear_status(clear_status), .serial_addr(serial_addr),.serial_data(serial_data),.serial_strobe(serial_strobe), - .debugbus(rx_debugbus) ); + .rx_WR(rx_WR), + .rx_databus(rx_databus), + .rx_WR_done(rx_WR_done), + .rx_WR_enabled(rx_WR_enabled), + .debugbus(rx_debugbus), + .rssi_0(rssi_0), .rssi_1(rssi_1), .rssi_2(rssi_2), .rssi_3(rssi_3)); + `else + rx_buffer rx_buffer + ( .usbclk(usbclk),.bus_reset(rx_bus_reset),.reset(rx_dsp_reset), + .reset_regs(rx_dsp_reset), + .usbdata(usbdata_out),.RD(RD),.have_pkt_rdy(have_pkt_rdy),.rx_overrun(rx_overrun), + .channels(rx_numchan), + .ch_0(ch0rx),.ch_1(ch1rx), + .ch_2(ch2rx),.ch_3(ch3rx), + .ch_4(ch4rx),.ch_5(ch5rx), + .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)/*, + .debugbus(rx_debugbus)*/); + `endif `ifdef RX_EN_0 rx_chain #(`FR_RX_FREQ_0,`FR_RX_PHASE_0) rx_chain_0 @@ -305,7 +350,6 @@ module usrp_inband_usb assign capabilities[3] = `RX_CAP_HB; assign capabilities[2:0] = `RX_CAP_NCHAN; - serial_io serial_io ( .master_clk(clk64),.serial_clock(SCLK),.serial_data_in(SDI), .enable(SEN_FPGA),.reset(1'b0),.serial_data_out(SDO), @@ -326,7 +370,7 @@ module usrp_inband_usb .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(rx_debugbus),.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,rx_overrun,decim_rate}), .reg_0(reg_0),.reg_1(reg_1),.reg_2(reg_2),.reg_3(reg_3) ); diff --git a/usrp/host/apps/Makefile.am b/usrp/host/apps/Makefile.am index f920ce59a..e0f5b8cf4 100644 --- a/usrp/host/apps/Makefile.am +++ b/usrp/host/apps/Makefile.am @@ -21,7 +21,10 @@ include $(top_srcdir)/Makefile.common -INCLUDES = $(USRP_INCLUDES) $(BOOST_CFLAGS) +INCLUDES = \ + $(DEFINES) $(OMNITHREAD_INCLUDES) $(PMT_INCLUDES) $(MBLOCK_INCLUDES) \ + $(USRP_INCLUDES) $(BOOST_CFLAGS) $(CPPUNIT_INCLUDES) + bin_PROGRAMS = \ usrper \ @@ -29,11 +32,20 @@ bin_PROGRAMS = \ noinst_PROGRAMS = \ check_order_quickly \ + test_usrp_inband_cs \ + test_usrp_inband_ping \ + test_usrp_inband_registers \ + test_usrp_inband_rx \ + test_usrp_inband_tx \ + test_usrp_inband_timestamps \ test_usrp_standard_rx \ - test_usrp_standard_tx + test_usrp_standard_tx \ + read_packets noinst_HEADERS = \ - time_stuff.h + time_stuff.h \ + ui_nco.h \ + ui_sincos.h noinst_PYTHON = \ burn-db-eeprom \ @@ -53,3 +65,24 @@ usrper_LDADD = $(USRP_LA) usrp_cal_dc_offset_SOURCES = usrp_cal_dc_offset.cc usrp_cal_dc_offset_LDADD = $(USRP_LA) + +test_usrp_inband_cs_SOURCES = test_usrp_inband_cs.cc time_stuff.c ui_sincos.c +test_usrp_inband_cs_LDADD = $(USRP_LA) + +test_usrp_inband_ping_SOURCES = test_usrp_inband_ping.cc time_stuff.c +test_usrp_inband_ping_LDADD = $(USRP_LA) + +test_usrp_inband_tx_SOURCES = test_usrp_inband_tx.cc time_stuff.c ui_sincos.c +test_usrp_inband_tx_LDADD = $(USRP_LA) + +test_usrp_inband_timestamps_SOURCES = test_usrp_inband_timestamps.cc time_stuff.c ui_sincos.c +test_usrp_inband_timestamps_LDADD = $(USRP_LA) + +test_usrp_inband_registers_SOURCES = test_usrp_inband_registers.cc time_stuff.c ui_sincos.c +test_usrp_inband_registers_LDADD = $(USRP_LA) + +test_usrp_inband_rx_SOURCES = test_usrp_inband_rx.cc time_stuff.c ui_sincos.c +test_usrp_inband_rx_LDADD = $(USRP_LA) + +read_packets_SOURCES = read_packets.cc +read_packets_LDADD = $(USRP_LA) diff --git a/usrp/host/apps/read_packets.cc b/usrp/host/apps/read_packets.cc new file mode 100644 index 000000000..92d8baf0d --- /dev/null +++ b/usrp/host/apps/read_packets.cc @@ -0,0 +1,103 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <iostream> +#include <usrp_inband_usb_packet.h> +#include <mb_class_registry.h> +#include <vector> +#include <usrp_usb_interface.h> +#include <fstream> + +typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy + +int main(int argc, char *argv[]) { + + if(argc !=2) { + std::cout << "Usage: ./read_packets <data_file>\n"; + return -1; + } + + std::ifstream infile; + std::ofstream outfile; + + unsigned int pkt_size = transport_pkt::max_pkt_size(); + unsigned int pkt_num=0; + + transport_pkt *pkt; + char pkt_data[pkt_size]; // allocate the number of bytes for a single packet + + pkt = (transport_pkt *)pkt_data; // makes operations cleaner to read + + // Open the file and read the packets, dumping information + infile.open(argv[1], std::ios::binary|std::ios::in); + if(!infile.is_open()) + exit(-1); + + //outfile.open("dump.dat",std::ios::out|std::ios::binary); + + // read 1 packet in to the memory + infile.read(pkt_data, pkt_size); + + while(!infile.eof()) { + + printf("Packet %u\n", pkt_num); + + if(pkt->start_of_burst()) + printf("\tstart of burst\n"); + + if(pkt->end_of_burst()) + printf("\tend of burst\n"); + +// if(pkt->carrier_sense()) +// printf("\tcarrier sense\n"); + + printf("\tchannel: \t0x%x\n", pkt->chan()); + printf("\ttimestamp: \t0x%x\n", pkt->timestamp()); + //printf("\ttimestamp: \t%u\n", pkt->timestamp()); + printf("\tlength: \t%u\n", pkt->payload_len()); + printf("\trssi: \t%u\n", pkt->rssi()); + + printf("\tpayload: \n"); + for(int i=0; i < pkt->payload_len(); i++) + //for(int i=0; i < pkt->max_payload(); i++) + { + printf("\t%d\t0x%x\n", i, *(pkt->payload()+i)); + //outfile.write((const char*)(pkt->payload()+i),1); + //printf("\t\t0x%x\n", pkt->payload()+i); + + } + printf("\n\n"); + + pkt_num++; + + // read 1 packet in to the memory + infile.read(pkt_data, pkt_size); + + } + + infile.close(); + //outfile.close(); + +} diff --git a/usrp/host/apps/test_usrp_inband_cs.cc b/usrp/host/apps/test_usrp_inband_cs.cc new file mode 100644 index 000000000..1d70341fe --- /dev/null +++ b/usrp/host/apps/test_usrp_inband_cs.cc @@ -0,0 +1,478 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <mb_mblock.h> +#include <mb_runtime.h> +#include <mb_runtime_nop.h> // QA only +#include <mb_protocol_class.h> +#include <mb_exception.h> +#include <mb_msg_queue.h> +#include <mb_message.h> +#include <mb_mblock_impl.h> +#include <mb_msg_accepter.h> +#include <mb_class_registry.h> +#include <pmt.h> +#include <ui_nco.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <iostream> + +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_tx.h> +#include <symbols_usrp_rx.h> + +#define NBPING 10 + +static bool verbose = false; + +class test_usrp_cs : public mb_mblock +{ + mb_port_sptr d_tx; + mb_port_sptr d_rx; + mb_port_sptr d_cs; + pmt_t d_tx_chan; // returned tx channel handle + pmt_t d_rx_chan; // returned tx channel handle + + struct timeval times[NBPING]; + + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNEL, + TRANSMITTING, + CLOSING_CHANNEL, + CLOSING_USRP, + }; + + state_t d_state; + long d_nsamples_to_send; + long d_nsamples_xmitted; + long d_nframes_xmitted; + long d_samples_per_frame; + bool d_done_sending; + + // for generating sine wave output + ui_nco<float,float> d_nco; + double d_amplitude; + + public: + test_usrp_cs(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_cs(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void open_usrp(); + void close_usrp(); + void allocate_channel(); + void send_packets(); + void enter_receiving(); + void enter_transmitting(); + void build_and_send_ping(); + void build_and_send_next_frame(); + void handle_xmit_response(pmt_t invocation_handle); + void enter_closing_channel(); +}; + +test_usrp_cs::test_usrp_cs(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_tx_chan(PMT_NIL), + d_rx_chan(PMT_NIL), + d_state(INIT), d_nsamples_to_send((long) 40e6), + d_nsamples_xmitted(0), + d_nframes_xmitted(0), + //d_samples_per_frame((long)(126)), + //d_samples_per_frame((long)(126 * 3.5)), // non-full packet + d_samples_per_frame((long)(126 * 4)), // full packet + d_done_sending(false), + d_amplitude(16384) +{ + if(verbose) + std::cout << "[TEST_USRP_INBAND_CS] Initializing...\n"; + + d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL); + d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + //bool fake_usrp_p = true; + bool fake_usrp_p = false; + + // Test the TX side + + pmt_t usrp_dict = pmt_make_dict(); + + if(fake_usrp_p) { + pmt_dict_set(usrp_dict, + pmt_intern("fake-usrp"), + PMT_T); + } + + // Set TX and RX interpolations + pmt_dict_set(usrp_dict, + pmt_intern("interp-tx"), + pmt_from_long(128)); + + pmt_dict_set(usrp_dict, + pmt_intern("interp-rx"), + pmt_from_long(16)); + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("boe.rbf")); + + define_component("server", "usrp_server", usrp_dict); + + connect("self", "tx0", "server", "tx0"); + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + + // initialize NCO + double freq = 100e3; + int interp = 32; // 32 -> 4MS/s + double sample_rate = 128e6 / interp; + d_nco.set_freq(2*M_PI * freq/sample_rate); + + // FIXME need to somehow set the interp rate in the USRP. + // for now, we'll have the low-level code hardwire it. +} + +test_usrp_cs::~test_usrp_cs() +{ +} + +void +test_usrp_cs::initial_transition() +{ + open_usrp(); +} + +void +test_usrp_cs::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + pmt_t port_id = msg->port_id(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + std::string error_msg; + + //std::cout << msg << std::endl; + + switch(d_state){ + case OPENING_USRP: + if (pmt_eq(event, s_response_open)){ + status = pmt_nth(1, data); + if (pmt_eq(status, PMT_T)){ + allocate_channel(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + } + goto unhandled; + + case ALLOCATING_CHANNEL: + if (pmt_eq(event, s_response_allocate_channel)){ + + if(pmt_eq(d_tx->port_symbol(), port_id)) { + status = pmt_nth(1, data); + d_tx_chan = pmt_nth(2, data); + + if (pmt_eq(status, PMT_T)){ + + if(verbose) + std::cout << "[TEST_USRP_INBAND_CS] Received allocation for TX\n"; + + if(!pmt_eqv(d_rx_chan, PMT_NIL)) { + enter_receiving(); + enter_transmitting(); + } + return; + } + else { + error_msg = "failed to allocate channel:"; + goto bail; + } + } + + if(pmt_eq(d_rx->port_symbol(), port_id)) { + status = pmt_nth(1, data); + d_rx_chan = pmt_nth(2, data); + + if (pmt_eq(status, PMT_T)){ + + if(verbose) + std::cout << "[TEST_USRP_INBAND_CS] Received allocation for TX\n"; + + if(!pmt_eqv(d_tx_chan, PMT_NIL)) { + enter_receiving(); + enter_transmitting(); + } + return; + } + else { + error_msg = "failed to allocate channel:"; + goto bail; + } + } + } + goto unhandled; + + case TRANSMITTING: + if (pmt_eq(event, s_response_xmit_raw_frame)){ + handle = pmt_nth(0, data); + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + handle_xmit_response(handle); + return; + } + else { + error_msg = "bad response-xmit-raw-frame:"; + goto bail; + } + } + goto unhandled; + + case CLOSING_CHANNEL: + if (pmt_eq(event, s_response_deallocate_channel)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + close_usrp(); + return; + } + else { + error_msg = "failed to deallocate channel:"; + goto bail; + } + } + goto unhandled; + + case CLOSING_USRP: + if (pmt_eq(event, s_response_close)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + shutdown_all(PMT_T); + return; + } + else { + error_msg = "failed to close USRP:"; + goto bail; + } + } + goto unhandled; + + default: + goto unhandled; + } + return; + + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + unhandled: + if(verbose) + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; +} + + +void +test_usrp_cs::open_usrp() +{ + pmt_t which_usrp = pmt_from_long(0); + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp)); + d_state = OPENING_USRP; +} + +void +test_usrp_cs::close_usrp() +{ + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); + d_state = CLOSING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_CS] Closing USRP\n"; +} + +void +test_usrp_cs::allocate_channel() +{ + long capacity = (long) 16e6; + d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_state = ALLOCATING_CHANNEL; +} + +void +test_usrp_cs::enter_receiving() +{ + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_F, + d_rx_chan)); +} + +void +test_usrp_cs::enter_transmitting() +{ + d_state = TRANSMITTING; + d_nsamples_xmitted = 0; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_CS] Beginning transmission\n"; + + sleep(1); + +// build_and_send_next_frame(); // fire off 4 to start pipeline + + build_and_send_ping(); + build_and_send_ping(); + build_and_send_ping(); + +} + +void +test_usrp_cs::build_and_send_ping() +{ + + d_tx->send(s_cmd_to_control_channel, + pmt_list2(PMT_NIL, pmt_list1(pmt_list2(s_op_ping_fixed, + pmt_list2(pmt_from_long(0), + pmt_from_long(0)))))); + + std::cout << "[TEST_USRP_INBAND_CS] Ping sent" << std::endl; +} + +void +test_usrp_cs::build_and_send_next_frame() +{ + // allocate the uniform vector for the samples + // FIXME perhaps hold on to this between calls + +#if 1 + long nsamples_this_frame = + std::min(d_nsamples_to_send - d_nsamples_xmitted, + d_samples_per_frame); +#else + long nsamples_this_frame = d_samples_per_frame; +#endif + + if (nsamples_this_frame == 0){ + d_done_sending = true; + return; + } + + + size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q + pmt_t uvec = pmt_make_s16vector(nshorts, 0); + size_t ignore; + int16_t *samples = pmt_s16vector_writeable_elements(uvec, ignore); + + // fill in the complex sinusoid + + for (int i = 0; i < nsamples_this_frame; i++){ + + if (1){ + gr_complex s; + d_nco.sincos(&s, 1, d_amplitude); + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + else { + gr_complex s(d_amplitude, d_amplitude); + + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + } + + pmt_t timestamp = pmt_from_long(0xffffffff); // NOW + d_tx->send(s_cmd_xmit_raw_frame, + pmt_list4(pmt_from_long(d_nframes_xmitted), // invocation-handle + d_tx_chan, // channel + uvec, // the samples + timestamp)); + + d_nsamples_xmitted += nsamples_this_frame; + d_nframes_xmitted++; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_CS] Transmitted frame\n"; +} + + +void +test_usrp_cs::handle_xmit_response(pmt_t handle) +{ + if (d_done_sending && + pmt_to_long(handle) == (d_nframes_xmitted - 1)){ + // We're done sending and have received all responses + enter_closing_channel(); + } + + //build_and_send_next_frame(); +} + +void +test_usrp_cs::enter_closing_channel() +{ + d_state = CLOSING_CHANNEL; + + d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan)); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_CS] Closing channel\n"; +} + +REGISTER_MBLOCK_CLASS(test_usrp_cs); + + +// ---------------------------------------------------------------- + +int +main (int argc, char **argv) +{ + // handle any command line args here + + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_cs", PMT_F, &result); +} diff --git a/usrp/host/apps/test_usrp_inband_ping.cc b/usrp/host/apps/test_usrp_inband_ping.cc new file mode 100644 index 000000000..a68f49272 --- /dev/null +++ b/usrp/host/apps/test_usrp_inband_ping.cc @@ -0,0 +1,376 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <mb_mblock.h> +#include <mb_runtime.h> +#include <mb_runtime_nop.h> // QA only +#include <mb_protocol_class.h> +#include <mb_exception.h> +#include <mb_msg_queue.h> +#include <mb_message.h> +#include <mb_mblock_impl.h> +#include <mb_msg_accepter.h> +#include <mb_class_registry.h> +#include <pmt.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <iostream> + +// Include the symbols needed for communication with USRP server +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_tx.h> +#include <symbols_usrp_rx.h> + +static bool verbose = false; + +class test_usrp_inband_ping : public mb_mblock +{ + + mb_port_sptr d_tx; // Ports connected to the USRP server + mb_port_sptr d_rx; + mb_port_sptr d_cs; + + pmt_t d_tx_chan; // Returned channel from TX allocation + pmt_t d_rx_chan; // Returned channel from RX allocation + + pmt_t d_which_usrp; // The USRP to use for the test + + long d_warm_msgs; // The number of messages to 'warm' the USRP + long d_warm_recvd; // The number of msgs received in the 'warm' state + + // Keep track of current state + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNELS, + WARMING_USRP, + PINGING, + CLOSING_CHANNELS, + CLOSING_USRP, + }; + state_t d_state; + + public: + test_usrp_inband_ping(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_inband_ping(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void opening_usrp(); + void allocating_channels(); + void enter_warming_usrp(); + void enter_pinging(); + void build_and_send_ping(); + void closing_channels(); + void closing_usrp(); +}; + + +int +main (int argc, char **argv) +{ + // handle any command line args here + + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_inband_ping", PMT_F, &result); +} + + +test_usrp_inband_ping::test_usrp_inband_ping(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_tx_chan(PMT_NIL), + d_rx_chan(PMT_NIL), + d_which_usrp(pmt_from_long(0)), + d_state(INIT) +{ + + // A dictionary is used to pass parameters to the USRP + pmt_t usrp_dict = pmt_make_dict(); + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("fixed1.rbf")); + + // Set TX and RX interpolations + pmt_dict_set(usrp_dict, + pmt_intern("interp-tx"), + pmt_from_long(128)); + + pmt_dict_set(usrp_dict, + pmt_intern("interp-rx"), + pmt_from_long(16)); + + d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL); + d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + // Create an instance of USRP server and connect ports + define_component("server", "usrp_server", usrp_dict); + connect("self", "tx0", "server", "tx0"); + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + +} + +test_usrp_inband_ping::~test_usrp_inband_ping() +{ +} + +void +test_usrp_inband_ping::initial_transition() +{ + opening_usrp(); +} + +// Handle message reads all incoming messages from USRP server which will be +// initialization and ping responses. We perform actions based on the current +// state and the event (ie, ping response) +void +test_usrp_inband_ping::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + pmt_t port_id = msg->port_id(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + std::string error_msg; + + // Dispatch based on state + switch(d_state) { + + //----------------------------- OPENING_USRP ----------------------------// + // We only expect a response from opening the USRP which should be succesful + // or failed. + case OPENING_USRP: + + if(pmt_eq(event, s_response_open)) { + + status = pmt_nth(1, data); // failed/succes + + if(pmt_eq(status, PMT_T)) { + allocating_channels(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + + } + + goto unhandled; // all other messages not handled in this state + + + //----------------------- ALLOCATING CHANNELS --------------------// + // When allocating channels, we need to wait for 2 responses from + // USRP server: one for TX and one for RX. Both are initialized to + // NIL so we know to continue to the next state once both are set. + case ALLOCATING_CHANNELS: + + // A TX allocation response + if(pmt_eq(event, s_response_allocate_channel) + && pmt_eq(d_tx->port_symbol(), port_id)) + { + status = pmt_nth(1, data); + + // If successful response, extract the channel + if(pmt_eq(status, PMT_T)) { + + d_tx_chan = pmt_nth(2, data); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Received TX allocation" + << " on channel " << d_tx_chan << std::endl; + + // If the RX has also been allocated already, we can continue + if(!pmt_eqv(d_rx_chan, PMT_NIL)) + enter_warming_usrp(); + + return; + } + else { // TX allocation failed + error_msg = "failed to allocate TX channel:"; + goto bail; + } + } + + // A RX allocation response + if(pmt_eq(event, s_response_allocate_channel) + && pmt_eq(d_rx->port_symbol(), port_id)) + { + status = pmt_nth(1, data); + + // If successful response, extract the channel + if(pmt_eq(status, PMT_T)) { + + d_rx_chan = pmt_nth(2, data); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Received RX allocation" + << " on channel " << d_rx_chan << std::endl; + + // If the TX has also been allocated already, we can continue + if(!pmt_eqv(d_tx_chan, PMT_NIL)) + enter_warming_usrp(); + + return; + } + else { // RX allocation failed + error_msg = "failed to allocate RX channel:"; + goto bail; + } + } + + goto unhandled; + + //----------------------- WARMING USRP --------------------// + // The FX2 seems to need some amount of data to be buffered + // before it begins reading. We use this state to simply + // warm up the USRP before benchmarking pings. + case WARMING_USRP: + + // We really don't care about the responses from the + // control channel in the warming stage, but once we receive + // the proper number of responses we switch states. + if(pmt_eq(event, s_response_from_control_channel) + && pmt_eq(d_rx->port_symbol(), port_id)) + { + d_warm_recvd++; + + if(d_warm_recvd > d_warm_msgs) + enter_pinging(); + + return; + } + + goto unhandled; + + case PINGING: + goto unhandled; + + case CLOSING_CHANNELS: + goto unhandled; + + case CLOSING_USRP: + goto unhandled; + + case INIT: + goto unhandled; + + } + + // An error occured, print it, and shutdown all m-blocks + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + // Received an unhandled message for a specific state + unhandled: + if(verbose) + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; + +} + + +// Sends a command to USRP server to open up a connection to the +// specified USRP, which is defaulted to USRP 0 on the system +void +test_usrp_inband_ping::opening_usrp() +{ + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Opening USRP " + << d_which_usrp << std::endl; + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, d_which_usrp)); + d_state = OPENING_USRP; +} + +// RX and TX channels must be allocated so that the USRP server can +// properly share bandwidth across multiple USRPs. No commands will be +// successful to the USRP through the USRP server on the TX or RX channels until +// a bandwidth allocation has been received. +void +test_usrp_inband_ping::allocating_channels() +{ + d_state = ALLOCATING_CHANNELS; + + long capacity = (long) 16e6; + d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); +} + +// The USRP needs some amount of initial data to pass a buffering point such +// that it begins to pull and read data from the FX2. We send an arbitrary +// amount of data to start the pipeline, which are just pings. +void +test_usrp_inband_ping::enter_warming_usrp() +{ + d_state = WARMING_USRP; + + for(int i=0; i < d_warm_msgs; i++) + build_and_send_ping(); +} + +void +test_usrp_inband_ping::enter_pinging() +{ + d_state = PINGING; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Running ping tests\n"; + +} + +// Pings are sent over the TX channel using the signal 'cmd-to-control-channel' +// to the USRP server. Within this message there can be infinite subpackets +// stored as a list (the second parameter) and sent. The only subpacket we send +// is a ping, interpreted by the 'op-ping-fixed' signal. +void +test_usrp_inband_ping::build_and_send_ping() +{ + + d_tx->send(s_cmd_to_control_channel, // USRP server signal + pmt_list2(PMT_NIL, // invocation handle + pmt_list1(pmt_list3(s_op_ping_fixed, + pmt_from_long(0), + pmt_from_long(0))))); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Ping!!" << std::endl; +} + +REGISTER_MBLOCK_CLASS(test_usrp_inband_ping); diff --git a/usrp/host/apps/test_usrp_inband_registers.cc b/usrp/host/apps/test_usrp_inband_registers.cc new file mode 100644 index 000000000..922b6215d --- /dev/null +++ b/usrp/host/apps/test_usrp_inband_registers.cc @@ -0,0 +1,436 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <mb_mblock.h> +#include <mb_runtime.h> +#include <mb_runtime_nop.h> // QA only +#include <mb_protocol_class.h> +#include <mb_exception.h> +#include <mb_msg_queue.h> +#include <mb_message.h> +#include <mb_mblock_impl.h> +#include <mb_msg_accepter.h> +#include <mb_class_registry.h> +#include <pmt.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <iostream> + +// Include the symbols needed for communication with USRP server +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_tx.h> +#include <symbols_usrp_rx.h> + +static bool verbose = true; + +class test_usrp_inband_registers : public mb_mblock +{ + + mb_port_sptr d_tx; // Ports connected to the USRP server + mb_port_sptr d_rx; + mb_port_sptr d_cs; + + pmt_t d_tx_chan; // Returned channel from TX allocation + pmt_t d_rx_chan; // Returned channel from RX allocation + + pmt_t d_which_usrp; // The USRP to use for the test + + long d_warm_msgs; // The number of messages to 'warm' the USRP + long d_warm_recvd; // The number of msgs received in the 'warm' state + + // Keep track of current state + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNELS, + WRITE_REGISTER, + READ_REGISTER, + CLOSING_CHANNELS, + CLOSING_USRP, + }; + state_t d_state; + + public: + test_usrp_inband_registers(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_inband_registers(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void opening_usrp(); + void allocating_channels(); + void write_register(); + void read_register(); + void closing_channels(); + void closing_usrp(); + void enter_receiving(); + void build_and_send_ping(); +}; + + +int +main (int argc, char **argv) +{ + // handle any command line args here + + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_inband_registers", PMT_F, &result); +} + + +test_usrp_inband_registers::test_usrp_inband_registers(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_tx_chan(PMT_NIL), + d_rx_chan(PMT_NIL), + d_which_usrp(pmt_from_long(0)), + d_state(INIT) +{ + + // A dictionary is used to pass parameters to the USRP + pmt_t usrp_dict = pmt_make_dict(); + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("boe2.rbf")); + + // Set TX and RX interpolations + pmt_dict_set(usrp_dict, + pmt_intern("interp-tx"), + pmt_from_long(128)); + + pmt_dict_set(usrp_dict, + pmt_intern("interp-rx"), + pmt_from_long(16)); + + d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL); + d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + // Create an instance of USRP server and connect ports + define_component("server", "usrp_server", usrp_dict); + connect("self", "tx0", "server", "tx0"); + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + +} + +test_usrp_inband_registers::~test_usrp_inband_registers() +{ +} + +void +test_usrp_inband_registers::initial_transition() +{ + opening_usrp(); +} + +// Handle message reads all incoming messages from USRP server which will be +// initialization and ping responses. We perform actions based on the current +// state and the event (ie, ping response) +void +test_usrp_inband_registers::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + pmt_t port_id = msg->port_id(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + std::string error_msg; + + // Dispatch based on state + switch(d_state) { + + //----------------------------- OPENING_USRP ----------------------------// + // We only expect a response from opening the USRP which should be succesful + // or failed. + case OPENING_USRP: + + if(pmt_eq(event, s_response_open)) { + + status = pmt_nth(1, data); // failed/succes + + if(pmt_eq(status, PMT_T)) { + allocating_channels(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + + } + + goto unhandled; // all other messages not handled in this state + + + //----------------------- ALLOCATING CHANNELS --------------------// + // When allocating channels, we need to wait for 2 responses from + // USRP server: one for TX and one for RX. Both are initialized to + // NIL so we know to continue to the next state once both are set. + case ALLOCATING_CHANNELS: + + // A TX allocation response + if(pmt_eq(event, s_response_allocate_channel) + && pmt_eq(d_tx->port_symbol(), port_id)) + { + status = pmt_nth(1, data); + + // If successful response, extract the channel + if(pmt_eq(status, PMT_T)) { + + d_tx_chan = pmt_nth(2, data); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Received TX allocation" + << " on channel " << d_tx_chan << std::endl; + + // If the RX has also been allocated already, we can continue + if(!pmt_eqv(d_rx_chan, PMT_NIL)) { + enter_receiving(); + write_register(); + } + + return; + } + else { // TX allocation failed + error_msg = "failed to allocate TX channel:"; + goto bail; + } + } + + // A RX allocation response + if(pmt_eq(event, s_response_allocate_channel) + && pmt_eq(d_rx->port_symbol(), port_id)) + { + status = pmt_nth(1, data); + + // If successful response, extract the channel + if(pmt_eq(status, PMT_T)) { + + d_rx_chan = pmt_nth(2, data); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Received RX allocation" + << " on channel " << d_rx_chan << std::endl; + + // If the TX has also been allocated already, we can continue + if(!pmt_eqv(d_tx_chan, PMT_NIL)) { + enter_receiving(); + write_register(); + } + + return; + } + else { // RX allocation failed + error_msg = "failed to allocate RX channel:"; + goto bail; + } + } + + goto unhandled; + + //-------------------------- WRITE REGISTER ----------------------------// + // In the write register state, we do not expect to receive any messages + // since the write does not directly generate a response until the USRP + // responds. + case WRITE_REGISTER: + goto unhandled; + + //-------------------------- READ REGISTER ----------------------------// + // In the read register state, we only expect a read register response back + // that has the value we expect to have in it. We read the response, ensure + // that the read was successful and display the register value. + case READ_REGISTER: + + if(pmt_eq(event, s_response_from_control_channel) + && pmt_eq(d_tx->port_symbol(), port_id)) + { + status = pmt_nth(1, data); + + // If the read was successful, we extract the subpacket information + if(pmt_eq(status, PMT_T)) { + + pmt_t subp = pmt_nth(2, data); // subpacket should be the read reg reply + + pmt_t subp_sig = pmt_nth(0, subp); + pmt_t subp_data = pmt_nth(1, subp); + + if(!pmt_eqv(subp_sig, s_op_read_reg_reply)) { + error_msg = "received improper subpacket when expecting reg reply."; + goto bail; + } + + pmt_t rid = pmt_nth(0, subp_data); + pmt_t reg_num = pmt_nth(1, subp_data); + pmt_t reg_val = pmt_nth(2, subp_data); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_REGISTERS] Received read reg reply " + << "(" + << "RID: " << rid << ", " + << "Reg: " << reg_num << ", " + << "Val: " << reg_val + << ")\n"; + + // read_register(); FIX ME STATE TRANSITION + return; + + } else { // bail on unsuccessful write + error_msg = "failed to write to register."; + goto bail; + } + } + goto unhandled; + + case CLOSING_CHANNELS: + goto unhandled; + + case CLOSING_USRP: + goto unhandled; + + case INIT: + goto unhandled; + + } + + // An error occured, print it, and shutdown all m-blocks + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + // Received an unhandled message for a specific state + unhandled: + if(verbose && !pmt_eq(event, s_response_recv_raw_samples)) + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; + +} + + +// Sends a command to USRP server to open up a connection to the +// specified USRP, which is defaulted to USRP 0 on the system +void +test_usrp_inband_registers::opening_usrp() +{ + + if(verbose) + std::cout << "[TEST_USRP_INBAND_PING] Opening USRP " + << d_which_usrp << std::endl; + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, d_which_usrp)); + d_state = OPENING_USRP; +} + +// RX and TX channels must be allocated so that the USRP server can +// properly share bandwidth across multiple USRPs. No commands will be +// successful to the USRP through the USRP server on the TX or RX channels until +// a bandwidth allocation has been received. +void +test_usrp_inband_registers::allocating_channels() +{ + d_state = ALLOCATING_CHANNELS; + + long capacity = (long) 16e6; + d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); +} + +// After allocating the channels, a write register command will be sent to the +// USRP. +void +test_usrp_inband_registers::write_register() +{ + d_state = WRITE_REGISTER; + + long reg = 0; + + d_tx->send(s_cmd_to_control_channel, // C/S packet + pmt_list2(PMT_NIL, // invoc handle + pmt_list1( + pmt_list2(s_op_write_reg, + pmt_list2( + pmt_from_long(reg), + pmt_from_long(0xbeef)))))); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_REGISTERS] Writing 0xbeef to " + << reg << std::endl; + + read_register(); // immediately transition to read the register +} + +// Temporary: for testing pings +void +test_usrp_inband_registers::build_and_send_ping() +{ + + d_tx->send(s_cmd_to_control_channel, + pmt_list2(PMT_NIL, pmt_list1(pmt_list2(s_op_ping_fixed, + pmt_list2(pmt_from_long(0), + pmt_from_long(0)))))); + + std::cout << "[TEST_USRP_INBAND_CS] Ping sent" << std::endl; +} + +// After writing to the register, we want to read the value back and ensure that +// it is the same value that we wrote. +void +test_usrp_inband_registers::read_register() +{ + d_state = READ_REGISTER; + + long reg = 9; + + d_tx->send(s_cmd_to_control_channel, // C/S packet + pmt_list2(PMT_NIL, // invoc handle + pmt_list1( + pmt_list2(s_op_read_reg, + pmt_list2( + pmt_from_long(0), // rid + pmt_from_long(reg)))))); + if(verbose) + std::cout << "[TEST_USRP_INBAND_REGISTERS] Reading from register " + << reg << std::endl; +} + +// Used to enter the receiving state +void +test_usrp_inband_registers::enter_receiving() +{ + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_F, + d_rx_chan)); +} + +REGISTER_MBLOCK_CLASS(test_usrp_inband_registers); diff --git a/usrp/host/apps/test_usrp_inband_rx.cc b/usrp/host/apps/test_usrp_inband_rx.cc new file mode 100644 index 000000000..4820c2d4e --- /dev/null +++ b/usrp/host/apps/test_usrp_inband_rx.cc @@ -0,0 +1,356 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <mb_mblock.h> +#include <mb_runtime.h> +#include <mb_runtime_nop.h> // QA only +#include <mb_protocol_class.h> +#include <mb_exception.h> +#include <mb_msg_queue.h> +#include <mb_message.h> +#include <mb_mblock_impl.h> +#include <mb_msg_accepter.h> +#include <mb_class_registry.h> +#include <pmt.h> +#include <stdio.h> +#include <string.h> +#include <iostream> +#include <fstream> + +// Signal set for the USRP server +static pmt_t s_cmd_allocate_channel = pmt_intern("cmd-allocate-channel"); +static pmt_t s_cmd_close = pmt_intern("cmd-close"); +static pmt_t s_cmd_deallocate_channel = pmt_intern("cmd-deallocate-channel"); +static pmt_t s_cmd_open = pmt_intern("cmd-open"); +static pmt_t s_cmd_start_recv_raw_samples = pmt_intern("cmd-start-recv-raw-samples"); +static pmt_t s_cmd_stop_recv_raw_samples = pmt_intern("cmd-stop-recv-raw-samples"); +static pmt_t s_cmd_to_control_channel = pmt_intern("cmd-to-control-channel"); +static pmt_t s_cmd_xmit_raw_frame = pmt_intern("cmd-xmit-raw-frame"); +static pmt_t s_cmd_max_capacity = pmt_intern("cmd-max-capacity"); +static pmt_t s_cmd_ntx_chan = pmt_intern("cmd-ntx-chan"); +static pmt_t s_cmd_nrx_chan = pmt_intern("cmd-nrx-chan"); +static pmt_t s_cmd_current_capacity_allocation = pmt_intern("cmd-current-capacity-allocation"); +static pmt_t s_response_allocate_channel = pmt_intern("response-allocate-channel"); +static pmt_t s_response_close = pmt_intern("response-close"); +static pmt_t s_response_deallocate_channel = pmt_intern("response-deallocate-channel"); +static pmt_t s_response_from_control_channel = pmt_intern("response-from-control-channel"); +static pmt_t s_response_open = pmt_intern("response-open"); +static pmt_t s_response_recv_raw_samples = pmt_intern("response-recv-raw-samples"); +static pmt_t s_response_xmit_raw_frame = pmt_intern("response-xmit-raw-frame"); +static pmt_t s_response_max_capacity = pmt_intern("response-max-capacity"); +static pmt_t s_response_ntx_chan = pmt_intern("response-ntx-chan"); +static pmt_t s_response_nrx_chan = pmt_intern("response-nrx-chan"); +static pmt_t s_response_current_capacity_allocation = pmt_intern("response-current-capacity-allocation"); + +static bool verbose = false; + +class test_usrp_rx : public mb_mblock +{ + mb_port_sptr d_rx; + mb_port_sptr d_cs; + pmt_t d_rx_chan; // returned tx channel handle + + bool d_disk_write; + + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNEL, + RECEIVING, + CLOSING_CHANNEL, + CLOSING_USRP, + }; + + state_t d_state; + + std::ofstream d_ofile; + + public: + test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_rx(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void open_usrp(); + void close_usrp(); + void allocate_channel(); + void send_packets(); + void enter_receiving(); + void build_and_send_next_frame(); + void handle_response_recv_raw_samples(pmt_t invocation_handle); + void enter_closing_channel(); +}; + +test_usrp_rx::test_usrp_rx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_disk_write(false) +{ + + d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + //bool fake_usrp_p = true; + bool fake_usrp_p = false; + + d_disk_write = true; + + // Test the TX side + + // Pass a dictionary to usrp_server which specifies which interface to use, the stub or USRP + pmt_t usrp_dict = pmt_make_dict(); + + if(fake_usrp_p) + pmt_dict_set(usrp_dict, + pmt_intern("fake-usrp"), + PMT_T); + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("tmac6.rbf")); + + // Set TX and RX interpolations + pmt_dict_set(usrp_dict, + pmt_intern("interp-tx"), + pmt_from_long(128)); + + pmt_dict_set(usrp_dict, + pmt_intern("interp-rx"), + pmt_from_long(16)); + + define_component("server", "usrp_server", usrp_dict); + + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + + if(d_disk_write) + d_ofile.open("pdump_rx.dat",std::ios::binary|std::ios::out); +} + +test_usrp_rx::~test_usrp_rx() +{ + if(d_disk_write) + d_ofile.close(); +} + +void +test_usrp_rx::initial_transition() +{ + open_usrp(); +} + +void +test_usrp_rx::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + std::string error_msg; + + switch(d_state){ + case OPENING_USRP: + if (pmt_eq(event, s_response_open)){ + status = pmt_nth(1, data); + if (pmt_eq(status, PMT_T)){ + allocate_channel(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + } + goto unhandled; + + case ALLOCATING_CHANNEL: + if (pmt_eq(event, s_response_allocate_channel)){ + status = pmt_nth(1, data); + d_rx_chan = pmt_nth(2, data); + + if (pmt_eq(status, PMT_T)){ + enter_receiving(); + return; + } + else { + error_msg = "failed to allocate channel:"; + goto bail; + } + } + goto unhandled; + + case RECEIVING: + if (pmt_eq(event, s_response_recv_raw_samples)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + handle_response_recv_raw_samples(data); + return; + } + else { + error_msg = "bad response-xmit-raw-frame:"; + goto bail; + } + } + goto unhandled; + + case CLOSING_CHANNEL: + if (pmt_eq(event, s_response_deallocate_channel)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + close_usrp(); + return; + } + else { + error_msg = "failed to deallocate channel:"; + goto bail; + } + } + goto unhandled; + + case CLOSING_USRP: + if (pmt_eq(event, s_response_close)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + shutdown_all(PMT_T); + return; + } + else { + error_msg = "failed to close USRP:"; + goto bail; + } + } + goto unhandled; + + default: + goto unhandled; + } + return; + + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + unhandled: + std::cout << "test_usrp_inband_rx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; +} + + +void +test_usrp_rx::open_usrp() +{ + pmt_t which_usrp = pmt_from_long(0); + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp)); + d_state = OPENING_USRP; +} + +void +test_usrp_rx::close_usrp() +{ + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); + d_state = CLOSING_USRP; +} + +void +test_usrp_rx::allocate_channel() +{ + long capacity = (long) 16e6; + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_state = ALLOCATING_CHANNEL; +} + +void +test_usrp_rx::enter_receiving() +{ + d_state = RECEIVING; + + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_F, + d_rx_chan)); +} + +void +test_usrp_rx::handle_response_recv_raw_samples(pmt_t data) +{ + pmt_t invocation_handle = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); + pmt_t v_samples = pmt_nth(2, data); + pmt_t timestamp = pmt_nth(3, data); + pmt_t properties = pmt_nth(4, data); + + size_t n_bytes; + + const char *samples = (const char *) pmt_uniform_vector_elements(v_samples, n_bytes); + + if(d_disk_write) + d_ofile.write(samples, n_bytes); + + if(verbose) + std::cout << "."; + + if (pmt_is_dict(properties)) { + // Read the RSSI + if(pmt_t rssi = pmt_dict_ref(properties, + pmt_intern("rssi"), + PMT_NIL)) { + if(!pmt_eqv(rssi, PMT_NIL)) + std::cout << "RSSI: " << rssi << std::endl; + } + } + + +} + +void +test_usrp_rx::enter_closing_channel() +{ + d_state = CLOSING_CHANNEL; + + d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_rx_chan)); +} + +REGISTER_MBLOCK_CLASS(test_usrp_rx); + + +// ---------------------------------------------------------------- + +int +main (int argc, char **argv) +{ + // handle any command line args here + + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_rx", PMT_F, &result); +} diff --git a/usrp/host/apps/test_usrp_inband_timestamps.cc b/usrp/host/apps/test_usrp_inband_timestamps.cc new file mode 100644 index 000000000..d48c2a789 --- /dev/null +++ b/usrp/host/apps/test_usrp_inband_timestamps.cc @@ -0,0 +1,508 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <mb_mblock.h> +#include <mb_runtime.h> +#include <mb_runtime_nop.h> // QA only +#include <mb_protocol_class.h> +#include <mb_exception.h> +#include <mb_msg_queue.h> +#include <mb_message.h> +#include <mb_mblock_impl.h> +#include <mb_msg_accepter.h> +#include <mb_class_registry.h> +#include <pmt.h> +#include <ui_nco.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <iostream> + +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_tx.h> +#include <symbols_usrp_rx.h> + +#define NBPING 10 + +static bool verbose = true; +bool bskip = false; +long bstep = 10000; +long bcurr = 0; +long incr = 0x500; +long ptime = 0x000; + +class test_usrp_inband_timestamps : public mb_mblock +{ + mb_port_sptr d_tx; + mb_port_sptr d_rx; + mb_port_sptr d_cs; + pmt_t d_tx_chan; // returned tx channel handle + pmt_t d_rx_chan; // returned tx channel handle + + struct timeval times[NBPING]; + + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNEL, + TRANSMITTING, + CLOSING_CHANNEL, + CLOSING_USRP, + }; + + state_t d_state; + long d_nsamples_to_send; + long d_nsamples_xmitted; + long d_nframes_xmitted; + long d_samples_per_frame; + bool d_done_sending; + + // for generating sine wave output + ui_nco<float,float> d_nco; + double d_amplitude; + + public: + test_usrp_inband_timestamps(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_inband_timestamps(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void open_usrp(); + void close_usrp(); + void allocate_channel(); + void send_packets(); + void enter_receiving(); + void enter_transmitting(); + void build_and_send_ping(); + void build_and_send_next_frame(); + void handle_xmit_response(pmt_t invocation_handle); + void enter_closing_channel(); +}; + +test_usrp_inband_timestamps::test_usrp_inband_timestamps(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_tx_chan(PMT_NIL), + d_rx_chan(PMT_NIL), + d_state(INIT), d_nsamples_to_send((long) 40e6), + d_nsamples_xmitted(0), + d_nframes_xmitted(0), + //d_samples_per_frame((long)(126)), + d_samples_per_frame((long)(126 * 2)), // non-full packet + //d_samples_per_frame((long)(126 * 3.5)), // non-full packet + //d_samples_per_frame((long)(126 * 4)), // full packet + d_done_sending(false), + d_amplitude(16384) +{ + if(verbose) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Initializing...\n"; + + d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL); + d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + bool fake_usrp_p = false; + + // Test the TX side + + pmt_t usrp_dict = pmt_make_dict(); + + if(fake_usrp_p) { + pmt_dict_set(usrp_dict, + pmt_intern("fake-usrp"), + PMT_T); + } + + // Set TX and RX interpolations + pmt_dict_set(usrp_dict, + pmt_intern("interp-tx"), + pmt_from_long(128)); + + pmt_dict_set(usrp_dict, + pmt_intern("interp-rx"), + pmt_from_long(16)); + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("tmac5.rbf")); + + define_component("server", "usrp_server", usrp_dict); + + connect("self", "tx0", "server", "tx0"); + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + + // initialize NCO + double freq = 100e3; + int interp = 32; // 32 -> 4MS/s + double sample_rate = 128e6 / interp; + d_nco.set_freq(2*M_PI * freq/sample_rate); + +} + +test_usrp_inband_timestamps::~test_usrp_inband_timestamps() +{ +} + +void +test_usrp_inband_timestamps::initial_transition() +{ + open_usrp(); +} + +void +test_usrp_inband_timestamps::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + pmt_t port_id = msg->port_id(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + std::string error_msg; + + //std::cout << msg << std::endl; + + switch(d_state){ + case OPENING_USRP: + if (pmt_eq(event, s_response_open)){ + status = pmt_nth(1, data); + if (pmt_eq(status, PMT_T)){ + allocate_channel(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + } + goto unhandled; + + case ALLOCATING_CHANNEL: + if (pmt_eq(event, s_response_allocate_channel)){ + + if(pmt_eq(d_tx->port_symbol(), port_id)) { + status = pmt_nth(1, data); + d_tx_chan = pmt_nth(2, data); + + if (pmt_eq(status, PMT_T)){ + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Received allocation for TX\n"; + + if(!pmt_eqv(d_rx_chan, PMT_NIL)) { + enter_receiving(); + enter_transmitting(); + } + return; + } + else { + error_msg = "failed to allocate channel:"; + goto bail; + } + } + + if(pmt_eq(d_rx->port_symbol(), port_id)) { + status = pmt_nth(1, data); + d_rx_chan = pmt_nth(2, data); + + if (pmt_eq(status, PMT_T)){ + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Received allocation for TX\n"; + + if(!pmt_eqv(d_tx_chan, PMT_NIL)) { + enter_receiving(); + enter_transmitting(); + } + return; + } + else { + error_msg = "failed to allocate channel:"; + goto bail; + } + } + } + goto unhandled; + + case TRANSMITTING: + if (pmt_eq(event, s_response_xmit_raw_frame)){ + handle = pmt_nth(0, data); + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + handle_xmit_response(handle); + return; + } + else { + error_msg = "bad response-xmit-raw-frame:"; + goto bail; + } + } + + if (pmt_eq(event, s_response_from_control_channel)) { + std::cout << "ping response!\n"; + } + goto unhandled; + + case CLOSING_CHANNEL: + if (pmt_eq(event, s_response_deallocate_channel)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + close_usrp(); + return; + } + else { + error_msg = "failed to deallocate channel:"; + goto bail; + } + } + goto unhandled; + + case CLOSING_USRP: + if (pmt_eq(event, s_response_close)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + shutdown_all(PMT_T); + return; + } + else { + error_msg = "failed to close USRP:"; + goto bail; + } + } + goto unhandled; + + default: + goto unhandled; + } + return; + + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + unhandled: + if(verbose && 0) + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; +} + + +void +test_usrp_inband_timestamps::open_usrp() +{ + pmt_t which_usrp = pmt_from_long(0); + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp)); + d_state = OPENING_USRP; +} + +void +test_usrp_inband_timestamps::close_usrp() +{ + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); + d_state = CLOSING_USRP; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Closing USRP\n"; +} + +void +test_usrp_inband_timestamps::allocate_channel() +{ + long capacity = (long) 16e6; + d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_state = ALLOCATING_CHANNEL; +} + +void +test_usrp_inband_timestamps::enter_receiving() +{ + d_rx->send(s_cmd_start_recv_raw_samples, + pmt_list2(PMT_F, + d_rx_chan)); +} + +void +test_usrp_inband_timestamps::enter_transmitting() +{ + d_state = TRANSMITTING; + d_nsamples_xmitted = 0; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Beginning transmission\n"; + + sleep(1); + + build_and_send_next_frame(); + build_and_send_next_frame(); + build_and_send_next_frame(); + build_and_send_next_frame(); + +} + +void +test_usrp_inband_timestamps::build_and_send_ping() +{ + + d_tx->send(s_cmd_to_control_channel, + pmt_list2(PMT_NIL, pmt_list1(pmt_list2(s_op_ping_fixed, + pmt_list2(pmt_from_long(0), + pmt_from_long(0)))))); + if(verbose && 0) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Ping sent" << std::endl; +} + +void +test_usrp_inband_timestamps::build_and_send_next_frame() +{ + // allocate the uniform vector for the samples + // FIXME perhaps hold on to this between calls + +#if 0 + long nsamples_this_frame = + std::min(d_nsamples_to_send - d_nsamples_xmitted, + d_samples_per_frame); +#else + long nsamples_this_frame = d_samples_per_frame; +#endif + + if (nsamples_this_frame == 0){ + d_done_sending = true; + return; + } + + + size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q + pmt_t uvec = pmt_make_s16vector(nshorts, 0); + size_t ignore; + int16_t *samples = pmt_s16vector_writeable_elements(uvec, ignore); + + // fill in the complex sinusoid + + for (int i = 0; i < nsamples_this_frame; i++){ + + if (1){ + gr_complex s; + d_nco.sincos(&s, 1, d_amplitude); + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + else { + gr_complex s(d_amplitude, d_amplitude); + + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + } + + pmt_t timestamp; + + if(bskip) { + timestamp = pmt_from_long(0x0); // throw away + bcurr++; + if(bcurr == bstep) { + bskip = false; + bcurr = 0; + } + } else { + timestamp = pmt_from_long(0xffffffff); // NOW + timestamp = pmt_from_long(ptime); + ptime += incr; + bcurr++; + if(bcurr == bstep) { + //bskip = true; + bcurr = 0; + } + } + + std::cout << bskip << " -- " << bcurr << std::endl; + + d_tx->send(s_cmd_xmit_raw_frame, + pmt_list4(pmt_from_long(d_nframes_xmitted), // invocation-handle + d_tx_chan, // channel + uvec, // the samples + timestamp)); + + d_nsamples_xmitted += nsamples_this_frame; + d_nframes_xmitted++; + + if(verbose && 0) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Transmitted frame\n"; + + //build_and_send_next_frame(); +} + + +void +test_usrp_inband_timestamps::handle_xmit_response(pmt_t handle) +{ + if (d_done_sending && + pmt_to_long(handle) == (d_nframes_xmitted - 1)){ + // We're done sending and have received all responses + enter_closing_channel(); + } + + build_and_send_next_frame(); + //build_and_send_ping(); +} + +void +test_usrp_inband_timestamps::enter_closing_channel() +{ + d_state = CLOSING_CHANNEL; + + d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan)); + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TIMESTAMPS] Closing channel\n"; +} + +REGISTER_MBLOCK_CLASS(test_usrp_inband_timestamps); + + +// ---------------------------------------------------------------- + +int +main (int argc, char **argv) +{ + // handle any command line args here + + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_inband_timestamps", PMT_F, &result); +} diff --git a/usrp/host/apps/test_usrp_inband_tx.cc b/usrp/host/apps/test_usrp_inband_tx.cc new file mode 100644 index 000000000..18d36213b --- /dev/null +++ b/usrp/host/apps/test_usrp_inband_tx.cc @@ -0,0 +1,409 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <mb_mblock.h> +#include <mb_runtime.h> +#include <mb_runtime_nop.h> // QA only +#include <mb_protocol_class.h> +#include <mb_exception.h> +#include <mb_msg_queue.h> +#include <mb_message.h> +#include <mb_mblock_impl.h> +#include <mb_msg_accepter.h> +#include <mb_class_registry.h> +#include <pmt.h> +#include <ui_nco.h> +#include <stdio.h> +#include <string.h> +#include <iostream> + +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_tx.h> + +static bool verbose = false; + +class test_usrp_tx : public mb_mblock +{ + mb_port_sptr d_tx; + mb_port_sptr d_cs; + pmt_t d_tx_chan; // returned tx channel handle + + enum state_t { + INIT, + OPENING_USRP, + ALLOCATING_CHANNEL, + TRANSMITTING, + CLOSING_CHANNEL, + CLOSING_USRP, + }; + + state_t d_state; + long d_nsamples_to_send; + long d_nsamples_xmitted; + long d_nframes_xmitted; + long d_samples_per_frame; + bool d_done_sending; + + // for generating sine wave output + ui_nco<float,float> d_nco; + double d_amplitude; + + public: + test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~test_usrp_tx(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void open_usrp(); + void close_usrp(); + void allocate_channel(); + void send_packets(); + void enter_transmitting(); + void build_and_send_next_frame(); + void handle_xmit_response(pmt_t invocation_handle); + void enter_closing_channel(); +}; + +test_usrp_tx::test_usrp_tx(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + d_state(INIT), d_nsamples_to_send((long) 40e6), + d_nsamples_xmitted(0), + d_nframes_xmitted(0), + //d_samples_per_frame((long)(126)), + //d_samples_per_frame((long)(126 * 3.5)), // non-full packet + d_samples_per_frame((long)(126 * 4)), // full packet + d_done_sending(false), + d_amplitude(16384) +{ + // std::cout << "[TEST_USRP_TX] Initializing...\n"; + + d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL); + d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL); + + //bool fake_usrp_p = true; + bool fake_usrp_p = false; + + // Test the TX side + + pmt_t usrp_dict = pmt_make_dict(); + + if(fake_usrp_p) { + pmt_dict_set(usrp_dict, + pmt_intern("fake-usrp"), + PMT_T); + } + + // Specify the RBF to use + pmt_dict_set(usrp_dict, + pmt_intern("rbf"), + pmt_intern("boe3.rbf")); + + // Set TX and RX interpolations + pmt_dict_set(usrp_dict, + pmt_intern("interp-tx"), + pmt_from_long(128)); + + pmt_dict_set(usrp_dict, + pmt_intern("interp-rx"), + pmt_from_long(16)); + + pmt_dict_set(usrp_dict, + pmt_intern("rf-freq"), + pmt_from_long(10e6)); + + define_component("server", "usrp_server", usrp_dict); + + connect("self", "tx0", "server", "tx0"); + connect("self", "cs", "server", "cs"); + + // initialize NCO + double freq = 100e3; + int interp = 32; // 32 -> 4MS/s + double sample_rate = 128e6 / interp; + d_nco.set_freq(2*M_PI * freq/sample_rate); + + // FIXME need to somehow set the interp rate in the USRP. + // for now, we'll have the low-level code hardwire it. +} + +test_usrp_tx::~test_usrp_tx() +{ +} + +void +test_usrp_tx::initial_transition() +{ + open_usrp(); +} + +void +test_usrp_tx::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t data = msg->data(); + + pmt_t handle = PMT_F; + pmt_t status = PMT_F; + std::string error_msg; + + //std::cout << msg << std::endl; + + switch(d_state){ + case OPENING_USRP: + if (pmt_eq(event, s_response_open)){ + status = pmt_nth(1, data); + if (pmt_eq(status, PMT_T)){ + allocate_channel(); + return; + } + else { + error_msg = "failed to open usrp:"; + goto bail; + } + } + goto unhandled; + + case ALLOCATING_CHANNEL: + if (pmt_eq(event, s_response_allocate_channel)){ + status = pmt_nth(1, data); + d_tx_chan = pmt_nth(2, data); + + if (pmt_eq(status, PMT_T)){ + enter_transmitting(); + return; + } + else { + error_msg = "failed to allocate channel:"; + goto bail; + } + } + goto unhandled; + + case TRANSMITTING: + if (pmt_eq(event, s_response_xmit_raw_frame)){ + handle = pmt_nth(0, data); + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + handle_xmit_response(handle); + return; + } + else { + error_msg = "bad response-xmit-raw-frame:"; + goto bail; + } + } + goto unhandled; + + case CLOSING_CHANNEL: + if (pmt_eq(event, s_response_deallocate_channel)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + close_usrp(); + return; + } + else { + error_msg = "failed to deallocate channel:"; + goto bail; + } + } + goto unhandled; + + case CLOSING_USRP: + if (pmt_eq(event, s_response_close)){ + status = pmt_nth(1, data); + + if (pmt_eq(status, PMT_T)){ + shutdown_all(PMT_T); + return; + } + else { + error_msg = "failed to close USRP:"; + goto bail; + } + } + goto unhandled; + + default: + goto unhandled; + } + return; + + bail: + std::cerr << error_msg << data + << "status = " << status << std::endl; + shutdown_all(PMT_F); + return; + + unhandled: + std::cout << "test_usrp_inband_tx: unhandled msg: " << msg + << "in state "<< d_state << std::endl; +} + + +void +test_usrp_tx::open_usrp() +{ + pmt_t which_usrp = pmt_from_long(0); + + d_cs->send(s_cmd_open, pmt_list2(PMT_NIL, which_usrp)); + d_state = OPENING_USRP; +} + +void +test_usrp_tx::close_usrp() +{ + d_cs->send(s_cmd_close, pmt_list1(PMT_NIL)); + d_state = CLOSING_USRP; +} + +void +test_usrp_tx::allocate_channel() +{ + long capacity = (long) 16e6; + d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(capacity))); + d_state = ALLOCATING_CHANNEL; +} + +void +test_usrp_tx::enter_transmitting() +{ + d_state = TRANSMITTING; + d_nsamples_xmitted = 0; + + // FIXME: carrier sense hack +// d_tx->send(s_cmd_to_control_channel, // C/S packet +// pmt_list2(PMT_NIL, // invoc handle +// pmt_list1( +// pmt_list2(s_op_write_reg, +// pmt_list2( +// pmt_from_long(1), +// pmt_from_long(0)))))); + + build_and_send_next_frame(); // fire off 4 to start pipeline + build_and_send_next_frame(); + build_and_send_next_frame(); + build_and_send_next_frame(); +} + +void +test_usrp_tx::build_and_send_next_frame() +{ + // allocate the uniform vector for the samples + // FIXME perhaps hold on to this between calls + +#if 1 + long nsamples_this_frame = + std::min(d_nsamples_to_send - d_nsamples_xmitted, + d_samples_per_frame); +#else + long nsamples_this_frame = d_samples_per_frame; +#endif + + if (nsamples_this_frame == 0){ + d_done_sending = true; + return; + } + + + size_t nshorts = 2 * nsamples_this_frame; // 16-bit I & Q + pmt_t uvec = pmt_make_s16vector(nshorts, 0); + size_t ignore; + int16_t *samples = pmt_s16vector_writeable_elements(uvec, ignore); + + // fill in the complex sinusoid + + for (int i = 0; i < nsamples_this_frame; i++){ + + if (1){ + gr_complex s; + d_nco.sincos(&s, 1, d_amplitude); + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + else { + gr_complex s(d_amplitude, d_amplitude); + + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + } + + pmt_t timestamp = pmt_from_long(0xffffffff); // NOW + d_tx->send(s_cmd_xmit_raw_frame, + pmt_list4(pmt_from_long(d_nframes_xmitted), // invocation-handle + d_tx_chan, // channel + uvec, // the samples + timestamp)); + + d_nsamples_xmitted += nsamples_this_frame; + d_nframes_xmitted++; + + if(verbose) + std::cout << "[TEST_USRP_INBAND_TX] Transmitted frame\n"; +} + + +void +test_usrp_tx::handle_xmit_response(pmt_t handle) +{ + if (d_done_sending && + pmt_to_long(handle) == (d_nframes_xmitted - 1)){ + // We're done sending and have received all responses + enter_closing_channel(); + } + + build_and_send_next_frame(); +} + +void +test_usrp_tx::enter_closing_channel() +{ + d_state = CLOSING_CHANNEL; + + d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_NIL, d_tx_chan)); +} + +REGISTER_MBLOCK_CLASS(test_usrp_tx); + + +// ---------------------------------------------------------------- + +int +main (int argc, char **argv) +{ + // handle any command line args here + + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_NIL; + + rt->run("top", "test_usrp_tx", PMT_F, &result); +} diff --git a/usrp/host/apps/ui_nco.h b/usrp/host/apps/ui_nco.h new file mode 100644 index 000000000..e6d7814ab --- /dev/null +++ b/usrp/host/apps/ui_nco.h @@ -0,0 +1,202 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_UI_NCO_H +#define INCLUDED_UI_NCO_H + + +#include <vector> +#include <ui_sincos.h> +#include <cmath> + +#include <complex> +typedef std::complex<float> gr_complex; + + +/*! + * \brief base class template for Numerically Controlled Oscillator (NCO) + */ + + +//FIXME Eventually generalize this to fixed point + +template<class o_type, class i_type> +class ui_nco { +public: + ui_nco () : phase (0), phase_inc(0) {} + + virtual ~ui_nco () {} + + // radians + void set_phase (double angle) { + phase = angle; + } + + void adjust_phase (double delta_phase) { + phase += delta_phase; + } + + + // angle_rate is in radians / step + void set_freq (double angle_rate){ + phase_inc = angle_rate; + } + + // angle_rate is a delta in radians / step + void adjust_freq (double delta_angle_rate) + { + phase_inc += delta_angle_rate; + } + + // increment current phase angle + + void step () + { + phase += phase_inc; + if (fabs (phase) > M_PI){ + + while (phase > M_PI) + phase -= 2*M_PI; + + while (phase < -M_PI) + phase += 2*M_PI; + } + } + + void step (int n) + { + phase += phase_inc * n; + if (fabs (phase) > M_PI){ + + while (phase > M_PI) + phase -= 2*M_PI; + + while (phase < -M_PI) + phase += 2*M_PI; + } + } + + // units are radians / step + double get_phase () const { return phase; } + double get_freq () const { return phase_inc; } + + // compute sin and cos for current phase angle + void sincos (float *sinx, float *cosx) const; + + // compute cos or sin for current phase angle + float cos () const { return std::cos (phase); } + float sin () const { return std::sin (phase); } + + // compute a block at a time + void sin (float *output, int noutput_items, double ampl = 1.0); + void cos (float *output, int noutput_items, double ampl = 1.0); + void sincos (gr_complex *output, int noutput_items, double ampl = 1.0); + void sin (short *output, int noutput_items, double ampl = 1.0); + void cos (short *output, int noutput_items, double ampl = 1.0); + void sin (int *output, int noutput_items, double ampl = 1.0); + void cos (int *output, int noutput_items, double ampl = 1.0); + +protected: + double phase; + double phase_inc; +}; + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::sincos (float *sinx, float *cosx) const +{ + ui_sincosf (phase, sinx, cosx); +} + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::sin (float *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (float)(sin () * ampl); + step (); + } +} + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::cos (float *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (float)(cos () * ampl); + step (); + } +} + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::sin (short *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (short)(sin() * ampl); + step (); + } +} + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::cos (short *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (short)(cos () * ampl); + step (); + } +} + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::sin (int *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (int)(sin () * ampl); + step (); + } +} + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::cos (int *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = (int)(cos () * ampl); + step (); + } +} + +template<class o_type, class i_type> +void +ui_nco<o_type,i_type>::sincos (gr_complex *output, int noutput_items, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + float cosx, sinx; + sincos (&sinx, &cosx); + output[i] = gr_complex(cosx * ampl, sinx * ampl); + step (); + } +} + +#endif /* INCLUDED_UI_NCO_H */ + diff --git a/usrp/host/apps/ui_sincos.c b/usrp/host/apps/ui_sincos.c new file mode 100644 index 000000000..36ca89c7d --- /dev/null +++ b/usrp/host/apps/ui_sincos.c @@ -0,0 +1,81 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define _GNU_SOURCE // ask for GNU extensions if available + +#include <ui_sincos.h> +#include <math.h> + +// ---------------------------------------------------------------- + +#if defined (HAVE_SINCOS) + +void +ui_sincos (double x, double *sinx, double *cosx) +{ + sincos (x, sinx, cosx); +} + +#else + +void +ui_sincos (double x, double *sinx, double *cosx) +{ + *sinx = sin (x); + *cosx = cos (x); +} + +#endif + +// ---------------------------------------------------------------- + +#if defined (HAVE_SINCOSF) + +void +ui_sincosf (float x, float *sinx, float *cosx) +{ + sincosf (x, sinx, cosx); +} + +#elif defined (HAVE_SINF) && defined (HAVE_COSF) + +void +ui_sincosf (float x, float *sinx, float *cosx) +{ + *sinx = sinf (x); + *cosx = cosf (x); +} + +#else + +void +ui_sincosf (float x, float *sinx, float *cosx) +{ + *sinx = sin (x); + *cosx = cos (x); +} + +#endif diff --git a/usrp/host/apps/ui_sincos.h b/usrp/host/apps/ui_sincos.h new file mode 100644 index 000000000..d2d6e4b76 --- /dev/null +++ b/usrp/host/apps/ui_sincos.h @@ -0,0 +1,39 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_UI_SINCOS_H +#define INCLUDED_UI_SINCOS_H + +#ifdef __cplusplus +extern "C" { +#endif + +// compute sine and cosine at the same time + +void ui_sincos (double x, double *sin, double *cos); +void ui_sincosf (float x, float *sin, float *cos); + +#ifdef __cplusplus +}; +#endif + +#endif /* INCLUDED_UI_SINCOS_H */ diff --git a/usrp/host/lib/inband/Makefile.am b/usrp/host/lib/inband/Makefile.am index 017c5c489..76e769fbe 100644 --- a/usrp/host/lib/inband/Makefile.am +++ b/usrp/host/lib/inband/Makefile.am @@ -22,46 +22,74 @@ include $(top_srcdir)/Makefile.common INCLUDES = \ $(DEFINES) $(OMNITHREAD_INCLUDES) $(PMT_INCLUDES) $(MBLOCK_INCLUDES) \ - $(USRP_INCLUDES) $(BOOST_CFLAGS) $(CPPUNIT_INCLUDES) + $(USRP_INCLUDES) $(BOOST_CFLAGS) $(CPPUNIT_INCLUDES) \ + -I$(srcdir)/../../apps TESTS = test_inband EXTRA_DIST = \ - usrp_server.mbh + usrp_server.mbh \ + usrp_interface.mbh + lib_LTLIBRARIES = \ libusrp_inband.la \ - libusrp_inband-qa.la + libusrp_inband-qa.la # ------------------------------------------------------------------------ # Build the inband library BUILT_SOURCES = \ - usrp_server_mbh.cc + usrp_server_mbh.cc \ + usrp_interface_mbh.cc usrp_server_mbh.cc : usrp_server.mbh $(COMPILE_MBH) $(srcdir)/usrp_server.mbh usrp_server_mbh.cc +usrp_interface_mbh.cc : usrp_interface.mbh + $(COMPILE_MBH) usrp_interface.mbh usrp_interface_mbh.cc + libusrp_inband_la_SOURCES = \ $(BUILT_SOURCES) \ - usrp_server.cc + ../../apps/ui_sincos.c \ + usrp_inband_usb_packet.cc \ + usrp_rx.cc \ + usrp_rx_stub.cc \ + usrp_server.cc \ + usrp_tx.cc \ + usrp_tx_stub.cc \ + usrp_usb_interface.cc libusrp_inband_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0 libusrp_inband_la_LIBADD = \ $(MBLOCK_LA) \ + ../legacy/libusrp.la \ -lstdc++ - include_HEADERS = \ - usrp_server.h + usrp_inband_usb_packet.h \ + usrp_rx.h \ + usrp_rx_stub.h \ + usrp_server.h \ + usrp_tx.h \ + usrp_tx_stub.h \ + usrp_usb_interface.h noinst_HEADERS = \ + fake_usrp.h \ qa_inband.h \ qa_inband_packet_prims.h \ qa_inband_usrp_server.h \ - usrp_inband_usb_packet.h + symbols_usrp_channel.h \ + symbols_usrp_interface_cs.h \ + symbols_usrp_low_level_cs.h \ + symbols_usrp_rx.h \ + symbols_usrp_rx_cs.h \ + symbols_usrp_server_cs.h \ + symbols_usrp_tx.h \ + symbols_usrp_tx_cs.h # ------------------------------------------------------------------------ @@ -79,17 +107,22 @@ libusrp_inband_qa_la_LDFLAGS = $(NO_UNDEFINED) -avoid-version libusrp_inband_qa_la_LIBADD = \ libusrp_inband.la \ $(CPPUNIT_LIBS) \ + ../legacy/libusrp.la \ + libusrp_inband.la \ -lstdc++ # ------------------------------------------------------------------------ noinst_PROGRAMS = \ - test_inband + test_inband \ + test_usrp_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 new file mode 100644 index 000000000..8a66d5c18 --- /dev/null +++ b/usrp/host/lib/inband/fake_usrp.cc @@ -0,0 +1,135 @@ +/* -*- 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 new file mode 100644 index 000000000..818c5a506 --- /dev/null +++ b/usrp/host/lib/inband/fake_usrp.h @@ -0,0 +1,43 @@ +/* -*- 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/gen_test_packets.py b/usrp/host/lib/inband/gen_test_packets.py index 1e22722d2..2ee646384 100755 --- a/usrp/host/lib/inband/gen_test_packets.py +++ b/usrp/host/lib/inband/gen_test_packets.py @@ -70,7 +70,7 @@ def gen_all_valid_packet_lengths_2_channels(output_file): lengths = gen_shuffled_lengths() npkts = len(lengths) # number of packets we'll generator on each stream pkt_gen_0 = packet_sequence_generator(0, lengths) - pkt_gen_1 = packet_sequence_generator(1, gen_shuffled_lengths()) + pkt_gen_1 = packet_sequence_generator(0x1f, gen_shuffled_lengths()) pkt_gen = (pkt_gen_0, pkt_gen_1) which_gen = (npkts * [0]) + (npkts * [1]) @@ -83,5 +83,6 @@ def gen_all_valid_packet_lengths_2_channels(output_file): assert pkt_gen_1.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127 if __name__ == '__main__': + random.seed(0) gen_all_valid_packet_lengths_1_channel(open("all_valid_packet_lengths_1_channel.dat", "w")) gen_all_valid_packet_lengths_2_channels(open("all_valid_packet_lengths_2_channels.dat", "w")) diff --git a/usrp/host/lib/inband/qa_inband_usrp_server.cc b/usrp/host/lib/inband/qa_inband_usrp_server.cc index 324d9ee11..b01e74e00 100644 --- a/usrp/host/lib/inband/qa_inband_usrp_server.cc +++ b/usrp/host/lib/inband/qa_inband_usrp_server.cc @@ -23,6 +23,7 @@ #include <config.h> #endif +#include <usrp_inband_usb_packet.h> #include <qa_inband_usrp_server.h> #include <cppunit/TestAssert.h> #include <stdio.h> @@ -33,22 +34,17 @@ #include <mb_class_registry.h> #include <vector> #include <iostream> +#include <pmt.h> -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"); +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_tx.h> +#include <symbols_usrp_rx.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_low_level_cs.h> +typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy + +static bool verbose = false; // ---------------------------------------------------------------------------------------------- @@ -82,16 +78,20 @@ qa_alloc_top::qa_alloc_top(mb_runtime *runtime, const std::string &instance_name : mb_mblock(runtime, instance_name, user_arg) { d_nrecvd=0; - d_nmsgs_to_recv = 7; + d_nmsgs_to_recv = 6; d_nstatus=0; - d_nstatus_to_recv = 3; + d_nstatus_to_recv = 50; 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", PMT_F); + define_component("server", "usrp_server", usrp_server_dict); connect("self", "tx0", "server", "tx0"); connect("self", "rx0", "server", "rx0"); connect("self", "cs", "server", "cs"); @@ -103,42 +103,86 @@ qa_alloc_top::~qa_alloc_top(){} void qa_alloc_top::initial_transition() { + // Allocations should fail before open + d_tx->send(s_cmd_allocate_channel, + pmt_list2(pmt_list2(s_response_allocate_channel, + s_err_usrp_not_opened), + pmt_from_long(1))); + + d_rx->send(s_cmd_allocate_channel, + pmt_list2(pmt_list2(s_response_allocate_channel, + s_err_usrp_not_opened), + pmt_from_long(1))); + // Retrieve information about the USRP, then run tests - d_cs->send(s_cmd_max_capacity, pmt_list1(PMT_F)); - d_cs->send(s_cmd_ntx_chan, pmt_list1(PMT_F)); - d_cs->send(s_cmd_nrx_chan, pmt_list1(PMT_F)); + d_cs->send(s_cmd_open, + pmt_list2(pmt_list2(s_response_open, PMT_T), + pmt_from_long(0))); + + d_cs->send(s_cmd_max_capacity, + pmt_list1(pmt_list2(s_response_max_capacity, PMT_T))); + + d_cs->send(s_cmd_ntx_chan, + pmt_list1(pmt_list2(s_response_ntx_chan, PMT_T))); + + d_cs->send(s_cmd_nrx_chan, + pmt_list1(pmt_list2(s_response_nrx_chan,PMT_T))); } void qa_alloc_top::run_tests() { - std::cout << "[qa_alloc_top] Starting tests...\n"; + if(verbose) + std::cout << "[qa_alloc_top] Starting tests...\n"; + // should be able to allocate 1 byte - d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1))); + d_tx->send(s_cmd_allocate_channel, + pmt_list2(PMT_T, pmt_from_long(1))); // should not be able to allocate max capacity after 100 bytes were allocated - d_tx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::RQSTD_CAPACITY_UNAVAIL), pmt_from_long(d_max_capacity))); + d_tx->send(s_cmd_allocate_channel, + pmt_list2(s_err_requested_capacity_unavailable, + pmt_from_long(d_max_capacity))); - // keep allocating a little more until all of the channels are used and test the error response - // we start at 1 since we've already allocated 1 channel + // keep allocating a little more until all of the channels are used and test + // the error response we start at 1 since we've already allocated 1 channel for(int i=1; i < d_ntx_chan; i++) { + + if(verbose) + std::cout << "[qa_alloc_top] Sent allocation request...\n"; + d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1))); + d_nmsgs_to_recv++; } - d_tx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_UNAVAIL), pmt_from_long(1))); + + // No more channels after allocating all of them is expected + d_tx->send(s_cmd_allocate_channel, + pmt_list2(s_err_channel_unavailable, + pmt_from_long(1))); // test out the same on the RX side d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1))); - d_rx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::RQSTD_CAPACITY_UNAVAIL), pmt_from_long(d_max_capacity))); + + d_rx->send(s_cmd_allocate_channel, + pmt_list2(s_err_requested_capacity_unavailable, + pmt_from_long(d_max_capacity))); for(int i=1; i < d_nrx_chan; i++) { + d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1))); + d_nmsgs_to_recv++; } - d_rx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_UNAVAIL), pmt_from_long(1))); - // when all is said and done, there should be d_ntx_chan+d_ntx_chan bytes allocated - d_cs->send(s_cmd_current_capacity_allocation, pmt_list1(pmt_from_long(d_ntx_chan+d_nrx_chan))); + d_rx->send(s_cmd_allocate_channel, + pmt_list2(s_err_channel_unavailable, + pmt_from_long(1))); + + // when all is said and done, there should be d_ntx_chan+d_ntx_chan bytes + // allocated + d_cs->send(s_cmd_current_capacity_allocation, + pmt_list1(pmt_from_long(d_ntx_chan+d_nrx_chan))); } void @@ -154,16 +198,22 @@ qa_alloc_top::handle_message(mb_message_sptr msg) if (pmt_eq(msg->port_id(), d_cs->port_symbol())) { if(pmt_eq(msg->signal(), s_response_max_capacity)) { - d_max_capacity = pmt_to_long(pmt_nth(1, data)); - std::cout << "[qa_alloc_top] USRP has max capacity of " << d_max_capacity << "\n"; + d_max_capacity = pmt_to_long(pmt_nth(2, data)); + if(verbose) + std::cout << "[qa_alloc_top] USRP has max capacity of " + << d_max_capacity << "\n"; } else if(pmt_eq(msg->signal(), s_response_ntx_chan)) { - d_ntx_chan = pmt_to_long(pmt_nth(1, data)); - std::cout << "[qa_alloc_top] USRP tx channels: " << d_ntx_chan << "\n"; + d_ntx_chan = pmt_to_long(pmt_nth(2, data)); + if(verbose) + std::cout << "[qa_alloc_top] USRP tx channels: " + << d_ntx_chan << "\n"; } else if(pmt_eq(msg->signal(), s_response_nrx_chan)) { - d_nrx_chan = pmt_to_long(pmt_nth(1, data)); - std::cout << "[qa_alloc_top] USRP rx channels: " << d_nrx_chan << "\n"; + d_nrx_chan = pmt_to_long(pmt_nth(2, data)); + if(verbose) + std::cout << "[qa_alloc_top] USRP rx channels: " + << d_nrx_chan << "\n"; } else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) { check_message(msg); @@ -171,6 +221,8 @@ qa_alloc_top::handle_message(mb_message_sptr msg) d_nstatus++; + check_message(msg); + if(d_nstatus==d_nstatus_to_recv) run_tests(); } @@ -180,18 +232,26 @@ void qa_alloc_top::check_message(mb_message_sptr msg) { pmt_t data = msg->data(); + pmt_t event = msg->signal(); + + pmt_t expected = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); - pmt_t expected_result = pmt_nth(0, data); - pmt_t result = pmt_nth(1, data); + pmt_t e_event = pmt_nth(0, expected); + pmt_t e_status = pmt_nth(1, expected); d_nrecvd++; - if(!pmt_eqv(expected_result, result)) { - std::cout << "Got: " << result << " Expected: " << expected_result << "\n"; + if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) { + if(verbose) + std::cout << "Got: " << status << " Expected: " << e_status << "\n"; shutdown_all(PMT_F); + return; } else { - std::cout << "[qa_alloc_top] Received expected response for message " << d_nrecvd << "\n"; + if(verbose) + std::cout << "[qa_alloc_top] Received expected response for message " + << d_nrecvd << " (" << event << ")\n"; } if(d_nrecvd == d_nmsgs_to_recv) @@ -242,16 +302,20 @@ qa_dealloc_top::qa_dealloc_top(mb_runtime *runtime, const std::string &instance_ d_ndealloc_recvd=0; d_ndealloc_to_recv = 0; d_nalloc_recvd=0; - d_nalloc_to_recv = 0; + d_nalloc_to_recv = 0; // auto-set d_nstatus=0; - d_nstatus_to_recv = 3; + d_nstatus_to_recv = 4; 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", PMT_F); + define_component("server", "usrp_server", usrp_server_dict); connect("self", "tx0", "server", "tx0"); connect("self", "rx0", "server", "rx0"); connect("self", "cs", "server", "cs"); @@ -262,26 +326,46 @@ qa_dealloc_top::~qa_dealloc_top(){} void qa_dealloc_top::initial_transition() { + + if(verbose) + std::cout << "[qa_dealloc_top] Initializing...\n"; + // Retrieve information about the USRP, then run tests - d_cs->send(s_cmd_max_capacity, pmt_list1(PMT_F)); - d_cs->send(s_cmd_ntx_chan, pmt_list1(PMT_F)); - d_cs->send(s_cmd_nrx_chan, pmt_list1(PMT_F)); + d_cs->send(s_cmd_open, + pmt_list2(pmt_list2(s_response_open,PMT_T), + pmt_from_long(0))); + + d_cs->send(s_cmd_max_capacity, + pmt_list1(pmt_list2(s_response_max_capacity,PMT_T))); + + d_cs->send(s_cmd_ntx_chan, + pmt_list1(pmt_list2(s_response_ntx_chan,PMT_T))); + + d_cs->send(s_cmd_nrx_chan, + pmt_list1(pmt_list2(s_response_nrx_chan,PMT_T))); } void qa_dealloc_top::allocate_max() { - std::cout << "[qa_dealloc_top] Max allocating...\n"; // Keep allocating until we hit the maximum number of channels for(int i=0; i < d_ntx_chan; i++) { - d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1))); + d_tx->send(s_cmd_allocate_channel, + pmt_list2(pmt_list2(s_response_allocate_channel,PMT_T), + pmt_from_long(1))); // 1 byte is good enough + d_nalloc_to_recv++; } + for(int i=0; i < d_nrx_chan; i++) { - d_rx->send(s_cmd_allocate_channel, pmt_list2(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))); + d_nalloc_to_recv++; } + } void @@ -289,40 +373,103 @@ qa_dealloc_top::deallocate_all() { // Deallocate all of the channels that were allocated from allocate_max() for(int i=0; i < (int)d_tx_chans.size(); i++) { - d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_T, pmt_from_long(d_tx_chans[i]))); + + if(verbose) + std::cout << "[qa_dealloc_top] Trying to dealloc TX " + << d_tx_chans[i] << std::endl; + + d_tx->send(s_cmd_deallocate_channel, + pmt_list2(pmt_list2(s_response_deallocate_channel,PMT_T), + pmt_from_long(d_tx_chans[i]))); + d_ndealloc_to_recv++; } + + // Deallocate the RX side now for(int i=0; i < (int)d_rx_chans.size(); i++) { - d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_T, pmt_from_long(d_rx_chans[i]))); + + if(verbose) + std::cout << "[qa_dealloc_top] Trying to dealloc RX " + << d_tx_chans[i] << std::endl; + + d_rx->send(s_cmd_deallocate_channel, + pmt_list2(pmt_list2(s_response_deallocate_channel,PMT_T), + pmt_from_long(d_rx_chans[i]))); + d_ndealloc_to_recv++; } - // Should get permission denied errors trying to re-dealloc the channels, as we no - // longer have permission to them after deallocating + // Should get permission denied errors trying to re-dealloc the channels, as + // we no longer have permission to them after deallocating for(int i=0; i < (int)d_tx_chans.size(); i++) { - d_tx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::PERMISSION_DENIED), pmt_from_long(d_tx_chans[i]))); + + d_tx->send(s_cmd_deallocate_channel, + pmt_list2(pmt_list2(s_response_deallocate_channel, + s_err_channel_permission_denied), + pmt_from_long(d_tx_chans[i]))); + d_ndealloc_to_recv++; } + + // Same for RX for(int i=0; i < (int)d_rx_chans.size(); i++) { - d_rx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::PERMISSION_DENIED), pmt_from_long(d_rx_chans[i]))); + + d_rx->send(s_cmd_deallocate_channel, + pmt_list2(pmt_list2(s_response_deallocate_channel, + s_err_channel_permission_denied), + pmt_from_long(d_rx_chans[i]))); + d_ndealloc_to_recv++; } - // Try to deallocate a channel that doesn't exist on both sides, the last element in the vectors - // is the highest channel number, so we take that plus 1 + // Try to deallocate a channel that doesn't exist on both sides, the last + // element in the vectors is the highest channel number, so we take that plus + // 1 d_ndealloc_to_recv+=2; - d_tx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_INVALID), pmt_from_long(d_rx_chans.back()+1))); - d_rx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_INVALID), pmt_from_long(d_rx_chans.back()+1))); + d_tx->send(s_cmd_deallocate_channel, + pmt_list2(pmt_list2(s_response_deallocate_channel, + s_err_channel_invalid), + pmt_from_long(d_rx_chans.back()+1))); + + d_rx->send(s_cmd_deallocate_channel, + pmt_list2(pmt_list2(s_response_deallocate_channel, + s_err_channel_invalid), + pmt_from_long(d_rx_chans.back()+1))); // The used capacity should be back to 0 now that we've deallocated everything - d_cs->send(s_cmd_current_capacity_allocation, pmt_list1(pmt_from_long(0))); + d_cs->send(s_cmd_current_capacity_allocation, + pmt_list1(pmt_list2(s_response_current_capacity_allocation, + PMT_T))); } void qa_dealloc_top::handle_message(mb_message_sptr msg) { pmt_t data = msg->data(); + pmt_t event = msg->signal(); + + if(pmt_eq(event, pmt_intern("%shutdown"))) + return; + + pmt_t expected = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); + + pmt_t e_event = pmt_nth(0, expected); + pmt_t e_status = pmt_nth(1, expected); + + if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) { + if(verbose) + std::cout << "Got: " << status << " Expected: " << e_status << "\n"; + shutdown_all(PMT_F); + return; + } else { + if(verbose) + std::cout << "[qa_alloc_top] Received expected response for message " + << d_ndealloc_recvd + << " (" << event << ")\n"; + } + if (pmt_eq(msg->port_id(), d_tx->port_symbol()) || pmt_eq(msg->port_id(), d_rx->port_symbol())) { @@ -330,34 +477,32 @@ qa_dealloc_top::handle_message(mb_message_sptr msg) check_allocation(msg); } - if(pmt_eq(msg->signal(), s_response_deallocate_channel)){ - check_deallocation(msg); - } } if (pmt_eq(msg->port_id(), d_cs->port_symbol())) { if(pmt_eq(msg->signal(), s_response_max_capacity)) { - d_max_capacity = pmt_to_long(pmt_nth(1, data)); - std::cout << "[qa_dealloc_top] USRP has max capacity of " << d_max_capacity << "\n"; + d_max_capacity = pmt_to_long(pmt_nth(2, data)); } else if(pmt_eq(msg->signal(), s_response_ntx_chan)) { - d_ntx_chan = pmt_to_long(pmt_nth(1, data)); - std::cout << "[qa_dealloc_top] USRP tx channels: " << d_ntx_chan << "\n"; + d_ntx_chan = pmt_to_long(pmt_nth(2, data)); } else if(pmt_eq(msg->signal(), s_response_nrx_chan)) { - d_nrx_chan = pmt_to_long(pmt_nth(1, data)); - std::cout << "[qa_dealloc_top] USRP rx channels: " << d_nrx_chan << "\n"; + d_nrx_chan = pmt_to_long(pmt_nth(2, data)); } else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) { - // the final command is a capacity check which should be 0, then we shutdown - pmt_t expected_result = pmt_nth(0, data); - pmt_t result = pmt_nth(1, data); + // the final command is a capacity check which should be 0, then we + // shutdown + pmt_t expected_result = pmt_from_long(0); + pmt_t result = pmt_nth(2, data); - if(pmt_eqv(expected_result, result)) + if(pmt_eqv(expected_result, result)) { shutdown_all(PMT_T); - else + return; + } else { shutdown_all(PMT_F); + return; + } } d_nstatus++; @@ -367,72 +512,833 @@ qa_dealloc_top::handle_message(mb_message_sptr msg) } } + void -qa_dealloc_top::check_deallocation(mb_message_sptr msg) +qa_dealloc_top::check_allocation(mb_message_sptr msg) { pmt_t data = msg->data(); + pmt_t event = msg->signal(); - pmt_t expected_result = pmt_nth(0, data); - pmt_t result = pmt_nth(1, data); + pmt_t expected = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); + pmt_t channel = pmt_nth(2, data); - d_ndealloc_recvd++; + d_nalloc_recvd++; - if(!pmt_eqv(expected_result, result)) { - std::cout << "Got: " << result << " Expected: " << expected_result << "\n"; + if(!pmt_eqv(status, PMT_T)) { shutdown_all(PMT_F); + return; } else { - std::cout << "[qa_dealloc_top] Received expected deallocation response for message " << d_ndealloc_recvd << "\n"; + // store all of the allocate channel numbers + if(pmt_eq(msg->port_id(), d_tx->port_symbol())) + d_tx_chans.push_back(pmt_to_long(channel)); + if(pmt_eq(msg->port_id(), d_rx->port_symbol())) + d_rx_chans.push_back(pmt_to_long(channel)); } + + if(d_nalloc_recvd == d_nalloc_to_recv) { + + if(verbose) { + std::cout << "[qa_dealloc_top] Allocated TX channels: "; + for(int i=0; i < (int)d_tx_chans.size(); i++) + std::cout << d_tx_chans[i] << " "; + + std::cout << "\n[qa_dealloc_top] Allocated RX channels: "; + for(int i=0; i < (int)d_rx_chans.size(); i++) + std::cout << d_rx_chans[i] << " "; + std::cout << "\n"; + } + + deallocate_all(); // once we've allocated all of our channels, try to + // dealloc them + } +} + +REGISTER_MBLOCK_CLASS(qa_dealloc_top); + +// ---------------------------------------------------------------------------------------------- + +class qa_open_close_top : public mb_mblock +{ + mb_port_sptr d_cs; + + long d_max_capacity; + + long d_nmsg_to_recv; + long d_nmsg_recvd; + + public: + qa_open_close_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~qa_open_close_top(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void check_cs(mb_message_sptr msg); + void run_tests(); +}; + +qa_open_close_top::qa_open_close_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg) +{ + + d_nmsg_to_recv=7; + d_nmsg_recvd=0; + + 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", "cs", "server", "cs"); } +qa_open_close_top::~qa_open_close_top(){} + void -qa_dealloc_top::check_allocation(mb_message_sptr msg) +qa_open_close_top::initial_transition() +{ + run_tests(); +} + +void +qa_open_close_top::run_tests() +{ + // std::cout << "[qa_open_close_top] Starting tests\n"; + + // A close before an open should fail + d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close, + s_err_usrp_already_closed))); + + // Perform an open, and a second open which should fail + d_cs->send(s_cmd_open, + pmt_list2(pmt_list2(s_response_open,PMT_T), + pmt_from_long(0))); + + d_cs->send(s_cmd_open, + pmt_list2(pmt_list2(s_response_open, + s_err_usrp_already_opened), + pmt_from_long(0))); + + // A close should now be successful since the interface is open + d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T))); + + // But, a second close should fail + d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close, + s_err_usrp_already_closed))); + + // Just to be thorough, try an open and close again + d_cs->send(s_cmd_open, + pmt_list2(pmt_list2(s_response_open,PMT_T), + pmt_from_long(0))); + + d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T))); + +} + + +void +qa_open_close_top::handle_message(mb_message_sptr msg) { pmt_t data = msg->data(); - pmt_t invocation_handle = pmt_nth(0, data); + if (pmt_eq(msg->port_id(), d_cs->port_symbol())) { + check_cs(msg); + } + + d_nmsg_recvd++; + + if(d_nmsg_to_recv == d_nmsg_recvd) + shutdown_all(PMT_T); +} + +void +qa_open_close_top::check_cs(mb_message_sptr msg) +{ + pmt_t data = msg->data(); + pmt_t event = msg->signal(); + + pmt_t expected = pmt_nth(0, data); pmt_t status = pmt_nth(1, data); - pmt_t channel = pmt_nth(2, data); + + pmt_t e_event = pmt_nth(0, expected); + pmt_t e_status = pmt_nth(1, expected); + + if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) { + + if(verbose) + std::cout << "[qa_open_close_top] FAILED check_cs... Got: " << status + << " Expected: " << e_status + << " for event " << event << "\n"; + + shutdown_all(PMT_F); + } else { + if(verbose) + std::cout << "[qa_open_close_top] Received expected CS response (" + << event << ")\n"; + } + +} + +REGISTER_MBLOCK_CLASS(qa_open_close_top); + +// ---------------------------------------------------------------------------------------------- + +class qa_tx_top : public mb_mblock +{ + mb_port_sptr d_tx; + mb_port_sptr d_rx; + mb_port_sptr d_cs; - d_nalloc_recvd++; + long d_max_capacity; + long d_ntx_chan, d_nrx_chan; + + long d_tx_chan; + long d_rx_chan; + + long d_nmsg_to_recv; + long d_nmsg_recvd; + + public: + qa_tx_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~qa_tx_top(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void check_allocation(mb_message_sptr msg); + void check_deallocation(mb_message_sptr msg); + void check_xmit(mb_message_sptr msg); + void check_cs(mb_message_sptr msg); + void run_tests(); +}; - if(pmt_eqv(status, PMT_F)) { - std::cout << "[qa_dealloc_top] Unexpected error response when allocating channels\n"; +qa_tx_top::qa_tx_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg) +{ + + d_nmsg_to_recv=10; + d_nmsg_recvd=0; + + 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_tx_top::~qa_tx_top(){} + +void +qa_tx_top::initial_transition() +{ + run_tests(); +} + +void +qa_tx_top::run_tests() +{ + if(verbose) + std::cout << "[qa_tx_top] Starting tests\n"; + + // A transmit before an open should fail + d_tx->send(s_cmd_xmit_raw_frame, + pmt_list4(pmt_list2(s_response_xmit_raw_frame, + s_err_usrp_not_opened), + pmt_from_long(0), + pmt_make_u32vector(transport_pkt::max_payload()/4, 0), + pmt_from_long(0))); + + // Now open + d_cs->send(s_cmd_open, + pmt_list2(pmt_list2(s_response_open,PMT_T), + pmt_from_long(0))); + + // Try to transmit on a channel that we have no allocation for + d_tx->send(s_cmd_xmit_raw_frame, + pmt_list4(pmt_list2(s_response_xmit_raw_frame, + s_err_channel_permission_denied), + pmt_from_long(0), + pmt_make_u32vector(transport_pkt::max_payload()/4, 0), + pmt_from_long(0))); + + // Get a channel allocation and send on it, we assume 0 (FIXME) until 'defer' + // is implemented for simplicity + d_tx->send(s_cmd_allocate_channel, + pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T), + pmt_from_long(1))); + + d_tx->send(s_cmd_xmit_raw_frame, + pmt_list4(pmt_list2(s_response_xmit_raw_frame, PMT_T), + pmt_from_long(0), + pmt_make_u32vector(transport_pkt::max_payload()/4, 0), + pmt_from_long(0))); + + // Close should be successful + d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T))); + + // After closing, a new transmit raw frame should fail again + d_tx->send(s_cmd_xmit_raw_frame, + pmt_list4(pmt_list2(s_response_xmit_raw_frame, + s_err_usrp_not_opened), + pmt_from_long(0), + pmt_make_u32vector(transport_pkt::max_payload()/4, 0), + pmt_from_long(0))); + + // Reopen and retry before getting an allocation, the first xmit should fail, + // after we allocate it should work again + d_cs->send(s_cmd_open, + pmt_list2(pmt_list2(s_response_open, PMT_T), + pmt_from_long(0))); + + d_tx->send(s_cmd_xmit_raw_frame, + pmt_list4(pmt_list2(s_response_xmit_raw_frame, + s_err_channel_permission_denied), + pmt_from_long(0), + pmt_make_u32vector(transport_pkt::max_payload()/4, 0), + pmt_from_long(0))); + + d_tx->send(s_cmd_allocate_channel, + pmt_list2(pmt_list2(s_response_allocate_channel, PMT_T), + pmt_from_long(1))); + + d_tx->send(s_cmd_xmit_raw_frame, + pmt_list4(pmt_list2(s_response_xmit_raw_frame,PMT_T), + pmt_from_long(0), + pmt_make_u32vector(transport_pkt::max_payload()/4, 0), + pmt_from_long(0))); + + // A final close which should be successful + d_cs->send(s_cmd_close, pmt_list1(pmt_list2(s_response_close,PMT_T))); + +} + + +void +qa_tx_top::handle_message(mb_message_sptr msg) +{ + pmt_t data = msg->data(); + pmt_t event = msg->signal(); + + if(pmt_eq(event, pmt_intern("%shutdown"))) + return; + + pmt_t expected = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); + + pmt_t e_event = pmt_nth(0, expected); + pmt_t e_status = pmt_nth(1, expected); + + if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) { + if(verbose) + std::cout << "[qa_xmit_top] Got: " << status + << " Expected: " << e_status + << "For signal: " << event << "\n"; shutdown_all(PMT_F); + return; } else { + if(verbose) + std::cout << "[qa_xmit_top] Received expected response for message " + << d_nmsg_recvd + << " (" << event << ")\n"; + } + + if (pmt_eq(msg->port_id(), d_tx->port_symbol()) + || pmt_eq(msg->port_id(), d_rx->port_symbol())) { + + if(pmt_eq(msg->signal(), s_response_allocate_channel)) + check_allocation(msg); + + } + + d_nmsg_recvd++; + + if(d_nmsg_to_recv == d_nmsg_recvd){ + shutdown_all(PMT_T); + return; + } +} + +void +qa_tx_top::check_allocation(mb_message_sptr msg) +{ + pmt_t data = msg->data(); + pmt_t event = msg->signal(); + + pmt_t expected = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); + pmt_t channel = pmt_nth(2, data); + + if(pmt_eqv(status, PMT_T)) { // store all of the allocate channel numbers if(pmt_eq(msg->port_id(), d_tx->port_symbol())) - d_tx_chans.push_back(pmt_to_long(channel)); + d_tx_chan = pmt_to_long(channel); if(pmt_eq(msg->port_id(), d_rx->port_symbol())) - d_rx_chans.push_back(pmt_to_long(channel)); + d_rx_chan = pmt_to_long(channel); } +} - if(d_nalloc_recvd == d_nalloc_to_recv) { +REGISTER_MBLOCK_CLASS(qa_tx_top); + +// ---------------------------------------------------------------------------------------------- + +class qa_rx_top : public mb_mblock +{ + mb_port_sptr d_rx; + mb_port_sptr d_cs; + + long d_max_capacity; + long d_ntx_chan, d_nrx_chan; + + long d_rx_chan; + + long d_got_response_recv; + + long d_nmsg_to_recv; + long d_nmsg_recvd; + + public: + qa_rx_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~qa_rx_top(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void check_allocation(mb_message_sptr msg); + void check_deallocation(mb_message_sptr msg); + void check_xmit(mb_message_sptr msg); + void check_cs(mb_message_sptr msg); + void run_tests(); +}; + +qa_rx_top::qa_rx_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg), + 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); + + // Test the TX side + define_component("server", "usrp_server", usrp_server_dict); + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); +} + +qa_rx_top::~qa_rx_top(){} + +void +qa_rx_top::initial_transition() +{ + run_tests(); +} + +void +qa_rx_top::run_tests() +{ + if(verbose) + std::cout << "[qa_rx_top] Starting tests\n"; + + d_cs->send(s_cmd_open, pmt_list2(pmt_list2(s_response_open,PMT_T), pmt_from_long(0))); + + d_rx->send(s_cmd_allocate_channel, + pmt_list2(pmt_list2(s_response_allocate_channel,PMT_T), + pmt_from_long(1))); + + d_rx->send(s_cmd_start_recv_raw_samples, + 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))); + +} + + +void +qa_rx_top::handle_message(mb_message_sptr msg) +{ + pmt_t data = msg->data(); + pmt_t event = msg->signal(); + + if(pmt_eq(event, pmt_intern("%shutdown"))) + return; + + pmt_t expected = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); + + // 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(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; + } + return; + } + + pmt_t e_event = pmt_nth(0, expected); + pmt_t e_status = pmt_nth(1, expected); + + if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) { + if(verbose) + std::cout << "Got: " << status << " Expected: " << e_status << "\n"; + shutdown_all(PMT_F); + return; + } else { + if(verbose) + std::cout << "[qa_rx_top] Received expected response for message " + << d_nmsg_recvd + << " (" << event << ")\n"; + } + + if (pmt_eq(msg->port_id(), d_rx->port_symbol())) { + + if(pmt_eq(msg->signal(), s_response_allocate_channel)) + check_allocation(msg); + + } + + // We stop when we get a close, we are successful if we + // got a response from recv, fail if we never got a recv response + if(pmt_eq(msg->signal(), s_response_close)) { - std::cout << "[qa_dealloc_top] Allocated TX channels: "; - for(int i=0; i < (int)d_tx_chans.size(); i++) - std::cout << d_tx_chans[i] << " "; + if(d_got_response_recv) { + shutdown_all(PMT_T); + return; + } + else { + shutdown_all(PMT_F); + if(verbose) + std::cout << "[qa_rx_top] No response message before close\n"; + return; + } + + } + + + d_nmsg_recvd++; + +} - std::cout << "\n[qa_dealloc_top] Allocated RX channels: "; - for(int i=0; i < (int)d_rx_chans.size(); i++) - std::cout << d_rx_chans[i] << " "; - std::cout << "\n"; - deallocate_all(); // once we've allocated all of our channels, try to dealloc them +void +qa_rx_top::check_allocation(mb_message_sptr msg) +{ + pmt_t data = msg->data(); + pmt_t event = msg->signal(); + + pmt_t expected = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); + pmt_t channel = pmt_nth(2, data); + + if(pmt_eqv(status, PMT_T)) { + // store all of the allocate channel numbers + if(pmt_eq(msg->port_id(), d_rx->port_symbol())) + d_rx_chan = pmt_to_long(channel); } } -REGISTER_MBLOCK_CLASS(qa_dealloc_top); +REGISTER_MBLOCK_CLASS(qa_rx_top); + + +// ---------------------------------------------------------------------------------------------- + +class qa_cs_top : public mb_mblock +{ + mb_port_sptr d_tx; + mb_port_sptr d_rx; + mb_port_sptr d_cs; + + long d_nmsgs_to_recv; + long d_nrecvd; + + long d_max_capacity; + long d_ntx_chan, d_nrx_chan; + + long d_nstatus; + long d_nstatus_to_recv; + + public: + qa_cs_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~qa_cs_top(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void check_message(mb_message_sptr msg); + void run_tests(); +}; + +qa_cs_top::qa_cs_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg) +{ + d_nrecvd=0; + d_nmsgs_to_recv = 8; + d_nstatus=0; + d_nstatus_to_recv = 50; + + 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_cs_top::~qa_cs_top(){} + +void +qa_cs_top::initial_transition() +{ + run_tests(); +} + +void +qa_cs_top::run_tests() +{ + if(verbose) + std::cout << "[qa_cs_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))); + + d_tx->send(s_cmd_to_control_channel, + pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T), + pmt_list1( + pmt_list2(s_op_ping_fixed, + pmt_list2(pmt_from_long(3), + pmt_from_long(0)))))); + + d_tx->send(s_cmd_to_control_channel, + pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T), + pmt_list1( + pmt_list2(s_op_write_reg, + pmt_list2( + pmt_from_long(0x3), + pmt_from_long(0x4)))))); + + d_tx->send(s_cmd_to_control_channel, + pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T), + pmt_list1( + pmt_list2(s_op_write_reg_masked, + pmt_list3( + pmt_from_long(0x3), + pmt_from_long(0x4), + pmt_from_long(0x5)))))); + + d_tx->send(s_cmd_to_control_channel, + pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T), + pmt_list1( + pmt_list2(s_op_read_reg, + pmt_list2(pmt_from_long(0), + pmt_from_long(0x6)))))); + + d_tx->send(s_cmd_to_control_channel, + pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T), + pmt_list1( + pmt_list2(s_op_delay, + pmt_list1(pmt_from_long(0x7)))))); + + pmt_t subpackets = pmt_list5( + pmt_list2(s_op_ping_fixed, pmt_list2(pmt_from_long(0), pmt_from_long(0))), + pmt_list2(s_op_delay, pmt_list1(pmt_from_long(0x7))), + pmt_list2(s_op_write_reg_masked, pmt_list3(pmt_from_long(3), + pmt_from_long(4), + pmt_from_long(5))), + pmt_list2(s_op_write_reg, pmt_list2(pmt_from_long(3), + pmt_from_long(4))), + pmt_list2(s_op_read_reg, pmt_list2(pmt_from_long(0), + pmt_from_long(6))) + ); + + d_tx->send(s_cmd_to_control_channel, + pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T), + subpackets)); + + pmt_t i2c_data = pmt_make_u8vector(8, 0xff); + + subpackets = pmt_list2( + pmt_list2(s_op_i2c_write, + pmt_list2(pmt_from_long(8), i2c_data)), + pmt_list2(s_op_i2c_read, + pmt_list3(pmt_from_long(0), pmt_from_long(9), pmt_from_long(1))) + + ); + + d_tx->send(s_cmd_to_control_channel, + pmt_list2(pmt_list2(s_response_from_control_channel, PMT_T), + subpackets)); + +} + +void +qa_cs_top::handle_message(mb_message_sptr msg) +{ + pmt_t data = msg->data(); + + if ((pmt_eq(msg->port_id(), d_tx->port_symbol()) + || pmt_eq(msg->port_id(), d_rx->port_symbol())) + && pmt_eq(msg->signal(), s_response_allocate_channel)) + check_message(msg); + + if (pmt_eq(msg->port_id(), d_tx->port_symbol()) + && pmt_eq(msg->signal(), s_response_from_control_channel)) + check_message(msg); + + if (pmt_eq(msg->port_id(), d_cs->port_symbol())) { + + if(pmt_eq(msg->signal(), s_response_max_capacity)) { + d_max_capacity = pmt_to_long(pmt_nth(2, data)); + if(verbose) + std::cout << "[qa_cs_top] USRP has max capacity of " + << d_max_capacity << "\n"; + } + else if(pmt_eq(msg->signal(), s_response_ntx_chan)) { + d_ntx_chan = pmt_to_long(pmt_nth(2, data)); + if(verbose) + std::cout << "[qa_cs_top] USRP tx channels: " + << d_ntx_chan << "\n"; + } + else if(pmt_eq(msg->signal(), s_response_nrx_chan)) { + d_nrx_chan = pmt_to_long(pmt_nth(2, data)); + if(verbose) + std::cout << "[qa_cs_top] USRP rx channels: " + << d_nrx_chan << "\n"; + } + else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) { + check_message(msg); + } + + d_nstatus++; + + check_message(msg); + + if(d_nstatus==d_nstatus_to_recv) + run_tests(); + } +} + +void +qa_cs_top::check_message(mb_message_sptr msg) +{ + pmt_t data = msg->data(); + pmt_t event = msg->signal(); + + pmt_t expected = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); + + pmt_t e_event = pmt_nth(0, expected); + pmt_t e_status = pmt_nth(1, expected); + + d_nrecvd++; + + + if(!pmt_eqv(e_status, status) || !pmt_eqv(e_event, event)) { + if(verbose) + std::cout << "[qa_cs_top] Got: " << status << " Expected: " << e_status << "\n"; + shutdown_all(PMT_F); + return; + } else { + if(verbose) + std::cout << "[qa_cs_top] Received expected response for message " + << d_nrecvd << " (" << event << ")\n"; + } + + if(d_nrecvd == d_nmsgs_to_recv) + shutdown_all(PMT_T); +} + +REGISTER_MBLOCK_CLASS(qa_cs_top); // ---------------------------------------------------------------------------------------------- void +qa_inband_usrp_server::test_open_close() +{ + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_T; + + // std::cout << "\n\n----------------------------\n"; + // std::cout << " RUNNING OPEN/CLOSE TESTS \n"; + + rt->run("top", "qa_open_close_top", PMT_F, &result); + + CPPUNIT_ASSERT(pmt_equal(PMT_T, result)); +} + +void qa_inband_usrp_server::test_chan_allocation() { mb_runtime_sptr rt = mb_make_runtime(); pmt_t result = PMT_T; - rt->run("top", "qa_alloc_top", PMT_F, &result); + // std::cout << "\n\n----------------------------\n"; + // std::cout << " RUNNING ALLOCATION TESTS \n"; + + rt->run("qa_alloc_top", "qa_alloc_top", PMT_F, &result); CPPUNIT_ASSERT(pmt_equal(PMT_T, result)); } @@ -443,13 +1349,52 @@ qa_inband_usrp_server::test_chan_deallocation() mb_runtime_sptr rt = mb_make_runtime(); pmt_t result = PMT_T; - rt->run("top", "qa_dealloc_top", PMT_F, &result); + // std::cout << "\n\n----------------------------\n"; + // std::cout << " RUNNING DEALLOCATION TESTS \n"; + + rt->run("qa_dealloc_top", "qa_dealloc_top", PMT_F, &result); + + CPPUNIT_ASSERT(pmt_equal(PMT_T, result)); +} + +void +qa_inband_usrp_server::test_tx() +{ + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_T; + + // std::cout << "\n\n-----------------\n"; + // std::cout << " RUNNING TX TESTS \n"; + + rt->run("top", "qa_tx_top", PMT_F, &result); + + CPPUNIT_ASSERT(pmt_equal(PMT_T, result)); +} + +void +qa_inband_usrp_server::test_rx() +{ + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_T; + + // std::cout << "\n\n-----------------\n"; + // std::cout << " RUNNING RX TESTS \n"; + + rt->run("top", "qa_rx_top", PMT_F, &result); CPPUNIT_ASSERT(pmt_equal(PMT_T, result)); } void -qa_inband_usrp_server::test_fragmentation() +qa_inband_usrp_server::test_cs() { + mb_runtime_sptr rt = mb_make_runtime(); + pmt_t result = PMT_T; + + // std::cout << "\n\n-----------------\n"; + // std::cout << " RUNNING CS TESTS \n"; + + rt->run("top", "qa_cs_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 91cf7d87c..5db57c3ed 100644 --- a/usrp/host/lib/inband/qa_inband_usrp_server.h +++ b/usrp/host/lib/inband/qa_inband_usrp_server.h @@ -28,15 +28,21 @@ class qa_inband_usrp_server : public CppUnit::TestCase { CPPUNIT_TEST_SUITE(qa_inband_usrp_server); + CPPUNIT_TEST(test_open_close); CPPUNIT_TEST(test_chan_allocation); CPPUNIT_TEST(test_chan_deallocation); - CPPUNIT_TEST(test_fragmentation); + CPPUNIT_TEST(test_tx); + CPPUNIT_TEST(test_rx); + CPPUNIT_TEST(test_cs); CPPUNIT_TEST_SUITE_END(); private: void test_chan_allocation(); void test_chan_deallocation(); - void test_fragmentation(); + void test_open_close(); + void test_tx(); + void test_rx(); + void test_cs(); }; #endif /* INCLUDED_QA_INBAND_USRP_SERVER_H */ diff --git a/usrp/host/lib/inband/symbols_usrp_channel.h b/usrp/host/lib/inband/symbols_usrp_channel.h new file mode 100644 index 000000000..a0114cf3c --- /dev/null +++ b/usrp/host/lib/inband/symbols_usrp_channel.h @@ -0,0 +1,40 @@ +/* -*- 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_SYMBOLS_USRP_CHANNEL_H +#define INCLUDED_SYMBOLS_USRP_CHANNEL_H + +#include <pmt.h> + +// Outgoing +static pmt_t s_cmd_allocate_channel = pmt_intern("cmd-allocate-channel"); +static pmt_t s_cmd_deallocate_channel = pmt_intern("cmd-deallocate-channel"); + +// Incoming +static pmt_t s_response_allocate_channel = pmt_intern("response-allocate-channel"); +static pmt_t s_response_deallocate_channel = pmt_intern("response-deallocate-channel"); + +// Errors +static pmt_t s_err_requested_capacity_unavailable = pmt_intern("err-requested-capacity-unavailable"); +static pmt_t s_err_channel_unavailable = pmt_intern("err-channel-unavailable"); +static pmt_t s_err_channel_invalid = pmt_intern("err-channel-invalid"); +static pmt_t s_err_channel_permission_denied = pmt_intern("err-channel-permission-denied"); + +#endif /* INCLUDED_SYMBOLS_USRP_CHANNEL_H */ diff --git a/usrp/host/lib/inband/symbols_usrp_interface_cs.h b/usrp/host/lib/inband/symbols_usrp_interface_cs.h new file mode 100644 index 000000000..72c8fcc91 --- /dev/null +++ b/usrp/host/lib/inband/symbols_usrp_interface_cs.h @@ -0,0 +1,43 @@ +/* -*- 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_SYMBOLS_USRP_INTERFACE_CS_H +#define INCLUDED_SYMBOLS_USRP_INTERFACE_CS_H + +#include <pmt.h> + +// Outgoing +static pmt_t s_cmd_usrp_open = pmt_intern("cmd-usrp-open"); +static pmt_t s_cmd_usrp_close = pmt_intern("cmd-usrp-close"); +static pmt_t s_cmd_usrp_ntx_chan = pmt_intern("cmd-usrp-ntx-chan"); +static pmt_t s_cmd_usrp_nrx_chan = pmt_intern("cmd-usrp-nrx-chan"); +static pmt_t s_cmd_usrp_write = pmt_intern("cmd-usrp-write"); +static pmt_t s_cmd_usrp_start_reading = pmt_intern("cmd-usrp-start-reading"); +static pmt_t s_cmd_usrp_stop_reading = pmt_intern("cmd-usrp-stop-reading"); + +// Incoming +static pmt_t s_response_usrp_open = pmt_intern("response-usrp-open"); +static pmt_t s_response_usrp_close = pmt_intern("response-usrp-close"); +static pmt_t s_response_usrp_ntx_chan = pmt_intern("response-usrp-ntx-chan"); +static pmt_t s_response_usrp_nrx_chan = pmt_intern("response-usrp-nrx-chan"); +static pmt_t s_response_usrp_write = pmt_intern("response-usrp-write"); +static pmt_t s_response_usrp_read = pmt_intern("response-usrp-read"); + +#endif /* INCLUDED_SYMBOLS_USRP_INTERFACE_CS_H */ diff --git a/usrp/host/lib/inband/symbols_usrp_low_level_cs.h b/usrp/host/lib/inband/symbols_usrp_low_level_cs.h new file mode 100644 index 000000000..a7260603a --- /dev/null +++ b/usrp/host/lib/inband/symbols_usrp_low_level_cs.h @@ -0,0 +1,47 @@ +/* -*- 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_SYMBOLS_USRP_LOW_LEVEL_CS_H +#define INCLUDED_SYMBOLS_USRP_LOW_LEVEL_CS_H + +#include <pmt.h> + +// Outgoing +static pmt_t s_cmd_to_control_channel = pmt_intern("cmd-to-control-channel"); + +// Incoming +static pmt_t s_response_from_control_channel = pmt_intern("response-from-control-channel"); + +// Subpackets +static pmt_t s_op_ping_fixed = pmt_intern("op-ping-fixed"); +static pmt_t s_op_ping_fixed_reply = pmt_intern("op-ping-fixed-reply"); +static pmt_t s_op_write_reg = pmt_intern("op-write-reg"); +static pmt_t s_op_write_reg_masked = pmt_intern("op-write-reg-masked"); +static pmt_t s_op_read_reg = pmt_intern("op-read-reg"); +static pmt_t s_op_read_reg_reply = pmt_intern("op-read-reg-reply"); +static pmt_t s_op_i2c_write = pmt_intern("op-i2c-write"); +static pmt_t s_op_i2c_read = pmt_intern("op-i2c-read"); +static pmt_t s_op_i2c_read_reply = pmt_intern("op-i2c-read-reply"); +static pmt_t s_op_spi_write = pmt_intern("op-spi-write"); +static pmt_t s_op_spi_read = pmt_intern("op-spi-read"); +static pmt_t s_op_spi_read_reply = pmt_intern("op-spi-read-reply"); +static pmt_t s_op_delay = pmt_intern("op-delay"); + +#endif /* INCLUDED_SYMBOLS_USRP_LOW_LEVEL_CS_H */ diff --git a/usrp/host/lib/inband/symbols_usrp_rx.h b/usrp/host/lib/inband/symbols_usrp_rx.h new file mode 100644 index 000000000..07d58a3f5 --- /dev/null +++ b/usrp/host/lib/inband/symbols_usrp_rx.h @@ -0,0 +1,36 @@ +/* -*- 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_SYMBOLS_USRP_RX_H +#define INCLUDED_SYMBOLS_USRP_RX_H + +#include <pmt.h> + +// Outgoing +static pmt_t s_cmd_start_recv_raw_samples = pmt_intern("cmd-start-recv-raw-samples"); +static pmt_t s_cmd_stop_recv_raw_samples = pmt_intern("cmd-stop-recv-raw-samples"); + +// Incoming +static pmt_t s_response_recv_raw_samples = pmt_intern("response-recv-raw-samples"); + +// Errors +static pmt_t s_err_already_receiving = pmt_intern("err-already-receiving"); + +#endif /* INCLUDED_SYMBOLS_USRP_RX_H */ diff --git a/usrp/host/lib/inband/symbols_usrp_rx_cs.h b/usrp/host/lib/inband/symbols_usrp_rx_cs.h new file mode 100644 index 000000000..bf4f0338b --- /dev/null +++ b/usrp/host/lib/inband/symbols_usrp_rx_cs.h @@ -0,0 +1,32 @@ +/* -*- 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_SYMBOLS_USRP_RX_CS_H +#define INCLUDED_SYMBOLS_USRP_RX_CS_H + +#include <pmt.h> + +// Outgoing +static pmt_t s_cmd_usrp_rx_start_reading = pmt_intern("cmd-usrp-rx-start-reading"); + +// Incoming +static pmt_t s_response_usrp_rx_read = pmt_intern("response-usrp-rx-read"); + +#endif /* INCLUDED_SYMBOLS_USRP_RX_CS_H */ diff --git a/usrp/host/lib/inband/symbols_usrp_server_cs.h b/usrp/host/lib/inband/symbols_usrp_server_cs.h new file mode 100644 index 000000000..e612e24ea --- /dev/null +++ b/usrp/host/lib/inband/symbols_usrp_server_cs.h @@ -0,0 +1,47 @@ +/* -*- 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_SYMBOLS_USRP_SERVER_CS_H +#define INCLUDED_SYMBOLS_USRP_SERVER_CS_H + +#include <pmt.h> + +// Outgoing +static pmt_t s_cmd_open = pmt_intern("cmd-open"); +static pmt_t s_cmd_close = pmt_intern("cmd-close"); +static pmt_t s_cmd_max_capacity = pmt_intern("cmd-max-capacity"); +static pmt_t s_cmd_ntx_chan = pmt_intern("cmd-ntx-chan"); +static pmt_t s_cmd_nrx_chan = pmt_intern("cmd-nrx-chan"); +static pmt_t s_cmd_current_capacity_allocation = pmt_intern("cmd-current-capacity-allocation"); + +// Incoming +static pmt_t s_response_open = pmt_intern("response-open"); +static pmt_t s_response_close = pmt_intern("response-close"); +static pmt_t s_response_max_capacity = pmt_intern("response-max-capacity"); +static pmt_t s_response_ntx_chan = pmt_intern("response-ntx-chan"); +static pmt_t s_response_nrx_chan = pmt_intern("response-nrx-chan"); +static pmt_t s_response_current_capacity_allocation = pmt_intern("response-current-capacity-allocation"); + +// Errors +static pmt_t s_err_usrp_not_opened = pmt_intern("err-usrp-not-opened"); +static pmt_t s_err_usrp_already_opened = pmt_intern("err-usrp-already-opened"); +static pmt_t s_err_usrp_already_closed = pmt_intern("err-usrp-already-closed"); + +#endif /* INCLUDED_SYMBOLS_USRP_SERVER_CS_H */ diff --git a/usrp/host/lib/inband/symbols_usrp_tx.h b/usrp/host/lib/inband/symbols_usrp_tx.h new file mode 100644 index 000000000..4e58e2cf9 --- /dev/null +++ b/usrp/host/lib/inband/symbols_usrp_tx.h @@ -0,0 +1,32 @@ +/* -*- 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_SYMBOLS_USRP_TX_H +#define INCLUDED_SYMBOLS_USRP_TX_H + +#include <pmt.h> + +// Outgoing +static pmt_t s_cmd_xmit_raw_frame = pmt_intern("cmd-xmit-raw-frame"); + +// Incoming +static pmt_t s_response_xmit_raw_frame = pmt_intern("response-xmit-raw-frame"); + +#endif /* INCLUDED_SYMBOLS_USRP_TX_H */ diff --git a/usrp/host/lib/inband/symbols_usrp_tx_cs.h b/usrp/host/lib/inband/symbols_usrp_tx_cs.h new file mode 100644 index 000000000..d02ef1d26 --- /dev/null +++ b/usrp/host/lib/inband/symbols_usrp_tx_cs.h @@ -0,0 +1,32 @@ +/* -*- 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_SYMBOLS_USRP_TX_CS_H +#define INCLUDED_SYMBOLS_USRP_TX_CS_H + +#include <pmt.h> + +// Outgoing +static pmt_t s_cmd_usrp_tx_write = pmt_intern("cmd-usrp-tx-write"); + +// Incoming +static pmt_t s_response_usrp_tx_write = pmt_intern("response-usrp-tx-write"); + +#endif /* INCLUDED_SYMBOLS_USRP_TX_CS_H */ diff --git a/usrp/host/lib/inband/test_usrp_inband.cc b/usrp/host/lib/inband/test_usrp_inband.cc new file mode 100644 index 000000000..dd8d46f84 --- /dev/null +++ b/usrp/host/lib/inband/test_usrp_inband.cc @@ -0,0 +1,297 @@ +/* -*- 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 <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 new file mode 100644 index 000000000..b8befa493 --- /dev/null +++ b/usrp/host/lib/inband/usrp_inband_usb_packet.cc @@ -0,0 +1,749 @@ +/* -*- 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 <usrp_inband_usb_packet.h> + +#include <usrp_bytesex.h> +#include <iostream> +#include <stdio.h> + +bool usrp_inband_usb_packet::align32() +{ + int p_len = payload_len(); + + int bytes_needed = 4 - (p_len % 4); + + if(bytes_needed == 4) + return true; + + // If the room left in the packet is less than the number of bytes + // needed, return false to indicate no room to align + 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); + + return true; +} + +bool usrp_inband_usb_packet::cs_ping(long rid, long ping_val) +{ + if(!align32()) + return false; + + int p_len = payload_len(); + + if((MAX_PAYLOAD - p_len) < (CS_PING_LEN + CS_FIXED_LEN)) + return false; + + uint32_t ping = ( + ((OP_PING_FIXED & CS_OPCODE_MASK) << CS_OPCODE_SHIFT) + | ((CS_PING_LEN & CS_LEN_MASK) << CS_LEN_SHIFT) + | ((rid & CS_RID_MASK) << CS_RID_SHIFT) + | (ping_val & CS_PINGVAL_MASK) + + ); + + uint32_t *payload = (uint32_t *) (d_payload + p_len); + *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); + + return true; +} + + +bool usrp_inband_usb_packet::cs_ping_reply(long rid, long ping_val) +{ + if(!align32()) + return false; + + int p_len = payload_len(); + + if((MAX_PAYLOAD - p_len) < (CS_PING_LEN + CS_FIXED_LEN)) + return false; + + uint32_t ping = ( + ((OP_PING_FIXED_REPLY & CS_OPCODE_MASK) << CS_OPCODE_SHIFT) + | ((CS_PING_LEN & CS_LEN_MASK) << CS_LEN_SHIFT) + | ((rid & CS_RID_MASK) << CS_RID_SHIFT) + | ((ping_val & CS_PINGVAL_MASK) << CS_PINGVAL_SHIFT) + + ); + + uint32_t *payload = (uint32_t *) (d_payload + p_len); + *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); + + return true; +} + +bool usrp_inband_usb_packet::cs_write_reg(long reg_num, long val) +{ + if(!align32()) + return false; + + int p_len = payload_len(); + + if((MAX_PAYLOAD - p_len) < (CS_WRITEREG_LEN + CS_FIXED_LEN)) + return false; + + uint32_t word0 = 0; + + // Build the first word which includes the register number + word0 = ( + ((OP_WRITE_REG & CS_OPCODE_MASK) << CS_OPCODE_SHIFT) + | ((CS_WRITEREG_LEN & CS_LEN_MASK) << CS_LEN_SHIFT) + | ((reg_num & CS_REGNUM_MASK) << CS_REGNUM_SHIFT) + ); + + uint32_t *payload = (uint32_t *) (d_payload + p_len); + *payload = host_to_usrp_u32(word0); + + // The second word is solely the register value to be written + // FIXME: should this be unsigned? + payload += 1; + *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); + + return true; +} + +bool usrp_inband_usb_packet::cs_write_reg_masked(long reg_num, long val, long mask) +{ + if(!align32()) + return false; + + int p_len = payload_len(); + + if((MAX_PAYLOAD - p_len) < (CS_WRITEREGMASKED_LEN + CS_FIXED_LEN)) + return false; + + uint32_t word0 = 0; + + // Build the first word which includes the register number + word0 = ( + ((OP_WRITE_REG_MASKED & CS_OPCODE_MASK) << CS_OPCODE_SHIFT) + | ((CS_WRITEREGMASKED_LEN & CS_LEN_MASK) << CS_LEN_SHIFT) + | ((reg_num & CS_REGNUM_MASK) << CS_REGNUM_SHIFT) + ); + + uint32_t *payload = (uint32_t *) (d_payload + p_len); + *payload = host_to_usrp_u32(word0); + + // Skip over the first word and write the register value + payload += 1; + *payload = host_to_usrp_u32((uint32_t) val); + + // Skip over the register value and write the mask + payload += 1; + *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); + + return true; +} + +bool usrp_inband_usb_packet::cs_read_reg(long rid, long reg_num) +{ + if(!align32()) + return false; + + int p_len = payload_len(); + + if((MAX_PAYLOAD - p_len) < (CS_READREG_LEN + CS_FIXED_LEN)) + return false; + + uint32_t read_reg = ( + ((OP_READ_REG & CS_OPCODE_MASK) << CS_OPCODE_SHIFT) + | ((CS_READREG_LEN & CS_LEN_MASK) << CS_LEN_SHIFT) + | ((rid & CS_RID_MASK) << CS_RID_SHIFT) + | ((reg_num & CS_REGNUM_MASK) << CS_REGNUM_SHIFT) + + ); + + uint32_t *payload = (uint32_t *) (d_payload + p_len); + *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); + + return true; +} + +bool usrp_inband_usb_packet::cs_read_reg_reply(long rid, long reg_num, long reg_val) +{ + if(!align32()) + return false; + + int p_len = payload_len(); + + if((MAX_PAYLOAD - p_len) < (CS_READREGREPLY_LEN + CS_FIXED_LEN)) + return false; + + uint32_t word0 = ( + ((OP_READ_REG_REPLY & CS_OPCODE_MASK) << CS_OPCODE_SHIFT) + | ((CS_READREGREPLY_LEN & CS_LEN_MASK) << CS_LEN_SHIFT) + | ((rid & CS_RID_MASK) << CS_RID_SHIFT) + | ((reg_num & CS_REGNUM_MASK) << CS_REGNUM_SHIFT) + + ); + + uint32_t *payload = (uint32_t *) (d_payload + p_len); + *payload = host_to_usrp_u32(word0); + + // Hop to the next word and write the reg value + payload += 1; + *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); + + return true; +} + +bool usrp_inband_usb_packet::cs_delay(long ticks) +{ + if(!align32()) + return false; + + int p_len = payload_len(); + + if((MAX_PAYLOAD - p_len) < (CS_DELAY_LEN + CS_FIXED_LEN)) + return false; + + uint32_t delay = ( + ((OP_DELAY & CS_OPCODE_MASK) << CS_OPCODE_SHIFT) + | ((CS_DELAY_LEN & CS_LEN_MASK) << CS_LEN_SHIFT) + | ((ticks & CS_DELAY_MASK) << CS_DELAY_SHIFT) + + ); + + uint32_t *payload = (uint32_t *) (d_payload + p_len); + *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); + + return true; +} + +bool usrp_inband_usb_packet::cs_i2c_write(long i2c_addr, uint8_t *i2c_data, size_t data_len) +{ + if(!align32()) + return false; + + int p_len = payload_len(); + + int i2c_len = data_len + 2; // 2 bytes between mbz and addr + + if((MAX_PAYLOAD - p_len) < (i2c_len + CS_FIXED_LEN)) + return false; + + uint32_t word0 = 0; + + word0 = ( + ((OP_I2C_WRITE & CS_OPCODE_MASK) << CS_OPCODE_SHIFT) + | ((i2c_len & CS_LEN_MASK) << CS_LEN_SHIFT) + | ((i2c_addr & CS_I2CADDR_MASK) << CS_I2CADDR_SHIFT) + ); + + uint32_t *payload = (uint32_t *) (d_payload + p_len); + *payload = host_to_usrp_u32(word0); + + // Jump over the first word and write the data + // FIXME: Should the data be changed to usrp byte order? + payload += 1; + 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); + + return true; +} + +bool usrp_inband_usb_packet::cs_i2c_read(long rid, long i2c_addr, long n_bytes) +{ + if(!align32()) + return false; + + int p_len = payload_len(); + + if((MAX_PAYLOAD - p_len) < (CS_I2CREAD_LEN + CS_FIXED_LEN)) + return false; + + uint32_t word0 = 0; + + word0 = ( + ((OP_I2C_READ & CS_OPCODE_MASK) << CS_OPCODE_SHIFT) + | ((CS_I2CREAD_LEN & CS_LEN_MASK) << CS_LEN_SHIFT) + | ((rid & CS_RID_MASK) << CS_RID_SHIFT) + | ((i2c_addr & CS_I2CADDR_MASK) << CS_I2CADDR_SHIFT) + ); + + uint32_t *payload = (uint32_t *) (d_payload + p_len); + *payload = host_to_usrp_u32(word0); + + // Jump a word and write the number of bytes to read + payload += 1; + uint32_t word1 = + (n_bytes & CS_I2CREADBYTES_MASK) << CS_I2CREADBYTES_SHIFT; + *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); + + return true; +} + +bool usrp_inband_usb_packet::cs_i2c_read_reply(long rid, long i2c_addr, uint8_t *i2c_data, long i2c_data_len) +{ + if(!align32()) + return false; + + int p_len = payload_len(); + + int i2c_len = i2c_data_len + 2; + + if((MAX_PAYLOAD - p_len) < (i2c_len + CS_FIXED_LEN)) + return false; + + uint32_t word0 = 0; + + word0 = ( + ((OP_I2C_READ_REPLY & CS_OPCODE_MASK) << CS_OPCODE_SHIFT) + | ((i2c_len & CS_LEN_MASK) << CS_LEN_SHIFT) + | ((rid & CS_RID_MASK) << CS_RID_SHIFT) + | ((i2c_addr & CS_I2CADDR_MASK) << CS_I2CADDR_SHIFT) + ); + + uint32_t *payload = (uint32_t *) (d_payload + p_len); + *payload = host_to_usrp_u32(word0); + + // Jump a word and write the actual data + payload += 1; + 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); + + return true; +} + +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()) + return false; + + int p_len = payload_len(); + + int spi_len = spi_data_len + 6; + + if((MAX_PAYLOAD - p_len) < (spi_len + CS_FIXED_LEN)) + return false; + + uint32_t word = 0; + + // First word contains the opcode and length, then mbz + word = ( + ((OP_SPI_WRITE & CS_OPCODE_MASK) << CS_OPCODE_SHIFT) + | ((spi_len & CS_LEN_MASK) << CS_LEN_SHIFT) + ); + uint32_t *payload = (uint32_t *) (d_payload + p_len); + *payload = host_to_usrp_u32(word); + + payload += 1; + + // Second word contains the enables, format, and optional tx bytes + word = 0; + word = ( + ((enables & CS_SPIENABLES_MASK) << CS_SPIENABLES_SHIFT) + | ((format & CS_SPIFORMAT_MASK) << CS_SPIFORMAT_SHIFT) + | ((opt_header_bytes & CS_SPIOPT_MASK) << CS_SPIOPT_SHIFT) + ); + payload = (uint32_t *) (d_payload + p_len); + *payload = host_to_usrp_u32(word); + + payload += 1; + 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); + + return true; +} + +bool usrp_inband_usb_packet::cs_spi_read(long rid, long enables, long format, long opt_header_bytes, long n_bytes) +{ + if(!align32()) + return false; + + int p_len = payload_len(); + + if((MAX_PAYLOAD - p_len) < (CS_SPIREAD_LEN + CS_FIXED_LEN)) + return false; + + uint32_t word = 0; + + // First word contains the opcode, length, and RID + word = ( + ((OP_SPI_READ & CS_OPCODE_MASK) << CS_OPCODE_SHIFT) + | ((CS_SPIREAD_LEN & CS_LEN_MASK) << CS_LEN_SHIFT) + | ((rid & CS_RID_MASK) << CS_RID_SHIFT) + ); + uint32_t *payload = (uint32_t *) (d_payload + p_len); + *payload = host_to_usrp_u32(word); + + payload += 1; + + // Second word contains the enables, format, and optional tx bytes + word = 0; + word = ( + ((enables & CS_SPIENABLES_MASK) << CS_SPIENABLES_SHIFT) + | ((format & CS_SPIFORMAT_MASK) << CS_SPIFORMAT_SHIFT) + | ((opt_header_bytes & CS_SPIOPT_MASK) << CS_SPIOPT_SHIFT) + ); + payload = (uint32_t *) (d_payload + p_len); + *payload = host_to_usrp_u32(word); + + payload += 1; + + // The third word contains the number of bytes + word = 0; + word = ( + ((n_bytes & CS_SPINBYTES_MASK) << CS_SPINBYTES_SHIFT) + ); + payload = (uint32_t *) (d_payload + p_len); + *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; + + set_header(h_flags, h_chan, h_tag, h_payload_len); + + return true; +} + +bool usrp_inband_usb_packet::cs_spi_read_reply(long rid, uint8_t *spi_data, long spi_data_len) +{ + if(!align32()) + return false; + + int p_len = payload_len(); + + int spi_len = spi_data_len + 2; + + if((MAX_PAYLOAD - p_len) < (spi_len + CS_FIXED_LEN)) + return false; + + uint32_t word = 0; + + // First word contains the opcode, length, and RID + word = ( + ((OP_SPI_READ_REPLY & CS_OPCODE_MASK) << CS_OPCODE_SHIFT) + | ((spi_len & CS_LEN_MASK) << CS_LEN_SHIFT) + | ((rid & CS_RID_MASK) << CS_RID_SHIFT) + ); + uint32_t *payload = (uint32_t *) (d_payload + p_len); + *payload = host_to_usrp_u32(word); + + // Jump a word and write the actual data + payload += 1; + 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); + + return true; +} + +// Takes an offset to the beginning of a subpacket and extracts 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. +pmt_t usrp_inband_usb_packet::read_subpacket(int payload_offset) { + + uint32_t subpkt = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset))); + uint32_t opcode = (subpkt >> CS_OPCODE_SHIFT) & CS_OPCODE_MASK; + uint32_t len = (subpkt >> CS_LEN_SHIFT) & CS_LEN_MASK; + + switch(opcode) { + + case OP_PING_FIXED_REPLY: + { + pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK); + pmt_t pingval = pmt_from_long((subpkt >> CS_PINGVAL_SHIFT) & CS_PINGVAL_MASK); + return pmt_list3(s_op_ping_fixed_reply, rid, pingval); + } + + case OP_READ_REG_REPLY: + { + pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK); + pmt_t reg_num = pmt_from_long((subpkt >> CS_REGNUM_SHIFT) & CS_REGNUM_MASK); + + // To get the register value we just read the next 32 bits + uint32_t val = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4))); + pmt_t reg_val = pmt_from_long(val); + + return pmt_list4(s_op_read_reg_reply, rid, reg_num, reg_val); + } + + case OP_I2C_READ_REPLY: + { + pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK); + pmt_t i2c_addr = pmt_from_long((subpkt >> CS_I2CADDR_SHIFT) & CS_I2CADDR_MASK); + + // Make a u8 vector to dump the data from the packet into + size_t i2c_data_len; + pmt_t i2c_data = pmt_make_u8vector(len - 2, 0); // skip rid+mbz+addr = 2 bytes + uint8_t *w_data = + (uint8_t *) pmt_u8vector_writeable_elements(i2c_data, i2c_data_len); + + memcpy(w_data, d_payload + payload_offset + 4, i2c_data_len); // skip first word + + return pmt_list4(s_op_i2c_read_reply, rid, i2c_addr, i2c_data); + } + + case OP_SPI_READ_REPLY: + { + pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK); + + // Make a u8 vector to dump the data from the packet into + size_t spi_data_len; + pmt_t spi_data = pmt_make_u8vector(len - 2, 0); // skip rid+mbz+addr = 2 bytes + uint8_t *w_data = + (uint8_t *) pmt_u8vector_writeable_elements(spi_data, spi_data_len); + + memcpy(w_data, d_payload + payload_offset + 4, spi_data_len); // skip first word + + return pmt_list3(s_op_spi_read_reply, rid, spi_data); + } + + case OP_PING_FIXED: + { + pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK); + pmt_t pingval = pmt_from_long((subpkt >> CS_PINGVAL_SHIFT) & CS_PINGVAL_MASK); + return pmt_list3(s_op_ping_fixed, rid, pingval); + } + + case OP_WRITE_REG: + { + pmt_t reg_num = pmt_from_long((subpkt >> CS_REGNUM_SHIFT) & CS_REGNUM_MASK); + + // To get the register value we just read the next 32 bits + uint32_t val = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4))); + pmt_t reg_val = pmt_from_long(val); + + return pmt_list3(s_op_write_reg, reg_num, reg_val); + } + + case OP_WRITE_REG_MASKED: + { + pmt_t reg_num = pmt_from_long((subpkt >> CS_REGNUM_SHIFT) & CS_REGNUM_MASK); + + // To get the register value we just read the next 32 bits + uint32_t val = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4))); + pmt_t reg_val = pmt_from_long(val); + + // The mask is the next 32 bits + uint32_t mask = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 8))); + pmt_t reg_mask = pmt_from_long(mask); + + return pmt_list4(s_op_write_reg_masked, reg_num, reg_val, reg_mask); + } + + case OP_READ_REG: + { + pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK); + pmt_t reg_num = pmt_from_long((subpkt >> CS_REGNUM_SHIFT) & CS_REGNUM_MASK); + + return pmt_list3(s_op_read_reg, rid, reg_num); + } + + case OP_I2C_WRITE: + { + pmt_t i2c_addr = pmt_from_long((subpkt >> CS_I2CADDR_SHIFT) & CS_I2CADDR_MASK); + + // The length includes an extra 2 bytes for storing the mbz and addr + pmt_t i2c_data = pmt_make_u8vector(len-2, 0); + + // Get a writeable address to copy the data from the packet + size_t ignore; + uint8_t *w_data = (uint8_t *) pmt_u8vector_writeable_elements(i2c_data, ignore); + memcpy(w_data, d_payload + payload_offset + 4, len-2); + + + return pmt_list3(s_op_i2c_write, i2c_addr, i2c_data); + } + + case OP_I2C_READ: + { + pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK); + pmt_t i2c_addr = pmt_from_long((subpkt >> CS_I2CADDR_SHIFT) & CS_I2CADDR_MASK); + + // The number of bytes is in the next word + uint32_t bytes = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4))); + bytes = (bytes >> CS_I2CREADBYTES_SHIFT) & CS_I2CREADBYTES_MASK; + pmt_t i2c_bytes = pmt_from_long(bytes); + + return pmt_list4(s_op_i2c_read, rid, i2c_addr, i2c_bytes); + } + + case OP_SPI_WRITE: + { + // Nothing interesting in the first word, skip to the next + uint32_t word = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4))); + pmt_t enables = pmt_from_long((word >> CS_SPIENABLES_SHIFT) & CS_SPIENABLES_MASK); + pmt_t format = pmt_from_long((word >> CS_SPIFORMAT_SHIFT) & CS_SPIFORMAT_MASK); + pmt_t opt = pmt_from_long((word >> CS_SPIOPT_SHIFT) & CS_SPIOPT_MASK); + + // From the next word and on is data + size_t spi_data_len; + pmt_t spi_data = pmt_make_u8vector(len - 6, 0); // skip rid+mbz+addr = 2 bytes + uint8_t *w_data = + (uint8_t *) pmt_u8vector_writeable_elements(spi_data, spi_data_len); + + memcpy(w_data, d_payload + payload_offset + 8, spi_data_len); // skip first 2 words + + return pmt_list5(s_op_spi_write, enables, format, opt, spi_data); + } + + case OP_SPI_READ: + { + // Read the RID from the first word, the rest is mbz + pmt_t rid = pmt_from_long((subpkt >> CS_RID_SHIFT) & CS_RID_MASK); + + // Continue at the next word... + uint32_t word = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 4))); + pmt_t enables = pmt_from_long((word >> CS_SPIENABLES_SHIFT) & CS_SPIENABLES_MASK); + pmt_t format = pmt_from_long((word >> CS_SPIFORMAT_SHIFT) & CS_SPIFORMAT_MASK); + pmt_t opt = pmt_from_long((word >> CS_SPIOPT_SHIFT) & CS_SPIOPT_MASK); + + // The number of bytes is the only thing to read in the next word + word = usrp_to_host_u32(*((uint32_t *)(d_payload + payload_offset + 8))); + pmt_t n_bytes = pmt_from_long((word >> CS_SPINBYTES_SHIFT) & CS_SPINBYTES_MASK); + + return pmt_list6(s_op_spi_read, rid, enables, format, opt, n_bytes); + } + + case OP_DELAY: + { + pmt_t ticks = pmt_from_long((subpkt >> CS_DELAY_SHIFT) & CS_DELAY_MASK); + + return pmt_list2(s_op_delay, ticks); + } + + default: + return PMT_NIL; + + } +} + diff --git a/usrp/host/lib/inband/usrp_inband_usb_packet.h b/usrp/host/lib/inband/usrp_inband_usb_packet.h index e22b567fa..9290f55ae 100644 --- a/usrp/host/lib/inband/usrp_inband_usb_packet.h +++ b/usrp/host/lib/inband/usrp_inband_usb_packet.h @@ -24,6 +24,10 @@ #include <usrp_bytesex.h> #include <mb_mblock.h> +#include <pmt.h> +#include <iostream> + +#include <symbols_usrp_low_level_cs.h> static const int USB_PKT_SIZE = 512; // bytes static const int MAX_PAYLOAD = USB_PKT_SIZE-2*sizeof(uint32_t); @@ -38,12 +42,28 @@ class usrp_inband_usb_packet { public: + enum opcodes { + OP_PING_FIXED = 0x00, + OP_PING_FIXED_REPLY = 0x01, + OP_WRITE_REG = 0x02, + OP_WRITE_REG_MASKED = 0x03, + OP_READ_REG = 0x04, + OP_READ_REG_REPLY = 0x05, + OP_I2C_WRITE = 0x06, + OP_I2C_READ = 0x07, + OP_I2C_READ_REPLY = 0x08, + OP_SPI_WRITE = 0x09, + OP_SPI_READ = 0x0a, + OP_SPI_READ_REPLY = 0x0b, + OP_DELAY = 0x0c + }; + enum flags { FL_OVERRUN = 0x80000000, FL_UNDERRUN = 0x40000000, FL_DROPPED = 0x20000000, - FL_END_OF_BURST = 0x10000000, - FL_START_OF_BURST = 0x08000000, + FL_START_OF_BURST = 0x10000000, + FL_END_OF_BURST = 0x08000000, FL_ALL_FLAGS = 0xf8000000 }; @@ -51,8 +71,8 @@ public: static const int FL_OVERRUN_SHIFT = 31; static const int FL_UNDERRUN_SHIFT = 30; static const int FL_DROPPED_SHIFT = 29; - static const int FL_END_OF_BURST_SHIFT = 28; - static const int FL_START_OF_BURST_SHIFT = 27; + static const int FL_END_OF_BURST_SHIFT = 27; + static const int FL_START_OF_BURST_SHIFT = 28; static const int RSSI_MASK = 0x3f; static const int RSSI_SHIFT = 21; @@ -66,6 +86,50 @@ public: static const int PAYLOAD_LEN_MASK = 0x1ff; static const int PAYLOAD_LEN_SHIFT = 0; + // Fixed size for opcode and length fields + static const int CS_FIXED_LEN = 2; + + static const int CS_OPCODE_MASK = 0xff; + static const int CS_OPCODE_SHIFT = 24; + + static const int CS_LEN_MASK = 0xff; + static const int CS_LEN_SHIFT = 16; + + static const int CS_RID_MASK = 0x3f; + static const int CS_RID_SHIFT = 10; + + static const int CS_PING_LEN = 2; + static const int CS_PINGVAL_MASK = 0x3ff; + static const int CS_PINGVAL_SHIFT = 0; + + static const int CS_WRITEREG_LEN = 6; + static const int CS_WRITEREGMASKED_LEN = 10; + static const int CS_READREG_LEN = 2; + static const int CS_READREGREPLY_LEN = 6; + static const int CS_REGNUM_MASK = 0x3ff; + static const int CS_REGNUM_SHIFT = 0; + + static const int CS_DELAY_LEN = 2; + static const int CS_DELAY_MASK = 0xffff; + static const int CS_DELAY_SHIFT = 0; + + static const int CS_I2CADDR_MASK = 0x7f; + static const int CS_I2CADDR_SHIFT = 0; + + static const int CS_I2CREAD_LEN = 3; + static const int CS_I2CREADBYTES_MASK = 0x7f; + static const int CS_I2CREADBYTES_SHIFT = 24; + + static const int CS_SPIOPT_MASK = 0xffff; + static const int CS_SPIOPT_SHIFT = 0; + static const int CS_SPIFORMAT_MASK = 0xff; + static const int CS_SPIFORMAT_SHIFT = 16; + static const int CS_SPIENABLES_MASK = 0xff; + static const int CS_SPIENABLES_SHIFT = 24; + static const int CS_SPIREAD_LEN = 7; + static const int CS_SPINBYTES_MASK = 0xff; + static const int CS_SPINBYTES_SHIFT = 24; + public: void set_timestamp(uint32_t timestamp){ @@ -77,7 +141,7 @@ public: word0 |= 1<<FL_END_OF_BURST_SHIFT; d_word0 = host_to_usrp_u32(word0); } - + void set_header(int flags, int chan, int tag, int payload_len){ uint32_t word0 = ((flags & FL_ALL_FLAGS) | ((chan & CHAN_MASK) << CHAN_SHIFT) @@ -144,6 +208,27 @@ public: return MAX_PAYLOAD; } + static int max_pkt_size() { + return USB_PKT_SIZE; + } + + // C/S methods + bool align32(); + bool cs_ping(long rid, long ping_val); + bool cs_ping_reply(long rid, long ping_val); + bool cs_write_reg(long reg_num, long val); + bool cs_write_reg_masked(long reg_num, long val, long mask); + bool cs_read_reg(long rid, long reg_num); + bool cs_read_reg_reply(long rid, long reg_num, long reg_val); + bool cs_delay(long ticks); + bool cs_i2c_write(long i2c_addr, uint8_t *i2c_data, size_t data_len); + bool cs_i2c_read(long rid, long i2c_addr, long n_bytes); + bool cs_i2c_read_reply(long rid, long i2c_addr, uint8_t *i2c_data, long i2c_data_len); + bool cs_spi_write(long enables, long format, long opt_header_bytes, uint8_t *spi_data, long spi_data_len); + bool cs_spi_read(long rid, long enables, long format, long opt_header_bytes, long n_bytes); + bool cs_spi_read_reply(long rid, uint8_t *spi_data, long spi_data_len); + int cs_len(int payload_offset); + pmt_t read_subpacket(int payload_offset); }; #endif diff --git a/usrp/host/lib/inband/usrp_interface.mbh b/usrp/host/lib/inband/usrp_interface.mbh new file mode 100644 index 000000000..ad0f78b4e --- /dev/null +++ b/usrp/host/lib/inband/usrp_interface.mbh @@ -0,0 +1,88 @@ +;; -*- 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++. +;; ---------------------------------------------------------------- + +;; ---------------------------------------------------------------- +;; usrp-interface-cs +;; +;; Handles interaction between the usrp_sever and the USB interface + +(define-protocol-class usrp-interface-cs + + (:outgoing + (cmd-usrp-open invocation-handle which-usrp) + (cmd-usrp-close invocation-handle) + (cmd-usrp-ntx-chan invocation-handle) + (cmd-usrp-nrx-chan invocation-handle) + (cmd-usrp-write invocation-handle channel data) + (cmd-usrp-start-reading invocation-handle channel) + ) + + (:incoming + (response-usrp-open invocation-handle status) + (response-usrp-close invocation-handle status) + (response-usrp-ntx-chan invocation-handle ntx-chan) + (response-usrp-nrx-chan invocation-handle nrx-chan) + (response-usrp-write invocation-handle status channel) + (response-usrp-read invocation-handle status data) + ) + ) + +;; ---------------------------------------------------------------- +;; usrp-tx-cs +;; +;; Handles interaction between the USB interface and TX interface + +(define-protocol-class usrp-tx-cs + + (:outgoing + (cmd-usrp-tx-write invocation-handle channel data tx-handle) + ) + + (:incoming + (response-usrp-tx-write invocation-handle status channel) + ) + ) + +;; ---------------------------------------------------------------- +;; usrp-rx-cs +;; +;; Handles interaction between the USB interface and RX interface + +(define-protocol-class usrp-rx-cs + + (:outgoing + (cmd-usrp-rx-start-reading invocation-handle rx-handle) + (cmd-usrp-rx-stop-reading invocation-handle) + ) + + (:incoming + (response-usrp-rx-read invocation-handle status data) + + ;; There is currently no response to a stop reading + ) + ) diff --git a/usrp/host/lib/inband/usrp_rx.cc b/usrp/host/lib/inband/usrp_rx.cc new file mode 100644 index 000000000..7344a6e89 --- /dev/null +++ b/usrp/host/lib/inband/usrp_rx.cc @@ -0,0 +1,142 @@ +/* -*- 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 <usrp_rx.h> + +#include <usrp_standard.h> +#include <iostream> +#include <vector> +#include <usb.h> +#include <mb_class_registry.h> +#include <usrp_inband_usb_packet.h> +#include <fpga_regs_common.h> +#include <stdio.h> + +#include <symbols_usrp_rx_cs.h> + +typedef usrp_inband_usb_packet transport_pkt; + +static const bool verbose = false; + +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_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_cs_ofile.open("rx_cs.dat",std::ios::binary|std::ios::out); + } + +} + +usrp_rx::~usrp_rx() +{ + if(d_disk_write) { + d_ofile.close(); + d_cs_ofile.close(); + } +} + +void +usrp_rx::initial_transition() +{ + +} + +void +usrp_rx::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t port_id = msg->port_id(); + pmt_t data = msg->data(); + + // 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_eqv(event, s_cmd_usrp_rx_start_reading)) + read_and_respond(data); + } +} + +void +usrp_rx::read_and_respond(pmt_t data) +{ + size_t ignore; + bool underrun; + unsigned int n_read; + unsigned int pkt_size = sizeof(transport_pkt); + + pmt_t invocation_handle = pmt_nth(0, data); + + // Need the handle to the RX port to send responses, this is passed + // by the USRP interface m-block + d_urx = + boost::any_cast<usrp_standard_rx *>(pmt_any_ref(pmt_nth(1, data))); + + if(verbose) + std::cout << "[usrp_rx] Waiting for packets..\n"; + + // Read by 512 which is packet size and send them back up + while(1) { + + pmt_t v_pkt = pmt_make_u8vector(pkt_size, 0); + transport_pkt *pkt = + (transport_pkt *) pmt_u8vector_writeable_elements(v_pkt, ignore); + + n_read = d_urx->read(pkt, pkt_size, &underrun); + + if(n_read != pkt_size) { + std::cerr << "[usrp_rx] Error reading packet, shutting down\n"; + d_cs->send(s_response_usrp_rx_read, + pmt_list3(PMT_NIL, PMT_F, PMT_NIL)); + return; + } + + if(underrun) + std::cout << "[usrp_rx] Underrun\n"; + + d_cs->send(s_response_usrp_rx_read, + pmt_list3(PMT_NIL, PMT_T, v_pkt)); + if(verbose) + std::cout << "[usrp_rx] Read 1 packet\n"; + + if(d_disk_write) { + if(pkt->chan() == 0x1f) + d_cs_ofile.write((const char *)pkt, transport_pkt::max_pkt_size()); + else + d_ofile.write((const char *)pkt, transport_pkt::max_pkt_size()); + + d_cs_ofile.flush(); + d_ofile.flush(); + } + } +} + +REGISTER_MBLOCK_CLASS(usrp_rx); diff --git a/usrp/host/lib/inband/usrp_rx.h b/usrp/host/lib/inband/usrp_rx.h new file mode 100644 index 000000000..e1a90a781 --- /dev/null +++ b/usrp/host/lib/inband/usrp_rx.h @@ -0,0 +1,55 @@ +/* -*- 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_USRP_RX_H +#define INCLUDED_USRP_RX_H + +#include <mb_mblock.h> +#include <fstream> + +class usrp_standard_rx; + +/*! + * \brief Implements the low level usb interface to the USRP + */ +class usrp_rx : public mb_mblock +{ + mb_port_sptr d_cs; + usrp_standard_rx *d_urx; + + bool d_disk_write; + std::ofstream d_ofile; + std::ofstream d_cs_ofile; + + public: + usrp_rx(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg); + ~usrp_rx(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + private: + void read_and_respond(pmt_t data); + void read_data(); + +}; + + +#endif /* INCLUDED_USRP_RX_H */ + diff --git a/usrp/host/lib/inband/usrp_rx_stub.cc b/usrp/host/lib/inband/usrp_rx_stub.cc new file mode 100644 index 000000000..bf78ddf27 --- /dev/null +++ b/usrp/host/lib/inband/usrp_rx_stub.cc @@ -0,0 +1,183 @@ +/* -*- 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 <usrp_rx_stub.h> + +#include <iostream> +#include <vector> +#include <usb.h> +#include <mb_class_registry.h> +#include <usrp_inband_usb_packet.h> +#include <fpga_regs_common.h> +#include "usrp_standard.h" +#include <stdio.h> +#include "ui_nco.h" +#include <fstream> + +#include <symbols_usrp_rx_cs.h> + +typedef usrp_inband_usb_packet transport_pkt; + +static const bool verbose = false; + +bool usrp_rx_stop; + +// 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. +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_amplitude(16384), + d_disk_write(false) +{ + 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; + d_nco.set_freq(2*M_PI * freq/sample_rate); + + //d_disk_write = true; + + if(d_disk_write) + d_ofile.open("raw_rx.dat",std::ios::binary|std::ios::out); + + usrp_rx_stop = false; +} + +usrp_rx_stub::~usrp_rx_stub() +{ + if(d_disk_write) + d_ofile.close(); +} + +void +usrp_rx_stub::initial_transition() +{ + +} + +void +usrp_rx_stub::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t port_id = msg->port_id(); + pmt_t data = msg->data(); + + // 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(verbose) + std::cout << "[USRP_RX_STUB] Starting...\n"; + + if(pmt_eqv(event, s_cmd_usrp_rx_start_reading)) + read_and_respond(data); + } +} + +void +usrp_rx_stub::read_and_respond(pmt_t data) +{ + + while(!usrp_rx_stop) { + + long nsamples_this_frame = d_samples_per_frame; + + 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); + + // fill in the complex sinusoid + + for (int i = 0; i < nsamples_this_frame; i++){ + + if (1){ + gr_complex s; + d_nco.sincos(&s, 1, d_amplitude); + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + else { + gr_complex s(d_amplitude, d_amplitude); + + // write 16-bit i & q + samples[2*i] = (int16_t) s.real(); + samples[2*i+1] = (int16_t) s.imag(); + } + } + + if(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)); + + // 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"; + } + + } + + usrp_rx_stop = false; + + if(verbose) + std::cout << "[USRP_RX_STUB] Got fake RX stop\n"; + +} + +REGISTER_MBLOCK_CLASS(usrp_rx_stub); diff --git a/usrp/host/lib/inband/usrp_rx_stub.h b/usrp/host/lib/inband/usrp_rx_stub.h new file mode 100644 index 000000000..483af5b48 --- /dev/null +++ b/usrp/host/lib/inband/usrp_rx_stub.h @@ -0,0 +1,71 @@ +/* -*- 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_USRP_RX_STUB_H +#define INCLUDED_USRP_RX_STUB_H + +#include <mb_mblock.h> +#include <vector> +#include "usrp_standard.h" +#include "ui_nco.h" +#include <fstream> +#include <queue> +#include <usrp_inband_usb_packet.h> + +typedef usrp_inband_usb_packet transport_pkt; + +extern bool usrp_rx_stop; // used to communicate a 'stop' to the RX stub +extern std::queue<pmt_t> d_cs_queue; + +/*! + * \brief Implements the low level usb interface to the USRP + */ +class usrp_rx_stub : public mb_mblock +{ + public: + + mb_port_sptr d_cs; + usrp_standard_rx* d_urx; + + long d_samples_per_frame; + + // for generating sine wave output + ui_nco<float,float> d_nco; + double d_amplitude; + + bool d_disk_write; + + std::ofstream d_ofile; + + public: + usrp_rx_stub(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg); + ~usrp_rx_stub(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + private: + void read_and_respond(pmt_t data); + void read_data(); + +}; + + +#endif /* INCLUDED_USRP_RX_H */ + diff --git a/usrp/host/lib/inband/usrp_server.cc b/usrp/host/lib/inband/usrp_server.cc index 800bf0e15..760397dc7 100644 --- a/usrp/host/lib/inband/usrp_server.cc +++ b/usrp/host/lib/inband/usrp_server.cc @@ -27,39 +27,19 @@ #include <usrp_inband_usb_packet.h> #include <mb_class_registry.h> #include <vector> +#include <usrp_usb_interface.h> + +#include <symbols_usrp_server_cs.h> +#include <symbols_usrp_channel.h> +#include <symbols_usrp_tx.h> +#include <symbols_usrp_rx.h> +#include <symbols_usrp_low_level_cs.h> +#include <symbols_usrp_interface_cs.h> +static pmt_t s_shutdown = pmt_intern("%shutdown"); typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy -// FIXME We should machine generate these by a simple preprocessor run over this file -// -// These are all the messages that we expect to receive. -// -// We "intern" these here (make them into symbols) so that our -// comparisions below are effectively pointer comparisons. - -static pmt_t s_cmd_allocate_channel = pmt_intern("cmd-allocate-channel"); -static pmt_t s_cmd_close = pmt_intern("cmd-close"); -static pmt_t s_cmd_deallocate_channel = pmt_intern("cmd-deallocate-channel"); -static pmt_t s_cmd_open = pmt_intern("cmd-open"); -static pmt_t s_cmd_start_recv_raw_samples = pmt_intern("cmd-start-recv-raw-samples"); -static pmt_t s_cmd_stop_recv_raw_samples = pmt_intern("cmd-stop-recv-raw-samples"); -static pmt_t s_cmd_to_control_channel = pmt_intern("cmd-to-control-channel"); -static pmt_t s_cmd_xmit_raw_frame = pmt_intern("cmd-xmit-raw-frame"); -static pmt_t s_cmd_max_capacity = pmt_intern("cmd-max-capacity"); -static pmt_t s_cmd_ntx_chan = pmt_intern("cmd-ntx-chan"); -static pmt_t s_cmd_nrx_chan = pmt_intern("cmd-nrx-chan"); -static pmt_t s_cmd_current_capacity_allocation = pmt_intern("cmd-current-capacity-allocation"); -static pmt_t s_response_allocate_channel = pmt_intern("response-allocate-channel"); -static pmt_t s_response_close = pmt_intern("response-close"); -static pmt_t s_response_deallocate_channel = pmt_intern("response-deallocate-channel"); -static pmt_t s_response_from_control_channel = pmt_intern("response-from-control-channel"); -static pmt_t s_response_open = pmt_intern("response-open"); -static pmt_t s_response_recv_raw_samples = pmt_intern("response-recv-raw-samples"); -static pmt_t s_response_xmit_raw_frame = pmt_intern("response-xmit-raw-frame"); -static pmt_t s_response_max_capacity = pmt_intern("response-max-capacity"); -static pmt_t s_response_ntx_chan = pmt_intern("response-ntx-chan"); -static pmt_t s_response_nrx_chan = pmt_intern("response-nrx-chan"); -static pmt_t s_response_current_capacity_allocation = pmt_intern("response-current-capacity-allocation"); +const static bool verbose = false; static std::string str(long x) @@ -70,36 +50,75 @@ 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) + : mb_mblock(rt, instance_name, user_arg), + d_fake_rx(false) { - // define our ports + // Dictionary for arguments to all of the components + pmt_t usrp_dict = user_arg; + // control & status port d_cs = define_port("cs", "usrp-server-cs", true, mb_port::EXTERNAL); + d_cs_usrp = define_port("cs_usrp", "usrp-interface-cs", false, mb_port::INTERNAL); // ports // // (if/when we do replicated ports, these will be replaced by a // single replicated port) for(int port=0; port < N_PORTS; port++) { - d_tx.push_back(define_port("tx"+str(port), "usrp-tx", true, mb_port::EXTERNAL)); - d_rx.push_back(define_port("rx"+str(port), "usrp-rx", true, mb_port::EXTERNAL)); + + d_tx.push_back(define_port("tx"+str(port), + "usrp-tx", + true, + mb_port::EXTERNAL)); + + d_rx.push_back(define_port("rx"+str(port), + "usrp-rx", + true, + mb_port::EXTERNAL)); } - // FIXME ... initializing to 2 channels on each for now, eventually we should - // query the FPGA to get these values - d_ntx_chan = 2; + define_component("usrp", "usrp_usb_interface", usrp_dict); + connect("self", "cs_usrp", "usrp", "cs"); + + d_defer=false; + d_opened=false; + + // FIXME: needs to be returned from open, if we want to use this d_nrx_chan = 2; + d_ntx_chan = 2; // Initialize capacity on each channel to 0 and to no owner + // Also initialize the USRP standard tx/rx pointers to NULL + for(int chan=0; chan < d_ntx_chan; chan++) + d_chaninfo_tx.push_back(channel_info()); + + for(int chan=0; chan < d_nrx_chan; chan++) + d_chaninfo_rx.push_back(channel_info()); + + d_rx_chan_mask = 0; + + for(int i=0; i < D_MAX_RID; i++) + d_rids.push_back(rid_info()); + + //d_fake_rx=true; +} + +void +usrp_server::reset_channels() +{ + for(int chan=0; chan < d_ntx_chan; chan++) { d_chaninfo_tx[chan].assigned_capacity = 0; d_chaninfo_tx[chan].owner = PMT_NIL; } + for(int chan=0; chan < d_nrx_chan; chan++) { d_chaninfo_rx[chan].assigned_capacity = 0; d_chaninfo_rx[chan].owner = PMT_NIL; } + + d_rx_chan_mask = 0; } usrp_server::~usrp_server() @@ -119,78 +138,328 @@ usrp_server::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 invocation_handle; - pmt_t reply_data; + pmt_t metadata = msg->metadata(); pmt_t status; - if (1){ + long port; + + if (pmt_eq(event, s_shutdown)) // ignore (for now) + return; + + invocation_handle = pmt_nth(0, data); + + if (0){ std::cout << "[USRP_SERVER] event: " << event << std::endl; std::cout << "[USRP_SERVER] port_id: " << port_id << std::endl; } - // It would be nice if this were all table driven, and we could - // compute our state transition as f(current_state, port_id, signal) + // It would be nice if this were all table driven, and we could compute our + // state transition as f(current_state, port_id, signal) + + // A message from the USRP CS, which should *only* be responses + // + // It is important that this set come before checking messages of any other + // components. This is since we always want to listen to the low level USRP + // server, even if we aren't initialized we are waiting for responses to + // become initialized. Likewise, after the usrp_server is "closed", we still + // want to pass responses back from the low level. - if (pmt_eq(port_id, d_cs->port_symbol())){ // message came in on our control/status port + //---------------- USRP RESPONSE ---------------// + if (pmt_eq(port_id, d_cs_usrp->port_symbol())) { + + //-------------- USRP OPEN ------------------// + if(pmt_eq(event, s_response_usrp_open)) { + // pass the response back over the regular CS port + pmt_t status = pmt_nth(1, data); + d_cs->send(s_response_open, pmt_list2(invocation_handle, status)); - if (pmt_eq(event, s_cmd_open)){ - // extract args from data - invocation_handle = pmt_nth(0, data); - long which_usrp = pmt_to_long(pmt_nth(1, data)); // integer usrp id, usually 0 + if(pmt_eqv(status,PMT_T)) { + d_opened = true; + d_defer = false; + recall_defer_queue(); + } + + return; + } + //------------- USRP CLOSE -------------------// + else if (pmt_eq(event, s_response_usrp_close)) { + pmt_t status = pmt_nth(1, data); + d_cs->send(s_response_close, pmt_list2(invocation_handle, status)); + + if(pmt_eqv(status,PMT_T)) { + d_opened = false; + d_defer = false; + reset_channels(); + recall_defer_queue(); + } - // Do the right thing.... - // build a reply - (void) which_usrp; // avoid unused warning + return; + } + //--------------- USRP WRITE --------------// + else if (pmt_eq(event, s_response_usrp_write)) { + + pmt_t status = pmt_nth(1, data); + long channel = pmt_to_long(pmt_nth(2, data)); + long port; + + // Do not report back responses if they were generated from a + // command packet + if(channel == 0x1f) + return; + + // Find the port through the owner of the channel + if((port = tx_port_index(d_chaninfo_tx[channel].owner)) !=-1 ) + d_tx[port]->send(s_response_xmit_raw_frame, + pmt_list2(invocation_handle, status)); + return; + } + //--------------- USRP READ ---------------// + else if (pmt_eq(event, s_response_usrp_read)) { + + pmt_t status = pmt_nth(1, data); + + if(!pmt_eqv(status, PMT_T)) { + std::cerr << "[USRP_SERVER] Error receiving packet\n"; + return; + } + else { + handle_response_usrp_read(data); + return; + } + } + + goto unhandled; + } + + // Checking for defer on all other messages + if(d_defer) { + if (verbose) + std::cout << "[USRP_SERVER] Received msg while deferring (" + << msg->signal() << ")\n"; + d_defer_queue.push(msg); + return; + } + + //--------- CONTROL / STATUS ------------// + if (pmt_eq(port_id, d_cs->port_symbol())){ + + //----------- OPEN -----------// + if (pmt_eq(event, s_cmd_open)){ - // if everything OK - status = PMT_T; - reply_data = pmt_list2(invocation_handle, status); + // Reject if already open + if(d_opened) { + d_cs->send(s_response_open, pmt_list2(invocation_handle, s_err_usrp_already_opened)); + return; + } - // ...and send it - d_cs->send(s_response_open, reply_data); + // the parameters are the same to the low level interface, so we just pass 'data' along + d_cs_usrp->send(s_cmd_usrp_open, data); + + d_defer = true; + return; } + //---------- CLOSE -----------// else if (pmt_eq(event, s_cmd_close)){ - // ... + + if(!d_opened) { + d_cs->send(s_response_close, pmt_list2(invocation_handle, s_err_usrp_already_closed)); + return; + } + + d_defer = true; + d_cs_usrp->send(s_cmd_usrp_close, pmt_list1(invocation_handle)); + + return; } + //---------- MAX CAPACITY ----------// else if (pmt_eq(event, s_cmd_max_capacity)) { - invocation_handle = pmt_nth(0, data); - reply_data = pmt_list2(invocation_handle, pmt_from_long(max_capacity())); - d_cs->send(s_response_max_capacity, reply_data); + + if(!d_opened) { + d_cs->send(s_response_max_capacity, + pmt_list3(invocation_handle, s_err_usrp_not_opened, pmt_from_long(0))); + return; + } + + d_cs->send(s_response_max_capacity, + pmt_list3(invocation_handle, + PMT_T, + pmt_from_long(max_capacity()))); return; } + //---------- NTX CHAN --------------// else if (pmt_eq(event, s_cmd_ntx_chan)) { - invocation_handle = pmt_nth(0, data); - reply_data = pmt_list2(invocation_handle, pmt_from_long(d_ntx_chan)); - d_cs->send(s_response_ntx_chan, reply_data); + + if(!d_opened) { + d_cs->send(s_response_ntx_chan, + pmt_list3(invocation_handle, s_err_usrp_not_opened, pmt_from_long(0))); + return; + } + + d_cs->send(s_response_ntx_chan, + pmt_list3(invocation_handle, + PMT_T, + pmt_from_long(d_ntx_chan))); + return; } + //---------- NRX CHAN -----------// else if (pmt_eq(event, s_cmd_nrx_chan)) { - invocation_handle = pmt_nth(0, data); - reply_data = pmt_list2(invocation_handle, pmt_from_long(d_nrx_chan)); - d_cs->send(s_response_nrx_chan, reply_data); - } + + if(!d_opened) { + d_cs->send(s_response_nrx_chan, + pmt_list3(invocation_handle, s_err_usrp_not_opened, pmt_from_long(0))); + return; + } + + d_cs->send(s_response_nrx_chan, + pmt_list3(invocation_handle, + PMT_T, + pmt_from_long(d_nrx_chan))); + return; + } + //--------- ALLOCATION? -----------// else if (pmt_eq(event, s_cmd_current_capacity_allocation)) { - invocation_handle = pmt_nth(0, data); - reply_data = pmt_list2(invocation_handle, pmt_from_long(current_capacity_allocation())); - d_cs->send(s_response_current_capacity_allocation, reply_data); + + if(!d_opened) { + d_cs->send(s_response_current_capacity_allocation, + pmt_list3(invocation_handle, + s_err_usrp_not_opened, + pmt_from_long(0))); + return; + } + + d_cs->send(s_response_current_capacity_allocation, + pmt_list3(invocation_handle, + PMT_T, + pmt_from_long(current_capacity_allocation()))); + return; } goto unhandled; } + + //-------------- TX ---------------// + if ((port = tx_port_index(port_id)) != -1) { + + //------------ ALLOCATE (TX) ----------------// + if (pmt_eq(event, s_cmd_allocate_channel)){ + + if(!d_opened) { + d_tx[port]->send(s_response_allocate_channel, + pmt_list3(invocation_handle, + s_err_usrp_not_opened, + pmt_from_long(0))); + return; + } + + handle_cmd_allocate_channel(d_tx[port], d_chaninfo_tx, data); + return; + } + + //----------- DEALLOCATE (TX) ---------------// + if (pmt_eq(event, s_cmd_deallocate_channel)) { + + if(!d_opened) { + d_tx[port]->send(s_response_deallocate_channel, + pmt_list3(invocation_handle, + s_err_usrp_not_opened, + pmt_from_long(0))); + return; + } - if (pmt_eq(event, s_cmd_allocate_channel)){ - handle_cmd_allocate_channel(port_id, data); - return; - } + handle_cmd_deallocate_channel(d_tx[port], d_chaninfo_tx, data); + return; + } + + //-------------- XMIT RAW FRAME -----------------/ + if (pmt_eq(event, s_cmd_xmit_raw_frame)){ - if (pmt_eq(event, s_cmd_deallocate_channel)) { - handle_cmd_deallocate_channel(port_id, data); - return; + if(!d_opened) { + d_tx[port]->send(s_response_xmit_raw_frame, + pmt_list2(invocation_handle, s_err_usrp_not_opened)); + return; + } + + handle_cmd_xmit_raw_frame(d_tx[port], d_chaninfo_tx, data); + return; + } + + //-------------- CONTROL PACKET -----------------/ + if (pmt_eq(event, s_cmd_to_control_channel)) { + + if(!d_opened) { + d_tx[port]->send(s_response_xmit_raw_frame, + pmt_list2(invocation_handle, s_err_usrp_not_opened)); + return; + } + + handle_cmd_to_control_channel(d_tx[port], d_chaninfo_tx, data); + return; + + } + + goto unhandled; } + + //-------------- RX ---------------// + if ((port = rx_port_index(port_id)) != -1) { - if (pmt_eq(event, s_cmd_xmit_raw_frame)){ - handle_cmd_xmit_raw_frame(data); - return; + //------------ ALLOCATE (RX) ----------------// + if (pmt_eq(event, s_cmd_allocate_channel)) { + + if(!d_opened) { + d_rx[port]->send(s_response_allocate_channel, + pmt_list3(invocation_handle, + s_err_usrp_not_opened, + pmt_from_long(0))); + return; + } + + handle_cmd_allocate_channel(d_rx[port], d_chaninfo_rx, data); + return; + } + + //----------- DEALLOCATE (RX) ---------------// + if (pmt_eq(event, s_cmd_deallocate_channel)) { + + if(!d_opened) { + d_rx[port]->send(s_response_deallocate_channel, + pmt_list3(invocation_handle, + s_err_usrp_not_opened, + pmt_from_long(0))); + return; + } + + handle_cmd_deallocate_channel(d_rx[port], d_chaninfo_rx, data); + return; + } + + //-------------- START RECV ----------------// + if (pmt_eq(event, s_cmd_start_recv_raw_samples)) { + + if(!d_opened) { + d_rx[port]->send(s_response_recv_raw_samples, + pmt_list2(invocation_handle, s_err_usrp_not_opened)); + return; + } + + handle_cmd_start_recv_raw_samples(d_rx[port], d_chaninfo_rx, data); + return; + } + + //-------------- STOP RECV ----------------// + if (pmt_eq(event, s_cmd_stop_recv_raw_samples)) { + + if(!d_opened) + return; + + // FIX ME : no response for stopping? even if error? (permissions) + handle_cmd_stop_recv_raw_samples(d_rx[port], d_chaninfo_rx, data); + + return; + } + + goto unhandled; } unhandled: @@ -231,128 +500,94 @@ long usrp_server::current_capacity_allocation() { return capacity; } -void usrp_server::handle_cmd_allocate_channel(pmt_t port_id, pmt_t data) { - +void +usrp_server::handle_cmd_allocate_channel( + mb_port_sptr port, + std::vector<struct channel_info> &chan_info, + pmt_t data) +{ pmt_t invocation_handle = pmt_nth(0, data); long rqstd_capacity = pmt_to_long(pmt_nth(1, data)); - long chan, port; - pmt_t reply_data; + long chan; - // If it's a TX port, allocate on a free channel, else check if it's a RX port - // and allocate. - if((port = tx_port_index(port_id)) != -1) { + // Check capacity exists + if((D_USB_CAPACITY - current_capacity_allocation()) < rqstd_capacity) { - // Check capacity exists - if((D_USB_CAPACITY - current_capacity_allocation()) < rqstd_capacity) { - reply_data = pmt_list3(invocation_handle, pmt_from_long(RQSTD_CAPACITY_UNAVAIL), PMT_NIL); // no capacity available - d_tx[port]->send(s_response_allocate_channel, reply_data); - return; - } + // no capacity available + port->send(s_response_allocate_channel, + pmt_list3(invocation_handle, + s_err_requested_capacity_unavailable, + PMT_NIL)); + return; + } - // Find a free channel, assign the capacity and respond - for(chan=0; chan < d_ntx_chan; chan++) { - if(d_chaninfo_tx[chan].owner == PMT_NIL) { - d_chaninfo_tx[chan].owner = port_id; - d_chaninfo_tx[chan].assigned_capacity = rqstd_capacity; - reply_data = pmt_list3(invocation_handle, PMT_T, pmt_from_long(chan)); - d_tx[port]->send(s_response_allocate_channel, reply_data); - return; - } - } + // Find a free channel, assign the capacity and respond + for(chan=0; chan < (long)chan_info.size(); chan++) { - std::cout << "[USRP_SERVER] Couldnt find a TX chan\n"; + if(verbose) + std::cout << "[USRP_SERVER] Checking chan: " << chan + << " owner " << chan_info[chan].owner + << " size " << chan_info.size() + << std::endl; - reply_data = pmt_list3(invocation_handle, pmt_from_long(CHANNEL_UNAVAIL), PMT_NIL); // no free TX chan found - d_tx[port]->send(s_response_allocate_channel, reply_data); - return; - } + if(chan_info[chan].owner == PMT_NIL) { - // Repeat the same process on the RX side if the port was not determined to be TX - if((port = rx_port_index(port_id)) != -1) { - - if((D_USB_CAPACITY - current_capacity_allocation()) < rqstd_capacity) { - reply_data = pmt_list3(invocation_handle, pmt_from_long(RQSTD_CAPACITY_UNAVAIL), PMT_NIL); // no capacity available - d_rx[port]->send(s_response_allocate_channel, reply_data); + chan_info[chan].owner = port->port_symbol(); + chan_info[chan].assigned_capacity = rqstd_capacity; + + port->send(s_response_allocate_channel, + pmt_list3(invocation_handle, + PMT_T, + pmt_from_long(chan))); + + if(verbose) + std::cout << "[USRP_SERVER] Assigning channel: " << chan + << " to " << chan_info[chan].owner + << std::endl; return; } + + } - for(chan=0; chan < d_nrx_chan; chan++) { - if(d_chaninfo_rx[chan].owner == PMT_NIL) { - d_chaninfo_rx[chan].owner = port_id; - d_chaninfo_rx[chan].assigned_capacity = rqstd_capacity; - reply_data = pmt_list3(invocation_handle, PMT_T, pmt_from_long(chan)); - d_rx[port]->send(s_response_allocate_channel, reply_data); - return; - } - } + if (verbose) + std::cout << "[USRP_SERVER] Couldnt find a TX chan\n"; - std::cout << "[USRP_SERVER] Couldnt find a RX chan\n"; - reply_data = pmt_list3(invocation_handle, pmt_from_long(CHANNEL_UNAVAIL), PMT_NIL); // no free RX chan found - d_rx[port]->send(s_response_allocate_channel, reply_data); - return; - } + // no free TX chan found + port->send(s_response_allocate_channel, + pmt_list3(invocation_handle, + s_err_channel_unavailable, + PMT_NIL)); + 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. -void usrp_server::handle_cmd_deallocate_channel(pmt_t port_id, pmt_t data) { +// that the owner of the method invocation is the owner of the port and that the +// channel number is valid. +void +usrp_server::handle_cmd_deallocate_channel( + 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)); - long port; - pmt_t reply_data; - - // Check that the channel number is valid, and that the calling port is the owner - // of the channel, and if so remove the assigned capacity. - if((port = tx_port_index(port_id)) != -1) { - - if(channel >= d_ntx_chan) { - reply_data = pmt_list2(invocation_handle, pmt_from_long(CHANNEL_INVALID)); // not a legit channel number - d_tx[port]->send(s_response_deallocate_channel, reply_data); - return; - } - if(d_chaninfo_tx[channel].owner != port_id) { - reply_data = pmt_list2(invocation_handle, pmt_from_long(PERMISSION_DENIED)); // not the owner of the port - d_tx[port]->send(s_response_deallocate_channel, reply_data); - return; - } - - d_chaninfo_tx[channel].assigned_capacity = 0; - d_chaninfo_tx[channel].owner = PMT_NIL; - - reply_data = pmt_list2(invocation_handle, PMT_T); - d_tx[port]->send(s_response_deallocate_channel, reply_data); + // Ensure the channel is valid and the caller owns the port + if(!check_valid(port, channel, chan_info, + pmt_list2(s_response_deallocate_channel, invocation_handle))) return; - } - - // Repeated process on the RX side - if((port = rx_port_index(port_id)) != -1) { - if(channel >= d_nrx_chan) { - reply_data = pmt_list2(invocation_handle, pmt_from_long(CHANNEL_INVALID)); // not a legit channel number - d_rx[port]->send(s_response_deallocate_channel, reply_data); - return; - } - - if(d_chaninfo_rx[channel].owner != port_id) { - reply_data = pmt_list2(invocation_handle, pmt_from_long(PERMISSION_DENIED)); // not the owner of the port - d_rx[port]->send(s_response_deallocate_channel, reply_data); - return; - } - - d_chaninfo_rx[channel].assigned_capacity = 0; - d_chaninfo_rx[channel].owner = PMT_NIL; - - reply_data = pmt_list2(invocation_handle, PMT_T); - d_rx[port]->send(s_response_deallocate_channel, reply_data); - return; - } + chan_info[channel].assigned_capacity = 0; + chan_info[channel].owner = PMT_NIL; + port->send(s_response_deallocate_channel, + pmt_list2(invocation_handle, + PMT_T)); + return; } -void usrp_server::handle_cmd_xmit_raw_frame(pmt_t data) { +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(); @@ -361,10 +596,18 @@ void usrp_server::handle_cmd_xmit_raw_frame(pmt_t data) { long channel = pmt_to_long(pmt_nth(1, data)); const void *samples = pmt_uniform_vector_elements(pmt_nth(2, data), n_bytes); long timestamp = pmt_to_long(pmt_nth(3, data)); + + // Ensure the channel is valid and the caller owns the port + if(!check_valid(port, channel, chan_info, + pmt_list2(s_response_xmit_raw_frame, invocation_handle))) + return; + + // Determine the number of packets to allocate contiguous memory for + // bursting over the USB and get a pointer to the memory to be used in + // building the packets + long n_packets = + static_cast<long>(std::ceil(n_bytes / (double)max_payload_len)); - // Determine the number of packets to allocate contiguous memory for bursting over the - // USB and get a pointer to the memory to be used in building the packets - long n_packets = static_cast<long>(std::ceil(n_bytes / (double)max_payload_len)); pmt_t v_packets = pmt_make_u8vector(sizeof(transport_pkt) * n_packets, 0); transport_pkt *pkts = @@ -372,7 +615,8 @@ void usrp_server::handle_cmd_xmit_raw_frame(pmt_t data) { for(int n=0; n < n_packets; n++) { - long payload_len = std::min((long)(n_bytes-(n*max_payload_len)), (long)max_payload_len); + long payload_len = + std::min((long)(n_bytes-(n*max_payload_len)), (long)max_payload_len); if(n == 0) { // first packet gets start of burst flag and timestamp pkts[n].set_header(pkts[n].FL_START_OF_BURST, channel, 0, payload_len); @@ -382,14 +626,740 @@ void usrp_server::handle_cmd_xmit_raw_frame(pmt_t data) { pkts[n].set_timestamp(0xffffffff); } - memcpy(pkts[n].payload(), (uint8_t *)samples+(max_payload_len * n), payload_len); + memcpy(pkts[n].payload(), + (uint8_t *)samples+(max_payload_len * n), + payload_len); + + } + + + pkts[n_packets-1].set_end_of_burst(); // set the last packet's end of burst + + if (verbose) + std::cout << "[USRP_SERVER] Received raw frame invocation: " + << invocation_handle << std::endl; + + // The actual response to the write will be generated by a + // s_response_usrp_write + d_cs_usrp->send(s_cmd_usrp_write, + pmt_list3(invocation_handle, + pmt_from_long(channel), + v_packets)); + + return; +} + +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); + pmt_t subpackets = pmt_nth(1, data); + + long n_subpkts = pmt_length(subpackets); + long curr_subpkt = 0; + + size_t psize; + long payload_len = 0; + long channel = 0x1f; + + // The design of the following code is optimized for simplicity, not + // performance. To performance optimize this code, the total size in bytes + // needed for all of the CS packets is needed to allocate contiguous memory + // which contains the USB packets for bursting over the bus. However to do + // this the packets subpackets would need to be parsed twice and their sizes + // would need to be determined. + // + // The approach taken is to keep parsing the subpackets and putting them in to + // USB packets. Once the USB packet is full, a write is sent for it and + // another packet is created. + // + // The subpacket creation methods will return false if the subpacket will not + // fit in to the current USB packet. In these cases a new USB packet is + // created and the old is sent. + + new_packet: + // This code needs to become "smart" and only make a new packet when full + pmt_t v_packet = pmt_make_u8vector(sizeof(transport_pkt), 0); + transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writeable_elements(v_packet, psize); + payload_len = 0; + + pkt->set_header(0, channel, 0, payload_len); + pkt->set_timestamp(0xffffffff); + + while(curr_subpkt < n_subpkts) { + + pmt_t subp = pmt_nth(curr_subpkt, subpackets); + pmt_t subp_cmd = pmt_nth(0, subp); + pmt_t subp_data = pmt_nth(1, subp); + + //--------- PING FIXED --------------// + if(pmt_eq(subp_cmd, s_op_ping_fixed)) { + + long urid = pmt_to_long(pmt_nth(0, subp_data)); + long pingval = pmt_to_long(pmt_nth(1, subp_data)); + + // USRP server sets request ID's to keep track of which application gets + // what response back. To allow a full 6-bits for an RID to the user, we + // keep a mapping and replace the RID's as the packets go in and out. If + // there are no RID's available, the command is thrown away silently. + long srid; + if((srid = next_rid()) == -1) + goto subpkt_bail; + + // We use a vector to store the owner of the ping request and will use it + // to send the request on any RX port they own. + d_rids[srid].owner = port->port_symbol(); + d_rids[srid].user_rid = urid; + + // Adds a ping after the previous command in the pkt + if(!pkt->cs_ping(srid, pingval)) + { + d_cs_usrp->send(s_cmd_usrp_write, + pmt_list3(invocation_handle, + pmt_from_long(channel), + v_packet)); + + // Return the RID + d_rids[srid].owner = PMT_NIL; + + goto new_packet; + } + + if(verbose) + std::cout << "[USRP_SERVER] Received ping command request" + << " assigning RID " << srid << std::endl; + + } + + //----------- WRITE REG ---------------// + if(pmt_eq(subp_cmd, s_op_write_reg)) { + + long reg_num = pmt_to_long(pmt_nth(0, subp_data)); + long val = pmt_to_long(pmt_nth(1, subp_data)); + + if(!pkt->cs_write_reg(reg_num, val)) + { + d_cs_usrp->send(s_cmd_usrp_write, + pmt_list3(invocation_handle, + pmt_from_long(channel), + v_packet)); + + goto new_packet; + } + + if(verbose) + std::cout << "[USRP_SERVER] Received write register request " + << "(" + << "Reg: " << reg_num << ", " + << "Val: " << val + << ")\n"; + } + + //------- WRITE REG MASKED ----------// + if(pmt_eq(subp_cmd, s_op_write_reg_masked)) { + + long reg_num = pmt_to_long(pmt_nth(0, subp_data)); + long val = pmt_to_long(pmt_nth(1, subp_data)); + long mask = pmt_to_long(pmt_nth(2, subp_data)); + + if(!pkt->cs_write_reg_masked(reg_num, val, mask)) + { + d_cs_usrp->send(s_cmd_usrp_write, + pmt_list3(invocation_handle, + pmt_from_long(channel), + v_packet)); + + goto new_packet; + } + + if(verbose) + std::cout << "[USRP_SERVER] Received write register masked request\n"; + } + + //------------ READ REG --------------// + if(pmt_eq(subp_cmd, s_op_read_reg)) { + + long urid = pmt_to_long(pmt_nth(0, subp_data)); + long reg_num = pmt_to_long(pmt_nth(1, subp_data)); + + long srid; + if((srid = next_rid()) == -1) + goto subpkt_bail; + + d_rids[srid].owner = port->port_symbol(); + d_rids[srid].user_rid = urid; + + if(!pkt->cs_read_reg(srid, reg_num)) + { + d_cs_usrp->send(s_cmd_usrp_write, + pmt_list3(invocation_handle, + pmt_from_long(channel), + v_packet)); + + // Return the rid + d_rids[srid].owner = PMT_NIL; + + goto new_packet; + } + + if(verbose) + std::cout << "[USRP_SERVER] Received read register request" + << " assigning RID " << srid << std::endl; + } + + //------------ DELAY --------------// + if(pmt_eq(subp_cmd, s_op_delay)) { + + long ticks = pmt_to_long(pmt_nth(0, subp_data)); + + if(!pkt->cs_delay(ticks)) + { + d_cs_usrp->send(s_cmd_usrp_write, + pmt_list3(invocation_handle, + pmt_from_long(channel), + v_packet)); + + goto new_packet; + } + + if(verbose) + std::cout << "[USRP_SERVER] Received delay request of " + << ticks << " ticks\n"; + } + + //--------- I2C WRITE -----------// + // FIXME: could check that byte count does not exceed 2^8 which + // is the max length in the subpacket for # of bytes to read. + if(pmt_eq(subp_cmd, s_op_i2c_write)) { + + long i2c_addr = pmt_to_long(pmt_nth(0, subp_data)); + pmt_t data = pmt_nth(1, subp_data); + + // Get a readable address to the data which also gives us the length + size_t data_len; + uint8_t *i2c_data = (uint8_t *) pmt_u8vector_writeable_elements(data, data_len); + + // Make the USB packet + if(!pkt->cs_i2c_write(i2c_addr, i2c_data, data_len)) + { + d_cs_usrp->send(s_cmd_usrp_write, + pmt_list3(invocation_handle, + pmt_from_long(channel), + v_packet)); + + goto new_packet; + } + + if(verbose) + std::cout << "[USRP_SERVER] Received I2C write\n"; + } + + //----------- I2C Read -------------// + if(pmt_eq(subp_cmd, s_op_i2c_read)) { + + long urid = pmt_to_long(pmt_nth(0, subp_data)); + long i2c_addr = pmt_to_long(pmt_nth(1, subp_data)); + long i2c_bytes = pmt_to_long(pmt_nth(2, subp_data)); + + long srid; + if((srid = next_rid()) == -1) + goto subpkt_bail; + + d_rids[srid].owner = port->port_symbol(); + d_rids[srid].user_rid = urid; + + if(!pkt->cs_i2c_read(srid, i2c_addr, i2c_bytes)) + { + + d_cs_usrp->send(s_cmd_usrp_write, + pmt_list3(invocation_handle, + pmt_from_long(channel), + v_packet)); + + d_rids[srid].owner = PMT_NIL; + + goto new_packet; + } + + if(verbose) + std::cout << "[USRP_SERVER] Received I2C read\n"; + } + + //--------- SPI WRITE -----------// + if(pmt_eq(subp_cmd, s_op_spi_write)) { + + long enables = pmt_to_long(pmt_nth(0, subp_data)); + long format = pmt_to_long(pmt_nth(1, subp_data)); + long opt = pmt_to_long(pmt_nth(2, subp_data)); + pmt_t data = pmt_nth(3, subp_data); + + // Get a readable address to the data which also gives us the length + size_t data_len; + uint8_t *spi_data = (uint8_t *) pmt_u8vector_writeable_elements(data, data_len); + + // Make the USB packet + if(!pkt->cs_spi_write(enables, format, opt, spi_data, data_len)) + { + d_cs_usrp->send(s_cmd_usrp_write, + pmt_list3(invocation_handle, + pmt_from_long(channel), + v_packet)); + + goto new_packet; + } + + if(verbose) + std::cout << "[USRP_SERVER] Received SPI write\n"; + } + + //--------- SPI READ -----------// + if(pmt_eq(subp_cmd, s_op_spi_read)) { + + long urid = pmt_to_long(pmt_nth(0, subp_data)); + long enables = pmt_to_long(pmt_nth(1, subp_data)); + long format = pmt_to_long(pmt_nth(2, subp_data)); + long opt = pmt_to_long(pmt_nth(3, subp_data)); + long n_bytes = pmt_to_long(pmt_nth(4, subp_data)); + + long srid; + if((srid = next_rid()) == -1) + goto subpkt_bail; + + d_rids[srid].owner = port->port_symbol(); + d_rids[srid].user_rid = urid; + + // Make the USB packet + if(!pkt->cs_spi_read(srid, enables, format, opt, n_bytes)) + { + d_cs_usrp->send(s_cmd_usrp_write, + pmt_list3(invocation_handle, + pmt_from_long(channel), + v_packet)); + + // Return the rid + d_rids[srid].owner = PMT_NIL; + + goto new_packet; + } + + if(verbose) + std::cout << "[USRP_SERVER] Received SPI read\n"; + } + + subpkt_bail: + curr_subpkt++; + + } + + + // If the current packets length is > 0, we know there are subpackets that + // need to be sent out still. + if(pkt->payload_len() > 0) + d_cs_usrp->send(s_cmd_usrp_write, + pmt_list3(invocation_handle, + pmt_from_long(channel), + v_packet)); + + return; +} + +void +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)); + + // Ensure the channel is valid and the caller owns the port + if(!check_valid(port, channel, chan_info, + pmt_list2(s_response_xmit_raw_frame, invocation_handle))) + return; + + // Already started receiving samples? (another start before a stop) + // Check the RX channel bitmask. + if(d_rx_chan_mask & (1 << channel)) { + port->send(s_response_recv_raw_samples, + pmt_list5(invocation_handle, + s_err_already_receiving, + PMT_NIL, + PMT_NIL, + PMT_NIL)); + return; + } + + // We only need to generate a 'start reading' command down to the + // low level interface if no other channel is already reading + // + // We carry this over the CS interface because the lower level + // interface does not care about the channel, we only demux it + // at the usrp_server on responses. + if(d_rx_chan_mask == 0) { + + if(verbose) + std::cout << "[USRP_SERVER] Sending read request down to start recv\n"; + + d_cs_usrp->send(s_cmd_usrp_start_reading, pmt_list1(invocation_handle)); + } + + d_rx_chan_mask |= 1<<channel; + + return; +} + +void +usrp_server::handle_cmd_stop_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)); + + // FIX ME : we have no responses to send an error... + // Ensure the channel is valid and the caller owns the port + //if(!check_valid(port, channel, chan_info, + // pmt_list2(s_response_xmit_raw_frame, invocation_handle))) + // return; + + // Remove this hosts bit from the receiver mask + d_rx_chan_mask &= ~(1<<channel); + + // We only need to generate a 'start reading' command down to the + // low level interface if no other channel is already reading + // + // We carry this over the CS interface because the lower level + // interface does not care about the channel, we only demux it + // at the usrp_server on responses. + if(d_rx_chan_mask == 0) { + + if(verbose) + std::cout << "[USRP_SERVER] Sending stop reading request down\n"; + + d_cs_usrp->send(s_cmd_usrp_stop_reading, pmt_list1(invocation_handle)); + } + + return; +} + +// Read the packet header, determine the port by the channel owner +void +usrp_server::handle_response_usrp_read(pmt_t data) +{ + + pmt_t invocation_handle = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); + pmt_t v_pkt = pmt_nth(2, data); + + size_t n_bytes; + size_t ignore; + + if (d_fake_rx) { + + pmt_t pkt = pmt_nth(2, data); + + d_rx[0]->send(s_response_recv_raw_samples, + pmt_list5(PMT_F, + PMT_T, + pkt, + pmt_from_long(0xffff), + PMT_NIL)); + + return; + } + + // Extract the packet and return appropriately + transport_pkt *pkt = (transport_pkt *) pmt_u8vector_writeable_elements(v_pkt, n_bytes); + + // The channel is used to find the port to pass the samples on + long channel = pkt->chan(); + long payload_len = pkt->payload_len(); + long port; + + // Ignore packets which seem to have incorrect size or size 0 + if(payload_len > pkt->max_payload() || payload_len == 0) + return; + + // If the packet is a C/S packet, parse it separately + if(channel == 0x1f) { + parse_control_pkt(invocation_handle, pkt); + return; + } + + if((port = rx_port_index(d_chaninfo_rx[channel].owner)) == -1) + return; // Don't know where to send the sample... possibility on abrupt close + + pmt_t v_samples = pmt_make_u8vector(payload_len, 0); + uint8_t *samples = pmt_u8vector_writeable_elements(v_samples, ignore); + + memcpy(samples, pkt->payload(), payload_len); + + // Build a properties dictionary to store things such as the RSSI + pmt_t properties = pmt_make_dict(); + + pmt_dict_set(properties, + pmt_intern("rssi"), + pmt_from_long(pkt->rssi())); + + if(pkt->overrun()) + pmt_dict_set(properties, + pmt_intern("overrun"), + PMT_T); + + if(pkt->underrun()) + pmt_dict_set(properties, + pmt_intern("underrun"), + PMT_T); + + d_rx[port]->send(s_response_recv_raw_samples, + pmt_list5(invocation_handle, + status, + v_samples, + pmt_from_long(pkt->timestamp()), + properties)); + return; +} + +void +usrp_server::parse_control_pkt(pmt_t invocation_handle, transport_pkt *pkt) +{ + + long payload_len = pkt->payload_len(); + long curr_payload = 0; + long port; + + // We dispatch based on the control packet type, however we can extract the + // opcode and the length immediately which is consistent in all responses. + // + // Since each control packet can have multiple responses, we keep reading the + // lengths of each subpacket until we reach the payload length. + while(curr_payload < payload_len) { + + pmt_t sub_packet = pkt->read_subpacket(curr_payload); + pmt_t op_symbol = pmt_nth(0, sub_packet); + + int len = pkt->cs_len(curr_payload); + + if(verbose) + std::cout << "[USRP_SERVER] Parsing subpacket " + << op_symbol << " ... length " << len << std::endl; + + //----------------- PING RESPONSE ------------------// + if(pmt_eq(op_symbol, s_op_ping_fixed_reply)) { + + long srid = pmt_to_long(pmt_nth(1, sub_packet)); + pmt_t pingval = pmt_nth(2, sub_packet); + + long urid = d_rids[srid].user_rid; + + if(verbose) + std::cout << "[USRP_SERVER] Found ping response " + << "(" + << "URID: " << urid << ", " + << "SRID: " << srid << ", " + << "VAL: " << pingval + << ")\n"; + + // Do some bounds checking incase of bogus/corrupt responses + if(srid > D_MAX_RID) + return; + + pmt_t owner = d_rids[srid].owner; + + // FIXME: should be 1 response for all subpackets here ? + if((port = tx_port_index(owner)) != -1) + d_tx[port]->send(s_response_from_control_channel, + pmt_list4(invocation_handle, + PMT_T, + pmt_list2(s_op_ping_fixed_reply, // subp + pmt_list2(pmt_from_long(urid), + pingval)), + pmt_from_long(pkt->timestamp()))); + } + + //----------------- READ REG RESPONSE ------------------// + else if(pmt_eq(op_symbol, s_op_read_reg_reply)) { + + long srid = pmt_to_long(pmt_nth(1, sub_packet)); + pmt_t reg_num = pmt_nth(2, sub_packet); + pmt_t reg_val = pmt_nth(3, sub_packet); + + long urid = d_rids[srid].user_rid; + + if(verbose) + std::cout << "[USRP_SERVER] Found read register response " + << "(" + << "URID: " << urid << ", " + << "SRID: " << srid << ", " + << "REG: " << reg_num << ", " + << "VAL: " << reg_val + << ")\n"; + + // Do some bounds checking to avoid seg faults + if(srid > D_MAX_RID) + return; + + pmt_t owner = d_rids[srid].owner; + + // FIXME: should be 1 response for all subpackets here ? + if((port = tx_port_index(owner)) != -1) + d_tx[port]->send(s_response_from_control_channel, + pmt_list4(invocation_handle, + PMT_T, + pmt_list2(s_op_read_reg_reply, // subp + pmt_list3(pmt_from_long(urid), + reg_num, + reg_val)), + pmt_from_long(pkt->timestamp()))); + } + + //------------------ I2C READ REPLY -------------------// + else if(pmt_eq(op_symbol, s_op_i2c_read_reply)) { + + long srid = pmt_to_long(pmt_nth(1, sub_packet)); + pmt_t i2c_addr = pmt_nth(2, sub_packet); + pmt_t i2c_data = pmt_nth(3, sub_packet); + + long urid = d_rids[srid].user_rid; + + if(verbose) + std::cout << "[USRP_SERVER] Found i2c read reply " + << "(" + << "URID: " << urid << ", " + << "SRID: " << srid << ", " + << "Addr: " << i2c_addr << ", " + << "Data: " << i2c_data + << ")\n"; + + // Do some bounds checking to avoid seg faults + if(srid > D_MAX_RID) + return; + + pmt_t owner = d_rids[srid].owner; + + if((port = tx_port_index(owner)) != -1) + d_tx[port]->send(s_response_from_control_channel, + pmt_list4(invocation_handle, + PMT_T, + pmt_list2(s_op_i2c_read_reply, + pmt_list3(pmt_from_long(urid), + i2c_addr, + i2c_data)), + pmt_from_long(pkt->timestamp()))); + } + + //------------------ SPI READ REPLY -------------------// + else if(pmt_eq(op_symbol, s_op_spi_read_reply)) { + + long srid = pmt_to_long(pmt_nth(1, sub_packet)); + pmt_t spi_data = pmt_nth(2, sub_packet); + + long urid = d_rids[srid].user_rid; + + if(verbose) + std::cout << "[USRP_SERVER] Found SPI read reply " + << "(" + << "URID: " << urid << ", " + << "SRID: " << srid << ", " + << "Data: " << spi_data + << ")\n"; + + // Bounds check the RID + if(srid > D_MAX_RID) + return; + + pmt_t owner = d_rids[srid].owner; + + if((port = tx_port_index(owner)) != -1) + d_tx[port]->send(s_response_from_control_channel, + pmt_list4(invocation_handle, + PMT_T, + pmt_list2(s_op_spi_read_reply, + pmt_list2(pmt_from_long(urid), + spi_data)), + pmt_from_long(pkt->timestamp()))); + } + + // Each subpacket has an unaccounted for 2 bytes which is the opcode + // and the length field + curr_payload += len + 2; + + // All subpackets are 32-bit aligned + int align_offset = 4 - (curr_payload % 4); + + if(align_offset != 4) + curr_payload += align_offset; + } +} + +void +usrp_server::recall_defer_queue() +{ + + std::vector<mb_message_sptr> recall; + + while(!d_defer_queue.empty()) { + recall.push_back(d_defer_queue.front()); + d_defer_queue.pop(); } - pkts[n_packets-1].set_end_of_burst(); // set the last packet's end of burst + // Parse the messages that were queued while waiting for an open response + for(int i=0; i < (int)recall.size(); i++) + handle_message(recall[i]); + + return; +} + +bool +usrp_server::check_valid(mb_port_sptr port, + long channel, + std::vector<struct channel_info> &chan_info, + pmt_t signal_info) +{ - // interface with the USRP to send the USB packet, since the memory is - // contiguous, this should be a serious of memory copies to the bus, each being - // USB_PKT_SIZE * MAX_PACKET_BURST bytes worth of data (given a full burst) + pmt_t response_signal = pmt_nth(0, signal_info); + pmt_t invocation_handle = pmt_nth(1, signal_info); + + // not a valid channel number? + if(channel >= (long)chan_info.size() && channel != 0x1f) { + port->send(response_signal, + pmt_list2(invocation_handle, + s_err_channel_invalid)); + + if(verbose) + std::cout << "[USRP_SERVER] Invalid channel number for event " + << response_signal << std::endl; + return false; + } + + // not the owner of the port? + if(chan_info[channel].owner != port->port_symbol()) { + port->send(response_signal, + pmt_list2(invocation_handle, + s_err_channel_permission_denied)); + + if(verbose) + std::cout << "[USRP_SERVER] Invalid permissions" + << " for " << response_signal + << " from " << port->port_symbol() + << " proper owner is " << chan_info[channel].owner + << " on channel " << channel + << " invocation " << invocation_handle + << std::endl; + return false; + } + + return true; +} + +// Goes through the vector of RIDs and retreieves an +// available one for use +long +usrp_server::next_rid() +{ + for(int i = 0; i < D_MAX_RID; i++) + if(pmt_eqv(d_rids[i].owner, PMT_NIL)) + return i; + + return -1; } REGISTER_MBLOCK_CLASS(usrp_server); diff --git a/usrp/host/lib/inband/usrp_server.h b/usrp/host/lib/inband/usrp_server.h index d2819cd66..81dceb1f4 100644 --- a/usrp/host/lib/inband/usrp_server.h +++ b/usrp/host/lib/inband/usrp_server.h @@ -23,21 +23,19 @@ #include <mb_mblock.h> #include <vector> +#include <queue> +#include <fstream> +#include <usrp_inband_usb_packet.h> + +typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy /*! - * \brief Implements the lowest-level mblock interface to the USRP + * \brief Implements the lowest-level mblock usb_interface to the USRP */ class usrp_server : public mb_mblock { public: - enum error_codes { - RQSTD_CAPACITY_UNAVAIL = 0, - CHANNEL_UNAVAIL = 1, - CHANNEL_INVALID = 2, - PERMISSION_DENIED = 3 - }; - // our ports enum port_types { RX_PORT = 0, @@ -46,19 +44,49 @@ public: static const int N_PORTS = 4; std::vector<mb_port_sptr> d_tx, d_rx; mb_port_sptr d_cs; + mb_port_sptr d_cs_usrp; static const int D_USB_CAPACITY = 32 * 1024 * 1024; static const int D_MAX_CHANNELS = 16; long d_ntx_chan; long d_nrx_chan; + // Keep track of the request IDs + struct rid_info { + pmt_t owner; + long user_rid; + + rid_info() { + owner = PMT_NIL; + user_rid = 0; + } + }; + + static const long D_MAX_RID = 64; + std::vector<rid_info> d_rids; + struct channel_info { - long assigned_capacity; // the capacity currently assignedby the channel + long assigned_capacity; // the capacity currently assignedby the channel pmt_t owner; // port ID of the owner of the channel + + channel_info() { + assigned_capacity = 0; + owner = PMT_NIL; + } }; - struct channel_info d_chaninfo_tx[D_MAX_CHANNELS]; - struct channel_info d_chaninfo_rx[D_MAX_CHANNELS]; + long d_rx_chan_mask; // A bitmask representing the channels in the + // receiving state + + std::vector<struct channel_info> d_chaninfo_tx; + std::vector<struct channel_info> d_chaninfo_rx; + + std::queue<mb_message_sptr> d_defer_queue; + + bool d_defer; + bool d_opened; + + bool d_fake_rx; public: usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg); @@ -71,12 +99,21 @@ protected: static int max_capacity() { return D_USB_CAPACITY; } private: - void handle_cmd_allocate_channel(pmt_t port_id, pmt_t data); - void handle_cmd_deallocate_channel(pmt_t port_id, pmt_t data); - void handle_cmd_xmit_raw_frame(pmt_t data); + void handle_cmd_allocate_channel(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data); + void handle_cmd_deallocate_channel(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data); + void handle_cmd_xmit_raw_frame(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data); + void handle_cmd_to_control_channel(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data); + void handle_cmd_start_recv_raw_samples(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data); + void handle_cmd_stop_recv_raw_samples(mb_port_sptr port, std::vector<struct channel_info> &chan_info, pmt_t data); int rx_port_index(pmt_t port_id); int tx_port_index(pmt_t port_id); long current_capacity_allocation(); + void recall_defer_queue(); + void reset_channels(); + void handle_response_usrp_read(pmt_t data); + 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(); }; #endif /* INCLUDED_USRP_SERVER_H */ diff --git a/usrp/host/lib/inband/usrp_server.mbh b/usrp/host/lib/inband/usrp_server.mbh index e96c3f1ac..06ec4b996 100644 --- a/usrp/host/lib/inband/usrp_server.mbh +++ b/usrp/host/lib/inband/usrp_server.mbh @@ -40,9 +40,8 @@ ;; mechanism to match asynchronous responses with the commands that ;; generated them. ;; -;; status is either #t, indicating success, or a pair containing -;; (status-code . message), where status-code is a symbol and message -;; is a string. +;; status is either #t, indicating success, or a symbol indicating an error. +;; All symbol's names shall begin with %error- ;; ---------------------------------------------------------------- @@ -128,7 +127,7 @@ (:incoming - (response-from-control-channel invocation-handle status list-of-subpackets) + (response-from-control-channel invocation-handle status list-of-subpackets timestamp) ) ) @@ -248,9 +247,9 @@ (:incoming (response-open invocation-handle status) (response-close invocation-handle status) - (response-max-capacity invocation-handle capacity) - (response-ntx-chan invocation-handle ntx-chan) - (response-nrx-chan invocation-handle nrx-chan) - (response-current-capacity-allocation invocation-handle capacity) + (response-max-capacity invocation-handle status capacity) + (response-ntx-chan invocation-handle status ntx-chan) + (response-nrx-chan invocation-handle status nrx-chan) + (response-current-capacity-allocation invocation-handle status capacity) ) ) diff --git a/usrp/host/lib/inband/usrp_tx.cc b/usrp/host/lib/inband/usrp_tx.cc new file mode 100644 index 000000000..a7a5e4a89 --- /dev/null +++ b/usrp/host/lib/inband/usrp_tx.cc @@ -0,0 +1,138 @@ +/* -*- 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 <usrp_tx.h> +#include <iostream> +#include <usb.h> +#include <mb_class_registry.h> +#include <usrp_inband_usb_packet.h> +#include <fpga_regs_common.h> +#include <usrp_standard.h> +#include <stdio.h> + +#include <symbols_usrp_tx_cs.h> + +typedef usrp_inband_usb_packet transport_pkt; + +static const bool verbose = false; + +usrp_tx::usrp_tx(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(rt, instance_name, user_arg), + d_disk_write(false) +{ + d_cs = define_port("cs", "usrp-tx-cs", true, mb_port::EXTERNAL); + + //d_disk_write=true; + + if(d_disk_write) { + d_ofile.open("tx_data.dat",std::ios::binary|std::ios::out); + d_cs_ofile.open("tx_cs.dat",std::ios::binary|std::ios::out); + } +} + +usrp_tx::~usrp_tx() +{ + if(d_disk_write) { + d_ofile.close(); + d_cs_ofile.close(); + } +} + +void +usrp_tx::initial_transition() +{ + +} + +void +usrp_tx::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t port_id = msg->port_id(); + pmt_t data = msg->data(); + + // 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_eqv(event, s_cmd_usrp_tx_write)) + write(data); + } +} + +void +usrp_tx::write(pmt_t data) +{ + pmt_t invocation_handle = pmt_nth(0, data); + pmt_t channel = pmt_nth(1, data); + pmt_t v_packets = pmt_nth(2, data); + d_utx = boost::any_cast<usrp_standard_tx *>(pmt_any_ref(pmt_nth(3, data))); + + size_t n_bytes; + bool underrun; // this will need to go, as it is taken care of in the packet headers + + transport_pkt *pkts = (transport_pkt *) pmt_u8vector_writeable_elements(v_packets, n_bytes); + + int ret = d_utx->write (pkts, n_bytes, &underrun); + + if (0 && underrun) + fprintf(stderr, "uU"); + + if (ret == (int) n_bytes) { + if (verbose) + std::cout << "[usrp_server] Write of " << n_bytes << " successful\n"; + // need to respond with the channel so the USRP server knows who to forward the result of + // the write to by looking up the owner of the channel + d_cs->send(s_response_usrp_tx_write, + pmt_list3(invocation_handle, PMT_T, channel)); + } + else { + if (verbose) + std::cout << "[usrp_server] Error writing " << n_bytes << " bytes to USB bus\n"; + d_cs->send(s_response_usrp_tx_write, + pmt_list3(invocation_handle, PMT_F, channel)); + } + + long n_packets = + static_cast<long>(std::ceil(n_bytes / (double)transport_pkt::max_pkt_size())); + + for(int i=0; i < n_packets; i++) { + + if(d_disk_write) { + if(pkts[i].chan() == 0x1f) + 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()); + + d_cs_ofile.flush(); + d_ofile.flush(); + } + } + + + return; +} + +REGISTER_MBLOCK_CLASS(usrp_tx); diff --git a/usrp/host/lib/inband/usrp_tx.h b/usrp/host/lib/inband/usrp_tx.h new file mode 100644 index 000000000..546a26afc --- /dev/null +++ b/usrp/host/lib/inband/usrp_tx.h @@ -0,0 +1,53 @@ +/* -*- 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_USRP_TX_H +#define INCLUDED_USRP_TX_H + +#include <mb_mblock.h> +#include <fstream> + +class usrp_standard_tx; + +/*! + * \brief Implements the low level usb interface to the USRP + */ +class usrp_tx : public mb_mblock +{ + mb_port_sptr d_cs; + usrp_standard_tx *d_utx; + + bool d_disk_write; + std::ofstream d_ofile; + std::ofstream d_cs_ofile; + + public: + usrp_tx(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg); + ~usrp_tx(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + private: + void write(pmt_t data); +}; + + +#endif /* INCLUDED_USRP_TX_H */ + diff --git a/usrp/host/lib/inband/usrp_tx_stub.cc b/usrp/host/lib/inband/usrp_tx_stub.cc new file mode 100644 index 000000000..7a9876322 --- /dev/null +++ b/usrp/host/lib/inband/usrp_tx_stub.cc @@ -0,0 +1,344 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <iostream> +#include <vector> +#include <usb.h> +#include <mb_class_registry.h> +#include <usrp_tx_stub.h> +#include <usrp_inband_usb_packet.h> +#include <fpga_regs_common.h> +#include "usrp_standard.h" +#include <stdio.h> +#include <fstream> +#include <usrp_rx_stub.h> + +#include <symbols_usrp_tx_cs.h> + +typedef usrp_inband_usb_packet transport_pkt; + +static const bool verbose = false; + +usrp_tx_stub::usrp_tx_stub(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(rt, instance_name, user_arg), + d_disk_write(false) +{ + d_cs = define_port("cs", "usrp-tx-cs", true, mb_port::EXTERNAL); + + //d_disk_write=true; + + if(d_disk_write) { + d_ofile.open("tx_stub_data.dat",std::ios::binary|std::ios::out); + d_cs_ofile.open("tx_stub_cs.dat",std::ios::binary|std::ios::out); + } +} + +usrp_tx_stub::~usrp_tx_stub() +{ + if(d_disk_write) { + d_ofile.close(); + d_cs_ofile.close(); + } +} + +void +usrp_tx_stub::initial_transition() +{ + +} + +void +usrp_tx_stub::handle_message(mb_message_sptr msg) +{ + pmt_t event = msg->signal(); + pmt_t port_id = msg->port_id(); + pmt_t data = msg->data(); + + // 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_eqv(event, s_cmd_usrp_tx_write)) + write(data); + } +} + +void +usrp_tx_stub::write(pmt_t data) +{ + pmt_t invocation_handle = pmt_nth(0, data); + pmt_t channel = pmt_nth(1, data); + pmt_t v_packets = pmt_nth(2, data); + d_utx = boost::any_cast<usrp_standard_tx *>(pmt_any_ref(pmt_nth(3, data))); + + size_t n_bytes; + + transport_pkt *pkts = (transport_pkt *) pmt_u8vector_writeable_elements(v_packets, n_bytes); + long n_packets = static_cast<long>(std::ceil(n_bytes / (double)transport_pkt::max_pkt_size())); + + // Parse the packets looking for C/S packets and dump them to a disk if + // necessary + for(long i=0; i<n_packets; i++) { + + if(d_disk_write) { + if(pkts[i].chan() == 0x1f) + 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()); + + d_cs_ofile.flush(); + d_ofile.flush(); + } + + if(pkts[i].chan() == 0x1f) + parse_cs(invocation_handle, pkts[i]); + } + + d_cs->send(s_response_usrp_tx_write, + pmt_list3(invocation_handle, PMT_T, channel)); + + return; +} + +void +usrp_tx_stub::parse_cs(pmt_t invocation_handle, transport_pkt pkt) +{ + + long payload_len = pkt.payload_len(); + long curr_payload = 0; + + size_t ignore; + + // There is the possibility that the responses for a single USB packet full of + // CS packets will not fit back in a single USB packet, considering some + // responses are greater than their commands (read registers). + new_packet: + pmt_t v_pkt = pmt_make_u8vector(sizeof(transport_pkt), 0); + + transport_pkt *q_pkt = + (transport_pkt *) pmt_u8vector_writeable_elements(v_pkt, ignore); + + q_pkt->set_header(0, 0x1f, 0, 0); + q_pkt->set_timestamp(0xffffffff); + + // We dispatch based on the control packet type, however we can extract the + // opcode and the length immediately which is consistent in all responses. + // + // Since each control packet can have multiple responses, we keep reading the + // lengths of each subpacket until we reach the payload length. + while(curr_payload < payload_len) { + + pmt_t sub_packet = pkt.read_subpacket(curr_payload); + pmt_t op_symbol = pmt_nth(0, sub_packet); + + int len = pkt.cs_len(curr_payload); + + if(verbose) + std::cout << "[USRP_TX_STUB] Parsing subpacket " + << op_symbol << " ... length " << len << std::endl; + + //----------------- PING FIXED ------------------// + if(pmt_eq(op_symbol, s_op_ping_fixed)) { + + long rid = pmt_to_long(pmt_nth(1, sub_packet)); + long pingval = pmt_to_long(pmt_nth(2, sub_packet)); + + // Generate a reply and put it in the queue for the RX stub to read + if(!q_pkt->cs_ping_reply(rid, pingval)) + goto new_packet; + + if(verbose) + std::cout << "[USRP_TX_STUB] Generated ping response " + << "(" + << "RID: " << rid << ", " + << "VAL: " << pingval + << ")\n"; + } + + //----------------- READ REG ------------------// + if(pmt_eq(op_symbol, s_op_read_reg)) { + + long rid = pmt_to_long(pmt_nth(1, sub_packet)); + long reg_num = pmt_to_long(pmt_nth(2, sub_packet)); + long reg_val = 0xdeef; + + // Generate a reply and put it in the queue for the RX stub to read + if(!q_pkt->cs_read_reg_reply(rid, reg_num, reg_val)) + goto new_packet; + + if(verbose) + std::cout << "[USRP_TX_STUB] Generated read register response " + << "(" + << "RID: " << rid << ", " + << "REG: " << reg_num << ", " + << "VAL: " << reg_val + << ")\n"; + } + + //----------------- DELAY ------------------// + if(pmt_eq(op_symbol, s_op_delay)) { + + long ticks = pmt_to_long(pmt_nth(1, sub_packet)); + + if(verbose) + std::cout << "[USRP_TX_STUB] Received delay command " + << "(" + << "Ticks: " << ticks + << ")\n"; + } + + //----------------- WRITE REG ------------------// + if(pmt_eq(op_symbol, s_op_write_reg)) { + + pmt_t reg_num = pmt_nth(1, sub_packet); + pmt_t reg_val = pmt_nth(2, sub_packet); + + if(verbose) + std::cout << "[USRP_TX_STUB] Received write register command " + << "(" + << "RegNum: " << reg_num << ", " + << "Val: " << reg_val + << ")\n"; + } + + //----------------- WRITE REG MASK ---------------// + if(pmt_eq(op_symbol, s_op_write_reg_masked)) { + + pmt_t reg_num = pmt_nth(1, sub_packet); + pmt_t reg_val = pmt_nth(2, sub_packet); + pmt_t mask = pmt_nth(3, sub_packet); + + if(verbose) + std::cout << "[USRP_TX_STUB] Received write register command " + << "(" + << "RegNum: " << reg_num << ", " + << "Val: " << reg_val << ", " + << "Mask: " << mask + << ")\n"; + } + + //---------------- I2C WRITE ------------------// + if(pmt_eq(op_symbol, s_op_i2c_write)) { + pmt_t i2c_addr = pmt_nth(1, sub_packet); + pmt_t i2c_data = pmt_nth(2, sub_packet); + + if(verbose) + std::cout << "[USRP_TX_STUB] Received i2c write command " + << "(" + << "Addr: " << i2c_addr << ", " + << "Data: " << i2c_data + << ")\n"; + } + + //---------------- I2C READ ------------------// + if(pmt_eq(op_symbol, s_op_i2c_read)) { + long rid = pmt_to_long(pmt_nth(1, sub_packet)); + long i2c_addr = pmt_to_long(pmt_nth(2, sub_packet)); + long i2c_bytes = pmt_to_long(pmt_nth(3, sub_packet)); + + // Create data to place as a response, filled with 0xff + size_t ignore; + pmt_t i2c_data = pmt_make_u8vector(i2c_bytes, 0xff); + uint8_t *w_data = (uint8_t *) pmt_u8vector_writeable_elements(i2c_data, ignore); + + // Generate a reply and put it in the queue for the RX stub to read + if(!q_pkt->cs_i2c_read_reply(rid, i2c_addr, w_data, i2c_bytes)) + goto new_packet; + + if(verbose) + std::cout << "[USRP_TX_STUB] Received i2c read " + << "(" + << "RID: " << rid << ", " + << "Addr: " << i2c_addr << ", " + << "Bytes: " << i2c_bytes + << ")\n"; + } + + //---------------- SPI WRITE ------------------// + if(pmt_eq(op_symbol, s_op_spi_write)) { + long enables = pmt_to_long(pmt_nth(1, sub_packet)); + long format = pmt_to_long(pmt_nth(2, sub_packet)); + long opt = pmt_to_long(pmt_nth(3, sub_packet)); + pmt_t data = pmt_nth(4, sub_packet); + + if(verbose) + std::cout << "[USRP_TX_STUB] Received spi write command " + << "(" + << "Enables: " << enables << ", " + << "Format: " << format << ", " + << "Options: " << opt << ", " + << "Data: " << data + << ")\n"; + } + + //---------------- SPI READ ------------------// + if(pmt_eq(op_symbol, s_op_spi_read)) { + long rid = pmt_to_long(pmt_nth(1, sub_packet)); + long enables = pmt_to_long(pmt_nth(2, sub_packet)); + long format = pmt_to_long(pmt_nth(3, sub_packet)); + long opt = pmt_to_long(pmt_nth(4, sub_packet)); + long n_bytes = pmt_to_long(pmt_nth(5, sub_packet)); + + // Create data to place as a fake response + size_t ignore; + pmt_t spi_data = pmt_make_u8vector(n_bytes, 0xff); + uint8_t *w_data = (uint8_t *) pmt_u8vector_writeable_elements(spi_data, ignore); + + // Generate a reply and put it in the queue for the RX stub to read + if(!q_pkt->cs_spi_read_reply(rid, w_data, n_bytes)) + goto new_packet; + + if(verbose) + std::cout << "[USRP_TX_STUB] Received spi read command " + << "(" + << "RID: " << rid << ", " + << "Enables: " << enables << ", " + << "Format: " << format << ", " + << "Options: " << opt << ", " + << "Bytes: " << n_bytes + << ")\n"; + + } + + // Each subpacket has an unaccounted for 2 bytes which is the opcode + // and the length field + curr_payload += len + 2; + + // All subpackets are 32-bit aligned + int align_offset = 4 - (curr_payload % 4); + + if(align_offset != 4) + curr_payload += align_offset; + + } + + // If the packet has data in the payload, it needs queued + if(q_pkt->payload_len() > 0) + d_cs_queue.push(pmt_list2(invocation_handle, v_pkt)); + + return; +} + +REGISTER_MBLOCK_CLASS(usrp_tx_stub); diff --git a/usrp/host/lib/inband/usrp_tx_stub.h b/usrp/host/lib/inband/usrp_tx_stub.h new file mode 100644 index 000000000..52294beec --- /dev/null +++ b/usrp/host/lib/inband/usrp_tx_stub.h @@ -0,0 +1,61 @@ +/* -*- 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_USRP_TX_STUB_H +#define INCLUDED_USRP_TX_STUB_H + +#include <mb_mblock.h> +#include <vector> +#include "usrp_standard.h" +#include <fstream> +#include <usrp_inband_usb_packet.h> + +typedef usrp_inband_usb_packet transport_pkt; + +/*! + * \brief Implements the low level usb interface to the USRP + */ +class usrp_tx_stub : public mb_mblock +{ + public: + + mb_port_sptr d_cs; + usrp_standard_tx* d_utx; + + std::ofstream d_ofile; + std::ofstream d_cs_ofile; + + bool d_disk_write; + + public: + usrp_tx_stub(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg); + ~usrp_tx_stub(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + private: + void write(pmt_t data); + void parse_cs(pmt_t invocation_handle, transport_pkt pkt); + +}; + + +#endif /* INCLUDED_USRP_TX_STUB_H */ + diff --git a/usrp/host/lib/inband/usrp_usb_interface.cc b/usrp/host/lib/inband/usrp_usb_interface.cc new file mode 100644 index 000000000..b2ccba81b --- /dev/null +++ b/usrp/host/lib/inband/usrp_usb_interface.cc @@ -0,0 +1,431 @@ +/* -*- 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 <usrp_usb_interface.h> + +#include <iostream> +#include <vector> +#include <usb.h> +#include <mb_class_registry.h> +#include <usrp_inband_usb_packet.h> +#include <fpga_regs_common.h> +#include "usrp_rx.h" +#include <usrp_rx_stub.h> +#include "usrp_tx.h" +#include "usrp_standard.h" +#include <stdio.h> + +typedef usrp_inband_usb_packet transport_pkt; + +#include <symbols_usrp_interface_cs.h> +#include <symbols_usrp_tx_cs.h> +#include <symbols_usrp_rx_cs.h> +static pmt_t s_shutdown = pmt_intern("%shutdown"); + +static const bool verbose = false; + + + +// need to take number of TX and RX channels as parameter +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_interp_tx(16), + d_interp_rx(16), + d_rf_freq(10e6), + d_rbf("inband_tx_rx.rbf") +{ + // Dictionary for arguments to all of the components + pmt_t usrp_dict = user_arg; + + // Default TX/RX interface + std::string tx_interface = "usrp_tx"; + std::string rx_interface = "usrp_rx"; + + if (pmt_is_dict(usrp_dict)) { + + // The 'fake-usrp' key enables the TX and RX stubs if PMT_T + if(pmt_t fake_usrp = pmt_dict_ref(usrp_dict, + pmt_intern("fake-usrp"), + PMT_NIL)) { + if(pmt_eqv(fake_usrp, PMT_T)) { + tx_interface = "usrp_tx_stub"; + rx_interface = "usrp_rx_stub"; + d_fake_usrp=true; + } + } + + // Read the TX interpolations + if(pmt_t interp_tx = pmt_dict_ref(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 interpolations + if(pmt_t interp_rx = pmt_dict_ref(usrp_dict, + pmt_intern("interp-rx"), + PMT_NIL)) { + if(!pmt_eqv(interp_rx, PMT_NIL)) + d_interp_rx = pmt_to_long(interp_rx); + } + + // Read the RBF + if(pmt_t rbf = pmt_dict_ref(usrp_dict, + pmt_intern("rbf"), + PMT_NIL)) { + if(!pmt_eqv(rbf, PMT_NIL)) + d_rbf = pmt_symbol_to_string(rbf); + } + + // The RF center frequency + if(pmt_t rf_freq = pmt_dict_ref(usrp_dict, + pmt_intern("rf-freq"), + PMT_NIL)) { + if(!pmt_eqv(rf_freq, PMT_NIL)) + d_rf_freq = pmt_to_long(rf_freq); + } + } + + if (verbose) { + std::cout << "[USRP_USB_INTERFACE] Setting USRP RBF to " + << d_rbf << std::endl; + + std::cout << "[USRP_USB_INTERFACE] Setting TX interpolation to " + << d_interp_tx << std::endl; + + std::cout << "[USRP_USB_INTERFACE] Setting RX interpolation to " + << d_interp_rx << std::endl; + + std::cout << "[USRP_USB_INTERFACE] Using TX interface: " + << tx_interface << "\n"; + + std::cout << "[USRP_USB_INTERFACE] Using RX interface: " + << rx_interface << "\n"; + + } + + d_cs = define_port("cs", "usrp-interface-cs", true, mb_port::EXTERNAL); + d_rx_cs = define_port("rx_cs", "usrp-rx-cs", false, mb_port::INTERNAL); + 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); + connect("self", "rx_cs", "rx", "cs"); + connect("self", "tx_cs", "tx", "cs"); + + // FIX ME: the code should query the FPGA to retrieve the number of channels and such + d_ntx_chan = 2; + d_nrx_chan = 2; + + 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() +{ + +} + +void +usrp_usb_interface::initial_transition() +{ + +} + +void +usrp_usb_interface::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 invocation_handle; + + if (pmt_eq(event, s_shutdown)) // ignore (for now) + return; + + //------------- CONTROL / STATUS -------------// + if (pmt_eq(port_id, d_cs->port_symbol())) { + + //------------ OPEN --------------// + if (pmt_eq(event, s_cmd_usrp_open)){ + handle_cmd_open(data); + return; + } + //----------- CLOSE -------------// + else if (pmt_eq(event, s_cmd_usrp_close)) { + handle_cmd_close(data); + return; + } + //---------- NTX CHAN ----------// + else if (pmt_eq(event, s_cmd_usrp_ntx_chan)) { + invocation_handle = pmt_nth(0, data); + d_cs->send(s_response_usrp_ntx_chan, + pmt_list2(invocation_handle, + pmt_from_long(d_ntx_chan))); + return; + } + //---------- NRX CHAN ----------// + else if (pmt_eq(event, s_cmd_usrp_nrx_chan)) { + invocation_handle = pmt_nth(0, data); + d_cs->send(s_response_usrp_nrx_chan, + pmt_list2(invocation_handle, + pmt_from_long(d_nrx_chan))); + return; + } + //------------ WRITE -----------// + else if(pmt_eq(event, s_cmd_usrp_write)) { + handle_cmd_write(data); + return; + } + //-------- START READING --------// + else if(pmt_eq(event, s_cmd_usrp_start_reading)) { + handle_cmd_start_reading(data); + return; + } + //-------- STOP READING --------// + else if(pmt_eq(event, s_cmd_usrp_stop_reading)) { + handle_cmd_stop_reading(data); + return; + } + + goto unhandled; + } + + //---------------- RX ------------------// + if (pmt_eq(port_id, d_rx_cs->port_symbol())) { + + // Relay reads back up + if(pmt_eq(event, s_response_usrp_rx_read)) { + d_cs->send(s_response_usrp_read, data); + return; + } + + goto unhandled; + } + + //---------------- TX ------------------// + if (pmt_eq(port_id, d_tx_cs->port_symbol())) { + + if(pmt_eq(event, s_response_usrp_tx_write)) { + + pmt_t invocation_handle = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); + pmt_t channel = pmt_nth(2, data); + + d_cs->send(s_response_usrp_write, + pmt_list3(invocation_handle, + status, + channel)); + + return; + } + + goto unhandled; + } + + unhandled: + std::cout << "[USRP_USB_INTERFACE] unhandled msg: " << msg << std::endl; +} + +void +usrp_usb_interface::handle_cmd_open(pmt_t data) +{ + pmt_t invocation_handle = pmt_nth(0, data); + long which_usrp = pmt_to_long(pmt_nth(1, data)); + pmt_t reply_data; + + if(d_fake_usrp) { + d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T)); + return; + } + + if (verbose) + std::cout << "[USRP_USB_INTERFACE] Handling open request for USRP " << which_usrp << "\n"; + + // Open up a standard RX and TX for communication with the USRP + + d_utx = usrp_standard_tx::make(which_usrp, + d_interp_tx, + 1, // 1 channel + -1, // mux + 4096, // USB block size + 16, // nblocks for async transfers + d_rbf + ); + + if(d_utx==0) { + if (verbose) + std::cout << "[USRP_USB_INTERFACE] Failed to open TX\n"; + reply_data = pmt_list2(invocation_handle, PMT_F); + d_cs->send(s_response_usrp_open, reply_data); + return; + } + + if(!d_utx->set_tx_freq (0,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); + d_cs->send(s_response_usrp_open, reply_data); + return; + } + + d_utx->start(); + + if (verbose) + std::cout << "[USRP_USB_INTERFACE] Setup TX channel\n"; + + d_urx = + usrp_standard_rx::make (which_usrp, + d_interp_rx, + 1, // nchan + -1, // mux + 0, // set blank mode to start + 4096, // USB block size + 16, // number of blocks for async transfers + d_rbf); + + if(!d_urx) { + if (verbose) + std::cout << "[usrp_server] Failed to open RX\n"; + reply_data = pmt_list2(invocation_handle, PMT_F); + d_cs->send(s_response_usrp_open, reply_data); + return; + } + + if(!d_urx->set_rx_freq (0, 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); +// } + } + + if (verbose) + std::cout << "[USRP_USB_INTERFACE] Setup RX channel\n"; + + d_cs->send(s_response_usrp_open, pmt_list2(invocation_handle, PMT_T)); +} + +void +usrp_usb_interface::handle_cmd_write(pmt_t data) +{ + pmt_t invocation_handle = pmt_nth(0, data); + pmt_t channel = pmt_nth(1, data); + pmt_t pkts = pmt_nth(2, data); + + pmt_t tx_handle = pmt_make_any(d_utx); + + d_tx_cs->send(s_cmd_usrp_tx_write, + pmt_list4(invocation_handle, + channel, + pkts, + tx_handle)); + + return; +} + +void +usrp_usb_interface::handle_cmd_start_reading(pmt_t data) +{ + pmt_t invocation_handle = pmt_nth(0, data); + + if(verbose) + std::cout << "[USRP_USB_INTERFACE] Starting RX...\n"; + + if(!d_fake_usrp) + d_urx->start(); + + pmt_t rx_handle = pmt_make_any(d_urx); + + d_rx_cs->send(s_cmd_usrp_rx_start_reading, pmt_list2(PMT_NIL, rx_handle)); + + return; +} + +void +usrp_usb_interface::handle_cmd_stop_reading(pmt_t data) +{ + pmt_t invocation_handle = pmt_nth(0, data); + + if(!d_fake_usrp) { + if(verbose) + std::cout << "[USRP_USB_INTERFACE] Stopping RX...\n"; + 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 + } + + return; +} + +void +usrp_usb_interface::handle_cmd_close(pmt_t data) +{ + pmt_t invocation_handle = pmt_nth(0, data); + + if(d_fake_usrp) { + d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T)); + return; + } + + if (verbose) + std::cout << "[USRP_USB_INTERFACE] Handling close request for USRP\n"; + + delete d_utx; + d_utx = 0; + + delete d_urx; + d_urx = 0; + + d_cs->send(s_response_usrp_close, pmt_list2(invocation_handle, PMT_T)); + + shutdown_all(PMT_T); +} + + +REGISTER_MBLOCK_CLASS(usrp_usb_interface); diff --git a/usrp/host/lib/inband/usrp_usb_interface.h b/usrp/host/lib/inband/usrp_usb_interface.h new file mode 100644 index 000000000..42cda7af1 --- /dev/null +++ b/usrp/host/lib/inband/usrp_usb_interface.h @@ -0,0 +1,72 @@ +/* -*- 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_USRP_USB_INTERFACE_H +#define INCLUDED_USRP_USB_INTERFACE_H + +#include <mb_mblock.h> +#include <vector> +#include "usrp_standard.h" + +/*! + * \brief Implements the low level usb interface to the USRP + */ +class usrp_usb_interface : public mb_mblock +{ + public: + + usrp_standard_tx* d_utx; + usrp_standard_rx* d_urx; + + mb_port_sptr d_cs; + mb_port_sptr d_rx_cs; + mb_port_sptr d_tx_cs; + + long d_ntx_chan; + long d_nrx_chan; + + long d_fpga_debug; + + bool d_fake_usrp; + + long d_interp_tx; + long d_interp_rx; + + long d_rf_freq; + + std::string d_rbf; + + public: + usrp_usb_interface(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg); + ~usrp_usb_interface(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + private: + void handle_cmd_open(pmt_t data); + void handle_cmd_close(pmt_t data); + void handle_cmd_write(pmt_t data); + void handle_cmd_start_reading(pmt_t data); + void handle_cmd_stop_reading(pmt_t data); + +}; + + +#endif /* INCLUDED_USRP_USB_INTERFACE_H */ |