Update README and add contrib dir
This commit is contained in:
328
contrib/tsn/model/tas.cc
Normal file
328
contrib/tsn/model/tas.cc
Normal file
@@ -0,0 +1,328 @@
|
||||
#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()));
|
||||
}
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user