From ac8ef5f69a69f11fd202470da68709cd3006d547 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 19 Nov 2021 21:29:45 +0100 Subject: Frames --- src/gr-fadingui/python/frame_obj.py | 74 +++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 src/gr-fadingui/python/frame_obj.py (limited to 'src/gr-fadingui/python/frame_obj.py') diff --git a/src/gr-fadingui/python/frame_obj.py b/src/gr-fadingui/python/frame_obj.py new file mode 100644 index 0000000..b9dae70 --- /dev/null +++ b/src/gr-fadingui/python/frame_obj.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2021 Naoki Pross. + +from functools import reduce +import operator as op + +import numpy as np +from gnuradio import gr + + +class frame_obj(gr.basic_block): + """ + Frame Object: Contains informations about a data frame. + + ------------------------------------------------------------------------------- + | Preamble | Padding | ID | Data Length | Parity | Payload | Padding | + | k bytes | 1 bit | 4 bits | 22 bits | 5 bits | | if necessary | + ------------------------------------------------------------------------------- + | (31, 26) Hamming code EC | + ----------------------------------- + + - The preamble is user defined. + - The ID (11 bits) + Data length (22 bits) together are a 31 bits, followed + by 26 parity bits computed using a (31,26) hamming code. + + This constraints the maximum payload size to 64 MB and the number IDs to + 1024 (i.e. max file size is 1 GB, more than enough for many thing) + + """ + def __init__(self, preamble, payload_len): + gr.basic_block.__init__(self, name="frame_obj", + in_sig=None, out_sig=None) + + self.preamble = np.array(preamble, dtype=np.uint8) + + self.preamble_len = len(self.preamble) + self.payload_len = payload_len + + @property + def length(self): + """Frame lenght in bytes""" + return self.preamble_len + self.payload_len + 8 + + def parity(self, bits): + """Compute the 5 parity bits for an unpacked array of 26 bits""" + assert(len(bits) == 26) + # FIXME: does not work + # gen = np.array( + # [[1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0], + # [0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1], + # [0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0], + # [0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0], + # [0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1]], + # dtype=np.uint8) + # return np.matmul(bits, gen) % 2 + return np.array([0, 0, 0, 0, 0]) + + def make(self, idv, data_len, data): + """Make a frame""" + return np.concatenate(self.preamble, np.packbits(hamming), data) + + def syndrome(self, bits): + """Compute the syndrome (check Hamming code) for an unpacked array of 31 bits""" + assert(len(bits) == 31) + return reduce(op.xor, [i for i, bit in enumerate(bits) if bit]) + + def general_work(self, input_items, output_items): + """ + This block has no inputs or output + """ + return 0; + -- cgit v1.2.1 From 2bb4a947d4d55e605e6912dec3ff95fbe541615a Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Sat, 20 Nov 2021 17:05:04 +0100 Subject: Implement Frame Object --- src/gr-fadingui/python/frame_obj.py | 77 ++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 30 deletions(-) (limited to 'src/gr-fadingui/python/frame_obj.py') diff --git a/src/gr-fadingui/python/frame_obj.py b/src/gr-fadingui/python/frame_obj.py index b9dae70..136fce0 100644 --- a/src/gr-fadingui/python/frame_obj.py +++ b/src/gr-fadingui/python/frame_obj.py @@ -10,65 +10,82 @@ import numpy as np from gnuradio import gr -class frame_obj(gr.basic_block): +class frame_obj: """ Frame Object: Contains informations about a data frame. ------------------------------------------------------------------------------- | Preamble | Padding | ID | Data Length | Parity | Payload | Padding | - | k bytes | 1 bit | 4 bits | 22 bits | 5 bits | | if necessary | + | k bytes | 1 bit | 5 bits | 21 bits | 5 bits | | if necessary | ------------------------------------------------------------------------------- - | (31, 26) Hamming code EC | - ----------------------------------- + | (31, 26) Hamming EC code | + --------------------------------- - The preamble is user defined. - - The ID (11 bits) + Data length (22 bits) together are a 31 bits, followed - by 26 parity bits computed using a (31,26) hamming code. + - The ID (5 bits) + Data length (21 bits) together are a 26 bits, followed + by 5 parity bits computed using a (31,26) hamming code. - This constraints the maximum payload size to 64 MB and the number IDs to - 1024 (i.e. max file size is 1 GB, more than enough for many thing) + This constraints the maximum payload size to 2 MiB and the number IDs to + 32, i.e. max file size is 64 MiB. """ def __init__(self, preamble, payload_len): - gr.basic_block.__init__(self, name="frame_obj", - in_sig=None, out_sig=None) + self._preamble = np.array(preamble, dtype=np.uint8) - self.preamble = np.array(preamble, dtype=np.uint8) + self._preamble_len = len(self._preamble) + self._payload_len = payload_len - self.preamble_len = len(self.preamble) - self.payload_len = payload_len + @property + def header_length(self) -> int: + """Get header length in bytes""" + # 4 is the number of bytes for the hamming part + return self._preamble_len + 4 + + @property + def payload_length(self) -> int: + return self._payload_len + + @property + def length(self) -> int: + """Get frame lenght in bytes""" + # 8 is the size of the hamming ECC part + 1 bit + return self.header_length + self.payload_length @property - def length(self): - """Frame lenght in bytes""" - return self.preamble_len + self.payload_len + 8 + def preamble(self): + """Get preamble""" + return self._preamble def parity(self, bits): """Compute the 5 parity bits for an unpacked array of 26 bits""" assert(len(bits) == 26) # FIXME: does not work - # gen = np.array( - # [[1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0], - # [0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1], - # [0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0], - # [0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0], - # [0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1]], - # dtype=np.uint8) # return np.matmul(bits, gen) % 2 return np.array([0, 0, 0, 0, 0]) def make(self, idv, data_len, data): """Make a frame""" - return np.concatenate(self.preamble, np.packbits(hamming), data) + # get lower 4 bits of idv + idv_bits = np.unpackbits([np.uint8(idv)])[:5] + + # get lower 22 bits of data_len + data_len_bytes = list(map(np.uint8, data_len.to_bytes(4, byteorder='little'))) + data_len_bits = np.unpackbits(data_len_bytes)[:21] + + # compute 5 parity bits + metadata = np.concatenate([idv_bits, data_len_bits]) + parity_bits = self.parity(metadata) + + # add padding + hamming_bits = np.concatenate([[0], metadata, parity_bits]) + assert(len(hamming_bits) == 32) + + # pack 32 bits into 4 bytes and add the rest + hamming = np.packbits(hamming_bits) + return np.concatenate([self.preamble, hamming, data]) def syndrome(self, bits): """Compute the syndrome (check Hamming code) for an unpacked array of 31 bits""" assert(len(bits) == 31) return reduce(op.xor, [i for i, bit in enumerate(bits) if bit]) - def general_work(self, input_items, output_items): - """ - This block has no inputs or output - """ - return 0; - -- cgit v1.2.1