add marking of whether an inbound CAC is long or short; fix issue with short CAC not properly building a puncturing buffer (even tho short CAC doesn't do puncturing, its needed for NXDN convolution); correct CAC getData() return; remove deprecated code causing decoding offsets to be wrong resulting in invalid RCCHs;

pull/61/head
Bryan Biedenkapp 2 years ago
parent 51bd9e749d
commit eacbc27143

@ -120,6 +120,7 @@ CAC::CAC() :
CAC::CAC(const CAC& data) : CAC::CAC(const CAC& data) :
m_ran(0U), m_ran(0U),
m_structure(ChStructure::SR_RCCH_SINGLE), m_structure(ChStructure::SR_RCCH_SINGLE),
m_longInbound(false),
m_idleBusy(true), m_idleBusy(true),
m_txContinuous(false), m_txContinuous(false),
m_receive(true), m_receive(true),
@ -150,6 +151,8 @@ CAC& CAC::operator=(const CAC& data)
m_ran = m_data[0U] & 0x3FU; m_ran = m_data[0U] & 0x3FU;
m_structure = (ChStructure::E)((m_data[0U] >> 6) & 0x03U); m_structure = (ChStructure::E)((m_data[0U] >> 6) & 0x03U);
m_longInbound = data.m_longInbound;
m_idleBusy = data.m_idleBusy; m_idleBusy = data.m_idleBusy;
m_txContinuous = data.m_txContinuous; m_txContinuous = data.m_txContinuous;
m_receive = data.m_receive; m_receive = data.m_receive;
@ -185,9 +188,11 @@ bool CAC::decode(const uint8_t* data, bool longInbound)
#endif #endif
if (longInbound) { if (longInbound) {
m_longInbound = longInbound;
// depuncture // depuncture
uint8_t puncture[324U]; uint8_t puncture[322U];
::memset(puncture, 0x00U, 324U); ::memset(puncture, 0x00U, 322U);
uint32_t n = 0U, index = 0U; uint32_t n = 0U, index = 0U;
for (uint32_t i = 0U; i < NXDN_CAC_IN_FEC_LENGTH_BITS; i++) { 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++]; uint8_t s1 = puncture[n++];
if (!conv.decode(s0, s1)) { 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; 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); conv.chainback(m_data, NXDN_CAC_LONG_CRC_LENGTH_BITS);
#if DEBUG_NXDN_CAC #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 #endif
// check CRC-16 // check CRC-16
bool ret = edac::CRC::checkCRC16(m_data, NXDN_CAC_LONG_LENGTH_BITS); bool ret = edac::CRC::checkCRC16(m_data, NXDN_CAC_LONG_LENGTH_BITS);
if (!ret) { if (!ret) {
LogError(LOG_NXDN, "CAC::decode(), failed CRC-6 check"); LogError(LOG_NXDN, "CAC::decode(longInbound), failed CRC-16 check");
return false; return false;
} }
@ -248,17 +253,31 @@ bool CAC::decode(const uint8_t* data, bool longInbound)
m_rxCRC = (crc[0U] << 8) | (crc[1U] << 0); m_rxCRC = (crc[0U] << 8) | (crc[1U] << 0);
} }
else { 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 // decode convolution
edac::Convolution conv; edac::Convolution conv;
conv.start(); conv.start();
uint32_t n = 0U; n = 0U;
for (uint32_t i = 0U; i < (NXDN_CAC_SHORT_CRC_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 s0 = pass[n++];
uint8_t s1 = buffer[n++]; uint8_t s1 = pass[n++];
if (!conv.decode(s0, s1)) { 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; return false;
} }
} }
@ -272,7 +291,7 @@ bool CAC::decode(const uint8_t* data, bool longInbound)
// check CRC-16 // check CRC-16
bool ret = edac::CRC::checkCRC16(m_data, NXDN_CAC_SHORT_LENGTH_BITS); bool ret = edac::CRC::checkCRC16(m_data, NXDN_CAC_SHORT_LENGTH_BITS);
if (!ret) { if (!ret) {
LogError(LOG_NXDN, "CAC::decode(), failed CRC-6 check"); LogError(LOG_NXDN, "CAC::decode(), failed CRC-16 check");
return false; return false;
} }
@ -390,9 +409,16 @@ void CAC::getData(uint8_t* data) const
assert(data != nullptr); assert(data != nullptr);
uint32_t offset = 8U; uint32_t offset = 8U;
for (uint32_t i = 0U; i < (NXDN_CAC_SHORT_LENGTH_BITS - 10); i++, offset++) { if (m_longInbound) {
bool b = READ_BIT(m_data, offset); for (uint32_t i = 0U; i < (NXDN_CAC_LONG_LENGTH_BITS - 8U); i++, offset++) {
WRITE_BIT(data, i, b); 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_ran = m_data[0U] & 0x3FU;
m_structure = (ChStructure::E)((m_data[0U] >> 6) & 0x03U); m_structure = (ChStructure::E)((m_data[0U] >> 6) & 0x03U);
m_longInbound = data.m_longInbound;
m_idleBusy = data.m_idleBusy; m_idleBusy = data.m_idleBusy;
m_txContinuous = data.m_txContinuous; m_txContinuous = data.m_txContinuous;
m_receive = data.m_receive; m_receive = data.m_receive;

@ -53,6 +53,8 @@ namespace nxdn
__PROPERTY(uint8_t, ran, RAN); __PROPERTY(uint8_t, ran, RAN);
/// <summary></summary> /// <summary></summary>
__PROPERTY(defines::ChStructure::E, structure, Structure); __PROPERTY(defines::ChStructure::E, structure, Structure);
/// <summary></summary>
__PROPERTY(bool, longInbound, LongInbound);
/** Collision Control Field */ /** Collision Control Field */
/// <summary>Idle/Busy.</summary> /// <summary>Idle/Busy.</summary>

@ -143,7 +143,7 @@ bool FACCH1::decode(const uint8_t* data, uint32_t offset)
uint8_t s1 = puncture[n++]; uint8_t s1 = puncture[n++];
if (!conv.decode(s0, s1)) { 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; return false;
} }
} }

@ -145,7 +145,7 @@ bool SACCH::decode(const uint8_t* data)
uint8_t s1 = puncture[n++]; uint8_t s1 = puncture[n++];
if (!conv.decode(s0, s1)) { 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; return false;
} }
} }

@ -169,7 +169,7 @@ bool UDCH::decode(const uint8_t* data)
uint8_t s1 = puncture[n++]; uint8_t s1 = puncture[n++];
if (!conv.decode(s0, s1)) { 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; return false;
} }
} }

@ -47,14 +47,6 @@ std::unique_ptr<RCCH> RCCHFactory::createRCCH(const uint8_t* data, uint32_t leng
{ {
assert(data != nullptr); 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 uint8_t messageType = data[0U] & 0x3FU; // Message Type
// message type opcodes // message type opcodes

@ -38,7 +38,7 @@ using namespace nxdn::packet;
// Constants // Constants
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
const uint8_t MAX_SYNC_BYTES_ERRS = 0U; const uint8_t MAX_SYNC_BYTES_ERRS = 3U;
const uint8_t SCRAMBLER[] = { const uint8_t SCRAMBLER[] = {
0x00U, 0x00U, 0x00U, 0x82U, 0xA0U, 0x88U, 0x8AU, 0x00U, 0xA2U, 0xA8U, 0x82U, 0x8AU, 0x82U, 0x02U, 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++) for (uint8_t i = 0U; i < NXDN_FSW_BYTES_LENGTH; i++)
errs += Utils::countBits8(syncBytes[i] ^ NXDN_FSW_BYTES[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) { if (errs >= MAX_SYNC_BYTES_ERRS) {
LogWarning(LOG_RF, "NXDN, possible sync word rejected, errs = %u, sync word = %02X %02X %02X", errs, LogWarning(LOG_RF, "NXDN, possible sync word rejected, errs = %u, sync word = %02X %02X %02X", errs,
syncBytes[0U], syncBytes[1U], syncBytes[2U]); 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); 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; bool ret = false;
if (rfct == RFChannelType::RCCH) { if (rfct == RFChannelType::RCCH) {
ret = m_control->process(fct, option, data, len); 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); ret = m_voice->process(fct, option, data, len);
break; break;
} }
if (m_ccRunning) {
m_ccHalted = false;
}
} else {
if (m_ccRunning) {
m_ccHalted = false;
}
} }
return ret; return ret;

@ -138,8 +138,9 @@ bool ControlSignaling::process(FuncChannelType::E fct, ChOption::E option, uint8
channel::CAC cac; channel::CAC cac;
bool validCAC = cac.decode(data + 2U, (fct == FuncChannelType::CAC_INBOUND_LONG)); 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; return false;
}
if (validCAC) { if (validCAC) {
uint8_t ran = cac.getRAN(); uint8_t ran = cac.getRAN();
@ -367,7 +368,7 @@ void ControlSignaling::writeRF_Message(RCCH* rcch, bool noNetwork, bool imm)
channel::LICH lich; channel::LICH lich;
lich.setRFCT(RFChannelType::RCCH); lich.setRFCT(RFChannelType::RCCH);
lich.setFCT(FuncChannelType::CAC_OUTBOUND); lich.setFCT(FuncChannelType::CAC_OUTBOUND);
lich.setOption(ChOption::DATA_COMMON); lich.setOption(ChOption::DATA_NORMAL);
lich.setOutbound(true); lich.setOutbound(true);
lich.encode(data + 2U); lich.encode(data + 2U);
@ -379,7 +380,7 @@ void ControlSignaling::writeRF_Message(RCCH* rcch, bool noNetwork, bool imm)
// generate the CAC // generate the CAC
channel::CAC cac; channel::CAC cac;
cac.setRAN(m_nxdn->m_ran); cac.setRAN(m_nxdn->m_ran);
cac.setStructure(ChStructure::SR_SINGLE); cac.setStructure(ChStructure::SR_RCCH_SINGLE);
cac.setData(buffer); cac.setData(buffer);
cac.encode(data + 2U); cac.encode(data + 2U);
@ -592,7 +593,7 @@ bool ControlSignaling::writeRF_Message_Grant(uint32_t srcId, uint32_t dstId, uin
req["dstId"].set<uint32_t>(dstId); req["dstId"].set<uint32_t>(dstId);
int ret = RESTClient::send(voiceChData.address(), voiceChData.port(), voiceChData.password(), 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) { 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); ::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); m_nxdn->m_affiliations.releaseGrant(dstId, false);

Loading…
Cancel
Save

Powered by TurnKey Linux.