?離散事件仿真器算行,主要原理是在當(dāng)前的時刻,計算某個未來事件的發(fā)生時刻[1]苫耸,并向仿真調(diào)度器中調(diào)度。仿真器按照時戳大小,對未來事件進(jìn)行調(diào)度[2][3]顾复。離散仿真器中的時間與操作系統(tǒng)時鐘無關(guān)竹揍。
?參考博客[3]腕唧。比如一條傳輸鏈路熏版,網(wǎng)卡的發(fā)送速率10Mbps器一,單向傳輸時延100ms霉晕。當(dāng)網(wǎng)卡設(shè)備向外發(fā)送一個數(shù)據(jù)包A(長度為L字節(jié))時较店,會模擬處理時延:
Time txTime = m_bps.CalculateBytesTxTime (p->GetSize ());
bool result = m_channel->TransmitStart (p, this, txTime);//發(fā)送到channel中模擬鏈路傳輸時延
經(jīng)過 Time txCompleteTime = txTime之后笼痛,網(wǎng)卡才能處理下一個數(shù)據(jù)包B裙秋。數(shù)據(jù)包A在鏈路上傳輸時,有一個傳輸時延(100ms缨伊,m_delay)摘刑。也就是經(jīng)過txTime + m_delay的時間后,仿真器才會向下一跳的網(wǎng)卡傳輸數(shù)據(jù)刻坊。
bool
PointToPointChannel::TransmitStart (
Ptr<const Packet> p,
Ptr<PointToPointNetDevice> src,
Time txTime)
{
Simulator::ScheduleWithContext (m_link[wire].m_dst->GetNode ()->GetId (),txTime + m_delay, &PointToPointNetDevice::Receive, m_link[wire].m_dst, p->Copy ());//經(jīng)過txTime + m_delay時延后枷恕,通過回調(diào)進(jìn)行數(shù)據(jù)上傳
}
?以uan-cw-example.cc為例,分析水聲通信模塊的數(shù)據(jù)包處理流程谭胚。
?打包程序采用的是OnOffHelper徐块,為仿真節(jié)點(diǎn)Node(可以理解為傳感器節(jié)點(diǎn)或者主機(jī))安裝發(fā)包應(yīng)用。
OnOffHelper app ("ns3::PacketSocketFactory", Address (socket));
app.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]"));
app.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]"));
app.SetAttribute ("DataRate", DataRateValue (m_dataRate));
app.SetAttribute ("PacketSize", UintegerValue (m_packetSize));
ApplicationContainer apps = app.Install (nc);
apps.Start (Seconds (0.5));//Applicaion 的啟動時間
?OnOffHelper在安裝ns3::OnOffApplication應(yīng)用的時候灾而,會對OnOffApplication設(shè)置屬性值胡控。
OnOffHelper::OnOffHelper (std::string protocol, Address address)
{
m_factory.SetTypeId ("ns3::OnOffApplication");
m_factory.Set ("Protocol", StringValue (protocol));
m_factory.Set ("Remote", AddressValue (address));
}
ApplicationContainer
OnOffHelper::Install (Ptr<Node> node) const
{
return ApplicationContainer (InstallPriv (node));
}
Ptr<Application>
OnOffHelper::InstallPriv (Ptr<Node> node) const
{
Ptr<Application> app = m_factory.Create<Application> ();
node->AddApplication (app);
return app;
}
?在主文件uan-cw-example.cc中,app.SetAttribute函數(shù)第一個參數(shù)表示屬性旁趟,在OnOffApplication有對應(yīng)的配置點(diǎn)昼激。沒有配置的屬性,則采用默認(rèn)值轻庆。m_cbrRate數(shù)據(jù)包發(fā)送速率癣猾,m_pktSize數(shù)據(jù)包長度余爆。m_tid代表SocketFactory的類型,屬性字符串為"Protocol"像捶,在主程序中被配置為"ns3::PacketSocketFactory"。
TypeId
OnOffApplication::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::OnOffApplication")
.SetParent<Application> ()
.SetGroupName("Applications")
.AddConstructor<OnOffApplication> ()
.AddAttribute ("DataRate", "The data rate in on state.",
DataRateValue (DataRate ("500kb/s")),
MakeDataRateAccessor (&OnOffApplication::m_cbrRate),
MakeDataRateChecker ())
.AddAttribute ("PacketSize", "The size of packets sent in on state",
UintegerValue (512),
MakeUintegerAccessor (&OnOffApplication::m_pktSize),
MakeUintegerChecker<uint32_t> (1))
.AddAttribute ("Remote", "The address of the destination",
AddressValue (),
MakeAddressAccessor (&OnOffApplication::m_peer),
MakeAddressChecker ())
.AddAttribute ("Local",
"The Address on which to bind the socket. If not set, it is generated automatically.",
AddressValue (),
MakeAddressAccessor (&OnOffApplication::m_local),
MakeAddressChecker ())
.AddAttribute ("OnTime", "A RandomVariableStream used to pick the duration of the 'On' state.",
StringValue ("ns3::ConstantRandomVariable[Constant=1.0]"),
MakePointerAccessor (&OnOffApplication::m_onTime),
MakePointerChecker <RandomVariableStream>())
.AddAttribute ("OffTime", "A RandomVariableStream used to pick the duration of the 'Off' state.",
StringValue ("ns3::ConstantRandomVariable[Constant=1.0]"),
MakePointerAccessor (&OnOffApplication::m_offTime),
MakePointerChecker <RandomVariableStream>())
.AddAttribute ("MaxBytes",
"The total number of bytes to send. Once these bytes are sent, "
"no packet is sent again, even in on state. The value zero means "
"that there is no limit.",
UintegerValue (0),
MakeUintegerAccessor (&OnOffApplication::m_maxBytes),
MakeUintegerChecker<uint64_t> ())
.AddAttribute ("Protocol", "The type of protocol to use. This should be "
"a subclass of ns3::SocketFactory",
TypeIdValue (UdpSocketFactory::GetTypeId ()),
MakeTypeIdAccessor (&OnOffApplication::m_tid),
// This should check for SocketFactory as a parent
MakeTypeIdChecker ())
;
return tid;
}
?ns3中可能有三種SocketFactory:UdpSocketFactory拓春,TcpSocketFactory亚隅,PacketSocketFactory硼莽,分別可以創(chuàng)建UdpSocket,TcpSocket和PacketSocket煮纵。PacketSocket可能主要針對一些傳感器網(wǎng)絡(luò)。
?apps.Start (Seconds (0.5))匆光,仿真器在0.5秒時刻啟動OnOffApplication终息。m_tid對應(yīng)PacketSocketFactory。
void OnOffApplication::StartApplication () // Called at time specified by Start
{
m_socket = Socket::CreateSocket (GetNode (), m_tid);
ScheduleStartEvent ();
}
//socket.cc
Socket::CreateSocket (Ptr<Node> node, TypeId tid)
{
NS_LOG_FUNCTION (node << tid);
Ptr<Socket> s;
NS_ASSERT (node != 0);
Ptr<SocketFactory> socketFactory = node->GetObject<SocketFactory> (tid);
NS_ASSERT (socketFactory != 0);
s = socketFactory->CreateSocket ();
NS_ASSERT (s != 0);
return s;
}
//packet-socket-factory.cc
Ptr<Socket> PacketSocketFactory::CreateSocket (void)
{
NS_LOG_FUNCTION (this);
Ptr<Node> node = GetObject<Node> ();
Ptr<PacketSocket> socket = CreateObject<PacketSocket> ();
socket->SetNode (node);
return socket;
}
?經(jīng)過offInterval時刻后柳譬,OnOffApplication向網(wǎng)絡(luò)中發(fā)包征绎。假設(shè)時刻t1磨取,ScheduleStartEvent向仿真器的調(diào)度器中注冊一個事件(OnOffApplication::StartSending,距離當(dāng)前時刻的間隔為offInterval凫岖,t2=t1+offInterval)哥放。當(dāng)t1時刻到來爹土,仿真器就會回調(diào)StartSending函數(shù)。
void OnOffApplication::ScheduleStartEvent ()
{ // Schedules the event to start sending data (switch to the "On" state)
NS_LOG_FUNCTION (this);
Time offInterval = Seconds (m_offTime->GetValue ());
NS_LOG_LOGIC ("start at " << offInterval.As (Time::S));
m_startStopEvent = Simulator::Schedule (offInterval, &OnOffApplication::StartSending, this);
}
?StartSending社露。ScheduleNextTx中按照配置的速率向外發(fā)送數(shù)據(jù)包峭弟。仿真器中需要頻繁地注冊未來事件脱拼,Simulator::Schedule的返回值可以認(rèn)為是一個定時器事件熄浓。
// Event handlers
void OnOffApplication::StartSending ()
{
NS_LOG_FUNCTION (this);
m_lastStartTime = Simulator::Now ();
ScheduleNextTx (); // Schedule the send packet event
ScheduleStopEvent ();
}
void OnOffApplication::ScheduleNextTx ()
{
NS_LOG_FUNCTION (this);
if (m_maxBytes == 0 || m_totBytes < m_maxBytes)
{
NS_ABORT_MSG_IF (m_residualBits > m_pktSize * 8, "Calculation to compute next send time will overflow");
uint32_t bits = m_pktSize * 8 - m_residualBits;
NS_LOG_LOGIC ("bits = " << bits);
Time nextTime (Seconds (bits /
static_cast<double>(m_cbrRate.GetBitRate ()))); // Time till next packet
NS_LOG_LOGIC ("nextTime = " << nextTime.As (Time::S));
m_sendEvent = Simulator::Schedule (nextTime,
&OnOffApplication::SendPacket, this);
}
}
?SendPacket會調(diào)用m_socket(類型為PacketSocket)將數(shù)據(jù)包發(fā)送出去。
void OnOffApplication::SendPacket (){
int actual = m_socket->Send (packet);
}
?看下PacketSocket的發(fā)送邏輯丁侄。
int
PacketSocket::Send (Ptr<Packet> p, uint32_t flags)
{
NS_LOG_FUNCTION (this << p << flags);
if (m_state == STATE_OPEN ||
m_state == STATE_BOUND)
{
m_errno = ERROR_NOTCONN;
return -1;
}
return SendTo (p, flags, m_destAddr);
}
int
PacketSocket::SendTo (Ptr<Packet> p, uint32_t flags, const Address &address)
{
device->Send (p, dest, ad.GetProtocol ())
}
?device發(fā)送數(shù)據(jù)包。主文件uan-cw-example.cc石景,在安裝channnel時候潮孽,返回了網(wǎng)卡設(shè)備。
//uan-cw-example.cc
NetDeviceContainer devices = uan.Install (nc, channel);
//uan-helper.cc
NetDeviceContainer
UanHelper::Install (NodeContainer c, Ptr<UanChannel> channel) const
{
NetDeviceContainer devices;
for (NodeContainer::Iterator i = c.Begin (); i != c.End (); i++)
{
Ptr<Node> node = *i;
Ptr<UanNetDevice> device = Install (node, channel);
devices.Add (device);
NS_LOG_DEBUG ("node=" << node << ", mob=" << node->GetObject<MobilityModel> ());
}
return devices;
}
Ptr<UanNetDevice>
UanHelper::Install (Ptr<Node> node, Ptr<UanChannel> channel) const
{
Ptr<UanNetDevice> device = CreateObject<UanNetDevice> ();
Ptr<UanMac> mac = m_mac.Create<UanMac> ();
Ptr<UanPhy> phy = m_phy.Create<UanPhy> ();
Ptr<UanTransducer> trans = m_transducer.Create<UanTransducer> ();
mac->SetAddress (Mac8Address::Allocate ());
device->SetMac (mac);
device->SetPhy (phy);
device->SetTransducer (trans);
device->SetChannel (channel);
node->AddDevice (device);
return device;
}
?device->Send,在UanNetDevice類中查看Send函數(shù)的實(shí)現(xiàn)挨决。
//uan-net-devices.cc
bool
UanNetDevice::Send (Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber)
{
uint8_t tmp [6];
dest.CopyTo (tmp);
Mac8Address udest (tmp[0]);
return m_mac->Enqueue (packet, protocolNumber, udest);
}
?UanHelper默認(rèn)的mac協(xié)議實(shí)現(xiàn)為UanMacAloha订歪,默認(rèn)的trans為UanTransducerHd刷晋,phy的默認(rèn)配置為UanPhyGen。
//uan-helper.cc
UanHelper::UanHelper ()
{
m_mac.SetTypeId ("ns3::UanMacAloha");
m_phy.SetTypeId ("ns3::UanPhyGen");
m_transducer.SetTypeId ("ns3::UanTransducerHd");
}
?針對m_mac->Enqueue喻奥,在類UanMacAloha查看其實(shí)現(xiàn)撞蚕。
//uan-mac-aloha.cc
bool
UanMacAloha::Enqueue (Ptr<Packet> packet, uint16_t protocolNumber, const Address &dest)
{
m_phy->SendPacket (packet, GetTxModeIndex ());
}
?在類UanPhyGen邮破,查看m_phy->SendPacket的實(shí)現(xiàn)抒和。GetTxModeIndex ()獲取調(diào)制模式。查找代碼庙洼,沒有看到對調(diào)制模式的配置油够,但是有這樣的接口(UanMac::SetTxModeIndex)。UanTxMode 中羅列的調(diào)制模式有PSK揩悄,QAM删性,F(xiàn)SK焕窝。
//uan-phy-gen.cc
void
UanPhyGen::SendPacket (Ptr<Packet> pkt, uint32_t modeNum)
{
NS_LOG_DEBUG ("PHY " << m_mac->GetAddress () << ": Transmitting packet");
if (m_state == DISABLED)
{
NS_LOG_DEBUG ("Energy depleted, node cannot transmit any packet. Dropping.");
return;
}
if (m_state == TX)
{
NS_LOG_DEBUG ("PHY requested to TX while already Transmitting. Dropping packet.");
return;
}
else if (m_state == SLEEP)
{
NS_LOG_DEBUG ("PHY requested to TX while sleeping. Dropping packet.");
return;
}
UanTxMode txMode = GetMode (modeNum);
if (m_pktRx != 0)
{
m_minRxSinrDb = -1e30;
m_pktRx = 0;
}
m_transducer->Transmit (Ptr<UanPhy> (this), pkt, m_txPwrDb, txMode);
m_state = TX;
UpdatePowerConsumption (TX);
double txdelay = pkt->GetSize () * 8.0 / txMode.GetDataRateBps ();
m_pktTx = pkt;
m_txEndEvent = Simulator::Schedule (Seconds (txdelay), &UanPhyGen::TxEndEvent, this);
NS_LOG_DEBUG ("PHY " << m_mac->GetAddress () << " notifying listeners");
NotifyListenersTxStart (Seconds (txdelay));
m_txLogger (pkt, m_txPwrDb, txMode);
}
? m_transducer->Transmit函數(shù)中攜帶有發(fā)送功率和調(diào)制模式參數(shù)它掂。在類UanTransducerHd虐秋,查看m_transducer->Transmit的實(shí)現(xiàn)。如果已經(jīng)處于傳輸模式雪猪,說明設(shè)備忙只恨,丟棄數(shù)據(jù)包抬虽,反之阐污,則進(jìn)入else之后的處理。不同的調(diào)制模式功氨,傳輸速率不同捷凄。
//uan-transducer-hd.cc
void
UanTransducerHd::Transmit (Ptr<UanPhy> src,
Ptr<Packet> packet,
double txPowerDb,
UanTxMode txMode)
{
if (m_state == TX)
{
m_endTxEvent.Cancel ();
src->NotifyTxDrop(packet); // traced source netanim
}
else
{
m_state = TX;
src->NotifyTxBegin(packet); // traced source netanim
}
//不同的調(diào)制模式围来,傳輸速率不同。
Time delay = Seconds (packet->GetSize () * 8.0 / txMode.GetDataRateBps ());
UanPhyList::const_iterator it = m_phyList.begin ();
for (; it != m_phyList.end (); it++)
{
if (src != (*it))
{
(*it)->NotifyTransStartTx (packet, txPowerDb, txMode);
}
}
m_channel->TxPacket (Ptr<UanTransducer> (this), packet, txPowerDb, txMode);
delay = std::max (delay, m_endTxTime - Simulator::Now ());
m_endTxEvent = Simulator::Schedule (delay, &UanTransducerHd::EndTx, this);
m_endTxTime = Simulator::Now () + delay;
Simulator::Schedule(delay, &UanPhy::NotifyTxEnd, src, packet); // traced source netanim
}
?m_channel->TxPacket航唆,查看其實(shí)現(xiàn)糯钙。
//uan-channel.cc
void
UanChannel::TxPacket (Ptr<UanTransducer> src, Ptr<Packet> packet,
double txPowerDb, UanTxMode txMode)
{
UanDeviceList::const_iterator i = m_devList.begin ();
for (; i != m_devList.end (); i++)
{
if (src != i->second)
{
NS_LOG_DEBUG ("Scheduling " << i->first->GetMac ()->GetAddress ());
Ptr<MobilityModel> rcvrMobility = i->first->GetNode ()->GetObject<MobilityModel> ();
Time delay = m_prop->GetDelay (senderMobility, rcvrMobility, txMode);
UanPdp pdp = m_prop->GetPdp (senderMobility, rcvrMobility, txMode);
double rxPowerDb = txPowerDb - m_prop->GetPathLossDb (senderMobility,
rcvrMobility,
txMode);
NS_LOG_DEBUG ("txPowerDb=" << txPowerDb << "dB, rxPowerDb="
<< rxPowerDb << "dB, distance="
<< senderMobility->GetDistanceFrom (rcvrMobility)
<< "m, delay=" << delay);
uint32_t dstNodeId = i->first->GetNode ()->GetId ();
Ptr<Packet> copy = packet->Copy ();
Simulator::ScheduleWithContext (dstNodeId, delay,
&UanChannel::SendUp,
this,
j,
copy,
rxPowerDb,
txMode,
pdp);
}
j++;
}
}
?主文件uan-cw-example.cc中超营,就配置了一個channel,所有的網(wǎng)絡(luò)節(jié)點(diǎn)共用此channel不跟,符合傳感器網(wǎng)絡(luò)通信的特點(diǎn)窝革。在上述代碼中虐译,數(shù)據(jù)包會向所有的節(jié)點(diǎn),提交數(shù)據(jù)包的拷貝( Ptr<Packet> copy=packet->Copy ())侮攀。另外這里有一些路徑損失(GetPathLossDb )的計算兰英,信道模型用到功率延遲分布(PDP供鸠,power delay profile),細(xì)節(jié)參見博客[4][5]薄坏。
Ptr<UanChannel> channel = CreateObjectWithAttributes<UanChannel> ("PropagationModel", PointerValue (prop));
?UanChannel向目標(biāo)節(jié)點(diǎn)發(fā)送數(shù)據(jù)包過程胶坠。UanTransducerHd的m_state == RX鼻忠,才能成功收包。
//uan-channel.cc
void
UanChannel::SendUp (uint32_t i, Ptr<Packet> packet, double rxPowerDb,
UanTxMode txMode, UanPdp pdp)
{
NS_LOG_DEBUG ("Channel: In sendup");
m_devList[i].second->Receive (packet, rxPowerDb, txMode, pdp);
}
//uan-transducer-hd.cc
void
UanTransducerHd::Receive (Ptr<Packet> packet,
double rxPowerDb,
UanTxMode txMode,
UanPdp pdp)
{
NS_LOG_FUNCTION (this << packet << rxPowerDb << txMode << pdp);
//Apply receiver gain in dB
rxPowerDb = ApplyRxGainDb (rxPowerDb, txMode);
UanPacketArrival arrival (packet,
rxPowerDb,
txMode,
pdp,
Simulator::Now ());
m_arrivalList.push_back (arrival);
Time txDelay = Seconds (packet->GetSize () * 8.0 / txMode.GetDataRateBps ());
Simulator::Schedule (txDelay, &UanTransducerHd::RemoveArrival, this, arrival);
NS_LOG_DEBUG (Now ().As (Time::S) << " Transducer in receive");
if (m_state == RX)
{
NS_LOG_DEBUG ("Transducer state = RX");
UanPhyList::const_iterator it = m_phyList.begin ();
for (; it != m_phyList.end (); it++)
{
NS_LOG_DEBUG ("Calling StartRx");
(*it)->StartRxPacket (packet, rxPowerDb, txMode, pdp);
}
}
}
?StartRxPacket函數(shù)中,需要計算SINR(Signal to Interference plus Noise Ratio)澈侠,設(shè)置一些狀態(tài)裝換哨啃。txdelay = pkt->GetSize () * 8.0 / txMode.GetDataRateBps (),模擬接受側(cè)網(wǎng)卡的處理時延(解調(diào)审姓?)魔吐。
//uan-phy-gen.cc
void
UanPhyGen::StartRxPacket (Ptr<Packet> pkt, double rxPowerDb, UanTxMode txMode, UanPdp pdp)
{
NS_LOG_DEBUG ("PHY " << m_mac->GetAddress () << ": rx power after RX gain = " << rxPowerDb << " dB re uPa");
switch (m_state)
{
case DISABLED:
NS_LOG_DEBUG ("Energy depleted, node cannot receive any packet. Dropping.");
NotifyRxDrop (pkt); // traced source netanim
return;
case TX:
NotifyRxDrop (pkt); // traced source netanim
NS_ASSERT (false);
break;
case RX:
{
NS_ASSERT (m_pktRx);
double newSinrDb = CalculateSinrDb (m_pktRx, m_pktRxArrTime, m_rxRecvPwrDb, m_pktRxMode, m_pktRxPdp);
m_minRxSinrDb = (newSinrDb < m_minRxSinrDb) ? newSinrDb : m_minRxSinrDb;
NS_LOG_DEBUG ("PHY " << m_mac->GetAddress () << ": Starting RX in RX mode. SINR of pktRx = " << m_minRxSinrDb);
NotifyRxBegin (pkt); // traced source netanim
}
break;
case CCABUSY:
case IDLE:
{
NS_ASSERT (!m_pktRx);
bool hasmode = false;
for (uint32_t i = 0; i < GetNModes (); i++)
{
if (txMode.GetUid () == GetMode (i).GetUid ())
{
hasmode = true;
break;
}
}
if (!hasmode)
{
break;
}
double newsinr = CalculateSinrDb (pkt, Simulator::Now (), rxPowerDb, txMode, pdp);
NS_LOG_DEBUG ("PHY " << m_mac->GetAddress () << ": Starting RX in IDLE mode. SINR = " << newsinr);
if (newsinr > m_rxThreshDb)
{
m_state = RX;
UpdatePowerConsumption (RX);
NotifyRxBegin (pkt); // traced source netanim
m_rxRecvPwrDb = rxPowerDb;
m_minRxSinrDb = newsinr;
m_pktRx = pkt;
m_pktRxArrTime = Simulator::Now ();
m_pktRxMode = txMode;
m_pktRxPdp = pdp;
double txdelay = pkt->GetSize () * 8.0 / txMode.GetDataRateBps ();
m_rxEndEvent = Simulator::Schedule (Seconds (txdelay), &UanPhyGen::RxEndEvent, this, pkt, rxPowerDb, txMode);
NotifyListenersRxStart ();
}
}
break;
case SLEEP:
NS_LOG_DEBUG ("Sleep mode. Dropping packet.");
NotifyRxDrop (pkt); // traced source netanim
break;
}
if (m_state == IDLE && GetInterferenceDb ( (Ptr<Packet>) 0) > m_ccaThreshDb)
{
m_state = CCABUSY;
NotifyListenersCcaStart ();
}
}
?UanPhyGen::RxEndEvent中會計算packer error rate(m_per->CalcPer),m_pg是個隨機(jī)數(shù)生成器辞色,生成值高于per浮定,才會繼續(xù)向上提交數(shù)據(jù)包桦卒。
void
UanPhyGen::RxEndEvent (Ptr<Packet> pkt, double rxPowerDb, UanTxMode txMode)
{
if (m_pg->GetValue (0, 1) > m_per->CalcPer (m_pktRx, m_minRxSinrDb, txMode))
{
m_rxOkLogger (pkt, m_minRxSinrDb, txMode);
NotifyListenersRxGood ();
if (!m_recOkCb.IsNull ())
{
m_recOkCb (pkt, m_minRxSinrDb, txMode);
}
}
}
?m_recOkCb的回調(diào)函數(shù)的配置點(diǎn)闸盔。m_recOkCb最終會調(diào)用UanMacAloha::RxPacketGood函數(shù)。目的地址是自身的設(shè)備地址躲撰,才會繼續(xù)向上層提交(m_forUpCb )击费。
void
UanMacAloha::AttachPhy (Ptr<UanPhy> phy)
{
m_phy = phy;
m_phy->SetReceiveOkCallback (MakeCallback (&UanMacAloha::RxPacketGood, this));
m_phy->SetReceiveErrorCallback (MakeCallback (&UanMacAloha::RxPacketError, this));
}
void
UanMacAloha::RxPacketGood (Ptr<Packet> pkt, double sinr, UanTxMode txMode)
{
NS_UNUSED (sinr);
UanHeaderCommon header;
pkt->RemoveHeader (header);
NS_LOG_DEBUG ("Receiving packet from " << header.GetSrc () << " For " << header.GetDest ());
if (header.GetDest () == GetAddress () || header.GetDest () == Mac8Address::GetBroadcast ())
{
m_forUpCb (pkt, header.GetProtocolNumber (), header.GetSrc ());
}
}
?m_forUpCb的設(shè)置函數(shù)為SetForwardUpCb 蔫巩。m_forUpCb最終調(diào)用UanNetDevice::ForwardUp函數(shù)。
void
UanMacAloha::SetForwardUpCb (Callback<void, Ptr<Packet>, uint16_t, const Mac8Address&> cb)
{
m_forUpCb = cb;
}
void
UanNetDevice::SetMac (Ptr<UanMac> mac)
{
m_mac->SetForwardUpCb (MakeCallback (&UanNetDevice::ForwardUp, this));
}
?UanNetDevice::ForwardUp的處理過程蔫劣。
void
UanNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
{
m_forwardUp = cb;
}
void
UanNetDevice::ForwardUp (Ptr<Packet> pkt, uint16_t protocolNumber, const Mac8Address &src)
{
NS_LOG_DEBUG ("Forwarding packet up to application");
m_rxLogger (pkt, src);
m_forwardUp (this, pkt, protocolNumber, src);
}
?m_forwardUp是在哪里被設(shè)置的呢脉幢?
Ptr<UanNetDevice>
UanHelper::Install (Ptr<Node> node, Ptr<UanChannel> channel) const
{
Ptr<UanNetDevice> device = CreateObject<UanNetDevice> ();
node->AddDevice (device);
}
uint32_t
Node::AddDevice (Ptr<NetDevice> device)
{
device->SetReceiveCallback (MakeCallback (&Node::NonPromiscReceiveFromDevice, this));
}
void
UanNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
{
m_forwardUp = cb;
}
?m_forwardUp最終調(diào)用Node::NonPromiscReceiveFromDevice嗦锐。
bool
Node::NonPromiscReceiveFromDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
const Address &from)
{
NS_LOG_FUNCTION (this << device << packet << protocol << &from);
return ReceiveFromDevice (device, packet, protocol, from, device->GetAddress (), NetDevice::PacketType (0), false);
}
bool
Node::ReceiveFromDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
const Address &from, const Address &to, NetDevice::PacketType packetType, bool promiscuous)
{
for (ProtocolHandlerList::iterator i = m_handlers.begin ();
i != m_handlers.end (); i++){
i->handler (device, packet, protocol, from, to, packetType);
}
}
?m_handlers的注冊過程:
int
PacketSocket::DoBind (const PacketSocketAddress &address)
{
m_node->RegisterProtocolHandler (MakeCallback (&PacketSocket::ForwardUp, this),
address.GetProtocol (), dev);
}
void
Node::RegisterProtocolHandler (ProtocolHandler handler,
uint16_t protocolType,
Ptr<NetDevice> device,
bool promiscuous){
m_handlers.push_back (entry);
}
?i->handler最終調(diào)用的函數(shù)為PacketSocket::ForwardUp萎羔。
void
PacketSocket::ForwardUp (Ptr<NetDevice> device, Ptr<const Packet> packet,
uint16_t protocol, const Address &from,
const Address &to, NetDevice::PacketType packetType)
{
if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize)
{
m_deliveryQueue.push (std::make_pair (copy, address));
NotifyDataRecv ();
}
}
?NotifyDataRecv會通知上層Application讀取數(shù)據(jù)包外驱。主程序uan-cw-example.cc設(shè)置了數(shù)據(jù)包讀取函數(shù)腻窒。
sinkSocket->SetRecvCallback (MakeCallback (&Experiment::ReceivePacket, this));
void
Experiment::ReceivePacket (Ptr<Socket> socket)
{
Ptr<Packet> packet;
while ((packet = socket->Recv ()))
{
m_bytesTotal += packet->GetSize ();
}
}
?物理層的退避儿子,信噪比的計算砸喻,需要相關(guān)領(lǐng)域的人員具體分析割岛。我不是搞無線網(wǎng)絡(luò)的。
Reference:
[1]ns3 simulator離散模擬機(jī)制
[2]ns3源碼閱讀(一)UdpSocketFactory的創(chuàng)建
[3]ns3源碼閱讀(二)net-device和channel
[4]基于PDP的信道建模
[5]學(xué)習(xí)筆記(十六):商用Wi-Fi的功率延遲分布