/* -*- c++ -*- */ /* * Copyright 2006,2007,2008 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 GNU Radio; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include static pmt_t s_cs = pmt_intern("cs"); static pmt_t s_debug = pmt_intern("debug"); static pmt_t s_in = pmt_intern("in"); static pmt_t s_out = pmt_intern("out"); // ================================================================ class dp_1 : public mb_mblock { public: dp_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); ~dp_1(); }; dp_1::dp_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) : mb_mblock(runtime, instance_name, user_arg) { } dp_1::~dp_1(){} REGISTER_MBLOCK_CLASS(dp_1); // ---------------------------------------------------------------- class dp_2 : public mb_mblock { public: dp_2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); ~dp_2(); }; dp_2::dp_2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) : mb_mblock(runtime, instance_name, user_arg) { define_port("cs", "cs-protocol", false, mb_port::EXTERNAL); } dp_2::~dp_2(){} REGISTER_MBLOCK_CLASS(dp_2); // ---------------------------------------------------------------- class dp_3 : public mb_mblock { public: dp_3(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); ~dp_3(); }; dp_3::dp_3(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) : mb_mblock(runtime, instance_name, user_arg) { define_port("cs", "cs-protocol", false, mb_port::EXTERNAL); define_port("cs", "cs-protocol", false, mb_port::EXTERNAL); // duplicate def } dp_3::~dp_3(){} REGISTER_MBLOCK_CLASS(dp_3); // ---------------------------------------------------------------- void qa_mblock_prims::test_define_ports() { mb_runtime_sptr rts = mb_make_runtime(); mb_runtime *rt = rts.get(); // Should work mb_mblock_sptr mb1 = mb_mblock_sptr(new dp_1(rt, "top", PMT_F)); // raises runtime_error because of unknown protocol "cs-protocol" CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_2(rt, "top", PMT_F)), std::runtime_error); // define the protocol class pmt_t pc = mb_make_protocol_class(pmt_intern("cs-protocol"), pmt_list2(pmt_intern("start"), pmt_intern("stop")), PMT_NIL); // std::cout << "pc = " << pc << '\n'; mb_mblock_sptr mb2 = mb_mblock_sptr(new dp_2(rt, "top", PMT_F)); // raises pmt_exception because of duplicate port definition of "cs" CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_3(rt, "top", PMT_F)), mbe_duplicate_port); } // ================================================================ class dc_0 : public mb_mblock { public: dc_0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); ~dc_0(); }; dc_0::dc_0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) : mb_mblock(runtime, instance_name, user_arg) { } dc_0::~dc_0() {} REGISTER_MBLOCK_CLASS(dc_0); // ---------------------------------------------------------------- class dc_ok : public mb_mblock { public: dc_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); ~dc_ok(); }; dc_ok::dc_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) : mb_mblock(runtime, instance_name, user_arg) { define_component("c0", "dc_0"); define_component("c1", "dc_0"); define_component("c2", "dc_0"); } dc_ok::~dc_ok(){} REGISTER_MBLOCK_CLASS(dc_ok); // ---------------------------------------------------------------- class dc_not_ok : public mb_mblock { public: dc_not_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg); ~dc_not_ok(); }; dc_not_ok::dc_not_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) : mb_mblock(runtime, instance_name, user_arg) { define_component("c0", "dc_0"); define_component("c0", "dc_0"); // duplicate name } dc_not_ok::~dc_not_ok(){} REGISTER_MBLOCK_CLASS(dc_not_ok); // ---------------------------------------------------------------- void qa_mblock_prims::test_define_components() { mb_runtime_sptr rts = mb_make_runtime(); mb_runtime *rt = rts.get(); // Should work mb_mblock_sptr mb1 = mb_mblock_sptr(new dc_ok(rt, "top", PMT_F)); // raises pmt_exception because of duplicate component definition of "c0" CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dc_not_ok(rt, "top", PMT_F)), mbe_duplicate_component); } // ================================================================ class tc_norm : public mb_mblock { public: tc_norm(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) : mb_mblock(runtime, instance_name, user_arg) { define_port("data", "i/o", false, mb_port::EXTERNAL); define_port("norm", "i/o", false, mb_port::EXTERNAL); define_port("conj", "i/o", true, mb_port::EXTERNAL); define_port("int", "i/o", false, mb_port::INTERNAL); } ~tc_norm(); }; tc_norm::~tc_norm(){} REGISTER_MBLOCK_CLASS(tc_norm); //////////////////////////////////////////////////////////////// class tc_0 : public mb_mblock { public: tc_0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) : mb_mblock(runtime, instance_name, user_arg) { define_port("norm", "i/o", false, mb_port::EXTERNAL); define_port("conj", "i/o", true, mb_port::EXTERNAL); define_port("int", "i/o", false, mb_port::INTERNAL); define_component("c0", "tc_norm"); define_component("c1", "tc_norm"); define_component("c2", "tc_norm"); define_component("c3", "tc_norm"); define_component("c4", "tc_norm"); define_component("c5", "tc_norm"); // OK connect("c0", "norm", "c1", "conj"); // No: No such component name CPPUNIT_ASSERT_THROW(connect("foo", "data", "c1", "norm"), mbe_no_such_component); // No: No such port name CPPUNIT_ASSERT_THROW(connect("c0", "data", "c1", "foo"), mbe_no_such_port); // No: already connected CPPUNIT_ASSERT_THROW(connect("c0", "norm", "c2", "data"), mbe_already_connected); // No: already connected CPPUNIT_ASSERT_THROW(connect("c2", "data", "c0", "norm"), mbe_already_connected); // No: incompatible ports CPPUNIT_ASSERT_THROW(connect("c1", "norm", "c2", "norm"), mbe_incompatible_ports); // OK connect("c1", "norm", "c2", "conj"); // No: No such port name CPPUNIT_ASSERT_THROW(connect("c2", "norm", "self", "foo"), mbe_no_such_port); // No: can't connect to child's internal port CPPUNIT_ASSERT_THROW(connect("c0", "conj", "c2", "int"), mbe_no_such_port); // No: can't connect to our own external port CPPUNIT_ASSERT_THROW(connect("self", "norm", "c0", "conj"), mbe_invalid_port_type); // OK: connecting to one of our internal ports connect("self", "int", "c3", "conj"); // ===== Now test disconnecting some stuff ===== // Confirm we're already connected CPPUNIT_ASSERT_THROW(connect("self", "int", "c3", "conj"), mbe_already_connected); int nc = nconnections(); disconnect("self", "int", "c3", "conj"); // disconnect CPPUNIT_ASSERT_EQUAL(nc-1, nconnections()); connect("self", "int", "c3", "conj"); // reconnect CPPUNIT_ASSERT_EQUAL(nc, nconnections()); // confirm we're already connected CPPUNIT_ASSERT_THROW(connect("self", "int", "c3", "conj"), mbe_already_connected); connect("c0", "conj", "c5", "data"); connect("c4", "norm", "c5", "conj"); connect("c4", "conj", "c5", "norm"); nc = nconnections(); disconnect_component("c4"); CPPUNIT_ASSERT_EQUAL(nc-2, nconnections()); disconnect_component("c5"); CPPUNIT_ASSERT_EQUAL(nc-3, nconnections()); disconnect_all(); CPPUNIT_ASSERT_EQUAL(0, nconnections()); } ~tc_0(); }; tc_0::~tc_0(){} REGISTER_MBLOCK_CLASS(tc_0); //////////////////////////////////////////////////////////////// class tc_1 : public mb_mblock { public: tc_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg) : mb_mblock(runtime, instance_name, user_arg) { define_component("c0", "tc_norm"); define_component("c1", "tc_norm"); connect("c0", "norm", "c1", "conj"); } ~tc_1(); }; tc_1::~tc_1(){} REGISTER_MBLOCK_CLASS(tc_1); //////////////////////////////////////////////////////////////// void qa_mblock_prims::test_connect() { // define the protocol class mb_make_protocol_class(pmt_intern("data"), // name of class pmt_list1(pmt_intern("data")), // in PMT_NIL); // out mb_make_protocol_class(pmt_intern("i/o"), // name of class pmt_list1(pmt_intern("in")), // in pmt_list1(pmt_intern("out"))); // out mb_runtime_sptr rts = mb_make_runtime(); mb_runtime *rt = rts.get(); mb_mblock_sptr mb0 = mb_mblock_sptr(new tc_0(rt, "top", PMT_F)); } //////////////////////////////////////////////////////////////// void qa_mblock_prims::test_msg_queue() { mb_msg_queue q; // check initial state CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0); CPPUNIT_ASSERT(MB_NPRI >= 5); // sanity check for this test // insert three messages at the same pri and ensure that they come out in order // signal data metadata pri q.insert(mb_make_message(PMT_NIL, pmt_from_long(0), PMT_NIL, MB_PRI_BEST + 2)); q.insert(mb_make_message(PMT_NIL, pmt_from_long(1), PMT_NIL, MB_PRI_BEST + 2)); q.insert(mb_make_message(PMT_NIL, pmt_from_long(2), PMT_NIL, MB_PRI_BEST + 2)); CPPUNIT_ASSERT_EQUAL(0L, pmt_to_long(q.get_highest_pri_msg_nowait()->data())); CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(q.get_highest_pri_msg_nowait()->data())); CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(q.get_highest_pri_msg_nowait()->data())); CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0); // insert messages of different priorities in pseudo-random order // signal data metadata pri q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 3)); q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 2)); q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 4)); q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 0)); q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 1)); q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 3)); q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 2)); q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 4)); q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 0)); q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 1)); // confirm that they come out in order CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg_nowait()->priority()); CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg_nowait()->priority()); CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg_nowait()->priority()); CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg_nowait()->priority()); CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg_nowait()->priority()); CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg_nowait()->priority()); CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg_nowait()->priority()); CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg_nowait()->priority()); CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg_nowait()->priority()); CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg_nowait()->priority()); // check final state CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0); } //////////////////////////////////////////////////////////////// void qa_mblock_prims::test_make_accepter() { mb_runtime_sptr rts = mb_make_runtime(); mb_runtime *rt = rts.get(); // create a block mb_mblock_sptr mb = mb_mblock_sptr(new dp_2(rt, "top", PMT_F)); // use "internal use only" method... mb_msg_accepter_sptr accepter = mb->impl()->make_accepter(pmt_intern("cs")); // Now push a few messages into it... // signal data metadata pri (*accepter)(PMT_NIL, pmt_from_long(0), PMT_NIL, MB_PRI_BEST + 2); (*accepter)(PMT_NIL, pmt_from_long(1), PMT_NIL, MB_PRI_BEST + 2); (*accepter)(PMT_NIL, pmt_from_long(2), PMT_NIL, MB_PRI_BEST + 2); // try to pull them out pmt_t cs = pmt_intern("cs"); mb_message_sptr msg = mb->impl()->msgq().get_highest_pri_msg_nowait(); CPPUNIT_ASSERT(pmt_eq(cs, msg->port_id())); // confirm that port_id is set CPPUNIT_ASSERT_EQUAL(0L, pmt_to_long(msg->data())); // and that data is correct CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg_nowait()->data())); CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg_nowait()->data())); }