Skip to content

Commit

Permalink
blocks/protocol/scmplusframer: add SCMPlusFramerBlock
Browse files Browse the repository at this point in the history
  • Loading branch information
vsergeev committed Oct 22, 2020
1 parent 057dc9c commit db7b1c8
Show file tree
Hide file tree
Showing 4 changed files with 312 additions and 0 deletions.
1 change: 1 addition & 0 deletions radio/blocks/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,5 @@ return {
--- ERT
IDMFramerBlock = require('radio.blocks.protocol.idmframer'),
SCMFramerBlock = require('radio.blocks.protocol.scmframer'),
SCMPlusFramerBlock = require('radio.blocks.protocol.scmplusframer'),
}
227 changes: 227 additions & 0 deletions radio/blocks/protocol/scmplusframer.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
---
-- Validate and extract SCM+ frames from a bit stream.
--
-- @category Protocol
-- @block SCMPlusFramerBlock
--
-- @signature in:Bit > out:SCMPlusFrameType
--
-- @usage
-- local framer = radio.SCMPlusFramerBlock()

---
-- SCM+ frame type, a Lua object with properties:
--
-- ``` text
-- {
-- type = "scm+",
-- protocol_id = <8-bit integer>,
-- ert_type = <8-bit integer>,
-- ert_id = <32-bit integer>,
-- consumption = <32-bit integer>,
-- tamper = <16-bit integer>,
-- crc = <16-bit integer>,
-- }
-- ```
--
-- @datatype SCMPlusFramerBlock.SCMPlusFrameType
-- @tparam string type Protocol type, constant "scm+"
-- @tparam int protocol_id Protocol ID field, 8-bits wide
-- @tparam int ert_type ERT Type field, 8-bits wide
-- @tparam int ert_id ERT ID field, 32-bits wide
-- @tparam int consumption Consumption field, 32-bits wide
-- @tparam int tamper Tamper field, 16-bits wide
-- @tparam int crc CRC field, 16-bits wide

local ffi = require('ffi')
local bit = require('bit')

local block = require('radio.core.block')
local debug = require('radio.core.debug')
local types = require('radio.types')

-- SCM+ Related Constants

local SCM_PLUS_PREAMBLE = types.Bit.vector_from_array({0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1})
local SCM_PLUS_FRAME_LEN = 128
local SCM_PLUS_CODEWORD_LEN = 112

-- Parity check matrix
-- Mapping of bit position to syndrome
local SCM_PLUS_CHECK_SYNDROMES = {
[0] = 0xaaa1, [1] = 0xdd40, [2] = 0x6ea0, [3] = 0x3750,
[4] = 0x1ba8, [5] = 0x0dd4, [6] = 0x06ea, [7] = 0x0375,
[8] = 0x89aa, [9] = 0x44d5, [10] = 0xaa7a, [11] = 0x553d,
[12] = 0xa28e, [13] = 0x5147, [14] = 0xa0b3, [15] = 0xd849,
[16] = 0xe434, [17] = 0x721a, [18] = 0x390d, [19] = 0x9496,
[20] = 0x4a4b, [21] = 0xad35, [22] = 0xde8a, [23] = 0x6f45,
[24] = 0xbfb2, [25] = 0x5fd9, [26] = 0xa7fc, [27] = 0x53fe,
[28] = 0x29ff, [29] = 0x9cef, [30] = 0xc667, [31] = 0xeb23,
[32] = 0xfd81, [33] = 0xf6d0, [34] = 0x7b68, [35] = 0x3db4,
[36] = 0x1eda, [37] = 0x0f6d, [38] = 0x8fa6, [39] = 0x47d3,
[40] = 0xabf9, [41] = 0xddec, [42] = 0x6ef6, [43] = 0x377b,
[44] = 0x93ad, [45] = 0xc1c6, [46] = 0x60e3, [47] = 0xb861,
[48] = 0xd420, [49] = 0x6a10, [50] = 0x3508, [51] = 0x1a84,
[52] = 0x0d42, [53] = 0x06a1, [54] = 0x8b40, [55] = 0x45a0,
[56] = 0x22d0, [57] = 0x1168, [58] = 0x08b4, [59] = 0x045a,
[60] = 0x022d, [61] = 0x8906, [62] = 0x4483, [63] = 0xaa51,
[64] = 0xdd38, [65] = 0x6e9c, [66] = 0x374e, [67] = 0x1ba7,
[68] = 0x85c3, [69] = 0xcaf1, [70] = 0xed68, [71] = 0x76b4,
[72] = 0x3b5a, [73] = 0x1dad, [74] = 0x86c6, [75] = 0x4363,
[76] = 0xa9a1, [77] = 0xdcc0, [78] = 0x6e60, [79] = 0x3730,
[80] = 0x1b98, [81] = 0x0dcc, [82] = 0x06e6, [83] = 0x0373,
[84] = 0x89a9, [85] = 0xccc4, [86] = 0x6662, [87] = 0x3331,
[88] = 0x9188, [89] = 0x48c4, [90] = 0x2462, [91] = 0x1231,
[92] = 0x8108, [93] = 0x4084, [94] = 0x2042, [95] = 0x1021,
[96] = 0x8000, [97] = 0x4000, [98] = 0x2000, [99] = 0x1000,
[100] = 0x0800, [101] = 0x0400, [102] = 0x0200, [103] = 0x0100,
[104] = 0x0080, [105] = 0x0040, [106] = 0x0020, [107] = 0x0010,
[108] = 0x0008, [109] = 0x0004, [110] = 0x0002, [111] = 0x0001,
}

-- Syndrome correction table (for single bit correction)
-- Mapping of syndrome to bit position
local SCM_PLUS_CORRECT_SYNDROMES = {
[0xaaa1] = 0, [0xdd40] = 1, [0x6ea0] = 2, [0x3750] = 3,
[0x1ba8] = 4, [0x0dd4] = 5, [0x06ea] = 6, [0x0375] = 7,
[0x89aa] = 8, [0x44d5] = 9, [0xaa7a] = 10, [0x553d] = 11,
[0xa28e] = 12, [0x5147] = 13, [0xa0b3] = 14, [0xd849] = 15,
[0xe434] = 16, [0x721a] = 17, [0x390d] = 18, [0x9496] = 19,
[0x4a4b] = 20, [0xad35] = 21, [0xde8a] = 22, [0x6f45] = 23,
[0xbfb2] = 24, [0x5fd9] = 25, [0xa7fc] = 26, [0x53fe] = 27,
[0x29ff] = 28, [0x9cef] = 29, [0xc667] = 30, [0xeb23] = 31,
[0xfd81] = 32, [0xf6d0] = 33, [0x7b68] = 34, [0x3db4] = 35,
[0x1eda] = 36, [0x0f6d] = 37, [0x8fa6] = 38, [0x47d3] = 39,
[0xabf9] = 40, [0xddec] = 41, [0x6ef6] = 42, [0x377b] = 43,
[0x93ad] = 44, [0xc1c6] = 45, [0x60e3] = 46, [0xb861] = 47,
[0xd420] = 48, [0x6a10] = 49, [0x3508] = 50, [0x1a84] = 51,
[0x0d42] = 52, [0x06a1] = 53, [0x8b40] = 54, [0x45a0] = 55,
[0x22d0] = 56, [0x1168] = 57, [0x08b4] = 58, [0x045a] = 59,
[0x022d] = 60, [0x8906] = 61, [0x4483] = 62, [0xaa51] = 63,
[0xdd38] = 64, [0x6e9c] = 65, [0x374e] = 66, [0x1ba7] = 67,
[0x85c3] = 68, [0xcaf1] = 69, [0xed68] = 70, [0x76b4] = 71,
[0x3b5a] = 72, [0x1dad] = 73, [0x86c6] = 74, [0x4363] = 75,
[0xa9a1] = 76, [0xdcc0] = 77, [0x6e60] = 78, [0x3730] = 79,
[0x1b98] = 80, [0x0dcc] = 81, [0x06e6] = 82, [0x0373] = 83,
[0x89a9] = 84, [0xccc4] = 85, [0x6662] = 86, [0x3331] = 87,
[0x9188] = 88, [0x48c4] = 89, [0x2462] = 90, [0x1231] = 91,
[0x8108] = 92, [0x4084] = 93, [0x2042] = 94, [0x1021] = 95,
[0x8000] = 96, [0x4000] = 97, [0x2000] = 98, [0x1000] = 99,
[0x0800] = 100, [0x0400] = 101, [0x0200] = 102, [0x0100] = 103,
[0x0080] = 104, [0x0040] = 105, [0x0020] = 106, [0x0010] = 107,
[0x0008] = 108, [0x0004] = 109, [0x0002] = 110, [0x0001] = 111,
}

-- SCM+ Frame Type

local SCMPlusFrameType = types.ObjectType.factory()

function SCMPlusFrameType.new(protocol_id, ert_type, ert_id, consumption, tamper, crc)
local self = setmetatable({}, SCMPlusFrameType)
self.type = "scm+"
self.protocol_id = protocol_id
self.ert_type = ert_type
self.ert_id = ert_id
self.consumption = consumption
self.tamper = tamper
self.crc = crc
return self
end

function SCMPlusFrameType:__tostring()
return string.format("SCMPlusFrame<protocol_id=0x%02x, ert_type=0x%02x, ert_id=%u, consumption=%u, tamper=0x%04x, crc=0x%04x>", self.protocol_id, self.ert_type, self.ert_id, self.consumption, self.tamper, self.crc)
end

-- SCM+ Framer Block

local SCMPlusFramerBlock = block.factory("SCMPlusFramerBlock")

SCMPlusFramerBlock.SCM_PLUS_PREAMBLE = SCM_PLUS_PREAMBLE
SCMPlusFramerBlock.SCM_PLUS_FRAME_LEN = SCM_PLUS_FRAME_LEN
SCMPlusFramerBlock.SCMPlusFrameType = SCMPlusFrameType

function SCMPlusFramerBlock:instantiate()
self:add_type_signature({block.Input("in", types.Bit)}, {block.Output("out", SCMPlusFrameType)})
end

function SCMPlusFramerBlock:initialize()
self.scm_plus_frame = types.Bit.vector(SCM_PLUS_FRAME_LEN)
self.scm_plus_frame_length = 0

self.out = SCMPlusFrameType.vector()
end

local function scm_plus_correct_codeword(bits, offset)
-- 112-bit codeword = 96-bits message + 16-bits error correcting code

-- Compute syndrome
local syndrome = 0x7b06
for i = 0, SCM_PLUS_CODEWORD_LEN-1 do
if bits.data[offset + i].value == 1 then
syndrome = bit.bxor(syndrome, SCM_PLUS_CHECK_SYNDROMES[i])
end
end

-- If the syndrome is zero, there is no error and return true
if syndrome == 0 then
return true
end

-- If there is a single correctable bit error, correct it and return true
local error_index = SCM_PLUS_CORRECT_SYNDROMES[syndrome]
if error_index then
bits.data[offset + error_index] = bits.data[offset + error_index]:bnot()
return true
end

-- If the codeword is uncorrectable, return false
return false
end

function SCMPlusFramerBlock:process(x)
local out = self.out:resize(0)

local i = 0
while i < x.length do
-- Shift in as many bits as we can into the frame buffer
if self.scm_plus_frame_length < SCM_PLUS_FRAME_LEN then
-- Calculate the maximum number of bits we can shift from x
local n = math.min(SCM_PLUS_FRAME_LEN - self.scm_plus_frame_length, x.length-i)

ffi.copy(self.scm_plus_frame.data[self.scm_plus_frame_length], x.data[i], n*ffi.sizeof(self.scm_plus_frame.data[0]))
i, self.scm_plus_frame_length = i + n, self.scm_plus_frame_length + n
elseif self.scm_plus_frame_length == SCM_PLUS_FRAME_LEN then
-- Shift frame buffer down by one bit
ffi.C.memmove(self.scm_plus_frame.data[0], self.scm_plus_frame.data[1], (SCM_PLUS_FRAME_LEN-1)*ffi.sizeof(self.scm_plus_frame.data[0]))

-- Shift in one bit from x
self.scm_plus_frame.data[SCM_PLUS_FRAME_LEN-1] = x.data[i]
i = i + 1
end

-- Try to validate the frame
if self.scm_plus_frame_length == SCM_PLUS_FRAME_LEN then
local frame_sync = types.Bit.tonumber(self.scm_plus_frame, 0, 16)

if frame_sync == 0x16a3 and scm_plus_correct_codeword(self.scm_plus_frame, 16) then
local protocol_id = types.Bit.tonumber(self.scm_plus_frame, 16, 8)

if protocol_id == 0x1e then
local ert_type = types.Bit.tonumber(self.scm_plus_frame, 24, 8)
local ert_id = types.Bit.tonumber(self.scm_plus_frame, 32, 32)
local consumption = types.Bit.tonumber(self.scm_plus_frame, 64, 32)
local tamper = types.Bit.tonumber(self.scm_plus_frame, 96, 16)
local crc = types.Bit.tonumber(self.scm_plus_frame, 112, 16)

out:append(SCMPlusFrameType(protocol_id, ert_type, ert_id, consumption, tamper, crc))

self.scm_plus_frame_length = 0
end
end
end
end

return out
end

return SCMPlusFramerBlock
43 changes: 43 additions & 0 deletions tests/blocks/protocol/scmplusframer_spec.gen.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
-- Do not edit! This file was generated by blocks/protocol/scmplusframer_spec.py

local radio = require('radio')
local jigs = require('tests.jigs')

jigs.TestBlock(radio.SCMPlusFramerBlock, {
{
desc = "Valid frame 1",
args = {},
inputs = {radio.types.Bit.vector_from_array({0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0})},
outputs = {require('radio.blocks.protocol.scmplusframer').SCMPlusFrameType.vector_from_array({{0x1e, 0xbc, 100169616, 169294, 0x0908, 0xcef1}})}
},
{
desc = "Valid frame 2",
args = {},
inputs = {radio.types.Bit.vector_from_array({0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1})},
outputs = {require('radio.blocks.protocol.scmplusframer').SCMPlusFrameType.vector_from_array({{0x1e, 0x9c, 91309068, 8438900, 0x1310, 0x419c}})}
},
{
desc = "Valid frame 3",
args = {},
inputs = {radio.types.Bit.vector_from_array({1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0})},
outputs = {require('radio.blocks.protocol.scmplusframer').SCMPlusFrameType.vector_from_array({{0x1e, 0x9c, 91307242, 3322100, 0x1510, 0x2549}})}
},
{
desc = "Frame 1 with message bit error",
args = {},
inputs = {radio.types.Bit.vector_from_array({1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0})},
outputs = {require('radio.blocks.protocol.scmplusframer').SCMPlusFrameType.vector_from_array({{0x1e, 0xbc, 100169616, 169294, 0x0908, 0xcef1}})}
},
{
desc = "Frame 2 with crc bit error",
args = {},
inputs = {radio.types.Bit.vector_from_array({0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0})},
outputs = {require('radio.blocks.protocol.scmplusframer').SCMPlusFrameType.vector_from_array({{0x1e, 0x9c, 91309068, 8438900, 0x1310, 0x419c}})}
},
{
desc = "Three frames",
args = {},
inputs = {radio.types.Bit.vector_from_array({1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1})},
outputs = {require('radio.blocks.protocol.scmplusframer').SCMPlusFrameType.vector_from_array({{0x1e, 0xbc, 100169616, 169294, 0x0908, 0xcef1},{0x1e, 0x9c, 91309068, 8438900, 0x1310, 0x419c},{0x1e, 0x9c, 91307242, 3322100, 0x1510, 0x2549}})}
},
}, {epsilon = 1.0e-06})
41 changes: 41 additions & 0 deletions tests/blocks/protocol/scmplusframer_spec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import numpy
from generate import *


def generate():
def test_vector_wrapper(frames):
template = "require('radio.blocks.protocol.scmplusframer').SCMPlusFrameType.vector_from_array({%s})"
return [template % (','.join(frames))]

frame1_bits = numpy.array([0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1], dtype=numpy.bool_)
frame1_object = "{0x1e, 0xbc, 100169616, 169294, 0x0908, 0xcef1}"

frame2_bits = numpy.array([0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0], dtype=numpy.bool_)
frame2_object = "{0x1e, 0x9c, 91309068, 8438900, 0x1310, 0x419c}"

frame3_bits = numpy.array([0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1], dtype=numpy.bool_)
frame3_object = "{0x1e, 0x9c, 91307242, 3322100, 0x1510, 0x2549}"

vectors = []

x = numpy.hstack([random_bit(20), frame1_bits, random_bit(20)])
vectors.append(TestVector([], [x], test_vector_wrapper([frame1_object]), "Valid frame 1"))

x = numpy.hstack([random_bit(20), frame2_bits, random_bit(20)])
vectors.append(TestVector([], [x], test_vector_wrapper([frame2_object]), "Valid frame 2"))

x = numpy.hstack([random_bit(20), frame3_bits, random_bit(20)])
vectors.append(TestVector([], [x], test_vector_wrapper([frame3_object]), "Valid frame 3"))

x = numpy.hstack([random_bit(20), frame1_bits, random_bit(20)])
x[70] = not x[70]
vectors.append(TestVector([], [x], test_vector_wrapper([frame1_object]), "Frame 1 with message bit error"))

x = numpy.hstack([random_bit(20), frame2_bits, random_bit(20)])
x[140] = not x[140]
vectors.append(TestVector([], [x], test_vector_wrapper([frame2_object]), "Frame 2 with crc bit error"))

x = numpy.hstack([random_bit(20), frame1_bits, random_bit(20), frame2_bits, random_bit(20), frame3_bits, random_bit(20)])
vectors.append(TestVector([], [x], test_vector_wrapper([frame1_object, frame2_object, frame3_object]), "Three frames"))

return BlockSpec("SCMPlusFramerBlock", vectors, 1e-6)

0 comments on commit db7b1c8

Please sign in to comment.