#include "cbs.h" #include "ns3/tsn-transmission-selection-algo.h" #include "ns3/log.h" #include "ns3/nstime.h" #include "ns3/uinteger.h" #include "ns3/data-rate.h" #include "ns3/simulator.h" #include "ns3/traced-callback.h" namespace ns3 { NS_LOG_COMPONENT_DEFINE("Cbs"); NS_OBJECT_ENSURE_REGISTERED(Cbs); TypeId Cbs::GetTypeId() { static TypeId tid = TypeId("ns3::Cbs") .SetParent() .SetGroupName("Tsn") .AddConstructor() .AddAttribute("IdleSlope", "CBS idle slope parameter in bit/s", DataRateValue(DataRate("1Gb/s")), MakeDataRateAccessor(&Cbs::m_idleSlope), MakeDataRateChecker()) .AddAttribute("portTransmitRate", "CBS port transmit rate parameter in bit/s", DataRateValue(DataRate("1Gb/s")), MakeDataRateAccessor(&Cbs::m_portTransmitRate), MakeDataRateChecker()) .AddTraceSource("Credit", "CBS credit", MakeTraceSourceAccessor(&Cbs::m_creditTrace), "ns3::TracedValueCallback::double") .AddAttribute("MaxIdleSlope", "CBS idle slope parameter in bit/s", DataRateValue(DataRate("1000Gb/s")), MakeDataRateAccessor(&Cbs::m_maxIdleSlope), MakeDataRateChecker()); return tid; } Cbs::Cbs() { NS_LOG_FUNCTION(this); m_credit = 0; m_state = IDLE; m_transmissionGateIsOpen = true; m_lastUpdateCreditTime = Simulator::Now(); } Cbs::~Cbs() { NS_LOG_FUNCTION(this); } bool Cbs::IsReadyToTransmit() { NS_LOG_FUNCTION(this); if(m_credit>=0){ return true; } else{ m_state = WAITING; return false; } } void Cbs::Update() { NS_LOG_FUNCTION(this); if (m_state != TRANSMITTING) { if (m_queue->IsEmpty()) { m_state = IDLE; } else { m_state = WAITING; } } UpdateCredit(false); } void Cbs::UpdateCredit(bool trigger_cb) { NS_LOG_FUNCTION(this); NS_ASSERT_MSG(m_idleSlope < m_maxIdleSlope, "Trying to use an idleSlope higher than " << m_maxIdleSlope << "."); Time sinceLastCreditUpdate = Simulator::Now() - m_lastUpdateCreditTime; if(m_transmissionGateIsOpen){ if(m_state == WAITING) { m_credit = m_credit + sinceLastCreditUpdate.GetSeconds() * m_idleSlope.GetBitRate(); } else if(m_state == IDLE) { double newCredit = m_credit + sinceLastCreditUpdate.GetSeconds() * m_idleSlope.GetBitRate(); if(newCredit>=0) { m_creditTrace(m_credit); //Hit the trace before reseting for nicer plot m_credit = 0; } else if(newCredit<0) { m_credit = newCredit; } } } m_creditTrace(m_credit); m_lastUpdateCreditTime = Simulator::Now(); if(m_credit < 0 && m_transmissionGateIsOpen){ Time nextUdpateDelay = Time(Seconds((-m_credit/m_idleSlope.GetBitRate()))); NS_LOG_INFO("Now " << m_lastUpdateCreditTime.GetNanoSeconds()); NS_LOG_INFO("Next update in " << nextUdpateDelay.GetNanoSeconds()); NS_LOG_INFO("Credit : " << m_credit << "\n"); if(Time::GetResolution()==Time::NS and nextUdpateDelay.GetNanoSeconds()==0) { //To solve infinit event schedule due to rounding error nextUdpateDelay = Time(NanoSeconds(1)); } else if(Time::GetResolution()==Time::PS and nextUdpateDelay.GetPicoSeconds()==0) { //To solve infinit event schedule due to rounding error nextUdpateDelay = Time(PicoSeconds(1)); } Simulator::Cancel(m_NextCreditUpdate); m_NextCreditUpdate = Simulator::Schedule(nextUdpateDelay, &Cbs::UpdateCredit, this, true); } if(trigger_cb && m_credit >= 0 && m_state==WAITING) { NS_ASSERT_MSG (m_net != nullptr, "NetDevice not set in CBS. Use cbs->SetTsnNetDevice(net);"); if (!m_MultidropMode) { ReadyToTransmitCallback(); } } } void Cbs::TransmitStart(Ptr p, Time txTime) { NS_LOG_FUNCTION(this); m_state = TRANSMITTING; UpdateCredit(true); } void Cbs::TransmitComplete(Ptr p) { NS_LOG_FUNCTION(this); if (m_queue->IsEmpty()){ m_state = IDLE; } else{ m_state = WAITING; } int64_t sendSlope = m_idleSlope.GetBitRate() - m_portTransmitRate.GetBitRate(); Time sinceLastCreditUpdate = Simulator::Now() - m_lastUpdateCreditTime; m_credit = m_credit + sendSlope*sinceLastCreditUpdate.GetSeconds(); m_lastUpdateCreditTime = Simulator::Now(); UpdateCredit(true); } void Cbs::UpdateTransmissionGate(bool IsOpen) { NS_LOG_FUNCTION(this); UpdateCredit(true); m_transmissionGateIsOpen = IsOpen; UpdateCredit(true); if (not IsOpen) { Simulator::Cancel(m_NextCreditUpdate); } } };