Skip to content

Commit

Permalink
blocks/protocol/varicodedecoder: add VaricodeDecoderBlock
Browse files Browse the repository at this point in the history
  • Loading branch information
vsergeev committed Jul 29, 2016
1 parent b9c6492 commit fde77b2
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 0 deletions.
2 changes: 2 additions & 0 deletions radio/blocks/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
}
89 changes: 89 additions & 0 deletions radio/blocks/protocol/varicodedecoder.lua
Original file line number Diff line number Diff line change
@@ -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
23 changes: 23 additions & 0 deletions tests/blocks/protocol/varicodedecoder_spec.lua
Original file line number Diff line number Diff line change
@@ -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})
21 changes: 21 additions & 0 deletions tests/generate/blocks/protocol/varicodedecoder_spec.py
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit fde77b2

Please sign in to comment.