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_encoder_bb_impl.cc | 37 +++++++++++++++++++++++++++-------
 1 file changed, 30 insertions(+), 7 deletions(-)

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

diff --git a/gr-digital/lib/diff_encoder_bb_impl.cc b/gr-digital/lib/diff_encoder_bb_impl.cc
index fb14504bc2..d14e7c28e6 100644
--- a/gr-digital/lib/diff_encoder_bb_impl.cc
+++ b/gr-digital/lib/diff_encoder_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,21 +16,29 @@
 #include "diff_encoder_bb_impl.h"
 #include <gnuradio/io_signature.h>
 
+#include <stdexcept>
+
 namespace gr {
 namespace digital {
 
-diff_encoder_bb::sptr diff_encoder_bb::make(unsigned int modulus)
+diff_encoder_bb::sptr diff_encoder_bb::make(unsigned int modulus,
+                                            enum diff_coding_type coding)
 {
-    return gnuradio::make_block_sptr<diff_encoder_bb_impl>(modulus);
+    return gnuradio::make_block_sptr<diff_encoder_bb_impl>(modulus, coding);
 }
 
-diff_encoder_bb_impl::diff_encoder_bb_impl(unsigned int modulus)
+diff_encoder_bb_impl::diff_encoder_bb_impl(unsigned int modulus,
+                                           enum diff_coding_type coding)
     : sync_block("diff_encoder_bb",
                  io_signature::make(1, 1, sizeof(unsigned char)),
                  io_signature::make(1, 1, sizeof(unsigned char))),
       d_last_out(0),
-      d_modulus(modulus)
+      d_modulus(modulus),
+      d_coding(coding)
 {
+    if (d_coding == DIFF_NRZI && d_modulus != 2) {
+        throw std::runtime_error("diff_encoder: NRZI only supported with modulus 2");
+    }
 }
 
 diff_encoder_bb_impl::~diff_encoder_bb_impl() {}
@@ -43,9 +52,23 @@ int diff_encoder_bb_impl::work(int noutput_items,
 
     unsigned last_out = d_last_out;
 
-    for (int i = 0; i < noutput_items; i++) {
-        out[i] = (in[i] + last_out) % d_modulus;
-        last_out = out[i];
+    if (d_coding == DIFF_NRZI) {
+        for (int i = 0; i < noutput_items; i++) {
+            out[i] = ~(in[i] ^ last_out) & 1;
+            last_out = out[i];
+        }
+    } else if (d_modulus == 2) {
+        // optimized implementation for modulus 2
+        for (int i = 0; i < noutput_items; i++) {
+            out[i] = (in[i] ^ last_out) & 1;
+            last_out = out[i];
+        }
+    } else {
+        // implementation for modulus != 2
+        for (int i = 0; i < noutput_items; i++) {
+            out[i] = (in[i] + last_out) % d_modulus;
+            last_out = out[i];
+        }
     }
 
     d_last_out = last_out;
-- 
cgit v1.2.3