diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 2ca0a02..62fd668 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -200,6 +200,7 @@ + @@ -270,6 +271,7 @@ + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 7fb37a0..d6ba4f3 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -227,6 +227,9 @@ Header Files + + Header Files + @@ -424,5 +427,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/P25Control.cpp b/P25Control.cpp index 183d439..647148e 100644 --- a/P25Control.cpp +++ b/P25Control.cpp @@ -67,6 +67,10 @@ m_netLDU1(NULL), m_netLDU2(NULL), m_lastIMBE(NULL), m_rfLDU(NULL), +m_rfPDURaw(NULL), +m_rfPDUCooked(NULL), +m_rfPDUCount(0U), +m_rfPDUBits(0U), m_rssiMapper(rssiMapper), m_rssi(0U), m_maxRSSI(0U), @@ -90,6 +94,12 @@ m_fp(NULL) m_rfLDU = new unsigned char[P25_LDU_FRAME_LENGTH_BYTES]; ::memset(m_rfLDU, 0x00U, P25_LDU_FRAME_LENGTH_BYTES); + + m_rfPDURaw = new unsigned char[P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES]; + ::memset(m_rfPDURaw, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES); + + m_rfPDUCooked = new unsigned char[P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES]; + ::memset(m_rfPDUCooked, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES); } CP25Control::~CP25Control() @@ -98,6 +108,8 @@ CP25Control::~CP25Control() delete[] m_netLDU2; delete[] m_lastIMBE; delete[] m_rfLDU; + delete[] m_rfPDURaw; + delete[] m_rfPDUCooked; } bool CP25Control::writeModem(unsigned char* data, unsigned int len) @@ -126,6 +138,19 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) return false; } + if (data[0U] == TAG_LOST && m_rfState == RS_RF_DATA) { + if (m_netState == RS_NET_IDLE) + m_display->clearP25(); + + m_rfState = RS_RF_LISTENING; + m_rfPDUCount = 0U; + m_rfPDUBits = 0U; +#if defined(DUMP_P25) + closeFile(); +#endif + return false; + } + if (data[0U] == TAG_LOST) { m_rfState = RS_RF_LISTENING; return false; @@ -362,9 +387,29 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) } } } else if (duid == P25_DUID_PDU) { + if (m_rfState != RS_RF_DATA) { + m_rfPDUCount = 0U; + m_rfPDUBits = 0U; + m_rfState = RS_RF_DATA; + } + + unsigned int start = m_rfPDUCount * P25_LDU_FRAME_LENGTH_BITS; + + unsigned char buffer[P25_LDU_FRAME_LENGTH_BYTES]; + unsigned int bits = CP25Utils::decode(data + 2U, buffer, start, start + P25_LDU_FRAME_LENGTH_BITS); + + for (unsigned int i = 0U; i < bits; i++, m_rfPDUBits++) { + bool b = READ_BIT(buffer, i); + WRITE_BIT(m_rfPDUCooked, m_rfPDUBits, b); + } + + ::memcpy(m_rfPDURaw + m_rfPDUCount * P25_LDU_FRAME_LENGTH_BYTES, data + 2U, P25_LDU_FRAME_LENGTH_BYTES); + m_rfPDUCount++; + + LogMessage("P25, received %u (%u) bits in %u LDUs", m_rfPDUBits, m_rfPDUBits - P25_SYNC_BITS_LENGTH - P25_NID_LENGTH_BITS, m_rfPDUCount); + LogMessage("P25, PDU received"); CUtils::dump("P25, PDU data", data + 2U, P25_LDU_FRAME_LENGTH_BYTES); - m_rfState = RS_RF_DATA; } return false; diff --git a/P25Control.h b/P25Control.h index cd0ca7c..fa1e180 100644 --- a/P25Control.h +++ b/P25Control.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX +* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -77,6 +77,10 @@ private: unsigned char* m_netLDU2; unsigned char* m_lastIMBE; unsigned char* m_rfLDU; + unsigned char* m_rfPDURaw; + unsigned char* m_rfPDUCooked; + unsigned int m_rfPDUCount; + unsigned int m_rfPDUBits; CRSSIInterpolator* m_rssiMapper; unsigned char m_rssi; unsigned char m_maxRSSI; diff --git a/P25Defines.h b/P25Defines.h index 14e2915..617a10e 100644 --- a/P25Defines.h +++ b/P25Defines.h @@ -38,6 +38,9 @@ const unsigned int P25_NID_LENGTH_BITS = P25_NID_LENGTH_BYTES * 8U; const unsigned char P25_SYNC_BYTES[] = {0x55U, 0x75U, 0xF5U, 0xFFU, 0x77U, 0xFFU}; const unsigned char P25_SYNC_BYTES_LENGTH = 6U; +const unsigned int P25_SYNC_BITS_LENGTH = P25_SYNC_BYTES_LENGTH * 8U; + +const unsigned int P25_MAX_PDU_COUNT = 10U; const unsigned int P25_MI_LENGTH_BYTES = 9U; diff --git a/P25Trellis.cpp b/P25Trellis.cpp new file mode 100644 index 0000000..8f8cf2c --- /dev/null +++ b/P25Trellis.cpp @@ -0,0 +1,529 @@ +/* +* Copyright (C) 2016,2018 by Jonathan Naylor, G4KLX +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; version 2 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include "P25Trellis.h" +#include "Log.h" + +#include +#include + +const unsigned int INTERLEAVE_TABLE[] = { + 0U, 1U, 8U, 9U, 16U, 17U, 24U, 25U, 32U, 33U, 40U, 41U, 48U, 49U, 56U, 57U, 64U, 65U, 72U, 73U, 80U, 81U, 88U, 89U, 96U, 97U, + 2U, 3U, 10U, 11U, 18U, 19U, 26U, 27U, 34U, 35U, 42U, 43U, 50U, 51U, 58U, 59U, 66U, 67U, 74U, 75U, 82U, 83U, 90U, 91U, + 4U, 5U, 12U, 13U, 20U, 21U, 28U, 29U, 36U, 37U, 44U, 45U, 52U, 53U, 60U, 61U, 68U, 69U, 76U, 77U, 84U, 85U, 92U, 93U, + 6U, 7U, 14U, 15U, 22U, 23U, 30U, 31U, 38U, 39U, 46U, 47U, 54U, 55U, 62U, 63U, 70U, 71U, 78U, 79U, 86U, 87U, 94U, 95U}; + +const unsigned char ENCODE_TABLE_34[] = { + 0U, 8U, 4U, 12U, 2U, 10U, 6U, 14U, + 4U, 12U, 2U, 10U, 6U, 14U, 0U, 8U, + 1U, 9U, 5U, 13U, 3U, 11U, 7U, 15U, + 5U, 13U, 3U, 11U, 7U, 15U, 1U, 9U, + 3U, 11U, 7U, 15U, 1U, 9U, 5U, 13U, + 7U, 15U, 1U, 9U, 5U, 13U, 3U, 11U, + 2U, 10U, 6U, 14U, 0U, 8U, 4U, 12U, + 6U, 14U, 0U, 8U, 4U, 12U, 2U, 10U}; + +const unsigned char ENCODE_TABLE_12[] = { + 0U, 15U, 12U, 3U, + 4U, 11U, 8U, 7U, + 13U, 2U, 1U, 14U, + 9U, 6U, 5U, 10U}; + +const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; + +#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) +#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) + +CP25Trellis::CP25Trellis() +{ +} + +CP25Trellis::~CP25Trellis() +{ +} + +bool CP25Trellis::decode34(const unsigned char* data, unsigned char* payload) +{ + assert(data != NULL); + assert(payload != NULL); + + signed char dibits[98U]; + deinterleave(data, dibits); + + unsigned char points[49U]; + dibitsToPoints(dibits, points); + + // Check the original code + unsigned char tribits[49U]; + unsigned int failPos = checkCode34(points, tribits); + if (failPos == 999U) { + tribitsToBits(tribits, payload); + return true; + } + + unsigned char savePoints[49U]; + for (unsigned int i = 0U; i < 49U; i++) + savePoints[i] = points[i]; + + bool ret = fixCode34(points, failPos, payload); + if (ret) + return true; + + if (failPos == 0U) + return false; + + // Backtrack one place for a last go + return fixCode34(savePoints, failPos - 1U, payload); +} + +void CP25Trellis::encode34(const unsigned char* payload, unsigned char* data) +{ + assert(payload != NULL); + assert(data != NULL); + + unsigned char tribits[49U]; + bitsToTribits(payload, tribits); + + unsigned char points[49U]; + unsigned char state = 0U; + + for (unsigned int i = 0U; i < 49U; i++) { + unsigned char tribit = tribits[i]; + + points[i] = ENCODE_TABLE_34[state * 8U + tribit]; + + state = tribit; + } + + signed char dibits[98U]; + pointsToDibits(points, dibits); + + interleave(dibits, data); +} + +bool CP25Trellis::decode12(const unsigned char* data, unsigned char* payload) +{ + assert(data != NULL); + assert(payload != NULL); + + signed char dibits[98U]; + deinterleave(data, dibits); + + unsigned char points[49U]; + dibitsToPoints(dibits, points); + + // Check the original code + unsigned char bits[49U]; + unsigned int failPos = checkCode12(points, bits); + if (failPos == 999U) { + dibitsToBits(bits, payload); + return true; + } + + unsigned char savePoints[49U]; + for (unsigned int i = 0U; i < 49U; i++) + savePoints[i] = points[i]; + + bool ret = fixCode12(points, failPos, payload); + if (ret) + return true; + + if (failPos == 0U) + return false; + + // Backtrack one place for a last go + return fixCode12(savePoints, failPos - 1U, payload); +} + +void CP25Trellis::encode12(const unsigned char* payload, unsigned char* data) +{ + assert(payload != NULL); + assert(data != NULL); + + unsigned char bits[49U]; + bitsToDibits(payload, bits); + + unsigned char points[49U]; + unsigned char state = 0U; + + for (unsigned int i = 0U; i < 49U; i++) { + unsigned char bit = bits[i]; + + points[i] = ENCODE_TABLE_12[state * 4U + bit]; + + state = bit; + } + + signed char dibits[98U]; + pointsToDibits(points, dibits); + + interleave(dibits, data); +} + +void CP25Trellis::deinterleave(const unsigned char* data, signed char* dibits) const +{ + for (unsigned int i = 0U; i < 98U; i++) { + unsigned int n = i * 2U + 0U; + if (n >= 98U) n += 68U; + bool b1 = READ_BIT(data, n) != 0x00U; + + n = i * 2U + 1U; + if (n >= 98U) n += 68U; + bool b2 = READ_BIT(data, n) != 0x00U; + + signed char dibit; + if (!b1 && b2) + dibit = +3; + else if (!b1 && !b2) + dibit = +1; + else if (b1 && !b2) + dibit = -1; + else + dibit = -3; + + n = INTERLEAVE_TABLE[i]; + dibits[n] = dibit; + } +} + +void CP25Trellis::interleave(const signed char* dibits, unsigned char* data) const +{ + for (unsigned int i = 0U; i < 98U; i++) { + unsigned int n = INTERLEAVE_TABLE[i]; + + bool b1, b2; + switch (dibits[n]) { + case +3: + b1 = false; + b2 = true; + break; + case +1: + b1 = false; + b2 = false; + break; + case -1: + b1 = true; + b2 = false; + break; + default: + b1 = true; + b2 = true; + break; + } + + n = i * 2U + 0U; + if (n >= 98U) n += 68U; + WRITE_BIT(data, n, b1); + + n = i * 2U + 1U; + if (n >= 98U) n += 68U; + WRITE_BIT(data, n, b2); + } +} + +void CP25Trellis::dibitsToPoints(const signed char* dibits, unsigned char* points) const +{ + for (unsigned int i = 0U; i < 49U; i++) { + if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == -1) + points[i] = 0U; + else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == -1) + points[i] = 1U; + else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == -3) + points[i] = 2U; + else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == -3) + points[i] = 3U; + else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == -1) + points[i] = 4U; + else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == -1) + points[i] = 5U; + else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == -3) + points[i] = 6U; + else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == -3) + points[i] = 7U; + else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == +3) + points[i] = 8U; + else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == +3) + points[i] = 9U; + else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == +1) + points[i] = 10U; + else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == +1) + points[i] = 11U; + else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == +3) + points[i] = 12U; + else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == +3) + points[i] = 13U; + else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == +1) + points[i] = 14U; + else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == +1) + points[i] = 15U; + } +} + +void CP25Trellis::pointsToDibits(const unsigned char* points, signed char* dibits) const +{ + for (unsigned int i = 0U; i < 49U; i++) { + switch (points[i]) { + case 0U: + dibits[i * 2U + 0U] = +1; + dibits[i * 2U + 1U] = -1; + break; + case 1U: + dibits[i * 2U + 0U] = -1; + dibits[i * 2U + 1U] = -1; + break; + case 2U: + dibits[i * 2U + 0U] = +3; + dibits[i * 2U + 1U] = -3; + break; + case 3U: + dibits[i * 2U + 0U] = -3; + dibits[i * 2U + 1U] = -3; + break; + case 4U: + dibits[i * 2U + 0U] = -3; + dibits[i * 2U + 1U] = -1; + break; + case 5U: + dibits[i * 2U + 0U] = +3; + dibits[i * 2U + 1U] = -1; + break; + case 6U: + dibits[i * 2U + 0U] = -1; + dibits[i * 2U + 1U] = -3; + break; + case 7U: + dibits[i * 2U + 0U] = +1; + dibits[i * 2U + 1U] = -3; + break; + case 8U: + dibits[i * 2U + 0U] = -3; + dibits[i * 2U + 1U] = +3; + break; + case 9U: + dibits[i * 2U + 0U] = +3; + dibits[i * 2U + 1U] = +3; + break; + case 10U: + dibits[i * 2U + 0U] = -1; + dibits[i * 2U + 1U] = +1; + break; + case 11U: + dibits[i * 2U + 0U] = +1; + dibits[i * 2U + 1U] = +1; + break; + case 12U: + dibits[i * 2U + 0U] = +1; + dibits[i * 2U + 1U] = +3; + break; + case 13U: + dibits[i * 2U + 0U] = -1; + dibits[i * 2U + 1U] = +3; + break; + case 14U: + dibits[i * 2U + 0U] = +3; + dibits[i * 2U + 1U] = +1; + break; + default: + dibits[i * 2U + 0U] = -3; + dibits[i * 2U + 1U] = +1; + break; + } + } +} + +void CP25Trellis::bitsToTribits(const unsigned char* payload, unsigned char* tribits) const +{ + for (unsigned int i = 0U; i < 48U; i++) { + unsigned int n = i * 3U; + + bool b1 = READ_BIT(payload, n) != 0x00U; + n++; + bool b2 = READ_BIT(payload, n) != 0x00U; + n++; + bool b3 = READ_BIT(payload, n) != 0x00U; + + unsigned char tribit = 0U; + tribit |= b1 ? 4U : 0U; + tribit |= b2 ? 2U : 0U; + tribit |= b3 ? 1U : 0U; + + tribits[i] = tribit; + } + + tribits[48U] = 0U; +} + +void CP25Trellis::bitsToDibits(const unsigned char* payload, unsigned char* dibits) const +{ + for (unsigned int i = 0U; i < 48U; i++) { + unsigned int n = i * 2U; + + bool b1 = READ_BIT(payload, n) != 0x00U; + n++; + bool b2 = READ_BIT(payload, n) != 0x00U; + + unsigned char dibit = 0U; + dibit |= b1 ? 2U : 0U; + dibit |= b2 ? 1U : 0U; + + dibits[i] = dibit; + } + + dibits[48U] = 0U; +} + +void CP25Trellis::tribitsToBits(const unsigned char* tribits, unsigned char* payload) const +{ + for (unsigned int i = 0U; i < 48U; i++) { + unsigned char tribit = tribits[i]; + + bool b1 = (tribit & 0x04U) == 0x04U; + bool b2 = (tribit & 0x02U) == 0x02U; + bool b3 = (tribit & 0x01U) == 0x01U; + + unsigned int n = i * 3U; + + WRITE_BIT(payload, n, b1); + n++; + WRITE_BIT(payload, n, b2); + n++; + WRITE_BIT(payload, n, b3); + } +} + +void CP25Trellis::dibitsToBits(const unsigned char* dibits, unsigned char* payload) const +{ + for (unsigned int i = 0U; i < 48U; i++) { + unsigned char dibit = dibits[i]; + + bool b1 = (dibit & 0x02U) == 0x02U; + bool b2 = (dibit & 0x01U) == 0x01U; + + unsigned int n = i * 2U; + + WRITE_BIT(payload, n, b1); + n++; + WRITE_BIT(payload, n, b2); + } +} + +bool CP25Trellis::fixCode34(unsigned char* points, unsigned int failPos, unsigned char* payload) const +{ + for (unsigned j = 0U; j < 20U; j++) { + unsigned int bestPos = 0U; + unsigned int bestVal = 0U; + + for (unsigned int i = 0U; i < 16U; i++) { + points[failPos] = i; + + unsigned char tribits[49U]; + unsigned int pos = checkCode34(points, tribits); + if (pos == 999U) { + tribitsToBits(tribits, payload); + return true; + } + + if (pos > bestPos) { + bestPos = pos; + bestVal = i; + } + } + + points[failPos] = bestVal; + failPos = bestPos; + } + + return false; +} + +unsigned int CP25Trellis::checkCode34(const unsigned char* points, unsigned char* tribits) const +{ + unsigned char state = 0U; + + for (unsigned int i = 0U; i < 49U; i++) { + tribits[i] = 9U; + + for (unsigned int j = 0U; j < 8U; j++) { + if (points[i] == ENCODE_TABLE_34[state * 8U + j]) { + tribits[i] = j; + break; + } + } + + if (tribits[i] == 9U) + return i; + + state = tribits[i]; + } + + if (tribits[48U] != 0U) + return 48U; + + return 999U; +} + + +bool CP25Trellis::fixCode12(unsigned char* points, unsigned int failPos, unsigned char* payload) const +{ + for (unsigned j = 0U; j < 20U; j++) { + unsigned int bestPos = 0U; + unsigned int bestVal = 0U; + + for (unsigned int i = 0U; i < 4U; i++) { + points[failPos] = i; + + unsigned char dibits[49U]; + unsigned int pos = checkCode12(points, dibits); + if (pos == 999U) { + dibitsToBits(dibits, payload); + return true; + } + + if (pos > bestPos) { + bestPos = pos; + bestVal = i; + } + } + + points[failPos] = bestVal; + failPos = bestPos; + } + + return false; +} + +unsigned int CP25Trellis::checkCode12(const unsigned char* points, unsigned char* dibits) const +{ + unsigned char state = 0U; + + for (unsigned int i = 0U; i < 49U; i++) { + dibits[i] = 5U; + + for (unsigned int j = 0U; j < 4U; j++) { + if (points[i] == ENCODE_TABLE_12[state * 4U + j]) { + dibits[i] = j; + break; + } + } + + if (dibits[i] == 5U) + return i; + + state = dibits[i]; + } + + if (dibits[48U] != 0U) + return 48U; + + return 999U; +} diff --git a/P25Trellis.h b/P25Trellis.h new file mode 100644 index 0000000..47e7c1d --- /dev/null +++ b/P25Trellis.h @@ -0,0 +1,43 @@ +/* +* Copyright (C) 2016,2018 by Jonathan Naylor, G4KLX +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; version 2 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#ifndef P25Trellis_H +#define P25Trellis_H + +class CP25Trellis { +public: + CP25Trellis(); + ~CP25Trellis(); + + bool decode34(const unsigned char* data, unsigned char* payload); + void encode34(const unsigned char* payload, unsigned char* data); + + bool decode12(const unsigned char* data, unsigned char* payload); + void encode12(const unsigned char* payload, unsigned char* data); + +private: + void deinterleave(const unsigned char* in, signed char* dibits) const; + void interleave(const signed char* dibits, unsigned char* out) const; + void dibitsToPoints(const signed char* dibits, unsigned char* points) const; + void pointsToDibits(const unsigned char* points, signed char* dibits) const; + void bitsToTribits(const unsigned char* payload, unsigned char* tribits) const; + void bitsToDibits(const unsigned char* payload, unsigned char* dibits) const; + void tribitsToBits(const unsigned char* tribits, unsigned char* payload) const; + void dibitsToBits(const unsigned char* dibits, unsigned char* payload) const; + bool fixCode34(unsigned char* points, unsigned int failPos, unsigned char* payload) const; + unsigned int checkCode34(const unsigned char* points, unsigned char* tribits) const; + bool fixCode12(unsigned char* points, unsigned int failPos, unsigned char* payload) const; + unsigned int checkCode12(const unsigned char* points, unsigned char* dibits) const; +}; + +#endif diff --git a/P25Utils.cpp b/P25Utils.cpp index 763d7e1..3575d60 100644 --- a/P25Utils.cpp +++ b/P25Utils.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016 by Jonathan Naylor G4KLX +* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,7 +27,7 @@ const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04 #define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) #define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) -void CP25Utils::decode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop) +unsigned int CP25Utils::decode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop) { assert(in != NULL); assert(out != NULL); @@ -53,9 +53,11 @@ void CP25Utils::decode(const unsigned char* in, unsigned char* out, unsigned int n++; } } + + return n; } -void CP25Utils::encode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop) +unsigned int CP25Utils::encode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop) { assert(in != NULL); assert(out != NULL); @@ -81,6 +83,8 @@ void CP25Utils::encode(const unsigned char* in, unsigned char* out, unsigned int n++; } } + + return n; } unsigned int CP25Utils::compare(const unsigned char* data1, const unsigned char* data2, unsigned int length) diff --git a/P25Utils.h b/P25Utils.h index cdfca06..142d407 100644 --- a/P25Utils.h +++ b/P25Utils.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016 by Jonathan Naylor G4KLX +* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,9 +21,9 @@ class CP25Utils { public: - static void encode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop); + static unsigned int encode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop); - static void decode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop); + static unsigned int decode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop); static unsigned int compare(const unsigned char* data1, const unsigned char* data2, unsigned int length);