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