3 * Copyright 2006,2007,2008 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 3, 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 <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>
42 static pmt_t s_cs = pmt_intern("cs");
43 static pmt_t s_debug = pmt_intern("debug");
44 static pmt_t s_in = pmt_intern("in");
45 static pmt_t s_out = pmt_intern("out");
48 // ================================================================
50 class dp_1 : public mb_mblock
53 dp_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
57 dp_1::dp_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
58 : mb_mblock(runtime, instance_name, user_arg)
64 REGISTER_MBLOCK_CLASS(dp_1);
66 // ----------------------------------------------------------------
68 class dp_2 : public mb_mblock
71 dp_2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
75 dp_2::dp_2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
76 : mb_mblock(runtime, instance_name, user_arg)
78 define_port("cs", "cs-protocol", false, mb_port::EXTERNAL);
83 REGISTER_MBLOCK_CLASS(dp_2);
85 // ----------------------------------------------------------------
87 class dp_3 : public mb_mblock
90 dp_3(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
94 dp_3::dp_3(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
95 : mb_mblock(runtime, instance_name, user_arg)
97 define_port("cs", "cs-protocol", false, mb_port::EXTERNAL);
98 define_port("cs", "cs-protocol", false, mb_port::EXTERNAL); // duplicate def
103 REGISTER_MBLOCK_CLASS(dp_3);
105 // ----------------------------------------------------------------
108 qa_mblock_prims::test_define_ports()
111 mb_runtime_sptr rts = mb_make_runtime();
112 mb_runtime *rt = rts.get();
115 mb_mblock_sptr mb1 = mb_mblock_sptr(new dp_1(rt, "top", PMT_F));
117 // raises runtime_error because of unknown protocol "cs-protocol"
118 CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_2(rt, "top", PMT_F)),
121 // define the protocol class
122 pmt_t pc = mb_make_protocol_class(pmt_intern("cs-protocol"),
123 pmt_list2(pmt_intern("start"),
127 // std::cout << "pc = " << pc << '\n';
129 mb_mblock_sptr mb2 = mb_mblock_sptr(new dp_2(rt, "top", PMT_F));
131 // raises pmt_exception because of duplicate port definition of "cs"
132 CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_3(rt, "top", PMT_F)),
136 // ================================================================
138 class dc_0 : public mb_mblock
141 dc_0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
145 dc_0::dc_0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
146 : mb_mblock(runtime, instance_name, user_arg)
152 REGISTER_MBLOCK_CLASS(dc_0);
154 // ----------------------------------------------------------------
156 class dc_ok : public mb_mblock
159 dc_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
163 dc_ok::dc_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
164 : mb_mblock(runtime, instance_name, user_arg)
166 define_component("c0", "dc_0");
167 define_component("c1", "dc_0");
168 define_component("c2", "dc_0");
173 REGISTER_MBLOCK_CLASS(dc_ok);
175 // ----------------------------------------------------------------
177 class dc_not_ok : public mb_mblock
180 dc_not_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
184 dc_not_ok::dc_not_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
185 : mb_mblock(runtime, instance_name, user_arg)
187 define_component("c0", "dc_0");
188 define_component("c0", "dc_0"); // duplicate name
191 dc_not_ok::~dc_not_ok(){}
193 REGISTER_MBLOCK_CLASS(dc_not_ok);
195 // ----------------------------------------------------------------
198 qa_mblock_prims::test_define_components()
200 mb_runtime_sptr rts = mb_make_runtime();
201 mb_runtime *rt = rts.get();
204 mb_mblock_sptr mb1 = mb_mblock_sptr(new dc_ok(rt, "top", PMT_F));
206 // raises pmt_exception because of duplicate component definition of "c0"
207 CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dc_not_ok(rt, "top", PMT_F)),
208 mbe_duplicate_component);
211 // ================================================================
213 class tc_norm : public mb_mblock
216 tc_norm(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
217 : mb_mblock(runtime, instance_name, user_arg)
219 define_port("data", "i/o", false, mb_port::EXTERNAL);
220 define_port("norm", "i/o", false, mb_port::EXTERNAL);
221 define_port("conj", "i/o", true, mb_port::EXTERNAL);
222 define_port("int", "i/o", false, mb_port::INTERNAL);
228 tc_norm::~tc_norm(){}
230 REGISTER_MBLOCK_CLASS(tc_norm);
232 ////////////////////////////////////////////////////////////////
234 class tc_0 : public mb_mblock
237 tc_0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
238 : mb_mblock(runtime, instance_name, user_arg)
240 define_port("norm", "i/o", false, mb_port::EXTERNAL);
241 define_port("conj", "i/o", true, mb_port::EXTERNAL);
242 define_port("int", "i/o", false, mb_port::INTERNAL);
244 define_component("c0", "tc_norm");
245 define_component("c1", "tc_norm");
246 define_component("c2", "tc_norm");
247 define_component("c3", "tc_norm");
248 define_component("c4", "tc_norm");
249 define_component("c5", "tc_norm");
252 connect("c0", "norm", "c1", "conj");
254 // No: No such component name
255 CPPUNIT_ASSERT_THROW(connect("foo", "data", "c1", "norm"), mbe_no_such_component);
257 // No: No such port name
258 CPPUNIT_ASSERT_THROW(connect("c0", "data", "c1", "foo"), mbe_no_such_port);
260 // No: already connected
261 CPPUNIT_ASSERT_THROW(connect("c0", "norm", "c2", "data"), mbe_already_connected);
263 // No: already connected
264 CPPUNIT_ASSERT_THROW(connect("c2", "data", "c0", "norm"), mbe_already_connected);
266 // No: incompatible ports
267 CPPUNIT_ASSERT_THROW(connect("c1", "norm", "c2", "norm"), mbe_incompatible_ports);
270 connect("c1", "norm", "c2", "conj");
272 // No: No such port name
273 CPPUNIT_ASSERT_THROW(connect("c2", "norm", "self", "foo"), mbe_no_such_port);
275 // No: can't connect to child's internal port
276 CPPUNIT_ASSERT_THROW(connect("c0", "conj", "c2", "int"), mbe_no_such_port);
278 // No: can't connect to our own external port
279 CPPUNIT_ASSERT_THROW(connect("self", "norm", "c0", "conj"), mbe_invalid_port_type);
281 // OK: connecting to one of our internal ports
282 connect("self", "int", "c3", "conj");
284 // ===== Now test disconnecting some stuff =====
286 // Confirm we're already connected
287 CPPUNIT_ASSERT_THROW(connect("self", "int", "c3", "conj"), mbe_already_connected);
289 int nc = nconnections();
290 disconnect("self", "int", "c3", "conj"); // disconnect
291 CPPUNIT_ASSERT_EQUAL(nc-1, nconnections());
293 connect("self", "int", "c3", "conj"); // reconnect
294 CPPUNIT_ASSERT_EQUAL(nc, nconnections());
296 // confirm we're already connected
297 CPPUNIT_ASSERT_THROW(connect("self", "int", "c3", "conj"), mbe_already_connected);
300 connect("c0", "conj", "c5", "data");
301 connect("c4", "norm", "c5", "conj");
302 connect("c4", "conj", "c5", "norm");
305 disconnect_component("c4");
306 CPPUNIT_ASSERT_EQUAL(nc-2, nconnections());
308 disconnect_component("c5");
309 CPPUNIT_ASSERT_EQUAL(nc-3, nconnections());
312 CPPUNIT_ASSERT_EQUAL(0, nconnections());
321 REGISTER_MBLOCK_CLASS(tc_0);
323 ////////////////////////////////////////////////////////////////
325 class tc_1 : public mb_mblock
328 tc_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
329 : mb_mblock(runtime, instance_name, user_arg)
331 define_component("c0", "tc_norm");
332 define_component("c1", "tc_norm");
334 connect("c0", "norm", "c1", "conj");
342 REGISTER_MBLOCK_CLASS(tc_1);
344 ////////////////////////////////////////////////////////////////
347 qa_mblock_prims::test_connect()
349 // define the protocol class
350 mb_make_protocol_class(pmt_intern("data"), // name of class
351 pmt_list1(pmt_intern("data")), // in
354 mb_make_protocol_class(pmt_intern("i/o"), // name of class
355 pmt_list1(pmt_intern("in")), // in
356 pmt_list1(pmt_intern("out"))); // out
358 mb_runtime_sptr rts = mb_make_runtime();
359 mb_runtime *rt = rts.get();
361 mb_mblock_sptr mb0 = mb_mblock_sptr(new tc_0(rt, "top", PMT_F));
364 ////////////////////////////////////////////////////////////////
367 qa_mblock_prims::test_msg_queue()
371 // check initial state
372 CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0);
374 CPPUNIT_ASSERT(MB_NPRI >= 5); // sanity check for this test
376 // insert three messages at the same pri and ensure that they come out in order
377 // signal data metadata pri
378 q.insert(mb_make_message(PMT_NIL, pmt_from_long(0), PMT_NIL, MB_PRI_BEST + 2));
379 q.insert(mb_make_message(PMT_NIL, pmt_from_long(1), PMT_NIL, MB_PRI_BEST + 2));
380 q.insert(mb_make_message(PMT_NIL, pmt_from_long(2), PMT_NIL, MB_PRI_BEST + 2));
382 CPPUNIT_ASSERT_EQUAL(0L, pmt_to_long(q.get_highest_pri_msg_nowait()->data()));
383 CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(q.get_highest_pri_msg_nowait()->data()));
384 CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(q.get_highest_pri_msg_nowait()->data()));
386 CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0);
389 // insert messages of different priorities in pseudo-random order
390 // signal data metadata pri
391 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 3));
392 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 2));
393 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 4));
394 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 0));
395 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 1));
396 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 3));
397 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 2));
398 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 4));
399 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 0));
400 q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 1));
402 // confirm that they come out in order
403 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg_nowait()->priority());
404 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg_nowait()->priority());
405 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg_nowait()->priority());
406 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg_nowait()->priority());
407 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg_nowait()->priority());
408 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg_nowait()->priority());
409 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg_nowait()->priority());
410 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg_nowait()->priority());
411 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg_nowait()->priority());
412 CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg_nowait()->priority());
415 CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0);
418 ////////////////////////////////////////////////////////////////
421 qa_mblock_prims::test_make_accepter()
423 mb_runtime_sptr rts = mb_make_runtime();
424 mb_runtime *rt = rts.get();
427 mb_mblock_sptr mb = mb_mblock_sptr(new dp_2(rt, "top", PMT_F));
429 // use "internal use only" method...
430 mb_msg_accepter_sptr accepter = mb->impl()->make_accepter(pmt_intern("cs"));
432 // Now push a few messages into it...
433 // signal data metadata pri
434 (*accepter)(PMT_NIL, pmt_from_long(0), PMT_NIL, MB_PRI_BEST + 2);
435 (*accepter)(PMT_NIL, pmt_from_long(1), PMT_NIL, MB_PRI_BEST + 2);
436 (*accepter)(PMT_NIL, pmt_from_long(2), PMT_NIL, MB_PRI_BEST + 2);
438 // try to pull them out
440 pmt_t cs = pmt_intern("cs");
442 mb_message_sptr msg = mb->impl()->msgq().get_highest_pri_msg_nowait();
443 CPPUNIT_ASSERT(pmt_eq(cs, msg->port_id())); // confirm that port_id is set
444 CPPUNIT_ASSERT_EQUAL(0L, pmt_to_long(msg->data())); // and that data is correct
446 CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg_nowait()->data()));
447 CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg_nowait()->data()));