libusrp/host/lib/inband/qa_inband_usrp_server.cc

456 lines
14 KiB
C++

/* -*- c++ -*- */
/*
* Copyright 2007 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* GNU Radio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <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()
{
}