// Include a header file from your module to test. #include "ns3/tsn-multidrop-net-device.h" #include "ns3/tsn-multidrop-channel.h" #include "ns3/tsn-net-device.h" #include "ns3/tsn-node.h" #include "ns3/ethernet-channel.h" #include "ns3/ethernet-header2.h" #include "ns3/ethernet-generator.h" #include "ns3/switch-net-device.h" // An essential include is test.h #include "ns3/test.h" #include "ns3/core-module.h" #include "ns3/drop-tail-queue.h" #include "ns3/timestamp-tag.h" // Do not put your test classes in namespace ns3. You may find it useful // to use the using directive to access the ns3 namespace directly using namespace ns3; NS_LOG_COMPONENT_DEFINE("TsnMultidropTestSuite"); // Add a doxygen group for tests. // If you have more than one test, this should be in only one of them. /** * \defgroup tsn-multidrop-tests Tests for multidrop tsn * \ingroup tsn * \ingroup tests */ /** * \ingroup tsn-multidrop-tests * Check if message crossed an tsn multidrop channel */ class TsnMultiDropBasicTestCase1Flow : public TestCase { public: TsnMultiDropBasicTestCase1Flow(); virtual ~TsnMultiDropBasicTestCase1Flow(); private: void DoRun() override; void SendTx(Ptr p); void ReceiveRx(Ptr p); uint64_t m_sent{0}; //!< number of bytes sent uint64_t m_received{0}; //!< number of bytes received }; // Add some help text to this case to describe what it is intended to test TsnMultiDropBasicTestCase1Flow::TsnMultiDropBasicTestCase1Flow() : TestCase("Check if message crossed an tsn multidrop channel") { } // This destructor does nothing but we include it as a reminder that // the test case should clean up after itself TsnMultiDropBasicTestCase1Flow::~TsnMultiDropBasicTestCase1Flow() { } void TsnMultiDropBasicTestCase1Flow::SendTx(Ptr p) { m_sent += p->GetSize(); } void TsnMultiDropBasicTestCase1Flow::ReceiveRx(Ptr p) { m_received += p->GetSize(); } // // This method is the pure virtual method from class TestCase that every // TestCase must implement // void TsnMultiDropBasicTestCase1Flow::DoRun() { //Create four nodes Ptr n0 = CreateObject(); Ptr n1 = CreateObject(); Ptr n2 = CreateObject(); Ptr n3 = CreateObject(); //Create and add a netDevice to each node Ptr net0 = CreateObject(); net0->SetAttribute("PLCALocalNodeId", UintegerValue(0)); net0->SetAttribute("PLCANodeCount", UintegerValue(4)); n0->AddDevice(net0); Ptr net1 = CreateObject(); net1->SetAttribute("PLCALocalNodeId", UintegerValue(1)); net1->SetAttribute("PLCANodeCount", UintegerValue(4)); n1->AddDevice(net1); Ptr net2 = CreateObject(); net2->SetAttribute("PLCALocalNodeId", UintegerValue(2)); net2->SetAttribute("PLCANodeCount", UintegerValue(4)); n2->AddDevice(net2); Ptr net3 = CreateObject(); net3->SetAttribute("PLCALocalNodeId", UintegerValue(3)); net3->SetAttribute("PLCANodeCount", UintegerValue(4)); n3->AddDevice(net3); //Create a 10Base-T1S Channel and attach it two the netDevices Ptr channel = CreateObject(); net0->Attach(channel); net1->Attach(channel); net2->Attach(channel); net3->Attach(channel); //Allocate a Mac address and create a FIFO (for the output port) //for each netDevice. net0->SetAddress(Mac48Address::Allocate()); net0->SetQueue(CreateObject>()); net1->SetAddress(Mac48Address::Allocate()); net1->SetQueue(CreateObject>()); net2->SetAddress(Mac48Address::Allocate()); net2->SetQueue(CreateObject>()); net3->SetAddress(Mac48Address::Allocate()); net3->SetQueue(CreateObject>()); //Application description Ptr app0 = CreateObject(); app0->Setup(net0); app0->SetAttribute("BurstSize", UintegerValue(10)); app0->SetAttribute("PayloadSize", UintegerValue(1400)); app0->SetAttribute("Period", TimeValue(Seconds(5))); app0->SetAttribute("VlanID", UintegerValue(1)); app0->SetStartTime(Seconds(0)); app0->SetStopTime(Seconds(10)); n0->AddApplication(app0); //Callback to trace the message being send and received net0->TraceConnectWithoutContext("MacTx", MakeCallback(&TsnMultiDropBasicTestCase1Flow::SendTx, this)); net1->TraceConnectWithoutContext("MacRx", MakeCallback(&TsnMultiDropBasicTestCase1Flow::ReceiveRx, this)); //Execute the simulation Simulator::Stop(Seconds(12)); Simulator::Run(); Simulator::Destroy(); NS_TEST_ASSERT_MSG_EQ(m_sent, 2 * 10 * (1400 + 22), "10 Packets have been sent two times"); NS_TEST_ASSERT_MSG_EQ(m_sent, m_received, "All Packets sent have been received"); } /** * \ingroup tsn-multidrop-tests * Check if message crossed an tsn multidrop channel from multiple * sources. */ class TsnMultiDropBasicTestCase3Flows : public TestCase { public: TsnMultiDropBasicTestCase3Flows(); virtual ~TsnMultiDropBasicTestCase3Flows(); private: void DoRun() override; void SendTx(Ptr p); void ReceiveRx(Ptr p); uint64_t m_sent{0}; //!< number of bytes sent uint64_t m_received{0}; //!< number of bytes received }; // Add some help text to this case to describe what it is intended to test TsnMultiDropBasicTestCase3Flows::TsnMultiDropBasicTestCase3Flows() : TestCase("Check if message crossed an tsn multidrop channel from" " multiple sources") { } // This destructor does nothing but we include it as a reminder that // the test case should clean up after itself TsnMultiDropBasicTestCase3Flows::~TsnMultiDropBasicTestCase3Flows() { } void TsnMultiDropBasicTestCase3Flows::SendTx(Ptr p) { m_sent += p->GetSize(); } void TsnMultiDropBasicTestCase3Flows::ReceiveRx(Ptr p) { m_received += p->GetSize(); } // // This method is the pure virtual method from class TestCase that every // TestCase must implement // void TsnMultiDropBasicTestCase3Flows::DoRun() { //Create four nodes Ptr n0 = CreateObject(); Ptr n1 = CreateObject(); Ptr n2 = CreateObject(); Ptr n3 = CreateObject(); //Create and add a netDevice to each node Ptr net0 = CreateObject(); net0->SetAttribute("PLCALocalNodeId", UintegerValue(0)); net0->SetAttribute("PLCANodeCount", UintegerValue(4)); n0->AddDevice(net0); Ptr net1 = CreateObject(); net1->SetAttribute("PLCALocalNodeId", UintegerValue(1)); net1->SetAttribute("PLCANodeCount", UintegerValue(4)); n1->AddDevice(net1); Ptr net2 = CreateObject(); net2->SetAttribute("PLCALocalNodeId", UintegerValue(2)); net2->SetAttribute("PLCANodeCount", UintegerValue(4)); n2->AddDevice(net2); Ptr net3 = CreateObject(); net3->SetAttribute("PLCALocalNodeId", UintegerValue(3)); net3->SetAttribute("PLCANodeCount", UintegerValue(4)); n3->AddDevice(net3); //Create a 10Base-T1S Channel and attach it two the netDevices Ptr channel = CreateObject(); net0->Attach(channel); net1->Attach(channel); net2->Attach(channel); net3->Attach(channel); //Allocate a Mac address and create a FIFO (for the output port) //for each netDevice. net0->SetAddress(Mac48Address::Allocate()); net0->SetQueue(CreateObject>()); net0->SetQueue(CreateObject>()); net1->SetAddress(Mac48Address::Allocate()); net1->SetQueue(CreateObject>()); net1->SetQueue(CreateObject>()); net2->SetAddress(Mac48Address::Allocate()); net2->SetQueue(CreateObject>()); net2->SetQueue(CreateObject>()); net3->SetAddress(Mac48Address::Allocate()); net3->SetQueue(CreateObject>()); net3->SetQueue(CreateObject>()); //Application description Ptr app0 = CreateObject(); app0->Setup(net0); app0->SetAttribute("BurstSize", UintegerValue(10)); app0->SetAttribute("PayloadSize", UintegerValue(1400)); app0->SetAttribute("Period", TimeValue(Seconds(5))); app0->SetAttribute("VlanID", UintegerValue(1)); app0->SetStartTime(Seconds(0)); app0->SetStopTime(Seconds(10)); n0->AddApplication(app0); Ptr app1 = CreateObject(); app1->Setup(net1); app1->SetAttribute("BurstSize", UintegerValue(1)); app1->SetAttribute("PayloadSize", UintegerValue(100)); app1->SetAttribute("Period", TimeValue(Seconds(5))); app1->SetAttribute("VlanID", UintegerValue(1)); app1->SetAttribute("PCP", UintegerValue(1)); app1->SetStartTime(Seconds(0)); app1->SetStopTime(Seconds(10)); n1->AddApplication(app1); Ptr app2 = CreateObject(); app2->Setup(net2); app2->SetAttribute("BurstSize", UintegerValue(2)); app2->SetAttribute("PayloadSize", UintegerValue(500)); app2->SetAttribute("Period", TimeValue(Seconds(5))); app2->SetAttribute("VlanID", UintegerValue(1)); app2->SetAttribute("PCP", UintegerValue(1)); app2->SetStartTime(Seconds(6)); app2->SetStopTime(Seconds(7)); n3->AddApplication(app2); //Callback to trace the message being send and received net0->TraceConnectWithoutContext("MacTx", MakeCallback(&TsnMultiDropBasicTestCase3Flows::SendTx, this)); net1->TraceConnectWithoutContext("MacRx", MakeCallback(&TsnMultiDropBasicTestCase3Flows::ReceiveRx, this)); net2->TraceConnectWithoutContext("MacRx", MakeCallback(&TsnMultiDropBasicTestCase3Flows::ReceiveRx, this)); //Execute the simulation Simulator::Stop(Seconds(12)); Simulator::Run(); Simulator::Destroy(); NS_TEST_ASSERT_MSG_EQ(m_sent, 2 * 10 * (1400 + 22), "10 Packets have been sent two times by net0"); NS_TEST_ASSERT_MSG_EQ(m_received, 2*2*10*(1400 + 22) + 2*1*(100+22) + 2*1*(500+22), "All Packets sent have been received"); } /** * \ingroup tsn-multidrop-tests * Check if message crossed an tsn multidrop channel with the expected latency */ class TsnMultiDropLatencyTestCase1Flow : public TestCase { public: TsnMultiDropLatencyTestCase1Flow(bool isLocalNodeId0, Time startTime, Time expectedLatency); virtual ~TsnMultiDropLatencyTestCase1Flow(); private: void DoRun() override; void LatencyCallback(Ptr p); bool m_is_local_node_id_0; Time m_expected_latency; Time m_latency; Time m_start_time; }; // Add some help text to this case to describe what it is intended to test TsnMultiDropLatencyTestCase1Flow::TsnMultiDropLatencyTestCase1Flow(bool isLocalNodeId0, Time startTime, Time expectedLatency) : TestCase("Check if message crossed an tsn multidrop channel with the expected latency") { m_is_local_node_id_0 = isLocalNodeId0; m_expected_latency = expectedLatency; m_start_time = startTime; } // This destructor does nothing but we include it as a reminder that // the test case should clean up after itself TsnMultiDropLatencyTestCase1Flow::~TsnMultiDropLatencyTestCase1Flow() { } void TsnMultiDropLatencyTestCase1Flow::LatencyCallback(Ptr p) { TimestampTag tag; if (!p->FindFirstMatchingByteTag(tag)) { return; } Ptr originalPacket = p->Copy(); EthernetHeader2 ethHeader; originalPacket->RemoveHeader(ethHeader); if (ethHeader.GetVid()!=1) { return; } Time arrival = Simulator::Now(); m_latency = arrival - tag.GetTimestamp(); } // // This method is the pure virtual method from class TestCase that every // TestCase must implement // void TsnMultiDropLatencyTestCase1Flow::DoRun() { //Create four nodes Ptr n0 = CreateObject(); Ptr n1 = CreateObject(); Ptr n2 = CreateObject(); Ptr n3 = CreateObject(); //Create and add a netDevice to each node Ptr net0 = CreateObject(); if (m_is_local_node_id_0){ net0->SetAttribute("PLCALocalNodeId", UintegerValue(0)); } else { net0->SetAttribute("PLCALocalNodeId", UintegerValue(2)); } net0->SetAttribute("PLCANodeCount", UintegerValue(4)); n0->AddDevice(net0); Ptr net1 = CreateObject(); net1->SetAttribute("PLCALocalNodeId", UintegerValue(1)); net1->SetAttribute("PLCANodeCount", UintegerValue(4)); n1->AddDevice(net1); Ptr net2 = CreateObject(); if (m_is_local_node_id_0){ net2->SetAttribute("PLCALocalNodeId", UintegerValue(2)); } else { net2->SetAttribute("PLCALocalNodeId", UintegerValue(0)); } net2->SetAttribute("PLCANodeCount", UintegerValue(4)); n2->AddDevice(net2); Ptr net3 = CreateObject(); net3->SetAttribute("PLCALocalNodeId", UintegerValue(3)); net3->SetAttribute("PLCANodeCount", UintegerValue(4)); n3->AddDevice(net3); //Create a 10Base-T1S Channel and attach it two the netDevices Ptr channel = CreateObject(); net0->Attach(channel); net1->Attach(channel); net2->Attach(channel); net3->Attach(channel); //Allocate a Mac address and create a FIFO (for the output port) //for each netDevice. net0->SetAddress(Mac48Address::Allocate()); net0->SetQueue(CreateObject>()); net1->SetAddress(Mac48Address::Allocate()); net1->SetQueue(CreateObject>()); net2->SetAddress(Mac48Address::Allocate()); net2->SetQueue(CreateObject>()); net3->SetAddress(Mac48Address::Allocate()); net3->SetQueue(CreateObject>()); //Application description Ptr app0 = CreateObject(); app0->Setup(net0); app0->SetAttribute("BurstSize", UintegerValue(1)); app0->SetAttribute("PayloadSize", UintegerValue(1400)); app0->SetAttribute("Period", TimeValue(Seconds(5))); app0->SetAttribute("VlanID", UintegerValue(1)); app0->SetStartTime(m_start_time); app0->SetStopTime(Seconds(1)); n0->AddApplication(app0); //Callback to trace the message being send and received net1->TraceConnectWithoutContext("Latency", MakeCallback(&TsnMultiDropLatencyTestCase1Flow::LatencyCallback, this)); //Execute the simulation Simulator::Stop(Seconds(1)); Simulator::Run(); Simulator::Destroy(); NS_TEST_ASSERT_MSG_EQ(m_latency, m_expected_latency, "The simulated latency is equal to the expected latency"); } /** * \ingroup tsn-multidrop-tests * Check if message crossed an tsn multidrop channel with the expected latency * when the channel is shared with two other flows */ class TsnMultiDropLatencyTestCase3Flows : public TestCase { public: TsnMultiDropLatencyTestCase3Flows(uint8_t burstSize, uint8_t priority, Time startTime, Time expectedLatency); virtual ~TsnMultiDropLatencyTestCase3Flows(); private: void DoRun() override; void LatencyCallback(Ptr p); uint8_t m_burst_size; uint8_t m_priority; Time m_expected_latency; Time m_latency; Time m_start_time; }; // Add some help text to this case to describe what it is intended to test TsnMultiDropLatencyTestCase3Flows::TsnMultiDropLatencyTestCase3Flows(uint8_t burstSize, uint8_t priority, Time startTime, Time expectedLatency) : TestCase("Check if message crossed an tsn multidrop channel with the " "expected latency when the channel is shared with two other flows") { m_burst_size = burstSize; m_priority = priority; m_expected_latency = expectedLatency; m_start_time = startTime; } // This destructor does nothing but we include it as a reminder that // the test case should clean up after itself TsnMultiDropLatencyTestCase3Flows::~TsnMultiDropLatencyTestCase3Flows() { } void TsnMultiDropLatencyTestCase3Flows::LatencyCallback(Ptr p) { TimestampTag tag; if (!p->FindFirstMatchingByteTag(tag)) { return; } Ptr originalPacket = p->Copy(); EthernetHeader2 ethHeader; originalPacket->RemoveHeader(ethHeader); if (ethHeader.GetVid()!=1) { return; } Time arrival = Simulator::Now(); m_latency = arrival - tag.GetTimestamp(); } // // This method is the pure virtual method from class TestCase that every // TestCase must implement // void TsnMultiDropLatencyTestCase3Flows::DoRun() { //Create four nodes Ptr n0 = CreateObject(); Ptr n1 = CreateObject(); Ptr n2 = CreateObject(); Ptr n3 = CreateObject(); //Create and add a netDevice to each node Ptr net0 = CreateObject(); net0->SetAttribute("PLCALocalNodeId", UintegerValue(0)); net0->SetAttribute("PLCANodeCount", UintegerValue(4)); n0->AddDevice(net0); Ptr net1 = CreateObject(); net1->SetAttribute("PLCALocalNodeId", UintegerValue(1)); net1->SetAttribute("PLCANodeCount", UintegerValue(4)); n1->AddDevice(net1); Ptr net2 = CreateObject(); net2->SetAttribute("PLCALocalNodeId", UintegerValue(2)); net2->SetAttribute("PLCANodeCount", UintegerValue(4)); n2->AddDevice(net2); Ptr net3 = CreateObject(); net3->SetAttribute("PLCALocalNodeId", UintegerValue(3)); net3->SetAttribute("PLCANodeCount", UintegerValue(4)); n3->AddDevice(net3); //Create a 10Base-T1S Channel and attach it two the netDevices Ptr channel = CreateObject(); net0->Attach(channel); net1->Attach(channel); net2->Attach(channel); net3->Attach(channel); //Allocate a Mac address and create a FIFO (for the output port) //for each netDevice. net0->SetAddress(Mac48Address::Allocate()); net0->SetQueue(CreateObject>()); net0->SetQueue(CreateObject>()); net1->SetAddress(Mac48Address::Allocate()); net1->SetQueue(CreateObject>()); net1->SetQueue(CreateObject>()); net2->SetAddress(Mac48Address::Allocate()); net2->SetQueue(CreateObject>()); net2->SetQueue(CreateObject>()); net3->SetAddress(Mac48Address::Allocate()); net3->SetQueue(CreateObject>()); net3->SetQueue(CreateObject>()); //Application description Ptr app0 = CreateObject(); app0->Setup(net0); app0->SetAttribute("BurstSize", UintegerValue(m_burst_size)); app0->SetAttribute("PayloadSize", UintegerValue(1400)); app0->SetAttribute("Period", TimeValue(Seconds(5))); app0->SetAttribute("VlanID", UintegerValue(1)); app0->SetAttribute("PCP", UintegerValue(m_priority)); app0->SetStartTime(m_start_time); app0->SetStopTime(Seconds(1)); n0->AddApplication(app0); Ptr app1 = CreateObject(); app1->Setup(net0); app1->SetAttribute("BurstSize", UintegerValue(2)); app1->SetAttribute("PayloadSize", UintegerValue(1000)); app1->SetAttribute("Period", TimeValue(Seconds(5))); app1->SetAttribute("VlanID", UintegerValue(2)); app1->SetAttribute("PCP", UintegerValue(0)); app1->SetStartTime(NanoSeconds(10)); app1->SetStopTime(Seconds(1)); n0->AddApplication(app1); Ptr app2 = CreateObject(); app2->Setup(net2); app2->SetAttribute("BurstSize", UintegerValue(1)); app2->SetAttribute("PayloadSize", UintegerValue(100)); app2->SetAttribute("Period", TimeValue(Seconds(5))); app2->SetAttribute("VlanID", UintegerValue(3)); app2->SetAttribute("PCP", UintegerValue(1)); app2->SetStartTime(NanoSeconds(0)); app2->SetStopTime(Seconds(1)); n2->AddApplication(app2); //Callback to trace the message being send and received net1->TraceConnectWithoutContext("Latency", MakeCallback(&TsnMultiDropLatencyTestCase3Flows::LatencyCallback, this)); //Execute the simulation Simulator::Stop(Seconds(1)); Simulator::Run(); Simulator::Destroy(); NS_TEST_ASSERT_MSG_EQ(m_latency, m_expected_latency, "The simulated latency is equal to the expected latency"); } /** * \ingroup tsn-multidrop-tests * Check if message can crossed from a switched network to a 10Base-T1S bus * and from a 10Base-T1S bus to a switched network */ class TsnMultiDropSwitchedBasicTestCase : public TestCase { public: TsnMultiDropSwitchedBasicTestCase(); virtual ~TsnMultiDropSwitchedBasicTestCase(); private: void DoRun() override; void ReceiveRxFrom10BaseT1SBus(Ptr p); void ReceiveRxFromSwitchedNetwork(Ptr p); uint64_t m_received_from_switched_network{0}; //!< number of bytes uint64_t m_received_from_10BaseT1S_bus{0}; //!< number of bytes }; // Add some help text to this case to describe what it is intended to test TsnMultiDropSwitchedBasicTestCase::TsnMultiDropSwitchedBasicTestCase() : TestCase("Check if message can crossed from a switched network to a 10Base-T1S" "bus and from a 10Base-T1S bus to a switched network") { } // This destructor does nothing but we include it as a reminder that // the test case should clean up after itself TsnMultiDropSwitchedBasicTestCase::~TsnMultiDropSwitchedBasicTestCase() { } void TsnMultiDropSwitchedBasicTestCase::ReceiveRxFrom10BaseT1SBus(Ptr p) { m_received_from_10BaseT1S_bus += p->GetSize(); } void TsnMultiDropSwitchedBasicTestCase::ReceiveRxFromSwitchedNetwork(Ptr p) { m_received_from_switched_network += p->GetSize(); } // // This method is the pure virtual method from class TestCase that every // TestCase must implement // void TsnMultiDropSwitchedBasicTestCase::DoRun() { //Create four nodes Ptr n0 = CreateObject(); Ptr n1 = CreateObject(); Ptr n2 = CreateObject(); Ptr n3 = CreateObject(); Ptr n4 = CreateObject(); //Create and add a netDevice to each node Ptr net0 = CreateObject(); n0->AddDevice(net0); Ptr swnet0 = CreateObject(); n4->AddDevice(swnet0); Ptr swnet1 = CreateObject(); swnet1->SetAttribute("PLCALocalNodeId", UintegerValue(0)); swnet1->SetAttribute("PLCANodeCount", UintegerValue(4)); n4->AddDevice(swnet1); Ptr net1 = CreateObject(); net1->SetAttribute("PLCALocalNodeId", UintegerValue(1)); net1->SetAttribute("PLCANodeCount", UintegerValue(4)); n1->AddDevice(net1); Ptr net2 = CreateObject(); net2->SetAttribute("PLCALocalNodeId", UintegerValue(2)); net2->SetAttribute("PLCANodeCount", UintegerValue(4)); n2->AddDevice(net2); Ptr net3 = CreateObject(); net3->SetAttribute("PLCALocalNodeId", UintegerValue(3)); net3->SetAttribute("PLCANodeCount", UintegerValue(4)); n3->AddDevice(net3); //Create a full-duplex channel Ptr channel0 = CreateObject(); net0->Attach(channel0); swnet0->Attach(channel0); //Create a 10Base-T1S Channel and attach it two the netDevices Ptr channel1 = CreateObject(); swnet1->Attach(channel1); net1->Attach(channel1); net2->Attach(channel1); net3->Attach(channel1); //Create and add a switch net device to the switch node Ptr sw = CreateObject(); sw->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10))); sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10))); n4->AddDevice(sw); sw->AddSwitchPort(swnet0); sw->AddSwitchPort(swnet1); //Allocate a Mac address and create a FIFO (for the output port) //for each netDevice. net0->SetAddress(Mac48Address::Allocate()); net0->SetQueue(CreateObject>()); net0->SetQueue(CreateObject>()); net1->SetAddress(Mac48Address::Allocate()); net1->SetQueue(CreateObject>()); net1->SetQueue(CreateObject>()); net2->SetAddress(Mac48Address::Allocate()); net2->SetQueue(CreateObject>()); net2->SetQueue(CreateObject>()); net3->SetAddress(Mac48Address::Allocate()); net3->SetQueue(CreateObject>()); net3->SetQueue(CreateObject>()); swnet0->SetAddress(Mac48Address::Allocate()); swnet0->SetQueue(CreateObject>()); swnet0->SetQueue(CreateObject>()); swnet1->SetAddress(Mac48Address::Allocate()); swnet1->SetQueue(CreateObject>()); swnet1->SetQueue(CreateObject>()); //Add forwarding table sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net1->GetAddress()), 10, {swnet1}); sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net0->GetAddress()), 20, {swnet0}); //Application description //From switched network to 10Base-T1S Ptr app0 = CreateObject(); app0->Setup(net0); app0->SetAttribute("Address", AddressValue(net1->GetAddress())); app0->SetAttribute("BurstSize", UintegerValue(5)); app0->SetAttribute("PayloadSize", UintegerValue(1400)); app0->SetAttribute("Period", TimeValue(Seconds(5))); app0->SetAttribute("VlanID", UintegerValue(10)); app0->SetAttribute("PCP", UintegerValue(0)); n0->AddApplication(app0); app0->SetStartTime(Seconds(0)); app0->SetStopTime(Seconds(10)); //From 10Base-T1S to switched network Ptr app1 = CreateObject(); app1->Setup(net1); app1->SetAttribute("Address", AddressValue(net0->GetAddress())); app1->SetAttribute("BurstSize", UintegerValue(2)); app1->SetAttribute("PayloadSize", UintegerValue(100)); app1->SetAttribute("Period", TimeValue(Seconds(5))); app1->SetAttribute("VlanID", UintegerValue(20)); app1->SetAttribute("PCP", UintegerValue(1)); n1->AddApplication(app1); app1->SetStartTime(Seconds(0)); app1->SetStopTime(Seconds(10)); //Callback to trace the message being send and received net0->TraceConnectWithoutContext("MacRx", MakeCallback(&TsnMultiDropSwitchedBasicTestCase::ReceiveRxFrom10BaseT1SBus, this)); net1->TraceConnectWithoutContext("MacRx", MakeCallback(&TsnMultiDropSwitchedBasicTestCase::ReceiveRxFromSwitchedNetwork, this)); //Execute the simulation Simulator::Stop(Seconds(12)); Simulator::Run(); Simulator::Destroy(); NS_TEST_ASSERT_MSG_EQ(m_received_from_10BaseT1S_bus, 2 * 2 * (100 + 22), "4 Packets have been received two times by net0"); NS_TEST_ASSERT_MSG_EQ(m_received_from_switched_network, 2 * 5 * (1400 + 22), "10 Packets have been received two times by net1"); } // The TestSuite class names the TestSuite, identifies what type of TestSuite, // and enables the TestCases to be run. Typically, only the constructor for // this class must be defined /** * \ingroup tsn-multidrop-tests * TestSuite for module tsn with a focus on multidrop */ class TsnMultidropTestSuite : public TestSuite { public: TsnMultidropTestSuite(); }; TsnMultidropTestSuite::TsnMultidropTestSuite() : TestSuite("tsn-multidrop", UNIT) { LogComponentEnable("TsnMultidropTestSuite", LOG_LEVEL_ALL); //Multidrop channel AddTestCase(new TsnMultiDropBasicTestCase1Flow, TestCase::QUICK); AddTestCase(new TsnMultiDropBasicTestCase3Flows, TestCase::QUICK); // Latency with one flow on the channel //Wait for 10Base-T1S init when producer is local nodeId = 0 AddTestCase(new TsnMultiDropLatencyTestCase1Flow(true, Time(NanoSeconds(0)), Time(NanoSeconds(((1400 + 22 + 8) + 1 * 20 + 4 * 32)*800 + 25))), TestCase::QUICK); //Frame ready just before the opportunity when producer is local nodeId = 0 AddTestCase(new TsnMultiDropLatencyTestCase1Flow(true, Time(NanoSeconds((20 + 4 *32) * 800 - 1)), Time(NanoSeconds((1400 + 22 + 8)*800 + 1 + 25))), TestCase::QUICK); //Wait for 10Base-T1S init when producer is local nodeId = 2 AddTestCase(new TsnMultiDropLatencyTestCase1Flow(false, Time(NanoSeconds(0)), Time(NanoSeconds(((1400 + 22 + 8) + 1 * 20 + (4 + 2) * 32)*800 + 25))), TestCase::QUICK); //Latency with multiple flows on the channel AddTestCase(new TsnMultiDropLatencyTestCase3Flows(1, 0, Time(NanoSeconds(0)), Time(NanoSeconds(((1400 + 22 + 8) + 1 * 20 + 4 * 32)*800 + 25))), TestCase::QUICK); AddTestCase(new TsnMultiDropLatencyTestCase3Flows(2, 0, Time(NanoSeconds(0)), Time(NanoSeconds(((1400 + 22 + 8) + 2 * 20 + (4+2) * 32 + (1400 + 22 + 8 + 12 + 100 + 22 + 8 + 12))*800 + 25 * 3))), TestCase::QUICK); AddTestCase(new TsnMultiDropLatencyTestCase3Flows(2, 0, Time(NanoSeconds(11)), Time(NanoSeconds(((1400 + 22 + 8) + 4 * 20 + (4+ 2 + 3 + 3) * 32 + (1042 * 2 + 1442 + 142))*800 + 25 * 3 - 11))), TestCase::QUICK); AddTestCase(new TsnMultiDropLatencyTestCase3Flows(2, 1, Time(NanoSeconds(11)), Time(NanoSeconds(((1400 + 22 + 8) + 2 * 20 + (4+ 2) * 32 + (1442 + 142))*800 + 25 * 3 - 11))), TestCase::QUICK); //Switched network connected to a multidrop channel AddTestCase(new TsnMultiDropSwitchedBasicTestCase, TestCase::QUICK); } // Do not forget to allocate an instance of this TestSuite /** * \ingroup tsn-tests * Static variable for test initialization */ static TsnMultidropTestSuite m_tsnMultidropTestSuite;