From fde77b2a7f5a2ed876e8aa7290d11b2c5a384584 Mon Sep 17 00:00:00 2001 From: Vanya Sergeev Date: Sun, 3 Jul 2016 01:30:08 -0700 Subject: [PATCH] blocks/protocol/varicodedecoder: add VaricodeDecoderBlock --- radio/blocks/init.lua | 2 + radio/blocks/protocol/varicodedecoder.lua | 89 +++++++++++++++++++ .../blocks/protocol/varicodedecoder_spec.lua | 23 +++++ .../blocks/protocol/varicodedecoder_spec.py | 21 +++++ 4 files changed, 135 insertions(+) create mode 100644 radio/blocks/protocol/varicodedecoder.lua create mode 100644 tests/blocks/protocol/varicodedecoder_spec.lua create mode 100644 tests/generate/blocks/protocol/varicodedecoder_spec.py diff --git a/radio/blocks/init.lua b/radio/blocks/init.lua index 48d28d4ba..1b34f3b86 100644 --- a/radio/blocks/init.lua +++ b/radio/blocks/init.lua @@ -93,4 +93,6 @@ return { --- POCSAG POCSAGFramerBlock = require('radio.blocks.protocol.pocsagframer'), POCSAGDecoderBlock = require('radio.blocks.protocol.pocsagdecoder'), + --- Varicode + VaricodeDecoderBlock = require('radio.blocks.protocol.varicodedecoder'), } diff --git a/radio/blocks/protocol/varicodedecoder.lua b/radio/blocks/protocol/varicodedecoder.lua new file mode 100644 index 000000000..2bcf90ed3 --- /dev/null +++ b/radio/blocks/protocol/varicodedecoder.lua @@ -0,0 +1,89 @@ +--- +-- Decode a Varicode encoded bit stream into bytes. +-- +-- @category Protocol +-- @block VaricodeDecoderBlock +-- +-- @signature in:Bit > out:Byte +-- +-- @usage +-- local decoder = radio.VaricodeDecoderBlock() + +local block = require('radio.core.block') +local types = require('radio.types') + +local VaricodeDecoderBlock = block.factory("VaricodeDecoderBlock") + +function VaricodeDecoderBlock:instantiate() + self:add_type_signature({block.Input("in", types.Bit)}, {block.Output("out", types.Byte)}) +end + +function VaricodeDecoderBlock:initialize() + self.state = types.Bit.vector() + self.out = types.Byte.vector() +end + +local varicode_table = { + [0x2ab] = 0x00, [0x2db] = 0x01, [0x2ed] = 0x02, [0x377] = 0x03, + [0x2eb] = 0x04, [0x35f] = 0x05, [0x2ef] = 0x06, [0x2fd] = 0x07, + [0x2ff] = 0x08, [0x0ef] = 0x09, [0x01d] = 0x0A, [0x36f] = 0x0B, + [0x2dd] = 0x0C, [0x01f] = 0x0D, [0x375] = 0x0E, [0x3ab] = 0x0F, + [0x2f7] = 0x10, [0x2f5] = 0x11, [0x3ad] = 0x12, [0x3af] = 0x13, + [0x35b] = 0x14, [0x36b] = 0x15, [0x36d] = 0x16, [0x357] = 0x17, + [0x37b] = 0x18, [0x37d] = 0x19, [0x3b7] = 0x1A, [0x355] = 0x1B, + [0x35d] = 0x1C, [0x3bb] = 0x1D, [0x2fb] = 0x1E, [0x37f] = 0x1F, + [0x3b5] = 0x7F, [0x001] = 0x20, [0x1ff] = 0x21, [0x15f] = 0x22, + [0x1f5] = 0x23, [0x1db] = 0x24, [0x2d5] = 0x25, [0x2bb] = 0x26, + [0x17f] = 0x27, [0x0fb] = 0x28, [0x0f7] = 0x29, [0x16f] = 0x2A, + [0x1df] = 0x2B, [0x075] = 0x2C, [0x035] = 0x2D, [0x057] = 0x2E, + [0x1af] = 0x2F, [0x0b7] = 0x30, [0x0bd] = 0x31, [0x0ed] = 0x32, + [0x0ff] = 0x33, [0x177] = 0x34, [0x15b] = 0x35, [0x16b] = 0x36, + [0x1ad] = 0x37, [0x1ab] = 0x38, [0x1b7] = 0x39, [0x0f5] = 0x3A, + [0x1bd] = 0x3B, [0x1ed] = 0x3C, [0x055] = 0x3D, [0x1d7] = 0x3E, + [0x2af] = 0x3F, [0x2bd] = 0x40, [0x07d] = 0x41, [0x0eb] = 0x42, + [0x0ad] = 0x43, [0x0b5] = 0x44, [0x077] = 0x45, [0x0db] = 0x46, + [0x0fd] = 0x47, [0x155] = 0x48, [0x07f] = 0x49, [0x1fd] = 0x4A, + [0x17d] = 0x4B, [0x0d7] = 0x4C, [0x0bb] = 0x4D, [0x0dd] = 0x4E, + [0x0ab] = 0x4F, [0x0d5] = 0x50, [0x1dd] = 0x51, [0x0af] = 0x52, + [0x06f] = 0x53, [0x06d] = 0x54, [0x157] = 0x55, [0x1b5] = 0x56, + [0x15d] = 0x57, [0x175] = 0x58, [0x17b] = 0x59, [0x2ad] = 0x5A, + [0x1f7] = 0x5B, [0x1ef] = 0x5C, [0x1fb] = 0x5D, [0x2bf] = 0x5E, + [0x16d] = 0x5F, [0x2df] = 0x60, [0x00b] = 0x61, [0x05f] = 0x62, + [0x02f] = 0x63, [0x02d] = 0x64, [0x003] = 0x65, [0x03d] = 0x66, + [0x05b] = 0x67, [0x02b] = 0x68, [0x00d] = 0x69, [0x1eb] = 0x6A, + [0x0bf] = 0x6B, [0x01b] = 0x6C, [0x03b] = 0x6D, [0x00f] = 0x6E, + [0x007] = 0x6F, [0x03f] = 0x70, [0x1bf] = 0x71, [0x015] = 0x72, + [0x017] = 0x73, [0x005] = 0x74, [0x037] = 0x75, [0x07b] = 0x76, + [0x06b] = 0x77, [0x0df] = 0x78, [0x05d] = 0x79, [0x1d5] = 0x7A, + [0x2b7] = 0x7B, [0x1bb] = 0x7C, [0x2b5] = 0x7D, [0x2d7] = 0x7E, +} + +function VaricodeDecoderBlock:process(x) + local out = self.out:resize(0) + + for i = 0, x.length-1 do + self.state:append(x.data[i]) + + if self.state.length >= 2 then + -- If we hit the 00 delimeter + if self.state.data[self.state.length-2].value == 0 and self.state.data[self.state.length-1].value == 0 then + -- Decode the character + local offset = (self.state.data[0].value == 1) and 0 or 1 + local char = varicode_table[types.Bit.tonumber(self.state, offset, self.state.length-offset-2)] + if char then + self.out:append(types.Byte(char)) + end + + -- Reset the state + self.state:resize(0) + elseif self.state.length > 10 then + -- If state got too long, reset it + self.state:resize(0) + end + end + end + + return out +end + +return VaricodeDecoderBlock diff --git a/tests/blocks/protocol/varicodedecoder_spec.lua b/tests/blocks/protocol/varicodedecoder_spec.lua new file mode 100644 index 000000000..579d0c255 --- /dev/null +++ b/tests/blocks/protocol/varicodedecoder_spec.lua @@ -0,0 +1,23 @@ +local radio = require('radio') +local jigs = require('tests.jigs') + +jigs.TestBlock(radio.VaricodeDecoderBlock, { + { + desc = "Valid message", + args = {}, + inputs = {radio.types.Bit.vector_from_array({0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0})}, + outputs = {radio.types.Byte.vector_from_array({0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64})} + }, + { + desc = "Valid message with extra leading 0 bit", + args = {}, + inputs = {radio.types.Bit.vector_from_array({0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0})}, + outputs = {radio.types.Byte.vector_from_array({0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64})} + }, + { + desc = "Empty message", + args = {}, + inputs = {radio.types.Bit.vector_from_array({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})}, + outputs = {radio.types.Byte.vector_from_array({})} + }, +}, {epsilon = 1.0e-06}) diff --git a/tests/generate/blocks/protocol/varicodedecoder_spec.py b/tests/generate/blocks/protocol/varicodedecoder_spec.py new file mode 100644 index 000000000..6cba222aa --- /dev/null +++ b/tests/generate/blocks/protocol/varicodedecoder_spec.py @@ -0,0 +1,21 @@ +import numpy +from generate import * + + +def generate(): + vectors = [] + + message1_bits = numpy.array([0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0], dtype=numpy.bool_) + message1 = numpy.array(bytearray("Hello World".encode())) + + message2_bits = numpy.array([0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0], dtype=numpy.bool_) + message2 = numpy.array(bytearray("Hello World".encode())) + + message3_bits = numpy.array([0]*40, dtype=numpy.bool_) + message3 = numpy.array([], dtype=numpy.uint8) + + vectors.append(TestVector([], [message1_bits], [message1], "Valid message")) + vectors.append(TestVector([], [message2_bits], [message2], "Valid message with extra leading 0 bit")) + vectors.append(TestVector([], [message3_bits], [message3], "Empty message")) + + return BlockSpec("VaricodeDecoderBlock", "tests/blocks/protocol/varicodedecoder_spec.lua", vectors, 1e-6)