From 51c504ebb1ca21c5f7071826c1af03e45e391a65 Mon Sep 17 00:00:00 2001
From: Daniel Estévez <daniel@destevez.net>
Date: Sun, 6 Jun 2021 11:25:57 +0200
Subject: digital: Add NRZI option to differential en/decoder
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This adds an option to the differential encoder an decoder blocks
to perform NRZI encoding and decoding. NRZI only makes sense with
a modulus of 2, so the blocks constructors will throw and exception
if passed nrzi = true and a modulus different from 2.

The GRC blocks handle this by hiding the modulus field if the user
selects NRZI encoding.

A new unit test for the NRZI version of the blocks is added. Besides
checking that encode plus decode gives the original, this test also
compares the C++ implementation results against a Numpy implementation.

Additionally, a faster implementation of differential encoding/
decoding for modulus 2 is included here.

Signed-off-by: Daniel Estévez <daniel@destevez.net>
---
 gr-digital/lib/diff_decoder_bb_impl.cc | 33 +++++++++++++++++++++++++++------
 1 file changed, 27 insertions(+), 6 deletions(-)

(limited to 'gr-digital/lib/diff_decoder_bb_impl.cc')

diff --git a/gr-digital/lib/diff_decoder_bb_impl.cc b/gr-digital/lib/diff_decoder_bb_impl.cc
index 95e5c2e9c3..f9b093400d 100644
--- a/gr-digital/lib/diff_decoder_bb_impl.cc
+++ b/gr-digital/lib/diff_decoder_bb_impl.cc
@@ -1,6 +1,7 @@
 /* -*- c++ -*- */
 /*
  * Copyright 2006,2010,2012 Free Software Foundation, Inc.
+ * Copyright 2021 Daniel Estevez <daniel@destevez.net>
  *
  * This file is part of GNU Radio
  *
@@ -15,19 +16,27 @@
 #include "diff_decoder_bb_impl.h"
 #include <gnuradio/io_signature.h>
 
+#include <stdexcept>
+
 namespace gr {
 namespace digital {
-diff_decoder_bb::sptr diff_decoder_bb::make(unsigned int modulus)
+diff_decoder_bb::sptr diff_decoder_bb::make(unsigned int modulus,
+                                            enum diff_coding_type coding)
 {
-    return gnuradio::make_block_sptr<diff_decoder_bb_impl>(modulus);
+    return gnuradio::make_block_sptr<diff_decoder_bb_impl>(modulus, coding);
 }
 
-diff_decoder_bb_impl::diff_decoder_bb_impl(unsigned int modulus)
+diff_decoder_bb_impl::diff_decoder_bb_impl(unsigned int modulus,
+                                           enum diff_coding_type coding)
     : sync_block("diff_decoder_bb",
                  io_signature::make(1, 1, sizeof(unsigned char)),
                  io_signature::make(1, 1, sizeof(unsigned char))),
-      d_modulus(modulus)
+      d_modulus(modulus),
+      d_coding(coding)
 {
+    if (d_coding == DIFF_NRZI && d_modulus != 2) {
+        throw std::runtime_error("diff_decoder: NRZI only supported with modulus 2");
+    }
     set_history(2); // need to look at two inputs
 }
 
@@ -43,8 +52,20 @@ int diff_decoder_bb_impl::work(int noutput_items,
 
     unsigned modulus = d_modulus;
 
-    for (int i = 0; i < noutput_items; i++) {
-        out[i] = (in[i] - in[i - 1]) % modulus;
+    if (d_coding == DIFF_NRZI) {
+        for (int i = 0; i < noutput_items; i++) {
+            out[i] = ~(in[i] ^ in[i - 1]) & 1;
+        }
+    } else if (modulus == 2) {
+        // optimized implementation for modulus 2
+        for (int i = 0; i < noutput_items; i++) {
+            out[i] = (in[i] ^ in[i - 1]) & 1;
+        }
+    } else {
+        // implementation for modulus != 2
+        for (int i = 0; i < noutput_items; i++) {
+            out[i] = (in[i] - in[i - 1]) % modulus;
+        }
     }
 
     return noutput_items;
-- 
cgit v1.2.3