864 lines
30 KiB
C++
864 lines
30 KiB
C++
|
|
// 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<const Packet> p);
|
|
void ReceiveRx(Ptr<const Packet> 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<const Packet> p)
|
|
{
|
|
m_sent += p->GetSize();
|
|
}
|
|
|
|
void
|
|
TsnMultiDropBasicTestCase1Flow::ReceiveRx(Ptr<const Packet> 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<TsnNode> n0 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
|
|
|
|
|
//Create and add a netDevice to each node
|
|
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
|
|
net0->SetAttribute("PLCALocalNodeId", UintegerValue(0));
|
|
net0->SetAttribute("PLCANodeCount", UintegerValue(4));
|
|
n0->AddDevice(net0);
|
|
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
|
|
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
|
|
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
|
n1->AddDevice(net1);
|
|
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
|
|
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
|
|
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
|
|
n2->AddDevice(net2);
|
|
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
|
|
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<TsnMultidropChannel> channel = CreateObject<TsnMultidropChannel>();
|
|
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<DropTailQueue<Packet>>());
|
|
|
|
net1->SetAddress(Mac48Address::Allocate());
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
net2->SetAddress(Mac48Address::Allocate());
|
|
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
net3->SetAddress(Mac48Address::Allocate());
|
|
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
|
|
//Application description
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
|
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<const Packet> p);
|
|
void ReceiveRx(Ptr<const Packet> 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<const Packet> p)
|
|
{
|
|
m_sent += p->GetSize();
|
|
}
|
|
|
|
void
|
|
TsnMultiDropBasicTestCase3Flows::ReceiveRx(Ptr<const Packet> 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<TsnNode> n0 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
|
|
|
|
|
//Create and add a netDevice to each node
|
|
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
|
|
net0->SetAttribute("PLCALocalNodeId", UintegerValue(0));
|
|
net0->SetAttribute("PLCANodeCount", UintegerValue(4));
|
|
n0->AddDevice(net0);
|
|
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
|
|
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
|
|
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
|
n1->AddDevice(net1);
|
|
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
|
|
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
|
|
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
|
|
n2->AddDevice(net2);
|
|
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
|
|
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<TsnMultidropChannel> channel = CreateObject<TsnMultidropChannel>();
|
|
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<DropTailQueue<Packet>>());
|
|
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
net1->SetAddress(Mac48Address::Allocate());
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
net2->SetAddress(Mac48Address::Allocate());
|
|
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
net3->SetAddress(Mac48Address::Allocate());
|
|
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
|
|
//Application description
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
|
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<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
|
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<EthernetGenerator> app2 = CreateObject<EthernetGenerator>();
|
|
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<const Packet> 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<const Packet> p)
|
|
{
|
|
TimestampTag tag;
|
|
if (!p->FindFirstMatchingByteTag(tag))
|
|
{
|
|
return;
|
|
}
|
|
Ptr<Packet> 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<TsnNode> n0 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
|
|
|
|
|
//Create and add a netDevice to each node
|
|
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
|
|
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<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
|
|
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
|
|
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
|
n1->AddDevice(net1);
|
|
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
|
|
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<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
|
|
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<TsnMultidropChannel> channel = CreateObject<TsnMultidropChannel>();
|
|
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<DropTailQueue<Packet>>());
|
|
|
|
net1->SetAddress(Mac48Address::Allocate());
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
net2->SetAddress(Mac48Address::Allocate());
|
|
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
net3->SetAddress(Mac48Address::Allocate());
|
|
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
|
|
//Application description
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
|
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<const Packet> 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<const Packet> p)
|
|
{
|
|
TimestampTag tag;
|
|
if (!p->FindFirstMatchingByteTag(tag))
|
|
{
|
|
return;
|
|
}
|
|
Ptr<Packet> 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<TsnNode> n0 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
|
|
|
|
|
//Create and add a netDevice to each node
|
|
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
|
|
net0->SetAttribute("PLCALocalNodeId", UintegerValue(0));
|
|
net0->SetAttribute("PLCANodeCount", UintegerValue(4));
|
|
n0->AddDevice(net0);
|
|
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
|
|
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
|
|
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
|
n1->AddDevice(net1);
|
|
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
|
|
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
|
|
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
|
|
n2->AddDevice(net2);
|
|
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
|
|
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<TsnMultidropChannel> channel = CreateObject<TsnMultidropChannel>();
|
|
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<DropTailQueue<Packet>>());
|
|
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
net1->SetAddress(Mac48Address::Allocate());
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
net2->SetAddress(Mac48Address::Allocate());
|
|
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
net3->SetAddress(Mac48Address::Allocate());
|
|
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
|
|
//Application description
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
|
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<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
|
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<EthernetGenerator> app2 = CreateObject<EthernetGenerator>();
|
|
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<const Packet> p);
|
|
void ReceiveRxFromSwitchedNetwork(Ptr<const Packet> 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<const Packet> p)
|
|
{
|
|
m_received_from_10BaseT1S_bus += p->GetSize();
|
|
}
|
|
|
|
void
|
|
TsnMultiDropSwitchedBasicTestCase::ReceiveRxFromSwitchedNetwork(Ptr<const Packet> 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<TsnNode> n0 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
|
Ptr<TsnNode> n4 = CreateObject<TsnNode>();
|
|
|
|
|
|
//Create and add a netDevice to each node
|
|
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
|
n0->AddDevice(net0);
|
|
Ptr<TsnNetDevice> swnet0 = CreateObject<TsnNetDevice>();
|
|
n4->AddDevice(swnet0);
|
|
|
|
Ptr<TsnMultidropNetDevice> swnet1 = CreateObject<TsnMultidropNetDevice>();
|
|
swnet1->SetAttribute("PLCALocalNodeId", UintegerValue(0));
|
|
swnet1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
|
n4->AddDevice(swnet1);
|
|
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
|
|
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
|
|
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
|
n1->AddDevice(net1);
|
|
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
|
|
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
|
|
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
|
|
n2->AddDevice(net2);
|
|
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
|
|
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
|
|
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
|
|
n3->AddDevice(net3);
|
|
|
|
|
|
//Create a full-duplex channel
|
|
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
|
|
net0->Attach(channel0);
|
|
swnet0->Attach(channel0);
|
|
|
|
//Create a 10Base-T1S Channel and attach it two the netDevices
|
|
Ptr<TsnMultidropChannel> channel1 = CreateObject<TsnMultidropChannel>();
|
|
swnet1->Attach(channel1);
|
|
net1->Attach(channel1);
|
|
net2->Attach(channel1);
|
|
net3->Attach(channel1);
|
|
|
|
//Create and add a switch net device to the switch node
|
|
Ptr<SwitchNetDevice> sw = CreateObject<SwitchNetDevice>();
|
|
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<DropTailQueue<Packet>>());
|
|
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
net1->SetAddress(Mac48Address::Allocate());
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
net2->SetAddress(Mac48Address::Allocate());
|
|
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
net3->SetAddress(Mac48Address::Allocate());
|
|
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
swnet0->SetAddress(Mac48Address::Allocate());
|
|
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
swnet1->SetAddress(Mac48Address::Allocate());
|
|
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
|
|
|
//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<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
|
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<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
|
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;
|