fix latent issue with symbol dump dumping 1 extra byte; correct bitwise CRC-16 incorrectly calculating the CRC-16-CCITT; add extra debugging logic to NXDN code; rework how various array sizes are handled for NXDN; continue work on NXDN RCCH CAC implementation; refactor NXDN LICH slightly (we don't need a 1 byte 'array' for this);

pull/12/head
Bryan Biedenkapp 4 years ago
parent f353e8f501
commit 936481f76b

@ -212,7 +212,7 @@ void Utils::symbols(const std::string& title, const uint8_t* data, uint32_t leng
}
for (unsigned i = 0U; i < 9U; i++) {
if (symOffset + i > length) {
if (symOffset + i >= length) {
break;
}

@ -660,7 +660,7 @@ bool CRC::checkCRC16(const uint8_t* in, uint32_t bitLength)
{
assert(in != NULL);
uint16_t crc = createCRC15(in, bitLength);
uint16_t crc = createCRC16(in, bitLength);
uint8_t temp1[2U];
temp1[0U] = (crc >> 8) & 0xFFU;
temp1[1U] = (crc >> 0) & 0xFFU;
@ -669,7 +669,7 @@ bool CRC::checkCRC16(const uint8_t* in, uint32_t bitLength)
temp2[0U] = 0x00U;
temp2[1U] = 0x00U;
uint32_t j = bitLength;
for (uint32_t i = 1U; i < 16U; i++, j++) {
for (uint32_t i = 0U; i < 16U; i++, j++) {
bool b = READ_BIT(in, j);
WRITE_BIT(temp2, i, b);
}
@ -692,14 +692,14 @@ void CRC::addCRC16(uint8_t* in, uint32_t bitLength)
{
assert(in != NULL);
uint16_t crc = createCRC15(in, bitLength);
uint16_t crc = createCRC16(in, bitLength);
uint8_t temp[2U];
temp[0U] = (crc >> 8) & 0xFFU;
temp[1U] = (crc >> 0) & 0xFFU;
uint32_t n = bitLength;
for (uint32_t i = 1U; i < 16U; i++, n++) {
for (uint32_t i = 0U; i < 16U; i++, n++) {
bool b = READ_BIT(temp, i);
WRITE_BIT(in, n, b);
}
@ -790,7 +790,7 @@ uint16_t CRC::createCRC15(const uint8_t* in, uint32_t bitLength)
/// <returns></returns>
uint16_t CRC::createCRC16(const uint8_t* in, uint32_t bitLength)
{
uint16_t crc = 0xFFFFU;
uint16_t crc = 0x0000U;
for (uint32_t i = 0U; i < bitLength; i++) {
bool bit1 = READ_BIT(in, i) != 0x00U;
@ -802,5 +802,6 @@ uint16_t CRC::createCRC16(const uint8_t* in, uint32_t bitLength)
crc ^= 0x1021U;
}
crc = ~crc;
return crc & 0xFFFFU;
}

@ -2138,7 +2138,8 @@ bool Host::createModem()
LogInfo(" UDP Address: %s", g_remoteAddress.c_str());
LogInfo(" UDP Port: %u", g_remotePort);
}
else {
if (!m_modemRemote) {
LogInfo(" RX Invert: %s", rxInvert ? "yes" : "no");
LogInfo(" TX Invert: %s", txInvert ? "yes" : "no");
LogInfo(" PTT Invert: %s", pttInvert ? "yes" : "no");

@ -117,7 +117,7 @@ Control::Control(uint32_t ran, uint32_t callHang, uint32_t queueSize, uint32_t t
m_rfTGHang(1000U, tgHang),
m_netTimeout(1000U, timeout),
m_networkWatchdog(1000U, 0U, 1500U),
m_ccPacketInterval(1000U, 0U, 25U),
m_ccPacketInterval(1000U, 0U, 10U),
m_ccFrameCnt(0U),
m_ccSeq(0U),
m_siteData(),
@ -709,14 +709,14 @@ void Control::writeRF_Message_Tx_Rel(bool noNetwork)
lich.setRFCT(NXDN_LICH_RFCT_RDCH);
lich.setFCT(NXDN_LICH_USC_UDCH);
lich.setOption(NXDN_LICH_USC_UDCH);
lich.setDirection(NXDN_LICH_DIRECTION_OUTBOUND);
lich.setOutbound(true);
lich.encode(data + 2U);
uint8_t buffer[NXDN_UDCH_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_UDCH_LENGTH_BYTES);
uint8_t buffer[NXDN_RTCH_LC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_RTCH_LC_LENGTH_BYTES);
m_rfLC.setMessageType(RTCH_MESSAGE_TYPE_TX_REL);
m_rfLC.encode(buffer, NXDH_UDCH_CRC_BITS);
m_rfLC.encode(buffer, NXDN_UDCH_LENGTH_BITS);
channel::UDCH udch;
udch.setRAN(m_ran);
@ -778,6 +778,10 @@ void Control::scrambler(uint8_t* data) const
{
assert(data != NULL);
if (m_debug) {
Utils::symbols("!!! *Tx NXDN (Unscrambled)", data, NXDN_FRAME_LENGTH_BYTES);
}
for (uint32_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++)
data[i] ^= SCRAMBLER[i];
}

@ -84,59 +84,51 @@ namespace nxdn
const uint32_t NXDN_SACCH_FEC_LENGTH_BYTES = (NXDN_SACCH_FEC_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_SACCH_FEC_CONV_LENGTH_BITS = 72U; // Convolution Length
const uint32_t NXDN_SACCH_FEC_CONV_LENGTH_BYTES = NXDN_SACCH_FEC_CONV_LENGTH_BITS / 8U;
const uint32_t NXDN_SACCH_LENGTH_BITS = 36U; // Data + CRC-6 + 4-bit NULL
const uint32_t NXDN_SACCH_LENGTH_BYTES = (NXDN_SACCH_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_SACCH_CRC_BITS = 26U; // Data
const uint32_t NXDN_SACCH_CRC_LENGTH_BITS = 36U; // Data + CRC-6 + 4-bit NULL
const uint32_t NXDN_SACCH_CRC_LENGTH_BYTES = (NXDN_SACCH_CRC_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_SACCH_LENGTH_BITS = 26U;
const uint32_t NXDN_FACCH1_FEC_LENGTH_BITS = 144U; // Puncture and Interleave Length
const uint32_t NXDN_FACCH1_FEC_LENGTH_BYTES = NXDN_FACCH1_FEC_LENGTH_BITS / 8U;
const uint32_t NXDN_FACCH1_FEC_CONV_LENGTH_BITS = 192U; // Convolution Length
const uint32_t NXDN_FACCH1_FEC_CONV_LENGTH_BYTES = NXDN_FACCH1_FEC_CONV_LENGTH_BITS / 8U;
const uint32_t NXDN_FACCH1_LENGTH_BITS = 96U; // Data + CRC-12 + 4-bit NULL
const uint32_t NXDN_FACCH1_LENGTH_BYTES = NXDN_FACCH1_LENGTH_BITS / 8U;
const uint32_t NXDN_FACCH1_CRC_BITS = 80U; // Data
const uint32_t NXDN_FACCH1_CRC_LENGTH_BITS = 96U; // Data + CRC-12 + 4-bit NULL
const uint32_t NXDN_FACCH1_CRC_LENGTH_BYTES = NXDN_FACCH1_CRC_LENGTH_BITS / 8U;
const uint32_t NXDN_FACCH1_LENGTH_BITS = 80U;
const uint32_t NXDN_UDCH_FEC_LENGTH_BITS = 348U; // Puncture and Interleave Length
const uint32_t NXDN_UDCH_FEC_LENGTH_BYTES = (NXDN_UDCH_FEC_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_UDCH_FEC_CONV_LENGTH_BITS = 406U; // Convolution Length
const uint32_t NXDN_UDCH_FEC_CONV_LENGTH_BYTES = (NXDN_UDCH_FEC_CONV_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_UDCH_LENGTH_BITS = 203U; // Data + CRC-15 + 4-bit NULL
const uint32_t NXDN_UDCH_LENGTH_BYTES = (NXDN_UDCH_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDH_UDCH_CRC_BITS = 184U; // Data
const uint32_t NXDH_UDCH_CRC_BYTES = NXDH_UDCH_CRC_BITS / 8U;
const uint32_t NXDN_CAC_LENGTH_BITS = 384U;
const uint32_t NXDN_CAC_LENGTH_BYTES = (NXDN_CAC_LENGTH_BITS / 8U);
const uint32_t NXDN_CAC_OUT_FEC_LENGTH_BITS = 300U; // Puncture and Interleave Length
const uint32_t NXDN_CAC_OUT_FEC_LENGTH_BYTES = (NXDN_CAC_OUT_FEC_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_CAC_OUT_FEC_CONV_LENGTH_BITS = 350U; // Convolution Length
const uint32_t NXDN_CAC_OUT_FEC_CONV_LENGTH_BYTES = (NXDN_CAC_OUT_FEC_CONV_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_CAC_OUT_LENGTH_BITS = 175U; // Data + CRC-16 + 4-bit NULL
const uint32_t NXDN_CAC_OUT_LENGTH_BYTES = (NXDN_CAC_OUT_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_CAC_OUT_CRC_BITS = 155U; // Data
const uint32_t NXDN_UDCH_CRC_LENGTH_BITS = 203U; // Data + CRC-15 + 4-bit NULL
const uint32_t NXDN_UDCH_CRC_LENGTH_BYTES = (NXDN_UDCH_CRC_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_UDCH_LENGTH_BITS = 184U;
const uint32_t NXDN_CAC_FRAME_LENGTH_BITS = 348U;
const uint32_t NXDN_CAC_FRAME_LENGTH_BYTES = (NXDN_CAC_FRAME_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_CAC_FEC_LENGTH_BITS = 300U; // Puncture and Interleave Length
const uint32_t NXDN_CAC_FEC_LENGTH_BYTES = (NXDN_CAC_FEC_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_CAC_FEC_CONV_LENGTH_BITS = 350U; // Convolution Length
const uint32_t NXDN_CAC_FEC_CONV_LENGTH_BYTES = (NXDN_CAC_FEC_CONV_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_CAC_CRC_LENGTH_BITS = 175U; // Data + CRC-16 + 4-bit NULL
const uint32_t NXDN_CAC_LENGTH_BITS = 155U;
const uint32_t NXDN_CAC_E_POST_FIELD_BITS = 24U;
const uint32_t NXDN_CAC_IN_FEC_LENGTH_BITS = 252U; // Puncture and Interleave Length
const uint32_t NXDN_CAC_IN_FEC_LENGTH_BYTES = (NXDN_CAC_IN_FEC_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_CAC_LONG_FEC_CONV_LENGTH_BITS = 312U; // Convolution Length
const uint32_t NXDN_CAC_LONG_FEC_CONV_LENGTH_BYTES = NXDN_CAC_LONG_FEC_CONV_LENGTH_BITS / 8U;
const uint32_t NXDN_CAC_LONG_CRC_LENGTH_BITS = 156U; // Data + CRC-16 + 4-bit NULL
const uint32_t NXDN_CAC_LONG_LENGTH_BITS = 136U;
const uint32_t NXDN_CAC_SHORT_CRC_LENGTH_BITS = 126U; // Data + CRC-16 + 4-bit NULL
const uint32_t NXDN_CAC_SHORT_LENGTH_BITS = 106U;
const uint32_t NXDN_CAC_LONG_IN_FEC_CONV_LENGTH_BITS = 312U; // Convolution Length
const uint32_t NXDN_CAC_LONG_IN_FEC_CONV_LENGTH_BYTES = NXDN_CAC_LONG_IN_FEC_CONV_LENGTH_BITS / 8U;
const uint32_t NXDN_CAC_LONG_IN_LENGTH_BITS = 156U; // Data + CRC-16 + 4-bit NULL
const uint32_t NXDN_CAC_LONG_IN_LENGTH_BYTES = (NXDN_CAC_LONG_IN_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_CAC_LONG_IN_CRC_BITS = 136U; // Data
const uint32_t NXDN_CAC_LONG_IN_CRC_BYTES = NXDN_CAC_LONG_IN_CRC_BITS / 8U;
const uint32_t NXDN_RTCH_LC_LENGTH_BYTES = 22U; // this is really the UDCH size...
const uint32_t NXDN_CAC_SHORT_IN_FEC_LENGTH_BITS = 252U; // Interleave Length
const uint32_t NXDN_CAC_SHORT_IN_FEC_LENGTH_BYTES = (NXDN_CAC_SHORT_IN_FEC_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_CAC_SHORT_IN_LENGTH_BITS = 126U; // Data + CRC-16 + 4-bit NULL
const uint32_t NXDN_CAC_SHORT_IN_LENGTH_BYTES = (NXDN_CAC_SHORT_IN_LENGTH_BITS / 8U) + 1U;
const uint32_t NXDN_CAC_SHORT_IN_CRC_BITS = 106U; // Data
const uint32_t NXDN_CAC_SHORT_IN_CRC_BYTES = (NXDN_CAC_SHORT_IN_CRC_BITS / 8U) + 1U;
const uint32_t NXDN_RTCH_LC_LENGTH_BYTES = 22U;
const uint32_t NXDN_RCCH_LC_LENGTH_BYTES = 22U;
const uint32_t NXDN_E_POST_FIELD_BITS = 24U;
const uint32_t NXDN_RCCH_LC_LENGTH_BITS = 144U;
const uint32_t NXDN_RCCH_LC_LENGTH_BYTES = (NXDN_RCCH_LC_LENGTH_BITS / 8U);
const uint32_t NXDN_RCCH_CAC_LC_LONG_LENGTH_BITS = 128U;
const uint32_t NXDN_RCCH_CAC_LC_SHORT_LENGTH_BITS = 96U;
const uint8_t POST_FIELD[] = { 0x57U, 0x75U, 0xFDU };
@ -166,8 +158,10 @@ namespace nxdn
const uint8_t NXDN_LICH_STEAL_FACCH1_1 = 1U;
const uint8_t NXDN_LICH_STEAL_FACCH = 0U;
const uint8_t NXDN_LICH_DIRECTION_INBOUND = 0U;
const uint8_t NXDN_LICH_DIRECTION_OUTBOUND = 1U;
const uint8_t NXDN_SR_RCCH_SINGLE = 0x00U;
const uint8_t NXDN_SR_RCCH_DUAL = 0x01U;
const uint8_t NXDN_SR_RCCH_HEAD_SINGLE = 0x02U;
const uint8_t NXDN_SR_RCCH_HEAD_DUAL = 0x03U;
const uint8_t NXDN_SR_SINGLE = 0U;
const uint8_t NXDN_SR_4_4 = 0U;

@ -120,10 +120,16 @@ const uint32_t PUNCTURE_LIST_OUT[] = {
/// </summary>
CAC::CAC() :
m_verbose(false),
m_ran(0U),
m_data(NULL)
m_ran(1U),
m_structure(NXDN_SR_RCCH_SINGLE),
m_idleBusy(true),
m_txContinuous(false),
m_receive(true),
m_data(NULL),
m_rxCRC(0U)
{
m_data = new uint8_t[NXDN_CAC_OUT_LENGTH_BYTES];
m_data = new uint8_t[NXDN_CAC_FRAME_LENGTH_BYTES];
::memset(m_data, 0x00U, NXDN_CAC_FRAME_LENGTH_BYTES);
}
/// <summary>
@ -132,8 +138,13 @@ CAC::CAC() :
/// <param name="data"></param>
CAC::CAC(const CAC& data) :
m_verbose(false),
m_ran(0U),
m_data(NULL)
m_ran(1U),
m_structure(NXDN_SR_RCCH_SINGLE),
m_idleBusy(true),
m_txContinuous(false),
m_receive(true),
m_data(NULL),
m_rxCRC(0U)
{
copy(data);
}
@ -154,11 +165,18 @@ CAC::~CAC()
CAC& CAC::operator=(const CAC& data)
{
if (&data != this) {
::memcpy(m_data, data.m_data, NXDN_CAC_OUT_LENGTH_BYTES);
::memcpy(m_data, data.m_data, NXDN_CAC_FRAME_LENGTH_BYTES);
m_verbose = data.m_verbose;
m_ran = m_data[0U] & 0x3FU;
m_structure = (m_data[0U] >> 6) & 0x03U;
m_idleBusy = data.m_idleBusy;
m_txContinuous = data.m_txContinuous;
m_receive = data.m_receive;
m_rxCRC = data.m_rxCRC;
}
return *this;
@ -173,7 +191,8 @@ bool CAC::decode(const uint8_t* data)
{
assert(data != NULL);
uint8_t buffer[NXDN_CAC_IN_FEC_LENGTH_BYTES + 1U];
uint8_t buffer[NXDN_CAC_IN_FEC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_CAC_IN_FEC_LENGTH_BYTES);
// deinterleave
for (uint32_t i = 0U; i < NXDN_CAC_IN_FEC_LENGTH_BITS; i++) {
@ -193,21 +212,21 @@ bool CAC::decode(const uint8_t* data)
conv.start();
uint32_t n = 0U;
for (uint32_t i = 0U; i < (NXDN_CAC_SHORT_IN_LENGTH_BITS + 4U); i++) {
for (uint32_t i = 0U; i < (NXDN_CAC_SHORT_CRC_LENGTH_BITS + 4U); i++) {
uint8_t s0 = buffer[n++];
uint8_t s1 = buffer[n++];
conv.decode(s0, s1);
}
conv.chainback(m_data, NXDN_CAC_SHORT_IN_LENGTH_BITS);
conv.chainback(m_data, NXDN_CAC_SHORT_CRC_LENGTH_BITS);
if (m_verbose) {
Utils::dump(2U, "Decoded CAC", m_data, NXDN_CAC_SHORT_IN_LENGTH_BYTES);
Utils::dump(2U, "Decoded CAC", m_data, (NXDN_CAC_SHORT_CRC_LENGTH_BITS / 8U) + 1U);
}
// check CRC-16
bool ret = CRC::checkCRC16(m_data, NXDN_CAC_SHORT_IN_CRC_BITS);
bool ret = CRC::checkCRC16(m_data, NXDN_CAC_SHORT_LENGTH_BITS);
if (!ret) {
LogError(LOG_NXDN, "SACCH::decode(), failed CRC-6 check");
return false;
@ -217,16 +236,22 @@ bool CAC::decode(const uint8_t* data)
uint8_t crc[2U];
::memset(crc, 0x00U, 2U);
uint32_t j = NXDN_CAC_SHORT_IN_CRC_BITS;
for (uint32_t i = 1U; i < 16U; i++, j++) {
bool b = READ_BIT(m_data, j);
m_ran = m_data[0U] & 0x3FU;
m_structure = (m_data[0U] >> 6) & 0x03U;
uint32_t offset = NXDN_CAC_SHORT_CRC_LENGTH_BITS - 20U;
for (uint32_t i = 0U; i < 16U; i++, offset++) {
bool b = READ_BIT(m_data, offset);
WRITE_BIT(crc, i, b);
}
m_rxCRC = (crc[0U] << 8) | (crc[1U] << 0);
m_ran = m_data[0U] & 0x3FU;
#if DEBUG_NXDN_CAC
if (m_verbose) {
Utils::dump(2U, "Raw CAC Buffer", m_data, NXDN_CAC_FEC_LENGTH_BYTES);
}
#endif
return true;
}
@ -238,36 +263,43 @@ void CAC::encode(uint8_t* data) const
{
assert(data != NULL);
m_data[0U] &= 0xC0U;
m_data[0U] |= m_ran;
m_data[0U] &= 0xC0U;
m_data[0U] |= m_ran;
uint8_t buffer[NXDN_CAC_OUT_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_CAC_OUT_LENGTH_BYTES);
m_data[0U] &= 0x3FU;
m_data[0U] |= (m_structure << 6) & 0xC0U;
for (uint32_t i = 0U; i < NXDN_CAC_OUT_CRC_BITS; i++) {
uint8_t buffer[NXDN_CAC_FEC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_CAC_FEC_LENGTH_BYTES);
for (uint32_t i = 0U; i < NXDN_CAC_LENGTH_BITS; i++) {
bool b = READ_BIT(m_data, i);
WRITE_BIT(buffer, i, b);
}
CRC::addCRC16(buffer, NXDN_CAC_OUT_CRC_BITS);
CRC::addCRC16(buffer, NXDN_CAC_LENGTH_BITS);
if (m_verbose) {
Utils::dump(2U, "Encoded CAC", buffer, NXDN_CAC_OUT_LENGTH_BYTES);
Utils::dump(2U, "Encoded CAC", buffer, NXDN_CAC_FEC_LENGTH_BYTES);
}
// encode convolution
uint8_t convolution[NXDN_CAC_OUT_FEC_CONV_LENGTH_BYTES];
uint8_t convolution[NXDN_CAC_FEC_CONV_LENGTH_BYTES];
::memset(convolution, 0x00U, NXDN_CAC_FEC_CONV_LENGTH_BYTES);
Convolution conv;
conv.encode(buffer, convolution, NXDN_CAC_OUT_LENGTH_BITS);
conv.encode(buffer, convolution, NXDN_CAC_CRC_LENGTH_BITS);
#if DEBUG_NXDN_CAC
Utils::dump(2U, "CAC::encode(), CAC Convolution", convolution, NXDN_CAC_OUT_FEC_CONV_LENGTH_BYTES);
Utils::dump(2U, "CAC::encode(), CAC Convolution", convolution, NXDN_CAC_FEC_CONV_LENGTH_BYTES);
#endif
// puncture
uint8_t puncture[NXDN_CAC_OUT_FEC_LENGTH_BYTES];
uint8_t puncture[NXDN_CAC_FEC_LENGTH_BYTES];
::memset(puncture, 0x00U, NXDN_CAC_FEC_LENGTH_BYTES);
uint32_t n = 0U, index = 0U;
for (uint32_t i = 0U; i < NXDN_CAC_OUT_FEC_CONV_LENGTH_BITS; i++) {
for (uint32_t i = 0U; i < NXDN_CAC_FEC_CONV_LENGTH_BITS; i++) {
if (i != PUNCTURE_LIST_OUT[index]) {
bool b = READ_BIT(convolution, i);
WRITE_BIT(puncture, n, b);
@ -278,41 +310,45 @@ void CAC::encode(uint8_t* data) const
}
// interleave
for (uint32_t i = 0U; i < NXDN_CAC_OUT_FEC_LENGTH_BITS; i++) {
for (uint32_t i = 0U; i < NXDN_CAC_FEC_LENGTH_BITS; i++) {
uint32_t n = INTERLEAVE_TABLE_OUT[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS;
bool b = READ_BIT(puncture, i);
WRITE_BIT(data, n, b);
}
#if DEBUG_NXDN_CAC
Utils::dump(2U, "CAC::encode(), CAC Puncture and Interleave", data, NXDN_CAC_OUT_FEC_LENGTH_BYTES);
Utils::dump(2U, "CAC::encode(), CAC Puncture and Interleave", data, NXDN_CAC_FRAME_LENGTH_BYTES);
#endif
// apply control field
uint8_t control[3U];
::memset(control, 0x00U, 3U);
uint8_t parity = 0x01U;
uint8_t parity = 0x03U;
if (m_idleBusy && m_txContinuous)
parity = 0x03U;
parity = 0x01U;
control[0U] = ((m_idleBusy ? 0x03U : 0x01U) << 22) + ((m_txContinuous ? 0x03U : 0x01U) << 20) +
(parity << 18) + ((m_receive ? 0x03U : 0x01U) << 16);
control[1U] = (m_rxCRC >> 8U);
control[2U] = (m_rxCRC >> 0U);
control[0U] = ((m_idleBusy ? 0x03U : 0x01U) << 6) + ((m_txContinuous ? 0x03U : 0x01U) << 4) +
(parity << 2) + ((m_receive ? 0x03U : 0x01U));
control[1U] = (m_rxCRC >> 8U) & 0xFFU;
control[2U] = (m_rxCRC >> 0U) & 0xFFU;
uint32_t offset = NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_CAC_OUT_FEC_LENGTH_BITS;
for (uint32_t i = 0U; i < NXDN_E_POST_FIELD_BITS; i++, offset++) {
for (uint32_t i = 0U; i < NXDN_CAC_E_POST_FIELD_BITS; i++) {
uint32_t n = i + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_CAC_FEC_LENGTH_BITS;
bool b = READ_BIT(control, i);
WRITE_BIT(data, offset, b);
WRITE_BIT(data, n, b);
}
// post field
offset = NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_CAC_OUT_FEC_LENGTH_BITS + NXDN_E_POST_FIELD_BITS;
for (uint32_t i = 0U; i < NXDN_E_POST_FIELD_BITS; i++, offset++) {
for (uint32_t i = 0U; i < NXDN_CAC_E_POST_FIELD_BITS; i++) {
uint32_t n = i + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_CAC_FEC_LENGTH_BITS + NXDN_CAC_E_POST_FIELD_BITS;
bool b = READ_BIT(POST_FIELD, i);
WRITE_BIT(data, offset, b);
WRITE_BIT(data, n, b);
}
#if DEBUG_NXDN_CAC
Utils::dump(2U, "CAC::encode(), CAC + E + Post", data, NXDN_FRAME_LENGTH_BYTES);
#endif
}
/// <summary>
@ -324,7 +360,7 @@ void CAC::getData(uint8_t* data) const
assert(data != NULL);
uint32_t offset = 8U;
for (uint32_t i = 0U; i < (NXDN_CAC_SHORT_IN_CRC_BITS - 8); i++, offset++) {
for (uint32_t i = 0U; i < (NXDN_CAC_SHORT_LENGTH_BITS - 10); i++, offset++) {
bool b = READ_BIT(m_data, offset);
WRITE_BIT(data, i, b);
}
@ -338,8 +374,10 @@ void CAC::setData(const uint8_t* data)
{
assert(data != NULL);
::memset(m_data, 0x00U, NXDN_CAC_FRAME_LENGTH_BYTES);
uint32_t offset = 8U;
for (uint32_t i = 0U; i < (NXDN_CAC_OUT_CRC_BITS - 8); i++, offset++) {
for (uint32_t i = 0U; i < (NXDN_CAC_CRC_LENGTH_BITS - 31); i++, offset++) {
bool b = READ_BIT(data, i);
WRITE_BIT(m_data, offset, b);
}
@ -355,8 +393,15 @@ void CAC::setData(const uint8_t* data)
/// <param name="data"></param>
void CAC::copy(const CAC& data)
{
m_data = new uint8_t[NXDN_CAC_OUT_LENGTH_BYTES];
::memcpy(m_data, data.m_data, NXDN_CAC_OUT_LENGTH_BYTES);
m_data = new uint8_t[NXDN_CAC_FRAME_LENGTH_BYTES];
::memcpy(m_data, data.m_data, NXDN_CAC_FRAME_LENGTH_BYTES);
m_ran = m_data[0U] & 0x3FU;
m_structure = (m_data[0U] >> 6) & 0x03U;
m_idleBusy = data.m_idleBusy;
m_txContinuous = data.m_txContinuous;
m_receive = data.m_receive;
m_rxCRC = data.m_rxCRC;
}

@ -70,6 +70,8 @@ namespace nxdn
/** Common Data */
/// <summary>Radio Access Number</summary>
__PROPERTY(uint8_t, ran, RAN);
/// <summary></summary>
__PROPERTY(uint8_t, structure, Structure);
/** Collision Control Field */
/// <summary>Idle/Busy.</summary>

@ -75,7 +75,8 @@ FACCH1::FACCH1() :
m_verbose(false),
m_data(NULL)
{
m_data = new uint8_t[NXDN_FACCH1_LENGTH_BYTES];
m_data = new uint8_t[NXDN_FACCH1_CRC_LENGTH_BYTES];
::memset(m_data, 0x00U, NXDN_FACCH1_CRC_LENGTH_BYTES);
}
/// <summary>
@ -105,7 +106,7 @@ FACCH1::~FACCH1()
FACCH1& FACCH1::operator=(const FACCH1& data)
{
if (&data != this) {
::memcpy(m_data, data.m_data, NXDN_FACCH1_LENGTH_BYTES);
::memcpy(m_data, data.m_data, NXDN_FACCH1_CRC_LENGTH_BYTES);
m_verbose = data.m_verbose;
}
@ -123,6 +124,7 @@ bool FACCH1::decode(const uint8_t* data, uint32_t offset)
assert(data != NULL);
uint8_t buffer[NXDN_FACCH1_FEC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_FACCH1_FEC_LENGTH_BYTES);
// deinterleave
for (uint32_t i = 0U; i < NXDN_FACCH1_FEC_LENGTH_BITS; i++) {
@ -157,21 +159,21 @@ bool FACCH1::decode(const uint8_t* data, uint32_t offset)
conv.start();
n = 0U;
for (uint32_t i = 0U; i < (NXDN_FACCH1_LENGTH_BITS + 4U); i++) {
for (uint32_t i = 0U; i < (NXDN_FACCH1_CRC_LENGTH_BITS + 4U); i++) {
uint8_t s0 = puncture[n++];
uint8_t s1 = puncture[n++];
conv.decode(s0, s1);
}
conv.chainback(m_data, NXDN_FACCH1_LENGTH_BITS);
conv.chainback(m_data, NXDN_FACCH1_CRC_LENGTH_BITS);
if (m_verbose) {
Utils::dump(2U, "Decoded FACCH1", m_data, NXDN_FACCH1_LENGTH_BYTES);
Utils::dump(2U, "Decoded FACCH1", m_data, NXDN_FACCH1_CRC_LENGTH_BYTES);
}
// check CRC-12
bool ret = CRC::checkCRC12(m_data, NXDN_FACCH1_CRC_BITS);
bool ret = CRC::checkCRC12(m_data, NXDN_FACCH1_LENGTH_BITS);
if (!ret) {
LogError(LOG_NXDN, "FACCH1::decode(), failed CRC-12 check");
return false;
@ -189,32 +191,36 @@ void FACCH1::encode(uint8_t* data, uint32_t offset) const
{
assert(data != NULL);
uint8_t buffer[NXDN_FACCH1_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_FACCH1_LENGTH_BYTES);
::memcpy(buffer, m_data, NXDN_FACCH1_LENGTH_BYTES - 2U);
uint8_t buffer[NXDN_FACCH1_CRC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_FACCH1_CRC_LENGTH_BYTES);
::memcpy(buffer, m_data, NXDN_FACCH1_CRC_LENGTH_BYTES - 2U);
CRC::addCRC12(buffer, NXDN_FACCH1_CRC_BITS);
CRC::addCRC12(buffer, NXDN_FACCH1_LENGTH_BITS);
if (m_verbose) {
Utils::dump(2U, "Encoded FACCH1", buffer, NXDN_FACCH1_LENGTH_BYTES);
Utils::dump(2U, "Encoded FACCH1", buffer, NXDN_FACCH1_CRC_LENGTH_BYTES);
}
// encode convolution
uint8_t convolution[NXDN_FACCH1_FEC_CONV_LENGTH_BYTES];
::memset(convolution, 0x00U, NXDN_FACCH1_FEC_CONV_LENGTH_BYTES);
Convolution conv;
conv.encode(buffer, convolution, NXDN_FACCH1_LENGTH_BITS);
conv.encode(buffer, convolution, NXDN_FACCH1_CRC_LENGTH_BITS);
#if DEBUG_NXDN_FACCH1
Utils::dump(2U, "FACCH1::encode(), FACCH1 Convolution", convolution, NXDN_FACCH1_FEC_CONV_LENGTH_BYTES);
#endif
// puncture
uint8_t raw[NXDN_FACCH1_FEC_LENGTH_BYTES];
uint8_t puncture[NXDN_FACCH1_FEC_LENGTH_BYTES];
::memset(puncture, 0x00U, NXDN_FACCH1_FEC_LENGTH_BYTES);
uint32_t n = 0U, index = 0U;
for (uint32_t i = 0U; i < NXDN_FACCH1_FEC_CONV_LENGTH_BITS; i++) {
if (i != PUNCTURE_LIST[index]) {
bool b = READ_BIT(convolution, i);
WRITE_BIT(raw, n, b);
WRITE_BIT(puncture, n, b);
n++;
} else {
index++;
@ -224,7 +230,7 @@ void FACCH1::encode(uint8_t* data, uint32_t offset) const
// interleave
for (uint32_t i = 0U; i < NXDN_FACCH1_FEC_LENGTH_BITS; i++) {
uint32_t n = INTERLEAVE_TABLE[i] + offset;
bool b = READ_BIT(raw, i);
bool b = READ_BIT(puncture, i);
WRITE_BIT(data, n, b);
}
@ -241,7 +247,7 @@ void FACCH1::getData(uint8_t* data) const
{
assert(data != NULL);
::memcpy(data, m_data, NXDN_FACCH1_LENGTH_BYTES - 2U);
::memcpy(data, m_data, NXDN_FACCH1_CRC_LENGTH_BYTES - 2U);
}
/// <summary>
@ -252,7 +258,7 @@ void FACCH1::setData(const uint8_t* data)
{
assert(data != NULL);
::memcpy(m_data, data, NXDN_FACCH1_LENGTH_BYTES - 2U);
::memcpy(m_data, data, NXDN_FACCH1_CRC_LENGTH_BYTES - 2U);
}
// ---------------------------------------------------------------------------
@ -265,8 +271,8 @@ void FACCH1::setData(const uint8_t* data)
/// <param name="data"></param>
void FACCH1::copy(const FACCH1& data)
{
m_data = new uint8_t[NXDN_FACCH1_LENGTH_BYTES];
::memcpy(m_data, data.m_data, NXDN_FACCH1_LENGTH_BYTES);
m_data = new uint8_t[NXDN_FACCH1_CRC_LENGTH_BYTES];
::memcpy(m_data, data.m_data, NXDN_FACCH1_CRC_LENGTH_BYTES);
m_verbose = data.m_verbose;
}

@ -30,6 +30,7 @@
*/
#include "nxdn/NXDNDefines.h"
#include "nxdn/channel/LICH.h"
#include "Log.h"
using namespace nxdn;
using namespace nxdn::channel;
@ -49,10 +50,10 @@ LICH::LICH() :
m_rfct(NXDN_LICH_RFCT_RCCH),
m_fct(NXDN_LICH_USC_SACCH_NS),
m_option(0U),
m_direction(NXDN_LICH_DIRECTION_OUTBOUND),
m_data(NULL)
m_outbound(true),
m_lich(0U)
{
m_data = new uint8_t[1U];
/* stub */
}
/// <summary>
@ -63,8 +64,8 @@ LICH::LICH(const LICH& data) :
m_rfct(NXDN_LICH_RFCT_RCCH),
m_fct(NXDN_LICH_USC_SACCH_NS),
m_option(0U),
m_direction(NXDN_LICH_DIRECTION_OUTBOUND),
m_data(NULL)
m_outbound(true),
m_lich(0U)
{
copy(data);
}
@ -74,7 +75,7 @@ LICH::LICH(const LICH& data) :
/// </summary>
LICH::~LICH()
{
delete[] m_data;
/* stub */
}
/// <summary>
@ -85,12 +86,12 @@ LICH::~LICH()
LICH& LICH::operator=(const LICH& data)
{
if (&data != this) {
m_data[0U] = data.m_data[0U];
m_lich = data.m_lich;
m_rfct = data.m_rfct;
m_fct = data.m_fct;
m_option = data.m_option;
m_direction = data.m_direction;
m_outbound = data.m_outbound;
}
return *this;
@ -108,16 +109,20 @@ bool LICH::decode(const uint8_t* data)
uint32_t offset = NXDN_FSW_LENGTH_BITS;
for (uint32_t i = 0U; i < (NXDN_LICH_LENGTH_BITS / 2U); i++, offset += 2U) {
bool b = READ_BIT(data, offset);
WRITE_BIT(m_data, i, b);
m_lich = (b) ? (m_lich | BIT_MASK_TABLE[(i) & 7]) : (m_lich & ~BIT_MASK_TABLE[(i) & 7]);
}
#if DEBUG_NXDN_LICH
LogDebug(LOG_NXDN, "LICH::decode(), m_lich = %02X", m_lich);
#endif
bool newParity = getParity();
bool origParity = (m_data[0U] & 0x01U) == 0x01U;
bool origParity = (m_lich & 0x01U) == 0x01U;
m_rfct = (m_data[0U] >> 6) & 0x03U;
m_fct = (m_data[0U] >> 4) & 0x03U;
m_option = (m_data[0U] >> 2) & 0x03U;
m_direction = (m_data[0U] >> 1) & 0x01U;
m_rfct = (m_lich >> 6) & 0x03U;
m_fct = (m_lich >> 4) & 0x03U;
m_option = (m_lich >> 2) & 0x03U;
m_outbound = ((m_lich >> 1) & 0x01U) == 0x01U;
return origParity == newParity;
}
@ -130,27 +135,33 @@ void LICH::encode(uint8_t* data)
{
assert(data != NULL);
m_data[0U] &= 0x3FU;
m_data[0U] |= (m_rfct << 6) & 0xC0U;
m_lich = 0U;
m_lich &= 0x3FU;
m_lich |= (m_rfct & 0x03U) << 6;
m_lich &= 0xCFU;
m_lich |= (m_fct & 0x03U) << 4;
m_data[0U] &= 0xCFU;
m_data[0U] |= (m_fct << 4) & 0x30U;
m_lich &= 0xF3U;
m_lich |= (m_option & 0x03U) << 2;
m_data[0U] &= 0xF3U;
m_data[0U] |= (m_option << 2) & 0x0CU;
m_lich &= 0xFDU;
m_lich |= (m_outbound ? 0x01U : 0x00U) << 1;
m_data[0U] &= 0xFDU;
m_data[0U] |= (m_direction << 1) & 0x02U;
#if DEBUG_NXDN_LICH
LogDebug(LOG_NXDN, "LICH::encode(), m_lich = %02X", m_lich);
#endif
bool parity = getParity();
if (parity)
m_data[0U] |= 0x01U;
m_lich |= 0x01U;
else
m_data[0U] &= 0xFEU;
m_lich &= 0xFEU;
uint32_t offset = NXDN_FSW_LENGTH_BITS;
for (uint32_t i = 0U; i < (NXDN_LICH_LENGTH_BITS / 2U); i++) {
bool b = READ_BIT(m_data, i);
bool b = (m_lich & BIT_MASK_TABLE[(i) & 7]);
WRITE_BIT(data, offset, b);
offset++;
WRITE_BIT(data, offset, true);
@ -168,13 +179,12 @@ void LICH::encode(uint8_t* data)
/// <param name="data"></param>
void LICH::copy(const LICH& data)
{
m_data = new uint8_t[1U];
m_data[0U] = data.m_data[0U];
m_lich = data.m_lich;
m_rfct = (m_data[0U] >> 6) & 0x03U;
m_fct = (m_data[0U] >> 4) & 0x03U;
m_option = (m_data[0U] >> 2) & 0x03U;
m_direction = (m_data[0U] >> 1) & 0x01U;
m_rfct = (m_lich >> 6) & 0x03U;
m_fct = (m_lich >> 4) & 0x03U;
m_option = (m_lich >> 2) & 0x03U;
m_outbound = ((m_lich >> 1) & 0x01U) == 0x01U;
}
/// <summary>
@ -183,7 +193,7 @@ void LICH::copy(const LICH& data)
/// <returns></returns>
bool LICH::getParity() const
{
switch (m_data[0U] & 0xF0U) {
switch (m_lich & 0xF0U) {
case 0x80U:
case 0xB0U:
return true;

@ -67,11 +67,11 @@ namespace nxdn
__PROPERTY(uint8_t, fct, FCT);
/// <summary>Channel Options</summary>
__PROPERTY(uint8_t, option, Option);
/// <summary>Channel Direction</summary>
__PROPERTY(uint8_t, direction, Direction);
/// <summary>Flag indicating outbound traffic direction</summary>
__PROPERTY(bool, outbound, Outbound);
private:
uint8_t* m_data;
uint8_t m_lich;
/// <summary>Internal helper to copy the class.</summary>
void copy(const LICH& data);

@ -66,11 +66,12 @@ const uint32_t PUNCTURE_LIST[] = { 5U, 11U, 17U, 23U, 29U, 35U, 41U, 47U, 53U, 5
/// </summary>
SACCH::SACCH() :
m_verbose(false),
m_ran(0U),
m_structure(0U),
m_ran(1U),
m_structure(NXDN_SR_SINGLE),
m_data(NULL)
{
m_data = new uint8_t[NXDN_SACCH_LENGTH_BYTES];
m_data = new uint8_t[NXDN_SACCH_CRC_LENGTH_BYTES];
::memset(m_data, 0x00U, NXDN_SACCH_CRC_LENGTH_BYTES);
}
/// <summary>
@ -79,8 +80,8 @@ SACCH::SACCH() :
/// <param name="data"></param>
SACCH::SACCH(const SACCH& data) :
m_verbose(false),
m_ran(0U),
m_structure(0U),
m_ran(1U),
m_structure(NXDN_SR_SINGLE),
m_data(NULL)
{
copy(data);
@ -102,7 +103,7 @@ SACCH::~SACCH()
SACCH& SACCH::operator=(const SACCH& data)
{
if (&data != this) {
::memcpy(m_data, data.m_data, NXDN_SACCH_LENGTH_BYTES);
::memcpy(m_data, data.m_data, NXDN_SACCH_CRC_LENGTH_BYTES);
m_verbose = data.m_verbose;
@ -123,6 +124,7 @@ bool SACCH::decode(const uint8_t* data)
assert(data != NULL);
uint8_t buffer[NXDN_SACCH_FEC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_SACCH_FEC_LENGTH_BYTES);
// deinterleave
for (uint32_t i = 0U; i < NXDN_SACCH_FEC_LENGTH_BITS; i++) {
@ -157,21 +159,21 @@ bool SACCH::decode(const uint8_t* data)
conv.start();
n = 0U;
for (uint32_t i = 0U; i < (NXDN_SACCH_LENGTH_BITS + 4U); i++) {
for (uint32_t i = 0U; i < (NXDN_SACCH_CRC_LENGTH_BITS + 4U); i++) {
uint8_t s0 = puncture[n++];
uint8_t s1 = puncture[n++];
conv.decode(s0, s1);
}
conv.chainback(m_data, NXDN_SACCH_LENGTH_BITS);
conv.chainback(m_data, NXDN_SACCH_CRC_LENGTH_BITS);
if (m_verbose) {
Utils::dump(2U, "Decoded SACCH", m_data, NXDN_SACCH_LENGTH_BYTES);
Utils::dump(2U, "Decoded SACCH", m_data, NXDN_SACCH_CRC_LENGTH_BYTES);
}
// check CRC-6
bool ret = CRC::checkCRC6(m_data, NXDN_SACCH_CRC_BITS);
bool ret = CRC::checkCRC6(m_data, NXDN_SACCH_LENGTH_BITS);
if (!ret) {
LogError(LOG_NXDN, "SACCH::decode(), failed CRC-6 check");
return false;
@ -191,30 +193,32 @@ void SACCH::encode(uint8_t* data) const
{
assert(data != NULL);
m_data[0U] &= 0xC0U;
m_data[0U] |= m_ran;
m_data[0U] &= 0xC0U;
m_data[0U] |= m_ran;
m_data[0U] &= 0x3FU;
m_data[0U] |= (m_structure << 6) & 0xC0U;
m_data[0U] &= 0x3FU;
m_data[0U] |= (m_structure << 6) & 0xC0U;
uint8_t buffer[NXDN_SACCH_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_SACCH_LENGTH_BYTES);
uint8_t buffer[NXDN_SACCH_CRC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_SACCH_CRC_LENGTH_BYTES);
for (uint32_t i = 0U; i < NXDN_SACCH_CRC_BITS; i++) {
for (uint32_t i = 0U; i < NXDN_SACCH_LENGTH_BITS; i++) {
bool b = READ_BIT(m_data, i);
WRITE_BIT(buffer, i, b);
}
CRC::addCRC6(buffer, NXDN_SACCH_CRC_BITS);
CRC::addCRC6(buffer, NXDN_SACCH_LENGTH_BITS);
if (m_verbose) {
Utils::dump(2U, "Encoded SACCH", buffer, NXDN_SACCH_LENGTH_BYTES);
Utils::dump(2U, "Encoded SACCH", buffer, NXDN_SACCH_CRC_LENGTH_BYTES);
}
// encode convolution
uint8_t convolution[NXDN_SACCH_FEC_CONV_LENGTH_BYTES];
::memset(convolution, 0x00U, NXDN_SACCH_FEC_CONV_LENGTH_BYTES);
Convolution conv;
conv.encode(buffer, convolution, NXDN_SACCH_LENGTH_BITS);
conv.encode(buffer, convolution, NXDN_SACCH_CRC_LENGTH_BITS);
#if DEBUG_NXDN_SACCH
Utils::dump(2U, "SACCH::encode(), SACCH Convolution", convolution, NXDN_SACCH_FEC_CONV_LENGTH_BYTES);
@ -222,6 +226,8 @@ void SACCH::encode(uint8_t* data) const
// puncture
uint8_t puncture[NXDN_SACCH_FEC_LENGTH_BYTES];
::memset(puncture, 0x00U, NXDN_SACCH_FEC_LENGTH_BYTES);
uint32_t n = 0U, index = 0U;
for (uint32_t i = 0U; i < NXDN_SACCH_FEC_CONV_LENGTH_BITS; i++) {
if (i != PUNCTURE_LIST[index]) {
@ -254,7 +260,7 @@ void SACCH::getData(uint8_t* data) const
assert(data != NULL);
uint32_t offset = 8U;
for (uint32_t i = 0U; i < (NXDN_SACCH_CRC_BITS - 8); i++, offset++) {
for (uint32_t i = 0U; i < (NXDN_SACCH_LENGTH_BITS - 8); i++, offset++) {
bool b = READ_BIT(m_data, offset);
WRITE_BIT(data, i, b);
}
@ -269,7 +275,7 @@ void SACCH::setData(const uint8_t* data)
assert(data != NULL);
uint32_t offset = 8U;
for (uint32_t i = 0U; i < (NXDN_SACCH_CRC_BITS - 8); i++, offset++) {
for (uint32_t i = 0U; i < (NXDN_SACCH_LENGTH_BITS - 8); i++, offset++) {
bool b = READ_BIT(data, i);
WRITE_BIT(m_data, offset, b);
}
@ -285,8 +291,8 @@ void SACCH::setData(const uint8_t* data)
/// <param name="data"></param>
void SACCH::copy(const SACCH& data)
{
m_data = new uint8_t[NXDN_SACCH_LENGTH_BYTES];
::memcpy(m_data, data.m_data, NXDN_SACCH_LENGTH_BYTES);
m_data = new uint8_t[NXDN_SACCH_CRC_LENGTH_BYTES];
::memcpy(m_data, data.m_data, NXDN_SACCH_CRC_LENGTH_BYTES);
m_ran = m_data[0U] & 0x3FU;
m_structure = (m_data[0U] >> 6) & 0x03U;

@ -98,7 +98,8 @@ UDCH::UDCH() :
m_ran(0U),
m_data(NULL)
{
m_data = new uint8_t[NXDN_UDCH_LENGTH_BYTES];
m_data = new uint8_t[NXDN_UDCH_CRC_LENGTH_BYTES];
::memset(m_data, 0x00U, NXDN_UDCH_CRC_LENGTH_BYTES);
}
/// <summary>
@ -129,7 +130,7 @@ UDCH::~UDCH()
UDCH& UDCH::operator=(const UDCH& data)
{
if (&data != this) {
::memcpy(m_data, data.m_data, NXDN_UDCH_LENGTH_BYTES);
::memcpy(m_data, data.m_data, NXDN_UDCH_CRC_LENGTH_BYTES);
m_verbose = data.m_verbose;
@ -149,6 +150,7 @@ bool UDCH::decode(const uint8_t* data)
assert(data != NULL);
uint8_t buffer[NXDN_UDCH_FEC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_UDCH_FEC_LENGTH_BYTES);
// deinterleave
for (uint32_t i = 0U; i < NXDN_UDCH_FEC_LENGTH_BITS; i++) {
@ -183,21 +185,21 @@ bool UDCH::decode(const uint8_t* data)
conv.start();
n = 0U;
for (uint32_t i = 0U; i < (NXDN_UDCH_LENGTH_BITS + 4U); i++) {
for (uint32_t i = 0U; i < (NXDN_UDCH_CRC_LENGTH_BITS + 4U); i++) {
uint8_t s0 = puncture[n++];
uint8_t s1 = puncture[n++];
conv.decode(s0, s1);
}
conv.chainback(m_data, NXDN_UDCH_LENGTH_BITS);
conv.chainback(m_data, NXDN_UDCH_CRC_LENGTH_BITS);
if (m_verbose) {
Utils::dump(2U, "Decoded UDCH", m_data, NXDN_UDCH_LENGTH_BYTES);
Utils::dump(2U, "Decoded UDCH", m_data, NXDN_UDCH_CRC_LENGTH_BYTES);
}
// check CRC-15
bool ret = CRC::checkCRC15(m_data, NXDH_UDCH_CRC_BITS);
bool ret = CRC::checkCRC15(m_data, NXDN_UDCH_LENGTH_BITS);
if (!ret) {
LogError(LOG_NXDN, "UDCH::decode(), failed CRC-15 check");
return false;
@ -218,20 +220,22 @@ void UDCH::encode(uint8_t* data) const
m_data[0U] = m_ran;
uint8_t buffer[NXDN_UDCH_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_UDCH_LENGTH_BYTES);
uint8_t buffer[NXDN_UDCH_CRC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_UDCH_CRC_LENGTH_BYTES);
::memcpy(buffer, m_data, 23U);
CRC::addCRC15(buffer, NXDH_UDCH_CRC_BITS);
CRC::addCRC15(buffer, NXDN_UDCH_LENGTH_BITS);
if (m_verbose) {
Utils::dump(2U, "Encoded UDCH", m_data, NXDN_UDCH_LENGTH_BYTES);
Utils::dump(2U, "Encoded UDCH", m_data, NXDN_UDCH_CRC_LENGTH_BYTES);
}
// encode convolution
uint8_t convolution[NXDN_UDCH_FEC_CONV_LENGTH_BYTES];
::memset(convolution, 0x00U, NXDN_UDCH_FEC_CONV_LENGTH_BYTES);
Convolution conv;
conv.encode(buffer, convolution, NXDN_UDCH_LENGTH_BITS);
conv.encode(buffer, convolution, NXDN_UDCH_CRC_LENGTH_BITS);
#if DEBUG_NXDN_UDCH
Utils::dump(2U, "UDCH::encode(), UDCH Convolution", convolution, NXDN_UDCH_FEC_CONV_LENGTH_BYTES);
@ -239,6 +243,8 @@ void UDCH::encode(uint8_t* data) const
// puncture
uint8_t puncture[NXDN_UDCH_FEC_LENGTH_BYTES];
::memset(puncture, 0x00U, NXDN_UDCH_FEC_LENGTH_BYTES);
uint32_t n = 0U, index = 0U;
for (uint32_t i = 0U; i < NXDN_UDCH_FEC_CONV_LENGTH_BITS; i++) {
if (i != PUNCTURE_LIST[index]) {
@ -270,7 +276,7 @@ void UDCH::getData(uint8_t* data) const
{
assert(data != NULL);
::memcpy(data, m_data + 1U, 22U);
::memcpy(data, m_data + 1U, NXDN_RTCH_LC_LENGTH_BYTES);
}
/// <summary>
@ -281,7 +287,7 @@ void UDCH::setData(const uint8_t* data)
{
assert(data != NULL);
::memcpy(m_data + 1U, data, 22U);
::memcpy(m_data + 1U, data, NXDN_RTCH_LC_LENGTH_BYTES);
}
// ---------------------------------------------------------------------------
@ -294,8 +300,8 @@ void UDCH::setData(const uint8_t* data)
/// <param name="data"></param>
void UDCH::copy(const UDCH& data)
{
m_data = new uint8_t[26U];
::memcpy(m_data, data.m_data, 26U);
m_data = new uint8_t[NXDN_UDCH_CRC_LENGTH_BYTES];
::memcpy(m_data, data.m_data, NXDN_UDCH_CRC_LENGTH_BYTES);
m_ran = m_data[0U] & 0x3FU;
}

@ -91,7 +91,13 @@ RCCH& RCCH::operator=(const RCCH& data)
{
if (&data != this) {
::memcpy(m_data, data.m_data, NXDN_RCCH_LC_LENGTH_BYTES);
decodeLC(m_data);
m_verbose = data.m_verbose;
if (m_data != NULL) {
if ((m_data[0] & 0x3FU) != 0U) {
decodeLC(m_data);
}
}
}
return *this;
@ -101,6 +107,8 @@ RCCH& RCCH::operator=(const RCCH& data)
/// Decode call link control data.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
/// <returns>True, if RCCH was decoded, otherwise false.</returns>
void RCCH::decode(const uint8_t* data, uint32_t length, uint32_t offset)
{
@ -111,10 +119,6 @@ void RCCH::decode(const uint8_t* data, uint32_t length, uint32_t offset)
WRITE_BIT(m_data, offset, b);
}
if (m_verbose) {
Utils::dump(2U, "Decoded RCCH Data", m_data, NXDN_RCCH_LC_LENGTH_BYTES);
}
decodeLC(m_data);
}
@ -134,10 +138,6 @@ void RCCH::encode(uint8_t* data, uint32_t length, uint32_t offset)
bool b = READ_BIT(m_data, offset);
WRITE_BIT(data, i, b);
}
if (m_verbose) {
Utils::dump(2U, "Encoded RCCH Data", data, length);
}
}
/// <summary>

@ -123,7 +123,13 @@ RTCH& RTCH::operator=(const RTCH& data)
{
if (&data != this) {
::memcpy(m_data, data.m_data, NXDN_RTCH_LC_LENGTH_BYTES);
decodeLC(m_data);
m_verbose = data.m_verbose;
if (m_data != NULL) {
if ((m_data[0] & 0x3FU) != 0U) {
decodeLC(m_data);
}
}
}
return *this;

@ -193,11 +193,11 @@ bool Data::process(uint8_t option, uint8_t* data, uint32_t len)
}
// the layer 3 LC data will only be correct if valid is true
uint8_t buffer[NXDN_UDCH_LENGTH_BYTES];
uint8_t buffer[NXDN_RTCH_LC_LENGTH_BYTES];
udch.getData(buffer);
lc::RTCH lc;
lc.decode(buffer, NXDH_UDCH_CRC_BITS);
lc.decode(buffer, NXDN_UDCH_LENGTH_BITS);
uint16_t dstId = lc.getDstId();
uint16_t srcId = lc.getSrcId();
bool group = lc.getGroup();
@ -237,10 +237,10 @@ bool Data::process(uint8_t option, uint8_t* data, uint32_t len)
lich.setRFCT(NXDN_LICH_RFCT_RDCH);
lich.setFCT(NXDN_LICH_USC_UDCH);
lich.setOption(option);
lich.setDirection(!m_nxdn->m_duplex ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND);
lich.setOutbound(!m_nxdn->m_duplex ? false : true);
lich.encode(data + 2U);
lich.setDirection(NXDN_LICH_DIRECTION_INBOUND);
lich.setOutbound(false);
uint8_t type = RTCH_MESSAGE_TYPE_DCALL_DATA;
if (validUDCH) {
@ -301,11 +301,11 @@ bool Data::processNetwork(uint8_t option, lc::RTCH& netLC, uint8_t* data, uint32
return false;
// The layer3 data will only be correct if valid is true
uint8_t buffer[NXDN_UDCH_LENGTH_BYTES];
uint8_t buffer[NXDN_RTCH_LC_LENGTH_BYTES];
udch.getData(buffer);
lc::RTCH lc;
lc.decode(buffer, NXDH_UDCH_CRC_BITS);
lc.decode(buffer, NXDN_UDCH_LENGTH_BITS);
uint16_t dstId = lc.getDstId();
uint16_t srcId = lc.getSrcId();
bool group = lc.getGroup();
@ -345,7 +345,7 @@ bool Data::processNetwork(uint8_t option, lc::RTCH& netLC, uint8_t* data, uint32
lich.setRFCT(NXDN_LICH_RFCT_RDCH);
lich.setFCT(NXDN_LICH_USC_UDCH);
lich.setOption(option);
lich.setDirection(NXDN_LICH_DIRECTION_OUTBOUND);
lich.setOutbound(true);
lich.encode(data + 2U);
uint8_t type = RTCH_MESSAGE_TYPE_DCALL_DATA;

@ -163,10 +163,10 @@ bool Trunk::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
m_nxdn->m_queue.clear();
// the layer3 data will only be correct if valid is true
uint8_t buffer[NXDN_CAC_LENGTH_BYTES];
uint8_t buffer[NXDN_CAC_FRAME_LENGTH_BYTES];
cac.getData(buffer);
m_rfLC.decode(buffer, NXDN_CAC_SHORT_IN_CRC_BITS);
m_rfLC.decode(buffer, NXDN_RCCH_CAC_LC_SHORT_LENGTH_BITS);
uint16_t srcId = m_rfLC.getSrcId();
uint16_t dstId = m_rfLC.getDstId();
@ -388,15 +388,16 @@ void Trunk::writeRF_Message(bool noNetwork, bool clearBeforeWrite)
lich.setRFCT(NXDN_LICH_RFCT_RCCH);
lich.setFCT(NXDN_LICH_CAC_OUTBOUND);
lich.setOption(NXDN_LICH_DATA_NORMAL);
lich.setDirection(NXDN_LICH_DIRECTION_OUTBOUND);
lich.setOutbound(true);
lich.encode(data + 2U);
uint8_t buffer[NXDN_RCCH_LC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES);
m_rfLC.encode(buffer, NXDN_CAC_OUT_CRC_BITS);
m_rfLC.encode(buffer, NXDN_RCCH_LC_LENGTH_BITS);
channel::CAC cac;
cac.setVerbose(m_dumpRCCH);
cac.setRAN(m_nxdn->m_ran);
cac.setData(buffer);
cac.encode(data + 2U);
@ -687,18 +688,20 @@ void Trunk::writeRF_CC_Message_Site_Info()
channel::LICH lich;
lich.setRFCT(NXDN_LICH_RFCT_RCCH);
lich.setFCT(NXDN_LICH_CAC_OUTBOUND);
lich.setOption(NXDN_LICH_DATA_NORMAL);
lich.setDirection(NXDN_LICH_DIRECTION_OUTBOUND);
lich.setOption(NXDN_LICH_DATA_COMMON);
lich.setOutbound(true);
lich.encode(data + 2U);
uint8_t buffer[NXDN_RCCH_LC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES);
m_rfLC.setMessageType(RCCH_MESSAGE_TYPE_SITE_INFO);
m_rfLC.encode(buffer, NXDN_CAC_OUT_CRC_BITS);
m_rfLC.encode(buffer, NXDN_RCCH_LC_LENGTH_BITS);
channel::CAC cac;
cac.setVerbose(m_dumpRCCH);
cac.setRAN(m_nxdn->m_ran);
cac.setStructure(NXDN_SR_RCCH_HEAD_SINGLE);
cac.setData(buffer);
cac.encode(data + 2U);
@ -730,17 +733,19 @@ void Trunk::writeRF_CC_Message_Service_Info()
lich.setRFCT(NXDN_LICH_RFCT_RCCH);
lich.setFCT(NXDN_LICH_CAC_OUTBOUND);
lich.setOption(NXDN_LICH_DATA_NORMAL);
lich.setDirection(NXDN_LICH_DIRECTION_OUTBOUND);
lich.setOutbound(true);
lich.encode(data + 2U);
uint8_t buffer[NXDN_RCCH_LC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES);
m_rfLC.setMessageType(MESSAGE_TYPE_SRV_INFO);
m_rfLC.encode(buffer, NXDN_CAC_OUT_CRC_BITS);
m_rfLC.encode(buffer, NXDN_RCCH_LC_LENGTH_BITS);
channel::CAC cac;
cac.setVerbose(m_dumpRCCH);
cac.setRAN(m_nxdn->m_ran);
cac.setStructure(NXDN_SR_RCCH_SINGLE);
cac.setData(buffer);
cac.encode(data + 2U);

@ -247,7 +247,7 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
lich.setRFCT(NXDN_LICH_RFCT_RDCH);
lich.setFCT(NXDN_LICH_USC_SACCH_NS);
lich.setOption(NXDN_LICH_STEAL_FACCH);
lich.setDirection(!m_nxdn->m_duplex ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND);
lich.setOutbound(!m_nxdn->m_duplex ? false : true);
lich.encode(data + 2U);
// generate the SACCH
@ -424,10 +424,10 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
lich.setRFCT(NXDN_LICH_RFCT_RDCH);
lich.setFCT(NXDN_LICH_USC_SACCH_NS);
lich.setOption(NXDN_LICH_STEAL_FACCH);
lich.setDirection(!m_nxdn->m_duplex ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND);
lich.setOutbound(!m_nxdn->m_duplex ? false : true);
lich.encode(start + 2U);
lich.setDirection(NXDN_LICH_DIRECTION_INBOUND);
lich.setOutbound(false);
// generate the SACCH
channel::SACCH sacch;
@ -436,7 +436,7 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
sacch.setStructure(NXDN_SR_SINGLE);
sacch.encode(start + 2U);
uint8_t message[22U];
uint8_t message[NXDN_RTCH_LC_LENGTH_BYTES];
m_nxdn->m_rfLC.getData(message);
facch.setData(message);
@ -465,10 +465,10 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
lich.setRFCT(NXDN_LICH_RFCT_RDCH);
lich.setFCT(NXDN_LICH_USC_SACCH_SS);
lich.setOption(option);
lich.setDirection(!m_nxdn->m_duplex ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND);
lich.setOutbound(!m_nxdn->m_duplex ? false : true);
lich.encode(data + 2U);
lich.setDirection(NXDN_LICH_DIRECTION_INBOUND);
lich.setOutbound(false);
// regenerate SACCH if it's valid
channel::SACCH sacch;
@ -672,7 +672,7 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
lich.setRFCT(NXDN_LICH_RFCT_RDCH);
lich.setFCT(NXDN_LICH_USC_SACCH_NS);
lich.setOption(NXDN_LICH_STEAL_FACCH);
lich.setDirection(NXDN_LICH_DIRECTION_OUTBOUND);
lich.setOutbound(true);
lich.encode(data + 2U);
// generate the SACCH
@ -827,7 +827,7 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
lich.setRFCT(NXDN_LICH_RFCT_RDCH);
lich.setFCT(NXDN_LICH_USC_SACCH_NS);
lich.setOption(NXDN_LICH_STEAL_FACCH);
lich.setDirection(NXDN_LICH_DIRECTION_OUTBOUND);
lich.setOutbound(true);
lich.encode(start + 2U);
// generate the SACCH
@ -837,7 +837,7 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
sacch.setStructure(NXDN_SR_SINGLE);
sacch.encode(start + 2U);
uint8_t message[22U];
uint8_t message[NXDN_RTCH_LC_LENGTH_BYTES];
m_nxdn->m_rfLC.getData(message);
facch.setData(message);
@ -864,7 +864,7 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
lich.setRFCT(NXDN_LICH_RFCT_RDCH);
lich.setFCT(NXDN_LICH_USC_SACCH_SS);
lich.setOption(option);
lich.setDirection(NXDN_LICH_DIRECTION_OUTBOUND);
lich.setOutbound(true);
lich.encode(data + 2U);
// regenerate SACCH if it's valid

Loading…
Cancel
Save

Powered by TurnKey Linux.