1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
/* -*- c++ -*- */
/* Copyright 2016 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* GNU Radio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DIGITAL_HEADER_FORMAT_BASE_H
#define INCLUDED_DIGITAL_HEADER_FORMAT_BASE_H
#include <pmt/pmt.h>
#include <gnuradio/digital/api.h>
#include <gnuradio/digital/header_buffer.h>
#include <gnuradio/logger.h>
#include <boost/enable_shared_from_this.hpp>
namespace gr {
namespace digital {
/*!
* \brief Base header formatter class.
* \ingroup packet_operators_blk
*
* \details
*
* Creates a base class that other packet formatters will inherit
* from. The child classes create and parse protocol-specific
* headers. To add a new protocol processing class, create a class
* that inherits from this and overload the necessary
* functions. The main functions to overload are:
*
* \li header_format_base::format: takes in a payload and
* creates a header from it.
*
* \li header_format_base::parse: receive bits and extract
* the header info. These are expected to be hard bits (0 or 1)
* that have either been sliced or gone through an FEC decoder.
*
* \li header_format_base::header_nbits: the number of bits
* in the full header (including an access code).
*
* \li header_format_base::header_ok: checks to see if the
* received header is ok. Since the header often specifies the
* length of the frame to decode next, it is important that this
* information be correct.
*
* \li header_format_base::header_payload: unpacks the header
* register (from the class header_buffer) as a set of bits into
* its component parts of the header. For example, this may find
* and extract the frame length field as a 16-bit value and/or
* flags related to the type of modulation and FEC codes used in
* the frame's payload.
*
* Protected functions of this class that the child class should
* overload include:
*
* \li enter_search
* \li enter_have_sync
* \li enter_have_header
*
* These three function represent the different states of the
* parsing state machine. Expected behavior is that the protocol
* has some known word that we are first looking for the identify
* the start of the frame. The parsing FSM starts in a state to
* search for the beginning of the header, normally by looking for
* a known word (i.e., the access code). Then it changes state to
* read in the full header. We expect that the protocol provides
* the length of the header for processing, so the parsing looks
* pulls in the full length of the header. Then it changes state
* to the "have header" state for checking and processing. The
* base class provides the basic functionality for this state
* machine. However, most likely, each child class must manage
* these states for themselves.
*
* This class is specifically designed to work with packets/frames
* in the asynchronous PDU architecture of GNU Radio. See the
* packet_format_async block for formatting the headers onto
* payloads and packet_parse_b block for parsing headers in a
* receiver.
*
* The Packet Format block takes in a PDU and uses a formatter
* class derived from this class to add a header onto the
* packet. The Packet Format blocks takes in the PDU, unpacks the
* message, and passes it to a formatter class' format function,
* which builds a header based on the payload. The header is
* passed back and emitted from formatter block as a separate
* output. The async format block, packet_format_async, has two
* message output ports. The 'header' port passes the header out
* as a PDU and the 'payload' passes the payload out as a PDU. The
* flowgraph can then separately modulate and combine these two
* pieces in the follow-on processing.
*
* The packet_sync_b block uses the formatter class by calling the
* 'parse' function to parse the received packet headers. This
* parser block is a sink for the data stream and emits a message
* from an 'info' port that contains an PMT dictionary of the
* information in the header. The formatter class determines the
* dictionary keys.
*
* This is the base class for dealing with formatting headers for
* different protocols and purposes. For other header formatting
* behaviors, create a child class from here and overload the
* format, parse, and parsing state machine functions as
* necessary.
*
* \sa header_format_default
* \sa header_format_counter
*/
class DIGITAL_API header_format_base
: public boost::enable_shared_from_this<gr::digital::header_format_base>
{
public:
typedef boost::shared_ptr<header_format_base> sptr;
header_format_base();
virtual ~header_format_base();
sptr base() { return shared_from_this(); };
sptr formatter() { return shared_from_this(); };
/*!
* Function to creates a header. The child classes overload this
* function to format the header in the protocol-specific way.
*
* \param nbytes_in The length (in bytes) of the \p input payload
* \param input An array of unsigned chars of the packet payload
* \param output A pmt::u8vector with the new header prepended
* onto the input data.
* \param info A pmt::dict containing meta data and info about
* the PDU (generally from the metadata portion of the
* input PDU). Data can be extracted from this for the
* header formatting or inserted.
*
* MUST be overloaded.
*/
virtual bool format(int nbytes_in,
const unsigned char *input,
pmt::pmt_t &output,
pmt::pmt_t &info) = 0;
/*!
* Parses a header. This function is overloaded in the child
* class, which knows how to convert the incoming hard bits (0's
* and 1's) back into a packet header.
*
* \param nbits_in The number of bits in the input array.
* \param input The input as hard decision bits.
* \param info A vector of pmt::dicts to hold any meta data or
* info about the PDU. When parsing the header, the
* formatter can add info from the header into this dict.
* Each packet has a single PMT dictionary of info, so
* the vector length is the number of packets received
* extracted during one call to this parser function.
* \param nbits_processed Number of input bits actually
* processed; If all goes well, this is nbits_in. A
* premature return after a bad header could be less than
* this.
*
* MUST be overloaded.
*/
virtual bool parse(int nbits_in,
const unsigned char *input,
std::vector<pmt::pmt_t> &info,
int &nbits_processed) = 0;
/*!
* Returns the length of the formatted header in bits.
* MUST be overloaded.
*/
virtual size_t header_nbits() const = 0;
/*!
* Returns the length of the formatted header in bytes.
* Auto-calculated from the overloaded header_nbits().
*/
size_t header_nbytes() const;
protected:
enum state_t {STATE_SYNC_SEARCH, STATE_HAVE_SYNC};
state_t d_state; //!< state of the state machine
header_buffer d_hdr_reg; //!< header_buffer object to hold header bits
pmt::pmt_t d_info; //!< info captured from the header
//! Enter Search state of the state machine to find the access code.
virtual void enter_search();
//! Access code found, start getting the header
virtual void enter_have_sync();
//! Header found, setup for pulling in the hard decision bits
virtual void enter_have_header(int payload_len);
//! Verify that the header is valid
virtual bool header_ok() = 0;
/*! Get info from the header; return payload length and package
* rest of data in d_info dictionary.
*/
virtual int header_payload() = 0;
/*! Used by blocks to access the logger system.
*/
gr::logger_ptr d_logger;
gr::logger_ptr d_debug_logger;
};
} // namespace digital
} // namespace gr
#endif /* INCLUDED_DIGITAL_HEADER_FORMAT_BASE_H */
|