diff --git a/src/common/nxdn/channel/CAC.cpp b/src/common/nxdn/channel/CAC.cpp
index 766d3770..bd0eeb36 100644
--- a/src/common/nxdn/channel/CAC.cpp
+++ b/src/common/nxdn/channel/CAC.cpp
@@ -120,6 +120,7 @@ CAC::CAC() :
CAC::CAC(const CAC& data) :
m_ran(0U),
m_structure(ChStructure::SR_RCCH_SINGLE),
+ m_longInbound(false),
m_idleBusy(true),
m_txContinuous(false),
m_receive(true),
@@ -150,6 +151,8 @@ CAC& CAC::operator=(const CAC& data)
m_ran = m_data[0U] & 0x3FU;
m_structure = (ChStructure::E)((m_data[0U] >> 6) & 0x03U);
+ m_longInbound = data.m_longInbound;
+
m_idleBusy = data.m_idleBusy;
m_txContinuous = data.m_txContinuous;
m_receive = data.m_receive;
@@ -185,9 +188,11 @@ bool CAC::decode(const uint8_t* data, bool longInbound)
#endif
if (longInbound) {
+ m_longInbound = longInbound;
+
// depuncture
- uint8_t puncture[324U];
- ::memset(puncture, 0x00U, 324U);
+ uint8_t puncture[322U];
+ ::memset(puncture, 0x00U, 322U);
uint32_t n = 0U, index = 0U;
for (uint32_t i = 0U; i < NXDN_CAC_IN_FEC_LENGTH_BITS; i++) {
@@ -214,7 +219,7 @@ bool CAC::decode(const uint8_t* data, bool longInbound)
uint8_t s1 = puncture[n++];
if (!conv.decode(s0, s1)) {
- LogError(LOG_NXDN, "CAC::decode(), failed to decode convolution");
+ LogError(LOG_NXDN, "CAC::decode(longInbound), failed to decode convolution, i = %u, n = %u", i);
return false;
}
}
@@ -222,13 +227,13 @@ bool CAC::decode(const uint8_t* data, bool longInbound)
conv.chainback(m_data, NXDN_CAC_LONG_CRC_LENGTH_BITS);
#if DEBUG_NXDN_CAC
- Utils::dump(2U, "Decoded CAC", m_data, (NXDN_CAC_LONG_CRC_LENGTH_BITS / 8U) + 1U);
+ Utils::dump(2U, "Decoded Long CAC", m_data, (NXDN_CAC_LONG_CRC_LENGTH_BITS / 8U) + 1U);
#endif
// check CRC-16
bool ret = edac::CRC::checkCRC16(m_data, NXDN_CAC_LONG_LENGTH_BITS);
if (!ret) {
- LogError(LOG_NXDN, "CAC::decode(), failed CRC-6 check");
+ LogError(LOG_NXDN, "CAC::decode(longInbound), failed CRC-16 check");
return false;
}
@@ -248,17 +253,31 @@ bool CAC::decode(const uint8_t* data, bool longInbound)
m_rxCRC = (crc[0U] << 8) | (crc[1U] << 0);
}
else {
+ // generate pass-thru bit buffer (no puncturing for short CAC)
+ uint8_t pass[322U];
+ ::memset(pass, 0x00U, 322U);
+
+ uint32_t n = 0U;
+ for (uint32_t i = 0U; i < NXDN_CAC_IN_FEC_LENGTH_BITS; i++) {
+ bool b = READ_BIT(buffer, i);
+ pass[n++] = b ? 2U : 0U;
+ }
+
+ for (uint32_t i = 0U; i < 8U; i++) {
+ pass[n++] = 0U;
+ }
+
// decode convolution
edac::Convolution conv;
conv.start();
- uint32_t n = 0U;
+ n = 0U;
for (uint32_t i = 0U; i < (NXDN_CAC_SHORT_CRC_LENGTH_BITS + 4U); i++) {
- uint8_t s0 = buffer[n++];
- uint8_t s1 = buffer[n++];
+ uint8_t s0 = pass[n++];
+ uint8_t s1 = pass[n++];
if (!conv.decode(s0, s1)) {
- LogError(LOG_NXDN, "CAC::decode(), failed to decode convolution");
+ LogError(LOG_NXDN, "CAC::decode(), failed to decode convolution, i = %u, n = %u", i);
return false;
}
}
@@ -272,7 +291,7 @@ bool CAC::decode(const uint8_t* data, bool longInbound)
// check CRC-16
bool ret = edac::CRC::checkCRC16(m_data, NXDN_CAC_SHORT_LENGTH_BITS);
if (!ret) {
- LogError(LOG_NXDN, "CAC::decode(), failed CRC-6 check");
+ LogError(LOG_NXDN, "CAC::decode(), failed CRC-16 check");
return false;
}
@@ -390,9 +409,16 @@ void CAC::getData(uint8_t* data) const
assert(data != nullptr);
uint32_t offset = 8U;
- 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);
+ if (m_longInbound) {
+ for (uint32_t i = 0U; i < (NXDN_CAC_LONG_LENGTH_BITS - 8U); i++, offset++) {
+ bool b = READ_BIT(m_data, offset);
+ WRITE_BIT(data, i, b);
+ }
+ } else {
+ for (uint32_t i = 0U; i < (NXDN_CAC_SHORT_LENGTH_BITS - 10U); i++, offset++) {
+ bool b = READ_BIT(m_data, offset);
+ WRITE_BIT(data, i, b);
+ }
}
}
@@ -429,6 +455,8 @@ void CAC::copy(const CAC& data)
m_ran = m_data[0U] & 0x3FU;
m_structure = (ChStructure::E)((m_data[0U] >> 6) & 0x03U);
+ m_longInbound = data.m_longInbound;
+
m_idleBusy = data.m_idleBusy;
m_txContinuous = data.m_txContinuous;
m_receive = data.m_receive;
diff --git a/src/common/nxdn/channel/CAC.h b/src/common/nxdn/channel/CAC.h
index 1a53f99b..439a4358 100644
--- a/src/common/nxdn/channel/CAC.h
+++ b/src/common/nxdn/channel/CAC.h
@@ -53,6 +53,8 @@ namespace nxdn
__PROPERTY(uint8_t, ran, RAN);
///
__PROPERTY(defines::ChStructure::E, structure, Structure);
+ ///
+ __PROPERTY(bool, longInbound, LongInbound);
/** Collision Control Field */
/// Idle/Busy.
diff --git a/src/common/nxdn/channel/FACCH1.cpp b/src/common/nxdn/channel/FACCH1.cpp
index a624c237..b5d92814 100644
--- a/src/common/nxdn/channel/FACCH1.cpp
+++ b/src/common/nxdn/channel/FACCH1.cpp
@@ -143,7 +143,7 @@ bool FACCH1::decode(const uint8_t* data, uint32_t offset)
uint8_t s1 = puncture[n++];
if (!conv.decode(s0, s1)) {
- LogError(LOG_NXDN, "FACCH1::decode(), failed to decode convolution");
+ LogError(LOG_NXDN, "FACCH1::decode(), failed to decode convolution, i = %u, n = %u", i);
return false;
}
}
diff --git a/src/common/nxdn/channel/SACCH.cpp b/src/common/nxdn/channel/SACCH.cpp
index dc7cb4a9..24fa77a9 100644
--- a/src/common/nxdn/channel/SACCH.cpp
+++ b/src/common/nxdn/channel/SACCH.cpp
@@ -145,7 +145,7 @@ bool SACCH::decode(const uint8_t* data)
uint8_t s1 = puncture[n++];
if (!conv.decode(s0, s1)) {
- LogError(LOG_NXDN, "SACCH::decode(), failed to decode convolution");
+ LogError(LOG_NXDN, "SACCH::decode(), failed to decode convolution, i = %u, n = %u", i);
return false;
}
}
diff --git a/src/common/nxdn/channel/UDCH.cpp b/src/common/nxdn/channel/UDCH.cpp
index d295352d..88e34fab 100644
--- a/src/common/nxdn/channel/UDCH.cpp
+++ b/src/common/nxdn/channel/UDCH.cpp
@@ -169,7 +169,7 @@ bool UDCH::decode(const uint8_t* data)
uint8_t s1 = puncture[n++];
if (!conv.decode(s0, s1)) {
- LogError(LOG_NXDN, "UDCH::decode(), failed to decode convolution");
+ LogError(LOG_NXDN, "UDCH::decode(), failed to decode convolution, i = %u, n = %u", i);
return false;
}
}
diff --git a/src/common/nxdn/lc/rcch/RCCHFactory.cpp b/src/common/nxdn/lc/rcch/RCCHFactory.cpp
index 8b62828c..7a9d2dd6 100644
--- a/src/common/nxdn/lc/rcch/RCCHFactory.cpp
+++ b/src/common/nxdn/lc/rcch/RCCHFactory.cpp
@@ -47,14 +47,6 @@ std::unique_ptr RCCHFactory::createRCCH(const uint8_t* data, uint32_t leng
{
assert(data != nullptr);
- uint8_t rcch[22U];
- ::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
-
- for (uint32_t i = 0U; i < length; i++, offset++) {
- bool b = READ_BIT(data, offset);
- WRITE_BIT(rcch, i, b);
- }
-
uint8_t messageType = data[0U] & 0x3FU; // Message Type
// message type opcodes
diff --git a/src/host/nxdn/Control.cpp b/src/host/nxdn/Control.cpp
index 0ce729aa..93f0bf13 100644
--- a/src/host/nxdn/Control.cpp
+++ b/src/host/nxdn/Control.cpp
@@ -38,7 +38,7 @@ using namespace nxdn::packet;
// Constants
// ---------------------------------------------------------------------------
-const uint8_t MAX_SYNC_BYTES_ERRS = 0U;
+const uint8_t MAX_SYNC_BYTES_ERRS = 3U;
const uint8_t SCRAMBLER[] = {
0x00U, 0x00U, 0x00U, 0x82U, 0xA0U, 0x88U, 0x8AU, 0x00U, 0xA2U, 0xA8U, 0x82U, 0x8AU, 0x82U, 0x02U,
@@ -428,6 +428,10 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
for (uint8_t i = 0U; i < NXDN_FSW_BYTES_LENGTH; i++)
errs += Utils::countBits8(syncBytes[i] ^ NXDN_FSW_BYTES[i]);
+ // silently ignore frames with errors greater then 2 times the maximum
+ if (errs > MAX_SYNC_BYTES_ERRS * 2U)
+ return false;
+
if (errs >= MAX_SYNC_BYTES_ERRS) {
LogWarning(LOG_RF, "NXDN, possible sync word rejected, errs = %u, sync word = %02X %02X %02X", errs,
syncBytes[0U], syncBytes[1U], syncBytes[2U]);
@@ -470,15 +474,7 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
LogDebug(LOG_RF, "NXDN, valid LICH, rfState = %u, netState = %u, rfct = %u, fct = %u", m_rfState, m_netState, rfct, fct);
}
- // are we interrupting a running CC?
- if (m_ccRunning) {
- if ((fct != FuncChannelType::CAC_INBOUND_SHORT) || (fct != FuncChannelType::CAC_INBOUND_LONG)) {
- m_ccHalted = true;
- }
- }
-
bool ret = false;
-
if (rfct == RFChannelType::RCCH) {
ret = m_control->process(fct, option, data, len);
}
@@ -493,14 +489,6 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
ret = m_voice->process(fct, option, data, len);
break;
}
-
- if (m_ccRunning) {
- m_ccHalted = false;
- }
- } else {
- if (m_ccRunning) {
- m_ccHalted = false;
- }
}
return ret;
diff --git a/src/host/nxdn/packet/ControlSignaling.cpp b/src/host/nxdn/packet/ControlSignaling.cpp
index 292bdea3..ba3e5527 100644
--- a/src/host/nxdn/packet/ControlSignaling.cpp
+++ b/src/host/nxdn/packet/ControlSignaling.cpp
@@ -138,8 +138,9 @@ bool ControlSignaling::process(FuncChannelType::E fct, ChOption::E option, uint8
channel::CAC cac;
bool validCAC = cac.decode(data + 2U, (fct == FuncChannelType::CAC_INBOUND_LONG));
- if (m_nxdn->m_rfState == RS_RF_LISTENING && !validCAC)
+ if (m_nxdn->m_rfState == RS_RF_LISTENING && !validCAC) {
return false;
+ }
if (validCAC) {
uint8_t ran = cac.getRAN();
@@ -367,7 +368,7 @@ void ControlSignaling::writeRF_Message(RCCH* rcch, bool noNetwork, bool imm)
channel::LICH lich;
lich.setRFCT(RFChannelType::RCCH);
lich.setFCT(FuncChannelType::CAC_OUTBOUND);
- lich.setOption(ChOption::DATA_COMMON);
+ lich.setOption(ChOption::DATA_NORMAL);
lich.setOutbound(true);
lich.encode(data + 2U);
@@ -379,7 +380,7 @@ void ControlSignaling::writeRF_Message(RCCH* rcch, bool noNetwork, bool imm)
// generate the CAC
channel::CAC cac;
cac.setRAN(m_nxdn->m_ran);
- cac.setStructure(ChStructure::SR_SINGLE);
+ cac.setStructure(ChStructure::SR_RCCH_SINGLE);
cac.setData(buffer);
cac.encode(data + 2U);
@@ -592,7 +593,7 @@ bool ControlSignaling::writeRF_Message_Grant(uint32_t srcId, uint32_t dstId, uin
req["dstId"].set(dstId);
int ret = RESTClient::send(voiceChData.address(), voiceChData.port(), voiceChData.password(),
- HTTP_PUT, PUT_PERMIT_TG, req, voiceChData.ssl(), REST_QUICK_WAIT, m_nxdn->m_debug);
+ HTTP_PUT, PUT_PERMIT_TG, req, voiceChData.ssl(), REST_QUICK_WAIT / 2, m_nxdn->m_debug);
if (ret != network::rest::http::HTTPPayload::StatusType::OK) {
::LogError((net) ? LOG_NET : LOG_RF, "NXDN, %s, failed to permit TG for use, chNo = %u", rcch->toString().c_str(), chNo);
m_nxdn->m_affiliations.releaseGrant(dstId, false);