Files

329 lines
10 KiB
C++
Raw Permalink Normal View History

2025-12-01 15:56:02 +01:00
#include "tas.h"
#include "ns3/log.h"
#include "ns3/simulator.h"
#include "ns3/data-rate.h"
#include "ns3/enum.h"
#include <bitset>
#include <math.h>
#include "ns3/random-variable-stream.h"
#include "ns3/tsn-net-device.h"
#include "ns3/tsn-transmission-selection-algo.h"
namespace ns3
{
NS_LOG_COMPONENT_DEFINE("Tas");
NS_OBJECT_ENSURE_REGISTERED(Tas);
TypeId
Tas::GetTypeId()
{
static TypeId tid =
TypeId("ns3::Tas")
.SetParent<Object>()
.SetGroupName("Tsn")
.AddConstructor<Tas>()
.AddAttribute("GuardBandMode",
"Mode for the TAS guard band",
EnumValue(Tas::MTU),
MakeEnumAccessor(&Tas::m_GuardBandMode),
MakeEnumChecker(Tas::NONE, "NONE", Tas::MTU,"MTU", Tas::PKTSIZE, "PKTSIZE"))
.AddAttribute("MultidropMode",
"Mode for the 10Base-T1S",
BooleanValue(false),
MakeBooleanAccessor(&Tas::m_MultidropMode),
MakeBooleanChecker())
.AddTraceSource("GatesUpdate",
"Trace source indicating the current tas gate "
"states",
MakeTraceSourceAccessor(&Tas::m_gatesUpdate),
"ns3::TracedValueCallback::uint")
.AddAttribute("MaxGclEntryNumber",
"The maximum number of entry in the gate control list",
UintegerValue(65535),
MakeUintegerAccessor(&Tas::m_maxGclEntryNumber),
MakeUintegerChecker<uint16_t>())
.AddAttribute("MaxGclCycleDuration",
"The maximum duration of the gate control list",
TimeValue(Seconds(65535)),
MakeTimeAccessor(&Tas::m_maxGclCycleDuration),
MakeTimeChecker())
.AddAttribute("MaxGclTimeInterval",
"The maximum time interval of a gate control list entry",
TimeValue(Seconds(65535)),
MakeTimeAccessor(&Tas::m_maxGclTimeInterval),
MakeTimeChecker())
.AddAttribute("MinLatencyOverhead",
"The minimum latency overhead cause by the TAS hardware implementation",
TimeValue(Seconds(0)),
MakeTimeAccessor(&Tas::m_minLatencyOverhead),
MakeTimeChecker())
.AddAttribute("MaxLatencyOverhead",
"The maximun latency overhead cause by the TAS hardware implementation",
TimeValue(Seconds(0)),
MakeTimeAccessor(&Tas::m_maxLatencyOverhead),
MakeTimeChecker());
return tid;
}
Tas::Tas()
{
NS_LOG_FUNCTION(this);
}
Tas::~Tas()
{
NS_LOG_FUNCTION(this);
}
void
Tas::SetTsnNetDevice(Ptr<TsnNetDevice> net)
{
NS_LOG_FUNCTION(this);
m_net = net;
GateUpdateCallback = MakeCallback(&TsnNetDevice::CheckForReadyPacket, m_net);
}
bool
Tas::IsEnable()
{
NS_LOG_FUNCTION(this);
if(m_GateControlList.size()==0)
{
return false;
}
else
{
return true;
}
}
void
Tas::AddTsa(Ptr<TsnTransmissionSelectionAlgo> tsa)
{
NS_LOG_FUNCTION(this);
m_transmissionSelectionAlgos.insert(m_transmissionSelectionAlgos.end(), tsa);
}
void
Tas::AddTransmissionGate()
{
NS_LOG_FUNCTION(this);
m_transmissionGates.insert(m_transmissionGates.end(), CreateObject<TransmissionGate>());
}
bool
Tas::IsGateOpen(int i)
{
NS_LOG_FUNCTION(this << i);
return m_transmissionGates[i]->IsOpen();
}
void
Tas::AddGclEntry(Time duration, uint8_t states)
{
NS_LOG_FUNCTION(this);
NS_ASSERT_MSG(m_GateControlList.size() < m_maxGclEntryNumber, "Trying to add more GCL entry than the " << m_maxGclEntryNumber << " available.");
NS_ASSERT_MSG(duration <= m_maxGclTimeInterval, "Trying to add entry with longer time interval than the " << m_maxGclTimeInterval << " possible.");
NS_ASSERT_MSG(m_cycleDuration + duration <= m_maxGclCycleDuration, "Trying to create a longer TAS cycle than " << m_maxGclCycleDuration << " possible.");
GclEntry entry = {duration, states};
m_GateControlList.insert(m_GateControlList.end(), entry);
m_cycleDuration = m_cycleDuration + duration;
}
void
Tas::Start(){
NS_LOG_FUNCTION(this);
m_start = true;
UpdateGates(false);
}
void
Tas::ClockUpdate()
{
NS_LOG_FUNCTION(this);
UpdateGates(true);
}
void
Tas::UpdateGates(bool clockUpdate)
{
NS_LOG_FUNCTION(this);
if(m_GateControlList.size() == 0){ return;}
if(!m_start){ return;}
//Find the current gcl entry. Can't only do m_CurrentGclEntry = m_CurrentGclEntry + 1
//because synchronization and clock correction;
int oldCurrentGclEntry = m_CurrentGclEntry;
m_CurrentGclEntry = GetCurrentGclEntry();
GclEntry entry = m_GateControlList[m_CurrentGclEntry];
std::string binary = std::bitset<8>(entry.states).to_string();
std::reverse(binary.begin(), binary.end());
m_gatesUpdate(entry.states);
for (int i = 0; i < (int)binary.length(); i++){
std::string c{binary[i]};
int state = std::stoi(c);
if(state)
{
m_transmissionGates[i]->Open();
// NS_LOG_INFO(i << " Open");
}
else
{
m_transmissionGates[i]->Close();
// NS_LOG_INFO(i << " Close");
}
m_transmissionSelectionAlgos[i]->UpdateTransmissionGate(m_transmissionGates[i]->IsOpen());
}
//Compute in how much time the gates need to be update
Time delay = Time(0);
Ptr<Clock> activeClock = m_net->GetNode()->GetObject<TsnNode>()->GetActiveClock();
Time currentTime = activeClock->GetLocalTime();
if(!clockUpdate){
delay = activeClock->GetDuration(entry.duration); //Get duration to wait in the clock timebase
m_lastGateOpeningTime = currentTime;
}
else{
//Find the last gate opening time if the gcl entry change due to clock update
if(oldCurrentGclEntry != m_CurrentGclEntry)
{
m_lastGateOpeningTime = GetLastOpeningTime(currentTime);
}
delay = activeClock->GetDuration(entry.duration - (currentTime - m_lastGateOpeningTime));
}
Simulator::Cancel(m_NextGatesUpdate);
m_NextGatesUpdate = Simulator::Schedule(delay, &Tas::UpdateGates, this, false);
//To inform the TSN net device that the gate have change so it can check if a
//packet can be sent
if(m_CurrentGclEntry != oldCurrentGclEntry and !m_MultidropMode){
GateUpdateCallback();
}
}
int
Tas::GetCurrentGclEntry()
{
//Find the current position in the GCL according to the node clock
Time t = m_net->GetNode()->GetObject<TsnNode>()->GetActiveClock()->GetLocalTime();
t = (t-m_startTime)%m_cycleDuration;
Time duration = Time(0);
for(int i = 0; i<(int)m_GateControlList.size(); i++)
{
if (duration <= t && t< duration + m_GateControlList[i].duration)
{
return i;
}
duration = duration + m_GateControlList[i].duration;
}
NS_ASSERT_MSG(false, "Can't find current GCL entry");
return 0;
}
Time
Tas::GetLastOpeningTime(Time currentTime)
{
Time lastEntryTime = m_startTime + ((currentTime-m_startTime)/m_cycleDuration) * m_cycleDuration; //Last start of the cycle
for(int i = 0; i<(int)m_GateControlList.size(); i++)
{
if (lastEntryTime <= currentTime && currentTime< lastEntryTime + m_GateControlList[i].duration)
{
return lastEntryTime;
}
lastEntryTime = lastEntryTime + m_GateControlList[i].duration;
}
NS_ASSERT_MSG(false, "Can't find current GCL entry");
return Time(0);
}
bool
Tas::IsSendable(Ptr<const Packet> p, DataRate d, uint8_t preambleAndSFDGap, uint8_t interframeGap, uint32_t mtu)
{
NS_LOG_FUNCTION(this);
Ptr<Clock> clock = m_net->GetNode()->GetObject<TsnNode>()->GetActiveClock();
Time now =clock->GetLocalTime();
Time nextUpdate = Time(0);
if(Time::GetResolution()==Time::NS){
nextUpdate = clock->GetTimeAt(Time(NanoSeconds(m_NextGatesUpdate.GetTs())));
}
else if(Time::GetResolution()==Time::PS){
nextUpdate = clock->GetTimeAt(Time(PicoSeconds(m_NextGatesUpdate.GetTs())));
}
else{
NS_ASSERT_MSG(false, "TAS only support Time resolution in NS or PS.");
}
if(m_GuardBandMode==NONE)
{
return(true);
}
else if (m_GuardBandMode==PKTSIZE)
{
Time preambleAndSFDGapTime = d.CalculateBytesTxTime(preambleAndSFDGap);
Time txTime = d.CalculateBytesTxTime(p->GetSize());
Time interpacketGapTime = d.CalculateBytesTxTime(interframeGap);
Time txCompleteTime = preambleAndSFDGapTime + txTime + interpacketGapTime;
//Avoid guard band when schedule loop
//int entryId = GetCurrentGclEntry();
//uint8_t currentStates = m_GateControlList[entryId].states;
//int nextEntryId = entryId + 1;
//if (nextEntryId >= (int)m_GateControlList.size()){
// nextEntryId = 0;
//}
//uint8_t nextStates = m_GateControlList[nextEntryId].states;
//Time nextStatesDuration = m_GateControlList[nextEntryId].duration;
//End of "avoid guard band when shedule loop" modification
if(txCompleteTime <= nextUpdate -now)
{
return(true);
}
//Avoid guard band when schedule loop
//else if(nextStates == currentStates && txCompleteTime <= nextUpdate + nextStatesDuration - now)
//{
//If not enough time but next state is the same and enough time with the two combine slot ==> return True
//return(true);
//}
//End of "avoid guard band when shedule loop" modification
else
{
return(false);
}
}
else if (m_GuardBandMode==MTU)
{
if(d.CalculateBytesTxTime(mtu) <= nextUpdate -now)
{
return(true);
}
else
{
return(false);
}
}
return(false);
}
Time
Tas::GetHardwareLatency()
{
NS_LOG_FUNCTION(this);
Ptr<UniformRandomVariable> randVar = CreateObject<UniformRandomVariable>();
return NanoSeconds(randVar->GetValue(m_minLatencyOverhead.GetNanoSeconds(), m_maxLatencyOverhead.GetNanoSeconds()));
}
};