commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] [gnuradio] 05/06: digital: Complete overhaul of protoc


From: git
Subject: [Commit-gnuradio] [gnuradio] 05/06: digital: Complete overhaul of protocol handling
Date: Wed, 15 Jun 2016 04:11:15 +0000 (UTC)

This is an automated email from the git hooks/post-receive script.

jcorgan pushed a commit to branch packet3
in repository gnuradio.

commit 817f61bbdd180a2854116c85ccf1020e561c523f
Author: Tom Rondeau <address@hidden>
Date:   Tue Jun 14 10:48:00 2016 -0700

    digital: Complete overhaul of protocol handling
    
    See documentation for details. In brief:
    
    - digital_protocol_* classes added (replace packet header blocks)
    - header_buffer class added
    - Lots of QA
    
        - default packet formatter: contains access code and payload length
          fields.
    
        - counter packet formatter: also contains the bits/sym in the payload
          modulation and a packet number counter.
    
        - Also adds QA code and the infrastructure for C++ QA code in
          gr-digital.
    
        - New block to use the packet formatter objects.
    
          - The header and payload are transmitted as PDU messages out of 
different ports.
    
        - header_buffer class for header formatting.
    
          - Used by packet_formatter_x classes to more easily add and format
            header data for transmission.
    
        - New blocks that parse headers.
    
          - Handles either hard or soft bits. Produces an info message to
            instruct payload demod.
    
        - 'receive mode' to header_buffer class.
    
          - Designed to make extracting fields from the received header bits
            easier for packet formatter classes. Use extract_field[N] to get
            the different fields out of a collected set of header bits.  *
            Docs describing both functions with small examples for how to use
            them.
    
        - Don't force access code to be a multiple of 8
    
          - need to verify everything else handles this correctly.
    
          - Throw an exception in the ctor if setting the code failed and emit a
            log message.
    
    Committed-By: Martin Braun <address@hidden>
---
 gr-digital/doc/packet_comms.dox                    |  653 +++++++
 gr-digital/examples/CMakeLists.txt                 |    8 +
 gr-digital/examples/ofdm/tx_ofdm.grc               | 2067 +++++++++++---------
 gr-digital/grc/digital_block_tree.xml              |    6 +-
 .../grc/digital_protocol_formatter_async.xml       |   33 +
 gr-digital/grc/digital_protocol_formatter_bb.xml   |   32 +
 gr-digital/grc/digital_protocol_parser_b.xml       |   25 +
 gr-digital/grc/variable_header_format_default.xml  |   35 +
 gr-digital/include/gnuradio/digital/CMakeLists.txt |   11 +-
 .../include/gnuradio/digital/header_buffer.h       |  310 +++
 .../include/gnuradio/digital/header_format_base.h  |  225 +++
 .../gnuradio/digital/header_format_counter.h       |  135 ++
 .../include/gnuradio/digital/header_format_crc.h   |  118 ++
 .../gnuradio/digital/header_format_default.h       |  217 ++
 .../include/gnuradio/digital/header_format_ofdm.h  |  127 ++
 .../gnuradio/digital/protocol_formatter_async.h    |   88 +
 .../gnuradio/digital/protocol_formatter_bb.h       |   81 +
 .../include/gnuradio/digital/protocol_parser_b.h   |   80 +
 gr-digital/lib/CMakeLists.txt                      |   46 +-
 gr-digital/lib/header_buffer.cc                    |  211 ++
 gr-digital/lib/header_format_base.cc               |   70 +
 gr-digital/lib/header_format_counter.cc            |  120 ++
 gr-digital/lib/header_format_crc.cc                |  161 ++
 gr-digital/lib/header_format_default.cc            |  222 +++
 gr-digital/lib/header_format_ofdm.cc               |  180 ++
 gr-digital/lib/packet_header_ofdm.cc               |    9 +-
 gr-digital/lib/protocol_formatter_async_impl.cc    |   94 +
 gr-digital/lib/protocol_formatter_async_impl.h     |   50 +
 gr-digital/lib/protocol_formatter_bb_impl.cc       |  118 ++
 gr-digital/lib/protocol_formatter_bb_impl.h        |   56 +
 gr-digital/lib/protocol_parser_b_impl.cc           |   83 +
 gr-digital/lib/protocol_parser_b_impl.h            |   52 +
 .../{swig/packet_header.i => lib/qa_digital.cc}    |   39 +-
 .../{swig/packet_header.i => lib/qa_digital.h}     |   34 +-
 gr-digital/lib/qa_header_buffer.cc                 |  364 ++++
 gr-digital/lib/qa_header_buffer.h                  |   59 +
 gr-digital/lib/qa_header_format.cc                 |  265 +++
 .../packet_header.i => lib/qa_header_format.h}     |   43 +-
 .../packet_header.i => lib/test_gr_digital.cc}     |   44 +-
 gr-digital/python/digital/qa_packet_format.py      |  135 ++
 gr-digital/swig/CMakeLists.txt                     |    1 +
 gr-digital/swig/digital_swig.i                     |   21 +-
 gr-digital/swig/packet_header.i                    |   34 +-
 43 files changed, 5757 insertions(+), 1005 deletions(-)

diff --git a/gr-digital/doc/packet_comms.dox b/gr-digital/doc/packet_comms.dox
new file mode 100644
index 0000000..9b9f59f
--- /dev/null
+++ b/gr-digital/doc/packet_comms.dox
@@ -0,0 +1,653 @@
+/*! \page page_packet_comms Packet Communications
+
+\section packet_introduction Introduction
+
+This page describes...
+
+The point of these examples and the work is to provide a canonical
+tool for exploring burst digital communications. Providing the entire
+PHY chain in GRC is to help us more easily explore and extract
+portions of the transmit and receive chains to better understand,
+tweak, and optimize the system.
+
+
+\section packet_tx Understanding the Transmitter
+
+The transmitter PHY layer defines the following properties of the
+transmitted frame:
+
+- Data integrity check, generally a \ref gr::digital::crc32_async_bb
+  "CRC". Standard practice would be to calculate a CRC32 of the
+  payload and append this to the end of the frame.
+
+- \ref page_fec "Forward Error Correction (FEC)". For correcting bit
+  errors during reception, we use FEC codes, which have different
+  properties for complexity, correcting capabilities, and amounts of
+  added redundancy. See our \ref page_fec "FEC-API page" in the manual
+  for more on how to use these and what types of codes are already
+  available.
+
+- Frame formatting. We expect the data to have been delivered to the
+  transmitter from some higher layer (MAC/Network), which we treat as
+  the payload. The PHY layer then puts on a bit of its own framing in
+  order to properly transmit it for other radios to receive
+  correctly. This often involves some information about the payload
+  format, such as the length, the type of FEC code used, and the type
+  of modulation or modulation parameters. The PHY layer frame will
+  also often add a known word to the front to help with
+  synchronization and identification. We use the Packet Header
+  Formatter block for this, which is completely defined by a packet
+  formatter object. See the gr::digital::header_format_base class
+  to understand more about how these formatters are created and used.
+
+  The \ref gr::digital::protocol_formatter_async "Protocol Formatter"
+  has two output paths, both emitted as PDUs from message ports. The
+  first message port is "header" that emits the header created for the
+  payload based on the formatter object. The second message port is
+  "payload" which is just the input payload PDU re-emitted. This
+  creates two paths, which allows us to separately modulate the header
+  and payload differently as well as encode the header with a
+  different FEC code. We often want to do this to provide a much
+  simpler and more robust modulation and FEC structure to the header
+  to ensure that it is correctly received and then use a different
+  modulation and code for the payload to maximize throughput.
+
+  NOTE: If the header formatter adds the known word / access code
+  here, and then we apply an FEC code to the header, then we have the
+  problem that the known word is also encoded. The receiver must be
+  made aware of this and correctly look for the encoded known
+  word. The packet_tx hier block example is a case where this
+  happens. If we use a repetition encoder, the access code is now
+  three bits out for every bit in. The packet_rx receiver example has
+  to account for this in the Correlation Estimator block that is
+  correlating against the known word.
+
+- Modulators. We create a modulator path for both the header and
+  payload. We define the operations of these two paths completely
+  using a \ref gr::digital::constellation "Constellation Object" (see
+  the \ref digital_constellations "Digital Modulation" manual page for
+  more information). The constellation objects define the mapping from
+  bits to complex symbols. You can use these objects in various ways,
+  but the packet_tx.grc example provides one way. After moving from
+  the PDU to tagged stream mode, the \ref gr::blocks::repack_bits_bb
+  "Repack Bits block" takes the packed 8-bits/byte data and converts
+  this into "chunks" of the number of bits per symbol of the
+  modulation (using the \ref
+  gr::digital::constellation::bits_per_symbol() "bits_per_symbol()"
+  property of the constellation object). We then map these chunks into
+  some known mapping function, most often a form of Gray Coding, using
+  the \ref gr::digital::map_bb "Map block" and the constellation object's \ref
+  gr::digital::constellation::pre_diff_code() "pre_diff_code()"
+  function. We then move these remapped chunks to complex symbols,
+  again as defined by the constellation object through the \ref
+  gr::digital::constellation::points() "points()" function in the
+  \ref gr::digital::chunks_to_symbols_bc "Chunks to Symbols block".
+
+- Combine the header and payload. We need to take both the header and
+  payload paths back together into a single stream. In packet_tx.grc,
+  we are working with tagged streams, so both paths keep track of the
+  size of their segments. Using the Tagged Stream Mux block, we
+  recombine these two paths into one.
+
+- Burst Shaping and Filtering. The next stage shapes the packet for
+  burst transmission. We apply two blocks to shape the burst
+  appropriately.
+
+  First, the \ref gr::digital::burst_shaper_cc "Burst Shaping block"
+  handles the structure of the burst by applying two different forms
+  of padding. First, there is a window that is applied to the time
+  domain of the burst. This involves a ramping up stage from 0 and a
+  ramping down stage back to 0. We define a window as a vector, and
+  the \ref gr::fft::window "fft.window" set of window functions is
+  useful here, such as using a Hann or Kaiser window. The size of the
+  window is split in half to apply the left half of the window for the
+  ramp-up and the right half of the window for the ramp-down. The
+  window has two different modes: to insert or not insert phasing
+  symbols. When inserting phasing symbols, a sequence of 1's and -1's
+  is inserted for the duration of the ramp-up and ramp-down
+  periods. So a window size of 20 will produce 10 alternative 1's and
+  -1's on the front of the burst and another 10 alternating symbols on
+  the rear of the burst. The window is then applied to these phasing
+  symbols and does not affect the burst symbols directly. If we are
+  not using the phasing symbols, the the window is applied to the
+  front and back of the burst directly.
+
+  The Burst Shaper can also add padded 0's to the front or back of the
+  burst. This allows us to provide some extra control over the
+  structure of the burst. In particular, it can be useful to add
+  post-padding 0's that is the length of the delay of the pulse
+  shaping filter that will come next. This makes sure that the full
+  burst of samples is pushed through the filter and transmitted
+  completely.
+
+
+\verbatim
+                      ____________________
+                     /                    \
+                    /                      \
+                   /                        \
+            ______/                          \____
+            |  E  | D |        C         | B | A |
+
+  A: Pre-padding 0's
+  B: Ramp-up window
+  C: Frame
+  D: Ramp-down window
+  E: Post-padding 0's
+\endverbatim
+
+
+  When using phasing symbols, C is the entire frame and sections B
+  and D are filled with alternative 1's and -1's.
+
+  When not using phase symbols, the frame extends B through C to D.
+
+  After creating this burst shape, we then put the burst through a
+  pulse shaping filter. This filter both shapes the complex samples
+  into appropriate symbols for transmission based on a spectral mask
+  as well as up-samples the burst to the specified number of samples
+  per symbol. In packet_tx, we are using a Polyphase Arbitrary
+  Resampler to perform this task for us, which means that we can
+  specify and real value for the number of samples/symbol, as long as
+  it is greater than or equal to 2.0.
+
+  Typical pulse shape filters are \ref
+  gr::filter::firdes::root_raised_cosine "Root Raised Cosine (RRC)"
+  filters and \ref gr::filter::firdes::gaussian "Gaussian" filters.
+
+  Because the pulse shape filter up-samples, in packet_tx, we use a
+  \ref gr::blocks::tagged_stream_multiply_length "Tagged Stream Multiply 
Length Tag block".
+  The resampler block knows nothing about
+  tagged streams, so when it up-samples, the \ref
+  page_tagged_stream_blocks "tagged stream block (TSB)" tag value does
+  not change. We need to change this tag's value, too, and so we use
+  the multiply length tag block for this purpose. This is helpful when
+  working with UHD devices, like in uhd_packet_tx.grc, because we can
+  explicitly tell the UHD USRP Sink block to expect a tagged stream to
+  manage the transmission of the burst.
+
+\subsection packet_tx_params Parameters of the packet_tx Example
+
+The canonical example for handling narrowband M-PSK or M-QAM is the
+packet_tx.grc hierarchical block.
+
+- Header FEC Code (hdr_enc)
+- Payload FEC Code (pld_enc)
+- Header Constellation Object (hdr_const)
+- Payload Constellation Object (pld_const)
+- Protocol Formatter Object (formatter)
+- Samples per symbol (sps as a float)
+- Pulse shaping filter (psf_taps, designed for the polyphase arbitrary
+  resampler)
+
+We can see all of these objects and settings in the
+packet_loopback_hier.grc example and uhd_packet_tx.grc if using a
+UHD-compatibly radio front end.
+
+\subsection packet_tx_examples Examples
+
+The following examples exist to showcase how to control each stage of
+the transmit processing.
+
+- tx_stage0.grc: simple creation of PDUs to input into the
+  transmitter. By default, this generates \ref gr::blocks::random_pdu
+  "random PDUs" for testing. However, we can switch in the \ref
+  gr::blocks::tuntap_pdu "TUNTAP PDU" block to create a tun or tap
+  device as the input of samples from some OS application. Note that
+  you will need root privileges to create a tun/tap device and
+  configure it.
+
+
+- tx_stage1.grc: Adding a CRC to the frame. The Message Debug prints
+  the before and after adding the \ref gr::digital::crc32_async_bb
+  "CRC32", so we can see the original PDU and then the PDU with the
+  added 4 bytes of check.
+
+
+- tx_stage2.grc: Adding \ref page_fec "forward error correction". This
+  adds an \ref gr::fec::async_encoder "FEC Async Encoder" block to
+  compare pre- and post-encoding. Three different FEC encoders are
+  available immediately in this example with the repetition encoder
+  enabled by default. This encoder just repeats every bit 3 times, so
+  it is easy to see the behavior before and after encoding. Simply
+  disable this FEC code and enabling one of the others will change the
+  encoding behavior.
+
+
+- tx_stage3.grc: takes the payload with the CRC32 check and creates
+  the packet structure. Both the header and payload are printed out,
+  where the payload is the input payload+CRC and the header is defined
+  by the 'formatter' object. The default formatter just applies an
+  access code (using the default 64-bit
+  digital.packet_utils.default_access_code code) and then it
+  calculates the payload length (in bytes) as a 16-bit value. This
+  16-bit length field is duplicated, so in the receiver it can check
+  both 16-bit fields to make sure they agree. This formatter also
+  takes a threshold value. The transmitter does not use this
+  threshold. That parameter is used in the receiver to know how many
+  bits can be wrong in the access code and still pass.
+
+  Disabling the \ref gr::digital::header_format_default
+  "default header definition" and enabling the other 'formatter' to
+  change the protocol. This other protocol definition is the \ref
+  gr::digital::header_format_counter "counter header". It adds the
+  access code and payload length fields as the header like the default
+  formatter. This formatter includes two other fields as well: the
+  number of bits/symbol used in the payload modulator (as a 16-bit
+  field) and a 16-bit counter. Each packet transmitted increments this
+  counter by 1, which means we can keep track of how many packets we
+  have sent and/or received.
+
+- tx_stage4.grc: Here we add the modulation to both the header and
+  payload paths, defined by the hdr_const and pld_const objects,
+  respectively. Both are defined as BPSK constellations by
+  default. The output is shown in two \ref page_qtgui "QTGUI display"
+  graphs. We see the samples in time first, and this is triggering off
+  the TSB tag "packet_len". When the time display updates, we can see
+  the same pattern right after the tag, which is the header, and then
+  the changing samples are the random values in the payload.
+
+  When we look at this Freq tab of this example, we just see a mostly
+  flat frequency response over the entire frequency range. This
+  response is due to the samples just being +1's and -1's with no
+  transition between them and sampled at 1 sampler per symbol. This is
+  not something that we can just transmit as a burst. The square
+  pulses we use provide horrible out-of-band (OOB) emissions if we put
+  this over the air directly, and each burst would go from 0 to +/-1
+  within the coarse of a single sample, which again provides large OOB
+  emissions. We need to shape the bursts properly from here.
+
+- tx_stage5.grc: Adds the \ref gr::digital::burst_shaper_cc "Burst Shaper"
+  block. The default parameters are to use a Hann window of 50 symbols
+  and to add 10 0's as pre- and post-padding. We can adjust any of
+  these values to explore what the output burst looks like. We can
+  stop the time sink from updating and turn on the markers for the
+  Re{Data 0} channel to easily count the samples and observe the
+  effect of the window.
+
+  As an aside, the window of 50 produces 25 phasing samples on either
+  side. This is a lot, but we did this to help show off the way the
+  window looks a bit more clearly.
+
+- tx_stage6.grc: We then need to up-sample the signal by the number of
+  samples/symbol (sps) and apply our pulse-shaping filter. Again, we
+  are using some larger numbers than we really would in an actual
+  scenario to make it visually clear what is happening. The psf_taps
+  filter creates an RRC filter designed for the 32-arm (set by nfilts)
+  polyphase filterbank resampler. In this RRC Filter Taps object, we
+  set the number of taps to be 15*sps*nfilts. The sps and nfilts are
+  properties of the sample stream and upsampling factor. The value 15
+  is the number of symbols to represent in this filter; basically that
+  we are going to look over the history effects of 15 samples to
+  manage the inter-symbol interference (ISI). That is a long RRC filter
+  but done so to make the simulation look better. Five or seven is a
+  more realistic value. Similarly, we set sps=4 here to make the time
+  and frequency plots look better. Normally, we would want this closer
+  to 2.
+
+  Now looking at the time domain plot, we see the filtered samples,
+  which are not as pretty as before. They have over- and under-shoots,
+  and if we turned on the line markers, we would not see the original
+  bits easily through this. That is the effect of the RRC filter,
+  which introduces ISI into the transmitted stream. However, when we
+  look at the frequency domain, we see a much better shape, which we
+  can transmit as part of our channel assignment.
+
+- tx_stage6a.grc: An aside here to study the RRC filters more. This
+  example adds a second RRC filter (without any resampling) that
+  matches the transmitter's RRC filter. The matched filter means that
+  the samples are filtered by two RRC filters, which together make a
+  raised cosine (RC) filter. This RC filter is what is known as a
+  Nyquist filter and has the properties of 0 (or very close to 0)
+  ISI. Though we introduced ISI in the transmit RRC filter, the second
+  stage at the receiver undoes that ISI making for a clean, filtered
+  signal. Turning on marker in the time domain shows two clean lines
+  at +1 and -1. The receiver just needs to know which of the sps
+  samples to grad to get the original symbol that was transmitted. But
+  that is the job of the receiver.
+
+At this point, we have an encoded, modulated, and shaped burst ready
+to be transmitted out of a radio. The uhd_packet_tx.grc example puts
+all this together, where we have packaged up most of the transmitter
+behavior into packet_tx.grc. We then generate random PDU's, put them
+through the packet_tx block, and then through a Multiply Const block
+and into a USRP sink. The Multiply Const block is used for digital
+scaling of the signal to allow us power control on top of the
+transmitter gain inside the USRP radio itself.
+
+
+\section packet_rx Understanding the Receiver
+
+The receiver is far more complicated. The work involved here is
+largely in the detection and synchronization of the received
+frames. We must assume that frames are coming in as bursts with
+potentially random time intervals.
+
+It is important to understand that it is very difficult to make a
+simple protocol work in all scenarios. We have to assume that some
+packets will be lost through either a missed detection at the start or
+poor synchronization statistics during processing of the burst.
+
+The generic receiver example can be found in packet_rx.grc. This hier
+block provides the main detection, synchronization, header/payload
+management, demodulation, and decoding of the PHY frames. The input to
+this hier block should be not be too far off in frequency. The GNU
+Radio block \ref gr::digital::fll_band_edge_cc "FLL Band-Edge" tends
+to work well enough, though this is unnecessary if the radio are
+synchronized in frequency some other way (e.g., with a GPSDO such as
+is available on USRPs).
+
+The main flow of samples here is to detect a frame by discovering its
+known word, which also provides initial estimates on timing and phase
+offsets of the received frame. We then go through a clock sync block
+to perform matched filtering and sample time correction to produce
+resampled symbols at 1 sample/symbol. Now we have samples that are
+split between the header and payload. We might have information inside
+of the header that helps the receiver understand the payload. For
+instance, the length of the payload is generally encoded in the
+header. So we have to demux the header and payload.
+
+We assume that we know the length of the header in symbols, which we
+pass on to the header demodulator chain. Knowing the header
+modulation, we synchronize the phase and frequency, demodulate the
+symbols into soft bits, decode those soft bits based on the known
+header's FEC code, and then parse the header information. The header
+parser extracts information about the payload, such as the number of
+symbols in the payload and possibly the number of bits/symbol used in
+the payload modulation.
+
+The \ref gr::digital::header_payload_demux "Header/Payload Demux"
+block sends the appropriate number of samples to the payload demod
+chain. This chain does its own phase/freq synchronization for the
+appropriate constellation used in the payload, decodes the samples to
+soft bits, performs the FEC decoding, and then does the CRC32
+check. If this passes, the payload is sent out of the hier block as a
+PDU with the PHY layer framing stripped.
+
+When looking at the packet_rx.grc example, notice that we have
+instrumented a number of debug ports along the way. These ports are
+designed to make it possible for us to externally hook up graphing and
+debug blocks in whatever way we are comfortable with to see the signal
+along the path and more easily debug.
+
+
+\subsection packet_rx_correst Correlation Estimator
+
+The first stage of the receiver searches for the known word prepended
+to every burst from the transmitter. The known word has gone through
+two stages of processing: encoding with the header's FEC (optional)
+and modulated by the header's modulator. The correlation of the known
+word is done at the input sample stage, so we have to recreate the
+modulated and possible encoded known word at the receiver.
+
+To simplify dealing with the encoding process, in packet_rx.grc, we
+assume one of two types of codes: dummy code (or not coded) and a 3x
+repetition code. We then just simply calculated the preamble's bits
+for both cases. Depending on the header decoder (hdr_dec) used, the
+hier block knows which preamble to use.
+
+Next, we need to take the known, encoded word and modulate it with the
+header's modulator and pulse shaping filter. We create a simple
+modulator in the variable 'rxmod' that takes the header \ref
+gr::digital::constellation "constellation object" (hdr_const), the
+number of samples per symbol, and the pulse shape filter's bandwidth
+parameter (eb). The \ref gr::digital::modulate_vector_bc "Modulate Vector"
+block than combines this 'rxmod' modulator with the 'preamble'
+known word into a vector of complex symbols, here called
+'modulated_sync_word'. This variable is then passed to the \ref
+gr::digital::corr_est_cc "Correlation Estimator" block.
+
+One tricky thing about burst communications and network setups is the
+power of the received samples is unknown and time varying. It is
+preferential to try to auto-detect the burst and scale the signal to
++/-1 before coming in to packet_rx. There is still a lot of work to be
+done for AGC loops in the hardware and automatic scaling in
+software. The Correlation Estimator tries to deal with this. We use a
+threshold as an approximate probability of detection. This value
+should be set very high; the default here is 99.9%. The correlation
+tends to scale well as the amplitudes change and for relatively low
+SNR conditions. Still, it is always possible to miss a detection event
+or have a false positive.
+
+Another thing that the Correlation Estimator can do for us is provide
+information for digital scaling the samples. When received over
+hardware, the signals tend to be very small, but most of our follow-on
+processing assumes they are about +/-1. The Correlation Estimator
+finds the amplitude of the sample where the correlation peak was
+found, inverts it, and sends it as a tag with the key 'amp_est'. We
+can use this down stream to adjust the amplitude by rescaling the
+samples from this value. For our packet_rx example, we use the \ref
+gr::blocks::multiply_by_tag_value_cc "Multiply by Tag Value" block,
+which updates its multiplicitive factor based on the tag. Much of this
+could be handled by a good AGC routine in the hardware.
+
+Finally, the main purpose of the Correlation Estimator block is to
+provide the down-stream synchronization blocks with initial estimates
+of the timing and phase offset. The peak of the magnitude of the
+correlation event corresponds to the sampling timing of the data
+stream.
+
+\verbatim
+    1.   /\      2.   _
+        /  \         / \
+     __/    \__   __/   \__
+\endverbatim
+
+The above two drawings show two different correlation scenarios. In
+scenario 1, the timing is exact and the sample at the peak of that
+curve is the proper sample time of the last symbol of the known
+word. In scenario 2, there is a timing offset where the correct timing
+offset is half-way between two samples. This would be a timing offset
+of 0.5 (or -0.5). Knowing where that estimated offset is helps our
+timing recover blocks start near the correct sample offset and then
+track from there.
+
+The magnitude of the correlation helps us discover the timing
+offset. The correlation itself is a complex vector. So where the peak
+of the magnitude happens, we can look to the complex value of the
+correlation at the same point and the phase difference between the
+real and imaginary parts is the phase offset of the signal.
+
+The Correlation Estimator block calculates the time and phase offsets
+and creates stream tags for "time_est" and "phase_est". It also
+creates two other tags: "corr_start" and "corr_est," both of which
+contain the value of the peak of the magnitude of the
+correlation. Because there is a delay in the correlation algorithm
+that is affected by the size of the correlation, we need to adjust
+where the correlation event occurs to where the tags are actually
+placed on the output stream. The block places the "corr_start" tag on
+the sample where the correlation actually occurred. It then places the
+other three tags offset by some "Tag marking delay," which is a
+user-calculated value to place the tags at the correct spot in the
+data stream for the actual start of the known word's first symbol.
+
+In packet_rx, we empirically discovered the tag marking delay for
+different values of the samples/symbol ('sps') variable and made a
+list 'mark_delays' that is index by 'sps' to properly set 'mark_delay'
+for the start of the known word. Getting is correct has a huge effect
+on the timing recover loop, which can take a while to converge if it
+starts offset in time by a sample.
+
+See the example example_corr_est.grc to explore the Correlation
+Estimator blocks more.
+
+
+\subsection packet_rx_timing Timing Recovery
+
+After detecting the frame and estimating the time and phase estimates,
+we have to actually perform the timing synchronization step. The
+packet_rx example uses the
+\ref gr::digital::pfb_clock_sync_ccf "Polyphase Clock Sync" block to
+do this. This PFB clock sync (PCS) block typically performs blind
+timing recovery on a series of samples. It is composed of 'nfilt'
+filters in a filterbank where each filter represents a different phase
+from [0, 2pi) in steps of 2pi/nfilts. The algorithm finds the correct
+arm of the filterbank that corresponds to the time shift of the
+samples. It also knows to look for a "time_est" stream tag and use
+that information to set its phase arm estimate. If we have a time
+estimate like scenario 1 above, we have perfect timing and so would
+select the 0th arm of the filterbank. In scenario 2, we are off by
+half a sample, so we select arm nfilts/2. The PCS is a tracking loop,
+so it will start with the initial estimate and then keep track of the
+timing as well as hone-in on actual timing information of the symbol
+stream.
+
+The PCS block uses a filterbank concept to perform its tracking
+operation. The filters within the filterbank operate best when they
+are phase offsets of the matched filter. So not only does the
+block recover the timing, it also performs the matched filtering and
+produces the optimal 1 sample/symbol output. These are then optimally
+sampled symbols in the complex constellation space. They need to be
+mapped back to bits and decoded. But first, we need to parse the
+header in order to discover information about the payload.
+
+See the example example_corr_est_and_clock_sync.grc to play with the
+parameters of time synchronization.
+
+
+\subsection packet_rx_hpd Header/Payload Demux
+
+Because the header and payload can be modulated differently, the rest
+of the symbol processing has to be split into two chains. We do this
+using the \ref gr::digital::header_payload_demux "Header/Payload Demux"
+block (HPD). We assume that we know the protocol, and so the format,
+coding, and modulation of the header. Generally speaking, these are
+all controlled through three different objects:
+
+- formatter: An object that described the header structure, derived
+  from gr::digital::header_format_base.
+
+- hdr_const: An object that describes the bit and symbol mapping,
+  derived from gr::digital::constellation.
+
+- hdr_dec: An object that describes the FEC code, derived from
+  gr::fec::generic_decoder.
+
+Through these, we can ask for any parameter to set up the following
+stages of processing.
+
+The HPD block is fairly complicated and we will only use it in one
+kind of configuration here. See the manual page for the \ref
+gr::digital::header_payload_demux "HPD" block itself for more
+details. In our use of the HPD block, it receives the data stream and
+looks for a Trigger Tag Key. We will use 'time_est', one of the tags
+produced by the Correlation Estimator to indicate the sample that
+starts the header. When the HPD block sees this trigger key, it passes
+along a known number of symbols out of the 'header' stream port. We
+know the number of symbols based on the formatter, constellation, and
+FEC decoder objects. The formatter objects knows the number of bits in
+the header via the header_nbits() function, the constellation knows
+how many bits per symbol (via bits_per_symbol()), and the FEC decoder
+knows the encoding rate (via 1/rate()). The number of symbols in the
+header is therefore:
+
+    (header_nbits() * 1/rate()) / bits_per_symbol()
+
+The HPD then sends this many symbols on to be processed. It holds up
+any more processing until triggered to do so with information through
+the 'header_data' input message port. The header processing chain will
+end with the Packet Parser producing the message here.
+
+When the 'header_data' input message port receives valid information,
+it releases the payload out of the 'payload' stream port. The main
+thing that the 'header_data' input message port receives is
+information about the length of the payload. The HPD parameter 'Length
+tag key' is matched to the message received in 'header_data', which is
+then used to gate the output of samples as the payload. In our case,
+we specify the length as the number of symbols through the message key
+'payload symbols'. This tag then becomes the tagged stream key for the
+payload chain.
+
+
+\subsection packet_rx_hdr_chain Header Processing Chain
+
+The header processing chain is kicked off when the HPD block receives
+the trigger stream tag (i.e., 'time_est'). We must first correct the
+phase and fine frequency offset of the received samples. The
+Correlation Estimator block will help us with this through the
+'phase_est' tag. The \ref gr::digital::costas_loop_cc "Costas Loop"
+looks for this tag, and, when found, it will take this estimate and
+reset its own internal phase value, which greatly speed up
+acquisition. The Costas loop will then track the phase and frequency
+over the course of the header.
+
+With the constellation locked in time, phase, and frequency, we can
+not decode the complex symbols. We use a \ref
+gr::digital::constellation_soft_decoder_cf "Constellation Soft Decoder"
+block for this, which uses the 'hdr_const' object to know the mappings
+from complex space to bits. Specifically, it performs a soft decoding,
+so the outputs are soft decision bits, which is useful for FEC
+decoding that is performed next.
+
+The \ref gr::fec::decoder "FEC decoder" operates on the soft decisions
+based on the hdr_dec object. Because of the bounded nature of the
+header, we would expect simple block codes used here as well as a
+fairly robust and easy to process code. In the current examples, we
+only provide no code (via the \ref gr::fec::code::dummy_encoder
+"Dummy Encoder" / \ref gr::fec::code::dummy_decoder "Dummy Decoder"
+classes) or a repetition code (via the
+\ref gr::fec::code::repetition_encoder "Repetition Encoder" / \ref
+gr::fec::code::repetition_decoder "Repetition Decoder" classes). The
+output of the FEC decoder block is a bit stream where each item is
+either a 1 or a 0.
+
+The last step in the header processing stage is to parse that bit
+stream back into the header. The \ref gr::digital::protocol_parser_b
+"Packet Parser" block does this by receiving a bit stream, passing it
+to the \ref gr::digital::header_format_base::parse "parse" function of
+the packet formatter object, and emitting a message with the
+information about the parsed data.
+
+The packet parsing is explained in detail in the \ref
+gr::digital::header_format_base "Packet Formatter Base" class. The
+parse function packs together the received bits into the different
+header fields, checks that the header is correct, and the constructs a
+PMT dictionary of the header information, such as the payload length
+and other possible information like the type of constellation or FEC
+coding used on the payload bits. This is the message that gets passed
+back to the HPD block to guide the payload processing.
+
+If the packet formatter parsing operation fails by not getting enough
+data or if the data is corrupted, it will return false. When the
+Packet Parser sees this, it emits a message that just contains a \ref
+page_pmt "PMT" False (pmt::PMT_F), which resets the HPD block to start
+looking for another header trigger event.
+
+If the header parsing completes successfully, the HPD block gets a
+message with information about the payload. Most importantly, it gets
+information about how many symbols make up the payload. It then sends
+a tagged stream to the payload processing chain with this many
+symbols.
+
+
+\subsection packet_rx_pld_chain Payload Processing Chain
+
+The payload processing chain behaves very similarly to the header
+processing chain for the first few blocks. It starts by locking the
+phase and frequency in another \ref gr::digital::costas_loop_cc
+"Costas loop", and then perform \ref
+gr::digital::constellation_soft_decoder_cf "soft decoding" on the
+symbols using the 'pld_const' object. Because we come in as symbols
+and out as soft decisions, the constellation soft decoder will produce
+\ref gr::digital::constellation::bits_per_symbol() "bits_per_symbol()"
+times as many outputs as inputs, but the soft decoder will not change
+the tag stream information. To compensate for this, we use a \ref
+gr::blocks::tagged_stream_multiply_length
+"Tagged Stream Multiply Length" block to update the tagged stream tag
+"payload symbols". We then move from the tagged stream mode into PDU
+mode and perform the FEC decoding through the \ref
+gr::fec::async_decoder "asynchronous FEC decoder". This decoder is
+nice in that it comes in with soft bits and produces packed
+bytes. These packed bytes are now the full payload with the CRC32
+appended. The \ref gr::digital::crc32_async_bb "Async CRC32" block in
+"Check CRC" mode will take this PDU of packed bytes, calculate the CRC
+and check it against the final four bytes of the payload. If they
+match, the PDU is stripped of the CRC bytes and the frame is passed
+out of the hier block. This PDU frame is now ready for use in higher
+layers of processing.
+
+This takes us through the entire processing chain on the
+receiver. From here, it is a matter of tweaking parameters and playing
+with options and other setups to improve behavior.
+
+*/
diff --git a/gr-digital/examples/CMakeLists.txt 
b/gr-digital/examples/CMakeLists.txt
index 38ee443..abf97ac 100644
--- a/gr-digital/examples/CMakeLists.txt
+++ b/gr-digital/examples/CMakeLists.txt
@@ -95,3 +95,11 @@ install(
     DESTINATION ${GR_PKG_DIGITAL_EXAMPLES_DIR}/demod
     COMPONENT "digital_python"
 )
+
+
+# PACKET
+install(
+    FILES
+    DESTINATION ${GR_PKG_DIGITAL_EXAMPLES_DIR}/packet
+    COMPONENT "digital_python"
+)
diff --git a/gr-digital/examples/ofdm/tx_ofdm.grc 
b/gr-digital/examples/ofdm/tx_ofdm.grc
index 368f16b..3c8aca2 100644
--- a/gr-digital/examples/ofdm/tx_ofdm.grc
+++ b/gr-digital/examples/ofdm/tx_ofdm.grc
@@ -1,160 +1,151 @@
-<?xml version='1.0' encoding='ASCII'?>
+<?xml version='1.0' encoding='utf-8'?>
+<?grc format='1' created='3.7.10'?>
 <flow_graph>
   <timestamp>Wed Jul  9 15:49:47 2014</timestamp>
   <block>
-    <key>variable</key>
+    <key>options</key>
     <param>
-      <key>id</key>
-      <value>sync_word2</value>
+      <key>author</key>
+      <value></value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>window_size</key>
+      <value>1280, 1024</value>
     </param>
     <param>
-      <key>value</key>
-      <value>[0, 0, 0, 0, 0, 0, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 
1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 0, 1, -1, 1, 1, 1, -1, 1, 1, 1, 
-1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 0, 0, 0, 0, 0] 
</value>
+      <key>category</key>
+      <value>Custom</value>
     </param>
     <param>
-      <key>alias</key>
+      <key>comment</key>
       <value></value>
     </param>
     <param>
+      <key>description</key>
+      <value>Example of an OFDM Transmitter</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
       <key>_coordinate</key>
-      <value>(496, 128)</value>
+      <value>(1, 0)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>variable</key>
     <param>
-      <key>id</key>
-      <value>length_tag_key</value>
+      <key>generate_options</key>
+      <value>qt_gui</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>hier_block_src_path</key>
+      <value>.:</value>
     </param>
     <param>
-      <key>value</key>
-      <value>"packet_len"</value>
+      <key>id</key>
+      <value>tx_ofdm</value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>max_nouts</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(352, 0)</value>
+      <key>qt_qss_theme</key>
+      <value></value>
     </param>
     <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>realtime_scheduling</key>
+      <value></value>
     </param>
-  </block>
-  <block>
-    <key>variable</key>
     <param>
-      <key>id</key>
-      <value>samp_rate</value>
+      <key>run_command</key>
+      <value>{python} -u {filename}</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>run_options</key>
+      <value>run</value>
     </param>
     <param>
-      <key>value</key>
-      <value>100000</value>
+      <key>run</key>
+      <value>True</value>
     </param>
     <param>
-      <key>alias</key>
+      <key>thread_safe_setters</key>
       <value></value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(255, 0)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>title</key>
+      <value>OFDM Tx</value>
     </param>
   </block>
   <block>
     <key>variable</key>
     <param>
-      <key>id</key>
-      <value>rolloff</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>value</key>
-      <value>0</value>
+      <key>_coordinate</key>
+      <value>(181, -1)</value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>_rotation</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(898, -1)</value>
+      <key>id</key>
+      <value>fft_len</value>
     </param>
     <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>value</key>
+      <value>64</value>
     </param>
   </block>
   <block>
     <key>variable</key>
     <param>
-      <key>id</key>
-      <value>payload_mod</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
-      <value>True</value>
+      <value>1</value>
     </param>
     <param>
-      <key>value</key>
-      <value>digital.constellation_qpsk()</value>
+      <key>_coordinate</key>
+      <value>(720, 69)</value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>_rotation</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(734, 0)</value>
+      <key>id</key>
+      <value>hdr_format</value>
     </param>
     <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>value</key>
+      <value>digital.header_format_ofdm(occupied_carriers, 1, 
length_tag_key,)</value>
     </param>
   </block>
   <block>
     <key>variable</key>
     <param>
-      <key>id</key>
-      <value>header_mod</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>value</key>
-      <value>digital.constellation_bpsk()</value>
-    </param>
-    <param>
-      <key>alias</key>
-      <value></value>
-    </param>
-    <param>
       <key>_coordinate</key>
       <value>(567, 0)</value>
     </param>
@@ -162,479 +153,462 @@
       <key>_rotation</key>
       <value>0</value>
     </param>
+    <param>
+      <key>id</key>
+      <value>header_mod</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>digital.constellation_bpsk()</value>
+    </param>
   </block>
   <block>
     <key>variable</key>
     <param>
-      <key>id</key>
-      <value>packet_len</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>value</key>
-      <value>96</value>
+      <key>_coordinate</key>
+      <value>(352, 0)</value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>_rotation</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(476, 0)</value>
+      <key>id</key>
+      <value>length_tag_key</value>
     </param>
     <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>value</key>
+      <value>"packet_len"</value>
     </param>
   </block>
   <block>
     <key>variable</key>
     <param>
-      <key>id</key>
-      <value>fft_len</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>value</key>
-      <value>64</value>
+      <key>_coordinate</key>
+      <value>(320, 69)</value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>_rotation</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(181, -1)</value>
+      <key>id</key>
+      <value>occupied_carriers</value>
     </param>
     <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>value</key>
+      <value>(range(-26, -21) + range(-20, -7) + range(-6, 0) + range(1, 7) + 
range(8, 21) + range(22, 27),)</value>
     </param>
   </block>
   <block>
     <key>variable</key>
     <param>
-      <key>id</key>
-      <value>header_formatter</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>value</key>
-      <value>digital.packet_header_ofdm(occupied_carriers, 1, 
length_tag_key)</value>
+      <key>_coordinate</key>
+      <value>(476, 0)</value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>_rotation</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(708, 64)</value>
+      <key>id</key>
+      <value>packet_len</value>
     </param>
     <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>value</key>
+      <value>96</value>
     </param>
   </block>
   <block>
     <key>variable</key>
     <param>
-      <key>id</key>
-      <value>pilot_carriers</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>value</key>
-      <value>((-21, -7, 7, 21,),)</value>
+      <key>_coordinate</key>
+      <value>(734, 0)</value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>_rotation</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(480, 64)</value>
+      <key>id</key>
+      <value>payload_mod</value>
     </param>
     <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>value</key>
+      <value>digital.constellation_qpsk()</value>
     </param>
   </block>
   <block>
     <key>variable</key>
     <param>
-      <key>id</key>
-      <value>occupied_carriers</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>value</key>
-      <value>(range(-26, -21) + range(-20, -7) + range(-6, 0) + range(1, 7) + 
range(8, 21) + range(22, 27),)</value>
+      <key>_coordinate</key>
+      <value>(480, 69)</value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>_rotation</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(329, 64)</value>
+      <key>id</key>
+      <value>pilot_carriers</value>
     </param>
     <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>value</key>
+      <value>((-21, -7, 7, 21,),)</value>
     </param>
   </block>
   <block>
     <key>variable</key>
     <param>
-      <key>id</key>
-      <value>pilot_symbols</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>value</key>
-      <value>((1, 1, 1, -1,),)</value>
+      <key>_coordinate</key>
+      <value>(608, 69)</value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>_rotation</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(601, 64)</value>
+      <key>id</key>
+      <value>pilot_symbols</value>
     </param>
     <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>value</key>
+      <value>((1, 1, 1, -1,),)</value>
     </param>
   </block>
   <block>
     <key>variable</key>
     <param>
-      <key>id</key>
-      <value>sync_word1</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
-      <value>True</value>
+      <value>1</value>
     </param>
     <param>
-      <key>value</key>
-      <value>[0., 0., 0., 0., 0., 0., 0., 1.41421356, 0., -1.41421356, 0., 
1.41421356, 0., -1.41421356, 0., -1.41421356, 0., -1.41421356, 0., 1.41421356, 
0., -1.41421356, 0., 1.41421356, 0., -1.41421356, 0., -1.41421356, 0., 
-1.41421356, 0., -1.41421356, 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 
0., 1.41421356, 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 0., 
1.41421356, 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 0., 1.41421356, 
0., 1.41421356, 0., 0., 0., 0., 0., 0.]</value>
+      <key>_coordinate</key>
+      <value>(898, -1)</value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>_rotation</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(352, 128)</value>
+      <key>id</key>
+      <value>rolloff</value>
     </param>
     <param>
-      <key>_rotation</key>
+      <key>value</key>
       <value>0</value>
     </param>
   </block>
   <block>
-    <key>virtual_source</key>
+    <key>variable</key>
     <param>
-      <key>id</key>
-      <value>virtual_source_0_0</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>stream_id</key>
-      <value>Payload Bits</value>
-    </param>
-    <param>
       <key>_coordinate</key>
-      <value>(0, 458)</value>
+      <value>(255, 0)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>import</key>
     <param>
       <key>id</key>
-      <value>import_0</value>
+      <value>samp_rate</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>value</key>
+      <value>100000</value>
     </param>
+  </block>
+  <block>
+    <key>variable</key>
     <param>
-      <key>import</key>
-      <value>import numpy</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(237, 93)</value>
+      <value>(8, 93)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>import</key>
     <param>
       <key>id</key>
-      <value>import_1</value>
+      <value>sync_word1</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>value</key>
+      <value>[0., 0., 0., 0., 0., 0., 0., 1.41421356, 0., -1.41421356, 0., 
1.41421356, 0., -1.41421356, 0., -1.41421356, 0., -1.41421356, 0., 1.41421356, 
0., -1.41421356, 0., 1.41421356, 0., -1.41421356, 0., -1.41421356, 0., 
-1.41421356, 0., -1.41421356, 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 
0., 1.41421356, 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 0., 
1.41421356, 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 0., 1.41421356, 
0., 1.41421356, 0., 0., 0., 0., 0., 0.]</value>
     </param>
+  </block>
+  <block>
+    <key>variable</key>
     <param>
-      <key>import</key>
-      <value>from gnuradio.digital.utils import tagged_streams</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(99, 93)</value>
+      <value>(152, 93)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>import</key>
     <param>
       <key>id</key>
-      <value>import_0_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <value>sync_word2</value>
     </param>
     <param>
-      <key>import</key>
-      <value>import random</value>
+      <key>value</key>
+      <value>[0, 0, 0, 0, 0, 0, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 
1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 0, 1, -1, 1, 1, 1, -1, 1, 1, 1, 
-1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 0, 0, 0, 0, 0] 
</value>
     </param>
+  </block>
+  <block>
+    <key>analog_random_source_x</key>
     <param>
       <key>alias</key>
       <value></value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(3, 94)</value>
-    </param>
-    <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>comment</key>
+      <value></value>
     </param>
-  </block>
-  <block>
-    <key>virtual_source</key>
     <param>
-      <key>id</key>
-      <value>virtual_source_0_0_0_0</value>
+      <key>affinity</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>stream_id</key>
-      <value>Time Domain</value>
-    </param>
-    <param>
       <key>_coordinate</key>
-      <value>(1, 747)</value>
+      <value>(16, 167)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>virtual_sink</key>
     <param>
       <key>id</key>
-      <value>virtual_sink_0_0_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <value>analog_random_source_x_0</value>
     </param>
     <param>
-      <key>stream_id</key>
-      <value>Pre-OFDM</value>
+      <key>maxoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(745, 441)</value>
+      <key>max</key>
+      <value>255</value>
     </param>
     <param>
-      <key>_rotation</key>
+      <key>minoutbuf</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>digital_chunks_to_symbols_xx</key>
     <param>
-      <key>id</key>
-      <value>digital_chunks_to_symbols_xx_0_0</value>
+      <key>min</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>num_samps</key>
+      <value>1000</value>
     </param>
     <param>
-      <key>in_type</key>
+      <key>type</key>
       <value>byte</value>
     </param>
     <param>
-      <key>out_type</key>
-      <value>complex</value>
-    </param>
-    <param>
-      <key>symbol_table</key>
-      <value>payload_mod.points()</value>
+      <key>repeat</key>
+      <value>True</value>
     </param>
+  </block>
+  <block>
+    <key>blocks_multiply_const_vxx</key>
     <param>
-      <key>dimension</key>
-      <value>1</value>
+      <key>alias</key>
+      <value></value>
     </param>
     <param>
-      <key>num_ports</key>
-      <value>1</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>const</key>
+      <value>0.05</value>
     </param>
     <param>
       <key>affinity</key>
       <value></value>
     </param>
     <param>
-      <key>minoutbuf</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>maxoutbuf</key>
-      <value>0</value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(212, 450)</value>
+      <value>(208, 692)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>virtual_source</key>
     <param>
       <key>id</key>
-      <value>virtual_source_0_0_0</value>
+      <value>blocks_multiply_const_vxx_0</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>type</key>
+      <value>complex</value>
     </param>
     <param>
-      <key>stream_id</key>
-      <value>Pre-OFDM</value>
+      <key>maxoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(0, 578)</value>
+      <key>minoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>vlen</key>
+      <value>1</value>
     </param>
   </block>
   <block>
-    <key>virtual_sink</key>
+    <key>blocks_repack_bits_bb</key>
     <param>
-      <key>id</key>
-      <value>virtual_sink_0</value>
+      <key>k</key>
+      <value>8</value>
+    </param>
+    <param>
+      <key>l</key>
+      <value>payload_mod.bits_per_symbol()</value>
+    </param>
+    <param>
+      <key>alias</key>
+      <value></value>
+    </param>
+    <param>
+      <key>comment</key>
+      <value></value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>stream_id</key>
-      <value>Time Domain</value>
+      <key>endianness</key>
+      <value>gr.GR_LSB_FIRST</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(855, 578)</value>
+      <value>(664, 245)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>fft_vxx</key>
     <param>
       <key>id</key>
-      <value>fft_vxx_0</value>
+      <value>blocks_repack_bits_bb_0</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>len_tag_key</key>
+      <value>length_tag_key</value>
     </param>
     <param>
-      <key>type</key>
-      <value>complex</value>
+      <key>maxoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>fft_size</key>
-      <value>fft_len</value>
+      <key>minoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>forward</key>
+      <key>align_output</key>
       <value>False</value>
     </param>
+  </block>
+  <block>
+    <key>blocks_repack_bits_bb</key>
     <param>
-      <key>window</key>
-      <value>()</value>
-    </param>
-    <param>
-      <key>shift</key>
-      <value>True</value>
+      <key>k</key>
+      <value>8</value>
     </param>
     <param>
-      <key>nthreads</key>
+      <key>l</key>
       <value>1</value>
     </param>
     <param>
@@ -642,300 +616,317 @@
       <value></value>
     </param>
     <param>
+      <key>comment</key>
+      <value></value>
+    </param>
+    <param>
       <key>affinity</key>
       <value></value>
     </param>
     <param>
-      <key>minoutbuf</key>
-      <value>0</value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
-      <key>maxoutbuf</key>
-      <value>0</value>
+      <key>endianness</key>
+      <value>gr.GR_LSB_FIRST</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(414, 548)</value>
+      <value>(896, 157)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>blocks_multiply_const_vxx</key>
     <param>
       <key>id</key>
-      <value>blocks_multiply_const_vxx_0</value>
+      <value>blocks_repack_bits_bb_0_0</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>len_tag_key</key>
+      <value>length_tag_key</value>
     </param>
     <param>
-      <key>type</key>
-      <value>complex</value>
+      <key>maxoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>const</key>
-      <value>0.05</value>
+      <key>minoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>vlen</key>
-      <value>1</value>
+      <key>align_output</key>
+      <value>False</value>
     </param>
+  </block>
+  <block>
+    <key>blocks_stream_to_tagged_stream</key>
     <param>
       <key>alias</key>
       <value></value>
     </param>
     <param>
-      <key>affinity</key>
+      <key>comment</key>
       <value></value>
     </param>
     <param>
-      <key>minoutbuf</key>
-      <value>0</value>
+      <key>affinity</key>
+      <value></value>
     </param>
     <param>
-      <key>maxoutbuf</key>
-      <value>0</value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(209, 747)</value>
+      <value>(192, 181)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>digital_chunks_to_symbols_xx</key>
     <param>
       <key>id</key>
-      <value>digital_chunks_to_symbols_xx_0</value>
+      <value>blocks_stream_to_tagged_stream_0</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>len_tag_key</key>
+      <value>length_tag_key</value>
     </param>
     <param>
-      <key>in_type</key>
-      <value>byte</value>
+      <key>maxoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>out_type</key>
-      <value>complex</value>
+      <key>minoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>symbol_table</key>
-      <value>header_mod.points()</value>
+      <key>packet_len</key>
+      <value>packet_len</value>
     </param>
     <param>
-      <key>dimension</key>
-      <value>1</value>
+      <key>type</key>
+      <value>byte</value>
     </param>
     <param>
-      <key>num_ports</key>
+      <key>vlen</key>
       <value>1</value>
     </param>
+  </block>
+  <block>
+    <key>blocks_tag_debug</key>
     <param>
       <key>alias</key>
       <value></value>
     </param>
     <param>
+      <key>comment</key>
+      <value></value>
+    </param>
+    <param>
       <key>affinity</key>
       <value></value>
     </param>
     <param>
-      <key>minoutbuf</key>
-      <value>0</value>
+      <key>display</key>
+      <value>True</value>
     </param>
     <param>
-      <key>maxoutbuf</key>
-      <value>0</value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(214, 376)</value>
+      <value>(680, 822)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>analog_random_source_x</key>
     <param>
       <key>id</key>
-      <value>analog_random_source_x_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <value>blocks_tag_debug_0</value>
     </param>
     <param>
       <key>type</key>
       <value>byte</value>
     </param>
     <param>
-      <key>min</key>
-      <value>0</value>
+      <key>filter</key>
+      <value>""</value>
     </param>
     <param>
-      <key>max</key>
-      <value>255</value>
+      <key>name</key>
+      <value>Rx'd Packets</value>
     </param>
     <param>
-      <key>num_samps</key>
-      <value>1000</value>
+      <key>num_inputs</key>
+      <value>1</value>
     </param>
     <param>
-      <key>repeat</key>
-      <value>True</value>
+      <key>vlen</key>
+      <value>1</value>
     </param>
+  </block>
+  <block>
+    <key>blocks_tag_gate</key>
     <param>
       <key>alias</key>
       <value></value>
     </param>
     <param>
-      <key>affinity</key>
+      <key>comment</key>
       <value></value>
     </param>
     <param>
-      <key>minoutbuf</key>
-      <value>0</value>
+      <key>affinity</key>
+      <value></value>
     </param>
     <param>
-      <key>maxoutbuf</key>
-      <value>0</value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(13, 220)</value>
+      <value>(376, 692)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>blocks_tagged_stream_mux</key>
     <param>
       <key>id</key>
-      <value>blocks_tagged_stream_mux_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <value>blocks_tag_gate_0</value>
     </param>
     <param>
       <key>type</key>
       <value>complex</value>
     </param>
     <param>
-      <key>ninputs</key>
-      <value>2</value>
+      <key>maxoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>lengthtagname</key>
-      <value>length_tag_key</value>
+      <key>minoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>vlen</key>
-      <value>1</value>
+      <key>propagate_tags</key>
+      <value>False</value>
     </param>
     <param>
-      <key>tag_preserve_head_pos</key>
-      <value>0</value>
+      <key>vlen</key>
+      <value>1</value>
     </param>
+  </block>
+  <block>
+    <key>blocks_tagged_stream_mux</key>
     <param>
       <key>alias</key>
       <value></value>
     </param>
     <param>
-      <key>affinity</key>
+      <key>comment</key>
       <value></value>
     </param>
     <param>
-      <key>minoutbuf</key>
-      <value>0</value>
+      <key>affinity</key>
+      <value></value>
     </param>
     <param>
-      <key>maxoutbuf</key>
-      <value>0</value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(510, 428)</value>
+      <value>(512, 369)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>digital_ofdm_cyclic_prefixer</key>
     <param>
       <key>id</key>
-      <value>digital_ofdm_cyclic_prefixer_0</value>
+      <value>blocks_tagged_stream_mux_0</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>type</key>
+      <value>complex</value>
     </param>
     <param>
-      <key>input_size</key>
-      <value>fft_len</value>
+      <key>lengthtagname</key>
+      <value>length_tag_key</value>
     </param>
     <param>
-      <key>cp_len</key>
-      <value>fft_len/4</value>
+      <key>maxoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>rolloff</key>
-      <value>rolloff</value>
+      <key>minoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>tagname</key>
-      <value>length_tag_key</value>
+      <key>ninputs</key>
+      <value>2</value>
+    </param>
+    <param>
+      <key>tag_preserve_head_pos</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
     </param>
+  </block>
+  <block>
+    <key>blocks_throttle</key>
     <param>
       <key>alias</key>
       <value></value>
     </param>
     <param>
-      <key>affinity</key>
+      <key>comment</key>
       <value></value>
     </param>
     <param>
-      <key>minoutbuf</key>
-      <value>0</value>
+      <key>affinity</key>
+      <value></value>
     </param>
     <param>
-      <key>maxoutbuf</key>
-      <value>0</value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(632, 564)</value>
+      <value>(560, 692)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>blocks_tag_gate</key>
     <param>
       <key>id</key>
-      <value>blocks_tag_gate_0</value>
+      <value>blocks_throttle_0</value>
     </param>
     <param>
-      <key>_enabled</key>
+      <key>ignoretag</key>
       <value>True</value>
     </param>
     <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>samples_per_second</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
       <key>type</key>
       <value>complex</value>
     </param>
@@ -943,12 +934,19 @@
       <key>vlen</key>
       <value>1</value>
     </param>
+  </block>
+  <block>
+    <key>channels_channel_model</key>
     <param>
-      <key>propagate_tags</key>
-      <value>False</value>
+      <key>alias</key>
+      <value></value>
     </param>
     <param>
-      <key>alias</key>
+      <key>block_tags</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>comment</key>
       <value></value>
     </param>
     <param>
@@ -956,292 +954,264 @@
       <value></value>
     </param>
     <param>
-      <key>minoutbuf</key>
-      <value>0</value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
-      <key>maxoutbuf</key>
-      <value>0</value>
+      <key>epsilon</key>
+      <value>1.0</value>
+    </param>
+    <param>
+      <key>freq_offset</key>
+      <value>0.0</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(372, 747)</value>
+      <value>(192, 801)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>blocks_repack_bits_bb</key>
     <param>
       <key>id</key>
-      <value>blocks_repack_bits_bb_0</value>
+      <value>channels_channel_model_0</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>maxoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>k</key>
-      <value>8</value>
+      <key>minoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>l</key>
-      <value>payload_mod.bits_per_symbol()</value>
+      <key>noise_voltage</key>
+      <value>0.0</value>
     </param>
     <param>
-      <key>len_tag_key</key>
-      <value>length_tag_key</value>
+      <key>seed</key>
+      <value>0</value>
     </param>
     <param>
-      <key>align_output</key>
-      <value>False</value>
+      <key>taps</key>
+      <value>1.0 + 1.0j</value>
     </param>
+  </block>
+  <block>
+    <key>digital_chunks_to_symbols_xx</key>
     <param>
       <key>alias</key>
       <value></value>
     </param>
     <param>
+      <key>comment</key>
+      <value></value>
+    </param>
+    <param>
       <key>affinity</key>
       <value></value>
     </param>
     <param>
-      <key>minoutbuf</key>
-      <value>0</value>
+      <key>dimension</key>
+      <value>1</value>
     </param>
     <param>
-      <key>maxoutbuf</key>
-      <value>0</value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(710, 301)</value>
+      <value>(216, 317)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>digital_packet_headergenerator_bb</key>
     <param>
       <key>id</key>
-      <value>digital_packet_headergenerator_bb_0</value>
+      <value>digital_chunks_to_symbols_xx_0</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>in_type</key>
+      <value>byte</value>
     </param>
     <param>
-      <key>header_formatter</key>
-      <value>header_formatter.formatter()</value>
+      <key>maxoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>len_tag_key</key>
-      <value>"packet_len"</value>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>num_ports</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>out_type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>symbol_table</key>
+      <value>header_mod.points()</value>
     </param>
+  </block>
+  <block>
+    <key>digital_chunks_to_symbols_xx</key>
     <param>
       <key>alias</key>
       <value></value>
     </param>
     <param>
+      <key>comment</key>
+      <value></value>
+    </param>
+    <param>
       <key>affinity</key>
       <value></value>
     </param>
     <param>
-      <key>minoutbuf</key>
-      <value>0</value>
+      <key>dimension</key>
+      <value>1</value>
     </param>
     <param>
-      <key>maxoutbuf</key>
-      <value>0</value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(703, 242)</value>
+      <value>(216, 397)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>blocks_stream_to_tagged_stream</key>
     <param>
       <key>id</key>
-      <value>blocks_stream_to_tagged_stream_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <value>digital_chunks_to_symbols_xx_0_0</value>
     </param>
     <param>
-      <key>type</key>
+      <key>in_type</key>
       <value>byte</value>
     </param>
     <param>
-      <key>vlen</key>
-      <value>1</value>
-    </param>
-    <param>
-      <key>packet_len</key>
-      <value>packet_len</value>
-    </param>
-    <param>
-      <key>len_tag_key</key>
-      <value>length_tag_key</value>
-    </param>
-    <param>
-      <key>alias</key>
-      <value></value>
-    </param>
-    <param>
-      <key>affinity</key>
-      <value></value>
+      <key>maxoutbuf</key>
+      <value>0</value>
     </param>
     <param>
       <key>minoutbuf</key>
       <value>0</value>
     </param>
     <param>
-      <key>maxoutbuf</key>
-      <value>0</value>
+      <key>num_ports</key>
+      <value>1</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(193, 235)</value>
+      <key>out_type</key>
+      <value>complex</value>
     </param>
     <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>symbol_table</key>
+      <value>payload_mod.points()</value>
     </param>
   </block>
   <block>
-    <key>virtual_sink</key>
-    <param>
-      <key>id</key>
-      <value>header_bits</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>stream_id</key>
-      <value>Header Bits</value>
-    </param>
+    <key>digital_crc32_bb</key>
     <param>
-      <key>_coordinate</key>
-      <value>(936, 243)</value>
+      <key>alias</key>
+      <value></value>
     </param>
     <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>comment</key>
+      <value></value>
     </param>
-  </block>
-  <block>
-    <key>virtual_sink</key>
     <param>
-      <key>id</key>
-      <value>virtual_sink_0_0</value>
+      <key>affinity</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>stream_id</key>
-      <value>Payload Bits</value>
-    </param>
-    <param>
       <key>_coordinate</key>
-      <value>(934, 324)</value>
+      <value>(432, 182)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>virtual_source</key>
     <param>
       <key>id</key>
-      <value>virtual_source_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>stream_id</key>
-      <value>Header Bits</value>
+      <value>digital_crc32_bb_0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(1, 382)</value>
+      <key>lengthtagname</key>
+      <value>length_tag_key</value>
     </param>
     <param>
-      <key>_rotation</key>
+      <key>maxoutbuf</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>digital_crc32_bb</key>
-    <param>
-      <key>id</key>
-      <value>digital_crc32_bb_0</value>
-    </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>minoutbuf</key>
+      <value>0</value>
     </param>
     <param>
       <key>check</key>
       <value>False</value>
     </param>
     <param>
-      <key>lengthtagname</key>
-      <value>length_tag_key</value>
+      <key>packed</key>
+      <value>True</value>
     </param>
+  </block>
+  <block>
+    <key>digital_ofdm_carrier_allocator_cvc</key>
     <param>
       <key>alias</key>
       <value></value>
     </param>
     <param>
+      <key>comment</key>
+      <value></value>
+    </param>
+    <param>
       <key>affinity</key>
       <value></value>
     </param>
     <param>
-      <key>minoutbuf</key>
-      <value>0</value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
-      <key>maxoutbuf</key>
-      <value>0</value>
+      <key>fft_len</key>
+      <value>fft_len</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(430, 235)</value>
+      <value>(192, 489)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>digital_ofdm_carrier_allocator_cvc</key>
     <param>
       <key>id</key>
       <value>digital_ofdm_carrier_allocator_cvc_0</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>len_tag_key</key>
+      <value>length_tag_key</value>
     </param>
     <param>
-      <key>fft_len</key>
-      <value>fft_len</value>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
     </param>
     <param>
       <key>occupied_carriers</key>
@@ -1259,12 +1229,19 @@
       <key>sync_words</key>
       <value>(sync_word1, sync_word2)</value>
     </param>
+  </block>
+  <block>
+    <key>digital_ofdm_cyclic_prefixer</key>
+    <param>
+      <key>alias</key>
+      <value></value>
+    </param>
     <param>
-      <key>len_tag_key</key>
-      <value>length_tag_key</value>
+      <key>cp_len</key>
+      <value>fft_len/4</value>
     </param>
     <param>
-      <key>alias</key>
+      <key>comment</key>
       <value></value>
     </param>
     <param>
@@ -1272,93 +1249,107 @@
       <value></value>
     </param>
     <param>
-      <key>minoutbuf</key>
-      <value>0</value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
-      <key>maxoutbuf</key>
-      <value>0</value>
+      <key>input_size</key>
+      <value>fft_len</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(192, 540)</value>
+      <value>(632, 503)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>virtual_source</key>
     <param>
       <key>id</key>
-      <value>virtual_source_1</value>
+      <value>digital_ofdm_cyclic_prefixer_0</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>tagname</key>
+      <value>length_tag_key</value>
     </param>
     <param>
-      <key>stream_id</key>
-      <value>Tx Signal</value>
+      <key>maxoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(0, 894)</value>
+      <key>minoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>rolloff</key>
+      <value>rolloff</value>
     </param>
   </block>
   <block>
-    <key>virtual_sink</key>
+    <key>digital_ofdm_rx</key>
     <param>
-      <key>id</key>
-      <value>virtual_sink_1</value>
+      <key>alias</key>
+      <value></value>
+    </param>
+    <param>
+      <key>comment</key>
+      <value></value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>cp_len</key>
+      <value>fft_len/4</value>
     </param>
     <param>
       <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>stream_id</key>
-      <value>Tx Signal</value>
+      <key>fft_len</key>
+      <value>fft_len</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(990, 646)</value>
+      <value>(440, 766)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>digital_ofdm_rx</key>
+    <param>
+      <key>header_mod</key>
+      <value>"BPSK"</value>
+    </param>
     <param>
       <key>id</key>
       <value>digital_ofdm_rx_0</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>log</key>
+      <value>False</value>
     </param>
     <param>
-      <key>fft_len</key>
-      <value>fft_len</value>
+      <key>maxoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>cp_len</key>
-      <value>fft_len/4</value>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>occupied_carriers</key>
+      <value>occupied_carriers</value>
     </param>
     <param>
       <key>packet_len_key</key>
       <value>"length"</value>
     </param>
     <param>
-      <key>occupied_carriers</key>
-      <value>occupied_carriers</value>
+      <key>payload_mod</key>
+      <value>"QPSK"</value>
     </param>
     <param>
       <key>pilot_carriers</key>
@@ -1369,6 +1360,10 @@
       <value>pilot_symbols</value>
     </param>
     <param>
+      <key>scramble_bits</key>
+      <value>False</value>
+    </param>
+    <param>
       <key>sync_word1</key>
       <value>sync_word1</value>
     </param>
@@ -1376,83 +1371,62 @@
       <key>sync_word2</key>
       <value>sync_word2</value>
     </param>
+  </block>
+  <block>
+    <key>digital_protocol_formatter_bb</key>
     <param>
-      <key>header_mod</key>
-      <value>"BPSK"</value>
+      <key>alias</key>
+      <value></value>
     </param>
     <param>
-      <key>payload_mod</key>
-      <value>"QPSK"</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
-      <key>scramble_bits</key>
-      <value>False</value>
+      <key>affinity</key>
+      <value></value>
     </param>
     <param>
-      <key>log</key>
-      <value>False</value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>format</key>
+      <value>hdr_format</value>
     </param>
     <param>
-      <key>affinity</key>
-      <value></value>
-    </param>
-    <param>
-      <key>minoutbuf</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>maxoutbuf</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>_coordinate</key>
-      <value>(439, 823)</value>
+      <key>_coordinate</key>
+      <value>(656, 157)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>channels_channel_model</key>
     <param>
       <key>id</key>
-      <value>channels_channel_model_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
-    </param>
-    <param>
-      <key>noise_voltage</key>
-      <value>0.0</value>
-    </param>
-    <param>
-      <key>freq_offset</key>
-      <value>0.0</value>
+      <value>digital_protocol_formatter_bb_0</value>
     </param>
     <param>
-      <key>epsilon</key>
-      <value>1.0</value>
+      <key>len_tag_key</key>
+      <value>length_tag_key</value>
     </param>
     <param>
-      <key>taps</key>
-      <value>1.0 + 1.0j</value>
+      <key>maxoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>seed</key>
+      <key>minoutbuf</key>
       <value>0</value>
     </param>
+  </block>
+  <block>
+    <key>fft_vxx</key>
     <param>
-      <key>block_tags</key>
-      <value>True</value>
+      <key>alias</key>
+      <value></value>
     </param>
     <param>
-      <key>alias</key>
+      <key>comment</key>
       <value></value>
     </param>
     <param>
@@ -1460,201 +1434,190 @@
       <value></value>
     </param>
     <param>
-      <key>minoutbuf</key>
-      <value>0</value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
-      <key>maxoutbuf</key>
-      <value>0</value>
+      <key>fft_size</key>
+      <value>fft_len</value>
+    </param>
+    <param>
+      <key>forward</key>
+      <value>False</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(193, 858)</value>
+      <value>(416, 496)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>blocks_tag_debug</key>
     <param>
       <key>id</key>
-      <value>blocks_tag_debug_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <value>fft_vxx_0</value>
     </param>
     <param>
       <key>type</key>
-      <value>byte</value>
+      <value>complex</value>
     </param>
     <param>
-      <key>name</key>
-      <value>Rx'd Packets</value>
+      <key>maxoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>filter</key>
-      <value>""</value>
+      <key>minoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>num_inputs</key>
+      <key>nthreads</key>
       <value>1</value>
     </param>
     <param>
-      <key>vlen</key>
-      <value>1</value>
+      <key>shift</key>
+      <value>True</value>
     </param>
     <param>
-      <key>display</key>
-      <value>True</value>
+      <key>window</key>
+      <value>()</value>
     </param>
+  </block>
+  <block>
+    <key>virtual_sink</key>
     <param>
-      <key>alias</key>
+      <key>comment</key>
       <value></value>
     </param>
     <param>
-      <key>affinity</key>
-      <value></value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
       <key>_coordinate</key>
-      <value>(689, 889)</value>
+      <value>(1104, 164)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
-  </block>
-  <block>
-    <key>blocks_throttle</key>
     <param>
       <key>id</key>
-      <value>blocks_throttle_0</value>
-    </param>
-    <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <value>header_bits</value>
     </param>
     <param>
-      <key>type</key>
-      <value>complex</value>
+      <key>stream_id</key>
+      <value>Header Bits</value>
     </param>
+  </block>
+  <block>
+    <key>qtgui_freq_sink_x</key>
     <param>
-      <key>samples_per_second</key>
-      <value>samp_rate</value>
+      <key>autoscale</key>
+      <value>True</value>
     </param>
     <param>
-      <key>vlen</key>
-      <value>1</value>
+      <key>average</key>
+      <value>1.0</value>
     </param>
     <param>
-      <key>ignoretag</key>
+      <key>axislabels</key>
       <value>True</value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>bw</key>
+      <value>samp_rate</value>
     </param>
     <param>
-      <key>affinity</key>
+      <key>alias</key>
       <value></value>
     </param>
     <param>
-      <key>minoutbuf</key>
-      <value>0</value>
-    </param>
-    <param>
-      <key>maxoutbuf</key>
+      <key>fc</key>
       <value>0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(559, 747)</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>ctrlpanel</key>
+      <value>False</value>
     </param>
-  </block>
-  <block>
-    <key>qtgui_freq_sink_x</key>
     <param>
-      <key>id</key>
-      <value>qtgui_freq_sink_x_0</value>
+      <key>affinity</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>type</key>
-      <value>complex</value>
+      <key>fftsize</key>
+      <value>1024</value>
     </param>
     <param>
-      <key>name</key>
-      <value>FFT Plot</value>
+      <key>_coordinate</key>
+      <value>(960, 759)</value>
     </param>
     <param>
-      <key>fftsize</key>
-      <value>1024</value>
+      <key>gui_hint</key>
+      <value></value>
     </param>
     <param>
-      <key>wintype</key>
-      <value>firdes.WIN_BLACKMAN_hARRIS</value>
+      <key>_rotation</key>
+      <value>0</value>
     </param>
     <param>
-      <key>fc</key>
-      <value>0</value>
+      <key>grid</key>
+      <value>False</value>
     </param>
     <param>
-      <key>bw</key>
-      <value>samp_rate</value>
+      <key>id</key>
+      <value>qtgui_freq_sink_x_0</value>
     </param>
     <param>
-      <key>autoscale</key>
+      <key>legend</key>
       <value>True</value>
     </param>
     <param>
-      <key>average</key>
+      <key>alpha1</key>
       <value>1.0</value>
     </param>
     <param>
-      <key>ymin</key>
-      <value>-140</value>
+      <key>color1</key>
+      <value>"blue"</value>
     </param>
     <param>
-      <key>ymax</key>
-      <value>10</value>
+      <key>label1</key>
+      <value></value>
     </param>
     <param>
-      <key>nconnections</key>
+      <key>width1</key>
       <value>1</value>
     </param>
     <param>
-      <key>update_time</key>
-      <value>0.10</value>
+      <key>alpha10</key>
+      <value>1.0</value>
     </param>
     <param>
-      <key>gui_hint</key>
-      <value></value>
+      <key>color10</key>
+      <value>"dark blue"</value>
     </param>
     <param>
-      <key>label1</key>
+      <key>label10</key>
       <value></value>
     </param>
     <param>
-      <key>width1</key>
+      <key>width10</key>
       <value>1</value>
     </param>
     <param>
-      <key>color1</key>
-      <value>"blue"</value>
+      <key>alpha2</key>
+      <value>1.0</value>
     </param>
     <param>
-      <key>alpha1</key>
-      <value>1.0</value>
+      <key>color2</key>
+      <value>"red"</value>
     </param>
     <param>
       <key>label2</key>
@@ -1665,12 +1628,12 @@
       <value>1</value>
     </param>
     <param>
-      <key>color2</key>
-      <value>"red"</value>
+      <key>alpha3</key>
+      <value>1.0</value>
     </param>
     <param>
-      <key>alpha2</key>
-      <value>1.0</value>
+      <key>color3</key>
+      <value>"green"</value>
     </param>
     <param>
       <key>label3</key>
@@ -1681,12 +1644,12 @@
       <value>1</value>
     </param>
     <param>
-      <key>color3</key>
-      <value>"green"</value>
+      <key>alpha4</key>
+      <value>1.0</value>
     </param>
     <param>
-      <key>alpha3</key>
-      <value>1.0</value>
+      <key>color4</key>
+      <value>"black"</value>
     </param>
     <param>
       <key>label4</key>
@@ -1697,12 +1660,12 @@
       <value>1</value>
     </param>
     <param>
-      <key>color4</key>
-      <value>"black"</value>
+      <key>alpha5</key>
+      <value>1.0</value>
     </param>
     <param>
-      <key>alpha4</key>
-      <value>1.0</value>
+      <key>color5</key>
+      <value>"cyan"</value>
     </param>
     <param>
       <key>label5</key>
@@ -1713,12 +1676,12 @@
       <value>1</value>
     </param>
     <param>
-      <key>color5</key>
-      <value>"cyan"</value>
+      <key>alpha6</key>
+      <value>1.0</value>
     </param>
     <param>
-      <key>alpha5</key>
-      <value>1.0</value>
+      <key>color6</key>
+      <value>"magenta"</value>
     </param>
     <param>
       <key>label6</key>
@@ -1729,12 +1692,12 @@
       <value>1</value>
     </param>
     <param>
-      <key>color6</key>
-      <value>"magenta"</value>
+      <key>alpha7</key>
+      <value>1.0</value>
     </param>
     <param>
-      <key>alpha6</key>
-      <value>1.0</value>
+      <key>color7</key>
+      <value>"yellow"</value>
     </param>
     <param>
       <key>label7</key>
@@ -1745,12 +1708,12 @@
       <value>1</value>
     </param>
     <param>
-      <key>color7</key>
-      <value>"yellow"</value>
+      <key>alpha8</key>
+      <value>1.0</value>
     </param>
     <param>
-      <key>alpha7</key>
-      <value>1.0</value>
+      <key>color8</key>
+      <value>"dark red"</value>
     </param>
     <param>
       <key>label8</key>
@@ -1761,12 +1724,12 @@
       <value>1</value>
     </param>
     <param>
-      <key>color8</key>
-      <value>"dark red"</value>
+      <key>alpha9</key>
+      <value>1.0</value>
     </param>
     <param>
-      <key>alpha8</key>
-      <value>1.0</value>
+      <key>color9</key>
+      <value>"dark green"</value>
     </param>
     <param>
       <key>label9</key>
@@ -1777,507 +1740,743 @@
       <value>1</value>
     </param>
     <param>
-      <key>color9</key>
-      <value>"dark green"</value>
+      <key>maxoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>alpha9</key>
-      <value>1.0</value>
+      <key>minoutbuf</key>
+      <value>0</value>
     </param>
     <param>
-      <key>label10</key>
-      <value></value>
+      <key>name</key>
+      <value>FFT Plot</value>
     </param>
     <param>
-      <key>width10</key>
+      <key>nconnections</key>
       <value>1</value>
     </param>
     <param>
-      <key>color10</key>
-      <value>"dark blue"</value>
+      <key>showports</key>
+      <value>True</value>
     </param>
     <param>
-      <key>alpha10</key>
-      <value>1.0</value>
+      <key>freqhalf</key>
+      <value>True</value>
     </param>
     <param>
-      <key>alias</key>
-      <value></value>
+      <key>tr_chan</key>
+      <value>0</value>
     </param>
     <param>
-      <key>affinity</key>
-      <value></value>
+      <key>tr_level</key>
+      <value>0.0</value>
     </param>
     <param>
-      <key>_coordinate</key>
-      <value>(966, 841)</value>
+      <key>tr_mode</key>
+      <value>qtgui.TRIG_MODE_FREE</value>
     </param>
     <param>
-      <key>_rotation</key>
-      <value>0</value>
+      <key>tr_tag</key>
+      <value>""</value>
     </param>
-  </block>
-  <block>
-    <key>qtgui_time_sink_x</key>
     <param>
-      <key>id</key>
-      <value>qtgui_time_sink_x_0</value>
+      <key>type</key>
+      <value>complex</value>
     </param>
     <param>
-      <key>_enabled</key>
-      <value>True</value>
+      <key>update_time</key>
+      <value>0.10</value>
     </param>
     <param>
-      <key>type</key>
-      <value>complex</value>
+      <key>wintype</key>
+      <value>firdes.WIN_BLACKMAN_hARRIS</value>
     </param>
     <param>
-      <key>name</key>
-      <value>Scope Plot</value>
+      <key>label</key>
+      <value>Relative Gain</value>
     </param>
     <param>
-      <key>size</key>
-      <value>1024</value>
+      <key>ymax</key>
+      <value>10</value>
     </param>
     <param>
-      <key>srate</key>
-      <value>samp_rate</value>
+      <key>ymin</key>
+      <value>-140</value>
+    </param>
+    <param>
+      <key>units</key>
+      <value>dB</value>
     </param>
+  </block>
+  <block>
+    <key>qtgui_time_sink_x</key>
     <param>
       <key>autoscale</key>
       <value>True</value>
     </param>
     <param>
-      <key>ymin</key>
-      <value>-1</value>
+      <key>axislabels</key>
+      <value>True</value>
     </param>
     <param>
-      <key>ymax</key>
-      <value>1</value>
+      <key>alias</key>
+      <value></value>
     </param>
     <param>
-      <key>nconnections</key>
-      <value>1</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
-      <key>update_time</key>
-      <value>0.10</value>
+      <key>ctrlpanel</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
     </param>
     <param>
       <key>entags</key>
       <value>True</value>
     </param>
     <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(960, 671)</value>
+    </param>
+    <param>
       <key>gui_hint</key>
       <value></value>
     </param>
     <param>
-      <key>tr_mode</key>
-      <value>qtgui.TRIG_MODE_FREE</value>
+      <key>_rotation</key>
+      <value>0</value>
     </param>
     <param>
-      <key>tr_slope</key>
-      <value>qtgui.TRIG_SLOPE_POS</value>
+      <key>grid</key>
+      <value>False</value>
     </param>
     <param>
-      <key>tr_level</key>
-      <value>0.0</value>
+      <key>id</key>
+      <value>qtgui_time_sink_x_0</value>
     </param>
     <param>
-      <key>tr_delay</key>
-      <value>0</value>
+      <key>legend</key>
+      <value>True</value>
     </param>
     <param>
-      <key>tr_chan</key>
-      <value>0</value>
+      <key>alpha1</key>
+      <value>1.0</value>
     </param>
     <param>
-      <key>tr_tag</key>
-      <value>""</value>
+      <key>color1</key>
+      <value>"blue"</value>
     </param>
     <param>
       <key>label1</key>
       <value>Scope Plot</value>
     </param>
     <param>
+      <key>marker1</key>
+      <value>-1</value>
+    </param>
+    <param>
+      <key>style1</key>
+      <value>1</value>
+    </param>
+    <param>
       <key>width1</key>
       <value>1</value>
     </param>
     <param>
-      <key>color1</key>
+      <key>alpha10</key>
+      <value>1.0</value>
+    </param>
+    <param>
+      <key>color10</key>
       <value>"blue"</value>
     </param>
     <param>
-      <key>style1</key>
-      <value>1</value>
+      <key>label10</key>
+      <value></value>
     </param>
     <param>
-      <key>marker1</key>
+      <key>marker10</key>
       <value>-1</value>
     </param>
     <param>
-      <key>alpha1</key>
-      <value>1.0</value>
+      <key>style10</key>
+      <value>1</value>
     </param>
     <param>
-      <key>label2</key>
-      <value></value>
+      <key>width10</key>
+      <value>1</value>
     </param>
     <param>
-      <key>width2</key>
-      <value>1</value>
+      <key>alpha2</key>
+      <value>1.0</value>
     </param>
     <param>
       <key>color2</key>
       <value>"red"</value>
     </param>
     <param>
-      <key>style2</key>
-      <value>1</value>
+      <key>label2</key>
+      <value></value>
     </param>
     <param>
       <key>marker2</key>
       <value>-1</value>
     </param>
     <param>
-      <key>alpha2</key>
-      <value>1.0</value>
+      <key>style2</key>
+      <value>1</value>
     </param>
     <param>
-      <key>label3</key>
-      <value></value>
+      <key>width2</key>
+      <value>1</value>
     </param>
     <param>
-      <key>width3</key>
-      <value>1</value>
+      <key>alpha3</key>
+      <value>1.0</value>
     </param>
     <param>
       <key>color3</key>
       <value>"green"</value>
     </param>
     <param>
-      <key>style3</key>
-      <value>1</value>
+      <key>label3</key>
+      <value></value>
     </param>
     <param>
       <key>marker3</key>
       <value>-1</value>
     </param>
     <param>
-      <key>alpha3</key>
-      <value>1.0</value>
+      <key>style3</key>
+      <value>1</value>
     </param>
     <param>
-      <key>label4</key>
-      <value></value>
+      <key>width3</key>
+      <value>1</value>
     </param>
     <param>
-      <key>width4</key>
-      <value>1</value>
+      <key>alpha4</key>
+      <value>1.0</value>
     </param>
     <param>
       <key>color4</key>
       <value>"black"</value>
     </param>
     <param>
-      <key>style4</key>
-      <value>1</value>
+      <key>label4</key>
+      <value></value>
     </param>
     <param>
       <key>marker4</key>
       <value>-1</value>
     </param>
     <param>
-      <key>alpha4</key>
-      <value>1.0</value>
+      <key>style4</key>
+      <value>1</value>
     </param>
     <param>
-      <key>label5</key>
-      <value></value>
+      <key>width4</key>
+      <value>1</value>
     </param>
     <param>
-      <key>width5</key>
-      <value>1</value>
+      <key>alpha5</key>
+      <value>1.0</value>
     </param>
     <param>
       <key>color5</key>
       <value>"cyan"</value>
     </param>
     <param>
-      <key>style5</key>
-      <value>1</value>
+      <key>label5</key>
+      <value></value>
     </param>
     <param>
       <key>marker5</key>
       <value>-1</value>
     </param>
     <param>
-      <key>alpha5</key>
-      <value>1.0</value>
+      <key>style5</key>
+      <value>1</value>
     </param>
     <param>
-      <key>label6</key>
-      <value></value>
+      <key>width5</key>
+      <value>1</value>
     </param>
     <param>
-      <key>width6</key>
-      <value>1</value>
+      <key>alpha6</key>
+      <value>1.0</value>
     </param>
     <param>
       <key>color6</key>
       <value>"magenta"</value>
     </param>
     <param>
-      <key>style6</key>
-      <value>1</value>
+      <key>label6</key>
+      <value></value>
     </param>
     <param>
       <key>marker6</key>
       <value>-1</value>
     </param>
     <param>
-      <key>alpha6</key>
-      <value>1.0</value>
+      <key>style6</key>
+      <value>1</value>
     </param>
     <param>
-      <key>label7</key>
-      <value></value>
+      <key>width6</key>
+      <value>1</value>
     </param>
     <param>
-      <key>width7</key>
-      <value>1</value>
+      <key>alpha7</key>
+      <value>1.0</value>
     </param>
     <param>
       <key>color7</key>
       <value>"yellow"</value>
     </param>
     <param>
-      <key>style7</key>
-      <value>1</value>
+      <key>label7</key>
+      <value></value>
     </param>
     <param>
       <key>marker7</key>
       <value>-1</value>
     </param>
     <param>
-      <key>alpha7</key>
-      <value>1.0</value>
+      <key>style7</key>
+      <value>1</value>
     </param>
     <param>
-      <key>label8</key>
-      <value></value>
+      <key>width7</key>
+      <value>1</value>
     </param>
     <param>
-      <key>width8</key>
-      <value>1</value>
+      <key>alpha8</key>
+      <value>1.0</value>
     </param>
     <param>
       <key>color8</key>
       <value>"dark red"</value>
     </param>
     <param>
-      <key>style8</key>
-      <value>1</value>
+      <key>label8</key>
+      <value></value>
     </param>
     <param>
       <key>marker8</key>
       <value>-1</value>
     </param>
     <param>
-      <key>alpha8</key>
-      <value>1.0</value>
+      <key>style8</key>
+      <value>1</value>
     </param>
     <param>
-      <key>label9</key>
-      <value></value>
+      <key>width8</key>
+      <value>1</value>
     </param>
     <param>
-      <key>width9</key>
-      <value>1</value>
+      <key>alpha9</key>
+      <value>1.0</value>
     </param>
     <param>
       <key>color9</key>
       <value>"dark green"</value>
     </param>
     <param>
-      <key>style9</key>
-      <value>1</value>
-    </param>
+      <key>label9</key>
+      <value></value>
+    </param>
     <param>
       <key>marker9</key>
       <value>-1</value>
     </param>
     <param>
-      <key>alpha9</key>
-      <value>1.0</value>
+      <key>style9</key>
+      <value>1</value>
     </param>
     <param>
-      <key>label10</key>
-      <value></value>
+      <key>width9</key>
+      <value>1</value>
     </param>
     <param>
-      <key>width10</key>
+      <key>name</key>
+      <value>Scope Plot</value>
+    </param>
+    <param>
+      <key>nconnections</key>
       <value>1</value>
     </param>
     <param>
-      <key>color10</key>
-      <value>"blue"</value>
+      <key>size</key>
+      <value>1024</value>
     </param>
     <param>
-      <key>style10</key>
+      <key>srate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>tr_chan</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>tr_delay</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>tr_level</key>
+      <value>0.0</value>
+    </param>
+    <param>
+      <key>tr_mode</key>
+      <value>qtgui.TRIG_MODE_FREE</value>
+    </param>
+    <param>
+      <key>tr_slope</key>
+      <value>qtgui.TRIG_SLOPE_POS</value>
+    </param>
+    <param>
+      <key>tr_tag</key>
+      <value>""</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>update_time</key>
+      <value>0.10</value>
+    </param>
+    <param>
+      <key>ylabel</key>
+      <value>Amplitude</value>
+    </param>
+    <param>
+      <key>yunit</key>
+      <value>""</value>
+    </param>
+    <param>
+      <key>ymax</key>
       <value>1</value>
     </param>
     <param>
-      <key>marker10</key>
+      <key>ymin</key>
       <value>-1</value>
     </param>
+  </block>
+  <block>
+    <key>virtual_sink</key>
     <param>
-      <key>alpha10</key>
-      <value>1.0</value>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
-      <key>alias</key>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(856, 524)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>id</key>
+      <value>virtual_sink_0</value>
+    </param>
+    <param>
+      <key>stream_id</key>
+      <value>Time Domain</value>
+    </param>
+  </block>
+  <block>
+    <key>virtual_sink</key>
+    <param>
+      <key>comment</key>
       <value></value>
     </param>
     <param>
-      <key>affinity</key>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(856, 252)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>id</key>
+      <value>virtual_sink_0_0</value>
+    </param>
+    <param>
+      <key>stream_id</key>
+      <value>Payload Bits</value>
+    </param>
+  </block>
+  <block>
+    <key>virtual_sink</key>
+    <param>
+      <key>comment</key>
       <value></value>
     </param>
     <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
       <key>_coordinate</key>
-      <value>(962, 714)</value>
+      <value>(744, 388)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
+    <param>
+      <key>id</key>
+      <value>virtual_sink_0_0_0</value>
+    </param>
+    <param>
+      <key>stream_id</key>
+      <value>Pre-OFDM</value>
+    </param>
   </block>
   <block>
-    <key>options</key>
+    <key>virtual_sink</key>
+    <param>
+      <key>comment</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(960, 620)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
     <param>
       <key>id</key>
-      <value>tx_ofdm</value>
+      <value>virtual_sink_1</value>
+    </param>
+    <param>
+      <key>stream_id</key>
+      <value>Tx Signal</value>
+    </param>
+  </block>
+  <block>
+    <key>virtual_source</key>
+    <param>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
       <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>title</key>
-      <value>OFDM Tx</value>
+      <key>_coordinate</key>
+      <value>(0, 324)</value>
     </param>
     <param>
-      <key>author</key>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>id</key>
+      <value>virtual_source_0</value>
+    </param>
+    <param>
+      <key>stream_id</key>
+      <value>Header Bits</value>
+    </param>
+  </block>
+  <block>
+    <key>virtual_source</key>
+    <param>
+      <key>comment</key>
       <value></value>
     </param>
     <param>
-      <key>description</key>
-      <value>Example of an OFDM Transmitter</value>
+      <key>_enabled</key>
+      <value>True</value>
     </param>
     <param>
-      <key>window_size</key>
-      <value>1280, 1024</value>
+      <key>_coordinate</key>
+      <value>(0, 404)</value>
     </param>
     <param>
-      <key>generate_options</key>
-      <value>qt_gui</value>
+      <key>_rotation</key>
+      <value>0</value>
     </param>
     <param>
-      <key>category</key>
-      <value>Custom</value>
+      <key>id</key>
+      <value>virtual_source_0_0</value>
     </param>
     <param>
-      <key>run_options</key>
-      <value>run</value>
+      <key>stream_id</key>
+      <value>Payload Bits</value>
+    </param>
+  </block>
+  <block>
+    <key>virtual_source</key>
+    <param>
+      <key>comment</key>
+      <value></value>
     </param>
     <param>
-      <key>run</key>
+      <key>_enabled</key>
       <value>True</value>
     </param>
     <param>
-      <key>max_nouts</key>
+      <key>_coordinate</key>
+      <value>(0, 524)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
       <value>0</value>
     </param>
     <param>
-      <key>realtime_scheduling</key>
+      <key>id</key>
+      <value>virtual_source_0_0_0</value>
+    </param>
+    <param>
+      <key>stream_id</key>
+      <value>Pre-OFDM</value>
+    </param>
+  </block>
+  <block>
+    <key>virtual_source</key>
+    <param>
+      <key>comment</key>
       <value></value>
     </param>
     <param>
-      <key>alias</key>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(0, 692)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>id</key>
+      <value>virtual_source_0_0_0_0</value>
+    </param>
+    <param>
+      <key>stream_id</key>
+      <value>Time Domain</value>
+    </param>
+  </block>
+  <block>
+    <key>virtual_source</key>
+    <param>
+      <key>comment</key>
       <value></value>
     </param>
     <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
       <key>_coordinate</key>
-      <value>(1, 0)</value>
+      <value>(0, 836)</value>
     </param>
     <param>
       <key>_rotation</key>
       <value>0</value>
     </param>
+    <param>
+      <key>id</key>
+      <value>virtual_source_1</value>
+    </param>
+    <param>
+      <key>stream_id</key>
+      <value>Tx Signal</value>
+    </param>
   </block>
   <connection>
-    <source_block_id>blocks_tagged_stream_mux_0</source_block_id>
-    <sink_block_id>virtual_sink_0_0_0</sink_block_id>
+    <source_block_id>analog_random_source_x_0</source_block_id>
+    <sink_block_id>blocks_stream_to_tagged_stream_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>virtual_source_0_0</source_block_id>
-    <sink_block_id>digital_chunks_to_symbols_xx_0_0</sink_block_id>
+    <source_block_id>blocks_multiply_const_vxx_0</source_block_id>
+    <sink_block_id>blocks_tag_gate_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>virtual_source_0</source_block_id>
-    <sink_block_id>digital_chunks_to_symbols_xx_0</sink_block_id>
+    <source_block_id>blocks_repack_bits_bb_0</source_block_id>
+    <sink_block_id>virtual_sink_0_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>digital_chunks_to_symbols_xx_0_0</source_block_id>
-    <sink_block_id>blocks_tagged_stream_mux_0</sink_block_id>
+    <source_block_id>blocks_repack_bits_bb_0_0</source_block_id>
+    <sink_block_id>header_bits</sink_block_id>
     <source_key>0</source_key>
-    <sink_key>1</sink_key>
+    <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>virtual_source_0_0_0_0</source_block_id>
-    <sink_block_id>blocks_multiply_const_vxx_0</sink_block_id>
+    <source_block_id>blocks_stream_to_tagged_stream_0</source_block_id>
+    <sink_block_id>digital_crc32_bb_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>virtual_source_0_0_0</source_block_id>
-    <sink_block_id>digital_ofdm_carrier_allocator_cvc_0</sink_block_id>
+    <source_block_id>blocks_tag_gate_0</source_block_id>
+    <sink_block_id>blocks_throttle_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>digital_ofdm_carrier_allocator_cvc_0</source_block_id>
-    <sink_block_id>fft_vxx_0</sink_block_id>
+    <source_block_id>blocks_tagged_stream_mux_0</source_block_id>
+    <sink_block_id>virtual_sink_0_0_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>fft_vxx_0</source_block_id>
-    <sink_block_id>digital_ofdm_cyclic_prefixer_0</sink_block_id>
+    <source_block_id>blocks_throttle_0</source_block_id>
+    <sink_block_id>qtgui_freq_sink_x_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>digital_ofdm_cyclic_prefixer_0</source_block_id>
-    <sink_block_id>virtual_sink_0</sink_block_id>
+    <source_block_id>blocks_throttle_0</source_block_id>
+    <sink_block_id>qtgui_time_sink_x_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>blocks_multiply_const_vxx_0</source_block_id>
-    <sink_block_id>blocks_tag_gate_0</sink_block_id>
+    <source_block_id>blocks_throttle_0</source_block_id>
+    <sink_block_id>virtual_sink_1</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>blocks_tag_gate_0</source_block_id>
-    <sink_block_id>blocks_throttle_0</sink_block_id>
+    <source_block_id>channels_channel_model_0</source_block_id>
+    <sink_block_id>digital_ofdm_rx_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
@@ -2288,74 +2487,80 @@
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>analog_random_source_x_0</source_block_id>
-    <sink_block_id>blocks_stream_to_tagged_stream_0</sink_block_id>
+    <source_block_id>digital_chunks_to_symbols_xx_0_0</source_block_id>
+    <sink_block_id>blocks_tagged_stream_mux_0</sink_block_id>
     <source_key>0</source_key>
-    <sink_key>0</sink_key>
+    <sink_key>1</sink_key>
   </connection>
   <connection>
-    <source_block_id>blocks_stream_to_tagged_stream_0</source_block_id>
-    <sink_block_id>digital_crc32_bb_0</sink_block_id>
+    <source_block_id>digital_crc32_bb_0</source_block_id>
+    <sink_block_id>blocks_repack_bits_bb_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
     <source_block_id>digital_crc32_bb_0</source_block_id>
-    <sink_block_id>digital_packet_headergenerator_bb_0</sink_block_id>
+    <sink_block_id>digital_protocol_formatter_bb_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>digital_crc32_bb_0</source_block_id>
-    <sink_block_id>blocks_repack_bits_bb_0</sink_block_id>
+    <source_block_id>digital_ofdm_carrier_allocator_cvc_0</source_block_id>
+    <sink_block_id>fft_vxx_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>digital_packet_headergenerator_bb_0</source_block_id>
-    <sink_block_id>header_bits</sink_block_id>
+    <source_block_id>digital_ofdm_cyclic_prefixer_0</source_block_id>
+    <sink_block_id>virtual_sink_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>blocks_repack_bits_bb_0</source_block_id>
-    <sink_block_id>virtual_sink_0_0</sink_block_id>
+    <source_block_id>digital_ofdm_rx_0</source_block_id>
+    <sink_block_id>blocks_tag_debug_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>blocks_throttle_0</source_block_id>
-    <sink_block_id>virtual_sink_1</sink_block_id>
+    <source_block_id>digital_protocol_formatter_bb_0</source_block_id>
+    <sink_block_id>blocks_repack_bits_bb_0_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>virtual_source_1</source_block_id>
-    <sink_block_id>channels_channel_model_0</sink_block_id>
+    <source_block_id>fft_vxx_0</source_block_id>
+    <sink_block_id>digital_ofdm_cyclic_prefixer_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>channels_channel_model_0</source_block_id>
-    <sink_block_id>digital_ofdm_rx_0</sink_block_id>
+    <source_block_id>virtual_source_0</source_block_id>
+    <sink_block_id>digital_chunks_to_symbols_xx_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>digital_ofdm_rx_0</source_block_id>
-    <sink_block_id>blocks_tag_debug_0</sink_block_id>
+    <source_block_id>virtual_source_0_0</source_block_id>
+    <sink_block_id>digital_chunks_to_symbols_xx_0_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>blocks_throttle_0</source_block_id>
-    <sink_block_id>qtgui_freq_sink_x_0</sink_block_id>
+    <source_block_id>virtual_source_0_0_0</source_block_id>
+    <sink_block_id>digital_ofdm_carrier_allocator_cvc_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
   <connection>
-    <source_block_id>blocks_throttle_0</source_block_id>
-    <sink_block_id>qtgui_time_sink_x_0</sink_block_id>
+    <source_block_id>virtual_source_0_0_0_0</source_block_id>
+    <sink_block_id>blocks_multiply_const_vxx_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>virtual_source_1</source_block_id>
+    <sink_block_id>channels_channel_model_0</sink_block_id>
     <source_key>0</source_key>
     <sink_key>0</sink_key>
   </connection>
diff --git a/gr-digital/grc/digital_block_tree.xml 
b/gr-digital/grc/digital_block_tree.xml
index 9bdf6e9..5e6e742 100644
--- a/gr-digital/grc/digital_block_tree.xml
+++ b/gr-digital/grc/digital_block_tree.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <!--
- Copyright 2011-2015 Free Software Foundation, Inc.
+ Copyright 2011-2016 Free Software Foundation, Inc.
 
  This file is part of GNU Radio
 
@@ -72,6 +72,10 @@
     <block>digital_crc32_bb</block>
     <block>digital_crc32_async_bb</block>
     <block>digital_framer_sink_1</block>
+    <block>variable_header_format_default</block>
+    <block>digital_protocol_formatter_async</block>
+    <block>digital_protocol_formatter_bb</block>
+    <block>digital_protocol_parser_b</block>
     <block>digital_header_payload_demux</block>
     <block>digital_packet_headergenerator_bb</block>
     <block>digital_packet_headergenerator_bb_default</block>
diff --git a/gr-digital/grc/digital_protocol_formatter_async.xml 
b/gr-digital/grc/digital_protocol_formatter_async.xml
new file mode 100644
index 0000000..52a67ec
--- /dev/null
+++ b/gr-digital/grc/digital_protocol_formatter_async.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+
+<block>
+  <name>Protocol Formatter (Async)</name>
+  <key>digital_protocol_formatter_async</key>
+  <import>from gnuradio import digital</import>
+  <make>digital.protocol_formatter_async($format)</make>
+
+  <param>
+    <name>Format Obj.</name>
+    <key>format</key>
+    <type>raw</type>
+  </param>
+
+  <sink>
+    <name>in</name>
+    <type>message</type>
+    <optional>1</optional>
+  </sink>
+
+  <source>
+    <name>header</name>
+    <type>message</type>
+    <optional>1</optional>
+  </source>
+
+  <source>
+    <name>payload</name>
+    <type>message</type>
+    <optional>1</optional>
+  </source>
+
+</block>
diff --git a/gr-digital/grc/digital_protocol_formatter_bb.xml 
b/gr-digital/grc/digital_protocol_formatter_bb.xml
new file mode 100644
index 0000000..b37a791
--- /dev/null
+++ b/gr-digital/grc/digital_protocol_formatter_bb.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+
+<block>
+  <name>Protocol Formatter</name>
+  <key>digital_protocol_formatter_bb</key>
+  <import>from gnuradio import digital</import>
+  <make>digital.protocol_formatter_bb($format, $len_tag_key)</make>
+
+  <param>
+    <name>Format Obj.</name>
+    <key>format</key>
+    <type>raw</type>
+  </param>
+
+  <param>
+    <name>Length Tag Name</name>
+    <key>len_tag_key</key>
+    <value>"packet_len"</value>
+    <type>string</type>
+  </param>
+
+  <sink>
+    <name>in</name>
+    <type>byte</type>
+  </sink>
+
+  <source>
+    <name>out</name>
+    <type>byte</type>
+  </source>
+
+</block>
diff --git a/gr-digital/grc/digital_protocol_parser_b.xml 
b/gr-digital/grc/digital_protocol_parser_b.xml
new file mode 100644
index 0000000..27fb15e
--- /dev/null
+++ b/gr-digital/grc/digital_protocol_parser_b.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+
+<block>
+  <name>Protocol Parser</name>
+  <key>digital_protocol_parser_b</key>
+  <import>from gnuradio import digital</import>
+  <make>digital.protocol_parser_b($format)</make>
+
+  <param>
+    <name>Format Obj.</name>
+    <key>format</key>
+    <type>raw</type>
+  </param>
+
+  <sink>
+    <name>in</name>
+    <type>byte</type>
+  </sink>
+
+  <source>
+    <name>info</name>
+    <type>message</type>
+    <optional>1</optional>
+  </source>
+</block>
diff --git a/gr-digital/grc/variable_header_format_default.xml 
b/gr-digital/grc/variable_header_format_default.xml
new file mode 100644
index 0000000..55b361f
--- /dev/null
+++ b/gr-digital/grc/variable_header_format_default.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+# header_format_default object
+###################################################
+ -->
+<block>
+  <name>Default Header Format Obj.</name>
+  <key>variable_header_format_default</key>
+  <import>from gnuradio import digital</import>
+  <var_make>
+#if int($access_code())==0 #
+self.$(id) = $(id) = 
digital.header_format_default(digital.packet_utils.default_access_code, 
$threshold)
+#else
+self.$(id) = $(id) = digital.header_format_default($access_code, $threshold)
+#end if
+  </var_make>
+  <var_value>digital.header_format_default($access_code, 
$threshold)</var_value>
+  <make></make>
+
+  <param>
+    <name>Access Code</name>
+    <key>access_code</key>
+    <value>0</value>
+    <type>string</type>
+  </param>
+
+  <param>
+    <name>Threshold</name>
+    <key>threshold</key>
+    <value>0</value>
+    <type>int</type>
+  </param>
+
+</block>
diff --git a/gr-digital/include/gnuradio/digital/CMakeLists.txt 
b/gr-digital/include/gnuradio/digital/CMakeLists.txt
index d8fe2b6..1b22265 100644
--- a/gr-digital/include/gnuradio/digital/CMakeLists.txt
+++ b/gr-digital/include/gnuradio/digital/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2011-2015 Free Software Foundation, Inc.
+# Copyright 2011-2016 Free Software Foundation, Inc.
 #
 # This file is part of GNU Radio
 #
@@ -65,6 +65,7 @@ install(FILES
     glfsr_source_f.h
     hdlc_deframer_bp.h
     hdlc_framer_pb.h
+    header_buffer.h
     header_payload_demux.h
     kurtotic_equalizer_cc.h
     lfsr.h
@@ -90,6 +91,14 @@ install(FILES
     ofdm_sampler.h
     ofdm_serializer_vcc.h
     ofdm_sync_sc_cfb.h
+    header_format_base.h
+    header_format_default.h
+    header_format_counter.h
+    header_format_crc.h
+    header_format_ofdm.h
+    protocol_formatter_async.h
+    protocol_formatter_bb.h
+    protocol_parser_b.h
     packet_header_default.h
     packet_header_ofdm.h
     packet_headergenerator_bb.h
diff --git a/gr-digital/include/gnuradio/digital/header_buffer.h 
b/gr-digital/include/gnuradio/digital/header_buffer.h
new file mode 100644
index 0000000..ddcc2a8
--- /dev/null
+++ b/gr-digital/include/gnuradio/digital/header_buffer.h
@@ -0,0 +1,310 @@
+/* -*- c++ -*- */
+/* Copyright 2015-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_BUFFER_H
+#define INCLUDED_DIGITAL_HEADER_BUFFER_H
+
+#include <gnuradio/digital/api.h>
+#include <vector>
+#include <stdint.h>
+
+namespace gr {
+  namespace digital {
+
+    /*!
+     * \brief Helper class for handling payload headers.
+     * \ingroup packet_operators_blk
+     *
+     * \details
+     *
+     * This class is used by the header format blocks (e.g.,
+     * digital::header_format_default) to make it easier to deal with
+     * payload headers. This class functions in two different ways
+     * depending on if it is used in a transmitter or receiver. When
+     * used in a transmitter, this class helps us build headers out of
+     * the fields of the protocol. When used in a receiver, this class
+     * helps us parse the received bits into the protocol's fields.
+     *
+     * This page describes how to work with the different modes,
+     * transmit or receive. The class is instructed as to which mode
+     * it is in by how the constructor is called. If the constructor
+     * is passed a valid array (non NULL), then it is in transmit mode
+     * and will pack this buffer with the header fields. If that
+     * buffer is NULL, the object is in receive mode.
+     *
+     * \section header_buffer_tx Transmit Mode
+     *
+     * When passed a valid buffer in the constructor, this object is in
+     * transmit mode. We can then use the add_field[N] functions to
+     * add new fields to this header. The buffer MUST be large enough
+     * to hold the full header. As this class is meant to work mostly
+     * with the digital::header_format_default and child
+     * classes, the header length can be read from
+     * digital::header_format_default::header_nbytes().
+     *
+     * Each field is a specific length of 8, 16, 32, or 64 bits that
+     * are to be transmitted in network byte order. We can adjust the
+     * direction of the bytes by setting the byte-swap flag, \p bs, to
+     * true or false.
+     *
+     * The length argument (\p len) for all add_field[N] calls is the
+     * number of bytes actually accounted for in the data
+     * structure. Often, we would use the full size of the field,
+     * which is sizeof(dtype), and the add_field[N] call defaults to
+     * len=N. Occasionally, we may need to use fewer bytes than
+     * actually represented by the data type. An example would be the
+     * access code used in the header_format_default, which is a
+     * uint64_t type but may have fewer bytes used in the actual
+     * access code.
+     *
+     * The function that calls this class is expected to handle the
+     * memory handling of the buffer -- both allocating and
+     * deallocating.
+     *
+     * As simple example of using this class in transmit mode:
+     *
+     * \verbatim
+     uint8_t* buffer = (uint8_t*)volk_malloc(header_nbytes(),
+                                             volk_get_alignment());
+
+     header_buffer hdr(buffer);
+     hdr.add_field64(sync_word, sync_word_len);
+     hdr.add_field16(payload_length);
+     hdr.add_field8(header_flags);
+     hdr.add_field8(header_options);
+
+     // Do something with the header
+
+     volk_free(buffer);
+     \endverbatim
+     *
+     * In this example, the header contains four fields:
+     *
+     * \verbatim
+       |0                           15|16          23|24          31|
+       |                          sync word                         |
+       |                                                            |
+       |           length             |     flags    |   options    |
+       \endverbatim
+     *
+     * The sync word can be up to 64-bits, but the add_field64 is also
+     * passed the number of actual bytes in the sync word and so could
+     * be fewer.
+     *
+     * \section header_buffer_rx Receive Mode
+     *
+     * In receive mode, we build up the header as bits are received by
+     * inserting them with insert_bit. We can find out how long the
+     * current header is, in bits, using the call to length(). If the
+     * header is of the appropriate length, we can then start
+     * extracting the fields from it. When we are done with the
+     * current header, call clear() to reset the internal buffer to
+     * empty, which will mean that length() returns 0.
+     *
+     * The header fields are extracted using the extract_field[N]
+     * functions. Like the add_field[N] functions, we specify the size
+     * (in bits) of the field we are extracting. We pass this function
+     * the bit-position of the expected field in the received header
+     * buffer. The extract_field[N] assumes that the number of bits
+     * for the field is N, but we can tell the function to use fewer
+     * bits if we want. Setting the length parameter of these
+     * functions greater than N is illegal, and it will throw an
+     * error.
+     *
+     * For example, given a header of | length | seq. num. | where the
+     * length is 16 bits and the sequence number is 32 bits, we would
+     * use:
+     *
+     * \verbatim
+          uint16_t len = d_hdr_reg.extract_field16(0);
+          uint32_t seq = d_hdr_reg.extract_field32(16);
+       \endverbatim
+     *
+     * The extract_field functions are specific to data types of the
+     * field and the number of bits for each field is inferred by the
+     * data type. So extract_field16 assumes we want all 16 bits in
+     * the field represented.
+     *
+     * Some headers have fields that are not standard sizes of
+     * integers, like a 1 bit, 4 bit, or even 12 bit fields. We can
+     * ask for fewer bits for each field. say:
+     *
+     * \verbatim
+       |0          15|16     19|20          31|
+       |     len     |  flags  |   options    |
+       \endverbatim
+     *
+     * We would use the following extraction functions:
+     *
+     * \verbatim
+          uint16_t len   = d_hdr_reg.extract_field16(0);
+          uint8_t  flags = d_hdr_reg.extract_field8(16, 4);
+          uint16_t opts  = d_hdr_reg.extract_field16(20, 12);
+       \endverbatim
+     *
+     * \sa header_format_default
+     * \sa header_format_counter
+     * \sa header_format_crc
+     */
+    class DIGITAL_API header_buffer
+    {
+    private:
+      size_t d_offset;
+      uint8_t *d_buffer;
+
+      std::vector<bool> d_input;
+
+    public:
+      /*!
+       * Create a header buffer object with a pre-allocated buffer, \p
+       * buffer, to hold the formatted header data.
+       *
+       * If \p buffer is set to NULL, then this object is in receive
+       * mode meant to receive bits from an incoming data stream and
+       * provide the ability to extract fields. In this mode, calls to
+       * add_field are invalid and will be nops.
+       */
+      header_buffer(uint8_t *buffer=NULL);
+
+      /*!
+       * Class destructor.
+       */
+      ~header_buffer();
+
+      /*!
+       * Clears the header.
+       *
+       * In transmit mode, this resets the current offset so new
+       * add_field functions start adding data to the start of the
+       * buffer.
+       *
+       * In receive mode, this clears the buffer that we have inserted
+       * bits in to.
+       */
+      void clear();
+
+
+      /*!
+       * In transmit mode, this returns the length of the data in
+       * the buffer (not the allocated buffer length).
+       *
+       * In receiving mode, this returns the current length in bits of
+       * the received header.
+       */
+      size_t length() const;
+
+      /*!
+       * Returns a constant pointer to the buffer.
+       */
+      const uint8_t* header() const;
+
+      /*!
+       * Add an 8-bit field to the header.
+       *
+       * \param data The 8-bit data item.
+       * \param len Length (in bits) of \p data.
+       * \param bs Set to 'true' to byte swap the data.
+       */
+      void add_field8(uint8_t data, int len=8, bool bs=false);
+
+      /*!
+       * Add an 16-bit field to the header.
+       *
+       * \param data The 16-bit data item.
+       * \param len Length (in bits) of \p data.
+       * \param bs Set to 'true' to byte swap the data.
+       */
+      void add_field16(uint16_t data, int len=16, bool bs=false);
+
+      /*!
+       * Add an 32-bit field to the header.
+       *
+       * \param data The 32-bit data item.
+       * \param len Length (in bits) of \p data.
+       * \param bs Set to 'true' to byte swap the data.
+       */
+      void add_field32(uint32_t data, int len=32, bool bs=false);
+
+      /*!
+       * Add an 64-bit field to the header.
+       *
+       * \param data The 64-bit data item.
+       * \param len Length (in bits) of \p data.
+       * \param bs Set to 'true' to byte swap the data.
+       */
+      void add_field64(uint64_t data, int len=64, bool bs=false);
+
+
+
+      /*****************************************************
+       *   Receive mode to build a header from bits        *
+       *****************************************************/
+
+      /*!
+       * Insert a new bit on the back of the input buffer. This
+       * function is used in receive mode to add new bits as they are
+       * received for later use of the extract_field functions.
+       *
+       * \param bit New bit to add.
+       */
+      void insert_bit(int bit);
+
+      /*!
+       * Returns up to an 8-bit field in the packet header.
+       *
+       * \param pos Bit position of the start of the field.
+       * \param len The number of bits in the field.
+       * \param bs Set to 'true' to byte swap the data.
+       */
+      uint8_t extract_field8(int pos, int len=8, bool bs=false);
+
+      /*!
+       * Returns up to a 16-bit field in the packet header.
+       *
+       * \param pos Bit position of the start of the field.
+       * \param len The number of bits in the field.
+       * \param bs Set to 'true' to byte swap the data.
+       */
+      uint16_t extract_field16(int pos, int len=16, bool bs=false);
+
+      /*!
+       * Returns up to a 32-bit field in the packet header.
+       *
+       * \param pos Bit position of the start of the field.
+       * \param len The number of bits in the field.
+       * \param bs Set to 'true' to byte swap the data.
+       */
+      uint32_t extract_field32(int pos, int len=32, bool bs=false);
+
+      /*!
+       * Returns up to a 64-bit field in the packet header.
+       *
+       * \param pos Bit position of the start of the field.
+       * \param len The number of bits in the field.
+       * \param bs Set to 'true' to byte swap the data.
+       */
+      uint64_t extract_field64(int pos, int len=64, bool bs=false);
+    };
+
+  } // namespace digital
+} // namespace gr
+
+#endif /* INCLUDED_DIGITAL_HEADER_BUFFER_H */
diff --git a/gr-digital/include/gnuradio/digital/header_format_base.h 
b/gr-digital/include/gnuradio/digital/header_format_base.h
new file mode 100644
index 0000000..557a55c
--- /dev/null
+++ b/gr-digital/include/gnuradio/digital/header_format_base.h
@@ -0,0 +1,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 */
diff --git a/gr-digital/include/gnuradio/digital/header_format_counter.h 
b/gr-digital/include/gnuradio/digital/header_format_counter.h
new file mode 100644
index 0000000..5eb075a
--- /dev/null
+++ b/gr-digital/include/gnuradio/digital/header_format_counter.h
@@ -0,0 +1,135 @@
+/* -*- c++ -*- */
+/* Copyright 2015-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_COUNTER_H
+#define INCLUDED_DIGITAL_HEADER_FORMAT_COUNTER_H
+
+#include <pmt/pmt.h>
+#include <gnuradio/digital/api.h>
+#include <gnuradio/digital/header_format_default.h>
+
+namespace gr {
+  namespace digital {
+
+    /*!
+     * \brief Header formatter that adds the payload bits/symbol
+     * format and a packet number counter.
+     * \ingroup packet_operators_blk
+     *
+     * \details
+     *
+     * Child class of header_format_default. This version adds two
+     * fields to the header:
+     *
+     * \li bps (16 bits): bits/symbol used when modulating the payload.
+     * \li count (16 bits): a counter for the packet number.
+     *
+     * Like the default packet formatter, the length is encoded as a
+     * 16-bit value repeated twice. The full packet looks like:
+     * \verbatim
+         | access code | hdr | payload |
+       \endverbatim
+     *
+     * Where the access code is <= 64 bits and hdr is:
+     * \verbatim
+         |  0 -- 15 | 16 -- 31 |
+         | pkt len  | pkt len  |
+         | bits/sym | counter  |
+       \endverbatim
+     *
+     * The access code and header are formatted for network byte order.
+     *
+     * \sa header_format_default
+     */
+    class DIGITAL_API header_format_counter
+      : public header_format_default
+    {
+     public:
+      header_format_counter(const std::string &access_code,
+                            int threshold, int bps);
+      virtual ~header_format_counter();
+
+      /*!
+       * Creates a header from the access code and packet length to
+       * build an output packet in the form:
+       *
+       * \verbatim
+           | access code | pkt len | pkt len | bps | counter |
+         \endverbatim
+       *
+       * \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.
+       */
+      virtual bool format(int nbytes_in,
+                          const unsigned char *input,
+                          pmt::pmt_t &output,
+                          pmt::pmt_t &info);
+
+      /*!
+       * Returns the length of the formatted header in bits.
+       */
+      virtual size_t header_nbits() const;
+
+      /*!
+       * Factory to create an async packet header formatter; returns
+       * an sptr to the object.
+       *
+       * \param access_code An access code that is used to find and
+       * synchronize the start of a packet. Used in the parser and in
+       * other blocks like a corr_est block that helps trigger the
+       * receiver. Can be up to 64-bits long.
+       * \param threshold How many bits can be wrong in the access
+       * code and still count as correct.
+       * \param bps The number of bits/second used in the payload's
+       * modulator.
+       */
+      static sptr make(const std::string &access_code,
+                       int threshold, int bps);
+
+    protected:
+      uint16_t d_counter;    //!< keeps track of the number of packets 
transmitted
+      uint16_t d_bps;        //!< bits/sec of payload modulation
+
+      //! Verify that the header is valid
+      bool header_ok();
+
+      /*! Get info from the header; return payload length and package
+       *  rest of data in d_info dictionary.
+       *
+       * Extracts the header of the form:
+       *
+       * \verbatim
+           | access code | pkt len | pkt len | bps | counter | payload |
+         \endverbatim
+       */
+      int header_payload();
+  };
+
+  } // namespace digital
+} // namespace gr
+
+#endif /* INCLUDED_DIGITAL_HEADER_FORMAT_COUNTER_H */
diff --git a/gr-digital/include/gnuradio/digital/header_format_crc.h 
b/gr-digital/include/gnuradio/digital/header_format_crc.h
new file mode 100644
index 0000000..edb1884
--- /dev/null
+++ b/gr-digital/include/gnuradio/digital/header_format_crc.h
@@ -0,0 +1,118 @@
+/* -*- 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_CRC_H
+#define INCLUDED_DIGITAL_HEADER_FORMAT_CRC_H
+
+#include <pmt/pmt.h>
+#include <gnuradio/digital/api.h>
+#include <gnuradio/digital/header_format_default.h>
+#include <boost/crc.hpp>
+
+namespace gr {
+  namespace digital {
+
+    /*!
+     * \brief Header formatter that includes the payload length,
+     * packet number, and a CRC check on the header.
+     * \ingroup packet_operators_blk
+     *
+     * \details
+     *
+     * Child class of header_format_base. This version's header
+     * format looks like:
+     *
+     * \li length (12 bits): length of the payload
+     * \li number (12 bits): packet number
+     * \li CRC8 (8 bits): A CRC8 check on the header contents
+     *
+     * Instead of duplicating the payload length, we only add it once
+     * and use the CRC8 to make sure it's correctly received.
+     *
+     * \verbatim
+         |  0 -- 11 | 12 -- 23 | 24 -- 31 |
+         |    len   | pkt len  |   CRC8   |
+       \endverbatim
+     *
+     * Reimplements packet_header_default in the style of the
+     * header_format_base.
+     */
+    class DIGITAL_API header_format_crc
+      : public header_format_base
+    {
+     public:
+      header_format_crc(const std::string &len_key_name="packet_len",
+                           const std::string &num_key_name="packet_num");
+      virtual ~header_format_crc();
+
+      void set_header_num(unsigned header_num) { d_header_number = header_num; 
};
+
+      /*!
+       * \brief Encodes the header information in the given tags into
+       * bits and places them into \p out.
+       *
+       * \details
+       * Uses the following header format:
+       *  - Bits 0-11: The packet length (what was stored in the tag with key 
\p len_tag_key)
+       *  - Bits 12-23: The header number (counts up everytime this function 
is called)
+       *  - Bit 24-31: 8-Bit CRC
+       */
+      virtual bool format(int nbytes_in,
+                          const unsigned char *input,
+                          pmt::pmt_t &output,
+                          pmt::pmt_t &info);
+
+      virtual bool parse(int nbits_in,
+                         const unsigned char *input,
+                         std::vector<pmt::pmt_t> &info,
+                         int &nbits_processed);
+
+      /*!
+       * Returns the length of the formatted header in bits.
+       */
+      virtual size_t header_nbits() const;
+
+      /*!
+       * Factory to create an async packet header formatter; returns
+       * an sptr to the object.
+       */
+      static sptr make(const std::string &len_key_name="packet_len",
+                       const std::string &num_key_name="packet_num");
+
+    protected:
+      uint16_t d_header_number;
+      pmt::pmt_t d_len_key_name;
+      pmt::pmt_t d_num_key_name;
+      boost::crc_optimal<8, 0x07, 0xFF, 0x00, false, false>  d_crc_impl;
+
+      //! Verify that the header is valid
+      virtual bool header_ok();
+
+      /*! Get info from the header; return payload length and package
+       *  rest of data in d_info dictionary.
+       */
+      virtual int header_payload();
+    };
+
+  } // namespace digital
+} // namespace gr
+
+#endif /* INCLUDED_DIGITAL_HEADER_FORMAT_CRC_H */
diff --git a/gr-digital/include/gnuradio/digital/header_format_default.h 
b/gr-digital/include/gnuradio/digital/header_format_default.h
new file mode 100644
index 0000000..4abd7bb
--- /dev/null
+++ b/gr-digital/include/gnuradio/digital/header_format_default.h
@@ -0,0 +1,217 @@
+/* -*- c++ -*- */
+/* Copyright 2015-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_DEFAULT_H
+#define INCLUDED_DIGITAL_HEADER_FORMAT_DEFAULT_H
+
+#include <pmt/pmt.h>
+#include <gnuradio/digital/api.h>
+#include <gnuradio/digital/header_format_base.h>
+#include <gnuradio/digital/header_buffer.h>
+#include <gnuradio/logger.h>
+#include <boost/enable_shared_from_this.hpp>
+
+namespace gr {
+  namespace digital {
+
+    /*!
+     * \brief Default header formatter for PDU formatting.
+     * \ingroup packet_operators_blk
+     *
+     * \details
+     * Used to handle the default packet header.
+     *
+     * See the parent class header_format_base for details of how
+     * these classes operate.
+     *
+     * The default header created in this base class consists of an
+     * access code and the packet length. The length is encoded as a
+     * 16-bit value repeated twice:
+     *
+     * \verbatim
+         | access code | hdr | payload |
+       \endverbatim
+     *
+     * Where the access code is <= 64 bits and hdr is:
+     *
+     * \verbatim
+         |  0 -- 15 | 16 -- 31 |
+         | pkt len  | pkt len  |
+       \endverbatim
+     *
+     * The access code and header are formatted for network byte order.
+     *
+     * This header generator does not calculate or append a CRC to the
+     * packet. Use the CRC32 Async block for that before adding the
+     * header. The header's length will then measure the payload plus
+     * the CRC length (4 bytes for a CRC32).
+     *
+     * The default header parser produces a PMT dictionary that
+     * contains the following keys. All formatter blocks MUST produce
+     * these two values in any dictionary.
+     *
+     * \li "payload symbols": the number of symbols in the
+     * payload. The payload decoder will have to know how this relates
+     * to the number of bits received. This block knows nothing about
+     * the payload modulation or the number of bits/symbol. Use the
+     * gr::digital::header_format_counter for that purpose.
+     *
+     * \sa header_format_counter
+     * \sa header_format_crc
+     * \sa header_format_ofdm
+     */
+    class DIGITAL_API header_format_default
+      : public header_format_base
+    {
+     public:
+      header_format_default(const std::string &access_code, int threshold);
+      virtual ~header_format_default();
+
+      /*!
+       * Creates a header from the access code and packet length and
+       * creates an output header as a PMT vector in the form:
+       *
+       * \verbatim
+           | access code | pkt len | pkt len |
+         \endverbatim
+       *
+       * \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.
+       */
+      virtual bool format(int nbytes_in,
+                          const unsigned char *input,
+                          pmt::pmt_t &output,
+                          pmt::pmt_t &info);
+
+      /*!
+       * Parses a header of the form:
+       *
+       * \verbatim
+           | access code | pkt len | pkt len | payload |
+         \endverbatim
+       *
+       * This is implemented as a state machine that starts off
+       * searching for the access code. Once found, the access code is
+       * used to find the start of the packet and the following
+       * header. This default header encodes the length of the payload
+       * a 16 bit integer twice. The state machine finds the header
+       * and checks that both payload length values are the same. It
+       * then goes into its final state that reads in the payload
+       * (based on the payload length) and produces a payload as a PMT
+       * u8 vector of packed bytes.
+       *
+       * \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.
+       */
+      virtual bool parse(int nbits_in,
+                         const unsigned char *input,
+                         std::vector<pmt::pmt_t> &info,
+                         int &nbits_processed);
+
+      /*!
+       * Returns the length of the formatted header in bits.
+       */
+      virtual size_t header_nbits() const;
+
+      /*!
+       * Updates the access code. Must be a string of 1's and 0's and
+       * <= 64 bits.
+       */
+      bool set_access_code(const std::string &access_code);
+
+      /*!
+       * Returns the formatted access code as a 64-bit register.
+       */
+      unsigned long long access_code() const;
+
+      /*!
+       * Sets the threshold for number of access code bits can be in
+       * error before detection. Defaults to 0.
+       */
+      void set_threshold(unsigned int thresh=0);
+
+      /*!
+       * Returns threshold value for access code detection.
+       */
+      unsigned int threshold() const;
+
+      /*!
+       * Factory to create an async packet header formatter; returns
+       * an sptr to the object.
+       *
+       * \param access_code An access code that is used to find and
+       * synchronize the start of a packet. Used in the parser and in
+       * other blocks like a corr_est block that helps trigger the
+       * receiver. Can be up to 64-bits long.
+       * \param threshold How many bits can be wrong in the access
+       * code and still count as correct.
+       */
+      static sptr make(const std::string &access_code, int threshold);
+
+    protected:
+      uint64_t d_access_code;        //!< register to hold the access code
+      size_t d_access_code_len;      //!< length in bits of the access code
+
+      unsigned long long d_data_reg; //!< used to look for access_code
+      unsigned long long d_mask;     /*!< masks access_code bits (top N bits 
are set where
+                                       N is the number of bits in the access 
code) */
+      unsigned int d_threshold;      //!< how many bits may be wrong in sync 
vector
+
+      int d_pkt_len;                 //!< Length of the packet to put into the 
output buffer
+      int d_pkt_count;               //!< Number of bytes bits already received
+
+      int d_nbits;                   //!< num bits processed since reset
+
+      //! 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();
+
+      /*! Get info from the header; return payload length and package
+       *  rest of data in d_info dictionary.
+       */
+      virtual int header_payload();
+    };
+
+  } // namespace digital
+} // namespace gr
+
+#endif /* INCLUDED_DIGITAL_HEADER_FORMAT_DEFAULT_H */
diff --git a/gr-digital/include/gnuradio/digital/header_format_ofdm.h 
b/gr-digital/include/gnuradio/digital/header_format_ofdm.h
new file mode 100644
index 0000000..b426c74
--- /dev/null
+++ b/gr-digital/include/gnuradio/digital/header_format_ofdm.h
@@ -0,0 +1,127 @@
+/* -*- 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_OFDM_H
+#define INCLUDED_DIGITAL_HEADER_FORMAT_OFDM_H
+
+#include <pmt/pmt.h>
+#include <gnuradio/digital/api.h>
+#include <gnuradio/digital/header_format_crc.h>
+#include <boost/crc.hpp>
+
+namespace gr {
+  namespace digital {
+
+    /*!
+     * \brief Header formatter that includes the payload length,
+     * packet number, and a CRC check on the header.
+     * \ingroup packet_operators_blk
+     *
+     * \details
+     *
+     * Child class of header_format_base. This version's header
+     * format looks like:
+     *
+     * \li length (12 bits): length of the payload
+     * \li number (12 bits): packet number
+     * \li CRC8 (8 bits): A CRC8 check on the header contents
+     *
+     * Instead of duplicating the payload length, we only add it once
+     * and use the CRC8 to make sure it's correctly received.
+     *
+     * \verbatim
+         |  0 -- 11 | 12 -- 23 | 24 -- 31 |
+         |    len   | pkt len  |   CRC8   |
+       \endverbatim
+     *
+     * Reimplements packet_header_default in the style of the
+     * header_format_base.
+     */
+    class DIGITAL_API header_format_ofdm
+      : public header_format_crc
+    {
+     public:
+      header_format_ofdm(const std::vector<std::vector<int> > 
&occupied_carriers,
+                            int n_syms,
+                            const std::string &len_key_name="packet_len",
+                            const std::string &frame_key_name="frame_len",
+                            const std::string &num_key_name="packet_num",
+                            int bits_per_header_sym=1,
+                            int bits_per_payload_sym=1,
+                            bool scramble_header=false);
+      virtual ~header_format_ofdm();
+
+      /*!
+       * \brief Encodes the header information in the given tags into
+       * bits and places them into \p out.
+       *
+       * \details
+       * Uses the following header format:
+       *  - Bits 0-11: The packet length (what was stored in the tag with key 
\p len_tag_key)
+       *  - Bits 12-23: The header number (counts up everytime this function 
is called)
+       *  - Bit 24-31: 8-Bit CRC
+       */
+      virtual bool format(int nbytes_in,
+                          const unsigned char *input,
+                          pmt::pmt_t &output,
+                          pmt::pmt_t &info);
+
+      virtual bool parse(int nbits_in,
+                         const unsigned char *input,
+                         std::vector<pmt::pmt_t> &info,
+                         int &nbits_processed);
+
+      /*!
+       * Returns the length of the formatted header in bits.
+       */
+      virtual size_t header_nbits() const;
+
+      /*!
+       * Factory to create an async packet header formatter; returns
+       * an sptr to the object.
+       */
+      static sptr make(const std::vector<std::vector<int> > &occupied_carriers,
+                       int n_syms,
+                       const std::string &len_key_name="packet_len",
+                       const std::string &frame_key_name="frame_len",
+                       const std::string &num_key_name="packet_num",
+                       int bits_per_header_sym=1,
+                       int bits_per_payload_sym=1,
+                       bool scramble_header=false);
+
+    protected:
+      pmt::pmt_t d_frame_key_name; //!< Tag key of the additional frame length 
tag
+      const std::vector<std::vector<int> > d_occupied_carriers; //!< Which 
carriers/symbols carry data
+      int d_syms_per_set; //!< Helper variable: Total number of elements in 
d_occupied_carriers
+      int d_bits_per_payload_sym;
+      std::vector<uint8_t> d_scramble_mask; //!< Bits are xor'd with this 
before tx'ing
+      size_t d_header_len;
+
+      /*! Get info from the header; return payload length and package
+       *  rest of data in d_info dictionary.
+       */
+      virtual int header_payload();
+    };
+
+  } // namespace digital
+} // namespace gr
+
+#endif /* INCLUDED_DIGITAL_HEADER_FORMAT_OFDM_H */
diff --git a/gr-digital/include/gnuradio/digital/protocol_formatter_async.h 
b/gr-digital/include/gnuradio/digital/protocol_formatter_async.h
new file mode 100644
index 0000000..560a236
--- /dev/null
+++ b/gr-digital/include/gnuradio/digital/protocol_formatter_async.h
@@ -0,0 +1,88 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2015-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_PROTOCOL_FORMATTER_ASYNC_H
+#define INCLUDED_DIGITAL_PROTOCOL_FORMATTER_ASYNC_H
+
+#include <gnuradio/digital/api.h>
+#include <gnuradio/digital/header_format_base.h>
+#include <gnuradio/block.h>
+
+namespace gr {
+  namespace digital {
+
+    /*!
+     * \brief Uses a header format object to append a header onto a
+     * PDU.
+     *
+     * \ingroup packet_operators_blk
+     *
+     * \details
+     * This block takes in PDUs and creates a header, generally for
+     * MAC-level processing. Each received PDU is assumed to be its
+     * own frame, so any fragmentation would be done upstream in or
+     * before the flowgraph.
+     *
+     * The header that is created and transmitted out of the 'header'
+     * message port as a PDU. The header is based entirely on the \p
+     * format object, which is an object derived from the
+     * header_format_base class. All of these packet header format
+     * objects operate the same: they take in the payload data as well
+     * as possible extra metadata info about the PDU; the format
+     * object then returns the output PDU as a PMT argument along
+     * with any changes to the metadata info PMT.
+     *
+     * For different packet header formatting needs, we can define new
+     * classes that inherit from the header_format_base block
+     * and which overload the header_format_base::format
+     * function.
+     *
+     * \sa header_format_base
+     * \sa header_format_default
+     * \sa header_format_counter
+     *
+     * This block only uses asynchronous message passing interfaces to
+     * receiver and emit PDUs. The message ports are:
+     *
+     * \li in: receives PDUs for the frame payload
+     * \li header: the header formatted for the given frame
+     * \li payload: the payload
+     */
+    class DIGITAL_API protocol_formatter_async : virtual public block
+    {
+     public:
+      typedef boost::shared_ptr<protocol_formatter_async> sptr;
+
+      /*!
+       * Make a packet header block using a given \p format.
+       *
+       * \param format The format object to use when creating the
+       *        header for the packet.
+       */
+      static sptr make(const header_format_base::sptr &format);
+    };
+
+  } // namespace digital
+} // namespace gr
+
+#endif /* INCLUDED_DIGITAL_PROTOCOL_FORMATTER_ASYNC_H */
diff --git a/gr-digital/include/gnuradio/digital/protocol_formatter_bb.h 
b/gr-digital/include/gnuradio/digital/protocol_formatter_bb.h
new file mode 100644
index 0000000..2a57fdc
--- /dev/null
+++ b/gr-digital/include/gnuradio/digital/protocol_formatter_bb.h
@@ -0,0 +1,81 @@
+/* -*- 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_PROTOCOL_FORMATTER_BB_H
+#define INCLUDED_DIGITAL_PROTOCOL_FORMATTER_BB_H
+
+#include <gnuradio/digital/api.h>
+#include <gnuradio/digital/header_format_base.h>
+#include <gnuradio/tagged_stream_block.h>
+
+namespace gr {
+  namespace digital {
+
+    /*!
+     * \brief Uses a header format object to create a header from a
+     * tagged stream packet.
+     *
+     * \ingroup packet_operators_blk
+     *
+     * \details
+     * This block takes in tagged stream and creates a header,
+     * generally for MAC-level processing. Each received tagged stream
+     * is assumed to be its own frame, so any fragmentation would be
+     * done upstream in or before the flowgraph.
+     *
+     * The header that is created and transmitted from this block. The
+     * payload should then be sent as a parallel tagged stream to be
+     * muxed together later. The header is based entirely on the \p
+     * format object, which is an object derived from the
+     * header_format_base class. All of these packet header format
+     * objects operate the same: they take in the payload data as well
+     * as possible extra metadata info about the PDU; the format
+     * object then returns the output and metadata info. This block
+     * then transmits the header vector and attaches and metadata as
+     * tags at the start of the header.
+     *
+     * \sa protocol_formatter_async
+     */
+    class DIGITAL_API protocol_formatter_bb : virtual public 
tagged_stream_block
+    {
+     public:
+      typedef boost::shared_ptr<protocol_formatter_bb> sptr;
+
+      /*!
+       * Make a packet header block using a given \p format.
+       *
+       * \param format The format object to use when creating the
+       *        header for the packet. Derived from the
+       *        header_format_base class.
+       * \param len_tag_key The tagged stream length key.
+       */
+      static sptr make(const header_format_base::sptr &format,
+                       const std::string &len_tag_key="packet_len");
+
+      virtual void set_header_format(header_format_base::sptr &format) = 0;
+    };
+
+  } // namespace digital
+} // namespace gr
+
+#endif /* INCLUDED_DIGITAL_PROTOCOL_FORMATTER_BB_H */
diff --git a/gr-digital/include/gnuradio/digital/protocol_parser_b.h 
b/gr-digital/include/gnuradio/digital/protocol_parser_b.h
new file mode 100644
index 0000000..89c7f7e
--- /dev/null
+++ b/gr-digital/include/gnuradio/digital/protocol_parser_b.h
@@ -0,0 +1,80 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2015-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_PACKET_PARSE_B_H
+#define INCLUDED_DIGITAL_PACKET_PARSE_B_H
+
+#include <gnuradio/digital/api.h>
+#include <gnuradio/digital/header_format_base.h>
+#include <gnuradio/sync_block.h>
+
+namespace gr {
+  namespace digital {
+
+    /*!
+     * \brief Block that synchronizes to a header based on a header
+     * format object class. Designed to accept hard bits and produce
+     * PDUs with packed bytes (pmt::u8vector).
+     *
+     * \ingroup packet_operators_blk
+     *
+     * \details
+     *
+     * A packet synchronizer block. This block takes in hard bits
+     * (unpacked bytes; 1's and 0's as the LSB) and finds the access
+     * code as a sync word to find the start of a frame.
+     *
+     * The block uses a format object derived from a
+     * header_format_base class.
+     *
+     * Once the frame is detected (usually through the use of an
+     * access code), the block uses the format object's parser
+     * function to decode the remaining header. Generally, as in the
+     * default header case, the header will contain the length of the
+     * frame's payload. That and anything else in the header will
+     * generally go into the PDU's meta-data dictionary.
+     *
+     * The block will output a PDU that contains frame's header info
+     * in the meta-data portion of the PDU and the payload itself. The
+     * payload is packed hard bits as taken from the input stream.
+     *
+     * \sa packet_sync_ff for a soft decision version.
+     */
+    class DIGITAL_API protocol_parser_b : virtual public sync_block
+    {
+     public:
+      typedef boost::shared_ptr<protocol_parser_b> sptr;
+
+      /*!
+       * Make a packet header block using a given \p format.
+       *
+       * \param format The format object to use when reading the
+       *        header.
+       */
+      static sptr make(const header_format_base::sptr &format);
+    };
+
+  } // namespace digital
+} // namespace gr
+
+#endif /* INCLUDED_DIGITAL_PROTOCOL_PARSER_B_H */
diff --git a/gr-digital/lib/CMakeLists.txt b/gr-digital/lib/CMakeLists.txt
index daa577f..84f53ec 100644
--- a/gr-digital/lib/CMakeLists.txt
+++ b/gr-digital/lib/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2011-2014 Free Software Foundation, Inc.
+# Copyright 2011-2016 Free Software Foundation, Inc.
 #
 # This file is part of GNU Radio
 #
@@ -83,6 +83,7 @@ list(APPEND digital_sources
     glfsr_source_f_impl.cc
     hdlc_deframer_bp_impl.cc
     hdlc_framer_pb_impl.cc
+    header_buffer.cc
     header_payload_demux_impl.cc
     kurtotic_equalizer_cc_impl.cc
     lms_dd_equalizer_cc_impl.cc
@@ -106,6 +107,14 @@ list(APPEND digital_sources
     ofdm_sampler_impl.cc
     ofdm_serializer_vcc_impl.cc
     ofdm_sync_sc_cfb_impl.cc
+    header_format_base.cc
+    header_format_default.cc
+    header_format_counter.cc
+    header_format_crc.cc
+    header_format_ofdm.cc
+    protocol_formatter_async_impl.cc
+    protocol_formatter_bb_impl.cc
+    protocol_parser_b_impl.cc
     packet_header_default.cc
     packet_header_ofdm.cc
     packet_headergenerator_bb_impl.cc
@@ -189,3 +198,38 @@ if(ENABLE_STATIC_LIBS)
     ARCHIVE DESTINATION lib${LIB_SUFFIX} COMPONENT "digital_devel"   # .lib 
file
     )
 endif(ENABLE_STATIC_LIBS)
+
+
+########################################################################
+# QA C++ Code for gr-blocks
+########################################################################
+if(ENABLE_TESTING)
+  include(GrTest)
+
+  include_directories(
+    ${GR_DIGITAL_INCLUDE_DIRS}
+    ${CPPUNIT_INCLUDE_DIRS})
+  link_directories(${CPPUNIT_LIBRARY_DIRS})
+
+  list(APPEND test_gr_digital_sources
+    ${CMAKE_CURRENT_SOURCE_DIR}/test_gr_digital.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/qa_digital.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/qa_header_format.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/qa_header_buffer.cc
+    )
+
+  add_executable(test-gr-digital ${test_gr_digital_sources})
+
+  list(APPEND GR_TEST_TARGET_DEPS test-gr-digital gnuradio-digital)
+
+  target_link_libraries(
+    test-gr-digital
+    gnuradio-runtime
+    gnuradio-digital
+    ${Boost_LIBRARIES}
+    ${CPPUNIT_LIBRARIES}
+    ${LOG4CPP_LIBRARIES}
+  )
+
+  GR_ADD_TEST(test_gr_digital test-gr-digital)
+endif(ENABLE_TESTING)
diff --git a/gr-digital/lib/header_buffer.cc b/gr-digital/lib/header_buffer.cc
new file mode 100644
index 0000000..04233da
--- /dev/null
+++ b/gr-digital/lib/header_buffer.cc
@@ -0,0 +1,211 @@
+/* -*- c++ -*- */
+/* Copyright 2015 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <algorithm>
+#include <stdexcept>
+#include <volk/volk.h>
+#include <gnuradio/digital/header_buffer.h>
+
+namespace gr {
+  namespace digital {
+
+    header_buffer::header_buffer(uint8_t *bytes_out)
+    {
+      d_offset = 0;
+      d_buffer = bytes_out;
+    }
+
+    header_buffer::~header_buffer()
+    {
+    }
+
+    void
+    header_buffer::clear()
+    {
+      if(d_buffer) // TX mode
+        d_offset = 0;
+      else // RX mode
+        d_input.clear();
+    }
+
+    size_t
+    header_buffer::length() const
+    {
+      if(d_buffer) // TX mode
+        return d_offset;
+      else // RX mode
+        return d_input.size();
+    }
+
+    const uint8_t*
+    header_buffer::header() const
+    {
+      return d_buffer;
+    }
+
+    void
+    header_buffer::add_field8(uint8_t data, int len, bool bs)
+    {
+      int nbytes = len/8;
+      if(d_buffer) {
+        memcpy(&d_buffer[d_offset], &data, nbytes);
+        d_offset += nbytes;
+      }
+    }
+
+    void
+    header_buffer::add_field16(uint16_t data, int len, bool bs)
+    {
+      int nbytes = len/8;
+      if(d_buffer) {
+        uint16_t x = data;
+        if(!bs) {
+          volk_16u_byteswap(&x, 1);
+          x = x >> (16-len);
+        }
+        memcpy(&d_buffer[d_offset], &x, nbytes);
+        d_offset += nbytes;
+      }
+    }
+
+    void
+    header_buffer::add_field32(uint32_t data, int len, bool bs)
+    {
+      int nbytes = len/8;
+      if(d_buffer) {
+        uint32_t x = data;
+        if(!bs) {
+          volk_32u_byteswap(&x, 1);
+          x = x >> (32-len);
+        }
+        memcpy(&d_buffer[d_offset], &x, nbytes);
+        d_offset += nbytes;
+      }
+    }
+
+    void
+    header_buffer::add_field64(uint64_t data, int len, bool bs)
+    {
+      int nbytes = len/8;
+      if(d_buffer) {
+        uint64_t x = data;
+        if(!bs) {
+          volk_64u_byteswap(&x, 1);
+          x = x >> (64-len);
+        }
+        memcpy(&d_buffer[d_offset], &x, nbytes);
+        d_offset += nbytes;
+      }
+    }
+
+    void
+    header_buffer::insert_bit(int bit)
+    {
+      d_input.push_back(bit);
+    }
+
+    uint8_t
+    header_buffer::extract_field8(int pos, int len, bool bs)
+    {
+      if(len > 8) {
+        throw std::runtime_error("header_buffer::extract_field for "
+                                 "uint8_t length must be <= 8");
+      }
+
+      uint8_t field = 0x00;
+      std::vector<bool>::iterator itr;
+      for(itr = d_input.begin()+pos; itr != d_input.begin()+pos+len; itr++) {
+        field = (field << 1) | ((*itr) & 0x1);
+      }
+
+      return field;
+    }
+
+    uint16_t
+    header_buffer::extract_field16(int pos, int len, bool bs)
+    {
+      if(len > 16) {
+        throw std::runtime_error("header_buffer::extract_field for "
+                                 "uint16_t length must be <= 16");
+      }
+
+      uint16_t field = 0x0000;
+      std::vector<bool>::iterator itr;
+      for(itr = d_input.begin()+pos; itr != d_input.begin()+pos+len; itr++) {
+        field = (field << 1) | ((*itr) & 0x1);
+      }
+
+      if(bs) {
+        volk_16u_byteswap(&field, 1);
+      }
+
+      return field;
+    }
+
+    uint32_t
+    header_buffer::extract_field32(int pos, int len, bool bs)
+    {
+      if(len > 32) {
+        throw std::runtime_error("header_buffer::extract_field for "
+                                 "uint32_t length must be <= 32");
+      }
+
+      uint32_t field = 0x00000000;
+      std::vector<bool>::iterator itr;
+      for(itr = d_input.begin()+pos; itr != d_input.begin()+pos+len; itr++) {
+        field = (field << 1) | ((*itr) & 0x1);
+      }
+
+      if(bs) {
+        volk_32u_byteswap(&field, 1);
+      }
+
+      return field;
+    }
+
+    uint64_t
+    header_buffer::extract_field64(int pos, int len, bool bs)
+    {
+      if(len > 64) {
+        throw std::runtime_error("header_buffer::extract_field for "
+                                 "uint64_t length must be <= 64");
+      }
+
+      uint64_t field = 0x0000000000000000;
+      std::vector<bool>::iterator itr;
+      for(itr = d_input.begin()+pos; itr != d_input.begin()+pos+len; itr++) {
+        field = (field << 1) | ((*itr) & 0x1);
+      }
+
+      if(bs) {
+        volk_64u_byteswap(&field, 1);
+      }
+
+      return field;
+    }
+
+  } /* namespace digital */
+} /* namespace gr */
diff --git a/gr-digital/lib/header_format_base.cc 
b/gr-digital/lib/header_format_base.cc
new file mode 100644
index 0000000..a8d8c86
--- /dev/null
+++ b/gr-digital/lib/header_format_base.cc
@@ -0,0 +1,70 @@
+/* -*- 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <iostream>
+#include <string.h>
+#include <volk/volk.h>
+#include <gnuradio/digital/header_format_base.h>
+#include <gnuradio/math.h>
+
+namespace gr {
+  namespace digital {
+
+    header_format_base::header_format_base()
+    {
+      enter_search();
+      configure_default_loggers(d_logger, d_debug_logger, "packet formatter");
+    }
+
+    header_format_base::~header_format_base()
+    {
+    }
+
+    size_t
+    header_format_base::header_nbytes() const
+    {
+      return header_nbits() / 8;
+    }
+
+    inline void
+    header_format_base::enter_search()
+    {
+      d_state = STATE_SYNC_SEARCH;
+    }
+
+    inline void
+    header_format_base::enter_have_sync()
+    {
+      d_state = STATE_HAVE_SYNC;
+    }
+
+    inline void
+    header_format_base::enter_have_header(int payload_len)
+    {
+      d_state = STATE_SYNC_SEARCH;
+    }
+
+  } /* namespace digital */
+} /* namespace gr */
diff --git a/gr-digital/lib/header_format_counter.cc 
b/gr-digital/lib/header_format_counter.cc
new file mode 100644
index 0000000..6244ec1
--- /dev/null
+++ b/gr-digital/lib/header_format_counter.cc
@@ -0,0 +1,120 @@
+/* -*- 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <iostream>
+#include <iomanip>
+#include <string.h>
+#include <volk/volk.h>
+#include <gnuradio/digital/header_format_counter.h>
+#include <gnuradio/digital/header_buffer.h>
+#include <gnuradio/math.h>
+
+namespace gr {
+  namespace digital {
+
+    header_format_counter::sptr
+    header_format_counter::make(const std::string &access_code,
+                                int threshold, int bps)
+    {
+      return header_format_counter::sptr
+        (new header_format_counter(access_code, threshold, bps));
+    }
+
+    header_format_counter::header_format_counter(const std::string 
&access_code,
+                                                 int threshold, int bps)
+      : header_format_default(access_code, threshold)
+    {
+      d_bps = bps;
+      d_counter = 0;
+    }
+
+    header_format_counter::~header_format_counter()
+    {
+    }
+
+    bool
+    header_format_counter::format(int nbytes_in,
+                                  const unsigned char *input,
+                                  pmt::pmt_t &output,
+                                  pmt::pmt_t &info)
+
+    {
+      uint8_t* bytes_out = (uint8_t*)volk_malloc(header_nbytes(),
+                                                 volk_get_alignment());
+
+      header_buffer header(bytes_out);
+      header.add_field64(d_access_code, d_access_code_len);
+      header.add_field16((uint16_t)(nbytes_in));
+      header.add_field16((uint16_t)(nbytes_in));
+      header.add_field16((uint16_t)(d_bps));
+      header.add_field16((uint16_t)(d_counter));
+
+      // Package output data into a PMT vector
+      output = pmt::init_u8vector(header_nbytes(), bytes_out);
+
+      // Creating the output pmt copies data; free our own here.
+      volk_free(bytes_out);
+
+      d_counter++;
+
+      return true;
+    }
+
+    size_t
+    header_format_counter::header_nbits() const
+    {
+      return d_access_code_len + 8*4*sizeof(uint16_t);
+    }
+
+    bool
+    header_format_counter::header_ok()
+    {
+      // confirm that two copies of header info are identical
+      uint16_t len0 = d_hdr_reg.extract_field16(0);
+      uint16_t len1 = d_hdr_reg.extract_field16(16);
+      return (len0 ^ len1) == 0;
+    }
+
+    int
+    header_format_counter::header_payload()
+    {
+      uint16_t len = d_hdr_reg.extract_field16(0);
+      uint16_t bps = d_hdr_reg.extract_field16(32);
+      uint16_t counter = d_hdr_reg.extract_field16(48);
+
+      d_bps = bps;
+
+      d_info = pmt::make_dict();
+      d_info = pmt::dict_add(d_info, pmt::intern("payload symbols"),
+                             pmt::from_long(8*len / d_bps));
+      d_info = pmt::dict_add(d_info, pmt::intern("bps"),
+                             pmt::from_long(bps));
+      d_info = pmt::dict_add(d_info, pmt::intern("counter"),
+                             pmt::from_long(counter));
+      return static_cast<int>(len);
+    }
+
+  } /* namespace digital */
+} /* namespace gr */
diff --git a/gr-digital/lib/header_format_crc.cc 
b/gr-digital/lib/header_format_crc.cc
new file mode 100644
index 0000000..7594449
--- /dev/null
+++ b/gr-digital/lib/header_format_crc.cc
@@ -0,0 +1,161 @@
+/* -*- 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <volk/volk.h>
+#include <gnuradio/digital/header_format_crc.h>
+#include <gnuradio/digital/header_buffer.h>
+
+namespace gr {
+  namespace digital {
+
+    header_format_crc::sptr
+    header_format_crc::make(const std::string &len_key_name,
+                            const std::string &num_key_name)
+    {
+      return header_format_crc::sptr
+        (new header_format_crc(len_key_name, num_key_name));
+    }
+
+    header_format_crc::header_format_crc(const std::string &len_key_name,
+                                         const std::string &num_key_name)
+      : header_format_base(),
+        d_header_number(0)
+    {
+      d_len_key_name = pmt::intern(len_key_name);
+      d_num_key_name = pmt::intern(num_key_name);
+    }
+
+    header_format_crc::~header_format_crc()
+    {
+    }
+
+    bool
+    header_format_crc::format(int nbytes_in,
+                              const unsigned char *input,
+                              pmt::pmt_t &output,
+                              pmt::pmt_t &info)
+    {
+      uint8_t* bytes_out = (uint8_t*)volk_malloc(header_nbytes(),
+                                                 volk_get_alignment());
+      memset(bytes_out, 0, header_nbytes());
+
+      // Should this throw instead of mask if the payload is too big
+      // for 12-bit representation?
+      nbytes_in &= 0x0FFF;
+
+      d_crc_impl.reset();
+      d_crc_impl.process_bytes((void const *) &nbytes_in, 2);
+      d_crc_impl.process_bytes((void const *) &d_header_number, 2);
+      uint8_t crc = d_crc_impl();
+
+      // Form 2 12-bit items into 1 2-byte item
+      uint32_t concat = 0;
+      concat = (d_header_number << 12) | (nbytes_in);
+
+      header_buffer header(bytes_out);
+      header.add_field32(concat, 24, true);
+      header.add_field8(crc);
+
+      d_header_number++;
+      d_header_number &= 0x0FFF;
+
+      // Package output data into a PMT vector
+      output = pmt::init_u8vector(header_nbytes(), bytes_out);
+
+      // Creating the output pmt copies data; free our own here.
+      volk_free(bytes_out);
+
+      return true;
+    }
+
+    bool
+    header_format_crc::parse(int nbits_in,
+                             const unsigned char *input,
+                             std::vector<pmt::pmt_t> &info,
+                             int &nbits_processed)
+    {
+      while(nbits_processed <= nbits_in) {
+        d_hdr_reg.insert_bit(input[nbits_processed++]);
+        if(d_hdr_reg.length() == header_nbits()) {
+          if(header_ok()) {
+            int payload_len = header_payload();
+            enter_have_header(payload_len);
+            info.push_back(d_info);
+            d_hdr_reg.clear();
+            return true;
+          }
+          else {
+            d_hdr_reg.clear();
+            return false;
+          }
+          break;
+        }
+      }
+
+      return true;
+    }
+
+    size_t
+    header_format_crc::header_nbits() const
+    {
+      return 32;
+    }
+
+
+    bool
+    header_format_crc::header_ok()
+    {
+      uint32_t pkt = d_hdr_reg.extract_field32(0, 24, true);
+      uint16_t pktlen = static_cast<uint16_t>((pkt >> 8) & 0x0fff);
+      uint16_t pktnum = static_cast<uint16_t>((pkt >> 20) & 0x0fff);
+      uint8_t crc_rcvd = d_hdr_reg.extract_field8(24);
+
+      // Check CRC8
+      d_crc_impl.reset();
+      d_crc_impl.process_bytes((void const *) &pktlen, 2);
+      d_crc_impl.process_bytes((void const *) &pktnum, 2);
+      uint8_t crc_clcd = d_crc_impl();
+
+      return (crc_rcvd == crc_clcd);
+    }
+
+    int
+    header_format_crc::header_payload()
+    {
+      uint32_t pkt = d_hdr_reg.extract_field32(0, 24, true);
+      uint16_t pktlen = static_cast<uint16_t>((pkt >> 8) & 0x0fff);
+      uint16_t pktnum = static_cast<uint16_t>((pkt >> 20) & 0x0fff);
+
+      d_info = pmt::make_dict();
+      d_info = pmt::dict_add(d_info, d_len_key_name,
+                             pmt::from_long(8*pktlen));
+      d_info = pmt::dict_add(d_info, d_num_key_name,
+                             pmt::from_long(pktnum));
+      return static_cast<int>(pktlen);
+    }
+
+  } /* namespace digital */
+} /* namespace gr */
diff --git a/gr-digital/lib/header_format_default.cc 
b/gr-digital/lib/header_format_default.cc
new file mode 100644
index 0000000..1b7a60e
--- /dev/null
+++ b/gr-digital/lib/header_format_default.cc
@@ -0,0 +1,222 @@
+/* -*- c++ -*- */
+/* Copyright 2015-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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <iostream>
+#include <string.h>
+#include <volk/volk.h>
+#include <gnuradio/digital/header_format_default.h>
+#include <gnuradio/math.h>
+
+namespace gr {
+  namespace digital {
+
+    header_format_default::sptr
+    header_format_default::make(const std::string &access_code,
+                                int threshold)
+    {
+      return header_format_default::sptr
+        (new header_format_default(access_code, threshold));
+    }
+
+    header_format_default::header_format_default(const std::string 
&access_code,
+                                                 int threshold)
+      : header_format_base(),
+        d_data_reg(0), d_mask(0), d_threshold(0),
+        d_pkt_len(0), d_pkt_count(0), d_nbits(0)
+    {
+      if(!set_access_code(access_code)) {
+        throw std::runtime_error("header_format_default: Setting access code 
failed");
+      }
+
+      set_threshold(threshold);
+    }
+
+    header_format_default::~header_format_default()
+    {
+    }
+
+    bool
+    header_format_default::set_access_code(const std::string &access_code)
+    {
+      d_access_code_len = access_code.length();        // # of bits in the 
access code
+
+      if(access_code.size() > 64) {
+        return false;
+      }
+
+      // set len top bits to 1.
+      d_mask = ((~0ULL) >> (64 - d_access_code_len));
+
+      d_access_code = 0;
+      for(unsigned i = 0; i < d_access_code_len; i++) {
+        d_access_code = (d_access_code << 1) | (access_code[i] & 1);
+      }
+
+      return true;
+    }
+
+    unsigned long long
+    header_format_default::access_code() const
+    {
+      return d_access_code;
+    }
+
+    void
+    header_format_default::set_threshold(unsigned int thresh)
+    {
+      if(d_threshold > d_access_code_len) {
+        throw std::runtime_error("header_format_default: Cannot set threshold 
" \
+                                 "larger than the access code length.");
+      }
+      d_threshold = thresh;
+    }
+
+    unsigned int
+    header_format_default::threshold() const
+    {
+      return d_threshold;
+    }
+
+    bool
+    header_format_default::format(int nbytes_in,
+                                  const unsigned char *input,
+                                  pmt::pmt_t &output,
+                                  pmt::pmt_t &info)
+    {
+      uint8_t* bytes_out = (uint8_t*)volk_malloc(header_nbytes(),
+                                                 volk_get_alignment());
+
+      header_buffer header(bytes_out);
+      header.add_field64(d_access_code, d_access_code_len);
+      header.add_field16((uint16_t)(nbytes_in));
+      header.add_field16((uint16_t)(nbytes_in));
+
+      // Package output data into a PMT vector
+      output = pmt::init_u8vector(header_nbytes(), bytes_out);
+
+      // Creating the output pmt copies data; free our own here.
+      volk_free(bytes_out);
+
+      return true;
+    }
+
+    bool
+    header_format_default::parse(int nbits_in,
+                                 const unsigned char *input,
+                                 std::vector<pmt::pmt_t> &info,
+                                 int &nbits_processed)
+    {
+      nbits_processed = 0;
+
+      while(nbits_processed < nbits_in) {
+        switch(d_state) {
+       case STATE_SYNC_SEARCH:    // Look for the access code correlation
+         while(nbits_processed < nbits_in) {
+            // shift in new data
+            d_data_reg = (d_data_reg << 1) | ((input[nbits_processed++]) & 
0x1);
+
+            // compute hamming distance between desired access code and 
current data
+            uint64_t wrong_bits = 0;
+            uint64_t nwrong = d_threshold+1;
+
+            wrong_bits = (d_data_reg ^ d_access_code) & d_mask;
+            volk_64u_popcnt(&nwrong, wrong_bits);
+
+            if(nwrong <= d_threshold) {
+              enter_have_sync();
+              break;
+            }
+          }
+          break;
+
+       case STATE_HAVE_SYNC:
+         while(nbits_processed <= nbits_in) {    // Shift bits one at a time 
into header
+            d_hdr_reg.insert_bit(input[nbits_processed++]);
+            if(d_hdr_reg.length() == (header_nbits()-d_access_code_len)) {
+
+             // we have a full header, check to see if it has been received 
properly
+             if(header_ok()) {
+                int payload_len = header_payload();
+               enter_have_header(payload_len);
+                info.push_back(d_info);
+                return true;
+              }
+             else {
+               enter_search();    // bad header
+                return false;
+              }
+              break;
+            }
+          }
+          break;
+        }
+      }
+
+      return false;
+    }
+
+    size_t
+    header_format_default::header_nbits() const
+    {
+      return d_access_code_len + 8*2*sizeof(uint16_t);
+    }
+
+    inline void
+    header_format_default::enter_have_sync()
+    {
+      d_state = STATE_HAVE_SYNC;
+      d_hdr_reg.clear();
+    }
+
+    inline void
+    header_format_default::enter_have_header(int payload_len)
+    {
+      d_state = STATE_SYNC_SEARCH;
+      d_pkt_len = payload_len;
+      d_pkt_count = 0;
+    }
+
+    bool
+    header_format_default::header_ok()
+    {
+      // confirm that two copies of header info are identical
+      uint16_t len0 = d_hdr_reg.extract_field16(0, 16);
+      uint16_t len1 = d_hdr_reg.extract_field16(16, 16);
+      return (len0 ^ len1) == 0;
+    }
+
+    int
+    header_format_default::header_payload()
+    {
+      uint16_t len = d_hdr_reg.extract_field16(0, 16);
+
+      d_info = pmt::make_dict();
+      d_info = pmt::dict_add(d_info, pmt::intern("payload symbols"),
+                             pmt::from_long(8*len));
+      return static_cast<int>(len);
+    }
+
+  } /* namespace digital */
+} /* namespace gr */
diff --git a/gr-digital/lib/header_format_ofdm.cc 
b/gr-digital/lib/header_format_ofdm.cc
new file mode 100644
index 0000000..acaf53b
--- /dev/null
+++ b/gr-digital/lib/header_format_ofdm.cc
@@ -0,0 +1,180 @@
+/* -*- 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <volk/volk.h>
+#include <gnuradio/digital/header_format_ofdm.h>
+#include <gnuradio/digital/header_buffer.h>
+#include <gnuradio/digital/lfsr.h>
+
+namespace gr {
+  namespace digital {
+
+    header_format_ofdm::sptr
+    header_format_ofdm::make(const std::vector<std::vector<int> > 
&occupied_carriers,
+                             int n_syms,
+                             const std::string &len_key_name,
+                             const std::string &frame_key_name,
+                             const std::string &num_key_name,
+                             int bits_per_header_sym,
+                             int bits_per_payload_sym,
+                             bool scramble_header)
+    {
+      return header_format_ofdm::sptr
+        (new header_format_ofdm(occupied_carriers, n_syms,
+                                len_key_name, frame_key_name, num_key_name,
+                                bits_per_header_sym,
+                                bits_per_payload_sym,
+                                scramble_header));
+    }
+
+    header_format_ofdm::header_format_ofdm(const std::vector<std::vector<int> 
> &occupied_carriers,
+                                           int n_syms,
+                                           const std::string &len_key_name,
+                                           const std::string &frame_key_name,
+                                           const std::string &num_key_name,
+                                           int bits_per_header_sym,
+                                           int bits_per_payload_sym,
+                                           bool scramble_header)
+    : header_format_crc(len_key_name, num_key_name),
+      d_frame_key_name(pmt::intern(frame_key_name)),
+      d_occupied_carriers(occupied_carriers),
+      d_bits_per_payload_sym(bits_per_payload_sym)
+    {
+      d_header_len = 0;
+      for(int i = 0; i < n_syms; i++) {
+       d_header_len += occupied_carriers[i].size();
+      }
+
+      d_syms_per_set = 0;
+      for(unsigned i = 0; i < d_occupied_carriers.size(); i++) {
+        d_syms_per_set += d_occupied_carriers[i].size();
+      }
+
+      // Init scrambler mask
+      d_scramble_mask = std::vector<uint8_t>(header_nbits(), 0);
+      if(scramble_header) {
+       // These are just random values which already have OK PAPR:
+       gr::digital::lfsr shift_reg(0x8a, 0x6f, 7);
+       for(size_t i = 0; i < header_nbytes(); i++) {
+         for(int k = 0; k < bits_per_header_sym; k++) {
+           d_scramble_mask[i] ^= shift_reg.next_bit() << k;
+         }
+       }
+      }
+    }
+
+    header_format_ofdm::~header_format_ofdm()
+    {
+    }
+
+    bool
+    header_format_ofdm::format(int nbytes_in,
+                               const unsigned char *input,
+                               pmt::pmt_t &output,
+                               pmt::pmt_t &info)
+    {
+      bool ret_val = header_format_crc::format(nbytes_in, input,
+                                               output, info);
+
+      //size_t len;
+      //uint8_t *out = pmt::u8vector_writable_elements(output, len);
+      //for(size_t i = 0; i < len; i++) {
+      //       out[i] ^= d_scramble_mask[i];
+      //}
+
+      return ret_val;
+    }
+
+    bool
+    header_format_ofdm::parse(int nbits_in,
+                                 const unsigned char *input,
+                                 std::vector<pmt::pmt_t> &info,
+                                 int &nbits_processed)
+    {
+      int index = 0;
+      while(nbits_processed <= nbits_in) {
+        d_hdr_reg.insert_bit(input[nbits_processed++] ^ 
d_scramble_mask[index++]);
+        if(d_hdr_reg.length() == header_nbits()) {
+          if(header_ok()) {
+            int payload_len = header_payload();
+            enter_have_header(payload_len);
+            info.push_back(d_info);
+            d_hdr_reg.clear();
+            return true;
+          }
+          else {
+            d_hdr_reg.clear();
+            return false;
+          }
+          break;
+        }
+      }
+
+      return true;
+    }
+
+    size_t
+    header_format_ofdm::header_nbits() const
+    {
+      return d_header_len;
+    }
+
+    int
+    header_format_ofdm::header_payload()
+    {
+      uint32_t pkt = d_hdr_reg.extract_field32(0, 24, true);
+      uint16_t pktlen = static_cast<uint16_t>((pkt >> 8) & 0x0fff);
+      uint16_t pktnum = static_cast<uint16_t>((pkt >> 20) & 0x0fff);
+
+      // Convert num bytes to num complex symbols in payload
+      pktlen *= 8;
+      uint16_t pldlen = pktlen / d_bits_per_payload_sym;
+      if(pktlen % d_bits_per_payload_sym) {
+        pldlen++;
+      }
+
+      // frame_len = # of OFDM symbols in this frame
+      int framelen = pldlen / d_syms_per_set;
+      int k = 0;
+      int i = framelen * d_syms_per_set;
+      while(i < pldlen) {
+       framelen++;
+       //i += d_occupied_carriers[k++].size();
+        i += d_occupied_carriers[k].size();
+      }
+
+      d_info = pmt::make_dict();
+      d_info = pmt::dict_add(d_info, d_len_key_name,
+                             pmt::from_long(pldlen));
+      d_info = pmt::dict_add(d_info, d_num_key_name,
+                             pmt::from_long(pktnum));
+      d_info = pmt::dict_add(d_info, d_frame_key_name,
+                             pmt::from_long(framelen));
+      return static_cast<int>(pldlen);
+    }
+
+  } /* namespace digital */
+} /* namespace gr */
diff --git a/gr-digital/lib/packet_header_ofdm.cc 
b/gr-digital/lib/packet_header_ofdm.cc
index 7a95586..22d62df 100644
--- a/gr-digital/lib/packet_header_ofdm.cc
+++ b/gr-digital/lib/packet_header_ofdm.cc
@@ -1,18 +1,18 @@
 /* -*- c++ -*- */
 /* Copyright 2012 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,
@@ -148,4 +148,3 @@ namespace gr {
 
   } /* namespace digital */
 } /* namespace gr */
-
diff --git a/gr-digital/lib/protocol_formatter_async_impl.cc 
b/gr-digital/lib/protocol_formatter_async_impl.cc
new file mode 100644
index 0000000..83a2eed
--- /dev/null
+++ b/gr-digital/lib/protocol_formatter_async_impl.cc
@@ -0,0 +1,94 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2015-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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <volk/volk.h>
+#include <gnuradio/io_signature.h>
+#include "protocol_formatter_async_impl.h"
+#include <stdio.h>
+
+namespace gr {
+  namespace digital {
+
+    protocol_formatter_async::sptr
+    protocol_formatter_async::make(const header_format_base::sptr &format)
+    {
+      return gnuradio::get_initial_sptr
+        (new protocol_formatter_async_impl(format));
+    }
+
+    protocol_formatter_async_impl::protocol_formatter_async_impl(const 
header_format_base::sptr &format)
+      : block("protocol_formatter_async",
+              io_signature::make(0, 0, 0),
+              io_signature::make(0, 0, 0))
+    {
+      d_format = format;
+
+      d_in_port = pmt::mp("in");
+      d_hdr_port = pmt::mp("header");
+      d_pld_port = pmt::mp("payload");
+
+      message_port_register_in(d_in_port);
+      message_port_register_out(d_hdr_port);
+      message_port_register_out(d_pld_port);
+
+      set_msg_handler(d_in_port,
+                      boost::bind(&protocol_formatter_async_impl::append, this 
,_1) );
+    }
+
+    protocol_formatter_async_impl::~protocol_formatter_async_impl()
+    {
+    }
+
+    void
+    protocol_formatter_async_impl::append(pmt::pmt_t msg)
+    {
+      // extract input pdu
+      pmt::pmt_t meta(pmt::car(msg));
+      pmt::pmt_t input(pmt::cdr(msg));
+      pmt::pmt_t header, output;
+
+      size_t pkt_len = 0;
+      const uint8_t* bytes_in = pmt::u8vector_elements(input, pkt_len);
+
+      // Pad the payload with 0's
+      uint8_t* payload = (uint8_t*)volk_malloc(pkt_len*sizeof(uint8_t),
+                                               volk_get_alignment());
+      memcpy(payload, bytes_in, pkt_len*sizeof(uint8_t));
+      output = pmt::init_u8vector(pkt_len, payload);
+      volk_free(payload);
+
+      // Build the header from the input, metadata, and format
+      d_format->format(pkt_len, bytes_in, header, meta);
+
+      // Package and publish
+      pmt::pmt_t hdr_pdu = pmt::cons(meta, header);
+      pmt::pmt_t pld_pdu = pmt::cons(meta, output);
+      message_port_pub(d_hdr_port, hdr_pdu);
+      message_port_pub(d_pld_port, pld_pdu);
+    }
+
+  } /* namespace digital */
+} /* namespace gr */
diff --git a/gr-digital/lib/protocol_formatter_async_impl.h 
b/gr-digital/lib/protocol_formatter_async_impl.h
new file mode 100644
index 0000000..79c80de
--- /dev/null
+++ b/gr-digital/lib/protocol_formatter_async_impl.h
@@ -0,0 +1,50 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2015-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_PROTOCOL_FORMATTER_ASYNC_IMPL_H
+#define INCLUDED_DIGITAL_PROTOCOL_FORMATTER_ASYNC_IMPL_H
+
+#include <gnuradio/digital/protocol_formatter_async.h>
+
+namespace gr {
+  namespace digital {
+
+    class protocol_formatter_async_impl
+      : public protocol_formatter_async
+    {
+     private:
+      header_format_base::sptr d_format;
+
+      pmt::pmt_t d_in_port;
+      pmt::pmt_t d_hdr_port, d_pld_port;
+
+      void append(pmt::pmt_t msg);
+
+     public:
+      protocol_formatter_async_impl(const header_format_base::sptr &format);
+      ~protocol_formatter_async_impl();
+    };
+
+  } // namespace digital
+} // namespace gr
+
+#endif /* INCLUDED_DIGITAL_PROTOCOL_FORMATTER_ASYNC_IMPL_H */
diff --git a/gr-digital/lib/protocol_formatter_bb_impl.cc 
b/gr-digital/lib/protocol_formatter_bb_impl.cc
new file mode 100644
index 0000000..fcf2f66
--- /dev/null
+++ b/gr-digital/lib/protocol_formatter_bb_impl.cc
@@ -0,0 +1,118 @@
+/* -*- 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <volk/volk.h>
+#include <gnuradio/io_signature.h>
+#include "protocol_formatter_bb_impl.h"
+#include <stdio.h>
+
+namespace gr {
+  namespace digital {
+
+    protocol_formatter_bb::sptr
+    protocol_formatter_bb::make(const header_format_base::sptr &format,
+                                const std::string &len_tag_key)
+    {
+      return gnuradio::get_initial_sptr
+        (new protocol_formatter_bb_impl(format, len_tag_key));
+    }
+
+    protocol_formatter_bb_impl::protocol_formatter_bb_impl(const 
header_format_base::sptr &format,
+                                                           const std::string 
&len_tag_key)
+      : tagged_stream_block("protocol_formatter_bb",
+                            io_signature::make(1, 1, sizeof(char)),
+                            io_signature::make(1, 1, sizeof(char)),
+                            len_tag_key),
+        d_format(format)
+    {
+      set_output_multiple(d_format->header_nbytes());
+
+      // This is the worst case rate, because we don't know the true value, of 
course
+      set_relative_rate(d_format->header_nbytes());
+      set_tag_propagation_policy(TPP_DONT);
+    }
+
+    protocol_formatter_bb_impl::~protocol_formatter_bb_impl()
+    {
+    }
+
+    void
+    protocol_formatter_bb_impl::set_header_format(header_format_base::sptr 
&format)
+    {
+      gr::thread::scoped_lock guard(d_setlock);
+      d_format = format;
+    }
+
+    int
+    protocol_formatter_bb_impl::work(int noutput_items,
+                                     gr_vector_int &ninput_items,
+                                     gr_vector_const_void_star &input_items,
+                                     gr_vector_void_star &output_items)
+    {
+      gr::thread::scoped_lock guard(d_setlock);
+      unsigned char *out = (unsigned char *) output_items[0];
+      const unsigned char *in = (const unsigned char *) input_items[0];
+
+      // Not really sure what to do with these tags; extract them and
+      // plug them into the info dictionary?
+      //std::vector<tag_t> tags;
+      //get_tags_in_window(tags, 0, 0, ninput_items[0]);
+
+      pmt::pmt_t pmt_out;
+      pmt::pmt_t info = pmt::PMT_NIL;
+      if(!d_format->format(ninput_items[0], in, pmt_out, info)) {
+       GR_LOG_FATAL(d_logger, boost::format("header format returned false "
+                                             "(this shouldn't happen). 
Offending "
+                                             "header started at %1%") % 
nitems_read(0));
+       throw std::runtime_error("header format returned false.");
+      }
+
+      size_t len;
+      const uint8_t *data = pmt::u8vector_elements(pmt_out, len);
+      if(len != d_format->header_nbytes()) {
+        throw std::runtime_error("Header format got wrong size header");
+      }
+      memcpy(out, data, len);
+
+      if(pmt::is_dict(info)) {
+        std::vector<tag_t> mtags;
+        pmt::pmt_t mkeys = pmt::dict_keys(info);
+        pmt::pmt_t mvals = pmt::dict_values(info);
+        for(size_t i = 0; i < pmt::length(mkeys); i++) {
+          tag_t tag;
+          tag.offset = nitems_written(0);
+          tag.key = pmt::nth(i, mkeys);
+          tag.value = pmt::nth(i, mvals);
+          tag.srcid = alias_pmt();
+          add_item_tag(0, tag);
+        }
+      }
+
+      return len;
+    }
+
+  } /* namespace digital */
+} /* namespace gr */
diff --git a/gr-digital/lib/protocol_formatter_bb_impl.h 
b/gr-digital/lib/protocol_formatter_bb_impl.h
new file mode 100644
index 0000000..c7c86e4
--- /dev/null
+++ b/gr-digital/lib/protocol_formatter_bb_impl.h
@@ -0,0 +1,56 @@
+/* -*- 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_PROTOCOL_FORMATTER_BB_IMPL_H
+#define INCLUDED_DIGITAL_PROTOCOL_FORMATTER_BB_IMPL_H
+
+#include <gnuradio/digital/protocol_formatter_bb.h>
+
+namespace gr {
+  namespace digital {
+
+    class protocol_formatter_bb_impl : public protocol_formatter_bb
+    {
+     private:
+      header_format_base::sptr d_format;
+
+     public:
+      protocol_formatter_bb_impl(const header_format_base::sptr &format,
+                                 const std::string &len_tag_key);
+      ~protocol_formatter_bb_impl();
+
+      void set_header_format(header_format_base::sptr &format);
+
+      void remove_length_tags(const std::vector<std::vector<tag_t> > &tags) {};
+      int calculate_output_stream_length(const gr_vector_int &ninput_items) {
+        return d_format->header_nbytes(); };
+
+      int work(int noutput_items,
+               gr_vector_int &ninput_items,
+               gr_vector_const_void_star &input_items,
+               gr_vector_void_star &output_items);
+    };
+
+  } // namespace digital
+} // namespace gr
+
+#endif /* INCLUDED_DIGITAL_PROTOCOL_FORMATTER_BB_IMPL_H */
diff --git a/gr-digital/lib/protocol_parser_b_impl.cc 
b/gr-digital/lib/protocol_parser_b_impl.cc
new file mode 100644
index 0000000..642fcae
--- /dev/null
+++ b/gr-digital/lib/protocol_parser_b_impl.cc
@@ -0,0 +1,83 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2015-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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "protocol_parser_b_impl.h"
+#include <gnuradio/io_signature.h>
+#include <stdexcept>
+#include <volk/volk.h>
+#include <iostream>
+
+namespace gr {
+  namespace digital {
+
+    protocol_parser_b::sptr
+    protocol_parser_b::make(const header_format_base::sptr &format)
+    {
+      return gnuradio::get_initial_sptr
+       (new protocol_parser_b_impl(format));
+    }
+
+
+    protocol_parser_b_impl::protocol_parser_b_impl(const 
header_format_base::sptr &format)
+      : sync_block("protocol_parser_b",
+                   io_signature::make(1, 1, sizeof(char)),
+                   io_signature::make(0, 0, 0))
+    {
+      d_format = format;
+
+      d_out_port = pmt::mp("info");
+      message_port_register_out(d_out_port);
+    }
+
+    protocol_parser_b_impl::~protocol_parser_b_impl()
+    {
+    }
+
+    int
+    protocol_parser_b_impl::work(int noutput_items,
+                                 gr_vector_const_void_star &input_items,
+                                 gr_vector_void_star &output_items)
+    {
+      const unsigned char *in = (const unsigned char*)input_items[0];
+
+      int count = 0;
+      std::vector<pmt::pmt_t> info;
+      bool ret = d_format->parse(noutput_items, in, info, count);
+
+      if(ret) {
+        for(size_t i = 0; i < info.size(); i++) {
+          message_port_pub(d_out_port, info[i]);
+        }
+      }
+      else {
+        message_port_pub(d_out_port, pmt::PMT_F);
+      }
+
+      return count;
+    }
+
+  } /* namespace digital */
+} /* namespace gr */
diff --git a/gr-digital/lib/protocol_parser_b_impl.h 
b/gr-digital/lib/protocol_parser_b_impl.h
new file mode 100644
index 0000000..7b09313
--- /dev/null
+++ b/gr-digital/lib/protocol_parser_b_impl.h
@@ -0,0 +1,52 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2015-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_PROTOCOL_PARSER_B_IMPL_H
+#define INCLUDED_DIGITAL_PROTOCOL_PARSER_B_IMPL_H
+
+#include <gnuradio/digital/protocol_parser_b.h>
+
+namespace gr {
+  namespace digital {
+
+    class protocol_parser_b_impl : public protocol_parser_b
+    {
+     private:
+      header_format_base::sptr d_format;
+      pmt::pmt_t d_out_port;
+
+     public:
+      protocol_parser_b_impl(const header_format_base::sptr &format);
+      ~protocol_parser_b_impl();
+
+      void set_threshold(unsigned int thresh);
+      unsigned int threshold() const;
+
+      int work(int noutput_items,
+               gr_vector_const_void_star &input_items,
+               gr_vector_void_star &output_items);
+    };
+
+  } // namespace digital
+} // namespace gr
+
+#endif /* INCLUDED_DIGITAL_PROTOCOL_PARSER_B_IMPL_H */
diff --git a/gr-digital/swig/packet_header.i b/gr-digital/lib/qa_digital.cc
similarity index 57%
copy from gr-digital/swig/packet_header.i
copy to gr-digital/lib/qa_digital.cc
index 7c06d19..2888d21 100644
--- a/gr-digital/swig/packet_header.i
+++ b/gr-digital/lib/qa_digital.cc
@@ -1,34 +1,41 @@
-/* -*- c++ -*- */
 /*
- * Copyright 2012 Free Software Foundation, Inc.
- * 
+ * Copyright 2014 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.
  */
 
-%template(packet_header_default_sptr) 
boost::shared_ptr<gr::digital::packet_header_default>;
-%pythoncode %{
-packet_header_default_sptr.__repr__ = lambda self: "<packet_header_default>"
-packet_header_default = packet_header_default .make;
-%}
+/*
+ * This class gathers together all the test cases for the gr-digital
+ * directory into a single test suite.  As you create new test cases,
+ * add them here.
+ */
+
+#include "qa_digital.h"
+#include "qa_header_format.h"
+#include "qa_header_buffer.h"
+
+CppUnit::TestSuite *
+qa_digital::suite()
+{
+  CppUnit::TestSuite *s = new CppUnit::TestSuite("gr-digital");
 
-%template(packet_header_ofdm_sptr) 
boost::shared_ptr<gr::digital::packet_header_ofdm>;
-%pythoncode %{
-packet_header_ofdm_sptr.__repr__ = lambda self: "<packet_header_ofdm>"
-packet_header_ofdm = packet_header_ofdm .make;
-%}
+  s->addTest(qa_header_format::suite());
+  s->addTest(qa_header_buffer::suite());
 
+  return s;
+}
diff --git a/gr-digital/swig/packet_header.i b/gr-digital/lib/qa_digital.h
similarity index 59%
copy from gr-digital/swig/packet_header.i
copy to gr-digital/lib/qa_digital.h
index 7c06d19..c5f3592 100644
--- a/gr-digital/swig/packet_header.i
+++ b/gr-digital/lib/qa_digital.h
@@ -1,34 +1,38 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2012 Free Software Foundation, Inc.
- * 
+ * Copyright 2014 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.
  */
 
-%template(packet_header_default_sptr) 
boost::shared_ptr<gr::digital::packet_header_default>;
-%pythoncode %{
-packet_header_default_sptr.__repr__ = lambda self: "<packet_header_default>"
-packet_header_default = packet_header_default .make;
-%}
+#ifndef _QA_GR_DIGITAL_H_
+#define _QA_GR_DIGITAL_H_
 
-%template(packet_header_ofdm_sptr) 
boost::shared_ptr<gr::digital::packet_header_ofdm>;
-%pythoncode %{
-packet_header_ofdm_sptr.__repr__ = lambda self: "<packet_header_ofdm>"
-packet_header_ofdm = packet_header_ofdm .make;
-%}
+#include <gnuradio/attributes.h>
+#include <cppunit/TestSuite.h>
 
+//! collect all the tests for the gr-digital directory
+
+class __GR_ATTR_EXPORT qa_digital
+{
+ public:
+  //! return suite of tests for all of gr-digital directory
+  static CppUnit::TestSuite *suite();
+};
+
+#endif /* _QA_GR_DIGITAL_H_ */
diff --git a/gr-digital/lib/qa_header_buffer.cc 
b/gr-digital/lib/qa_header_buffer.cc
new file mode 100644
index 0000000..321e901
--- /dev/null
+++ b/gr-digital/lib/qa_header_buffer.cc
@@ -0,0 +1,364 @@
+/* -*- 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <volk/volk.h>
+#include <gnuradio/attributes.h>
+
+#include <stdio.h>
+#include <cppunit/TestAssert.h>
+
+#include "qa_header_buffer.h"
+#include <gnuradio/digital/header_buffer.h>
+
+void
+qa_header_buffer::test_add8()
+{
+  size_t len = sizeof(uint8_t);
+  uint8_t *buf = (uint8_t*)volk_malloc(len, volk_get_alignment());
+
+  gr::digital::header_buffer header(buf);
+  header.add_field8(0xAF);
+
+  CPPUNIT_ASSERT_EQUAL(len, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0xAF, header.header()[0]);
+
+  header.clear();
+  CPPUNIT_ASSERT_EQUAL((size_t)0, header.length());
+
+  volk_free(buf);
+}
+
+void
+qa_header_buffer::test_add16()
+{
+  size_t len = sizeof(uint16_t);
+  uint8_t *buf = (uint8_t*)volk_malloc(len, volk_get_alignment());
+
+  uint16_t data = 0xAF5C;
+
+  gr::digital::header_buffer header(buf);
+  header.add_field16(data);
+
+  // Test standard add of a uint16
+  CPPUNIT_ASSERT_EQUAL(len, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0xAF, header.header()[0]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[1]);
+
+  // Clear; test to make sure it's clear
+  header.clear();
+  CPPUNIT_ASSERT_EQUAL((size_t)0, header.length());
+
+  // Test adding some subset of bits (must be a byte boundary)
+  header.add_field16(data, 8);
+  CPPUNIT_ASSERT_EQUAL((size_t)1, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[0]);
+  header.clear();
+
+  // Test adding and byte swapping
+  header.add_field16(data, 16, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)2, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[0]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0xAF, header.header()[1]);
+  header.clear();
+
+  // Test adding some subset of bits and byte swapping
+  header.add_field16(data, 8, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)1, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[0]);
+  header.clear();
+
+  volk_free(buf);
+}
+
+void
+qa_header_buffer::test_add32()
+{
+  size_t len = sizeof(uint32_t);
+  uint8_t *buf = (uint8_t*)volk_malloc(len, volk_get_alignment());
+
+  uint32_t data = 0xAF5C7654;
+
+  gr::digital::header_buffer header(buf);
+  header.add_field32(data);
+
+  // Test standard add of a uint32
+  CPPUNIT_ASSERT_EQUAL(len, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0xAF, header.header()[0]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[1]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x76, header.header()[2]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[3]);
+
+  // Clear; test to make sure it's clear
+  header.clear();
+  CPPUNIT_ASSERT_EQUAL((size_t)0, header.length());
+
+  // Test adding some subset of bits (must be a byte boundary)
+  header.add_field32(data, 8);
+  CPPUNIT_ASSERT_EQUAL((size_t)1, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[0]);
+  header.clear();
+
+  // Test adding and byte swapping
+  header.add_field32(data, 32, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)4, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[0]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x76, header.header()[1]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[2]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0xAF, header.header()[3]);
+  header.clear();
+
+  // Test adding some subset of bits and byte swapping
+  header.add_field32(data, 24, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)3, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[0]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x76, header.header()[1]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[2]);
+  header.clear();
+
+  volk_free(buf);
+}
+
+void
+qa_header_buffer::test_add64()
+{
+  size_t len = sizeof(uint64_t);
+  uint8_t *buf = (uint8_t*)volk_malloc(len, volk_get_alignment());
+
+  uint64_t data = 0xAF5C765432104567;
+
+  gr::digital::header_buffer header(buf);
+  header.add_field64(data);
+
+  // Test standard add of a uint64
+  CPPUNIT_ASSERT_EQUAL(len, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0xAF, header.header()[0]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[1]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x76, header.header()[2]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[3]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x32, header.header()[4]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x10, header.header()[5]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x45, header.header()[6]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x67, header.header()[7]);
+
+  // Clear; test to make sure it's clear
+  header.clear();
+  CPPUNIT_ASSERT_EQUAL((size_t)0, header.length());
+
+  // Test adding some subset of bits (must be a byte boundary)
+  header.add_field64(data, 48);
+  CPPUNIT_ASSERT_EQUAL((size_t)6, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x76, header.header()[0]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[1]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x32, header.header()[2]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x10, header.header()[3]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x45, header.header()[4]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x67, header.header()[5]);
+  header.clear();
+
+  // Test adding and byte swapping
+  header.add_field64(data, 64, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)8, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x67, header.header()[0]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x45, header.header()[1]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x10, header.header()[2]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x32, header.header()[3]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[4]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x76, header.header()[5]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x5C, header.header()[6]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0xAF, header.header()[7]);
+  header.clear();
+
+  // Test adding some subset of bits and byte swapping
+  header.add_field64(data, 40, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)5, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x67, header.header()[0]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x45, header.header()[1]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x10, header.header()[2]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x32, header.header()[3]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[4]);
+  header.clear();
+
+  volk_free(buf);
+}
+
+void
+qa_header_buffer::test_add_many()
+{
+  size_t len = (32+64+8+16+32)/8;
+  uint8_t *buf = (uint8_t*)volk_malloc(len, volk_get_alignment());
+
+  gr::digital::header_buffer header(buf);
+  header.add_field32(0x01234567);
+  header.add_field64(0x89ABCDEFFEDCBA98);
+  header.add_field8(0x76);
+  header.add_field16(0x5432);
+  header.add_field32(0x10012345);
+
+  CPPUNIT_ASSERT_EQUAL(len, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x01, header.header()[0]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x23, header.header()[1]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x45, header.header()[2]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x67, header.header()[3]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x89, header.header()[4]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0xAB, header.header()[5]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0xCD, header.header()[6]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0xEF, header.header()[7]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0xFE, header.header()[8]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0xDC, header.header()[9]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0xBA, header.header()[10]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x98, header.header()[11]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x76, header.header()[12]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x54, header.header()[13]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x32, header.header()[14]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x10, header.header()[15]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x01, header.header()[16]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x23, header.header()[17]);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x45, header.header()[18]);
+}
+
+void
+qa_header_buffer::test_extract8()
+{
+  gr::digital::header_buffer header;
+
+  uint64_t data = 0x0123456701234567;
+
+  // Packed format: 0x80C4A2E680C4A2E6
+
+  volk_64u_byteswap(&data, 1);
+  for(int i = 0; i < 64; i++) {
+    header.insert_bit((data >> i) & 0x01);
+  }
+
+  uint8_t x0 = header.extract_field8(0);
+  uint8_t x1 = header.extract_field8(12, 8);
+  uint8_t x2 = header.extract_field8(12, 4);
+
+  CPPUNIT_ASSERT_EQUAL((size_t)64, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x80, x0);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x4A, x1);
+  CPPUNIT_ASSERT_EQUAL((uint8_t)0x04, x2);
+}
+
+void
+qa_header_buffer::test_extract16()
+{
+  gr::digital::header_buffer header;
+
+  uint64_t data = 0x0123456701234567;
+
+  // Packed format: 0x80C4A2E680C4A2E6
+
+  volk_64u_byteswap(&data, 1);
+  for(int i = 0; i < 64; i++) {
+    header.insert_bit((data >> i) & 0x01);
+  }
+
+  uint16_t x0 = header.extract_field16(0);
+  uint16_t x1 = header.extract_field16(12, 16);
+  uint16_t x2 = header.extract_field16(12, 12);
+
+  CPPUNIT_ASSERT_EQUAL((size_t)64, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint16_t)0x80C4, x0);
+  CPPUNIT_ASSERT_EQUAL((uint16_t)0x4A2E, x1);
+  CPPUNIT_ASSERT_EQUAL((uint16_t)0x04A2, x2);
+}
+
+void
+qa_header_buffer::test_extract32()
+{
+  gr::digital::header_buffer header;
+
+  uint64_t data = 0x0123456701234567;
+
+  // Packed format: 0x80C4A2E680C4A2E6
+
+  volk_64u_byteswap(&data, 1);
+  for(int i = 0; i < 64; i++) {
+    header.insert_bit((data >> i) & 0x01);
+  }
+
+  uint32_t x0 = header.extract_field32(0);
+  uint32_t x1 = header.extract_field32(12, 32);
+  uint32_t x2 = header.extract_field32(12, 24);
+
+  CPPUNIT_ASSERT_EQUAL((size_t)64, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint32_t)0x80C4A2E6, x0);
+  CPPUNIT_ASSERT_EQUAL((uint32_t)0x4A2E680C, x1);
+  CPPUNIT_ASSERT_EQUAL((uint32_t)0x004A2E68, x2);
+}
+
+void
+qa_header_buffer::test_extract64()
+{
+  gr::digital::header_buffer header;
+
+  uint64_t data = 0x0123456701234567;
+
+  // Packed format: 0x80C4A2E680C4A2E6
+
+  volk_64u_byteswap(&data, 1);
+  for(int i = 0; i < 64; i++) {
+    header.insert_bit((data >> i) & 0x01);
+  }
+
+  uint64_t x0 = header.extract_field64(0);
+  uint64_t x1 = header.extract_field64(0, 32);
+  uint64_t x2 = header.extract_field64(0, 44);
+
+  CPPUNIT_ASSERT_EQUAL((size_t)64, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint64_t)0x80C4A2E680C4A2E6, x0);
+  CPPUNIT_ASSERT_EQUAL((uint64_t)0x0000000080C4A2E6, x1);
+  CPPUNIT_ASSERT_EQUAL((uint64_t)0x0000080C4A2E680C, x2);
+}
+
+void
+qa_header_buffer::test_extract_many()
+{
+  gr::digital::header_buffer header;
+
+  uint64_t data = 0x0123456701234567;
+
+  // Packed format: 0x80C4A2E680C4A2E6
+
+  volk_64u_byteswap(&data, 1);
+  for(int i = 0; i < 64; i++) {
+    header.insert_bit((data >> i) & 0x01);
+  }
+
+  uint64_t x0 = header.extract_field64(0);
+  uint16_t x1 = header.extract_field16(28, 12);
+  uint32_t x2 = header.extract_field32(40, 21);
+  uint16_t x3 = header.extract_field16(1, 12);
+  uint8_t  x4 = header.extract_field8 (7, 5);
+
+  CPPUNIT_ASSERT_EQUAL((size_t)64, header.length());
+  CPPUNIT_ASSERT_EQUAL((uint64_t)0x80C4A2E680C4A2E6, x0);
+  CPPUNIT_ASSERT_EQUAL((uint16_t)0x0680, x1);
+  CPPUNIT_ASSERT_EQUAL((uint32_t)0x0018945C, x2);
+  CPPUNIT_ASSERT_EQUAL((uint16_t)0x0018, x3);
+  CPPUNIT_ASSERT_EQUAL((uint8_t) 0x0C, x4);
+}
diff --git a/gr-digital/lib/qa_header_buffer.h 
b/gr-digital/lib/qa_header_buffer.h
new file mode 100644
index 0000000..48ab086
--- /dev/null
+++ b/gr-digital/lib/qa_header_buffer.h
@@ -0,0 +1,59 @@
+/* -*- 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 _QA_DIGITAL_HEADER_BUFFER_H_
+#define _QA_DIGITAL_HEADER_BUFFER_H_
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+class qa_header_buffer : public CppUnit::TestCase
+{
+  CPPUNIT_TEST_SUITE(qa_header_buffer);
+  CPPUNIT_TEST(test_add8);
+  CPPUNIT_TEST(test_add16);
+  CPPUNIT_TEST(test_add32);
+  CPPUNIT_TEST(test_add64);
+  CPPUNIT_TEST(test_add_many);
+
+  CPPUNIT_TEST(test_extract8);
+  CPPUNIT_TEST(test_extract16);
+  CPPUNIT_TEST(test_extract32);
+  CPPUNIT_TEST(test_extract64);
+  CPPUNIT_TEST(test_extract_many);
+  CPPUNIT_TEST_SUITE_END();
+
+ private:
+  void test_add8();
+  void test_add16();
+  void test_add32();
+  void test_add64();
+  void test_add_many();
+
+  void test_extract8();
+  void test_extract16();
+  void test_extract32();
+  void test_extract64();
+  void test_extract_many();
+};
+
+#endif /* _QA_DIGITAL_HEADER_BUFFER_H_ */
diff --git a/gr-digital/lib/qa_header_format.cc 
b/gr-digital/lib/qa_header_format.cc
new file mode 100644
index 0000000..b06a2dd
--- /dev/null
+++ b/gr-digital/lib/qa_header_format.cc
@@ -0,0 +1,265 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2015-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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gnuradio/attributes.h>
+
+#include <stdio.h>
+#include <cmath>
+#include <volk/volk.h>
+#include <gnuradio/expj.h>
+#include <cppunit/TestAssert.h>
+
+#include "qa_header_format.h"
+#include <gnuradio/digital/header_format_counter.h>
+#include <gnuradio/digital/header_format_default.h>
+#include <gnuradio/blocks/unpack_k_bits.h>
+
+void
+qa_header_format::test_default_format()
+{
+  static const int N = 4800;
+  int upper8 = (N >> 8) & 0xFF;
+  int lower8 = N & 0xFF;
+
+  std::string ac = "1010101010101010"; //0xAAAA
+  unsigned char *data = (unsigned char*)volk_malloc(N*sizeof(unsigned char),
+                                                    volk_get_alignment());
+  srand (time(NULL));
+  for(unsigned int i = 0; i < N; i++) {
+    data[i] = rand() % 256;
+  }
+
+  gr::digital::header_format_default::sptr hdr_format;
+  hdr_format = gr::digital::header_format_default::make(ac, 0);
+
+  pmt::pmt_t output;
+  pmt::pmt_t info = pmt::make_dict();
+
+  bool ret = hdr_format->format(N, data, output, info);
+  size_t length = pmt::length(output);
+
+  CPPUNIT_ASSERT(ret);
+  CPPUNIT_ASSERT_EQUAL(length, hdr_format->header_nbytes());
+  CPPUNIT_ASSERT_EQUAL(8*length, hdr_format->header_nbits());
+
+  // Test access code formatted correctly
+  unsigned char h0 = pmt::u8vector_ref(output, 0);
+  unsigned char h1 = pmt::u8vector_ref(output, 1);
+  CPPUNIT_ASSERT_EQUAL(0xAA, (int)h0);
+  CPPUNIT_ASSERT_EQUAL(0xAA, (int)h1);
+
+  // Test upper and lower portion of length field, repeated twice
+  unsigned char h2 = pmt::u8vector_ref(output, 2);
+  unsigned char h3 = pmt::u8vector_ref(output, 3);
+  unsigned char h4 = pmt::u8vector_ref(output, 4);
+  unsigned char h5 = pmt::u8vector_ref(output, 5);
+  CPPUNIT_ASSERT_EQUAL(upper8, (int)h2);
+  CPPUNIT_ASSERT_EQUAL(lower8, (int)h3);
+  CPPUNIT_ASSERT_EQUAL(upper8, (int)h4);
+  CPPUNIT_ASSERT_EQUAL(lower8, (int)h5);
+
+  volk_free(data);
+}
+
+
+void
+qa_header_format::test_default_parse()
+{
+  static const int nbytes = 106;
+  static const int nbits = 8*nbytes;
+  unsigned char *bytes = (unsigned char*)volk_malloc(nbytes*sizeof(unsigned 
char),
+                                                     volk_get_alignment());
+  unsigned char *bits = (unsigned char*)volk_malloc(nbits*sizeof(unsigned 
char),
+                                                    volk_get_alignment());
+
+  srand(time(NULL));
+
+  // Fill bytes with random values
+  for(unsigned int i = 0; i < nbytes; i++) {
+    bytes[i] = rand() % 256;
+  }
+
+  int index = 0;
+  bytes[index+0] = 0xAA;
+  bytes[index+1] = 0xAA;
+  bytes[index+2] = 0x00;
+  bytes[index+3] = 0x64;
+  bytes[index+4] = 0x00;
+  bytes[index+5] = 0x64;
+
+  gr::blocks::kernel::unpack_k_bits unpacker = 
gr::blocks::kernel::unpack_k_bits(8);
+  unpacker.unpack(bits, bytes, nbytes);
+
+  std::string ac = "1010101010101010"; //0xAAAA
+  gr::digital::header_format_default::sptr hdr_format;
+  hdr_format = gr::digital::header_format_default::make(ac, 0);
+
+  int count = 0;
+  std::vector<pmt::pmt_t> info;
+  bool ret = hdr_format->parse(nbits, bits, info, count);
+
+  CPPUNIT_ASSERT(ret);
+  CPPUNIT_ASSERT_EQUAL((size_t)1, info.size());
+
+  pmt::pmt_t dict = info[0];
+  int payload_bits = pmt::to_long(pmt::dict_ref(dict, pmt::intern("payload 
symbols"),
+                                                pmt::from_long(-1)));
+
+  int hdr_bits = (int)hdr_format->header_nbits();
+  int expected_bits = nbits - hdr_bits;
+  CPPUNIT_ASSERT_EQUAL(expected_bits, payload_bits);
+
+  volk_free(bytes);
+  volk_free(bits);
+}
+
+void
+qa_header_format::test_counter_format()
+{
+  static const int N = 4800;
+  int upper8 = (N >> 8) & 0xFF;
+  int lower8 = N & 0xFF;
+
+  std::string ac = "1010101010101010"; //0xAAAA
+  unsigned char *data = (unsigned char*)volk_malloc(N*sizeof(unsigned char),
+                                                    volk_get_alignment());
+  srand (time(NULL));
+  for(unsigned int i = 0; i < N; i++) {
+    data[i] = rand() % 256;
+  }
+
+  uint16_t expected_bps = 2;
+  gr::digital::header_format_counter::sptr hdr_format;
+  hdr_format = gr::digital::header_format_counter::make(ac, 0, expected_bps);
+
+  pmt::pmt_t output;
+  pmt::pmt_t info = pmt::make_dict();
+
+  bool ret = hdr_format->format(N, data, output, info);
+  size_t length = pmt::length(output);
+
+  CPPUNIT_ASSERT(ret);
+  CPPUNIT_ASSERT_EQUAL(length, hdr_format->header_nbytes());
+  CPPUNIT_ASSERT_EQUAL(8*length, hdr_format->header_nbits());
+
+  // Test access code formatted correctly
+  unsigned char h0 = pmt::u8vector_ref(output, 0);
+  unsigned char h1 = pmt::u8vector_ref(output, 1);
+  CPPUNIT_ASSERT_EQUAL(0xAA, (int)h0);
+  CPPUNIT_ASSERT_EQUAL(0xAA, (int)h1);
+
+  // Test upper and lower portion of length field, repeated twice
+  unsigned char h2 = pmt::u8vector_ref(output, 2);
+  unsigned char h3 = pmt::u8vector_ref(output, 3);
+  unsigned char h4 = pmt::u8vector_ref(output, 4);
+  unsigned char h5 = pmt::u8vector_ref(output, 5);
+  CPPUNIT_ASSERT_EQUAL(upper8, (int)h2);
+  CPPUNIT_ASSERT_EQUAL(lower8, (int)h3);
+  CPPUNIT_ASSERT_EQUAL(upper8, (int)h4);
+  CPPUNIT_ASSERT_EQUAL(lower8, (int)h5);
+
+  uint16_t h6 = (uint16_t)pmt::u8vector_ref(output, 6);
+  uint16_t h7 = (uint16_t)pmt::u8vector_ref(output, 7);
+  uint16_t bps = ((h6 << 8) & 0xFF00) | (h7 & 0x00FF);
+  CPPUNIT_ASSERT_EQUAL(expected_bps, bps);
+
+  uint16_t h8 = pmt::u8vector_ref(output, 8);
+  uint16_t h9 = pmt::u8vector_ref(output, 9);
+  uint16_t counter = ((h8 << 8) & 0xFF00) | (h9 & 0x00FF);
+  CPPUNIT_ASSERT_EQUAL((uint16_t)0, counter);
+
+  // Run another format to increment the counter to 1 and test.
+  ret = hdr_format->format(N, data, output, info);
+  h8 = pmt::u8vector_ref(output, 8);
+  h9 = pmt::u8vector_ref(output, 9);
+  counter = ((h8 << 8) & 0xFF00) | (h9 & 0x00FF);
+  CPPUNIT_ASSERT_EQUAL((uint16_t)1, counter);
+
+  volk_free(data);
+}
+
+
+void
+qa_header_format::test_counter_parse()
+{
+  static const int nbytes = 110;
+  static const int nbits = 8*nbytes;
+  unsigned char *bytes = (unsigned char*)volk_malloc(nbytes*sizeof(unsigned 
char),
+                                                     volk_get_alignment());
+  unsigned char *bits = (unsigned char*)volk_malloc(nbits*sizeof(unsigned 
char),
+                                                    volk_get_alignment());
+
+  srand(time(NULL));
+
+  // Fill bytes with random values
+  for(unsigned int i = 0; i < nbytes; i++) {
+    bytes[i] = rand() % 256;
+  }
+
+  int index = 0;
+  bytes[index+0] = 0xAA;
+  bytes[index+1] = 0xAA;
+  bytes[index+2] = 0x00;
+  bytes[index+3] = 0x64;
+  bytes[index+4] = 0x00;
+  bytes[index+5] = 0x64;
+  bytes[index+6] = 0x00;
+  bytes[index+7] = 0x02;
+  bytes[index+8] = 0x00;
+  bytes[index+9] = 0x00;
+
+  gr::blocks::kernel::unpack_k_bits unpacker = 
gr::blocks::kernel::unpack_k_bits(8);
+  unpacker.unpack(bits, bytes, nbytes);
+
+  uint16_t expected_bps = 2;
+  std::string ac = "1010101010101010"; //0xAAAA
+  gr::digital::header_format_counter::sptr hdr_format;
+  hdr_format = gr::digital::header_format_counter::make(ac, 0, expected_bps);
+
+  int count = 0;
+  std::vector<pmt::pmt_t> info;
+  bool ret = hdr_format->parse(nbits, bits, info, count);
+
+  CPPUNIT_ASSERT(ret);
+  CPPUNIT_ASSERT_EQUAL((size_t)1, info.size());
+
+  pmt::pmt_t dict = info[0];
+  int payload_syms = pmt::to_long(pmt::dict_ref(dict, pmt::intern("payload 
symbols"),
+                                                pmt::from_long(-1)));
+  int bps = pmt::to_long(pmt::dict_ref(dict, pmt::intern("bps"),
+                                       pmt::from_long(-1)));
+  int counter = pmt::to_long(pmt::dict_ref(dict, pmt::intern("counter"),
+                                           pmt::from_long(-1)));
+
+  int hdr_bits = (int)hdr_format->header_nbits();
+  int expected_bits = nbits - hdr_bits;
+  CPPUNIT_ASSERT_EQUAL(expected_bits, payload_syms * bps);
+  CPPUNIT_ASSERT_EQUAL(expected_bps, (uint16_t)bps);
+  CPPUNIT_ASSERT_EQUAL(0, counter);
+
+  volk_free(bytes);
+  volk_free(bits);
+}
diff --git a/gr-digital/swig/packet_header.i b/gr-digital/lib/qa_header_format.h
similarity index 51%
copy from gr-digital/swig/packet_header.i
copy to gr-digital/lib/qa_header_format.h
index 7c06d19..281e8f4 100644
--- a/gr-digital/swig/packet_header.i
+++ b/gr-digital/lib/qa_header_format.h
@@ -1,34 +1,47 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2012 Free Software Foundation, Inc.
- * 
+ * Copyright 2015-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.
  */
 
-%template(packet_header_default_sptr) 
boost::shared_ptr<gr::digital::packet_header_default>;
-%pythoncode %{
-packet_header_default_sptr.__repr__ = lambda self: "<packet_header_default>"
-packet_header_default = packet_header_default .make;
-%}
+#ifndef _QA_DIGITAL_HEADER_FORMAT_H_
+#define _QA_DIGITAL_HEADER_FORMAT_H_
 
-%template(packet_header_ofdm_sptr) 
boost::shared_ptr<gr::digital::packet_header_ofdm>;
-%pythoncode %{
-packet_header_ofdm_sptr.__repr__ = lambda self: "<packet_header_ofdm>"
-packet_header_ofdm = packet_header_ofdm .make;
-%}
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
 
+class qa_header_format : public CppUnit::TestCase
+{
+  CPPUNIT_TEST_SUITE(qa_header_format);
+  CPPUNIT_TEST(test_default_format);
+  CPPUNIT_TEST(test_default_parse);
+  CPPUNIT_TEST(test_counter_format);
+  CPPUNIT_TEST(test_counter_parse);
+  CPPUNIT_TEST_SUITE_END();
+
+ private:
+  void test_default_format();
+  void test_default_parse();
+  void test_default_parse_soft();
+  void test_counter_format();
+  void test_counter_parse();
+  void test_counter_parse_soft();
+};
+
+#endif /* _QA_DIGITAL_HEADER_FORMAT_H_ */
diff --git a/gr-digital/swig/packet_header.i b/gr-digital/lib/test_gr_digital.cc
similarity index 53%
copy from gr-digital/swig/packet_header.i
copy to gr-digital/lib/test_gr_digital.cc
index 7c06d19..7a6049d 100644
--- a/gr-digital/swig/packet_header.i
+++ b/gr-digital/lib/test_gr_digital.cc
@@ -1,34 +1,48 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2012 Free Software Foundation, Inc.
- * 
+ * Copyright 2014 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.
  */
 
-%template(packet_header_default_sptr) 
boost::shared_ptr<gr::digital::packet_header_default>;
-%pythoncode %{
-packet_header_default_sptr.__repr__ = lambda self: "<packet_header_default>"
-packet_header_default = packet_header_default .make;
-%}
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 
-%template(packet_header_ofdm_sptr) 
boost::shared_ptr<gr::digital::packet_header_ofdm>;
-%pythoncode %{
-packet_header_ofdm_sptr.__repr__ = lambda self: "<packet_header_ofdm>"
-packet_header_ofdm = packet_header_ofdm .make;
-%}
+#include <cppunit/TextTestRunner.h>
+#include <cppunit/XmlOutputter.h>
 
+#include <gnuradio/unittests.h>
+#include "qa_digital.h"
+#include <iostream>
+#include <fstream>
+
+int
+main(int argc, char **argv)
+{
+  CppUnit::TextTestRunner runner;
+  std::ofstream xmlfile(get_unittest_path("digital.xml").c_str());
+  CppUnit::XmlOutputter *xmlout = new CppUnit::XmlOutputter(&runner.result(), 
xmlfile);
+
+  runner.addTest(qa_digital::suite());
+  runner.setOutputter(xmlout);
+
+  bool was_successful = runner.run("", false);
+
+  return was_successful ? 0 : 1;
+}
diff --git a/gr-digital/python/digital/qa_packet_format.py 
b/gr-digital/python/digital/qa_packet_format.py
new file mode 100644
index 0000000..6440b80
--- /dev/null
+++ b/gr-digital/python/digital/qa_packet_format.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+#
+# Copyright 2015,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.
+#
+
+import random, time, struct
+import pmt
+from gnuradio import gr, gr_unittest, digital, blocks
+from gnuradio.digital import packet_utils
+
+class test_packet_format_fb(gr_unittest.TestCase):
+
+    def setUp(self):
+        self.tb = gr.top_block()
+
+    def tearDown(self):
+        self.tb = None
+
+    def test_packet_format_async_default(self):
+        ac = packet_utils.default_access_code
+        hdr_format = digital.header_format_default(ac, 0)
+
+        formatter = digital.protocol_formatter_async(hdr_format)
+        snk_hdr = blocks.message_debug()
+        snk_pld = blocks.message_debug()
+
+        self.tb.msg_connect(formatter, 'header', snk_hdr, 'store')
+        self.tb.msg_connect(formatter, 'payload', snk_pld, 'store')
+
+
+        send_str = "Hello World"
+        send_pmt = pmt.make_u8vector(len(send_str), ord(' '))
+        for i in range(len(send_str)):
+            pmt.u8vector_set(send_pmt, i, ord(send_str[i]))
+        msg = pmt.cons(pmt.PMT_NIL, send_pmt)
+
+        port = pmt.intern("in")
+        formatter.to_basic_block()._post(port, msg)
+
+        self.tb.start()
+        while (snk_hdr.num_messages() < 1) and (snk_pld.num_messages() < 1):
+            time.sleep(0.1)
+        self.tb.stop()
+        self.tb.wait()
+
+        result_hdr_pmt = pmt.cdr(snk_hdr.get_message(0))
+        result_pld_pmt = pmt.cdr(snk_pld.get_message(0))
+
+        result_hdr = pmt.u8vector_elements(result_hdr_pmt)
+        result_pld = pmt.u8vector_elements(result_pld_pmt)
+        header = "".join([chr(r) for r in result_hdr])
+        payload = "".join([chr(r) for r in result_pld])
+
+        access_code = 
packet_utils.conv_1_0_string_to_packed_binary_string(packet_utils.default_access_code)[0]
+        rx_access_code = header[0:len(access_code)]
+
+        length = len(send_str)
+        rx_length = struct.unpack_from("!H", header, len(access_code))[0]
+
+        self.assertEqual(access_code, rx_access_code)
+        self.assertEqual(length, rx_length)
+        self.assertEqual(length, len(payload))
+        self.assertEqual(send_str, payload[0:length])
+
+
+    def test_packet_format_async_counter(self):
+        bps = 2
+        ac = packet_utils.default_access_code
+        hdr_format = digital.header_format_counter(ac, 0, 2)
+
+        formatter = digital.protocol_formatter_async(hdr_format)
+        snk_hdr = blocks.message_debug()
+        snk_pld = blocks.message_debug()
+
+        self.tb.msg_connect(formatter, 'header', snk_hdr, 'store')
+        self.tb.msg_connect(formatter, 'payload', snk_pld, 'store')
+
+
+        send_str = "Hello World" + 1000*"xxx"
+        send_pmt = pmt.make_u8vector(len(send_str), ord(' '))
+        for i in range(len(send_str)):
+            pmt.u8vector_set(send_pmt, i, ord(send_str[i]))
+        msg = pmt.cons(pmt.PMT_NIL, send_pmt)
+
+        port = pmt.intern("in")
+        formatter.to_basic_block()._post(port, msg)
+
+        self.tb.start()
+        while (snk_hdr.num_messages() < 1) and (snk_pld.num_messages() < 1):
+            time.sleep(0.1)
+        self.tb.stop()
+        self.tb.wait()
+
+        result_hdr_pmt = pmt.cdr(snk_hdr.get_message(0))
+        result_pld_pmt = pmt.cdr(snk_pld.get_message(0))
+
+        result_hdr = pmt.u8vector_elements(result_hdr_pmt)
+        result_pld = pmt.u8vector_elements(result_pld_pmt)
+        header = "".join([chr(r) for r in result_hdr])
+        payload = "".join([chr(r) for r in result_pld])
+
+        access_code = 
packet_utils.conv_1_0_string_to_packed_binary_string(packet_utils.default_access_code)[0]
+        rx_access_code = header[0:len(access_code)]
+
+        length = len(send_str)
+        rx_length = struct.unpack_from("!H", header, len(access_code))[0]
+        rx_bps = struct.unpack_from("!H", header, len(access_code)+4)[0]
+        rx_counter = struct.unpack_from("!H", header, len(access_code)+6)[0]
+
+        self.assertEqual(access_code, rx_access_code)
+        self.assertEqual(length, rx_length)
+        self.assertEqual(bps, rx_bps)
+        self.assertEqual(0, rx_counter)
+        self.assertEqual(length, len(payload))
+        self.assertEqual(send_str, payload[0:length])
+
+if __name__ == '__main__':
+    gr_unittest.run(test_packet_format_fb, "test_packet_format_fb.xml")
diff --git a/gr-digital/swig/CMakeLists.txt b/gr-digital/swig/CMakeLists.txt
index d87b7e9..2f00dc1 100644
--- a/gr-digital/swig/CMakeLists.txt
+++ b/gr-digital/swig/CMakeLists.txt
@@ -30,6 +30,7 @@ set(GR_SWIG_INCLUDE_DIRS
     ${GR_FFT_INCLUDE_DIRS}
     ${GR_FILTER_INCLUDE_DIRS}
     ${GNURADIO_RUNTIME_SWIG_INCLUDE_DIRS}
+    ${VOLK_INCLUDE_DIRS}
     ${Boost_INCLUDE_DIRS}
 )
 
diff --git a/gr-digital/swig/digital_swig.i b/gr-digital/swig/digital_swig.i
index d7a3b81..8a38d65 100644
--- a/gr-digital/swig/digital_swig.i
+++ b/gr-digital/swig/digital_swig.i
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011-2015 Free Software Foundation, Inc.
+ * Copyright 2011-2016 Free Software Foundation, Inc.
  *
  * This file is part of GNU Radio
  *
@@ -100,6 +100,14 @@
 #include "gnuradio/digital/ofdm_sampler.h"
 #include "gnuradio/digital/ofdm_serializer_vcc.h"
 #include "gnuradio/digital/ofdm_sync_sc_cfb.h"
+#include "gnuradio/digital/header_format_base.h"
+#include "gnuradio/digital/header_format_default.h"
+#include "gnuradio/digital/header_format_counter.h"
+#include "gnuradio/digital/header_format_crc.h"
+#include "gnuradio/digital/header_format_ofdm.h"
+#include "gnuradio/digital/protocol_formatter_async.h"
+#include "gnuradio/digital/protocol_formatter_bb.h"
+#include "gnuradio/digital/protocol_parser_b.h"
 #include "gnuradio/digital/packet_header_default.h"
 #include "gnuradio/digital/packet_header_ofdm.h"
 #include "gnuradio/digital/packet_headergenerator_bb.h"
@@ -181,6 +189,14 @@
 %include "gnuradio/digital/ofdm_sampler.h"
 %include "gnuradio/digital/ofdm_serializer_vcc.h"
 %include "gnuradio/digital/ofdm_sync_sc_cfb.h"
+%include "gnuradio/digital/header_format_base.h"
+%include "gnuradio/digital/header_format_default.h"
+%include "gnuradio/digital/header_format_counter.h"
+%include "gnuradio/digital/header_format_crc.h"
+%include "gnuradio/digital/header_format_ofdm.h"
+%include "gnuradio/digital/protocol_formatter_async.h"
+%include "gnuradio/digital/protocol_formatter_bb.h"
+%include "gnuradio/digital/protocol_parser_b.h"
 %include "gnuradio/digital/packet_header_default.h"
 %include "gnuradio/digital/packet_header_ofdm.h"
 %include "gnuradio/digital/packet_headergenerator_bb.h"
@@ -249,6 +265,9 @@ GR_SWIG_BLOCK_MAGIC2(digital, ofdm_mapper_bcv);
 GR_SWIG_BLOCK_MAGIC2(digital, ofdm_sampler);
 GR_SWIG_BLOCK_MAGIC2(digital, ofdm_serializer_vcc);
 GR_SWIG_BLOCK_MAGIC2(digital, ofdm_sync_sc_cfb);
+GR_SWIG_BLOCK_MAGIC2(digital, protocol_formatter_async);
+GR_SWIG_BLOCK_MAGIC2(digital, protocol_formatter_bb);
+GR_SWIG_BLOCK_MAGIC2(digital, protocol_parser_b);
 GR_SWIG_BLOCK_MAGIC2(digital, packet_headergenerator_bb);
 GR_SWIG_BLOCK_MAGIC2(digital, packet_headerparser_b);
 GR_SWIG_BLOCK_MAGIC2(digital, packet_sink);
diff --git a/gr-digital/swig/packet_header.i b/gr-digital/swig/packet_header.i
index 7c06d19..ace7030 100644
--- a/gr-digital/swig/packet_header.i
+++ b/gr-digital/swig/packet_header.i
@@ -1,19 +1,19 @@
 /* -*- c++ -*- */
 /*
  * Copyright 2012 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,
@@ -32,3 +32,29 @@ packet_header_ofdm_sptr.__repr__ = lambda self: 
"<packet_header_ofdm>"
 packet_header_ofdm = packet_header_ofdm .make;
 %}
 
+%template(header_format_base_sptr) 
boost::shared_ptr<gr::digital::header_format_base>;
+
+%template(header_format_default_sptr) 
boost::shared_ptr<gr::digital::header_format_default>;
+%pythoncode %{
+header_format_default_sptr.__repr__ = lambda self: "<header_format_default>"
+header_format_default = header_format_default .make;
+%}
+
+
+%template(header_format_counter_sptr) 
boost::shared_ptr<gr::digital::header_format_counter>;
+%pythoncode %{
+header_format_counter_sptr.__repr__ = lambda self: "<header_format_counter>"
+header_format_counter = header_format_counter .make;
+%}
+
+%template(header_format_crc_sptr) 
boost::shared_ptr<gr::digital::header_format_crc>;
+%pythoncode %{
+header_format_crc_sptr.__repr__ = lambda self: "<header_format_crc>"
+header_format_crc = header_format_crc .make;
+%}
+
+%template(header_format_ofdm_sptr) 
boost::shared_ptr<gr::digital::header_format_ofdm>;
+%pythoncode %{
+header_format_ofdm_sptr.__repr__ = lambda self: "<header_format_ofdm>"
+header_format_ofdm = header_format_ofdm .make;
+%}



reply via email to

[Prev in Thread] Current Thread [Next in Thread]