EMANE  1.2.1
pormanager.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 - Adjacent Link LLC, Bridgewater, New Jersey
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * * Neither the name of Adjacent Link LLC nor the names of its
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "pormanager.h"
36 
37 #include <cmath>
38 #include <cstdlib>
39 #include <limits>
40 
41 #include <libxml/parser.h>
42 #include <libxml/xmlschemas.h>
43 
44 namespace
45 {
46  const char * pzSchema="\
47 <xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>\
48  <xs:simpleType name='SIPrefixType'>\
49  <xs:restriction base='xs:token'>\
50  <xs:pattern value='[0-9]+(.[0-9]+){0,1}(G|M|K){0,1}'/>\
51  </xs:restriction>\
52  </xs:simpleType>\
53  <xs:simpleType name='SINRType'>\
54  <xs:restriction base='xs:token'>\
55  <xs:pattern value='[+-]?(0|[1-9][0-9]*)(.[0-9]{1,2})?'/>\
56  </xs:restriction>\
57  </xs:simpleType>\
58  <xs:simpleType name='PORType'>\
59  <xs:restriction base='xs:token'>\
60  <xs:pattern value='(0|[1-9][0-9]*)(.[0-9]{1,2})?'/>\
61  </xs:restriction>\
62  </xs:simpleType>\
63  <xs:element name='tdmabasemodel-pcr'>\
64  <xs:complexType>\
65  <xs:sequence>\
66  <xs:element name='datarate' maxOccurs='unbounded'>\
67  <xs:complexType>\
68  <xs:sequence>\
69  <xs:element name='entry' maxOccurs='unbounded'>\
70  <xs:complexType>\
71  <xs:attribute name='sinr' type='SINRType' use='optional'/>\
72  <xs:attribute name='por' type='PORType' use='optional'/>\
73  </xs:complexType>\
74  </xs:element>\
75  </xs:sequence>\
76  <xs:attribute name='bps' type='SIPrefixType' use='required'/>\
77  </xs:complexType>\
78  </xs:element>\
79  </xs:sequence>\
80  <xs:attribute name='packetsize' type='xs:unsignedShort' use='required'/>\
81  </xs:complexType>\
82  </xs:element>\
83 </xs:schema>";
84 
85  std::string scaleFloatToInteger(const std::string & sValue)
86  {
87  const int iScaleFactor{2};
88  std::string sTmpParameter{sValue};
89 
90  // location of decimal point, if exists
91  std::string::size_type indexPoint = sTmpParameter.find(".",0);
92 
93  if(indexPoint != std::string::npos)
94  {
95  std::string::size_type numberOfDigitsAfterPoint =
96  sTmpParameter.size() - indexPoint - 1;
97 
98  if(numberOfDigitsAfterPoint > iScaleFactor)
99  {
100  // need to move the decimal point, enough digits are present
101  sTmpParameter.insert(sTmpParameter.size() - (numberOfDigitsAfterPoint - iScaleFactor),
102  ".");
103  }
104  else
105  {
106  // need to append 0s
107  sTmpParameter.append(iScaleFactor - numberOfDigitsAfterPoint,'0');
108  }
109 
110  // remove original decimal point
111  sTmpParameter.erase(indexPoint,1);
112  }
113  else
114  {
115  // need to append 0s
116  sTmpParameter.append(iScaleFactor,'0');
117  }
118 
119  return sTmpParameter;
120  }
121 }
122 
124  u64DefaultCurveDataRate_{},
125  modifierLengthBytes_{}{}
126 
127 void EMANE::Models::TDMA::PORManager::load(const std::string & sPCRFileName)
128 {
129  xmlDocPtr pSchemaDoc{xmlReadMemory(pzSchema,
130  strlen(pzSchema),
131  "file:///tdmabasemodelpcr.xsd",
132  NULL,
133  0)};
134  if(!pSchemaDoc)
135  {
136  throw makeException<ConfigurationException>("unable to open schema");
137  }
138 
139  xmlSchemaParserCtxtPtr pParserContext{xmlSchemaNewDocParserCtxt(pSchemaDoc)};
140 
141  if(!pParserContext)
142  {
143  throw makeException<ConfigurationException>("bad schema context");
144  }
145 
146  xmlSchemaPtr pSchema{xmlSchemaParse(pParserContext)};
147 
148  if(!pSchema)
149  {
150  throw makeException<ConfigurationException>("bad schema parser");
151  }
152 
153  xmlSchemaValidCtxtPtr pSchemaValidCtxtPtr{xmlSchemaNewValidCtxt(pSchema)};
154 
155  if(!pSchemaValidCtxtPtr)
156  {
157  throw makeException<ConfigurationException>("bad schema valid context");
158  }
159 
160  xmlSchemaSetValidOptions(pSchemaValidCtxtPtr,XML_SCHEMA_VAL_VC_I_CREATE);
161 
162  xmlDocPtr pDoc = xmlReadFile(sPCRFileName.c_str(),nullptr,0);
163 
164  if(xmlSchemaValidateDoc(pSchemaValidCtxtPtr, pDoc))
165  {
166  throw makeException<ConfigurationException>("invalid document: %s",
167  sPCRFileName.c_str());
168  }
169 
170  xmlNodePtr pRoot = xmlDocGetRootElement(pDoc);
171 
172  xmlChar * pPacketSize = xmlGetProp(pRoot,BAD_CAST "packetsize");
173 
174  modifierLengthBytes_ = Utils::ParameterConvert(reinterpret_cast<const char *>(pPacketSize)).toUINT16();
175 
176  xmlFree(pPacketSize);
177 
178  for(xmlNodePtr pDataRateNode = pRoot->children;
179  pDataRateNode != nullptr;
180  pDataRateNode = pDataRateNode->next)
181  {
182  if(!xmlStrcmp(pDataRateNode->name, BAD_CAST "datarate"))
183  {
184  xmlChar * pDataRatebps = xmlGetProp(pDataRateNode,BAD_CAST "bps");
185 
186  std::uint64_t u64DataRatebps =
187  Utils::ParameterConvert(reinterpret_cast<const char *>(pDataRatebps)).toUINT64();
188 
189  xmlFree(pDataRatebps);
190 
191  if(dataRateTable_.empty())
192  {
193  u64DefaultCurveDataRate_ = u64DataRatebps;
194  }
195 
196  Curve curve{};
197  std::int32_t i32MinScaledSINR{std::numeric_limits<std::int32_t>::max()};
198  std::int32_t i32MaxScaledSINR{std::numeric_limits<std::int32_t>::lowest()};
199 
200  for(xmlNodePtr pEntryNode = pDataRateNode->children;
201  pEntryNode != nullptr;
202  pEntryNode = pEntryNode->next)
203  {
204  if(!xmlStrcmp(pEntryNode->name, BAD_CAST "entry"))
205  {
206  xmlChar * pSINR = xmlGetProp(pEntryNode,BAD_CAST "sinr");
207  xmlChar * pPOR = xmlGetProp(pEntryNode,BAD_CAST "por");
208 
209  std::int32_t i32ScaledSINR =
210  Utils::ParameterConvert(scaleFloatToInteger(reinterpret_cast<const char *>(pSINR))).toINT32();
211 
212  auto ret =
213  curve.insert(std::make_pair(i32ScaledSINR,
214  Utils::ParameterConvert(reinterpret_cast<const char *>(pPOR)).toFloat()/100));
215 
216  if(!ret.second)
217  {
218  throw makeException<ConfigurationException>("duplicate PCR SINR value for datarate: %zu sinr: %s in %s",
219  u64DataRatebps,
220  reinterpret_cast<const char *>(pSINR),
221  sPCRFileName.c_str());
222  }
223 
224  xmlFree(pSINR);
225  xmlFree(pPOR);
226 
227  i32MinScaledSINR = std::min(i32ScaledSINR,i32MinScaledSINR);
228  i32MaxScaledSINR = std::max(i32ScaledSINR,i32MaxScaledSINR);
229  }
230  }
231 
232  Curve interpolation{};
233 
234  auto iter = curve.begin();
235 
236  while(iter != curve.end())
237  {
238  auto x0 = iter->first;
239  auto y0 = iter->second;
240 
241  ++iter;
242 
243  if(iter != curve.end())
244  {
245  auto x1 = iter->first;
246  auto y1 = iter->second;
247 
248  auto slope = (y1 - y0) / (x1 - x0);
249 
250  for(auto i = x0; i < x1; ++i)
251  {
252  interpolation.insert({i,y1 - (x1 - i) * slope});
253  }
254  }
255  }
256 
257  curve.insert(interpolation.begin(),interpolation.end());
258 
259  auto ret = dataRateTable_.insert(std::make_pair(u64DataRatebps,
260  std::make_tuple(i32MinScaledSINR,
261  i32MaxScaledSINR,
262  curve)));
263 
264  if(!ret.second)
265  {
266  throw makeException<ConfigurationException>("duplicate PCR datarate: %zu in %s",
267  u64DataRatebps,
268  sPCRFileName.c_str());
269  }
270 
271  }
272  }
273 
274  xmlFreeDoc(pSchemaDoc);
275 
276  xmlFreeDoc(pDoc);
277 }
278 
279 
280 float EMANE::Models::TDMA::PORManager::getPOR(std::uint64_t u64DataRatebps,
281  float fSINR,
282  size_t packetLengthBytes)
283 {
284  auto iter = dataRateTable_.find(u64DataRatebps);
285 
286  if(iter == dataRateTable_.end())
287  {
288  iter = dataRateTable_.find(u64DefaultCurveDataRate_);
289  }
290 
291  std::int32_t i32MinScaledSINR = std::get<0>(iter->second);
292  std::int32_t i32MaxScaledSINR = std::get<1>(iter->second);
293  Curve & curve = std::get<2>(iter->second);
294 
295  std::int32_t i32Scaled{static_cast<std::int32_t>(fSINR * 100)};
296 
297  if(i32Scaled < i32MinScaledSINR)
298  {
299  return 0;
300  }
301 
302  if(i32Scaled > i32MaxScaledSINR)
303  {
304  return 1;
305  }
306 
307  auto curveIter = curve.find(i32Scaled);
308 
309  if(curveIter != curve.end())
310  {
311  auto por = curveIter->second;
312 
313  if(modifierLengthBytes_)
314  {
315  por = powf(por, packetLengthBytes / static_cast<float>(modifierLengthBytes_));
316  }
317 
318  return por;
319  }
320 
321  return 0;
322 }
323 
325 EMANE::Models::TDMA::PORManager::PORManager::dump()
326 {
327  CurveDumps ret{};
328 
329  for(const auto & dataRateEntry : dataRateTable_)
330  {
331  CurveDump entries{};
332 
333  for(const auto & porEntry : std::get<2>(dataRateEntry.second))
334  {
335  entries.insert({porEntry.first / 100.0, porEntry.second});
336  }
337 
338  ret.insert({dataRateEntry.first,entries});
339  }
340 
341  return ret;
342 }
void load(const std::string &sPCRFileName)
Definition: pormanager.cc:127
std::map< std::uint64_t, CurveDump > CurveDumps
Definition: pormanager.h:68
std::map< float, float > CurveDump
Definition: pormanager.h:67
std::uint16_t toUINT16(std::uint16_t u16Min=std::numeric_limits< std::uint16_t >::min(), std::uint16_t u16Max=std::numeric_limits< std::uint16_t >::max()) const
std::uint64_t toUINT64(std::uint64_t u64Min=std::numeric_limits< std::uint64_t >::min(), std::uint64_t u64Max=std::numeric_limits< std::uint64_t >::max()) const
float getPOR(std::uint64_t u64DataRate, float fSINR, size_t packetLengthBytes)
Definition: pormanager.cc:280
std::int32_t toINT32(std::int32_t i32Min=std::numeric_limits< std::int32_t >::min(), std::int32_t i32Max=std::numeric_limits< std::int32_t >::max()) const
Parameter conversion class with range checks.