GNU Radio Manual and C++ API Reference  3.10.9.1
The Free & Open Software Radio Ecosystem
header_buffer.h
Go to the documentation of this file.
1 /* -*- c++ -*- */
2 /* Copyright 2015-2016 Free Software Foundation, Inc.
3  *
4  * This file is part of GNU Radio
5  *
6  * SPDX-License-Identifier: GPL-3.0-or-later
7  *
8  */
9 
10 #ifndef INCLUDED_DIGITAL_HEADER_BUFFER_H
11 #define INCLUDED_DIGITAL_HEADER_BUFFER_H
12 
13 #include <gnuradio/digital/api.h>
14 #include <cstdint>
15 #include <cstdlib>
16 #include <vector>
17 
18 namespace gr {
19 namespace digital {
20 
21 /*!
22  * \brief Helper class for handling payload headers.
23  * \ingroup packet_operators_blk
24  *
25  * \details
26  *
27  * This class is used by the header format blocks (e.g.,
28  * digital::header_format_default) to make it easier to deal with
29  * payload headers. This class functions in two different ways
30  * depending on if it is used in a transmitter or receiver. When
31  * used in a transmitter, this class helps us build headers out of
32  * the fields of the protocol. When used in a receiver, this class
33  * helps us parse the received bits into the protocol's fields.
34  *
35  * This page describes how to work with the different modes,
36  * transmit or receive. The class is instructed as to which mode
37  * it is in by how the constructor is called. If the constructor
38  * is passed a valid array (non NULL), then it is in transmit mode
39  * and will pack this buffer with the header fields. If that
40  * buffer is NULL, the object is in receive mode.
41  *
42  * \section header_buffer_tx Transmit Mode
43  *
44  * When passed a valid buffer in the constructor, this object is in
45  * transmit mode. We can then use the add_field[N] functions to
46  * add new fields to this header. The buffer MUST be large enough
47  * to hold the full header. As this class is meant to work mostly
48  * with the digital::header_format_default and child
49  * classes, the header length can be read from
50  * digital::header_format_default::header_nbytes().
51  *
52  * Each field is a specific length of 8, 16, 32, or 64 bits that
53  * are to be transmitted in network byte order. We can adjust the
54  * direction of the bytes by setting the byte-swap flag, \p bs, to
55  * true or false.
56  *
57  * The length argument (\p len) for all add_field[N] calls is the
58  * number of bytes actually accounted for in the data
59  * structure. Often, we would use the full size of the field,
60  * which is sizeof(dtype), and the add_field[N] call defaults to
61  * len=N. Occasionally, we may need to use fewer bytes than
62  * actually represented by the data type. An example would be the
63  * access code used in the header_format_default, which is a
64  * uint64_t type but may have fewer bytes used in the actual
65  * access code.
66  *
67  * The function that calls this class is expected to handle the
68  * memory handling of the buffer -- both allocating and
69  * deallocating.
70  *
71  * As simple example of using this class in transmit mode:
72  *
73  * \verbatim
74  volk::vector<uint8_t> buffer(header_nbytes());
75 
76  header_buffer hdr(buffer);
77  hdr.add_field64(sync_word, sync_word_len);
78  hdr.add_field16(payload_length);
79  hdr.add_field8(header_flags);
80  hdr.add_field8(header_options);
81 
82  // Do something with the header
83  \endverbatim
84  *
85  * In this example, the header contains four fields:
86  *
87  * \verbatim
88  |0 15|16 23|24 31|
89  | sync word |
90  | |
91  | length | flags | options |
92  \endverbatim
93  *
94  * The sync word can be up to 64-bits, but the add_field64 is also
95  * passed the number of actual bytes in the sync word and so could
96  * be fewer.
97  *
98  * \section header_buffer_rx Receive Mode
99  *
100  * In receive mode, we build up the header as bits are received by
101  * inserting them with insert_bit. We can find out how long the
102  * current header is, in bits, using the call to length(). If the
103  * header is of the appropriate length, we can then start
104  * extracting the fields from it. When we are done with the
105  * current header, call clear() to reset the internal buffer to
106  * empty, which will mean that length() returns 0.
107  *
108  * The header fields are extracted using the extract_field[N]
109  * functions. Like the add_field[N] functions, we specify the size
110  * (in bits) of the field we are extracting. We pass this function
111  * the bit-position of the expected field in the received header
112  * buffer. The extract_field[N] assumes that the number of bits
113  * for the field is N, but we can tell the function to use fewer
114  * bits if we want. Setting the length parameter of these
115  * functions greater than N is illegal, and it will throw an
116  * error.
117  *
118  * For example, given a header of | length | seq. num. | where the
119  * length is 16 bits and the sequence number is 32 bits, we would
120  * use:
121  *
122  * \verbatim
123  uint16_t len = d_hdr_reg.extract_field16(0);
124  uint32_t seq = d_hdr_reg.extract_field32(16);
125  \endverbatim
126  *
127  * The extract_field functions are specific to data types of the
128  * field and the number of bits for each field is inferred by the
129  * data type. So extract_field16 assumes we want all 16 bits in
130  * the field represented.
131  *
132  * Some headers have fields that are not standard sizes of
133  * integers, like a 1 bit, 4 bit, or even 12 bit fields. We can
134  * ask for fewer bits for each field. say:
135  *
136  * \verbatim
137  |0 15|16 19|20 31|
138  | len | flags | options |
139  \endverbatim
140  *
141  * We would use the following extraction functions:
142  *
143  * \verbatim
144  uint16_t len = d_hdr_reg.extract_field16(0);
145  uint8_t flags = d_hdr_reg.extract_field8(16, 4);
146  uint16_t opts = d_hdr_reg.extract_field16(20, 12);
147  \endverbatim
148  *
149  * \sa header_format_default
150  * \sa header_format_counter
151  * \sa header_format_crc
152  */
154 {
155 private:
156  size_t d_offset;
157  uint8_t* d_buffer;
158 
159  std::vector<bool> d_input;
160 
161 public:
162  /*!
163  * Create a header buffer object with a pre-allocated buffer, \p
164  * buffer, to hold the formatted header data.
165  *
166  * If \p buffer is set to NULL, then this object is in receive
167  * mode meant to receive bits from an incoming data stream and
168  * provide the ability to extract fields. In this mode, calls to
169  * add_field are invalid and will be nops.
170  */
171  header_buffer(uint8_t* buffer = NULL);
172 
173  /*!
174  * Class destructor.
175  */
177 
178  /*!
179  * Clears the header.
180  *
181  * In transmit mode, this resets the current offset so new
182  * add_field functions start adding data to the start of the
183  * buffer.
184  *
185  * In receive mode, this clears the buffer that we have inserted
186  * bits in to.
187  */
188  void clear();
189 
190 
191  /*!
192  * In transmit mode, this returns the length of the data in
193  * the buffer (not the allocated buffer length).
194  *
195  * In receiving mode, this returns the current length in bits of
196  * the received header.
197  */
198  size_t length() const;
199 
200  /*!
201  * Returns a constant pointer to the buffer.
202  */
203  const uint8_t* header() const;
204 
205  /*!
206  * Add an 8-bit field to the header.
207  *
208  * \param data The 8-bit data item.
209  * \param len Length (in bits) of \p data.
210  * \param bs Set to 'true' to byte swap the data.
211  */
212  void add_field8(uint8_t data, int len = 8, bool bs = false);
213 
214  /*!
215  * Add an 16-bit field to the header.
216  *
217  * \param data The 16-bit data item.
218  * \param len Length (in bits) of \p data.
219  * \param bs Set to 'true' to byte swap the data.
220  */
221  void add_field16(uint16_t data, int len = 16, bool bs = false);
222 
223  /*!
224  * Add an 32-bit field to the header.
225  *
226  * \param data The 32-bit data item.
227  * \param len Length (in bits) of \p data.
228  * \param bs Set to 'true' to byte swap the data.
229  */
230  void add_field32(uint32_t data, int len = 32, bool bs = false);
231 
232  /*!
233  * Add an 64-bit field to the header.
234  *
235  * \param data The 64-bit data item.
236  * \param len Length (in bits) of \p data.
237  * \param bs Set to 'true' to byte swap the data.
238  */
239  void add_field64(uint64_t data, int len = 64, bool bs = false);
240 
241 
242  /*****************************************************
243  * Receive mode to build a header from bits *
244  *****************************************************/
245 
246  /*!
247  * Insert a new bit on the back of the input buffer. This
248  * function is used in receive mode to add new bits as they are
249  * received for later use of the extract_field functions.
250  *
251  * \param bit New bit to add.
252  */
253  void insert_bit(int bit);
254 
255 
256  /*!
257  * Returns a field in the packet header.
258  *
259  * \param pos Bit position of the start of the field.
260  * \param len The number of bits in the field.
261  * \param bs Set to 'true' to byte swap the data.
262  * \param lsb_first Set to 'true' to read field encoded as least significant bit first
263  */
264  template <class T>
265  T extract_field(int pos,
266  int len = 8 * sizeof(T),
267  bool bs = false,
268  bool lsb_first = false);
269 
270  /*!
271  * Returns up to an 8-bit field in the packet header.
272  *
273  * \param pos Bit position of the start of the field.
274  * \param len The number of bits in the field.
275  * \param bs Set to 'true' to byte swap the data.
276  * \param lsb_first Set to 'true' to read field encoded as least significant bit first
277  */
278  uint8_t extract_field8(int pos, int len = 8, bool bs = false, bool lsb_first = false)
279  {
280  return extract_field<uint8_t>(pos, len, bs, lsb_first);
281  };
282  // constexpr auto& extract_field8 = extract_field<uint8_t>;
283  /*!
284  * Returns up to a 16-bit field in the packet header.
285  *
286  * \param pos Bit position of the start of the field.
287  * \param len The number of bits in the field.
288  * \param bs Set to 'true' to byte swap the data.
289  * \param lsb_first Set to 'true' to read field encoded as least significant bit first
290  */
291  uint16_t
292  extract_field16(int pos, int len = 16, bool bs = false, bool lsb_first = false)
293  {
294  return extract_field<uint16_t>(pos, len, bs, lsb_first);
295  };
296 
297  /*!
298  * Returns up to a 32-bit field in the packet header.
299  *
300  * \param pos Bit position of the start of the field.
301  * \param len The number of bits in the field.
302  * \param bs Set to 'true' to byte swap the data.
303  * \param lsb_first Set to 'true' to read field encoded as least significant bit first
304  */
305  uint32_t
306  extract_field32(int pos, int len = 32, bool bs = false, bool lsb_first = false)
307  {
308  return extract_field<uint32_t>(pos, len, bs, lsb_first);
309  };
310 
311  /*!
312  * Returns up to a 64-bit field in the packet header.
313  *
314  * \param pos Bit position of the start of the field.
315  * \param len The number of bits in the field.
316  * \param bs Set to 'true' to byte swap the data.
317  * \param lsb_first Set to 'true' to read field encoded as least significant bit first
318  */
319  uint64_t
320  extract_field64(int pos, int len = 64, bool bs = false, bool lsb_first = false)
321  {
322  return extract_field<uint64_t>(pos, len, bs, lsb_first);
323  };
324 };
325 
326 } // namespace digital
327 } // namespace gr
328 
329 #endif /* INCLUDED_DIGITAL_HEADER_BUFFER_H */
Single writer, multiple reader fifo.
Definition: buffer.h:67
Helper class for handling payload headers.
Definition: header_buffer.h:154
uint8_t extract_field8(int pos, int len=8, bool bs=false, bool lsb_first=false)
Definition: header_buffer.h:278
void add_field8(uint8_t data, int len=8, bool bs=false)
uint16_t extract_field16(int pos, int len=16, bool bs=false, bool lsb_first=false)
Definition: header_buffer.h:292
uint64_t extract_field64(int pos, int len=64, bool bs=false, bool lsb_first=false)
Definition: header_buffer.h:320
void add_field64(uint64_t data, int len=64, bool bs=false)
void add_field16(uint16_t data, int len=16, bool bs=false)
const uint8_t * header() const
void add_field32(uint32_t data, int len=32, bool bs=false)
header_buffer(uint8_t *buffer=NULL)
T extract_field(int pos, int len=8 *sizeof(T), bool bs=false, bool lsb_first=false)
uint32_t extract_field32(int pos, int len=32, bool bs=false, bool lsb_first=false)
Definition: header_buffer.h:306
#define DIGITAL_API
Definition: gr-digital/include/gnuradio/digital/api.h:18
GNU Radio logging wrapper.
Definition: basic_block.h:29