Merged features/inband -r4812:5218 into trunk. This group of changes

includes:

 * working stand-alone mblock code
 * work-in-progress on usrp inband signaling

usrp now depends on mblock, and guile is a dependency.



git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@5221 221aa14e-8319-0410-a670-987f0aec2ac5
This commit is contained in:
eb 2007-05-02 04:08:47 +00:00
parent 071e2f6d1b
commit 87a72fff96
77 changed files with 3625 additions and 377 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

135
fpga/inband_lib/usb_fifo_reader.v Executable file
View File

@ -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

112
fpga/inband_lib/usb_packet_fifo.v Executable file
View File

@ -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

View File

@ -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

116
fpga/megacells/fifo_512.bsf Executable file
View File

@ -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))
)
)

31
fpga/megacells/fifo_512.cmp Executable file
View File

@ -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;

32
fpga/megacells/fifo_512.inc Executable file
View File

@ -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
);

180
fpga/megacells/fifo_512.v Executable file
View File

@ -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

131
fpga/megacells/fifo_512_bb.v Executable file
View File

@ -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

View File

@ -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"
set_global_assignment -name VERILOG_FILE ../../sdr_lib/sign_extend.v

View File

@ -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

View File

@ -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)

View File

@ -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 <foo>_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

Binary file not shown.

View File

@ -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

65
host/lib/inband/dump_packets.py Executable file
View File

@ -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()

View File

@ -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"))

View File

@ -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 <qa_inband.h>
#include <qa_inband_packet_prims.h>
#include <qa_inband_usrp_server.h>
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;
}

View File

@ -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 <cppunit/TestSuite.h>
//! 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 */

View File

@ -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 <config.h>
#endif
#include <qa_inband_packet_prims.h>
#include <cppunit/TestAssert.h>
#include <stdio.h>
#include <usrp_inband_usb_packet.h> // 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);
}
//////////////////////////////////////////////////////////////////////

View File

@ -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 <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
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 */

View File

@ -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 <config.h>
#endif
#include <qa_inband_usrp_server.h>
#include <cppunit/TestAssert.h>
#include <stdio.h>
#include <usrp_server.h>
#include <mb_mblock.h>
#include <mb_runtime.h>
#include <mb_protocol_class.h>
#include <mb_class_registry.h>
#include <vector>
#include <iostream>
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<long> d_tx_chans;
std::vector<long> 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()
{
}

View File

@ -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 <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
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 */

View File

@ -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 <cppunit/TextTestRunner.h>
#include <qa_inband.h>
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;
}

View File

@ -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

View File

@ -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 <usrp_bytesex.h>
#include <mb_mblock.h>
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<<FL_END_OF_BURST_SHIFT;
d_word0 = host_to_usrp_u32(word0);
}
void set_header(int flags, int chan, int tag, int payload_len){
uint32_t word0 = ((flags & FL_ALL_FLAGS)
| ((chan & CHAN_MASK) << CHAN_SHIFT)
| ((tag & TAG_MASK) << TAG_SHIFT)
| ((payload_len & PAYLOAD_LEN_MASK) << PAYLOAD_LEN_SHIFT));
d_word0 = host_to_usrp_u32(word0);
}
uint32_t timestamp() const {
return usrp_to_host_u32(d_timestamp);
}
int rssi() const {
uint32_t word0 = usrp_to_host_u32(d_word0);
return (word0 >> 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

View File

@ -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 <config.h>
#endif
#include <usrp_server.h>
#include <iostream>
#include <usrp_inband_usb_packet.h>
#include <mb_class_registry.h>
#include <vector>
typedef usrp_inband_usb_packet transport_pkt; // makes conversion to gigabit easy
// 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<long>(std::ceil(n_bytes / (double)max_payload_len));
pmt_t v_packets = pmt_make_u8vector(sizeof(transport_pkt) * n_packets, 0);
transport_pkt *pkts =
(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);

View File

@ -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 <mb_mblock.h>
#include <vector>
/*!
* \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<mb_port_sptr> 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 */

View File

@ -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)
)
)

153
host/lib/legacy/Makefile.am Normal file
View File

@ -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 <foo>_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

View File

@ -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);
}

View File

@ -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)
{

View File

@ -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