If Create<>() is used to create an object of an Object subclass, attributes are not initialized.
494 lines
14 KiB
C++
494 lines
14 KiB
C++
/*
|
|
* Copyright (c) 2007,2008,2009 INRIA, UDcast
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-only
|
|
*
|
|
* Authors: Jahanzeb Farooq <jahanzeb.farooq@sophia.inria.fr>
|
|
* Mohamed Amine Ismail <amine.ismail@sophia.inria.fr>
|
|
* <amine.ismail@UDcast.com>
|
|
*/
|
|
|
|
#include "ss-link-manager.h"
|
|
|
|
#include "burst-profile-manager.h"
|
|
#include "service-flow-manager.h"
|
|
|
|
#include "ns3/enum.h"
|
|
#include "ns3/log.h"
|
|
#include "ns3/node.h"
|
|
#include "ns3/packet.h"
|
|
#include "ns3/pointer.h"
|
|
#include "ns3/simulator.h"
|
|
|
|
#include <cstdint>
|
|
|
|
namespace ns3
|
|
{
|
|
|
|
NS_LOG_COMPONENT_DEFINE("SSLinkManager");
|
|
|
|
NS_OBJECT_ENSURE_REGISTERED(SSLinkManager);
|
|
|
|
TypeId
|
|
SSLinkManager::GetTypeId()
|
|
{
|
|
static TypeId tid = TypeId("ns3::SSLinkManager").SetParent<Object>().SetGroupName("Wimax");
|
|
return tid;
|
|
}
|
|
|
|
SSLinkManager::SSLinkManager(Ptr<SubscriberStationNetDevice> ss)
|
|
: m_ss(ss),
|
|
m_rangingStatus(WimaxNetDevice::RANGING_STATUS_EXPIRED),
|
|
m_bsEirp(65535),
|
|
m_eirXPIrMax(65535),
|
|
m_pTxIrMax(0),
|
|
m_initRangOppNumber(0),
|
|
m_contentionRangingRetries(0),
|
|
m_rngReqFrameNumber(0),
|
|
m_dlChnlNr(0),
|
|
m_frequency(0),
|
|
m_rangingIntervalFound(false),
|
|
m_nrRngReqsSent(0),
|
|
m_nrRngRspsRecvd(0),
|
|
m_nrInvitedPollsRecvd(0),
|
|
m_rangingCW(0),
|
|
m_rangingBO(0),
|
|
m_nrRangingTransOpps(0),
|
|
m_isBackoffSet(false),
|
|
m_rangingAnomalies(0)
|
|
{
|
|
}
|
|
|
|
SSLinkManager::~SSLinkManager()
|
|
{
|
|
m_ss = nullptr;
|
|
}
|
|
|
|
void
|
|
SSLinkManager::DoDispose()
|
|
{
|
|
m_ss = nullptr;
|
|
}
|
|
|
|
void
|
|
SSLinkManager::SetBsEirp(uint16_t bs_eirp)
|
|
{
|
|
m_bsEirp = bs_eirp;
|
|
}
|
|
|
|
void
|
|
SSLinkManager::SetEirXPIrMax(uint16_t eir_x_p_ir_max)
|
|
{
|
|
m_eirXPIrMax = eir_x_p_ir_max;
|
|
}
|
|
|
|
void
|
|
SSLinkManager::SetRangingIntervalFound(bool rangingIntervalFound)
|
|
{
|
|
m_rangingIntervalFound = rangingIntervalFound;
|
|
}
|
|
|
|
bool
|
|
SSLinkManager::GetRangingIntervalFound() const
|
|
{
|
|
return m_rangingIntervalFound;
|
|
}
|
|
|
|
void
|
|
SSLinkManager::SetNrRangingTransOpps(uint8_t nrRangingTransOpps)
|
|
{
|
|
m_nrRangingTransOpps = nrRangingTransOpps;
|
|
}
|
|
|
|
void
|
|
SSLinkManager::SetRangingCW(uint8_t rangingCW)
|
|
{
|
|
m_rangingCW = rangingCW;
|
|
}
|
|
|
|
void
|
|
SSLinkManager::IncrementNrInvitedPollsRecvd()
|
|
{
|
|
m_nrInvitedPollsRecvd++;
|
|
}
|
|
|
|
EventId
|
|
SSLinkManager::GetDlMapSyncTimeoutEvent()
|
|
{
|
|
return m_dlMapSyncTimeoutEvent;
|
|
}
|
|
|
|
void
|
|
SSLinkManager::StartScanning(SubscriberStationNetDevice::EventType type, bool deleteParameters)
|
|
{
|
|
// temp parameter "type" just to check on expiry of which event the function was called
|
|
|
|
if (deleteParameters)
|
|
{
|
|
DeleteUplinkParameters();
|
|
}
|
|
|
|
NS_ASSERT_MSG(!m_ss->IsRegistered(),
|
|
"Subscriber Station: Error while scanning: Already registered with a BS");
|
|
|
|
if (m_ss->GetState() != SubscriberStationNetDevice::SS_STATE_IDLE)
|
|
{
|
|
m_dlChnlNr++;
|
|
}
|
|
|
|
// using max number of channel according to according to Section 8.5.1 of IEEE 802.16-2004
|
|
// standard.
|
|
if (m_dlChnlNr >= 200)
|
|
{
|
|
m_dlChnlNr = 0;
|
|
}
|
|
|
|
uint64_t dlChannel = m_ss->GetChannel(m_dlChnlNr);
|
|
|
|
m_ss->SetState(SubscriberStationNetDevice::SS_STATE_SCANNING);
|
|
m_ss->GetPhy()->StartScanning(dlChannel,
|
|
m_ss->GetIntervalT20(),
|
|
MakeCallback(&SSLinkManager::EndScanning, this));
|
|
}
|
|
|
|
void
|
|
SSLinkManager::EndScanning(bool status, uint64_t frequency)
|
|
{
|
|
if (status)
|
|
{
|
|
StartSynchronizing();
|
|
m_frequency = frequency;
|
|
}
|
|
else
|
|
{
|
|
StartScanning(SubscriberStationNetDevice::EVENT_NONE, false);
|
|
}
|
|
}
|
|
|
|
void
|
|
SSLinkManager::StartSynchronizing()
|
|
{
|
|
m_ss->SetState(SubscriberStationNetDevice::SS_STATE_SYNCHRONIZING);
|
|
m_ss->SetTimer(Simulator::Schedule(m_ss->GetIntervalT21(),
|
|
&SSLinkManager::StartScanning,
|
|
this,
|
|
SubscriberStationNetDevice::EVENT_DL_MAP_SYNC_TIMEOUT,
|
|
false),
|
|
m_dlMapSyncTimeoutEvent);
|
|
}
|
|
|
|
void
|
|
SSLinkManager::SendRangingRequest(uint8_t uiuc, uint16_t allocationSize)
|
|
{
|
|
NS_ASSERT_MSG(
|
|
m_ss->GetState() == SubscriberStationNetDevice::SS_STATE_WAITING_REG_RANG_INTRVL ||
|
|
m_ss->GetState() == SubscriberStationNetDevice::SS_STATE_WAITING_INV_RANG_INTRVL,
|
|
"SS: Error while sending a ranging request: the ss state should be "
|
|
"SS_STATE_WAITING_REG_RANG_INTRVL or SS_STATE_WAITING_INV_RANG_INTRVL");
|
|
|
|
if (m_nrRngReqsSent == 0) // sending the first time
|
|
{
|
|
m_pTxIrMax = CalculateMaxIRSignalStrength();
|
|
m_rngreq.SetReqDlBurstProfile(m_ss->GetBurstProfileManager()->GetBurstProfileToRequest());
|
|
m_rngreq.SetMacAddress(m_ss->GetMacAddress());
|
|
}
|
|
else
|
|
{
|
|
m_pTxIrMax++;
|
|
if (m_nrRngRspsRecvd > 0)
|
|
{
|
|
m_rngreq.SetRangingAnomalies(m_rangingAnomalies);
|
|
}
|
|
}
|
|
|
|
Ptr<Packet> packet = Create<Packet>();
|
|
Ptr<PacketBurst> burst = CreateObject<PacketBurst>();
|
|
|
|
packet->AddHeader(m_rngreq);
|
|
packet->AddHeader(ManagementMessageType(ManagementMessageType::MESSAGE_TYPE_RNG_REQ));
|
|
|
|
Ptr<WimaxConnection> connection;
|
|
|
|
if (m_rangingStatus == WimaxNetDevice::RANGING_STATUS_CONTINUE)
|
|
{
|
|
connection = m_ss->GetBasicConnection();
|
|
}
|
|
else // have been assigned BCID, means currently adjusting parameters
|
|
{
|
|
connection = m_ss->GetInitialRangingConnection();
|
|
}
|
|
|
|
m_ss->Enqueue(packet, MacHeaderType(), connection);
|
|
|
|
m_ss->SetState(SubscriberStationNetDevice::SS_STATE_WAITING_RNG_RSP);
|
|
m_ss->SetTimer(
|
|
Simulator::Schedule(m_ss->GetIntervalT3(), &SSLinkManager::StartContentionResolution, this),
|
|
m_waitForRngRspEvent);
|
|
m_nrRngReqsSent++;
|
|
|
|
NS_ASSERT_MSG(allocationSize ==
|
|
m_ss->GetCurrentUcd().GetChannelEncodings().GetRangReqOppSize() /
|
|
m_ss->GetPhy()->GetPsPerSymbol(),
|
|
"SS: Error while sending a ranging request: the allocation size is not correct");
|
|
|
|
// will work even if connection is not passed (i.e. null is passed) as scheduler will
|
|
// automatically select the same connection
|
|
m_ss->SendBurst(uiuc, allocationSize, connection);
|
|
}
|
|
|
|
void
|
|
SSLinkManager::StartContentionResolution()
|
|
{
|
|
NS_ASSERT_MSG(
|
|
m_ss->GetState() == SubscriberStationNetDevice::SS_STATE_WAITING_RNG_RSP ||
|
|
m_ss->GetState() == SubscriberStationNetDevice::SS_STATE_WAITING_REG_RANG_INTRVL ||
|
|
m_ss->GetState() == SubscriberStationNetDevice::SS_STATE_ADJUSTING_PARAMETERS,
|
|
"SS: Can not start connection resolution: The SS state should be SS_STATE_WAITING_RNG_RSP "
|
|
"or SS_STATE_WAITING_REG_RANG_INTRVL or SS_STATE_ADJUSTING_PARAMETERS");
|
|
|
|
if (m_ss->GetState() == SubscriberStationNetDevice::SS_STATE_WAITING_RNG_RSP)
|
|
{
|
|
m_ss->SetState(SubscriberStationNetDevice::SS_STATE_WAITING_REG_RANG_INTRVL);
|
|
IncreaseRangingRequestCW();
|
|
m_contentionRangingRetries++;
|
|
}
|
|
else if (m_ss->GetState() == SubscriberStationNetDevice::SS_STATE_ADJUSTING_PARAMETERS)
|
|
{
|
|
m_ss->SetState(SubscriberStationNetDevice::SS_STATE_WAITING_REG_RANG_INTRVL);
|
|
}
|
|
|
|
if (m_contentionRangingRetries == m_ss->GetMaxContentionRangingRetries())
|
|
{
|
|
StartScanning(SubscriberStationNetDevice::EVENT_NONE, false);
|
|
}
|
|
else
|
|
{
|
|
if (!m_isBackoffSet)
|
|
{
|
|
SelectRandomBackoff();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
SSLinkManager::PerformBackoff()
|
|
{
|
|
Time deferTime;
|
|
Time timeToAllocation;
|
|
uint16_t nrPsPerRangOpp = m_ss->GetCurrentUcd().GetChannelEncodings().GetRangReqOppSize();
|
|
uint16_t oppSize = m_ss->GetCurrentUcd().GetChannelEncodings().GetRangReqOppSize() /
|
|
m_ss->GetPhy()->GetPsPerSymbol();
|
|
|
|
for (uint8_t deferTOs = 0; deferTOs < m_nrRangingTransOpps; deferTOs++)
|
|
{
|
|
if (m_rangingBO == 0)
|
|
{
|
|
deferTime =
|
|
Seconds(deferTOs * nrPsPerRangOpp * m_ss->GetPhy()->GetPsDuration().GetSeconds());
|
|
timeToAllocation = m_ss->GetTimeToAllocation(deferTime);
|
|
|
|
Simulator::Schedule(timeToAllocation,
|
|
&SSLinkManager::SendRangingRequest,
|
|
this,
|
|
OfdmUlBurstProfile::UIUC_INITIAL_RANGING,
|
|
oppSize);
|
|
|
|
m_rngReqFrameNumber = m_ss->GetNrFrames();
|
|
m_initRangOppNumber = deferTOs + 1;
|
|
|
|
m_isBackoffSet = false;
|
|
break;
|
|
}
|
|
m_rangingBO--;
|
|
}
|
|
}
|
|
|
|
void
|
|
SSLinkManager::SelectRandomBackoff()
|
|
{
|
|
NS_ASSERT_MSG(
|
|
m_rangingCW != 0 && m_rangingBO == 0,
|
|
"be sure that CW has been set and BO is not already set"); // ensuring CW has been set and
|
|
// BO is not already set
|
|
|
|
m_rangingBO = (rand() % m_rangingCW);
|
|
m_isBackoffSet = true;
|
|
}
|
|
|
|
void
|
|
SSLinkManager::IncreaseRangingRequestCW()
|
|
{
|
|
m_rangingCW =
|
|
std::min(uint8_t((m_rangingCW * 2 + 1) - 1), m_ss->GetCurrentUcd().GetRangingBackoffEnd());
|
|
}
|
|
|
|
void
|
|
SSLinkManager::ResetRangingRequestCW()
|
|
{
|
|
m_rangingCW =
|
|
(uint8_t)std::pow(2.0, (double)m_ss->GetCurrentUcd().GetRangingBackoffStart()) - 1;
|
|
}
|
|
|
|
void
|
|
SSLinkManager::PerformRanging(Cid cid, RngRsp rngrsp)
|
|
{
|
|
// need to distinguish initial ranging or periodic ranging
|
|
|
|
if (cid == m_ss->GetInitialRangingConnection()->GetCid())
|
|
{
|
|
if (rngrsp.GetFrameNumber() == m_rngReqFrameNumber &&
|
|
rngrsp.GetInitRangOppNumber() == m_initRangOppNumber)
|
|
{
|
|
Simulator::Cancel(m_waitForRngRspEvent);
|
|
m_nrRngRspsRecvd++;
|
|
|
|
// RNG-REQ was undecodable
|
|
ResetRangingRequestCW();
|
|
AdjustRangingParameters(rngrsp);
|
|
m_ss->SetState(SubscriberStationNetDevice::SS_STATE_ADJUSTING_PARAMETERS);
|
|
return;
|
|
}
|
|
|
|
if (m_ss->GetAddress() != rngrsp.GetMacAddress())
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_ss->SetBasicConnection(CreateObject<WimaxConnection>(rngrsp.GetBasicCid(), Cid::BASIC));
|
|
|
|
m_ss->SetPrimaryConnection(
|
|
CreateObject<WimaxConnection>(rngrsp.GetPrimaryCid(), Cid::PRIMARY));
|
|
m_ss->SetAreManagementConnectionsAllocated(true);
|
|
}
|
|
else
|
|
{
|
|
// either periodic ranging or an additional RNG-RSP during initial ranging
|
|
}
|
|
|
|
m_nrRngRspsRecvd++;
|
|
if (m_waitForRngRspEvent.IsPending())
|
|
{
|
|
Simulator::Cancel(m_waitForRngRspEvent);
|
|
}
|
|
|
|
m_rangingStatus = (WimaxNetDevice::RangingStatus)rngrsp.GetRangStatus();
|
|
|
|
NS_ASSERT_MSG(m_rangingStatus == WimaxNetDevice::RANGING_STATUS_CONTINUE ||
|
|
m_rangingStatus == WimaxNetDevice::RANGING_STATUS_ABORT ||
|
|
m_rangingStatus == WimaxNetDevice::RANGING_STATUS_SUCCESS,
|
|
"SS: Can not perform ranging: the ranging status should be "
|
|
"RANGING_STATUS_CONTINUE or RANGING_STATUS_ABORT or RANGING_STATUS_SUCCESS");
|
|
|
|
if (m_rangingStatus == WimaxNetDevice::RANGING_STATUS_ABORT)
|
|
{
|
|
if (rngrsp.GetDlFreqOverride())
|
|
{
|
|
// code to move to new channel/frequency goes here
|
|
}
|
|
// deassigning basic and primary CIDs
|
|
m_ss->SetBasicConnection(nullptr);
|
|
m_ss->SetPrimaryConnection(nullptr);
|
|
m_ss->SetAreManagementConnectionsAllocated(false);
|
|
}
|
|
else
|
|
{
|
|
AdjustRangingParameters(rngrsp);
|
|
|
|
if (m_rangingStatus == WimaxNetDevice::RANGING_STATUS_SUCCESS)
|
|
{
|
|
m_ss->SetState(SubscriberStationNetDevice::SS_STATE_REGISTERED);
|
|
// initiate service flows
|
|
if (m_ss->HasServiceFlows() && !m_ss->GetAreServiceFlowsAllocated())
|
|
{
|
|
m_ss->GetServiceFlowManager()->InitiateServiceFlows();
|
|
}
|
|
|
|
NegotiateBasicCapabilities();
|
|
}
|
|
else
|
|
{
|
|
m_ss->SetState(SubscriberStationNetDevice::SS_STATE_WAITING_INV_RANG_INTRVL);
|
|
// wait for invited ranging interval assigned to its Basic CID
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
SSLinkManager::DeleteUplinkParameters()
|
|
{
|
|
m_ss->SetCurrentUcd(Ucd());
|
|
}
|
|
|
|
bool
|
|
SSLinkManager::IsUlChannelUsable()
|
|
{
|
|
// don't know how to check if usable, see Figure 58.
|
|
return true; // temporarily assuming usable
|
|
}
|
|
|
|
void
|
|
SSLinkManager::AdjustRangingParameters(const RngRsp& rngrsp)
|
|
{
|
|
#if 0 /* a template for future implementation following */
|
|
bool successful = true;
|
|
uint8_t temp = rngrsp.GetTimingAdjust ();
|
|
temp = rngrsp.GetPowerLevelAdjust ();
|
|
temp = rngrsp.GetOffsetFreqAdjust ();
|
|
|
|
// code for adjusting parameters goes here
|
|
|
|
if (!successful)
|
|
{
|
|
// code for setting ranging anomalies goes here
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void
|
|
SSLinkManager::NegotiateBasicCapabilities()
|
|
{
|
|
// code to nagotiate basic capabilities goes here, ignored until very advanced stages
|
|
}
|
|
|
|
uint16_t
|
|
SSLinkManager::CalculateMaxIRSignalStrength()
|
|
{
|
|
// SS obtains RSSI measurement from the OFDM downlink preambles using a complex formula, page
|
|
// 486
|
|
uint16_t rss = 1;
|
|
|
|
if (m_bsEirp == 65535 || m_eirXPIrMax == 65535)
|
|
{
|
|
return GetMinTransmitPowerLevel();
|
|
}
|
|
else
|
|
{
|
|
return m_eirXPIrMax + m_bsEirp - rss;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint16_t
|
|
SSLinkManager::GetMinTransmitPowerLevel()
|
|
{
|
|
// code to calculate minimum transmit power level of the SS, see page 189 of amendment
|
|
return 10; // temp
|
|
}
|
|
|
|
void
|
|
SSLinkManager::ScheduleScanningRestart(Time interval,
|
|
SubscriberStationNetDevice::EventType eventType,
|
|
bool deleteUlParameters,
|
|
EventId& eventId)
|
|
{
|
|
m_ss->SetTimer(Simulator::Schedule(interval,
|
|
&SSLinkManager::StartScanning,
|
|
this,
|
|
eventType,
|
|
deleteUlParameters),
|
|
eventId);
|
|
}
|
|
|
|
} // namespace ns3
|