From 2851102398e565a3533d5d4f48b633e33d96cea5 Mon Sep 17 00:00:00 2001 From: Martin Hebnes Pedersen Date: Tue, 7 May 2019 22:38:16 +0200 Subject: [PATCH 1/2] Fix serialization of Confirmed DataBlock The serialized form should be 10 octets of user-data plus the two octets for serial/crc. Previous implementation forgot to account for the two extra octets when allocating the final data slice. --- data.go | 3 +++ data_test.go | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/data.go b/data.go index 049f812..0eb998d 100644 --- a/data.go +++ b/data.go @@ -81,6 +81,9 @@ func (db *DataBlock) Bytes(dataType uint8, confirmed bool) []byte { // Applying CRC mask, see DMR AI spec. page 143 db.CRC ^= 0x01ff + // Grow data slice to support the two byte prefix + data = append(data, make([]byte, 2)...) + data[0] = (db.Serial << 1) | (uint8(db.CRC>>8) & 0x01) data[1] = uint8(db.CRC) copy(data[2:], db.Data) diff --git a/data_test.go b/data_test.go index 04aaa84..f717d59 100644 --- a/data_test.go +++ b/data_test.go @@ -19,7 +19,8 @@ func TestDataBlock(t *testing.T) { if data == nil { t.Fatal("encode failed") } - size := int(dataBlockLength(Rate34Data, true)) + // Size is the user-data + two octets of serial/crc + size := int(dataBlockLength(Rate34Data, true)) + 2 if len(data) != size { t.Fatalf("encode failed: expected %d bytes, got %d", size, len(data)) } From 29c24593f9e1fbc433d992fe4768ced41050a787 Mon Sep 17 00:00:00 2001 From: Martin Hebnes Pedersen Date: Tue, 7 May 2019 22:38:24 +0200 Subject: [PATCH 2/2] Support Rate 1/2 Data CRC Mask The previous implementation hardcoded the mask for Rate 3/4 Data (0x01ff), causing CRC check failure for Rate 1/2 on both encode and decode. This patch also refactors to avoid code copying and fixes a bug where calling DataBlock.Byte() on the output of Fragment.DataBlocks() produced an incorrect CRC value due to Bytes() not resetting db.CRC before performing it's own CRC calculation. --- data.go | 61 +++++++++++++++++++++++++-------------------------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/data.go b/data.go index 0eb998d..6aace42 100644 --- a/data.go +++ b/data.go @@ -15,6 +15,30 @@ const ( MaxPacketFragmentSize = 1500 ) +// CRC Masks for data block's CRC-9 calculation, see DMR AI spec. page 148 (Table B.21). +var crc9Masks = map[uint8]uint16{ + Rate12Data: 0x00f0, + Rate34Data: 0x01ff, + //Rate1Data: 0x010f, +} + +func calculateCRC9(serial uint8, data []byte, dataType uint8) (crc uint16) { + for _, block := range data { + crc9(&crc, block, 8) + } + crc9(&crc, serial, 7) + crc9end(&crc, 8) + + // Inverting according to the inversion polynomial. + crc = ^crc + crc &= 0x01ff + + // Applying Data Type CRC Mask + crc ^= crc9Masks[dataType] + + return crc +} + type DataBlock struct { Serial uint8 CRC uint16 @@ -37,17 +61,7 @@ func ParseDataBlock(data []byte, dataType uint8, confirmed bool) (*DataBlock, er db.Data = make([]byte, db.Length) copy(db.Data, data[2:2+db.Length]) - for _, block := range db.Data { - crc9(&crc, block, 8) - } - crc9(&crc, db.Serial, 7) - crc9end(&crc, 8) - - // Inverting according to the inversion polynomial. - crc = ^crc - crc &= 0x01ff - // Applying CRC mask, see DMR AI spec. page 143 - crc ^= 0x01ff + crc = calculateCRC9(db.Serial, db.Data, dataType) // FIXME(pd0mz): this is not working if crc != db.CRC { @@ -69,17 +83,7 @@ func (db *DataBlock) Bytes(dataType uint8, confirmed bool) []byte { ) if confirmed { - for _, block := range db.Data { - crc9(&db.CRC, block, 8) - } - crc9(&db.CRC, db.Serial, 7) - crc9end(&db.CRC, 8) - - // Inverting according to the inversion polynomial. - db.CRC = ^db.CRC - db.CRC &= 0x01ff - // Applying CRC mask, see DMR AI spec. page 143 - db.CRC ^= 0x01ff + db.CRC = calculateCRC9(db.Serial, db.Data, dataType) // Grow data slice to support the two byte prefix data = append(data, make([]byte, 2)...) @@ -180,18 +184,7 @@ func (df *DataFragment) DataBlocks(dataType uint8, confirm bool) ([]*DataBlock, } // Calculate block CRC9 - block.CRC = 0 - for _, b := range block.Data { - crc9(&block.CRC, b, 8) - } - crc9(&block.CRC, block.Serial, 7) - crc9end(&block.CRC, 8) - - // Inverting according to the inversion polynomial - block.CRC = ^block.CRC - block.CRC &= 0x01ff - // Applying CRC mask, see DMR AI spec. page 143 - block.CRC ^= 0x01ff + block.CRC = calculateCRC9(block.Serial, block.Data, dataType) blocks[i] = block }