diff --git a/doc/inband-signaling-usb-host b/doc/inband-signaling-usb-host index ca306fe..1a5d870 100644 --- a/doc/inband-signaling-usb-host +++ b/doc/inband-signaling-usb-host @@ -18,241 +18,6 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # -This is preliminary design document on the organization of the host -component of the USRP inband signaling implementation over USB. -Assumptions: we'll have a single usrp_usb_daemon, implemented as an -mblock, that will provide the high-level message based interface to -the USRP. The daemon will handle all resource allocation, muxing and -demuxing for the control and status messages from multiple clients. - -The underlying cross-process IPC mechanism is not yet specified. -All communication will be via messages. - -The external interface to the usrp_usb_daemon will consist of two sets -of replicated ports, one set for the transmit, and one set for -receive. - - -// ------------------------------------------------------------------------ - -// Protocol class usrp_usb_common -// Defined from client's point-of-view -// -// This protocol class is shared by the usrp_usb_tx and usrp_usb_rx -// protocol classes - -// outgoing: - -cmd_allocate_channel(invocation_handle, channel, capacity_reservation) - -invocation_handle -Type Handle -Use The identifier provided by the client to tag the method invocation. - The identifier will be returned with the response, to provide - the client with a mechanism to match asynchronous responses with - commands that generated them. - -channel -Type integer -Use Specifies the Tx channel to allocate - -capacity_reservation -Type float, units are bytes/s -Use Specifies the number of bytes/s of USB capacity to reserve for - this channel. - - -// incoming: - -response_allocate_channel(invocation_handle, status) - -Type Handle -Use The identifier provided by the client in the prompting invocation. - The identifier is returned with the response, so that the - client has a mechanism to match asynchronous responses with - commands that generated them. The value of the invocation_handle - is opaque to the server, and is not required by the server to be unique. - -Type Status -Use Contains the status code for the operation, per FIXME, and - an optional message. - -Preconditions: - a) None - -Postconditions: - a) If successful, the requested channel and USB capacity are - allocated for the client's exclusive use. - - -// outgoing: - -cmd_deallocate_channel(invocation_handle, channel) - -invocation_handle -Type Handle -Use The identifier provided by the client to tag the method invocation. - The identifier will be returned with the response, to provide - the client with a mechanism to match asynchronous responses with - commands that generated them. - -channel -Type integer -Use Specifies the Tx channel to deallocate - - -// incoming: - -response_deallocate_channel(invocation_handle, status) - -Type Handle -Use The identifier provided by the client in the prompting invocation. - The identifier is returned with the response, so that the - client has a mechanism to match asynchronous responses with - commands that generated them. The value of the invocation_handle - is opaque to the server, and is not required by the server to be unique. - -Type Status -Use Contains the status code for the operation, per FIXME, and - an optional message. - -Preconditions: - a) None - -Postconditions: - a) If successful, the requested channel and associated USB capacity - are deallocated, and return to the pool of available resources. - - -// ------------------------------------------------------------------------ - -// Protocol class usrp_usb_tx inherits from usrp_usb_common -// Defined from client's point-of-view - -// outgoing: - -cmd_xmit_raw_frame(invocation_handle, channel, samples, timestamp) - -invocation_handle -Type Handle -Use The identifier provided by the client to tag the method invocation. - The identifier will be returned with the response, to provide - the client with a mechanism to match asynchronous responses with - commands that generated them. - -channel -Type integer -Use Specifies the channel that the frame of samples shall be transmitted on. - -samples -Type homogenous vector of unsigned char -Use These samples must already be in the appropriate format for parsing - by the USRP FPGA. The required format depends on the - configuration associated with this channel. No conversion of - the samples takes place in this method. Samples will be split - into multiple USB data packets as required for transport - across the USB. - -timestamp -Type 32-bit integer -Use Specifies the time at which the first sample in samples - shall be sent to the D/A converter. The format and - interpretation of time is as specified in - inband-signaling-usb. - - -// incoming: - -response_xmit_raw_frame(invocation_handle, status) - -Type Handle -Use The identifier provided by the client in the prompting invocation. - The identifier is returned with the response, so that the - client has a mechanism to match asynchronous responses with - commands that generated them. The value of the invocation_handle - is opaque to the server, and is not required by the server to be unique. - -Type Status -Use Contains the status code for the operation, per FIXME, and - an optional message. - -Preconditions: - a) The specified channel is allocated to this client - -Postconditions: - a) If successful, the samples of the frame have been queued for - transmission to the USRP. - - -// ------------------------------------------------------------------------ - -// Protocol class usrp_usb_rx inherits from usrp_usb_common -// Defined from client's point-of-view - - -// outgoing: - -cmd_recv_raw_samples(invocation_handle, channel) - -invocation_handle -Type Handle -Use The identifier provided by the client to tag the method invocation. - The identifier will be returned with the response, to provide - the client with a mechanism to match asynchronous responses with - commands that generated them. - -channel -Type integer -Use Specifies the channel that the samples shall be received from. - -The client may issue multiple cmd_recv_raw_samples commands to ensure -an uninterrupted flow of samples. The appropriate number of -outstanding cmds to issue is TBD, but is at least 2. - -[Discussion: I'm not sure if this is really the interface we want. -We may want to provide an enable/disable method, and then just begin -streaming samples. Or, we may wan to implement packet boundary -detection in the FPGA, and then return a frame's worth of samples -(potentially in multiple pieces). - -It may be that we need to different modes, one for packet based -reception and one for continuous streaming.] - - -// incoming: - -response_recv_raw_samples(invocation_handle, samples, timestamp, properties) - -Type Handle -Use The identifier provided by the client in the prompting invocation. - The identifier is returned with the response, so that the - client has a mechanism to match asynchronous responses with - commands that generated them. The value of the invocation_handle - is opaque to the server, and is not required by the server to be unique. - -samples -Type homogenous vector of unsigned char -Use Samples as returned by the USRP FPGA. The format of the - returned samples depends on the configuration associated with - this channel. No conversion or unpacking of samples takes place in - this method. - -timestamp -Type 32-bit integer -Use Specifies the time at which the first sample in samples - was received from the A/D converter. The format and - interpretation of time is as specified in - inband-signaling-usb. - -properties -Type Map -Use Returns additional (key, value) pairs associated with the - reception of these samples. In particular, the map may contain - the Received Strength Signal Indication (RSSI) reported by the - front end at the time the first sample was received from the A/D. - -// ------------------------------------------------------------------------ - -To do: control and configuration messages... +See usrp/host/lib/inband/usrp_server.mbh for interface diff --git a/fpga/inband_lib/chan_fifo_reader.v b/fpga/inband_lib/chan_fifo_reader.v new file mode 100755 index 0000000..2b3178d --- /dev/null +++ b/fpga/inband_lib/chan_fifo_reader.v @@ -0,0 +1,197 @@ +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) ; + + // Should not be needed if adc clock rate < tx clock rate + `define JITTER 5 + + //Samples format + // 16 bits interleaved complex samples + `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 + + // State registers + reg[3:0] reader_state; + reg[3:0] reader_next_state; + + //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) + begin + reader_state <= `IDLE; + reader_next_state <= `IDLE; + rdreq <= 0; + skip <= 0; + overrun <= 0; + underrun <= 0; + burst <= 0; + qsample <= 1; + end + else + begin + reader_state = reader_next_state; + case (reader_state) + `IDLE: + begin + if (pkt_waiting == 1) + begin + reader_next_state <= `READ; + 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 + + // Read payload length + `HEADER2: + begin + payload_len <= (fifodata & 16'h1FF); + read_len <= 9'd0; + reader_next_state <= `TIMESTAMP1; + end + + `TIMESTAMP1: + begin + timestamp <= {fifodata, 16'b0}; + rdreq <= 0; + reader_next_state <= `TIMESTAMP2; + end + + `TIMESTAMP2: + begin + timestamp <= timestamp + fifodata; + reader_next_state <= `WAIT; + 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; + // Let's send it + else if ((timestamp < adc_clock + `JITTER + && timestamp > adc_clock) + || timestamp == 32'hFFFFFFFF) + begin + reader_next_state <= `WAITSTROBE; + end + // Outdated + else if (timestamp < adc_clock) + begin + reader_next_state <= `DISCARD; + skip <= 1; + end + end + + // Wait for the transmit chain to be ready + `WAITSTROBE: + begin + // If end of payload... + if (read_len == payload_len) + begin + reader_next_state <= `DISCARD; + skip <= (payload_len < 508); + 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 + 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 + + default: + begin + $display ("Error unknown state"); + reader_state <= `IDLE; + reader_next_state <= `IDLE; + end + endcase + end + end + +endmodule \ No newline at end of file diff --git a/fpga/inband_lib/data_packet_fifo.v b/fpga/inband_lib/data_packet_fifo.v new file mode 100755 index 0000000..5b37b14 --- /dev/null +++ b/fpga/inband_lib/data_packet_fifo.v @@ -0,0 +1,128 @@ +module data_packet_fifo + ( input reset, + input clock, + input [15:0]ram_data_in, + input write_enable, + output reg have_space, + output reg [15:0]ram_data_out, + output reg pkt_waiting, + input read_enable, + input pkt_complete, + input skip_packet) ; + + /* Some parameters for usage later on */ + parameter DATA_WIDTH = 16 ; + parameter NUM_PACKETS = 4 ; + + /* Create the RAM here */ + reg [DATA_WIDTH-1:0] usb_ram [256*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 ; + + wire [7-2+NUM_PACKETS:0] usb_ram_aout ; + wire [7-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) + begin + if (reset) + pkt_waiting <= 0; + else if (usb_ram_ain >= usb_ram_aout) + pkt_waiting <= usb_ram_ain - usb_ram_aout >= 256; + else + pkt_waiting <= (usb_ram_ain + 10'b1111111111 - usb_ram_aout) >= 256; + end + + // Check if there is room + always @(usb_ram_ain, usb_ram_aout) + begin + if (reset) + have_space <= 1; + else 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); + else + have_space <= (usb_ram_aout - usb_ram_ain) >= 256; + 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 */ + always @(posedge clock) + begin + if( write_enable ) + begin + usb_ram[usb_ram_ain] <= ram_data_in ; + end + end + + /* RAM Read Address process */ + always @(posedge clock) + begin + if( reset ) + begin + usb_ram_packet_out <= 0 ; + usb_ram_offset_out <= 0 ; + isfull <= 0; + end + else + if( skip_packet ) + begin + usb_ram_packet_out <= usb_ram_packet_out + 1 ; + usb_ram_offset_out <= 0 ; + end + else if(read_enable) begin + if( usb_ram_offset_out == 8'b11111111 ) + begin + 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 + +endmodule diff --git a/fpga/inband_lib/tx_buffer_inband.v b/fpga/inband_lib/tx_buffer_inband.v new file mode 100755 index 0000000..56c0780 --- /dev/null +++ b/fpga/inband_lib/tx_buffer_inband.v @@ -0,0 +1,183 @@ +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 + ); + + wire [15:0] tx_data_bus; + + 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; + + 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) + ); + + 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) + ); + + + //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) + ); + +endmodule // tx_buffer + diff --git a/fpga/inband_lib/usb_fifo_reader.v b/fpga/inband_lib/usb_fifo_reader.v new file mode 100755 index 0000000..170c70f --- /dev/null +++ b/fpga/inband_lib/usb_fifo_reader.v @@ -0,0 +1,135 @@ +module usb_fifo_reader (tx_clock, fifodata, pkt_waiting, reset, + rdreq, skip, done_chan, WR_chan, tx_data_bus); + + /* Module parameters */ + parameter NUM_CHAN = 2 ; + parameter WIDTH = 32 ; + + 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 + + + \ No newline at end of file diff --git a/fpga/inband_lib/usb_packet_fifo.v b/fpga/inband_lib/usb_packet_fifo.v new file mode 100755 index 0000000..c416e2b --- /dev/null +++ b/fpga/inband_lib/usb_packet_fifo.v @@ -0,0 +1,112 @@ +module usb_packet_fifo + ( input reset, + input clock_in, + input clock_out, + input [15:0]ram_data_in, + input write_enable, + output reg [15:0]ram_data_out, + output reg pkt_waiting, + output reg have_space, + input read_enable, + input skip_packet ) ; + + /* Some parameters for usage later on */ + parameter DATA_WIDTH = 16 ; + parameter NUM_PACKETS = 4 ; + + /* Create the RAM here */ + reg [DATA_WIDTH-1:0] usb_ram [256*NUM_PACKETS-1:0] ; + + /* Create the address signals */ + reg [7-2+NUM_PACKETS:0] usb_ram_ain ; + reg [7:0] usb_ram_offset ; + reg [1:0] usb_ram_packet ; + + wire [7-2+NUM_PACKETS:0] usb_ram_aout ; + reg isfull; + + assign usb_ram_aout = {usb_ram_packet,usb_ram_offset} ; + + // Check if there is one full packet to process + always @(usb_ram_ain, usb_ram_aout) + begin + if (reset) + pkt_waiting <= 0; + else 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) >= 256; + else + pkt_waiting <= (usb_ram_ain + 10'b1111111111 - usb_ram_aout) >= 256; + end + + // Check if there is room + always @(usb_ram_ain, usb_ram_aout) + begin + if (reset) + have_space <= 1; + else 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); + else + have_space <= (usb_ram_aout - usb_ram_ain) >= 256; + end + + /* RAM Write Address process */ + always @(posedge clock_in) + begin + if( reset ) + usb_ram_ain <= 0 ; + else + if( write_enable ) + begin + usb_ram_ain <= usb_ram_ain + 1 ; + if (usb_ram_ain + 1 == usb_ram_aout) + isfull <= 1; + end + end + + /* RAM Writing process */ + always @(posedge clock_in) + begin + if( write_enable ) + begin + usb_ram[usb_ram_ain] <= ram_data_in ; + end + end + + /* RAM Read Address process */ + always @(posedge clock_out) + begin + if( reset ) + begin + usb_ram_packet <= 0 ; + usb_ram_offset <= 0 ; + isfull <= 0; + end + else + if( skip_packet ) + begin + usb_ram_packet <= usb_ram_packet + 1 ; + usb_ram_offset <= 0 ; + end + else if(read_enable) + if( usb_ram_offset == 8'b11111111 ) + begin + usb_ram_offset <= 0 ; + usb_ram_packet <= usb_ram_packet + 1 ; + end + else + usb_ram_offset <= usb_ram_offset + 1 ; + if (usb_ram_ain == usb_ram_aout) + isfull <= 0; + end + + /* RAM Reading Process */ + always @(posedge clock_out) + begin + ram_data_out <= usb_ram[usb_ram_aout] ; + end + +endmodule \ No newline at end of file diff --git a/fpga/inband_lib/usb_packet_fifo2.v b/fpga/inband_lib/usb_packet_fifo2.v new file mode 100755 index 0000000..d815e4e --- /dev/null +++ b/fpga/inband_lib/usb_packet_fifo2.v @@ -0,0 +1,119 @@ +`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/fpga/megacells/fifo_512.bsf b/fpga/megacells/fifo_512.bsf new file mode 100755 index 0000000..a955b56 --- /dev/null +++ b/fpga/megacells/fifo_512.bsf @@ -0,0 +1,116 @@ +/* +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/fpga/megacells/fifo_512.cmp b/fpga/megacells/fifo_512.cmp new file mode 100755 index 0000000..86fc078 --- /dev/null +++ b/fpga/megacells/fifo_512.cmp @@ -0,0 +1,31 @@ +--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_512 + PORT + ( + aclr : IN STD_LOGIC := '0'; + data : IN STD_LOGIC_VECTOR (31 DOWNTO 0); + rdclk : IN STD_LOGIC ; + 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 + ); +end component; diff --git a/fpga/megacells/fifo_512.inc b/fpga/megacells/fifo_512.inc new file mode 100755 index 0000000..9ae1e3a --- /dev/null +++ b/fpga/megacells/fifo_512.inc @@ -0,0 +1,32 @@ +--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_512 +( + aclr, + data[31..0], + rdclk, + rdreq, + wrclk, + wrreq +) + +RETURNS ( + q[31..0], + rdempty, + rdfull, + wrempty, + wrfull +); diff --git a/fpga/megacells/fifo_512.v b/fpga/megacells/fifo_512.v new file mode 100755 index 0000000..b034b4d --- /dev/null +++ b/fpga/megacells/fifo_512.v @@ -0,0 +1,180 @@ +// megafunction wizard: %LPM_FIFO+% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: dcfifo + +// ============================================================ +// File Name: fifo_512.v +// Megafunction Name(s): +// dcfifo +// ============================================================ +// ************************************************************ +// 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_512 ( + aclr, + data, + rdclk, + rdreq, + wrclk, + wrreq, + q, + rdempty, + rdfull, + wrempty, + wrfull); + + input aclr; + input [31:0] data; + input rdclk; + input rdreq; + input wrclk; + input wrreq; + output [31:0] q; + output rdempty; + output rdfull; + output wrempty; + output wrfull; + + wire sub_wire0; + wire sub_wire1; + wire 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]; + + dcfifo dcfifo_component ( + .wrclk (wrclk), + .rdreq (rdreq), + .aclr (aclr), + .rdclk (rdclk), + .wrreq (wrreq), + .data (data), + .rdfull (sub_wire0), + .rdempty (sub_wire1), + .wrfull (sub_wire2), + .wrempty (sub_wire3), + .q (sub_wire4) + // synopsys translate_off + , + .rdusedw (), + .wrusedw () + // 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"; + + +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 "4" +// Retrieval info: PRIVATE: Depth NUMERIC "128" +// 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 "32" +// Retrieval info: PRIVATE: dc_aclr NUMERIC "1" +// Retrieval info: PRIVATE: rsEmpty NUMERIC "1" +// Retrieval info: PRIVATE: rsFull NUMERIC "1" +// Retrieval info: PRIVATE: rsUsedW NUMERIC "0" +// Retrieval info: PRIVATE: sc_aclr NUMERIC "0" +// Retrieval info: PRIVATE: sc_sclr NUMERIC "0" +// Retrieval info: PRIVATE: wsEmpty NUMERIC "1" +// 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_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: 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: 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: 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: @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: @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 diff --git a/fpga/megacells/fifo_512_bb.v b/fpga/megacells/fifo_512_bb.v new file mode 100755 index 0000000..b118031 --- /dev/null +++ b/fpga/megacells/fifo_512_bb.v @@ -0,0 +1,131 @@ +// megafunction wizard: %LPM_FIFO+%VBB% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: dcfifo + +// ============================================================ +// File Name: fifo_512.v +// Megafunction Name(s): +// dcfifo +// ============================================================ +// ************************************************************ +// 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_512 ( + aclr, + data, + rdclk, + rdreq, + wrclk, + wrreq, + q, + rdempty, + rdfull, + wrempty, + wrfull); + + input aclr; + input [31:0] data; + input rdclk; + input rdreq; + input wrclk; + input wrreq; + output [31:0] q; + output rdempty; + output rdfull; + output wrempty; + output wrfull; + +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 "4" +// Retrieval info: PRIVATE: Depth NUMERIC "128" +// 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 "32" +// Retrieval info: PRIVATE: dc_aclr NUMERIC "1" +// Retrieval info: PRIVATE: rsEmpty NUMERIC "1" +// Retrieval info: PRIVATE: rsFull NUMERIC "1" +// Retrieval info: PRIVATE: rsUsedW NUMERIC "0" +// Retrieval info: PRIVATE: sc_aclr NUMERIC "0" +// Retrieval info: PRIVATE: sc_sclr NUMERIC "0" +// Retrieval info: PRIVATE: wsEmpty NUMERIC "1" +// 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_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: 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: 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: 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: @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: @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 diff --git a/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.qsf b/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.qsf index 2646d83..8296a45 100644 --- a/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.qsf +++ b/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.qsf @@ -27,7 +27,7 @@ # ======================== set_global_assignment -name ORIGINAL_QUARTUS_VERSION 3.0 set_global_assignment -name PROJECT_CREATION_TIME_DATE "00:14:04 JULY 13, 2003" -set_global_assignment -name LAST_QUARTUS_VERSION 6.1 +set_global_assignment -name LAST_QUARTUS_VERSION "5.1 SP1" # Pin & Location Assignments # ========================== @@ -371,6 +371,13 @@ 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/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 set_global_assignment -name VERILOG_FILE ../../megacells/fifo_4k.v @@ -405,5 +412,4 @@ 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 -set_global_assignment -name FITTER_AUTO_EFFORT_DESIRED_SLACK_MARGIN "100 ps" \ No newline at end of file +set_global_assignment -name VERILOG_FILE ../../sdr_lib/sign_extend.v \ No newline at end of file diff --git a/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.v b/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.v index 55701b8..cc7490c 100644 --- a/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.v +++ b/fpga/toplevel/usrp_inband_usb/usrp_inband_usb.v @@ -19,6 +19,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA // +`define IN_BAND `include "config.vh" `include "../../../firmware/include/fpga_regs_common.v" @@ -122,6 +123,20 @@ module usrp_inband_usb assign bb_tx_i1 = ch2tx; assign bb_tx_q1 = ch3tx; +`ifdef 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), + .channels({tx_numchan,1'b0}), + .tx_i_0(ch0tx),.tx_q_0(ch1tx), + .tx_i_1(ch2tx),.tx_q_1(ch3tx), + .tx_i_2(),.tx_q_2(), + .tx_i_3(),.tx_q_3(), + .txclk(clk64),.txstrobe(strobe_interp), + .clear_status(clear_status), + .tx_empty(tx_empty), + .debugbus(tx_debugbus) ); +`else tx_buffer 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), @@ -134,6 +149,7 @@ module usrp_inband_usb .clear_status(clear_status), .tx_empty(tx_empty), .debugbus(tx_debugbus) ); +`endif `ifdef TX_EN_0 tx_chain tx_chain_0 diff --git a/host/apps/Makefile.am b/host/apps/Makefile.am index 8e0768e..035a23a 100644 --- a/host/apps/Makefile.am +++ b/host/apps/Makefile.am @@ -23,8 +23,6 @@ include $(top_srcdir)/Makefile.common INCLUDES = $(USRP_INCLUDES) $(BOOST_CFLAGS) -USRP_LIB = $(top_builddir)/usrp/host/lib/libusrp.la - bin_PROGRAMS = \ usrper \ usrp_cal_dc_offset @@ -45,13 +43,13 @@ noinst_PYTHON = \ check_order_quickly_SOURCES = check_order_quickly.cc test_usrp_standard_rx_SOURCES = test_usrp_standard_rx.cc time_stuff.c -test_usrp_standard_rx_LDADD = $(USRP_LIB) +test_usrp_standard_rx_LDADD = $(USRP_LA) test_usrp_standard_tx_SOURCES = test_usrp_standard_tx.cc time_stuff.c -test_usrp_standard_tx_LDADD = $(USRP_LIB) +test_usrp_standard_tx_LDADD = $(USRP_LA) usrper_SOURCES = usrper.cc -usrper_LDADD = $(USRP_LIB) +usrper_LDADD = $(USRP_LA) usrp_cal_dc_offset_SOURCES = usrp_cal_dc_offset.cc -usrp_cal_dc_offset_LDADD = $(USRP_LIB) +usrp_cal_dc_offset_LDADD = $(USRP_LA) diff --git a/host/lib/Makefile.am b/host/lib/Makefile.am index 7d17a38..cd37a9b 100644 --- a/host/lib/Makefile.am +++ b/host/lib/Makefile.am @@ -20,133 +20,5 @@ include $(top_srcdir)/Makefile.common -INCLUDES = $(USRP_INCLUDES) +SUBDIRS = legacy inband -lib_LTLIBRARIES = libusrp.la - - -EXTRA_DIST = \ - std_paths.h.in \ - usrp_dbid.dat - - -BUILT_SOURCES = \ - usrp_dbid.h \ - usrp_dbid.cc \ - usrp_dbid.py - - -# ---------------------------------------------------------------- -# FUSB_TECH is set at configure time by way of -# usrp/config/usrp_fusb_tech.m4. -# It indicates which fast usb strategy we should be building. -# We currently implement "generic", "darwin", "win32" and "linux" - - -generic_CODE = \ - fusb_generic.cc \ - fusb_sysconfig_generic.cc - -darwin_CODE = \ - fusb_darwin.cc \ - fusb_sysconfig_darwin.cc \ - README_OSX \ - circular_buffer.h \ - circular_linked_list.h \ - darwin_libusb.h \ - mld_threads.h - -win32_CODE = \ - fusb_win32.cc \ - fusb_sysconfig_win32.cc - -linux_CODE = \ - fusb_linux.cc \ - fusb_sysconfig_linux.cc - -ra_wb_CODE = \ - fusb_ra_wb.cc \ - fusb_sysconfig_ra_wb.cc - - -# -# include each _CODE entry here... -# -EXTRA_libusrp_la_SOURCES = \ - $(generic_CODE) \ - $(darwin_CODE) \ - $(win32_CODE) \ - $(linux_CODE) \ - $(ra_wb_CODE) - - -# work around automake deficiency -libusrp_la_common_SOURCES = \ - fusb.cc \ - md5.c \ - usrp_basic.cc \ - usrp_config.cc \ - usrp_dbid.cc \ - usrp_local_sighandler.cc \ - usrp_prims.cc \ - usrp_standard.cc - - -if FUSB_TECH_generic -libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(generic_CODE) -endif - -if FUSB_TECH_darwin -libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(darwin_CODE) -endif - -if FUSB_TECH_win32 -libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(win32_CODE) -endif - -if FUSB_TECH_linux -libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(linux_CODE) -endif - -if FUSB_TECH_ra_wb -libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(ra_wb_CODE) -endif - - -libusrp_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0 -libusrp_la_LIBADD = $(USB_LIBS) ../misc/libmisc.la - -include_HEADERS = \ - usrp_basic.h \ - usrp_bytesex.h \ - usrp_config.h \ - usrp_dbid.h \ - usrp_prims.h \ - usrp_slots.h \ - usrp_standard.h - -noinst_HEADERS = \ - ad9862.h \ - fusb.h \ - fusb_darwin.h \ - fusb_win32.h \ - fusb_generic.h \ - fusb_linux.h \ - fusb_ra_wb.h \ - md5.h \ - rate_to_regval.h \ - usrp_local_sighandler.h - -usrppython_PYTHON = \ - usrp_dbid.py - -noinst_PYTHON = \ - gen_usrp_dbid.py \ - check_data.py \ - dump_data.py - -usrp_dbid.py usrp_dbid.h usrp_dbid.cc: gen_usrp_dbid.py usrp_dbid.dat - PYTHONPATH=$(top_srcdir)/usrp/src srcdir=$(srcdir) $(PYTHON) $(srcdir)/gen_usrp_dbid.py $(srcdir)/usrp_dbid.dat - -MOSTLYCLEANFILES = \ - $(BUILT_SOURCES) *~ *.pyc diff --git a/host/lib/dxc-io-assignments.gnumeric b/host/lib/dxc-io-assignments.gnumeric deleted file mode 100644 index 85e1a88..0000000 Binary files a/host/lib/dxc-io-assignments.gnumeric and /dev/null differ diff --git a/host/lib/inband/Makefile.am b/host/lib/inband/Makefile.am new file mode 100644 index 0000000..9f6a7ab --- /dev/null +++ b/host/lib/inband/Makefile.am @@ -0,0 +1,92 @@ +# +# 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. +# + +include $(top_srcdir)/Makefile.common + +INCLUDES = \ + $(DEFINES) $(OMNITHREAD_INCLUDES) $(PMT_INCLUDES) $(MBLOCK_INCLUDES) \ + $(USRP_INCLUDES) $(BOOST_CFLAGS) $(CPPUNIT_INCLUDES) + +TESTS = test_inband + +EXTRA_DIST = + +lib_LTLIBRARIES = \ + libusrp_inband.la \ + libusrp_inband-qa.la + + +# ------------------------------------------------------------------------ +# Build the inband library + +BUILT_SOURCES = \ + usrp_server_mbh.cc + +usrp_server_mbh.cc : usrp_server.mbh + $(COMPILE_MBH) usrp_server.mbh usrp_server_mbh.cc + +libusrp_inband_la_SOURCES = \ + $(BUILT_SOURCES) \ + usrp_server.cc + +libusrp_inband_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0 + +libusrp_inband_la_LIBADD = \ + $(MBLOCK_LA) \ + -lstdc++ + + +include_HEADERS = \ + usrp_server.h + +noinst_HEADERS = \ + qa_inband.h \ + qa_inband_packet_prims.h \ + qa_inband_usrp_server.h + +# ------------------------------------------------------------------------ +# Build the qa code in its own library + +libusrp_inband_qa_la_SOURCES = \ + qa_inband.cc \ + qa_inband_packet_prims.cc \ + qa_inband_usrp_server.cc + +# magic flags +libusrp_inband_qa_la_LDFLAGS = $(NO_UNDEFINED) -avoid-version + +# link against c++ standard library +libusrp_inband_qa_la_LIBADD = \ + libusrp_inband.la \ + $(CPPUNIT_LIBS) \ + -lstdc++ + +# ------------------------------------------------------------------------ + +noinst_PROGRAMS = \ + test_inband + +test_inband_SOURCES = test_inband.cc +test_inband_LDADD = libusrp_inband-qa.la + + +MOSTLYCLEANFILES = \ + $(BUILT_SOURCES) *~ *.pyc + diff --git a/host/lib/inband/dump_packets.py b/host/lib/inband/dump_packets.py new file mode 100755 index 0000000..ea27ca5 --- /dev/null +++ b/host/lib/inband/dump_packets.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# +# 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. +# + +import sys +import struct +from optparse import OptionParser + +from usb_packet import * + +def dump_packet(raw_pkt, outfile, dump_payload): + pkt = usb_packet(raw_pkt) + outfile.write(pkt.decoded_flags()) + outfile.write(' chan= %2d len= %3d timestamp= 0x%08x rssi= % 2d tag= %2d\n' % ( + pkt.chan(), pkt.payload_len(), pkt.timestamp(), pkt.rssi(), pkt.tag())) + if dump_payload: + assert pkt.payload_len() % 4 == 0 + shorts = struct.unpack('<%dh' % (pkt.payload_len() // 2), pkt.payload()) + for i in range(0, len(shorts), 2): + outfile.write(' %6d, %6d\n' % (shorts[i], shorts[i+1])) + + +def dump_packets(infile, outfile, dump_payload): + raw_pkt = infile.read(512) + while raw_pkt: + if len(raw_pkt) != 512: + sys.stderr.write("File length is not a multiple of 512 bytes") + raise SystemExit, 1 + + dump_packet(raw_pkt, outfile, dump_payload) + raw_pkt = infile.read(512) + + +def main(): + parser = OptionParser() + parser.add_option('-p', '--dump-payload', action='store_true', default=False, + help='dump payload in decimal and hex') + + (options, files) = parser.parse_args() + if len(files) == 0: + dump_packets(sys.stdin, sys.stdout, options.dump_payload) + else: + for f in files: + dump_packets(open(f, "r"), sys.stdout, options.dump_payload) + + +if __name__ == '__main__': + main() diff --git a/host/lib/inband/gen_test_packets.py b/host/lib/inband/gen_test_packets.py new file mode 100755 index 0000000..1e22722 --- /dev/null +++ b/host/lib/inband/gen_test_packets.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python + +import random +import struct +from pprint import pprint +from usb_packet import * + +MAX_PAYLOAD = 504 +TIME_NOW = 0xffffffff + + +class sequence_generator(object): + def __init__(self): + self.i = 0 + + def __call__(self): + t = self.i + self.i += 1 + return t + +def gen_shuffled_lengths(): + valid_lengths = range(0, MAX_PAYLOAD+1, 4) # [0, 4, 8, ... 504] + random.shuffle(valid_lengths) + return valid_lengths + + +class packet_sequence_generator(object): + def __init__(self, channel, lengths): + self.next = sequence_generator() + self.channel = channel + self.lengths = lengths + + def __call__(self, output_file): + gen_packet(output_file, self.channel, self.next, self.lengths[0]) + del self.lengths[0] + + +def gen_packet(output_file, channel, content_generator, payload_len): + assert (payload_len % 4) == 0 + payload = [] + n_iq = payload_len // 4 + for n in range(n_iq): + payload.append(content_generator()) # I + payload.append(content_generator()) # Q + for n in range(MAX_PAYLOAD // 4 - n_iq): + payload.append(0x0000) + payload.append(0xffff) + + assert (len(payload) == MAX_PAYLOAD // 2) + + #print "\npayload_len =", payload_len + #pprint(payload) + + output_file.write(make_header(FL_START_OF_BURST|FL_END_OF_BURST, + channel, payload_len, TIME_NOW)) + output_file.write(struct.pack('<252h', *payload)) + + +def gen_all_valid_packet_lengths_1_channel(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) + for i in range(npkts): + pkt_gen_0(output_file) + + assert pkt_gen_0.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127 + + +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 = (pkt_gen_0, pkt_gen_1) + + which_gen = (npkts * [0]) + (npkts * [1]) + random.shuffle(which_gen) + + for i in which_gen: + pkt_gen[i](output_file) + + assert pkt_gen_0.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127 + assert pkt_gen_1.next() == 16002 # 2*sum(1, 2, ..., 126) == 126 * 127 + +if __name__ == '__main__': + 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/host/lib/inband/qa_inband.cc b/host/lib/inband/qa_inband.cc new file mode 100644 index 0000000..00a821f --- /dev/null +++ b/host/lib/inband/qa_inband.cc @@ -0,0 +1,35 @@ +/* -*- 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 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. + */ + +#include +#include +#include + +CppUnit::TestSuite * +qa_inband::suite() +{ + CppUnit::TestSuite *s = new CppUnit::TestSuite("inband"); + + s->addTest (qa_inband_packet_prims::suite()); + s->addTest (qa_inband_usrp_server::suite()); + + return s; +} diff --git a/host/lib/inband/qa_inband.h b/host/lib/inband/qa_inband.h new file mode 100644 index 0000000..92386f9 --- /dev/null +++ b/host/lib/inband/qa_inband.h @@ -0,0 +1,35 @@ +/* -*- 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 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. + */ + +#ifndef INCLUDED_QA_INBAND_H +#define INCLUDED_QA_INBAND_H + +#include + +//! collect all the tests for the user server + +class qa_inband { + public: + //! return suite of tests for all of usrp server + static CppUnit::TestSuite *suite(); +}; + +#endif /* INCLUDED_QA_INBAND_H */ diff --git a/host/lib/inband/qa_inband_packet_prims.cc b/host/lib/inband/qa_inband_packet_prims.cc new file mode 100644 index 0000000..9d9a0c7 --- /dev/null +++ b/host/lib/inband/qa_inband_packet_prims.cc @@ -0,0 +1,161 @@ +/* -*- 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 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include // will change on gigabit crossover + +typedef usrp_inband_usb_packet transport_pkt; + +void +qa_inband_packet_prims::test_flags() +{ + transport_pkt pkt; + + // Test each one of the flags while ensuring no other fields become set in the process + pkt.set_header(pkt.FL_START_OF_BURST,0,0,0); + CPPUNIT_ASSERT_EQUAL(1, pkt.start_of_burst()); + CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst()); + CPPUNIT_ASSERT_EQUAL(0, pkt.overrun()); + CPPUNIT_ASSERT_EQUAL(0, pkt.underrun()); + CPPUNIT_ASSERT_EQUAL(0, pkt.dropped()); + CPPUNIT_ASSERT_EQUAL(0, pkt.chan()); + CPPUNIT_ASSERT_EQUAL(0, pkt.tag()); + CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len()); + + pkt.set_header(pkt.FL_END_OF_BURST,0,0,0); + CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst()); + CPPUNIT_ASSERT_EQUAL(1, pkt.end_of_burst()); + CPPUNIT_ASSERT_EQUAL(0, pkt.overrun()); + CPPUNIT_ASSERT_EQUAL(0, pkt.underrun()); + CPPUNIT_ASSERT_EQUAL(0, pkt.dropped()); + CPPUNIT_ASSERT_EQUAL(0, pkt.chan()); + CPPUNIT_ASSERT_EQUAL(0, pkt.tag()); + CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len()); + + pkt.set_header(pkt.FL_OVERRUN,0,0,0); + CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst()); + CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst()); + CPPUNIT_ASSERT_EQUAL(1, pkt.overrun()); + CPPUNIT_ASSERT_EQUAL(0, pkt.underrun()); + CPPUNIT_ASSERT_EQUAL(0, pkt.dropped()); + CPPUNIT_ASSERT_EQUAL(0, pkt.chan()); + CPPUNIT_ASSERT_EQUAL(0, pkt.tag()); + CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len()); + + pkt.set_header(pkt.FL_UNDERRUN,0,0,0); + CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst()); + CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst()); + CPPUNIT_ASSERT_EQUAL(0, pkt.overrun()); + CPPUNIT_ASSERT_EQUAL(1, pkt.underrun()); + CPPUNIT_ASSERT_EQUAL(0, pkt.dropped()); + CPPUNIT_ASSERT_EQUAL(0, pkt.chan()); + CPPUNIT_ASSERT_EQUAL(0, pkt.tag()); + CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len()); + + pkt.set_header(pkt.FL_DROPPED,0,0,0); + CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst()); + CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst()); + CPPUNIT_ASSERT_EQUAL(0, pkt.overrun()); + CPPUNIT_ASSERT_EQUAL(0, pkt.underrun()); + CPPUNIT_ASSERT_EQUAL(1, pkt.dropped()); + CPPUNIT_ASSERT_EQUAL(0, pkt.chan()); + CPPUNIT_ASSERT_EQUAL(0, pkt.tag()); + CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len()); + + // test of all fields set + pkt.set_header( + pkt.FL_START_OF_BURST | + pkt.FL_END_OF_BURST | + pkt.FL_UNDERRUN | + pkt.FL_OVERRUN | + pkt.FL_DROPPED + ,0,0,0); + CPPUNIT_ASSERT_EQUAL(1, pkt.start_of_burst()); + CPPUNIT_ASSERT_EQUAL(1, pkt.end_of_burst()); + CPPUNIT_ASSERT_EQUAL(1, pkt.overrun()); + CPPUNIT_ASSERT_EQUAL(1, pkt.underrun()); + CPPUNIT_ASSERT_EQUAL(1, pkt.dropped()); + CPPUNIT_ASSERT_EQUAL(0, pkt.chan()); + CPPUNIT_ASSERT_EQUAL(0, pkt.tag()); + CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len()); + + +} +////////////////////////////////////////////////////////////////////// + +void +qa_inband_packet_prims::test_fields() +{ + transport_pkt pkt; + void * payload; + + // test word0 field exclusiveness + // + // I want to test max values of each field to ensure field boundaries + // but these max values could change based on technology? The + // max payload is returned by a private method so the code is not + // technology dependent + pkt.set_header(0,16,0,0); + CPPUNIT_ASSERT_EQUAL(16, pkt.chan()); + CPPUNIT_ASSERT_EQUAL(0, pkt.tag()); + CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len()); + + pkt.set_header(0,0,8,0); + CPPUNIT_ASSERT_EQUAL(0, pkt.chan()); + CPPUNIT_ASSERT_EQUAL(8, pkt.tag()); + CPPUNIT_ASSERT_EQUAL(0,pkt.payload_len()); + + pkt.set_header(0,0,0,pkt.max_payload()); + CPPUNIT_ASSERT_EQUAL(0, pkt.chan()); + CPPUNIT_ASSERT_EQUAL(0, pkt.tag()); + CPPUNIT_ASSERT_EQUAL(pkt.max_payload(), pkt.payload_len()); + + // test timestamp, shouldn't have to test other fields since + // setting the timestamp only has the ability to affect one word + pkt.set_timestamp(54); + CPPUNIT_ASSERT_EQUAL(uint32_t(54), pkt.timestamp()); + + // test the payload, ensure no other fields overwritten + // + // is there a better test for this? + pkt.set_header(0,0,0,0); + payload = malloc(pkt.payload_len()); + memset(payload, 'f', pkt.payload_len()); + memcpy(pkt.payload(), payload, pkt.payload_len()); + CPPUNIT_ASSERT_EQUAL(0, memcmp(pkt.payload(), payload, pkt.payload_len())); + CPPUNIT_ASSERT_EQUAL(0, pkt.start_of_burst()); + CPPUNIT_ASSERT_EQUAL(0, pkt.end_of_burst()); + CPPUNIT_ASSERT_EQUAL(0, pkt.overrun()); + CPPUNIT_ASSERT_EQUAL(0, pkt.underrun()); + CPPUNIT_ASSERT_EQUAL(0, pkt.dropped()); + CPPUNIT_ASSERT_EQUAL(0, pkt.chan()); + CPPUNIT_ASSERT_EQUAL(0, pkt.tag()); + CPPUNIT_ASSERT_EQUAL(0, pkt.payload_len()); + free(payload); + +} +////////////////////////////////////////////////////////////////////// diff --git a/host/lib/inband/qa_inband_packet_prims.h b/host/lib/inband/qa_inband_packet_prims.h new file mode 100644 index 0000000..5e60c60 --- /dev/null +++ b/host/lib/inband/qa_inband_packet_prims.h @@ -0,0 +1,41 @@ +/* -*- 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 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. + */ + +#ifndef QA_INBAND_PACKET_PRIMS_H +#define QA_INBAND_PACKET_PRIMS_H + +#include +#include + +class qa_inband_packet_prims : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE(qa_inband_packet_prims); + CPPUNIT_TEST(test_flags); + CPPUNIT_TEST(test_fields); + CPPUNIT_TEST_SUITE_END(); + + private: + void test_flags(); + void test_fields(); + +}; + +#endif /* INCLUDED_QA_INBAND_PACKET_PRIMS_H */ diff --git a/host/lib/inband/qa_inband_usrp_server.cc b/host/lib/inband/qa_inband_usrp_server.cc new file mode 100644 index 0000000..2885a4d --- /dev/null +++ b/host/lib/inband/qa_inband_usrp_server.cc @@ -0,0 +1,455 @@ +/* -*- 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 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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"); + + +// ---------------------------------------------------------------------------------------------- + +class qa_alloc_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_alloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~qa_alloc_top(); + void initial_transition(); + void handle_message(mb_message_sptr msg); + + protected: + void check_message(mb_message_sptr msg); + void run_tests(); +}; + +qa_alloc_top::qa_alloc_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 = 7; + d_nstatus=0; + d_nstatus_to_recv = 3; + + 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); + + // Test the TX side + define_component("server", "usrp_server", PMT_F); + connect("self", "tx0", "server", "tx0"); + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); + +} + +qa_alloc_top::~qa_alloc_top(){} + +void +qa_alloc_top::initial_transition() +{ + // 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)); +} + +void +qa_alloc_top::run_tests() +{ + 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))); + + // 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))); + + // 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++) { + 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))); + + // 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))); + + 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))); +} + +void +qa_alloc_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_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"; + } + 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"; + } + 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"; + } + else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) { + check_message(msg); + } + + d_nstatus++; + + if(d_nstatus==d_nstatus_to_recv) + run_tests(); + } +} + +void +qa_alloc_top::check_message(mb_message_sptr msg) +{ + pmt_t data = msg->data(); + + pmt_t expected_result = pmt_nth(0, data); + pmt_t result = pmt_nth(1, data); + + d_nrecvd++; + + + if(!pmt_eqv(expected_result, result)) { + std::cout << "Got: " << result << " Expected: " << expected_result << "\n"; + shutdown_all(PMT_F); + } else { + std::cout << "[qa_alloc_top] Received expected response for message " << d_nrecvd << "\n"; + } + + if(d_nrecvd == d_nmsgs_to_recv) + shutdown_all(PMT_T); +} + +REGISTER_MBLOCK_CLASS(qa_alloc_top); + +// ---------------------------------------------------------------------------------------------- + +class qa_dealloc_top : public mb_mblock +{ + mb_port_sptr d_tx; + mb_port_sptr d_rx; + mb_port_sptr d_cs; + + long d_max_capacity; + long d_ntx_chan, d_nrx_chan; + + long d_nstatus; + long d_nstatus_to_recv; + + long d_nalloc_to_recv; + long d_nalloc_recvd; + + long d_ndealloc_to_recv; + long d_ndealloc_recvd; + + std::vector d_tx_chans; + std::vector d_rx_chans; + + public: + qa_dealloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); + ~qa_dealloc_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 allocate_max(); + void deallocate_all(); +}; + +qa_dealloc_top::qa_dealloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(runtime, instance_name, user_arg) +{ + d_ndealloc_recvd=0; + d_ndealloc_to_recv = 0; + d_nalloc_recvd=0; + d_nalloc_to_recv = 0; + d_nstatus=0; + d_nstatus_to_recv = 3; + + 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); + + // Test the TX side + define_component("server", "usrp_server", PMT_F); + connect("self", "tx0", "server", "tx0"); + connect("self", "rx0", "server", "rx0"); + connect("self", "cs", "server", "cs"); +} + +qa_dealloc_top::~qa_dealloc_top(){} + +void +qa_dealloc_top::initial_transition() +{ + // 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)); +} + +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_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_nalloc_to_recv++; + } +} + +void +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]))); + d_ndealloc_to_recv++; + } + 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]))); + 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 + 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_ndealloc_to_recv++; + } + 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_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 + 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))); + + + // 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))); +} + +void +qa_dealloc_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())) { + + if(pmt_eq(msg->signal(), s_response_allocate_channel)) { + 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"; + } + 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"; + } + 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"; + } + 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); + + if(pmt_eqv(expected_result, result)) + shutdown_all(PMT_T); + else + shutdown_all(PMT_F); + } + + d_nstatus++; + + if(d_nstatus==d_nstatus_to_recv) + allocate_max(); + } +} + +void +qa_dealloc_top::check_deallocation(mb_message_sptr msg) +{ + pmt_t data = msg->data(); + + pmt_t expected_result = pmt_nth(0, data); + pmt_t result = pmt_nth(1, data); + + d_ndealloc_recvd++; + + if(!pmt_eqv(expected_result, result)) { + std::cout << "Got: " << result << " Expected: " << expected_result << "\n"; + shutdown_all(PMT_F); + } else { + std::cout << "[qa_dealloc_top] Received expected deallocation response for message " << d_ndealloc_recvd << "\n"; + } +} + +void +qa_dealloc_top::check_allocation(mb_message_sptr msg) +{ + pmt_t data = msg->data(); + + pmt_t invocation_handle = pmt_nth(0, data); + pmt_t status = pmt_nth(1, data); + pmt_t channel = pmt_nth(2, data); + + d_nalloc_recvd++; + + if(pmt_eqv(status, PMT_F)) { + std::cout << "[qa_dealloc_top] Unexpected error response when allocating channels\n"; + shutdown_all(PMT_F); + } else { + // 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) { + + 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); + +// ---------------------------------------------------------------------------------------------- + +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); + + CPPUNIT_ASSERT(pmt_equal(PMT_T, result)); +} + +void +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); + + CPPUNIT_ASSERT(pmt_equal(PMT_T, result)); +} + +void +qa_inband_usrp_server::test_fragmentation() +{ + +} diff --git a/host/lib/inband/qa_inband_usrp_server.h b/host/lib/inband/qa_inband_usrp_server.h new file mode 100644 index 0000000..eb0f7a3 --- /dev/null +++ b/host/lib/inband/qa_inband_usrp_server.h @@ -0,0 +1,42 @@ +/* -*- 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 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. + */ + +#ifndef QA_INBAND_USRP_SERVER_H +#define QA_INBAND_USRP_SERVER_H + +#include +#include + +class qa_inband_usrp_server : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE(qa_inband_usrp_server); + CPPUNIT_TEST(test_chan_allocation); + CPPUNIT_TEST(test_chan_deallocation); + CPPUNIT_TEST(test_fragmentation); + CPPUNIT_TEST_SUITE_END(); + + private: + void test_chan_allocation(); + void test_chan_deallocation(); + void test_fragmentation(); +}; + +#endif /* INCLUDED_QA_INBAND_USRP_SERVER_H */ diff --git a/host/lib/inband/test_inband.cc b/host/lib/inband/test_inband.cc new file mode 100644 index 0000000..49619be --- /dev/null +++ b/host/lib/inband/test_inband.cc @@ -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 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. + */ + +#include +#include + +int +main(int argc, char **argv) +{ + + CppUnit::TextTestRunner runner; + + runner.addTest(qa_inband::suite ()); + + bool was_successful = runner.run("", false); + + return was_successful ? 0 : 1; +} diff --git a/host/lib/inband/usb_packet.py b/host/lib/inband/usb_packet.py new file mode 100644 index 0000000..5ca19b7 --- /dev/null +++ b/host/lib/inband/usb_packet.py @@ -0,0 +1,115 @@ +# +# 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. +# + +import struct + + +FL_OVERRUN = 0x80000000 +FL_UNDERRUN = 0x40000000 +FL_DROPPED = 0x20000000 +FL_END_OF_BURST = 0x10000000 +FL_START_OF_BURST = 0x08000000 + +FL_ALL_FLAGS = 0xf8000000 + +FL_OVERRUN_SHIFT = 31 +FL_UNDERRUN_SHIFT = 30 +FL_DROPPED_SHIFT = 29 +FL_END_OF_BURST_SHIFT = 28 +FL_START_OF_BURST_SHIFT = 27 + +RSSI_MASK = 0x3f +RSSI_SHIFT = 21 + +CHAN_MASK = 0x1f +CHAN_SHIFT = 16 + +TAG_MASK = 0xf +TAG_SHIFT = 9 + +PAYLOAD_LEN_MASK = 0x1ff +PAYLOAD_LEN_SHIFT = 0 + +def make_header(flags, chan, payload_len, timestamp, rssi=0, tag=0): + word0 = ((flags & FL_ALL_FLAGS) + | ((rssi & RSSI_MASK) << RSSI_SHIFT) + | ((chan & CHAN_MASK) << CHAN_SHIFT) + | ((tag & TAG_MASK) << TAG_SHIFT) + | ((payload_len & PAYLOAD_LEN_MASK) << PAYLOAD_LEN_SHIFT)) + word1 = timestamp + return struct.pack('<2I', word0, word1) + + +def _decode(pred, indicator): + if pred: + return indicator + else: + return '-' + + +class usb_packet(object): + def __init__(self, raw_pkt): + assert isinstance(raw_pkt, str) and len(raw_pkt) == 512 + self._raw_pkt = raw_pkt; + (self._word0, self._word1) = struct.unpack('<2I', self._raw_pkt[0:8]) + + def timestamp(self): + return self._word1 + + def rssi(self): + return (self._word0 >> RSSI_SHIFT) & RSSI_MASK + + def chan(self): + return (self._word0 >> CHAN_SHIFT) & CHAN_MASK + + def tag(self): + return (self._word0 >> TAG_SHIFT) & TAG_MASK + + def payload_len(self): + return (self._word0 >> PAYLOAD_LEN_SHIFT) & PAYLOAD_LEN_MASK + + def flags(self): + return self._word0 & FL_ALL_FLAGS + + def overrun(self): + return (self._word0 >> FL_OVERRUN_SHIFT) & 0x1 + + def underrun(self): + return (self._word0 >> FL_UNDERRUN_SHIFT) & 0x1 + + def start_of_burst(self): + return (self._word0 >> FL_START_OF_BURST_SHIFT) & 0x1 + + def end_of_burst(self): + return (self._word0 >> FL_END_OF_BURST_SHIFT) & 0x1 + + def dropped(self): + return (self._word0 >> FL_DROPPED_SHIFT) & 0x1 + + def payload(self): + return self._raw_pkt[8:8+self.payload_len()] + + def decoded_flags(self): + s = (_decode(self.overrun(), 'O') + + _decode(self.underrun(), 'U') + + _decode(self.dropped(), 'D') + + _decode(self.end_of_burst(), 'E') + + _decode(self.start_of_burst(), 'S')) + return s diff --git a/host/lib/inband/usrp_inband_usb_packet.h b/host/lib/inband/usrp_inband_usb_packet.h new file mode 100644 index 0000000..471bfc6 --- /dev/null +++ b/host/lib/inband/usrp_inband_usb_packet.h @@ -0,0 +1,149 @@ +/* -*- 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 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. + */ + +#ifndef INCLUDED_USRP_INBAND_USB_PACKET_H_ +#define INCLUDED_USRP_INBAND_USB_PACKET_H_ + +#include +#include + +static const int USB_PKT_SIZE = 512; // bytes +static const int MAX_PAYLOAD = USB_PKT_SIZE-2*sizeof(uint32_t); + +class usrp_inband_usb_packet { + // + // keep raw packet in USRP-endian order + // + uint32_t d_word0; + uint32_t d_timestamp; + unsigned char d_payload[MAX_PAYLOAD]; + +public: + + enum flags { + FL_OVERRUN = 0x80000000, + FL_UNDERRUN = 0x40000000, + FL_DROPPED = 0x20000000, + FL_END_OF_BURST = 0x10000000, + FL_START_OF_BURST = 0x08000000, + + FL_ALL_FLAGS = 0xf8000000 + }; + + 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 RSSI_MASK = 0x3f; + static const int RSSI_SHIFT = 21; + + static const int CHAN_MASK = 0x1f; + static const int CHAN_SHIFT = 16; + + static const int TAG_MASK = 0xf; + static const int TAG_SHIFT = 9; + + static const int PAYLOAD_LEN_MASK = 0x1ff; + static const int PAYLOAD_LEN_SHIFT = 0; + +public: + + void set_timestamp(uint32_t timestamp){ + d_timestamp = host_to_usrp_u32(timestamp); + } + + void set_end_of_burst() { + uint32_t word0 = usrp_to_host_u32(d_word0); + word0 |= 1<> RSSI_SHIFT) & RSSI_MASK; + } + + int chan() const { + uint32_t word0 = usrp_to_host_u32(d_word0); + return (word0 >> CHAN_SHIFT) & CHAN_MASK; + } + + int tag() const { + uint32_t word0 = usrp_to_host_u32(d_word0); + return (word0 >> TAG_SHIFT) & TAG_MASK; + } + + int payload_len() const { + uint32_t word0 = usrp_to_host_u32(d_word0); + return (word0 >> PAYLOAD_LEN_SHIFT) & PAYLOAD_LEN_MASK; + } + + int flags() const { + return usrp_to_host_u32(d_word0) & FL_ALL_FLAGS; + } + + int overrun() const { + return (usrp_to_host_u32(d_word0) & FL_OVERRUN) >> FL_OVERRUN_SHIFT; + } + + + int underrun() const { + return (usrp_to_host_u32(d_word0) & FL_UNDERRUN) >> FL_UNDERRUN_SHIFT; + } + + + int start_of_burst() const { + return (usrp_to_host_u32(d_word0) & FL_START_OF_BURST) >> FL_START_OF_BURST_SHIFT; + } + + int end_of_burst() const { + return (usrp_to_host_u32(d_word0) & FL_END_OF_BURST) >> FL_END_OF_BURST_SHIFT; + } + + int dropped() const { + return (usrp_to_host_u32(d_word0) & FL_DROPPED) >> FL_DROPPED_SHIFT; + } + + unsigned char *payload() { + return d_payload; + } + + static int max_payload() { + return MAX_PAYLOAD; + } + +}; + +#endif diff --git a/host/lib/inband/usrp_server.cc b/host/lib/inband/usrp_server.cc new file mode 100644 index 0000000..5041a92 --- /dev/null +++ b/host/lib/inband/usrp_server.cc @@ -0,0 +1,394 @@ +/* -*- 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 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include + +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"); + +static std::string +str(long x) +{ + std::ostringstream s; + s << x; + return s.str(); +} + +usrp_server::usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg) + : mb_mblock(rt, instance_name, user_arg) +{ + // define our ports + + // control & status port + d_cs = define_port("cs", "usrp-server-cs", true, mb_port::EXTERNAL); + + // 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)); + } + + // FIXME ... initializing to 2 channels on each for now, eventually we should + // query the FPGA to get these values + d_ntx_chan = 2; + d_nrx_chan = 2; + + // Initialize capacity on each channel to 0 and to no owner + 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; + } +} + +usrp_server::~usrp_server() +{ +} + + +void +usrp_server::initial_transition() +{ + // the initial transition +} + +void +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 status; + + if (1){ + 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) + + if (pmt_eq(port_id, d_cs->port_symbol())){ // message came in on our control/status port + + 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 + + // Do the right thing.... + // build a reply + + // if everything OK + status = PMT_T; + reply_data = pmt_list2(invocation_handle, status); + + // ...and send it + d_cs->send(s_response_open, reply_data); + return; + } + else if (pmt_eq(event, s_cmd_close)){ + // ... + } + 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); + return; + } + 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); + } + 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); + } + 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); + } + goto unhandled; + } + + if (pmt_eq(event, s_cmd_allocate_channel)){ + handle_cmd_allocate_channel(port_id, data); + return; + } + + if (pmt_eq(event, s_cmd_deallocate_channel)) { + handle_cmd_deallocate_channel(port_id, data); + return; + } + + if (pmt_eq(event, s_cmd_xmit_raw_frame)){ + handle_cmd_xmit_raw_frame(data); + return; + } + + unhandled: + std::cout << "[USRP_SERVER] unhandled msg: " << msg << std::endl; +} + +// Return -1 if it is not an RX port, or an index +int usrp_server::tx_port_index(pmt_t port_id) { + + for(int i=0; i < (int) d_tx.size(); i++) + if(pmt_eq(d_tx[i]->port_symbol(), port_id)) + return i; + + return -1; +} + +// Return -1 if it is not an RX port, or an index +int usrp_server::rx_port_index(pmt_t port_id) { + + for(int i=0; i < (int) d_rx.size(); i++) + if(pmt_eq(d_rx[i]->port_symbol(), port_id)) + return i; + + return -1; +} + +// Go through all TX and RX channels, sum up the assigned capacity +// and return it +long usrp_server::current_capacity_allocation() { + long capacity = 0; + + for(int chan=0; chan < d_ntx_chan; chan++) + capacity += d_chaninfo_tx[chan].assigned_capacity; + + for(int chan=0; chan < d_nrx_chan; chan++) + capacity += d_chaninfo_rx[chan].assigned_capacity; + + return capacity; +} + +void usrp_server::handle_cmd_allocate_channel(pmt_t port_id, 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; + + // 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) { + 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; + } + + // 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; + } + } + + std::cout << "[USRP_SERVER] Couldnt find a TX chan\n"; + + 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; + } + + // 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); + 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; + } + } + + 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; + } +} + +// 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) { + + 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); + 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; + } + +} + +void usrp_server::handle_cmd_xmit_raw_frame(pmt_t data) { + + size_t n_bytes, psize; + long max_payload_len = transport_pkt::max_payload(); + + pmt_t invocation_handle = pmt_nth(0, 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)); + + // 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(std::ceil(n_bytes / (double)max_payload_len)); + pmt_t v_packets = pmt_make_u8vector(sizeof(transport_pkt) * n_packets, 0); + + transport_pkt *pkts = + (transport_pkt *) pmt_u8vector_writeable_elements(v_packets, psize); + + for(int n=0; n < n_packets; n++) { + + 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); + pkts[n].set_timestamp(timestamp); + } else { + pkts[n].set_header(0, channel, 0, payload_len); + pkts[n].set_timestamp(0xffffffff); + } + + 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 + + // 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) +} + +REGISTER_MBLOCK_CLASS(usrp_server); diff --git a/host/lib/inband/usrp_server.h b/host/lib/inband/usrp_server.h new file mode 100644 index 0000000..87c2768 --- /dev/null +++ b/host/lib/inband/usrp_server.h @@ -0,0 +1,82 @@ +/* -*- 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 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. + */ +#ifndef INCLUDED_USRP_SERVER_H +#define INCLUDED_USRP_SERVER_H + +#include +#include + +/*! + * \brief Implements the lowest-level mblock 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, + TX_PORT = 1 + }; + static const int N_PORTS = 4; + std::vector d_tx, d_rx; + mb_port_sptr d_cs; + + static const int D_USB_CAPACITY = 32 * 1024 * 1024; + static const int D_MAX_CHANNELS = 16; + long d_ntx_chan; + long d_nrx_chan; + + struct channel_info { + long assigned_capacity; // the capacity currently assignedby the channel + pmt_t owner; // port ID of the owner of the channel + }; + + struct channel_info d_chaninfo_tx[D_MAX_CHANNELS]; + struct channel_info d_chaninfo_rx[D_MAX_CHANNELS]; + +public: + usrp_server(mb_runtime *rt, const std::string &instance_name, pmt_t user_arg); + ~usrp_server(); + + void initial_transition(); + void handle_message(mb_message_sptr msg); + +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); + int rx_port_index(pmt_t port_id); + int tx_port_index(pmt_t port_id); + long current_capacity_allocation(); +}; + +#endif /* INCLUDED_USRP_SERVER_H */ diff --git a/host/lib/inband/usrp_server.mbh b/host/lib/inband/usrp_server.mbh new file mode 100644 index 0000000..97bb0e6 --- /dev/null +++ b/host/lib/inband/usrp_server.mbh @@ -0,0 +1,256 @@ +;; -*- scheme -*- ; not really, but tells emacs how to format this +;; +;; Copyright 2007 Free Software Foundation, Inc. +;; +;; This file is part of GNU Radio +;; +;; GNU Radio is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; GNU Radio is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License along +;; with this program; if not, write to the Free Software Foundation, Inc., +;; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +;; + +;; ---------------------------------------------------------------- +;; This is an mblock header file +;; +;; The format is very much a work-in-progress. +;; It'll be compiled to C++. +;; ---------------------------------------------------------------- + +;; In the outgoing messages described below, invocation-handle is an +;; identifier provided by the client to tag the method invocation. +;; The identifier will be returned with the response, to provide the +;; client with a mechanism to match asynchronous responses with the +;; commands that generate them. The value of the invocation-handle is +;; opaque the the server, and is not required by the server to be +;; unique. +;; +;; In the incoming messages described below, invocation-handle is the +;; identifier provided by the client in the prompting invocation. The +;; identifier is returned with the response, so that the client has a +;; mechanism to match asynchronous responses with the commands that +;; generated them. +;; +;; status is either #t, indicating success, or a pair containing +;; (status-code . message), where status-code is a symbol and message +;; is a string. + + +;; ---------------------------------------------------------------- +;; usrp-channel +;; +;; The protocol class is defined from the client's point-of-view. +;; (The client port is unconjugated, the server port is conjugated.) + +(define-protocol-class usrp-channel + + (:outgoing + + (cmd-allocate-channel invocation-handle capacity-reservation) + + ;; The cmd-allocate-channel message requests that the server + ;; allocates a logical channel in the FPGA for use. + ;; capacity-reservation specifies the number of bytes/s of + ;; interconnect capacity (USB or ethernet) to reserve for this + ;; channel. (The reservation is just a sanity check, no OS + ;; specific mechanism is used.) + + (cmd-deallocate-channel invocation-handle channel) + + ;; The integer channel specifies the channel to deallocate. + + ) + + (:incoming + + + (response-allocate-channel invocation-handle status channel) + + ;; If successful, a channel the specified capacity was allocated. + ;; channel, an integer, indicates which channel was allocated. + + (response-deallocate-channel invocation-handle status) + + ;; If successful, the specified channel and associated interconnect + ;; capacity were deallocated. + + ) + ) + +;; ---------------------------------------------------------------- +;; usrp-low-level-cs +;; +;; The protocol class is defined from the client's point-of-view. +;; (The client port is unconjugated, the server port is conjugated.) +;; +;; This defines a low level control and status interface to the usrp. +;; This will probably be replaced (or at least augmented) with a +;; higher level interface. For now, this will allow us to get on +;; the air. +;; +;; The subpackets are lists containing the relevant parameters. The +;; server will marshall them appropriately. Below is a list of +;; subpackets. See inband-signaling-usb for details. The opcodes are +;; symbols; unless otherwise indicated the remaining parameters are +;; integers. rid values are limited to 3-bits. +;; +;; (op-ping-fixed rid ping-value) +;; (op-ping-fixed-reply rid ping-value) +;; (op-write-reg reg-number reg-value) +;; (op-write-reg-masked reg-number reg-value mask-value) +;; (op-read-reg rid reg-number reg-value) +;; (op-read-reg-reply rid reg-number reg-value) +;; (op-i2c-write i2c-addr u8-vec) +;; (op-i2c-read rid i2c-addr nbytes) +;; (op-i2c-read-reply rid i2c-addr u8-vec) +;; (op-spi-write enables format opt-header-bytes u8-vec) +;; (op-spi-read rid enables format opt-header-bytes nbytes) +;; (op-spi-read-reply rid u8-vec) +;; (op-delay ticks) + + +(define-protocol-class usrp-low-level-cs + + (:outgoing + + (cmd-to-control-channel invocation-handle list-of-subpackets) + + ) + + (:incoming + + (response-from-control-channel invocation-handle status list-of-subpackets) + + ) + ) + +;; ---------------------------------------------------------------- +;; usrp-tx +;; +;; The protocol class is defined from the client's point-of-view. +;; (The client port is unconjugated, the server port is conjugated.) + +(define-protocol-class usrp-tx + (:include usrp-channel) + (:include usrp-low-level-cs) + + (:outgoing + + (cmd-xmit-raw-frame invocation-handle channel samples timestamp) + + ;; The argument channel must be an integer. It specifies the + ;; channel on which the frame of samples will be be sent. + ;; + ;; samples must be a uniform numeric vector. The contents of the + ;; sample vector is treated as opaque and is passed on to the FPGA + ;; unmodified. It is the responsibility of the sender to ensure + ;; that the binary format is sensible for the current FPGA + ;; configuration. + ;; + ;; timestamp is a 32-bit integer that specifies the time at which + ;; the first sample in samples shall be sent to the D/A converter. + ;; The format and interpration of time is specified in the file + ;; inband-signaling-usb + ) + + (:incoming + + (response-xmit-raw-frame invocation-handle status) + + ;; If successful, the samples of the associated frame have been + ;; transmitted to the USRP. This message may be used to implement + ;; Tx flow control. The client could for example implement a + ;; policy of never having more than 4 unacknowledged + ;; cmd-xmit-raw-frame's outstanding. + + ) + ) + +;; ---------------------------------------------------------------- +;; usrp-rx +;; +;; The protocol class is defined from the client's point-of-view. +;; (The client port is unconjugated, the server port is conjugated.) + +(define-protocol-class usrp-rx + (:include usrp-channel) + (:include usrp-low-level-cs) + + (:outgoing + + (cmd-start-recv-raw-samples invocation-handle channel) + + ;; The argument channel must be an integer. It specifies the + ;; channel from which frames of samples will be be received. The + ;; server will return response-recv-raw-samples messages until a + ;; cmd-stop-recv-raw-samples message is received. + + (cmd-stop-recv-raw-samples invocation-handle channel) + + ;; The argument channel must be an integer. There is no reply to + ;; this message. + + ) + + (:incoming + + (response-recv-raw-samples invocation-handle status samples timestamp properties) + + ;; samples is a uniform numeric vector. The contents of the sample + ;; vector is treated as opaque and is passed from the FPGA + ;; unmodified. It is the responsibility of the receiver to decode + ;; the binary format as appropriate for the current FPGA + ;; configuration. + ;; + ;; timestamp is a 32-bit integer that specifies the time at which + ;; the first sample in samples was received from the A/D converter. + ;; The format and interpretation of time is as specified in the + ;; file inband-signaling-usb. + ;; + ;; properties is a dictionary containing additional (key, value) + ;; pairs associated with the reception of these samples. In + ;; particular, the map may contain the Received Signal Strength + ;; Indication (RSSI) reported by the front end at the time the + ;; first sample was received from the A/D. + + ) + ) + + +;; ---------------------------------------------------------------- +;; usrp-server-cs +;; +;; Control and status port for usrp-server +;; +;; The protocol class is defined from the client's point-of-view. +;; (The client port is unconjugated, the server port is conjugated.) + +(define-protocol-class usrp-server-cs + + (:outgoing + (cmd-open invocation-handle which-usrp) + (cmd-close invocation-handle) + (cmd-max-capacity invocation-handle) + (cmd-ntx-chan invocation-handle) + (cmd-nrx-chan invocation-handle) + (cmd-current-capacity-allocation invocation-handle) + ) + + (: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) + ) + ) diff --git a/host/lib/legacy/Makefile.am b/host/lib/legacy/Makefile.am new file mode 100644 index 0000000..7303fb4 --- /dev/null +++ b/host/lib/legacy/Makefile.am @@ -0,0 +1,153 @@ +# +# USRP - Universal Software Radio Peripheral +# +# Copyright (C) 2003,2004,2006,2007 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA +# + +include $(top_srcdir)/Makefile.common + +INCLUDES = $(USRP_INCLUDES) + +lib_LTLIBRARIES = libusrp.la + +libusrp_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0 + +libusrp_la_LIBADD = \ + $(USB_LIBS) \ + ../../misc/libmisc.la + +EXTRA_DIST = \ + std_paths.h.in \ + usrp_dbid.dat + + +BUILT_SOURCES = \ + usrp_dbid.h \ + usrp_dbid.cc \ + usrp_dbid.py + + +# ---------------------------------------------------------------- +# FUSB_TECH is set at configure time by way of +# usrp/config/usrp_fusb_tech.m4. +# It indicates which fast usb strategy we should be building. +# We currently implement "generic", "darwin", "win32" and "linux" + + +generic_CODE = \ + fusb_generic.cc \ + fusb_sysconfig_generic.cc + +darwin_CODE = \ + fusb_darwin.cc \ + fusb_sysconfig_darwin.cc \ + README_OSX \ + circular_buffer.h \ + circular_linked_list.h \ + darwin_libusb.h \ + mld_threads.h + +win32_CODE = \ + fusb_win32.cc \ + fusb_sysconfig_win32.cc + +linux_CODE = \ + fusb_linux.cc \ + fusb_sysconfig_linux.cc + +ra_wb_CODE = \ + fusb_ra_wb.cc \ + fusb_sysconfig_ra_wb.cc + + +# +# include each _CODE entry here... +# +EXTRA_libusrp_la_SOURCES = \ + $(generic_CODE) \ + $(darwin_CODE) \ + $(win32_CODE) \ + $(linux_CODE) \ + $(ra_wb_CODE) + + +# work around automake deficiency +libusrp_la_common_SOURCES = \ + fusb.cc \ + md5.c \ + usrp_basic.cc \ + usrp_config.cc \ + usrp_dbid.cc \ + usrp_local_sighandler.cc \ + usrp_prims.cc \ + usrp_standard.cc + + +if FUSB_TECH_generic +libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(generic_CODE) +endif + +if FUSB_TECH_darwin +libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(darwin_CODE) +endif + +if FUSB_TECH_win32 +libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(win32_CODE) +endif + +if FUSB_TECH_linux +libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(linux_CODE) +endif + +if FUSB_TECH_ra_wb +libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(ra_wb_CODE) +endif + +include_HEADERS = \ + usrp_basic.h \ + usrp_bytesex.h \ + usrp_config.h \ + usrp_dbid.h \ + usrp_prims.h \ + usrp_slots.h \ + usrp_standard.h + +noinst_HEADERS = \ + ad9862.h \ + fusb.h \ + fusb_darwin.h \ + fusb_win32.h \ + fusb_generic.h \ + fusb_linux.h \ + fusb_ra_wb.h \ + md5.h \ + rate_to_regval.h \ + usrp_local_sighandler.h + +usrppython_PYTHON = \ + usrp_dbid.py + +noinst_PYTHON = \ + gen_usrp_dbid.py \ + check_data.py \ + dump_data.py + +usrp_dbid.py usrp_dbid.h usrp_dbid.cc: gen_usrp_dbid.py usrp_dbid.dat + PYTHONPATH=$(top_srcdir)/usrp/src srcdir=$(srcdir) $(PYTHON) $(srcdir)/gen_usrp_dbid.py $(srcdir)/usrp_dbid.dat + +MOSTLYCLEANFILES = \ + $(BUILT_SOURCES) *~ *.pyc diff --git a/host/lib/README_OSX b/host/lib/legacy/README_OSX similarity index 100% rename from host/lib/README_OSX rename to host/lib/legacy/README_OSX diff --git a/host/lib/ad9862.h b/host/lib/legacy/ad9862.h similarity index 100% rename from host/lib/ad9862.h rename to host/lib/legacy/ad9862.h diff --git a/host/lib/check_data.py b/host/lib/legacy/check_data.py similarity index 100% rename from host/lib/check_data.py rename to host/lib/legacy/check_data.py diff --git a/host/lib/circular_buffer.h b/host/lib/legacy/circular_buffer.h similarity index 100% rename from host/lib/circular_buffer.h rename to host/lib/legacy/circular_buffer.h diff --git a/host/lib/circular_linked_list.h b/host/lib/legacy/circular_linked_list.h similarity index 100% rename from host/lib/circular_linked_list.h rename to host/lib/legacy/circular_linked_list.h diff --git a/host/lib/darwin_libusb.h b/host/lib/legacy/darwin_libusb.h similarity index 100% rename from host/lib/darwin_libusb.h rename to host/lib/legacy/darwin_libusb.h diff --git a/host/lib/dump_data.py b/host/lib/legacy/dump_data.py similarity index 100% rename from host/lib/dump_data.py rename to host/lib/legacy/dump_data.py diff --git a/host/lib/fusb.cc b/host/lib/legacy/fusb.cc similarity index 100% rename from host/lib/fusb.cc rename to host/lib/legacy/fusb.cc diff --git a/host/lib/fusb.h b/host/lib/legacy/fusb.h similarity index 100% rename from host/lib/fusb.h rename to host/lib/legacy/fusb.h diff --git a/host/lib/fusb_darwin.cc b/host/lib/legacy/fusb_darwin.cc similarity index 100% rename from host/lib/fusb_darwin.cc rename to host/lib/legacy/fusb_darwin.cc diff --git a/host/lib/fusb_darwin.h b/host/lib/legacy/fusb_darwin.h similarity index 100% rename from host/lib/fusb_darwin.h rename to host/lib/legacy/fusb_darwin.h diff --git a/host/lib/fusb_generic.cc b/host/lib/legacy/fusb_generic.cc similarity index 100% rename from host/lib/fusb_generic.cc rename to host/lib/legacy/fusb_generic.cc diff --git a/host/lib/fusb_generic.h b/host/lib/legacy/fusb_generic.h similarity index 100% rename from host/lib/fusb_generic.h rename to host/lib/legacy/fusb_generic.h diff --git a/host/lib/fusb_linux.cc b/host/lib/legacy/fusb_linux.cc similarity index 100% rename from host/lib/fusb_linux.cc rename to host/lib/legacy/fusb_linux.cc diff --git a/host/lib/fusb_linux.h b/host/lib/legacy/fusb_linux.h similarity index 100% rename from host/lib/fusb_linux.h rename to host/lib/legacy/fusb_linux.h diff --git a/host/lib/fusb_ra_wb.cc b/host/lib/legacy/fusb_ra_wb.cc similarity index 100% rename from host/lib/fusb_ra_wb.cc rename to host/lib/legacy/fusb_ra_wb.cc diff --git a/host/lib/fusb_ra_wb.h b/host/lib/legacy/fusb_ra_wb.h similarity index 100% rename from host/lib/fusb_ra_wb.h rename to host/lib/legacy/fusb_ra_wb.h diff --git a/host/lib/fusb_sysconfig_darwin.cc b/host/lib/legacy/fusb_sysconfig_darwin.cc similarity index 100% rename from host/lib/fusb_sysconfig_darwin.cc rename to host/lib/legacy/fusb_sysconfig_darwin.cc diff --git a/host/lib/fusb_sysconfig_generic.cc b/host/lib/legacy/fusb_sysconfig_generic.cc similarity index 100% rename from host/lib/fusb_sysconfig_generic.cc rename to host/lib/legacy/fusb_sysconfig_generic.cc diff --git a/host/lib/fusb_sysconfig_linux.cc b/host/lib/legacy/fusb_sysconfig_linux.cc similarity index 100% rename from host/lib/fusb_sysconfig_linux.cc rename to host/lib/legacy/fusb_sysconfig_linux.cc diff --git a/host/lib/fusb_sysconfig_ra_wb.cc b/host/lib/legacy/fusb_sysconfig_ra_wb.cc similarity index 100% rename from host/lib/fusb_sysconfig_ra_wb.cc rename to host/lib/legacy/fusb_sysconfig_ra_wb.cc diff --git a/host/lib/fusb_sysconfig_win32.cc b/host/lib/legacy/fusb_sysconfig_win32.cc similarity index 100% rename from host/lib/fusb_sysconfig_win32.cc rename to host/lib/legacy/fusb_sysconfig_win32.cc diff --git a/host/lib/fusb_win32.cc b/host/lib/legacy/fusb_win32.cc similarity index 100% rename from host/lib/fusb_win32.cc rename to host/lib/legacy/fusb_win32.cc diff --git a/host/lib/fusb_win32.h b/host/lib/legacy/fusb_win32.h similarity index 100% rename from host/lib/fusb_win32.h rename to host/lib/legacy/fusb_win32.h diff --git a/host/lib/gen_usrp_dbid.py b/host/lib/legacy/gen_usrp_dbid.py similarity index 100% rename from host/lib/gen_usrp_dbid.py rename to host/lib/legacy/gen_usrp_dbid.py diff --git a/host/lib/md5.c b/host/lib/legacy/md5.c similarity index 100% rename from host/lib/md5.c rename to host/lib/legacy/md5.c diff --git a/host/lib/md5.h b/host/lib/legacy/md5.h similarity index 100% rename from host/lib/md5.h rename to host/lib/legacy/md5.h diff --git a/host/lib/mld_threads.h b/host/lib/legacy/mld_threads.h similarity index 100% rename from host/lib/mld_threads.h rename to host/lib/legacy/mld_threads.h diff --git a/host/lib/rate_to_regval.h b/host/lib/legacy/rate_to_regval.h similarity index 100% rename from host/lib/rate_to_regval.h rename to host/lib/legacy/rate_to_regval.h diff --git a/host/lib/std_paths.h.in b/host/lib/legacy/std_paths.h.in similarity index 100% rename from host/lib/std_paths.h.in rename to host/lib/legacy/std_paths.h.in diff --git a/host/lib/usrp_basic.cc b/host/lib/legacy/usrp_basic.cc similarity index 99% rename from host/lib/usrp_basic.cc rename to host/lib/legacy/usrp_basic.cc index cc9df04..2eef147 100644 --- a/host/lib/usrp_basic.cc +++ b/host/lib/legacy/usrp_basic.cc @@ -923,8 +923,6 @@ usrp_basic_tx::usrp_basic_tx (int which_board, int fusb_block_size, int fusb_nbl _write_fpga_reg(FR_ATR_MASK_2, 0); _write_fpga_reg(FR_ATR_TXVAL_2, 0); _write_fpga_reg(FR_ATR_RXVAL_2, 0); - _write_fpga_reg(FR_ATR_TX_DELAY, 0); - _write_fpga_reg(FR_ATR_RX_DELAY, 0); } diff --git a/host/lib/usrp_basic.h b/host/lib/legacy/usrp_basic.h similarity index 100% rename from host/lib/usrp_basic.h rename to host/lib/legacy/usrp_basic.h diff --git a/host/lib/usrp_bytesex.h b/host/lib/legacy/usrp_bytesex.h similarity index 76% rename from host/lib/usrp_bytesex.h rename to host/lib/legacy/usrp_bytesex.h index 391d29c..6c4e129 100644 --- a/host/lib/usrp_bytesex.h +++ b/host/lib/legacy/usrp_bytesex.h @@ -38,11 +38,30 @@ bswap_16 (unsigned short int x) { return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)); } + +static inline unsigned int +bswap32 (unsigned int x) +{ + return ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) \ + | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)); +} #endif #ifdef WORDS_BIGENDIAN +static inline unsigned int +host_to_usrp_u32 (unsigned int x) +{ + return bswap_32(x); +} + +static inline unsigned int +usrp_to_host_u32 (unsigned int x) +{ + return bswap_32(x); +} + static inline short int host_to_usrp_short (short int x) { @@ -57,6 +76,18 @@ usrp_to_host_short (short int x) #else +static inline unsigned int +host_to_usrp_u32 (unsigned int x) +{ + return x; +} + +static inline unsigned int +usrp_to_host_u32 (unsigned int x) +{ + return x; +} + static inline short int host_to_usrp_short (short int x) { diff --git a/host/lib/usrp_config.cc b/host/lib/legacy/usrp_config.cc similarity index 100% rename from host/lib/usrp_config.cc rename to host/lib/legacy/usrp_config.cc diff --git a/host/lib/usrp_config.h b/host/lib/legacy/usrp_config.h similarity index 100% rename from host/lib/usrp_config.h rename to host/lib/legacy/usrp_config.h diff --git a/host/lib/usrp_dbid.dat b/host/lib/legacy/usrp_dbid.dat similarity index 100% rename from host/lib/usrp_dbid.dat rename to host/lib/legacy/usrp_dbid.dat diff --git a/host/lib/usrp_local_sighandler.cc b/host/lib/legacy/usrp_local_sighandler.cc similarity index 100% rename from host/lib/usrp_local_sighandler.cc rename to host/lib/legacy/usrp_local_sighandler.cc diff --git a/host/lib/usrp_local_sighandler.h b/host/lib/legacy/usrp_local_sighandler.h similarity index 100% rename from host/lib/usrp_local_sighandler.h rename to host/lib/legacy/usrp_local_sighandler.h diff --git a/host/lib/usrp_prims.cc b/host/lib/legacy/usrp_prims.cc similarity index 100% rename from host/lib/usrp_prims.cc rename to host/lib/legacy/usrp_prims.cc diff --git a/host/lib/usrp_prims.h b/host/lib/legacy/usrp_prims.h similarity index 100% rename from host/lib/usrp_prims.h rename to host/lib/legacy/usrp_prims.h diff --git a/host/lib/usrp_slots.h b/host/lib/legacy/usrp_slots.h similarity index 100% rename from host/lib/usrp_slots.h rename to host/lib/legacy/usrp_slots.h diff --git a/host/lib/usrp_standard.cc b/host/lib/legacy/usrp_standard.cc similarity index 100% rename from host/lib/usrp_standard.cc rename to host/lib/legacy/usrp_standard.cc diff --git a/host/lib/usrp_standard.h b/host/lib/legacy/usrp_standard.h similarity index 100% rename from host/lib/usrp_standard.h rename to host/lib/legacy/usrp_standard.h diff --git a/host/swig/Makefile.am b/host/swig/Makefile.am index 8868d1e..35a81ea 100644 --- a/host/swig/Makefile.am +++ b/host/swig/Makefile.am @@ -64,7 +64,7 @@ _usrp_prims_la_SOURCES = \ noinst_HEADERS = -_usrp_prims_la_LIBADD = $(top_builddir)/usrp/host/lib/libusrp.la -lstdc++ $(PYTHON_LDFLAGS) +_usrp_prims_la_LIBADD = $(USRP_LA) -lstdc++ $(PYTHON_LDFLAGS) _usrp_prims_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version