3 * Copyright 2006,2007 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
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)
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.
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.
27 #include <qa_mblock_prims.h>
28 #include <cppunit/TestAssert.h>
29 #include <mb_mblock.h>
30 #include <mb_runtime.h>
31 #include <mb_protocol_class.h>
32 #include <mb_exception.h>
33 #include <mb_msg_queue.h>
34 #include <mb_message.h>
35 #include <mb_mblock_impl.h>
36 #include <mb_msg_accepter.h>
39 static pmt_t s_cs = pmt_intern("cs");
40 static pmt_t s_debug = pmt_intern("debug");
41 static pmt_t s_in = pmt_intern("in");
42 static pmt_t s_out = pmt_intern("out");
45 // ================================================================
47 class dp_1 : public mb_mblock
60 // ----------------------------------------------------------------
62 class dp_2 : public mb_mblock
71 define_port("cs", "cs-protocol", false, mb_port::EXTERNAL);
76 // ----------------------------------------------------------------
78 class dp_3 : public mb_mblock
87 define_port("cs", "cs-protocol", false, mb_port::EXTERNAL);
88 define_port("cs", "cs-protocol", false, mb_port::EXTERNAL); // duplicate def
93 // ----------------------------------------------------------------
96 qa_mblock_prims::test_define_ports()
98 // std::vector<mb_port_sptr> intf;
100 mb_mblock_sptr mb1 = mb_mblock_sptr(new dp_1());
101 // intf = mb1->peer_interface();
102 // CPPUNIT_ASSERT_EQUAL(size_t(0), intf.size());
104 // raises runtime_error because of unknown protocol "cs-protocol"
105 CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_2()), std::runtime_error);
107 // define the protocol class
108 pmt_t pc = mb_make_protocol_class(pmt_intern("cs-protocol"),
109 pmt_list2(pmt_intern("start"),
113 // std::cout << "pc = " << pc << '\n';
115 mb_mblock_sptr mb2 = mb_mblock_sptr(new dp_2());
117 // raises pmt_exception because of duplicate port definition of "cs"
118 CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_3()), mbe_duplicate_port);
121 // ================================================================
123 class dc_0 : public mb_mblock
136 // ----------------------------------------------------------------
138 class dc_ok : public mb_mblock
147 define_component("c0", mb_mblock_sptr(new dc_0()));
148 define_component("c1", mb_mblock_sptr(new dc_0()));
149 define_component("c2", mb_mblock_sptr(new dc_0()));
154 // ----------------------------------------------------------------
156 class dc_not_ok : public mb_mblock
163 dc_not_ok::dc_not_ok()
166 define_component("c0", mb_mblock_sptr(new dc_0()));
167 define_component("c0", mb_mblock_sptr(new dc_0())); // duplicate name
170 dc_not_ok::~dc_not_ok(){}
172 // ----------------------------------------------------------------
175 qa_mblock_prims::test_define_components()
177 mb_mblock_sptr mb1 = mb_mblock_sptr(new dc_ok()); // OK
179 // raises pmt_exception because of duplicate component definition of "c0"
180 CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dc_not_ok()), mbe_duplicate_component);
183 // ================================================================
185 class tc_norm : public mb_mblock
189 define_port("data", "i/o", false, mb_port::EXTERNAL);
190 define_port("norm", "i/o", false, mb_port::EXTERNAL);
191 define_port("conj", "i/o", true, mb_port::EXTERNAL);
192 define_port("int", "i/o", false, mb_port::INTERNAL);
198 tc_norm::~tc_norm(){}
200 ////////////////////////////////////////////////////////////////
202 class tc_0 : public mb_mblock
206 define_port("norm", "i/o", false, mb_port::EXTERNAL);
207 define_port("conj", "i/o", true, mb_port::EXTERNAL);
208 define_port("int", "i/o", false, mb_port::INTERNAL);
210 define_component("c0", mb_mblock_sptr(new tc_norm()));
211 define_component("c1", mb_mblock_sptr(new tc_norm()));
212 define_component("c2", mb_mblock_sptr(new tc_norm()));
213 define_component("c3", mb_mblock_sptr(new tc_norm()));
214 define_component("c4", mb_mblock_sptr(new tc_norm()));
215 define_component("c5", mb_mblock_sptr(new tc_norm()));
218 connect("c0", "norm", "c1", "conj");
220 // No: No such component name
221 CPPUNIT_ASSERT_THROW(connect("foo", "data", "c1", "norm"), mbe_no_such_component);
223 // No: No such port name
224 CPPUNIT_ASSERT_THROW(connect("c0", "data", "c1", "foo"), mbe_no_such_port);
226 // No: already connected
227 CPPUNIT_ASSERT_THROW(connect("c0", "norm", "c2", "data"), mbe_already_connected);
229 // No: already connected
230 CPPUNIT_ASSERT_THROW(connect("c2", "data", "c0", "norm"), mbe_already_connected);
232 // No: incompatible ports
233 CPPUNIT_ASSERT_THROW(connect("c1", "norm", "c2", "norm"), mbe_incompatible_ports);
236 connect("c1", "norm", "c2", "conj");
238 // No: No such port name
239 CPPUNIT_ASSERT_THROW(connect("c2", "norm", "self", "foo"), mbe_no_such_port);
241 // No: can't connect to child's internal port
242 CPPUNIT_ASSERT_THROW(connect("c0", "conj", "c2", "int"), mbe_no_such_port);
244 // No: can't connect to our own external port
245 CPPUNIT_ASSERT_THROW(connect("self", "norm", "c0", "conj"), mbe_invalid_port_type);
247 // OK: connecting to one of our internal ports
248 connect("self", "int", "c3", "conj");
250 // ===== Now test disconnecting some stuff =====
252 // Confirm we're already connected
253 CPPUNIT_ASSERT_THROW(connect("self", "int", "c3", "conj"), mbe_already_connected);
255 int nc = nconnections();
256 disconnect("self", "int", "c3", "conj"); // disconnect
257 CPPUNIT_ASSERT_EQUAL(nc-1, nconnections());
259 connect("self", "int", "c3", "conj"); // reconnect
260 CPPUNIT_ASSERT_EQUAL(nc, nconnections());
262 // confirm we're already connected
263 CPPUNIT_ASSERT_THROW(connect("self", "int", "c3", "conj"), mbe_already_connected);
266 connect("c0", "conj", "c5", "data");
267 connect("c4", "norm", "c5", "conj");
268 connect("c4", "conj", "c5", "norm");
271 disconnect_component("c4");
272 CPPUNIT_ASSERT_EQUAL(nc-2, nconnections());
274 disconnect_component("c5");
275 CPPUNIT_ASSERT_EQUAL(nc-3, nconnections());
278 CPPUNIT_ASSERT_EQUAL(0, nconnections());
287 ////////////////////////////////////////////////////////////////
289 class tc_1 : public mb_mblock
293 define_component("c0", mb_mblock_sptr(new tc_norm()));
294 define_component("c1", mb_mblock_sptr(new tc_norm()));
296 connect("c0", "norm", "c1", "conj");
304 ////////////////////////////////////////////////////////////////
307 qa_mblock_prims::test_connect()
309 // define the protocol class
310 mb_make_protocol_class(pmt_intern("data"), // name of class
311 pmt_list1(pmt_intern("data")), // in
314 mb_make_protocol_class(pmt_intern("i/o"), // name of class
315 pmt_list1(pmt_intern("in")), // in
316 pmt_list1(pmt_intern("out"))); // out
318 mb_mblock_sptr mb0 = mb_mblock_sptr(new tc_0());
321 ////////////////////////////////////////////////////////////////
324 qa_mblock_prims::test_msg_queue()
328 // check initial state
329 CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0);
331 CPPUNIT_ASSERT(MB_NPRI >= 5); // sanity check for this test
333 // insert three messages at the same pri and ensure that they come out in order
334 // signal data metadata pri
335 q.insert(mb_make_message(PMT_NIL, pmt_from_long(0), PMT_NIL, MB_PRI_BEST + 2));
336 q.insert(mb_make_message(PMT_NIL, pmt_from_long(1), PMT_NIL, MB_PRI_BEST + 2));
337 q.insert(mb_make_message(PMT_NIL, pmt_from_long(2), PMT_NIL, MB_PRI_BEST + 2));
339 CPPUNIT_ASSERT_EQUAL(0L, pmt_to_long(q.get_highest_pri_msg_nowait()->data()));
340 CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(q.get_highest_pri_msg_nowait()->data()));
341 CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(q.get_highest_pri_msg_nowait()->data()));
343 CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0);
346 // insert messages of different priorities in pseudo-random order
347 // signal data metadata pri
348 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 3));
349 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 2));
350 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 4));
351 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 0));
352 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 1));
353 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 3));
354 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 2));
355 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 4));
356 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 0));
357 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 1));
359 // confirm that they come out in order
360 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg_nowait()->priority());
361 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg_nowait()->priority());
362 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg_nowait()->priority());
363 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg_nowait()->priority());
364 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg_nowait()->priority());
365 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg_nowait()->priority());
366 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg_nowait()->priority());
367 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg_nowait()->priority());
368 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg_nowait()->priority());
369 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg_nowait()->priority());
372 CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0);
375 ////////////////////////////////////////////////////////////////
378 qa_mblock_prims::test_make_accepter()
381 mb_mblock_sptr mb = mb_mblock_sptr(new dp_2());
383 // use "internal use only" method...
384 mb_msg_accepter_sptr accepter = mb->impl()->make_accepter("cs");
386 // Now push a few messages into it...
387 // signal data metadata pri
388 (*accepter)(PMT_NIL, pmt_from_long(0), PMT_NIL, MB_PRI_BEST + 2);
389 (*accepter)(PMT_NIL, pmt_from_long(1), PMT_NIL, MB_PRI_BEST + 2);
390 (*accepter)(PMT_NIL, pmt_from_long(2), PMT_NIL, MB_PRI_BEST + 2);
392 // try to pull them out
394 pmt_t cs = pmt_intern("cs");
396 mb_message_sptr msg = mb->impl()->msgq().get_highest_pri_msg_nowait();
397 CPPUNIT_ASSERT(pmt_eq(cs, msg->port_id())); // confirm that port_id is set
398 CPPUNIT_ASSERT_EQUAL(0L, pmt_to_long(msg->data())); // and that data is correct
400 CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg_nowait()->data()));
401 CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg_nowait()->data()));