summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gr-digital/include/gnuradio/digital/packet_header_ofdm.h24
-rw-r--r--gr-digital/lib/packet_header_ofdm.cc40
-rw-r--r--gr-digital/python/digital/ofdm_txrx.py116
-rwxr-xr-xgr-digital/python/digital/qa_packet_headerparser_b.py37
4 files changed, 160 insertions, 57 deletions
diff --git a/gr-digital/include/gnuradio/digital/packet_header_ofdm.h b/gr-digital/include/gnuradio/digital/packet_header_ofdm.h
index 4603450915..2b73dc6a5f 100644
--- a/gr-digital/include/gnuradio/digital/packet_header_ofdm.h
+++ b/gr-digital/include/gnuradio/digital/packet_header_ofdm.h
@@ -45,17 +45,31 @@ namespace gr {
const std::string &frame_len_tag_key,
const std::string &num_tag_key,
int bits_per_header_sym,
- int bits_per_payload_sym);
+ int bits_per_payload_sym,
+ bool scramble_header);
~packet_header_ofdm();
/*!
+ * \brief Header formatter.
+ *
+ * Does the same as packet_header_default::header_formatter(), but
+ * optionally scrambles the bits (this is more important for OFDM to avoid
+ * PAPR spikes).
+ */
+ bool header_formatter(
+ long packet_len,
+ unsigned char *out,
+ const std::vector<tag_t> &tags
+ );
+
+ /*!
* \brief Inverse function to header_formatter().
*
* Does the same as packet_header_default::header_parser(), but
* adds another tag that stores the number of OFDM symbols in the
* packet.
* Note that there is usually no linear connection between the number
- * of OFDM symbols and the packet length, because, a packet might
+ * of OFDM symbols and the packet length because a packet might
* finish mid-OFDM-symbol.
*/
bool header_parser(
@@ -85,15 +99,17 @@ namespace gr {
const std::string &frame_len_tag_key="frame_len",
const std::string &num_tag_key="packet_num",
int bits_per_header_sym=1,
- int bits_per_payload_sym=1
+ int bits_per_payload_sym=1,
+ bool scramble_header=false
);
protected:
- pmt::pmt_t d_frame_len_tag_key;
+ pmt::pmt_t d_frame_len_tag_key; //!< 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<unsigned char> d_scramble_mask; //!< Bits are xor'd with this before tx'ing
};
} // namespace digital
diff --git a/gr-digital/lib/packet_header_ofdm.cc b/gr-digital/lib/packet_header_ofdm.cc
index f163657bab..4893b866e2 100644
--- a/gr-digital/lib/packet_header_ofdm.cc
+++ b/gr-digital/lib/packet_header_ofdm.cc
@@ -24,6 +24,7 @@
#endif
#include <gnuradio/digital/packet_header_ofdm.h>
+#include <gnuradio/digital/lfsr.h>
namespace gr {
namespace digital {
@@ -46,11 +47,13 @@ namespace gr {
const std::string &frame_len_tag_key,
const std::string &num_tag_key,
int bits_per_header_sym,
- int bits_per_payload_sym)
+ int bits_per_payload_sym,
+ bool scramble_header)
{
return packet_header_ofdm::sptr(
new packet_header_ofdm(
- occupied_carriers, n_syms, len_tag_key, frame_len_tag_key, num_tag_key, bits_per_header_sym, bits_per_payload_sym
+ occupied_carriers, n_syms, len_tag_key, frame_len_tag_key, num_tag_key,
+ bits_per_header_sym, bits_per_payload_sym, scramble_header
)
);
}
@@ -62,8 +65,9 @@ namespace gr {
const std::string &frame_len_tag_key,
const std::string &num_tag_key,
int bits_per_header_sym,
- int bits_per_payload_sym)
- : packet_header_default(
+ int bits_per_payload_sym,
+ bool scramble_header
+ ) : packet_header_default(
_get_header_len_from_occupied_carriers(occupied_carriers, n_syms),
len_tag_key,
num_tag_key,
@@ -71,23 +75,47 @@ namespace gr {
d_frame_len_tag_key(pmt::string_to_symbol(frame_len_tag_key)),
d_occupied_carriers(occupied_carriers),
d_syms_per_set(0),
- d_bits_per_payload_sym(bits_per_payload_sym)
+ d_bits_per_payload_sym(bits_per_payload_sym),
+ d_scramble_mask(d_header_len, 0)
{
for (unsigned i = 0; i < d_occupied_carriers.size(); i++) {
d_syms_per_set += d_occupied_carriers[i].size();
}
+
+ // Init scrambler mask
+ if (scramble_header) {
+ // These are just random values which already have OK PAPR:
+ gr::digital::lfsr shift_reg(0x8a, 0x6f, 7);
+ for (int i = 0; i < d_header_len; i++) {
+ for (int k = 0; k < bits_per_header_sym; k++) {
+ d_scramble_mask[i] ^= shift_reg.next_bit() << k;
+ }
+ }
+ }
}
packet_header_ofdm::~packet_header_ofdm()
{
}
+ bool packet_header_ofdm::header_formatter(long packet_len, unsigned char *out, const std::vector<tag_t> &tags)
+ {
+ bool ret_val = packet_header_default::header_formatter(packet_len, out, tags);
+ for (int i = 0; i < d_header_len; i++) {
+ out[i] ^= d_scramble_mask[i];
+ }
+ return ret_val;
+ }
bool packet_header_ofdm::header_parser(
const unsigned char *in,
std::vector<tag_t> &tags)
{
- if (!packet_header_default::header_parser(in, tags)) {
+ std::vector<unsigned char> in_descrambled(d_header_len, 0);
+ for (int i = 0; i < d_header_len; i++) {
+ in_descrambled[i] = in[i] ^ d_scramble_mask[i];
+ }
+ if (!packet_header_default::header_parser(&in_descrambled[0], tags)) {
return false;
}
int packet_len = 0; // # of bytes in this frame
diff --git a/gr-digital/python/digital/ofdm_txrx.py b/gr-digital/python/digital/ofdm_txrx.py
index 76bf337b8d..b1ebc9e9c2 100644
--- a/gr-digital/python/digital/ofdm_txrx.py
+++ b/gr-digital/python/digital/ofdm_txrx.py
@@ -63,6 +63,7 @@ _seq_seed = 42
def _get_active_carriers(fft_len, occupied_carriers, pilot_carriers):
+ """ Returns a list of all carriers that at some point carry data or pilots. """
active_carriers = list()
for carrier in list(occupied_carriers[0]) + list(pilot_carriers[0]):
if carrier < 0:
@@ -134,6 +135,8 @@ class ofdm_tx(gr.hier_block2):
sync_word2: The second sync preamble symbol. This has to be filled entirely. Also used for
coarse frequency offset and channel estimation.
rolloff: The rolloff length in samples. Must be smaller than the CP.
+ debug_log: Write output into log files (Warning: creates lots of data!)
+ scramble_bits: Activates the scramblers (set this to True unless debugging)
"""
def __init__(self, fft_len=_def_fft_len, cp_len=_def_cp_len,
packet_length_tag_key=_def_packet_length_tag_key,
@@ -160,7 +163,6 @@ class ofdm_tx(gr.hier_block2):
self.pilot_symbols = pilot_symbols
self.bps_header = bps_header
self.bps_payload = bps_payload
- n_sync_words = 1
self.sync_word1 = sync_word1
if sync_word1 is None:
self.sync_word1 = _make_sync_word1(fft_len, occupied_carriers, pilot_carriers)
@@ -175,8 +177,11 @@ class ofdm_tx(gr.hier_block2):
if len(self.sync_word2) != fft_len:
raise ValueError("Length of sync sequence(s) must be FFT length.")
self.sync_word2 = list(self.sync_word2)
- n_sync_words = 2
self.sync_words.append(self.sync_word2)
+ if scramble_bits:
+ self.scramble_seed = 0x7f
+ else:
+ self.scramble_seed = 0x00 # We deactivate the scrambler by init'ing it with zeros
### Header modulation ################################################
crc = digital.crc32_bb(False, self.packet_length_tag_key)
header_constellation = _get_constellation(bps_header)
@@ -184,42 +189,39 @@ class ofdm_tx(gr.hier_block2):
formatter_object = digital.packet_header_ofdm(
occupied_carriers=occupied_carriers, n_syms=1,
bits_per_header_sym=self.bps_header,
- bits_per_payload_sym=self.bps_payload
+ bits_per_payload_sym=self.bps_payload,
+ scramble_header=scramble_bits
)
header_gen = digital.packet_headergenerator_bb(formatter_object.base(), self.packet_length_tag_key)
header_payload_mux = blocks.tagged_stream_mux(gr.sizeof_gr_complex*1, self.packet_length_tag_key)
- self.connect(self, crc, header_gen, header_mod, (header_payload_mux, 0))
+ self.connect(
+ self,
+ crc,
+ header_gen,
+ header_mod,
+ (header_payload_mux, 0)
+ )
if debug_log:
self.connect(header_gen, blocks.file_sink(1, 'tx-hdr.dat'))
### Payload modulation ###############################################
payload_constellation = _get_constellation(bps_payload)
payload_mod = digital.chunks_to_symbols_bc(payload_constellation.points())
- if scramble_bits:
- self.connect(
- crc,
- digital.additive_scrambler_bb(
- 0x8a, 0x7f, 7,
- bits_per_byte=bps_payload,
- reset_tag_key=self.packet_length_tag_key
- ),
- blocks.repack_bits_bb(
- 8, # Unpack 8 bits per byte
- bps_payload,
- self.packet_length_tag_key
- ),
- payload_mod
- )
- else:
- self.connect(
- crc,
- blocks.repack_bits_bb(
- 8, # Unpack 8 bits per byte
- bps_payload,
- self.packet_length_tag_key
- ),
- payload_mod
- )
+ payload_scrambler = digital.additive_scrambler_bb(
+ 0x8a,
+ self.scramble_seed,
+ 7,
+ 0, # Don't reset after fixed length (let the reset tag do that)
+ bits_per_byte=bps_payload,
+ reset_tag_key=self.packet_length_tag_key
+ )
self.connect(
+ crc,
+ payload_scrambler,
+ blocks.repack_bits_bb(
+ 8, # Unpack 8 bits per byte
+ bps_payload,
+ self.packet_length_tag_key
+ ),
payload_mod,
(header_payload_mux, 1)
)
@@ -246,8 +248,8 @@ class ofdm_tx(gr.hier_block2):
)
self.connect(header_payload_mux, allocator, ffter, cyclic_prefixer, self)
if debug_log:
- self.connect(allocator, blocks.file_sink(8*64, 'tx-post-allocator.dat'))
- self.connect(cyclic_prefixer, blocks.file_sink(8, 'tx-signal.dat'))
+ self.connect(allocator, blocks.file_sink(gr.sizeof_gr_complex * fft_len, 'tx-post-allocator.dat'))
+ self.connect(cyclic_prefixer, blocks.file_sink(gr.sizeof_gr_complex, 'tx-signal.dat'))
class ofdm_rx(gr.hier_block2):
@@ -312,6 +314,10 @@ class ofdm_rx(gr.hier_block2):
raise ValueError("Length of sync sequence(s) must be FFT length.")
self.sync_word2 = sync_word2
n_sync_words = 2
+ if scramble_bits:
+ self.scramble_seed = 0x7f
+ else:
+ self.scramble_seed = 0x00 # We deactivate the scrambler by init'ing it with zeros
### Sync ############################################################
sync_detect = digital.ofdm_sync_sc_cfb(fft_len, cp_len)
delay = blocks.delay(gr.sizeof_gr_complex, fft_len+cp_len)
@@ -357,10 +363,19 @@ class ofdm_rx(gr.hier_block2):
frame_length_tag_key,
packet_num_tag_key,
bps_header,
- bps_payload
+ bps_payload,
+ scramble_header=scramble_bits
)
header_parser = digital.packet_headerparser_b(header_formatter.formatter())
- self.connect((hpd, 0), header_fft, chanest, header_eq, header_serializer, header_demod, header_parser)
+ self.connect(
+ (hpd, 0),
+ header_fft,
+ chanest,
+ header_eq,
+ header_serializer,
+ header_demod,
+ header_parser
+ )
self.msg_connect(header_parser, "header_data", hpd, "header_data")
if debug_log:
self.connect((chanest, 1), blocks.file_sink(gr.sizeof_gr_complex * fft_len, 'channel-estimate.dat'))
@@ -368,7 +383,7 @@ class ofdm_rx(gr.hier_block2):
self.connect((chanest, 0), blocks.tag_debug(gr.sizeof_gr_complex * fft_len, 'post-hdr-chanest'))
self.connect(header_eq, blocks.file_sink(gr.sizeof_gr_complex * fft_len, 'post-hdr-eq.dat'))
self.connect(header_serializer, blocks.file_sink(gr.sizeof_gr_complex, 'post-hdr-serializer.dat'))
- self.connect(header_demod, blocks.file_sink(1, 'post-hdr-demod.dat'))
+ self.connect(header_descrambler, blocks.file_sink(1, 'post-hdr-demod.dat'))
### Payload demod ####################################################
payload_fft = fft.fft_vcc(self.fft_len, True, (), True)
payload_constellation = _get_constellation(bps_payload)
@@ -391,20 +406,29 @@ class ofdm_rx(gr.hier_block2):
1 # Skip 1 symbol (that was already in the header)
)
payload_demod = digital.constellation_decoder_cb(payload_constellation.base())
+ self.payload_descrambler = digital.additive_scrambler_bb(
+ 0x8a,
+ self.scramble_seed,
+ 7,
+ 0, # Don't reset after fixed length
+ bits_per_byte=bps_payload,
+ reset_tag_key=self.packet_length_tag_key
+ )
repack = blocks.repack_bits_bb(bps_payload, 8, self.packet_length_tag_key, True)
- crc = digital.crc32_bb(True, self.packet_length_tag_key)
- self.connect((hpd, 1), payload_fft, payload_eq, payload_serializer, payload_demod, repack)
- if scramble_bits:
- descrambler = digital.additive_scrambler_bb(
- 0x8a, 0x7f, 7,
- bits_per_byte=bps_payload,
- reset_tag_key=self.packet_length_tag_key
- )
- self.connect(repack, descrambler, crc, self)
- else:
- self.connect(repack, crc, self)
+ self.crc = digital.crc32_bb(True, self.packet_length_tag_key)
+ self.connect(
+ (hpd, 1),
+ payload_fft,
+ payload_eq,
+ payload_serializer,
+ payload_demod,
+ repack,
+ self.payload_descrambler,
+ self.crc,
+ self
+ )
if debug_log:
- self.connect((hpd, 1), blocks.tag_debug(gr.sizeof_gr_complex*fft_len, 'post-hpd'));
+ self.connect((hpd, 1), blocks.tag_debug(gr.sizeof_gr_complex*fft_len, 'post-hpd'))
self.connect(payload_fft, blocks.file_sink(gr.sizeof_gr_complex*fft_len, 'post-payload-fft.dat'))
self.connect(payload_eq, blocks.file_sink(gr.sizeof_gr_complex*fft_len, 'post-payload-eq.dat'))
self.connect(payload_serializer, blocks.file_sink(gr.sizeof_gr_complex, 'post-payload-serializer.dat'))
diff --git a/gr-digital/python/digital/qa_packet_headerparser_b.py b/gr-digital/python/digital/qa_packet_headerparser_b.py
index abd23c8945..7754a7304c 100755
--- a/gr-digital/python/digital/qa_packet_headerparser_b.py
+++ b/gr-digital/python/digital/qa_packet_headerparser_b.py
@@ -130,7 +130,42 @@ class qa_packet_headerparser_b (gr_unittest.TestCase):
self.assertEqual(msg1, {'packet_len': 193*4, 'frame_len': 25, 'packet_num': 0})
self.assertEqual(msg2, {'packet_len': 8*4, 'frame_len': 1, 'packet_num': 1})
+ def test_004_ofdm_scramble(self):
+ """
+ Test scrambling for OFDM header gen
+ """
+ header_len = 32
+ packet_length = 23
+ packet_len_tagname = "packet_len"
+ frame_len_tagname = "frame_len"
+ data, tags = tagged_streams.packets_to_vectors([range(packet_length),range(packet_length),], packet_len_tagname)
+ src = blocks.vector_source_b(data, False, 1, tags)
+ header_formatter = digital.packet_header_ofdm(
+ (range(32),), # 32 carriers are occupied (which doesn't matter here)
+ 1, # 1 OFDM symbol per header (= 32 bits)
+ packet_len_tagname,
+ frame_len_tagname,
+ "packet_num",
+ 1, # 1 bit per header symbols (BPSK)
+ 2, # 2 bits per payload symbol (QPSK)
+ scramble_header=True
+ )
+ header_gen = digital.packet_headergenerator_bb(header_formatter.base())
+ header_parser = digital.packet_headerparser_b(header_formatter.base())
+ sink = blocks.message_debug()
+ self.tb.connect(src, header_gen, header_parser)
+ self.tb.msg_connect(header_parser, "header_data", sink, "store")
+ self.tb.start()
+ time.sleep(1)
+ self.tb.stop()
+ self.tb.wait()
+ msg = pmt.to_python(sink.get_message(0))
+ self.assertEqual(msg, {'packet_len': packet_length, 'packet_num': 0, 'frame_len': 4})
+ msg = pmt.to_python(sink.get_message(1))
+ self.assertEqual(msg, {'packet_len': packet_length, 'packet_num': 1, 'frame_len': 4})
+
if __name__ == '__main__':
- gr_unittest.run(qa_packet_headerparser_b, "qa_packet_headerparser_b.xml")
+ #gr_unittest.run(qa_packet_headerparser_b, "qa_packet_headerparser_b.xml")
+ gr_unittest.run(qa_packet_headerparser_b)