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 
31 NS_LOG_COMPONENT_DEFINE("SatBbFrameContainer");
32 
33 namespace ns3
34 {
35 
36 NS_OBJECT_ENSURE_REGISTERED(SatBbFrameContainer);
37 
39  : m_totalDuration(Seconds(0)),
40  m_defaultBbFrameType(SatEnums::NORMAL_FRAME)
41 {
42  NS_LOG_FUNCTION(this);
43  NS_FATAL_ERROR("Default constructor of SatBbFrameContainer not supported.");
44 }
45 
46 SatBbFrameContainer::SatBbFrameContainer(std::vector<SatEnums::SatModcod_t>& modcodsInUse,
47  Ptr<SatBbFrameConf> conf)
48  : m_totalDuration(Seconds(0)),
49  m_bbFrameConf(conf),
50  m_maxSymbolRate(conf->GetSymbolRate())
51 {
52  NS_LOG_FUNCTION(this);
53 
54  for (std::vector<SatEnums::SatModcod_t>::const_iterator it = modcodsInUse.begin();
55  it != modcodsInUse.end();
56  it++)
57  {
58  std::pair<FrameContainer_t::iterator, bool> result =
59  m_container.insert(std::make_pair(*it, std::deque<Ptr<SatBbFrame>>()));
60 
61  if (result.second == false)
62  {
63  NS_FATAL_ERROR("Queue for MODCOD: " << *it << " already exists!!!");
64  }
65  }
66 
68 
69  if (m_bbFrameConf->GetBbFrameUsageMode() == SatEnums::SHORT_FRAMES)
70  {
72  }
73 }
74 
76 {
77  NS_LOG_FUNCTION(this);
78 
79  m_container.clear();
80 }
81 
82 TypeId
84 {
85  static TypeId tid =
86  TypeId("ns3::SatBbFrameContainer")
87  .SetParent<Object>()
88  .AddConstructor<SatBbFrameContainer>()
89  .AddTraceSource("BBFrameMergeTrace",
90  "Trace for merged BB Frames.",
91  MakeTraceSourceAccessor(&SatBbFrameContainer::m_bbFrameMergeTrace),
92  "ns3::SatBbFrame::BbFrameMergeCallback");
93  return tid;
94 }
95 
97 SatBbFrameContainer::GetModcod(uint32_t priorityClass, double cno)
98 {
99  NS_LOG_FUNCTION(this);
100 
101  SatEnums::SatModcod_t modcod = m_bbFrameConf->GetDefaultModCod();
102 
103  if (priorityClass == 0)
104  {
105  modcod = m_bbFrameConf->GetMostRobustModcod(m_defaultBbFrameType);
106  }
107  else if (std::isnan(cno) == false)
108  {
109  modcod = m_bbFrameConf->GetBestModcod(cno, m_defaultBbFrameType);
110  }
111 
112  return modcod;
113 }
114 
115 uint32_t
117 {
118  NS_LOG_FUNCTION(this);
119 
120  uint32_t payloadBytes = 0;
121 
122  if (priorityClass > 0)
123  {
124  payloadBytes = m_bbFrameConf->GetBbFramePayloadBits(modcod, m_defaultBbFrameType) /
126  }
127  else
128  {
129  payloadBytes = m_bbFrameConf->GetBbFramePayloadBits(
130  m_bbFrameConf->GetMostRobustModcod(m_defaultBbFrameType),
133  }
134 
135  return payloadBytes;
136 }
137 
138 uint32_t
140 {
141  NS_LOG_FUNCTION(this);
142 
143  uint32_t bytesLeft = GetMaxFramePayloadInBytes(priorityClass, modcod);
144 
145  if (priorityClass > 0)
146  {
147  if (m_container.at(modcod).empty() != true)
148  {
149  bytesLeft -= m_container.at(modcod).back()->GetSpaceUsedInBytes();
150  }
151  else
152  {
153  bytesLeft -= m_bbFrameConf->GetBbFrameHeaderSizeInBytes();
154  }
155  }
156  else
157  {
158  if (m_ctrlContainer.empty() != true)
159  {
160  bytesLeft -= m_ctrlContainer.back()->GetSpaceUsedInBytes();
161  }
162  else
163  {
164  bytesLeft -= m_bbFrameConf->GetBbFrameHeaderSizeInBytes();
165  }
166  }
167 
168  return bytesLeft;
169 }
170 
171 bool
173 {
174  NS_LOG_FUNCTION(this);
175 
176  if (priorityClass > 0)
177  {
178  return m_container.at(modcod).empty();
179  }
180  else
181  {
182  return m_ctrlContainer.empty();
183  }
184 }
185 
186 void
187 SatBbFrameContainer::AddData(uint32_t priorityClass, SatEnums::SatModcod_t modcod, Ptr<Packet> data)
188 {
189  NS_LOG_FUNCTION(this);
190 
191  if (priorityClass > 0)
192  {
193  if ((m_container.at(modcod).empty()) ||
194  (GetBytesLeftInTailFrame(priorityClass, modcod) < data->GetSize()))
195  {
196  CreateFrameToTail(priorityClass, modcod);
197  }
198  else if ((m_bbFrameConf->GetBbFrameUsageMode() == SatEnums::SHORT_AND_NORMAL_FRAMES) &&
199  (m_container.at(modcod).back()->GetFrameType() == SatEnums::SHORT_FRAME))
200  {
201  m_totalDuration += m_container.at(modcod).back()->Extend(m_bbFrameConf);
202  }
203  m_container.at(modcod).back()->AddPayload(data);
204  }
205  else
206  {
207  if (m_ctrlContainer.empty() ||
208  GetBytesLeftInTailFrame(priorityClass, modcod) < data->GetSize())
209  {
210  // create and add frame to tail
211  CreateFrameToTail(priorityClass,
212  m_bbFrameConf->GetMostRobustModcod(m_defaultBbFrameType));
213  }
214  else if ((m_bbFrameConf->GetBbFrameUsageMode() == SatEnums::SHORT_AND_NORMAL_FRAMES) &&
215  (m_container.at(modcod).back()->GetFrameType() == SatEnums::SHORT_FRAME))
216  {
217  m_totalDuration += m_ctrlContainer.back()->Extend(m_bbFrameConf);
218  }
219  m_ctrlContainer.back()->AddPayload(data);
220  }
221 }
222 
223 Time
225 {
226  return m_totalDuration;
227 }
228 
229 uint32_t
231 {
232  return m_bbFrameConf->GetBbFrameDuration(modcod, m_defaultBbFrameType).GetSeconds() *
233  m_bbFrameConf->GetSymbolRate();
234 }
235 
236 void
238 {
239  m_maxSymbolRate = maxSymbolRate;
240 }
241 
242 uint32_t
244 {
245  return m_maxSymbolRate;
246 }
247 
248 Ptr<SatBbFrame>
250 {
251  Ptr<SatBbFrame> nextFrame = NULL;
252 
253  if (m_ctrlContainer.empty() == false)
254  {
255  nextFrame = m_ctrlContainer.front();
256  m_ctrlContainer.pop_front();
257  m_totalDuration -= nextFrame->GetDuration();
258  }
259  else
260  {
261  std::vector<std::deque<Ptr<SatBbFrame>>*> nonEmptyQueues;
262 
263  for (FrameContainer_t::iterator it = m_container.begin(); it != m_container.end(); ++it)
264  {
265  if ((*it).second.empty() == false)
266  {
267  nonEmptyQueues.push_back(&it->second);
268  }
269  }
270 
271  if (nonEmptyQueues.empty() == false)
272  {
273  std::random_shuffle(nonEmptyQueues.begin(), nonEmptyQueues.end());
274 
275  nextFrame = (*nonEmptyQueues.begin())->front();
276  (*nonEmptyQueues.begin())->pop_front();
277  m_totalDuration -= nextFrame->GetDuration();
278  }
279  }
280 
281  return nextFrame;
282 }
283 
284 void
286 {
287  NS_LOG_FUNCTION(this << modcod);
288 
289  Ptr<SatBbFrame> frame = Create<SatBbFrame>(modcod, m_defaultBbFrameType, m_bbFrameConf);
290 
291  if (frame != NULL)
292  {
293  if (priorityClass > 0)
294  {
295  m_container.at(modcod).push_back(frame);
296  }
297  else
298  {
299  m_ctrlContainer.push_back(frame);
300  }
301 
302  m_totalDuration += frame->GetDuration();
303  }
304  else
305  {
306  NS_FATAL_ERROR("BB Frame creation failed!!!");
307  }
308 }
309 
310 void
311 SatBbFrameContainer::MergeBbFrames(double carrierBandwidthInHz)
312 {
313  // go through all BB Frame containers from the most efficient to the robust
314  for (FrameContainer_t::reverse_iterator itFromMerge = m_container.rbegin();
315  itFromMerge != m_container.rend();
316  itFromMerge++)
317  {
318  // BB Frames currently exists in the BB Frame container for this MODCOD.
319  if (itFromMerge->second.empty() == false)
320  {
321  // Get occupancy i.e. ratio of used space to maximum space in buffer at the back of the
322  // list. Occupancy is not necessarily efficiency.
323  double occupancy = itFromMerge->second.back()->GetOccupancy();
324 
325  // GetBbFrameHighOccupancyThreshold () returns a configured parameter. Part of a
326  // high-low threshold hysteresis damper. Current occupancy is no good. Need to off load
327  // the contents to some other BB Frame.
328  if (occupancy < m_bbFrameConf->GetBbFrameHighOccupancyThreshold())
329  {
330  // weighted occupancy takes into account the spectra efficiency of the current frame
331  // (MODCOD and frame length).
332  double weightedOccupancy =
333  itFromMerge->second.back()->GetSpectralEfficiency(carrierBandwidthInHz) *
334  occupancy;
335 
336  double maxNewOccupancyIfMerged =
337  0.0; // holder variable during a maximum value search
338  Ptr<SatBbFrame> frameToMerge =
339  NULL; // holder variable for frame to potentially merge
340 
341  // check rest of the containers to find frame to merge.
342  for (FrameContainer_t::reverse_iterator itToMerge =
343  ++FrameContainer_t::reverse_iterator(itFromMerge);
344  itToMerge != m_container.rend();
345  itToMerge++)
346  {
347  // BB Frames currently exists in the BB Frame container for this MODCOD.
348  if (itToMerge->second.empty() == false)
349  {
350  /* check whether there is enough space in the frame */
351  // GetBbFrameLowOccupancyThreshold() returns a configured parameter. Part of
352  // a high-low threshold hysteresis damper. Current occupancy is no good.
353  // Need to fill in more.
354  double occupancy2 = itToMerge->second.back()->GetOccupancy();
355 
356  if (occupancy2 < m_bbFrameConf->GetBbFrameLowOccupancyThreshold())
357  {
358  Ptr<SatBbFrame> frame = itFromMerge->second.back();
359 
360  double newOccupancyIfMerged =
361  itToMerge->second.back()->GetOccupancyIfMerged(frame);
362 
363  if (newOccupancyIfMerged > maxNewOccupancyIfMerged)
364  {
365  maxNewOccupancyIfMerged = newOccupancyIfMerged;
366  frameToMerge = itToMerge->second.back();
367  }
368  }
369  }
370  }
371 
372  // check control message container tail still, if it is not empty and MODCOD match
373  // control messages are used default MODCOD
374  if ((m_ctrlContainer.empty() == false) &&
375  (m_ctrlContainer.back()->GetModcod() <= itFromMerge->first))
376  {
377  if (m_ctrlContainer.back()->GetOccupancy() <
378  m_bbFrameConf->GetBbFrameLowOccupancyThreshold())
379  {
380  double newOccupancyIfMerged = m_ctrlContainer.back()->GetOccupancyIfMerged(
381  itFromMerge->second.back());
382 
383  if (newOccupancyIfMerged > maxNewOccupancyIfMerged)
384  {
385  maxNewOccupancyIfMerged = newOccupancyIfMerged;
386  frameToMerge = m_ctrlContainer.back();
387  }
388  }
389  }
390 
391  // frame found where merging can be tried
392  if (frameToMerge)
393  {
394  double newWeightedOccupancyIfMerged =
395  frameToMerge->GetSpectralEfficiency(carrierBandwidthInHz) *
396  maxNewOccupancyIfMerged;
397 
398  if (newWeightedOccupancyIfMerged > weightedOccupancy)
399  {
400  // Merge two frames
401 
402  if (frameToMerge->MergeWithFrame(itFromMerge->second.back(),
404  {
405  m_totalDuration -= itFromMerge->second.back()->GetDuration();
406  itFromMerge->second.pop_back();
407  }
408  }
409  }
410  }
411  }
412  }
413 
414  // if both short and normal frames are used then try to shrink normal frames
415  // which are last ones in containers
416  if (m_bbFrameConf->GetBbFrameUsageMode() == SatEnums::SHORT_AND_NORMAL_FRAMES)
417  {
418  // go through all MODCOD based BB Frame containers and try to shrink last frame in the
419  // container
420  for (FrameContainer_t::reverse_iterator it = m_container.rbegin(); it != m_container.rend();
421  it++)
422  {
423  if (it->second.empty() == false)
424  {
425  m_totalDuration -= it->second.back()->Shrink(m_bbFrameConf);
426  }
427  }
428 
429  if (m_ctrlContainer.empty() == false)
430  {
431  m_totalDuration -= m_ctrlContainer.back()->Shrink(m_bbFrameConf);
432  }
433  }
434 }
435 
436 } // 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
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.