ns3 uan模塊數(shù)據(jù)收發(fā)過程分析

?離散事件仿真器算行,主要原理是在當(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的功率延遲分布

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市惠爽,隨后出現(xiàn)的幾起案子婚肆,更是在濱河造成了極大的恐慌,老刑警劉巖用僧,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件责循,死亡現(xiàn)場離奇詭異沼死,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)耸别,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進(jìn)店門秀姐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來若贮,“玉大人谴麦,你說我怎么就攤上這事∠象埃” “怎么了面哼?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵魔策,是天一觀的道長闯袒。 經(jīng)常有香客問我,道長原茅,這世上最難降的妖魔是什么堕仔? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任摩骨,我火速辦了婚禮,結(jié)果婚禮上哭懈,老公的妹妹穿的比我還像新娘茎用。我一直安慰自己轨功,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布垂券。 她就那樣靜靜地躺著菇爪,像睡著了一般柒昏。 火紅的嫁衣襯著肌膚如雪职祷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天奖亚,我揣著相機(jī)與錄音,去河邊找鬼爆袍。 笑死作郭,一個胖子當(dāng)著我的面吹牛夹攒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播压语,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼胎食,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了衩匣?” 一聲冷哼從身側(cè)響起琅捏,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤午绳,失蹤者是張志新(化名)和其女友劉穎映之,沒想到半個月后杠输,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年搞糕,在試婚紗的時候發(fā)現(xiàn)自己被綠了曼追。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片礼殊。...
    茶點(diǎn)故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡晶伦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出族沃,到底是詐尸還是另有隱情竭业,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布窟绷,位于F島的核電站兼蜈,受9級特大地震影響拙友,放射性物質(zhì)發(fā)生泄漏遗契。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望辐怕。 院中可真熱鬧从绘,春花似錦僵井、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽却汉。三九已至荷并,卻和暖如春源织,著一層夾襖步出監(jiān)牢的瞬間微猖,已是汗流浹背凛剥。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工犁珠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留犁享,地道東北人豹休。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像威根,于是被迫代替她去往敵國和親凤巨。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容