satellite-bbframe-container.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013 Magister Solutions Ltd
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Sami Rantanen <sami.rantanen@magister.fi>
19  */
20 
22 
24 #include "satellite-utils.h"
25 
26 #include <ns3/enum.h>
27 #include <ns3/log.h>
28 
29 #include <algorithm>
30 #include <cmath>
31 #include <deque>
32 #include <utility>
33 #include <vector>
34 
35 NS_LOG_COMPONENT_DEFINE("SatBbFrameContainer");
36 
37 namespace ns3
38 {
39 
40 NS_OBJECT_ENSURE_REGISTERED(SatBbFrameContainer);
41 
43  : m_totalDuration(Seconds(0)),
44  m_defaultBbFrameType(SatEnums::NORMAL_FRAME)
45 {
46  NS_LOG_FUNCTION(this);
47  NS_FATAL_ERROR("Default constructor of SatBbFrameContainer not supported.");
48 }
49 
50 SatBbFrameContainer::SatBbFrameContainer(std::vector<SatEnums::SatModcod_t>& modcodsInUse,
51  Ptr<SatBbFrameConf> conf)
52  : m_totalDuration(Seconds(0)),
53  m_bbFrameConf(conf),
54  m_maxSymbolRate(conf->GetSymbolRate())
55 {
56  NS_LOG_FUNCTION(this);
57 
58  for (std::vector<SatEnums::SatModcod_t>::const_iterator it = modcodsInUse.begin();
59  it != modcodsInUse.end();
60  it++)
61  {
62  std::pair<FrameContainer_t::iterator, bool> result =
63  m_container.insert(std::make_pair(*it, std::deque<Ptr<SatBbFrame>>()));
64 
65  if (result.second == false)
66  {
67  NS_FATAL_ERROR("Queue for MODCOD: " << *it << " already exists!!!");
68  }
69  }
70 
72 
73  if (m_bbFrameConf->GetBbFrameUsageMode() == SatEnums::SHORT_FRAMES)
74  {
76  }
77 }
78 
80 {
81  NS_LOG_FUNCTION(this);
82 
83  m_container.clear();
84 }
85 
86 TypeId
88 {
89  static TypeId tid =
90  TypeId("ns3::SatBbFrameContainer")
91  .SetParent<Object>()
92  .AddConstructor<SatBbFrameContainer>()
93  .AddTraceSource("BBFrameMergeTrace",
94  "Trace for merged BB Frames.",
95  MakeTraceSourceAccessor(&SatBbFrameContainer::m_bbFrameMergeTrace),
96  "ns3::SatBbFrame::BbFrameMergeCallback");
97  return tid;
98 }
99 
101 SatBbFrameContainer::GetModcod(uint32_t priorityClass, double cno)
102 {
103  NS_LOG_FUNCTION(this);
104 
105  SatEnums::SatModcod_t modcod = m_bbFrameConf->GetDefaultModCod();
106 
107  if (priorityClass == 0)
108  {
109  modcod = m_bbFrameConf->GetMostRobustModcod(m_defaultBbFrameType);
110  }
111  else if (std::isnan(cno) == false)
112  {
113  modcod = m_bbFrameConf->GetBestModcod(cno, m_defaultBbFrameType);
114  }
115 
116  return modcod;
117 }
118 
119 uint32_t
121 {
122  NS_LOG_FUNCTION(this);
123 
124  uint32_t payloadBytes = 0;
125 
126  if (priorityClass > 0)
127  {
128  payloadBytes = m_bbFrameConf->GetBbFramePayloadBits(modcod, m_defaultBbFrameType) /
130  }
131  else
132  {
133  payloadBytes = m_bbFrameConf->GetBbFramePayloadBits(
134  m_bbFrameConf->GetMostRobustModcod(m_defaultBbFrameType),
137  }
138 
139  return payloadBytes;
140 }
141 
142 uint32_t
144 {
145  NS_LOG_FUNCTION(this);
146 
147  uint32_t bytesLeft = GetMaxFramePayloadInBytes(priorityClass, modcod);
148 
149  if (priorityClass > 0)
150  {
151  if (m_container.at(modcod).empty() != true)
152  {
153  bytesLeft -= m_container.at(modcod).back()->GetSpaceUsedInBytes();
154  }
155  else
156  {
157  bytesLeft -= m_bbFrameConf->GetBbFrameHeaderSizeInBytes();
158  }
159  }
160  else
161  {
162  if (m_ctrlContainer.empty() != true)
163  {
164  bytesLeft -= m_ctrlContainer.back()->GetSpaceUsedInBytes();
165  }
166  else
167  {
168  bytesLeft -= m_bbFrameConf->GetBbFrameHeaderSizeInBytes();
169  }
170  }
171 
172  return bytesLeft;
173 }
174 
175 bool
177 {
178  NS_LOG_FUNCTION(this);
179 
180  if (priorityClass > 0)
181  {
182  return m_container.at(modcod).empty();
183  }
184  else
185  {
186  return m_ctrlContainer.empty();
187  }
188 }
189 
190 void
191 SatBbFrameContainer::AddData(uint32_t priorityClass, SatEnums::SatModcod_t modcod, Ptr<Packet> data)
192 {
193  NS_LOG_FUNCTION(this);
194 
195  if (priorityClass > 0)
196  {
197  if ((m_container.at(modcod).empty()) ||
198  (GetBytesLeftInTailFrame(priorityClass, modcod) < data->GetSize()))
199  {
200  CreateFrameToTail(priorityClass, modcod);
201  }
202  else if ((m_bbFrameConf->GetBbFrameUsageMode() == SatEnums::SHORT_AND_NORMAL_FRAMES) &&
203  (m_container.at(modcod).back()->GetFrameType() == SatEnums::SHORT_FRAME))
204  {
205  m_totalDuration += m_container.at(modcod).back()->Extend(m_bbFrameConf);
206  }
207  m_container.at(modcod).back()->AddPayload(data);
208  }
209  else
210  {
211  if (m_ctrlContainer.empty() ||
212  GetBytesLeftInTailFrame(priorityClass, modcod) < data->GetSize())
213  {
214  // create and add frame to tail
215  CreateFrameToTail(priorityClass,
216  m_bbFrameConf->GetMostRobustModcod(m_defaultBbFrameType));
217  }
218  else if ((m_bbFrameConf->GetBbFrameUsageMode() == SatEnums::SHORT_AND_NORMAL_FRAMES) &&
219  (m_container.at(modcod).back()->GetFrameType() == SatEnums::SHORT_FRAME))
220  {
221  m_totalDuration += m_ctrlContainer.back()->Extend(m_bbFrameConf);
222  }
223  m_ctrlContainer.back()->AddPayload(data);
224  }
225 }
226 
227 Time
229 {
230  return m_totalDuration;
231 }
232 
233 uint32_t
235 {
236  return m_bbFrameConf->GetBbFrameDuration(modcod, m_defaultBbFrameType).GetSeconds() *
237  m_bbFrameConf->GetSymbolRate();
238 }
239 
240 void
242 {
243  m_maxSymbolRate = maxSymbolRate;
244 }
245 
246 uint32_t
248 {
249  return m_maxSymbolRate;
250 }
251 
252 void
254 {
255  NS_LOG_FUNCTION(this);
256 
257  m_ctrlContainer.clear();
258  for (FrameContainer_t::iterator it = m_container.begin(); it != m_container.end(); ++it)
259  {
260  it->second.clear();
261  }
262 }
263 
264 Ptr<SatBbFrame>
266 {
267  Ptr<SatBbFrame> nextFrame = nullptr;
268 
269  if (m_ctrlContainer.empty() == false)
270  {
271  nextFrame = m_ctrlContainer.front();
272  m_ctrlContainer.pop_front();
273  m_totalDuration -= nextFrame->GetDuration();
274  }
275  else
276  {
277  std::vector<std::deque<Ptr<SatBbFrame>>*> nonEmptyQueues;
278 
279  for (FrameContainer_t::iterator it = m_container.begin(); it != m_container.end(); ++it)
280  {
281  if ((*it).second.empty() == false)
282  {
283  nonEmptyQueues.push_back(&it->second);
284  }
285  }
286 
287  if (nonEmptyQueues.empty() == false)
288  {
289  std::random_shuffle(nonEmptyQueues.begin(), nonEmptyQueues.end());
290 
291  nextFrame = (*nonEmptyQueues.begin())->front();
292  (*nonEmptyQueues.begin())->pop_front();
293  m_totalDuration -= nextFrame->GetDuration();
294  }
295  }
296 
297  return nextFrame;
298 }
299 
300 void
302 {
303  NS_LOG_FUNCTION(this << modcod);
304 
305  Ptr<SatBbFrame> frame = Create<SatBbFrame>(modcod, m_defaultBbFrameType, m_bbFrameConf);
306 
307  if (frame != nullptr)
308  {
309  if (priorityClass > 0)
310  {
311  m_container.at(modcod).push_back(frame);
312  }
313  else
314  {
315  m_ctrlContainer.push_back(frame);
316  }
317 
318  m_totalDuration += frame->GetDuration();
319  }
320  else
321  {
322  NS_FATAL_ERROR("BB Frame creation failed!!!");
323  }
324 }
325 
326 void
327 SatBbFrameContainer::MergeBbFrames(double carrierBandwidthInHz)
328 {
329  // go through all BB Frame containers from the most efficient to the robust
330  for (FrameContainer_t::reverse_iterator itFromMerge = m_container.rbegin();
331  itFromMerge != m_container.rend();
332  itFromMerge++)
333  {
334  // BB Frames currently exists in the BB Frame container for this MODCOD.
335  if (itFromMerge->second.empty() == false)
336  {
337  // Get occupancy i.e. ratio of used space to maximum space in buffer at the back of the
338  // list. Occupancy is not necessarily efficiency.
339  double occupancy = itFromMerge->second.back()->GetOccupancy();
340 
341  // GetBbFrameHighOccupancyThreshold () returns a configured parameter. Part of a
342  // high-low threshold hysteresis damper. Current occupancy is no good. Need to off load
343  // the contents to some other BB Frame.
344  if (occupancy < m_bbFrameConf->GetBbFrameHighOccupancyThreshold())
345  {
346  // weighted occupancy takes into account the spectra efficiency of the current frame
347  // (MODCOD and frame length).
348  double weightedOccupancy =
349  itFromMerge->second.back()->GetSpectralEfficiency(carrierBandwidthInHz) *
350  occupancy;
351 
352  double maxNewOccupancyIfMerged =
353  0.0; // holder variable during a maximum value search
354  Ptr<SatBbFrame> frameToMerge =
355  nullptr; // holder variable for frame to potentially merge
356 
357  // check rest of the containers to find frame to merge.
358  for (FrameContainer_t::reverse_iterator itToMerge =
359  ++FrameContainer_t::reverse_iterator(itFromMerge);
360  itToMerge != m_container.rend();
361  itToMerge++)
362  {
363  // BB Frames currently exists in the BB Frame container for this MODCOD.
364  if (itToMerge->second.empty() == false)
365  {
366  /* check whether there is enough space in the frame */
367  // GetBbFrameLowOccupancyThreshold() returns a configured parameter. Part of
368  // a high-low threshold hysteresis damper. Current occupancy is no good.
369  // Need to fill in more.
370  double occupancy2 = itToMerge->second.back()->GetOccupancy();
371 
372  if (occupancy2 < m_bbFrameConf->GetBbFrameLowOccupancyThreshold())
373  {
374  Ptr<SatBbFrame> frame = itFromMerge->second.back();
375 
376  double newOccupancyIfMerged =
377  itToMerge->second.back()->GetOccupancyIfMerged(frame);
378 
379  if (newOccupancyIfMerged > maxNewOccupancyIfMerged)
380  {
381  maxNewOccupancyIfMerged = newOccupancyIfMerged;
382  frameToMerge = itToMerge->second.back();
383  }
384  }
385  }
386  }
387 
388  // check control message container tail still, if it is not empty and MODCOD match
389  // control messages are used default MODCOD
390  if ((m_ctrlContainer.empty() == false) &&
391  (m_ctrlContainer.back()->GetModcod() <= itFromMerge->first))
392  {
393  if (m_ctrlContainer.back()->GetOccupancy() <
394  m_bbFrameConf->GetBbFrameLowOccupancyThreshold())
395  {
396  double newOccupancyIfMerged = m_ctrlContainer.back()->GetOccupancyIfMerged(
397  itFromMerge->second.back());
398 
399  if (newOccupancyIfMerged > maxNewOccupancyIfMerged)
400  {
401  maxNewOccupancyIfMerged = newOccupancyIfMerged;
402  frameToMerge = m_ctrlContainer.back();
403  }
404  }
405  }
406 
407  // frame found where merging can be tried
408  if (frameToMerge)
409  {
410  double newWeightedOccupancyIfMerged =
411  frameToMerge->GetSpectralEfficiency(carrierBandwidthInHz) *
412  maxNewOccupancyIfMerged;
413 
414  if (newWeightedOccupancyIfMerged > weightedOccupancy)
415  {
416  // Merge two frames
417 
418  if (frameToMerge->MergeWithFrame(itFromMerge->second.back(),
420  {
421  m_totalDuration -= itFromMerge->second.back()->GetDuration();
422  itFromMerge->second.pop_back();
423  }
424  }
425  }
426  }
427  }
428  }
429 
430  // if both short and normal frames are used then try to shrink normal frames
431  // which are last ones in containers
432  if (m_bbFrameConf->GetBbFrameUsageMode() == SatEnums::SHORT_AND_NORMAL_FRAMES)
433  {
434  // go through all MODCOD based BB Frame containers and try to shrink last frame in the
435  // container
436  for (FrameContainer_t::reverse_iterator it = m_container.rbegin(); it != m_container.rend();
437  it++)
438  {
439  if (it->second.empty() == false)
440  {
441  m_totalDuration -= it->second.back()->Shrink(m_bbFrameConf);
442  }
443  }
444 
445  if (m_ctrlContainer.empty() == false)
446  {
447  m_totalDuration -= m_ctrlContainer.back()->Shrink(m_bbFrameConf);
448  }
449  }
450 }
451 
452 } // namespace ns3
virtual ~SatBbFrameContainer()
Destructor.
static TypeId GetTypeId(void)
Get the type ID.
uint32_t GetMaxFramePayloadInBytes(uint32_t priorityClass, SatEnums::SatModcod_t modcod)
Get maximum payload bytes of a frame with the given priority class and MODCOD.
uint32_t GetBytesLeftInTailFrame(uint32_t priorityClass, SatEnums::SatModcod_t modcod)
Get bytes left in last frame of the queue with the given priority class and MODCOD.
void SetMaxSymbolRate(uint32_t maxSymbolRate)
Set the maximum symbol rate of this container, used for time-slicing.
uint32_t GetMaxSymbolRate()
Set the maximum symbol rate of this container, used for time-slicing.
Time GetTotalDuration() const
Get total transmission duration of the frames in container.
void MergeBbFrames(double carrierBandwidthInHz)
Ptr< SatBbFrame > GetNextFrame()
Get next frame from container to transmit.
TracedCallback< Ptr< SatBbFrame >, Ptr< SatBbFrame > > m_bbFrameMergeTrace
Trace for merged BB frames.
uint32_t GetFrameSymbols(SatEnums::SatModcod_t modcod)
Get the total number of symbols, incuding headers, when creating a new BBFrame.
bool IsEmpty(uint32_t priorityClass, SatEnums::SatModcod_t modcod)
Indicates if the container for a ModCod and priority is empty (no BBFrame).
std::deque< Ptr< SatBbFrame > > m_ctrlContainer
void CreateFrameToTail(uint32_t priorityClass, SatEnums::SatModcod_t modcod)
Create short or normal frame according to MODCOD and member #m_bbFrameUsageMode.
void AddData(uint32_t priorityClass, SatEnums::SatModcod_t modcod, Ptr< Packet > data)
Add data according to given priority class and MODCOD to container.
SatEnums::SatBbFrameType_t m_defaultBbFrameType
void ClearAllFrames()
Remove all frames in containers.
SatBbFrameContainer()
Default constructor for SatBbFrameContainer not supported.
SatEnums::SatModcod_t GetModcod(uint32_t priorityClass, double cno)
Get maximum MODCOD with the given priority class and C/N0.
SatEnums class is for simplifying the use of enumerators in the satellite module.
SatModcod_t
Modulation scheme and coding rate for DVB-S2.
@ SHORT_AND_NORMAL_FRAMES
SHORT_AND_NORMAL_FRAMES.
@ SHORT_FRAMES
SHORT_FRAMES.
constexpr uint32_t BITS_PER_BYTE
Number of bits in a byte.
SatArqSequenceNumber is handling the sequence numbers for the ARQ process.