Files
eden-sim/contrib/tsn/examples/tsn-point2point-withTAS-gPTP.cc

192 lines
6.3 KiB
C++
Raw Permalink Normal View History

2025-12-01 15:56:02 +01:00
#include "ns3/core-module.h"
#include "ns3/applications-module.h"
#include "ns3/command-line.h"
#include "ns3/simulator.h"
#include "ns3/node.h"
#include "ns3/drop-tail-queue.h"
#include <bitset>
#include "ns3/tsn-node.h"
#include "ns3/tsn-net-device.h"
#include "ns3/ethernet-channel.h"
#include "ns3/ethernet-generator.h"
#include "ns3/ethernet-header2.h"
#include "ns3/gPTP.h"
#include "ns3/clock.h"
#include "ns3/clock-constant-drift.h"
/**
* \file
*
* Example of the use of tsn-node.cc tsn-net-device.cc ethernet-channel.cc
* on a network composed of two end-stations connected by a 100Mb/s
* full duplex link with TAS on ES1 port. ES2 is GPTP grandmaster and ES1 is in
* slave state.
* ES1 ====== ES2
*/
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("Example");
//A callback to log the pkt reception
static void
MacRxCallback(std::string context, Ptr<const Packet> p)
{
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !");
}
//A callback to log the pkt emission
static void
PhyTxCallback(std::string context, Ptr<const Packet> p)
{
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " begin transmission !");
}
//A callback to log the gate update
static void
TasCallback(std::string context, uint8_t states)
{
Time t = Simulator::Now();
std::string str = "";
std::string binary = std::bitset<8>(states).to_string();
std::reverse(binary.begin(), binary.end());
for (int i = 0; i < (int)binary.length(); i++) {
str += " Fifo " + std::to_string(i);
std::string c{binary[i]};
int state = std::stoi(c);
if(state)
{
str += " Open ;";
}
else
{
str += " Close;";
}
}
NS_LOG_INFO(context << " : At "<< t.GetNanoSeconds() <<" Tas gate states update :" << str);
}
static void
ClockAfterCorrectionCallback(std::string context, Time clockValue)
{
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << " clock value after correction = " << clockValue.GetNanoSeconds() << "ns (error = "<< (Simulator::Now()-clockValue).GetNanoSeconds() << "ns)");
}
int
main(int argc, char* argv[])
{
//Enable logging
LogComponentEnable("Example", LOG_LEVEL_INFO);
LogComponentEnable("TsnNode", LOG_LEVEL_INFO);
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
LogComponentEnable("Tas", LOG_LEVEL_INFO);
LogComponentEnable("Clock", LOG_LEVEL_INFO);
// LogComponentEnable("GPTP", LOG_LEVEL_INFO);
CommandLine cmd(__FILE__);
cmd.Parse(argc, argv);
//Create two nodes
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
Names::Add("ES1", n0);
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
Names::Add("ES2", n1);
//Create and add clock to TsnNode
Ptr<ConstantDriftClock> c0 = CreateObject<ConstantDriftClock>();
c0->SetAttribute("InitialOffset", TimeValue(Seconds(5)));
c0->SetAttribute("DriftRate", DoubleValue(50));
c0->SetAttribute("Granularity", TimeValue(NanoSeconds(1)));
n0->SetMainClock(c0);
Ptr<Clock> c1 = CreateObject<Clock>(); //Perfect clock for the GM
n1->SetMainClock(c1);
//Create and add a netDevice to each node
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n0->AddDevice(net0);
Names::Add("ES1#01", net0);
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n1->AddDevice(net1);
Names::Add("ES2#01", net1);
//Create a Ethernet Channel and attach it two the two netDevices
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
channel->SetAttribute("Delay", TimeValue(NanoSeconds(200)));
net0->Attach(channel);
net1->Attach(channel);
//Allocate a Mac address
net0->SetAddress(Mac48Address::Allocate());
net1->SetAddress(Mac48Address::Allocate());
//Create and add eight FIFO on each net device
for (int i=0; i<8; i++)
{
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
}
//Add and configure GPTP
Ptr<GPTP> gPTP0 = CreateObject<GPTP>();
gPTP0->SetNode(n0);
gPTP0->SetMainClock(c0);
gPTP0->AddDomain(0);
gPTP0->AddPort(net0, GPTP::SLAVE, 0);
gPTP0->SetAttribute("Priority", UintegerValue(0));
n0->AddApplication(gPTP0);
gPTP0->SetStartTime(Seconds(0));
Ptr<GPTP> gPTP1 = CreateObject<GPTP>();
gPTP1->SetNode(n1);
gPTP1->SetMainClock(c1);
gPTP1->AddDomain(0);
gPTP1->AddPort(net1, GPTP::MASTER, 0);
gPTP1->SetAttribute("Priority", UintegerValue(0));
n1->AddApplication(gPTP1);
gPTP1->SetStartTime(Seconds(0));
//Add two GCL entry on net0 and start TAS
//(must be done after GPTP declaration due to clock declaration)
net0->AddGclEntry(Time(MilliSeconds(10)), 1);
net0->AddGclEntry(Time(MilliSeconds(10)), 2);
net0->StartTas();
//Application description
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
app0->Setup(net0);
app0->SetAttribute("BurstSize", UintegerValue(1));
app0->SetAttribute("PayloadSize", UintegerValue(1400));
app0->SetAttribute("Period", TimeValue(MilliSeconds(15)));
app0->SetAttribute("PCP", UintegerValue(1));
app0->SetAttribute("VlanID", UintegerValue(100));
n0->AddApplication(app0);
app0->SetStartTime(Seconds(0));
app0->SetStopTime(Seconds(4));
//Callback to display the packet transmitted and received log
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
//Callback to display the gate update log (must be before StartTas() to display the initial gate states)
net0->GetTas()->TraceConnectWithoutContext("GatesUpdate", MakeBoundCallback(&TasCallback, Names::FindName(net0)));
//Callback to monitor synchronization
gPTP0->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n0)));
//Execute the simulation
Simulator::Stop(Seconds(1.5));
Simulator::Run();
Simulator::Destroy();
return 0;
}