A Discrete-Event Network Simulator
API
bit-serializer.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Universita' di Firenze, Italy
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Tommaso Pecorella <tommaso.pecorella@unifi.it>
18  */
19 
20 #include "ns3/bit-serializer.h"
21 
22 #include "ns3/bit-deserializer.h"
23 
24 #include <iostream>
25 
26 using namespace ns3;
27 
28 // The main purpose of the BitSerializer and bitDeserializer classes is to
29 // simplify the bit serialization and deserialization in headers, trailers
30 // and packet bodies.
31 //
32 // This is usually performed by using bit masks, which works great if the
33 // field delimiters are known in advance, and are in a fixed position.
34 // If the field (i.e., a group of bits) position is dependent from some
35 // other parameter, then the code is more complex.
36 // If the field boundary is not even a multiple of a byte, then the problem
37 // is even more complex.
38 //
39 // BitSerializer allows you to "push" bits into a temporary buffer, and then
40 // extract an array of uint8_t to be used in
41 // Buffer::Iterator:Write (uint8_t const *buffer, uint32_t size).
42 //
43 // Similarly, BitDeserializer can be initialized by an array of uint8_t,
44 // typically obtained by a Buffer::Iterator:Read (uint8_t *buffer, uint32_t size)
45 // and then "pop" bits from the underlying buffer.
46 //
47 // This example shows the basic operations.
48 
49 int
50 main()
51 {
52  BitSerializer testBitSerializer1;
53 
54  // add 7 bits - 0x55 (101 0101)
55  testBitSerializer1.PushBits(0x55, 7);
56  // add 3 bits - 0x7 (111)
57  testBitSerializer1.PushBits(0x7, 3);
58  // add 2 bits - 0x0 (00)
59  testBitSerializer1.PushBits(0x0, 2);
60  // The results is 1010 1011 1100.
61  // Adding 4 bits of padding at the end the result is 0xabc0.
62 
63  std::vector<uint8_t> result = testBitSerializer1.GetBytes();
64 
65  std::cout << "Result: ";
66  for (std::size_t i = 0; i < result.size(); i++)
67  {
68  std::cout << std::hex << int(result[i]) << " ";
69  }
70  std::cout << std::endl;
71  std::cout << "Expecting: ab c0" << std::endl;
72 
73  // Here, instead of printing bits, you typically serialize them using
74  // Buffer::Iterator:Write (uint8_t const *buffer, uint32_t size).
75  //
76  // In this case the number of bits pushed is not a multiple of a byte
77  // so the class adds a padding at the end of the buffer.
78  // This is the default behaviour.
79 
80  BitSerializer testBitSerializer2;
81 
82  // add 7 bits - 0x55 (101 0101)
83  testBitSerializer2.PushBits(0x55, 7);
84  // add 3 bits - 0x7 (111)
85  testBitSerializer2.PushBits(0x7, 3);
86  // add 2 bits - 0x0 (00)
87  testBitSerializer2.PushBits(0x0, 2);
88 
89  // Change the class behaviour so to use a padding at the start of the buffer.
90  testBitSerializer2.InsertPaddingAtEnd(false);
91  // The results is 1010 1011 1100.
92  // Adding 4 bits of padding at the start the result is 0xabc.
93 
94  result = testBitSerializer2.GetBytes();
95 
96  std::cout << "Result: ";
97  for (std::size_t i = 0; i < result.size(); i++)
98  {
99  std::cout << std::hex << int(result[i]) << " ";
100  }
101  std::cout << std::endl;
102  std::cout << "Expecting: a bc" << std::endl;
103 
104  // Here, instead of printing bits, you typically serialize them using
105  // Buffer::Iterator:Write (uint8_t const *buffer, uint32_t size).
106  //
107  // In this case the number of bits pushed is not a multiple of a byte
108  // so the class adds a padding at the start of the buffer.
109 
110  BitDeserializer testBitDeserializer;
111  uint8_t test[2];
112  test[0] = 0xab;
113  test[1] = 0xc0;
114 
115  // Typically a BitDeserializer will be initialized by an array obtained by
116  // Buffer::Iterator:Read (uint8_t *buffer, uint32_t size).
117 
118  testBitDeserializer.PushBytes(test, 2);
119  uint16_t nibble1 = testBitDeserializer.GetBits(7);
120  uint8_t nibble2 = testBitDeserializer.GetBits(3);
121  uint8_t nibble3 = testBitDeserializer.GetBits(2);
122  // if you deserialize too many bits you'll get an assert.
123  // uint8_t errorNibble = testBitDeserializer.GetBits (6);
124 
125  std::cout << "Result: " << std::hex << nibble1 << " " << +nibble2 << " " << +nibble3 << " "
126  << std::endl;
127  std::cout << "Expecting: 55 7 0" << std::endl;
128 
129  return 0;
130 }
Bit deserializer.
void PushBytes(std::vector< uint8_t > bytes)
Pushes some bytes into the blob to be deserialized.
uint64_t GetBits(uint8_t size)
Pops a given number of bits from the blob front.
Bit serializer.
void PushBits(uint64_t value, uint8_t significantBits)
Pushes a number of bits in the blob.
std::vector< uint8_t > GetBytes()
Get the bytes representation of the blob.
void InsertPaddingAtEnd(bool padAtEnd)
Toggles the padding insertion policy.
Every class exported by the ns3 library is enclosed in the ns3 namespace.