Imported Upstream version 3.2.2
[debian/gnuradio] / mblock / src / lib / qa_mblock_prims.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2006,2007,2008 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 3, 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
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <qa_mblock_prims.h>
28 #include <cppunit/TestAssert.h>
29 #include <mblock/mblock.h>
30 #include <mblock/runtime.h>
31 #include <mblock/protocol_class.h>
32 #include <mblock/exception.h>
33 #include <mblock/msg_queue.h>
34 #include <mblock/message.h>
35 #include <mb_mblock_impl.h>
36 #include <mblock/msg_accepter.h>
37 #include <mblock/class_registry.h>
38 #include <stdio.h>
39
40 static pmt_t s_cs = pmt_intern("cs");
41 static pmt_t s_debug = pmt_intern("debug");
42 static pmt_t s_in = pmt_intern("in");
43 static pmt_t s_out = pmt_intern("out");
44   
45
46 // ================================================================
47
48 class dp_1 : public mb_mblock
49 {
50 public:
51   dp_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
52   ~dp_1();
53 };
54
55 dp_1::dp_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
56   : mb_mblock(runtime, instance_name, user_arg)
57 {
58 }
59
60 dp_1::~dp_1(){}
61
62 REGISTER_MBLOCK_CLASS(dp_1);
63
64 // ----------------------------------------------------------------
65
66 class dp_2 : public mb_mblock
67 {
68 public:
69   dp_2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
70   ~dp_2();
71 };
72
73 dp_2::dp_2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
74   : mb_mblock(runtime, instance_name, user_arg)
75 {
76   define_port("cs", "cs-protocol", false, mb_port::EXTERNAL);
77 }
78
79 dp_2::~dp_2(){}
80
81 REGISTER_MBLOCK_CLASS(dp_2);
82
83 // ----------------------------------------------------------------
84
85 class dp_3 : public mb_mblock
86 {
87 public:
88   dp_3(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
89   ~dp_3();
90 };
91
92 dp_3::dp_3(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
93   : mb_mblock(runtime, instance_name, user_arg)
94 {
95   define_port("cs", "cs-protocol", false, mb_port::EXTERNAL);
96   define_port("cs", "cs-protocol", false, mb_port::EXTERNAL);   // duplicate def
97 }
98
99 dp_3::~dp_3(){}
100
101 REGISTER_MBLOCK_CLASS(dp_3);
102
103 // ----------------------------------------------------------------
104
105 void
106 qa_mblock_prims::test_define_ports()
107 {
108   
109   mb_runtime_sptr rts = mb_make_runtime();
110   mb_runtime *rt = rts.get();
111   
112   // Should work
113   mb_mblock_sptr  mb1 = mb_mblock_sptr(new dp_1(rt, "top", PMT_F));
114
115   // raises runtime_error because of unknown protocol "cs-protocol"
116   CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_2(rt, "top", PMT_F)),
117                        std::runtime_error);
118
119   // define the protocol class
120   pmt_t pc = mb_make_protocol_class(pmt_intern("cs-protocol"),
121                                     pmt_list2(pmt_intern("start"),
122                                               pmt_intern("stop")),
123                                     PMT_NIL);
124
125   // std::cout << "pc = " << pc << '\n';
126
127   mb_mblock_sptr mb2 = mb_mblock_sptr(new dp_2(rt, "top", PMT_F));
128
129   // raises pmt_exception because of duplicate port definition of "cs"
130   CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_3(rt, "top", PMT_F)),
131                        mbe_duplicate_port);
132 }
133
134 // ================================================================
135
136 class dc_0 : public mb_mblock
137 {
138 public:
139   dc_0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
140   ~dc_0();
141 };
142
143 dc_0::dc_0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
144   : mb_mblock(runtime, instance_name, user_arg)
145 {
146 }
147
148 dc_0::~dc_0() {}
149
150 REGISTER_MBLOCK_CLASS(dc_0);
151
152 // ----------------------------------------------------------------
153
154 class dc_ok : public mb_mblock
155 {
156 public:
157   dc_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
158   ~dc_ok();
159 };
160
161 dc_ok::dc_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
162   : mb_mblock(runtime, instance_name, user_arg)
163 {
164   define_component("c0", "dc_0");
165   define_component("c1", "dc_0");
166   define_component("c2", "dc_0");
167 }
168
169 dc_ok::~dc_ok(){}
170
171 REGISTER_MBLOCK_CLASS(dc_ok);
172
173 // ----------------------------------------------------------------
174
175 class dc_not_ok : public mb_mblock
176 {
177 public:
178   dc_not_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
179   ~dc_not_ok();
180 };
181
182 dc_not_ok::dc_not_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
183   : mb_mblock(runtime, instance_name, user_arg)
184 {
185   define_component("c0", "dc_0");
186   define_component("c0", "dc_0");       // duplicate name
187 }
188
189 dc_not_ok::~dc_not_ok(){}
190
191 REGISTER_MBLOCK_CLASS(dc_not_ok);
192
193 // ----------------------------------------------------------------
194
195 void
196 qa_mblock_prims::test_define_components()
197 {
198   mb_runtime_sptr rts = mb_make_runtime();
199   mb_runtime *rt = rts.get();
200   
201   // Should work
202   mb_mblock_sptr  mb1 = mb_mblock_sptr(new dc_ok(rt, "top", PMT_F));
203
204   // raises pmt_exception because of duplicate component definition of "c0"
205   CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dc_not_ok(rt, "top", PMT_F)),
206                        mbe_duplicate_component);
207 }
208
209 // ================================================================
210
211 class tc_norm : public mb_mblock
212 {
213 public:
214   tc_norm(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
215     : mb_mblock(runtime, instance_name, user_arg)
216   {
217     define_port("data", "i/o", false, mb_port::EXTERNAL);
218     define_port("norm", "i/o", false, mb_port::EXTERNAL);
219     define_port("conj", "i/o", true,  mb_port::EXTERNAL);
220     define_port("int",  "i/o", false, mb_port::INTERNAL);
221   }
222
223   ~tc_norm();
224 };
225
226 tc_norm::~tc_norm(){}
227
228 REGISTER_MBLOCK_CLASS(tc_norm);
229
230 ////////////////////////////////////////////////////////////////
231
232 class tc_0 : public mb_mblock
233 {
234 public:
235   tc_0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
236     : mb_mblock(runtime, instance_name, user_arg)
237   {
238     define_port("norm", "i/o", false, mb_port::EXTERNAL);
239     define_port("conj", "i/o", true,  mb_port::EXTERNAL);
240     define_port("int",  "i/o", false, mb_port::INTERNAL);
241
242     define_component("c0", "tc_norm");
243     define_component("c1", "tc_norm");
244     define_component("c2", "tc_norm");
245     define_component("c3", "tc_norm");
246     define_component("c4", "tc_norm");
247     define_component("c5", "tc_norm");
248
249     // OK
250     connect("c0", "norm", "c1", "conj");
251
252     // No:  No such component name
253     CPPUNIT_ASSERT_THROW(connect("foo", "data", "c1", "norm"), mbe_no_such_component);
254
255     // No:  No such port name
256     CPPUNIT_ASSERT_THROW(connect("c0", "data", "c1", "foo"), mbe_no_such_port);
257
258     // No:  already connected
259     CPPUNIT_ASSERT_THROW(connect("c0", "norm", "c2", "data"), mbe_already_connected);
260
261     // No:  already connected
262     CPPUNIT_ASSERT_THROW(connect("c2", "data", "c0", "norm"), mbe_already_connected);
263
264     // No: incompatible ports
265     CPPUNIT_ASSERT_THROW(connect("c1", "norm", "c2", "norm"), mbe_incompatible_ports);
266
267     // OK
268     connect("c1", "norm", "c2", "conj");
269
270     // No: No such port name
271     CPPUNIT_ASSERT_THROW(connect("c2", "norm", "self", "foo"), mbe_no_such_port);
272
273     // No: can't connect to child's internal port
274     CPPUNIT_ASSERT_THROW(connect("c0", "conj", "c2", "int"), mbe_no_such_port);
275
276     // No: can't connect to our own external port
277     CPPUNIT_ASSERT_THROW(connect("self", "norm", "c0", "conj"), mbe_invalid_port_type);
278
279     // OK:  connecting to one of our internal ports
280     connect("self", "int", "c3", "conj");
281
282     // =====  Now test disconnecting some stuff =====
283
284     // Confirm we're already connected
285     CPPUNIT_ASSERT_THROW(connect("self", "int", "c3", "conj"), mbe_already_connected);
286
287     int nc = nconnections();
288     disconnect("self", "int", "c3", "conj");    // disconnect
289     CPPUNIT_ASSERT_EQUAL(nc-1, nconnections());
290     
291     connect("self", "int", "c3", "conj");       // reconnect
292     CPPUNIT_ASSERT_EQUAL(nc, nconnections());
293
294     // confirm we're already connected
295     CPPUNIT_ASSERT_THROW(connect("self", "int", "c3", "conj"), mbe_already_connected);
296
297
298     connect("c0", "conj", "c5", "data");
299     connect("c4", "norm", "c5", "conj");
300     connect("c4", "conj", "c5", "norm");
301
302     nc = nconnections();
303     disconnect_component("c4");
304     CPPUNIT_ASSERT_EQUAL(nc-2, nconnections());
305
306     disconnect_component("c5");
307     CPPUNIT_ASSERT_EQUAL(nc-3, nconnections());
308
309     disconnect_all();
310     CPPUNIT_ASSERT_EQUAL(0, nconnections());
311
312   }
313
314   ~tc_0();
315 };
316
317 tc_0::~tc_0(){}
318
319 REGISTER_MBLOCK_CLASS(tc_0);
320
321 ////////////////////////////////////////////////////////////////
322
323 class tc_1 : public mb_mblock
324 {
325 public:
326   tc_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
327     : mb_mblock(runtime, instance_name, user_arg)
328   {
329     define_component("c0", "tc_norm");
330     define_component("c1", "tc_norm");
331
332     connect("c0", "norm", "c1", "conj");
333   }
334
335   ~tc_1();
336 };
337
338 tc_1::~tc_1(){}
339
340 REGISTER_MBLOCK_CLASS(tc_1);
341
342 ////////////////////////////////////////////////////////////////
343
344 void
345 qa_mblock_prims::test_connect()
346 {
347   // define the protocol class
348   mb_make_protocol_class(pmt_intern("data"),                    // name of class
349                          pmt_list1(pmt_intern("data")),         // in
350                          PMT_NIL);                              // out
351
352   mb_make_protocol_class(pmt_intern("i/o"),                     // name of class
353                          pmt_list1(pmt_intern("in")),           // in
354                          pmt_list1(pmt_intern("out")));         // out
355
356   mb_runtime_sptr rts = mb_make_runtime();
357   mb_runtime *rt = rts.get();
358
359   mb_mblock_sptr        mb0 = mb_mblock_sptr(new tc_0(rt, "top", PMT_F));
360 }
361
362 ////////////////////////////////////////////////////////////////
363
364 void
365 qa_mblock_prims::test_msg_queue()
366 {
367   mb_msg_queue  q;
368
369   // check initial state
370   CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0);
371
372   CPPUNIT_ASSERT(MB_NPRI >= 5); // sanity check for this test
373
374   // insert three messages at the same pri and ensure that they come out in order
375   //                       signal       data          metadata     pri
376   q.insert(mb_make_message(PMT_NIL, pmt_from_long(0), PMT_NIL, MB_PRI_BEST + 2));
377   q.insert(mb_make_message(PMT_NIL, pmt_from_long(1), PMT_NIL, MB_PRI_BEST + 2));
378   q.insert(mb_make_message(PMT_NIL, pmt_from_long(2), PMT_NIL, MB_PRI_BEST + 2));
379   
380   CPPUNIT_ASSERT_EQUAL(0L, pmt_to_long(q.get_highest_pri_msg_nowait()->data()));
381   CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(q.get_highest_pri_msg_nowait()->data()));
382   CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(q.get_highest_pri_msg_nowait()->data()));
383
384   CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0);
385
386
387   // insert messages of different priorities in pseudo-random order
388   //                       signal   data     metadata     pri
389   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 3));
390   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 2));
391   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 4));
392   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 0));
393   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 1));
394   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 3));
395   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 2));
396   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 4));
397   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 0));
398   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 1));
399
400   // confirm that they come out in order
401   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg_nowait()->priority());
402   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg_nowait()->priority());
403   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg_nowait()->priority());
404   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg_nowait()->priority());
405   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg_nowait()->priority());
406   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg_nowait()->priority());
407   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg_nowait()->priority());
408   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg_nowait()->priority());
409   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg_nowait()->priority());
410   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg_nowait()->priority());
411   
412   // check final state
413   CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0);
414 }
415
416 ////////////////////////////////////////////////////////////////
417
418 void
419 qa_mblock_prims::test_make_accepter()
420 {
421   mb_runtime_sptr rts = mb_make_runtime();
422   mb_runtime *rt = rts.get();
423
424   // create a block
425   mb_mblock_sptr mb = mb_mblock_sptr(new dp_2(rt, "top", PMT_F));
426
427   // use "internal use only" method...
428   mb_msg_accepter_sptr accepter = mb->impl()->make_accepter(pmt_intern("cs"));
429
430   // Now push a few messages into it...
431   //          signal       data          metadata     pri
432   (*accepter)(PMT_NIL, pmt_from_long(0), PMT_NIL, MB_PRI_BEST + 2);
433   (*accepter)(PMT_NIL, pmt_from_long(1), PMT_NIL, MB_PRI_BEST + 2);
434   (*accepter)(PMT_NIL, pmt_from_long(2), PMT_NIL, MB_PRI_BEST + 2);
435
436   // try to pull them out
437
438   pmt_t cs = pmt_intern("cs");
439
440   mb_message_sptr msg = mb->impl()->msgq().get_highest_pri_msg_nowait();
441   CPPUNIT_ASSERT(pmt_eq(cs, msg->port_id()));         // confirm that port_id is set
442   CPPUNIT_ASSERT_EQUAL(0L, pmt_to_long(msg->data())); // and that data is correct
443
444   CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg_nowait()->data()));
445   CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg_nowait()->data()));
446 }