From dd795612f0ca0d84e0a17075f8e56d783937bf10 Mon Sep 17 00:00:00 2001
From: Nao Pross <np@0hm.ch>
Date: Thu, 18 Nov 2021 16:11:24 +0100
Subject: Begin frame sync block

---
 src/gr-fadingui/python/datasource.py     |  3 +-
 src/gr-fadingui/python/xor_frame_sync.py | 58 ++++++++++++++++++++++++++++++--
 2 files changed, 57 insertions(+), 4 deletions(-)

(limited to 'src/gr-fadingui/python')

diff --git a/src/gr-fadingui/python/datasource.py b/src/gr-fadingui/python/datasource.py
index 764b4d5..ab2f441 100644
--- a/src/gr-fadingui/python/datasource.py
+++ b/src/gr-fadingui/python/datasource.py
@@ -10,7 +10,8 @@ from gnuradio import gr
 
 class datasource(gr.sync_block):
     """
-    Loads data from a file choosen in the graphical user interface.
+    Loads data from a file choosen in the graphical user interface, splits into
+    chunks and puts a preamble in front of it(frame).
     """
 
     HEADER_LEN = 11;
diff --git a/src/gr-fadingui/python/xor_frame_sync.py b/src/gr-fadingui/python/xor_frame_sync.py
index 9d9064f..735a031 100644
--- a/src/gr-fadingui/python/xor_frame_sync.py
+++ b/src/gr-fadingui/python/xor_frame_sync.py
@@ -4,24 +4,76 @@
 # Copyright 2021 Naoki Pross.
 
 
-import numpy
+import numpy as np
+from numpy_ringbuffer import RingBuffer
+
 from gnuradio import gr
 
+
 class xor_frame_sync(gr.sync_block):
     """
     docstring for block xor_frame_sync
     """
-    def __init__(self, sync_pattern):
+    def __init__(self, sync_pattern, buffer_size):
         gr.sync_block.__init__(self,
             name="xor_frame_sync",
             in_sig=[np.byte],
             out_sig=[np.byte])
 
+        # binary pattern to match
+        self.pattern = np.array(sync_pattern, dtype=np.dtype("uint8"))
+        self.nbits = len(sync_pattern)
+
+        # buffer to delay the data
+        self.delay_fifo = RingBuffer(buffer_size, dtype=np.byte)
+
+        # buffers to store cross correlation data
+        self.xcorr = RingBuffer(buffer_size, dtype=np.dtype("uint8"))
+
+        # synchronization state
+        self.synchronized = False
+        self.delay = 0
+
+    def xcorrelation(self):
+        """
+        Compute the binary correlation between the stream and the stored
+        pattern. Binary correlation between two bit vectors is just size of the
+        vector(s) minus the number of bits that differ.
+        """
+        unpacked = np.unpackbits(self.delay_fifo[0])
+        return self.nbits - sum(np.logical_xor(unpacked, self.pattern))
+
     def work(self, input_items, output_items):
+        """
+        Process the inputs, that means:
+
+            - Check that the buffer is synchronized, i.e. there is the sync
+              pattern appears every k bits, where k is the size of the packet.
+
+            - If the buffer is not synchronized, compute a binary cross
+              correlation to find how by much the stream should be delayed.
+        """
         inp = input_items[0]
         out = output_items[0]
 
-        out[:] = inp
+        # Add data to delay buffer
+        self.delay_fifo.appendleft(inp)
+
+        # TODO: check for synchronization, else compute
+
+        # Compute correlation
+        if not self.synchronized:
+            self.xcorr.append(self.xcorrelation())
+
+            peak = np.argmax(self.xcorr)
+            if self.xcorr[peak] != self.nbits:
+                print(f"Warning! XOR correlation is not perfect (peak value = {self.xcorr[peak]})")
+
+            self.delay = peak
+            self.synchronized = True
+
+        # return data with delay
+        out[:] = self.delay_fifo[self.delay]
 
         return len(output_items[0])
 
-- 
cgit v1.2.1