Merged features/inband -r4812:5218 into trunk. This group of changes
[debian/gnuradio] / usrp / host / lib / inband / qa_inband_usrp_server.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2007 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <qa_inband_usrp_server.h>
27 #include <cppunit/TestAssert.h>
28 #include <stdio.h>
29 #include <usrp_server.h>
30 #include <mb_mblock.h>
31 #include <mb_runtime.h>
32 #include <mb_protocol_class.h>
33 #include <mb_class_registry.h>
34 #include <vector>
35 #include <iostream>
36
37 static pmt_t s_cmd_allocate_channel = pmt_intern("cmd-allocate-channel");
38 static pmt_t s_response_allocate_channel = pmt_intern("response-allocate-channel");
39 static pmt_t s_send_allocate_channel = pmt_intern("send-allocate-channel");
40 static pmt_t s_cmd_deallocate_channel = pmt_intern("cmd-deallocate-channel");
41 static pmt_t s_response_deallocate_channel = pmt_intern("response-deallocate-channel");
42 static pmt_t s_send_deallocate_channel = pmt_intern("send-deallocate-channel");
43 static pmt_t s_cmd_max_capacity = pmt_intern("cmd-max-capacity");
44 static pmt_t s_response_max_capacity = pmt_intern("response-max-capacity");
45 static pmt_t s_cmd_ntx_chan  = pmt_intern("cmd-ntx-chan");
46 static pmt_t s_cmd_nrx_chan  = pmt_intern("cmd-nrx-chan");
47 static pmt_t s_response_ntx_chan = pmt_intern("response-ntx-chan");
48 static pmt_t s_response_nrx_chan = pmt_intern("response-nrx-chan");
49 static pmt_t s_cmd_current_capacity_allocation  = pmt_intern("cmd-current-capacity-allocation");
50 static pmt_t s_response_current_capacity_allocation  = pmt_intern("response-current-capacity-allocation");
51
52
53 // ----------------------------------------------------------------------------------------------
54
55 class qa_alloc_top : public mb_mblock
56 {
57   mb_port_sptr d_tx;
58   mb_port_sptr d_rx;
59   mb_port_sptr d_cs;
60
61   long d_nmsgs_to_recv;
62   long d_nrecvd;
63
64   long d_max_capacity;
65   long d_ntx_chan, d_nrx_chan;
66
67   long d_nstatus;
68   long d_nstatus_to_recv;
69
70  public:
71   qa_alloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
72   ~qa_alloc_top();
73   void initial_transition();
74   void handle_message(mb_message_sptr msg);
75
76  protected:
77   void check_message(mb_message_sptr msg);
78   void run_tests();
79 };
80
81 qa_alloc_top::qa_alloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
82   : mb_mblock(runtime, instance_name, user_arg)
83
84   d_nrecvd=0;
85   d_nmsgs_to_recv = 7;
86   d_nstatus=0;
87   d_nstatus_to_recv = 3;
88   
89   d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
90   d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
91   d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
92
93   // Test the TX side
94   define_component("server", "usrp_server", PMT_F);
95   connect("self", "tx0", "server", "tx0");
96   connect("self", "rx0", "server", "rx0");
97   connect("self", "cs", "server", "cs");
98
99 }
100
101 qa_alloc_top::~qa_alloc_top(){}
102
103 void
104 qa_alloc_top::initial_transition()
105 {
106   // Retrieve information about the USRP, then run tests
107   d_cs->send(s_cmd_max_capacity, pmt_list1(PMT_F));
108   d_cs->send(s_cmd_ntx_chan, pmt_list1(PMT_F));
109   d_cs->send(s_cmd_nrx_chan, pmt_list1(PMT_F));
110 }
111
112 void
113 qa_alloc_top::run_tests()
114 {
115   std::cout << "[qa_alloc_top] Starting tests...\n";
116   // should be able to allocate 1 byte
117   d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
118   
119   // should not be able to allocate max capacity after 100 bytes were allocated
120   d_tx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::RQSTD_CAPACITY_UNAVAIL), pmt_from_long(d_max_capacity)));  
121   
122   // keep allocating a little more until all of the channels are used and test the error response
123   // we start at 1 since we've already allocated 1 channel
124   for(int i=1; i < d_ntx_chan; i++) {
125     d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
126     d_nmsgs_to_recv++;
127   }
128   d_tx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_UNAVAIL), pmt_from_long(1)));
129
130   // test out the same on the RX side
131   d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
132   d_rx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::RQSTD_CAPACITY_UNAVAIL), pmt_from_long(d_max_capacity)));  
133
134   for(int i=1; i < d_nrx_chan; i++) {
135     d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
136     d_nmsgs_to_recv++;
137   }
138   d_rx->send(s_cmd_allocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_UNAVAIL), pmt_from_long(1)));
139
140   // when all is said and done, there should be d_ntx_chan+d_ntx_chan bytes allocated
141   d_cs->send(s_cmd_current_capacity_allocation, pmt_list1(pmt_from_long(d_ntx_chan+d_nrx_chan)));
142 }
143
144 void
145 qa_alloc_top::handle_message(mb_message_sptr msg)
146 {
147   pmt_t data = msg->data();
148
149   if ((pmt_eq(msg->port_id(), d_tx->port_symbol())
150        || pmt_eq(msg->port_id(), d_rx->port_symbol()))
151        && pmt_eq(msg->signal(), s_response_allocate_channel))
152     check_message(msg);
153   
154   if (pmt_eq(msg->port_id(), d_cs->port_symbol())) {
155       
156     if(pmt_eq(msg->signal(), s_response_max_capacity)) {
157       d_max_capacity = pmt_to_long(pmt_nth(1, data));
158       std::cout << "[qa_alloc_top] USRP has max capacity of " << d_max_capacity << "\n";
159     }
160     else if(pmt_eq(msg->signal(), s_response_ntx_chan)) {
161       d_ntx_chan = pmt_to_long(pmt_nth(1, data));
162       std::cout << "[qa_alloc_top] USRP tx channels: " << d_ntx_chan << "\n";
163     }
164     else if(pmt_eq(msg->signal(), s_response_nrx_chan)) {
165       d_nrx_chan = pmt_to_long(pmt_nth(1, data));
166       std::cout << "[qa_alloc_top] USRP rx channels: " << d_nrx_chan << "\n";
167     }
168     else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) {
169       check_message(msg);
170     }
171     
172     d_nstatus++;
173
174     if(d_nstatus==d_nstatus_to_recv)
175       run_tests();
176   }
177 }
178
179 void
180 qa_alloc_top::check_message(mb_message_sptr msg)
181 {
182   pmt_t data = msg->data();
183
184   pmt_t expected_result = pmt_nth(0, data);
185   pmt_t result = pmt_nth(1, data);
186   
187   d_nrecvd++;
188
189
190   if(!pmt_eqv(expected_result, result)) {
191     std::cout << "Got: " << result << " Expected: " << expected_result << "\n";
192     shutdown_all(PMT_F);
193   } else {
194     std::cout << "[qa_alloc_top] Received expected response for message " << d_nrecvd << "\n";
195   }
196
197   if(d_nrecvd == d_nmsgs_to_recv)
198     shutdown_all(PMT_T);
199 }
200
201 REGISTER_MBLOCK_CLASS(qa_alloc_top);
202
203 // ----------------------------------------------------------------------------------------------
204
205 class qa_dealloc_top : public mb_mblock
206 {
207   mb_port_sptr d_tx;
208   mb_port_sptr d_rx;
209   mb_port_sptr d_cs;
210   
211   long d_max_capacity;
212   long d_ntx_chan, d_nrx_chan;
213
214   long d_nstatus;
215   long d_nstatus_to_recv;
216
217   long d_nalloc_to_recv;
218   long d_nalloc_recvd;
219
220   long d_ndealloc_to_recv;
221   long d_ndealloc_recvd;
222
223   std::vector<long> d_tx_chans;
224   std::vector<long> d_rx_chans;
225
226  public:
227   qa_dealloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
228   ~qa_dealloc_top();
229   void initial_transition();
230   void handle_message(mb_message_sptr msg);
231
232  protected:
233   void check_allocation(mb_message_sptr msg);
234   void check_deallocation(mb_message_sptr msg);
235   void allocate_max();
236   void deallocate_all();
237 };
238
239 qa_dealloc_top::qa_dealloc_top(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
240   : mb_mblock(runtime, instance_name, user_arg)
241
242   d_ndealloc_recvd=0;
243   d_ndealloc_to_recv = 0;
244   d_nalloc_recvd=0;
245   d_nalloc_to_recv = 0;
246   d_nstatus=0;
247   d_nstatus_to_recv = 3;
248   
249   d_rx = define_port("rx0", "usrp-rx", false, mb_port::INTERNAL);
250   d_tx = define_port("tx0", "usrp-tx", false, mb_port::INTERNAL);
251   d_cs = define_port("cs", "usrp-server-cs", false, mb_port::INTERNAL);
252
253   // Test the TX side
254   define_component("server", "usrp_server", PMT_F);
255   connect("self", "tx0", "server", "tx0");
256   connect("self", "rx0", "server", "rx0");
257   connect("self", "cs", "server", "cs");
258 }
259
260 qa_dealloc_top::~qa_dealloc_top(){}
261
262 void
263 qa_dealloc_top::initial_transition()
264 {
265   // Retrieve information about the USRP, then run tests
266   d_cs->send(s_cmd_max_capacity, pmt_list1(PMT_F));
267   d_cs->send(s_cmd_ntx_chan, pmt_list1(PMT_F));
268   d_cs->send(s_cmd_nrx_chan, pmt_list1(PMT_F));
269 }
270
271 void
272 qa_dealloc_top::allocate_max()
273 {
274   std::cout << "[qa_dealloc_top] Max allocating...\n";
275
276   // Keep allocating until we hit the maximum number of channels
277   for(int i=0; i < d_ntx_chan; i++) {
278     d_tx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
279     d_nalloc_to_recv++;
280   }
281   for(int i=0; i < d_nrx_chan; i++) {
282     d_rx->send(s_cmd_allocate_channel, pmt_list2(PMT_T, pmt_from_long(1)));
283     d_nalloc_to_recv++;
284   }
285 }
286
287 void
288 qa_dealloc_top::deallocate_all() {
289   
290   // Deallocate all of the channels that were allocated from allocate_max()
291   for(int i=0; i < (int)d_tx_chans.size(); i++) {
292     d_tx->send(s_cmd_deallocate_channel, pmt_list2(PMT_T, pmt_from_long(d_tx_chans[i])));
293     d_ndealloc_to_recv++;
294   }
295   for(int i=0; i < (int)d_rx_chans.size(); i++) {
296     d_rx->send(s_cmd_deallocate_channel, pmt_list2(PMT_T, pmt_from_long(d_rx_chans[i])));
297     d_ndealloc_to_recv++;
298   }
299
300   // Should get permission denied errors trying to re-dealloc the channels, as we no
301   // longer have permission to them after deallocating
302   for(int i=0; i < (int)d_tx_chans.size(); i++) {
303     d_tx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::PERMISSION_DENIED), pmt_from_long(d_tx_chans[i])));
304     d_ndealloc_to_recv++;
305   }
306   for(int i=0; i < (int)d_rx_chans.size(); i++) {
307     d_rx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::PERMISSION_DENIED), pmt_from_long(d_rx_chans[i])));
308     d_ndealloc_to_recv++;
309   }
310
311   // Try to deallocate a channel that doesn't exist on both sides, the last element in the vectors
312   // is the highest channel number, so we take that plus 1
313   d_ndealloc_to_recv+=2;
314   d_tx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_INVALID), pmt_from_long(d_rx_chans.back()+1)));
315   d_rx->send(s_cmd_deallocate_channel, pmt_list2(pmt_from_long(usrp_server::CHANNEL_INVALID), pmt_from_long(d_rx_chans.back()+1)));
316
317
318   // The used capacity should be back to 0 now that we've deallocated everything
319   d_cs->send(s_cmd_current_capacity_allocation, pmt_list1(pmt_from_long(0)));
320 }
321
322 void
323 qa_dealloc_top::handle_message(mb_message_sptr msg)
324 {
325   pmt_t data = msg->data();
326   if (pmt_eq(msg->port_id(), d_tx->port_symbol())
327        || pmt_eq(msg->port_id(), d_rx->port_symbol())) {
328     
329     if(pmt_eq(msg->signal(), s_response_allocate_channel)) {
330       check_allocation(msg);
331     }
332     
333     if(pmt_eq(msg->signal(), s_response_deallocate_channel)){
334       check_deallocation(msg);
335     }
336   }
337   
338   if (pmt_eq(msg->port_id(), d_cs->port_symbol())) {
339       
340     if(pmt_eq(msg->signal(), s_response_max_capacity)) {
341       d_max_capacity = pmt_to_long(pmt_nth(1, data));
342       std::cout << "[qa_dealloc_top] USRP has max capacity of " << d_max_capacity << "\n";
343     }
344     else if(pmt_eq(msg->signal(), s_response_ntx_chan)) {
345       d_ntx_chan = pmt_to_long(pmt_nth(1, data));
346       std::cout << "[qa_dealloc_top] USRP tx channels: " << d_ntx_chan << "\n";
347     }
348     else if(pmt_eq(msg->signal(), s_response_nrx_chan)) {
349       d_nrx_chan = pmt_to_long(pmt_nth(1, data));
350       std::cout << "[qa_dealloc_top] USRP rx channels: " << d_nrx_chan << "\n";
351     }
352     else if(pmt_eq(msg->signal(), s_response_current_capacity_allocation)) {
353       // the final command is a capacity check which should be 0, then we shutdown
354       pmt_t expected_result = pmt_nth(0, data);
355       pmt_t result = pmt_nth(1, data);
356
357       if(pmt_eqv(expected_result, result))
358         shutdown_all(PMT_T);
359       else
360         shutdown_all(PMT_F);
361     }
362     
363     d_nstatus++;
364
365     if(d_nstatus==d_nstatus_to_recv)
366       allocate_max();
367   }
368 }
369
370 void
371 qa_dealloc_top::check_deallocation(mb_message_sptr msg)
372 {
373   pmt_t data = msg->data();
374
375   pmt_t expected_result = pmt_nth(0, data);
376   pmt_t result = pmt_nth(1, data);
377
378   d_ndealloc_recvd++;
379
380   if(!pmt_eqv(expected_result, result)) {
381     std::cout << "Got: " << result << " Expected: " << expected_result << "\n";
382     shutdown_all(PMT_F);
383   } else {
384     std::cout << "[qa_dealloc_top] Received expected deallocation response for message " << d_ndealloc_recvd << "\n";
385   }
386 }
387
388 void
389 qa_dealloc_top::check_allocation(mb_message_sptr msg)
390 {
391   pmt_t data = msg->data();
392
393   pmt_t invocation_handle = pmt_nth(0, data);
394   pmt_t status = pmt_nth(1, data);
395   pmt_t channel = pmt_nth(2, data);
396   
397   d_nalloc_recvd++;
398
399   if(pmt_eqv(status, PMT_F)) {
400     std::cout << "[qa_dealloc_top] Unexpected error response when allocating channels\n";
401     shutdown_all(PMT_F);
402   } else {
403     // store all of the allocate channel numbers
404     if(pmt_eq(msg->port_id(), d_tx->port_symbol()))
405       d_tx_chans.push_back(pmt_to_long(channel));
406     if(pmt_eq(msg->port_id(), d_rx->port_symbol()))
407       d_rx_chans.push_back(pmt_to_long(channel));
408   }
409
410   if(d_nalloc_recvd == d_nalloc_to_recv) {
411     
412     std::cout << "[qa_dealloc_top] Allocated TX channels: ";
413     for(int i=0; i < (int)d_tx_chans.size(); i++)
414       std::cout << d_tx_chans[i] << " ";
415
416     std::cout << "\n[qa_dealloc_top] Allocated RX channels: ";
417     for(int i=0; i < (int)d_rx_chans.size(); i++)
418       std::cout << d_rx_chans[i] << " ";
419     std::cout << "\n";
420
421     deallocate_all();   // once we've allocated all of our channels, try to dealloc them
422   }
423 }
424
425 REGISTER_MBLOCK_CLASS(qa_dealloc_top);
426
427 // ----------------------------------------------------------------------------------------------
428
429 void 
430 qa_inband_usrp_server::test_chan_allocation()
431 {
432   mb_runtime_sptr rt = mb_make_runtime();
433   pmt_t result = PMT_T;
434
435   rt->run("top", "qa_alloc_top", PMT_F, &result);
436   
437   CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
438 }
439
440 void
441 qa_inband_usrp_server::test_chan_deallocation()
442 {
443   mb_runtime_sptr rt = mb_make_runtime();
444   pmt_t result = PMT_T;
445
446   rt->run("top", "qa_dealloc_top", PMT_F, &result);
447   
448   CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
449 }
450
451 void
452 qa_inband_usrp_server::test_fragmentation()
453 {
454   
455 }