diff --git a/src/common/nxdn/NXDNDefines.h b/src/common/nxdn/NXDNDefines.h
index e77f22c9..3317af59 100644
--- a/src/common/nxdn/NXDNDefines.h
+++ b/src/common/nxdn/NXDNDefines.h
@@ -135,7 +135,7 @@ namespace nxdn
CAC_INBOUND_LONG = 1U, // Common Access Channel - Inbound Long
CAC_INBOUND_SHORT = 3U, // Common Access Channel - Inbound Short
- // Slow Associated Control Channel / User Data Channel
+ // Slow Associated Control Channel / User Specific Channel
USC_SACCH_NS = 0U, //
USC_UDCH = 1U, //
USC_SACCH_SS = 2U, //
diff --git a/src/common/nxdn/SiteData.h b/src/common/nxdn/SiteData.h
index e108a515..64bfb0c7 100644
--- a/src/common/nxdn/SiteData.h
+++ b/src/common/nxdn/SiteData.h
@@ -30,7 +30,8 @@ namespace nxdn
m_locId(1U),
m_channelId(1U),
m_channelNo(1U),
- m_serviceClass(defines::SiteInformation1::VOICE_CALL_SVC | defines::SiteInformation1::DATA_CALL_SVC),
+ m_siteInfo1(defines::SiteInformation1::VOICE_CALL_SVC | defines::SiteInformation1::DATA_CALL_SVC),
+ m_siteInfo2(0U),
m_isAdjSite(false),
m_callsign("CHANGEME"),
m_requireReg(false),
@@ -42,13 +43,15 @@ namespace nxdn
/// NXDN Location ID.
/// Channel ID.
/// Channel Number.
- /// Service class.
+ /// Site Information 1.
+ /// Site Information 2.
///
- SiteData(uint32_t locId, uint8_t channelId, uint32_t channelNo, uint8_t serviceClass, bool requireReq) :
+ SiteData(uint32_t locId, uint8_t channelId, uint32_t channelNo, uint8_t siteInfo1, uint8_t siteInfo2, bool requireReq) :
m_locId(locId),
m_channelId(channelId),
m_channelNo(channelNo),
- m_serviceClass(defines::SiteInformation1::VOICE_CALL_SVC | defines::SiteInformation1::DATA_CALL_SVC),
+ m_siteInfo1(defines::SiteInformation1::VOICE_CALL_SVC | defines::SiteInformation1::DATA_CALL_SVC),
+ m_siteInfo2(0U),
m_isAdjSite(false),
m_callsign("CHANGEME"),
m_requireReg(requireReq),
@@ -69,7 +72,8 @@ namespace nxdn
m_channelNo = 1023U;
}
- m_serviceClass = serviceClass;
+ m_siteInfo1 = siteInfo1;
+ m_siteInfo2 = siteInfo2;
}
/// Helper to set the site callsign.
@@ -90,8 +94,9 @@ namespace nxdn
/// NXDN Location ID.
/// Channel ID.
/// Channel Number.
- /// Service class.
- void setAdjSite(uint32_t locId, uint8_t rfssId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, uint8_t serviceClass)
+ /// Site Information 1.
+ /// Site Information 2.
+ void setAdjSite(uint32_t locId, uint8_t rfssId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, uint8_t siteInfo1, uint8_t siteInfo2)
{
if (m_locId > 0xFFFFFFU)
m_locId = 0xFFFFFFU;
@@ -113,7 +118,8 @@ namespace nxdn
m_channelId = channelId;
m_channelNo = channelNo;
- m_serviceClass = serviceClass;
+ m_siteInfo1 = siteInfo1;
+ m_siteInfo2 = siteInfo2;
m_isAdjSite = true;
@@ -132,7 +138,8 @@ namespace nxdn
m_channelId = data.m_channelId;
m_channelNo = data.m_channelNo;
- m_serviceClass = data.m_serviceClass;
+ m_siteInfo1 = data.m_siteInfo1;
+ m_siteInfo2 = data.m_siteInfo2;
m_isAdjSite = data.m_isAdjSite;
@@ -153,8 +160,10 @@ namespace nxdn
__READONLY_PROPERTY_PLAIN(uint8_t, channelId);
/// Channel number.
__READONLY_PROPERTY_PLAIN(uint32_t, channelNo);
- /// Service class.
- __READONLY_PROPERTY_PLAIN(uint8_t, serviceClass);
+ /// Site Information 1.
+ __READONLY_PROPERTY_PLAIN(uint8_t, siteInfo1);
+ /// Site Information 2.
+ __READONLY_PROPERTY_PLAIN(uint8_t, siteInfo2);
/// Flag indicating whether this site data is for an adjacent site.
__READONLY_PROPERTY_PLAIN(bool, isAdjSite);
/// Callsign.
diff --git a/src/common/nxdn/channel/CAC.cpp b/src/common/nxdn/channel/CAC.cpp
index c9c45bd3..766d3770 100644
--- a/src/common/nxdn/channel/CAC.cpp
+++ b/src/common/nxdn/channel/CAC.cpp
@@ -164,8 +164,9 @@ CAC& CAC::operator=(const CAC& data)
/// Decode a common access channel.
///
///
+///
/// True, if CAC was decoded, otherwise false.
-bool CAC::decode(const uint8_t* data)
+bool CAC::decode(const uint8_t* data, bool longInbound)
{
assert(data != nullptr);
@@ -183,50 +184,113 @@ bool CAC::decode(const uint8_t* data)
Utils::dump(2U, "CAC::decode(), CAC Raw", buffer, NXDN_CAC_IN_FEC_LENGTH_BYTES);
#endif
- // TODO TODO -- Long CAC Puncturing
+ if (longInbound) {
+ // depuncture
+ uint8_t puncture[324U];
+ ::memset(puncture, 0x00U, 324U);
- // decode convolution
- edac::Convolution conv;
- conv.start();
+ uint32_t n = 0U, index = 0U;
+ for (uint32_t i = 0U; i < NXDN_CAC_IN_FEC_LENGTH_BITS; i++) {
+ if (n == PUNCTURE_LIST_LONG_IN[index]) {
+ puncture[n++] = 1U;
+ index++;
+ }
+
+ bool b = READ_BIT(buffer, i);
+ puncture[n++] = b ? 2U : 0U;
+ }
+
+ for (uint32_t i = 0U; i < 8U; i++) {
+ puncture[n++] = 0U;
+ }
+
+ // decode convolution
+ edac::Convolution conv;
+ conv.start();
+
+ n = 0U;
+ for (uint32_t i = 0U; i < (NXDN_CAC_LONG_CRC_LENGTH_BITS + 4U); i++) {
+ uint8_t s0 = puncture[n++];
+ uint8_t s1 = puncture[n++];
+
+ if (!conv.decode(s0, s1)) {
+ LogError(LOG_NXDN, "CAC::decode(), failed to decode convolution");
+ return false;
+ }
+ }
+
+ conv.chainback(m_data, NXDN_CAC_LONG_CRC_LENGTH_BITS);
- uint32_t 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++];
+#if DEBUG_NXDN_CAC
+ Utils::dump(2U, "Decoded CAC", m_data, (NXDN_CAC_LONG_CRC_LENGTH_BITS / 8U) + 1U);
+#endif
- if (!conv.decode(s0, s1)) {
- LogError(LOG_NXDN, "CAC::decode(), failed to decode convolution");
+ // 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");
return false;
}
+
+ // store recieved CRC-16
+ uint8_t crc[2U];
+ ::memset(crc, 0x00U, 2U);
+
+ m_ran = m_data[0U] & 0x3FU;
+ m_structure = (ChStructure::E)((m_data[0U] >> 6) & 0x03U);
+
+ uint32_t offset = NXDN_CAC_LONG_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);
}
+ else {
+ // decode convolution
+ edac::Convolution conv;
+ conv.start();
+
+ uint32_t 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++];
+
+ if (!conv.decode(s0, s1)) {
+ LogError(LOG_NXDN, "CAC::decode(), failed to decode convolution");
+ return false;
+ }
+ }
- conv.chainback(m_data, NXDN_CAC_SHORT_CRC_LENGTH_BITS);
+ conv.chainback(m_data, NXDN_CAC_SHORT_CRC_LENGTH_BITS);
#if DEBUG_NXDN_CAC
- Utils::dump(2U, "Decoded CAC", m_data, (NXDN_CAC_SHORT_CRC_LENGTH_BITS / 8U) + 1U);
+ Utils::dump(2U, "Decoded CAC", m_data, (NXDN_CAC_SHORT_CRC_LENGTH_BITS / 8U) + 1U);
#endif
- // 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");
- return false;
- }
+ // 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");
+ return false;
+ }
- // store recieved CRC-16
- uint8_t crc[2U];
- ::memset(crc, 0x00U, 2U);
+ // store recieved CRC-16
+ uint8_t crc[2U];
+ ::memset(crc, 0x00U, 2U);
- m_ran = m_data[0U] & 0x3FU;
- m_structure = (ChStructure::E)((m_data[0U] >> 6) & 0x03U);
+ m_ran = m_data[0U] & 0x3FU;
+ m_structure = (ChStructure::E)((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);
- }
+ 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_rxCRC = (crc[0U] << 8) | (crc[1U] << 0);
+ }
#if DEBUG_NXDN_CAC
Utils::dump(2U, "Raw CAC Buffer", m_data, NXDN_CAC_FEC_LENGTH_BYTES);
diff --git a/src/common/nxdn/channel/CAC.h b/src/common/nxdn/channel/CAC.h
index f5550f74..1a53f99b 100644
--- a/src/common/nxdn/channel/CAC.h
+++ b/src/common/nxdn/channel/CAC.h
@@ -38,7 +38,7 @@ namespace nxdn
CAC& operator=(const CAC& data);
/// Decode a common access channel.
- bool decode(const uint8_t* data);
+ bool decode(const uint8_t* data, bool longInbound = false);
/// Encode a common access channel.
void encode(uint8_t* data) const;
diff --git a/src/common/nxdn/lc/rcch/MESSAGE_TYPE_SITE_INFO.cpp b/src/common/nxdn/lc/rcch/MESSAGE_TYPE_SITE_INFO.cpp
index 882d8b0f..f4fe8ef8 100644
--- a/src/common/nxdn/lc/rcch/MESSAGE_TYPE_SITE_INFO.cpp
+++ b/src/common/nxdn/lc/rcch/MESSAGE_TYPE_SITE_INFO.cpp
@@ -63,6 +63,10 @@ void MESSAGE_TYPE_SITE_INFO::encode(uint8_t* data, uint32_t length, uint32_t off
{
assert(data != nullptr);
+ uint8_t siteInfo2 = m_siteData.siteInfo2();
+ if ((siteInfo2 & SiteInformation2::IP_NETWORK) == SiteInformation2::IP_NETWORK)
+ siteInfo2 &= ~SiteInformation2::IP_NETWORK; // clear the IP_NETWORK bit -- that will be provided by netActive()
+
uint8_t rcch[NXDN_RCCH_LC_LENGTH_BYTES + 4U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
@@ -76,16 +80,19 @@ void MESSAGE_TYPE_SITE_INFO::encode(uint8_t* data, uint32_t length, uint32_t off
((m_ccchMultiCnt & 0x07U) << 4) + // ... - Number of Multipurpose Frames
((m_rcchIterateCnt & 0x0FU) << 0); // ... - Number of Iteration
- rcch[6U] = m_siteData.serviceClass(); // Service Information
- rcch[7U] = (m_siteData.netActive() ? SiteInformation2::IP_NETWORK : 0x00U); // ...
+ rcch[6U] = m_siteData.siteInfo1(); // Site Information 1
+ rcch[7U] = (m_siteData.netActive() ? SiteInformation2::IP_NETWORK : 0x00U) + // Site Information 2
+ siteInfo2;
// bryanb: this is currently fixed -- maybe dynamic in the future
rcch[8U] = 0U; // Restriction Information - No access restriction / No cycle restriction
rcch[9U] = 0U; // ... - No group restriction / No Location Registration Restriction
- rcch[10U] = (!m_siteData.netActive() ? 0x01U : 0x00U); // ... - No group ratio restriction / No delay time extension / ISO
+ //rcch[10U] = (!m_siteData.netActive() ? 0x01U : 0x00U); // ... - No group ratio restriction / No delay time extension / ISO
+ rcch[10U] = 0U;
// bryanb: this is currently fixed -- maybe dynamic in the future
- rcch[11U] = ChAccessBase::FREQ_SYS_DEFINED << 2; // Channel Access Information - Channel Version / Sys Defined Step / Sys Defined Base Freq
+ //rcch[11U] = ChAccessBase::FREQ_SYS_DEFINED << 2; // Channel Access Information - Channel Version / Sys Defined Step / Sys Defined Base Freq
+ rcch[11U] = 0U;
rcch[14U] = 1U; // Version
diff --git a/src/common/nxdn/lc/rcch/MESSAGE_TYPE_SRV_INFO.cpp b/src/common/nxdn/lc/rcch/MESSAGE_TYPE_SRV_INFO.cpp
index 461df229..224ab90a 100644
--- a/src/common/nxdn/lc/rcch/MESSAGE_TYPE_SRV_INFO.cpp
+++ b/src/common/nxdn/lc/rcch/MESSAGE_TYPE_SRV_INFO.cpp
@@ -58,14 +58,19 @@ void MESSAGE_TYPE_SRV_INFO::encode(uint8_t* data, uint32_t length, uint32_t offs
{
assert(data != nullptr);
+ uint8_t siteInfo2 = m_siteData.siteInfo2();
+ if ((siteInfo2 & SiteInformation2::IP_NETWORK) == SiteInformation2::IP_NETWORK)
+ siteInfo2 &= ~SiteInformation2::IP_NETWORK; // clear the IP_NETWORK bit -- that will be provided by netActive()
+
uint8_t rcch[NXDN_RCCH_LC_LENGTH_BYTES + 4U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
rcch[1U] = (m_siteData.locId() >> 16) & 0xFFU; // Location ID
rcch[2U] = (m_siteData.locId() >> 8) & 0xFFU; // ...
rcch[3U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
- rcch[4U] = m_siteData.serviceClass(); // Service Information
- rcch[5U] = (m_siteData.netActive() ? SiteInformation2::IP_NETWORK : 0x00U); // ...
+ rcch[4U] = m_siteData.siteInfo1(); // Site Information 1
+ rcch[5U] = (m_siteData.netActive() ? SiteInformation2::IP_NETWORK : 0x00U) + // Site Information 2
+ siteInfo2;
// bryanb: this is currently fixed -- maybe dynamic in the future
rcch[8U] = 0U; // Restriction Information - No access restriction / No cycle restriction
diff --git a/src/host/nxdn/Control.cpp b/src/host/nxdn/Control.cpp
index 853542ff..0ce729aa 100644
--- a/src/host/nxdn/Control.cpp
+++ b/src/host/nxdn/Control.cpp
@@ -259,11 +259,12 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw
}
/*
- ** CC Service Class
+ ** CC Site Info
*/
- uint8_t serviceClass = SiteInformation1::VOICE_CALL_SVC | SiteInformation1::DATA_CALL_SVC;
+ uint8_t siteInfo1 = SiteInformation1::VOICE_CALL_SVC | SiteInformation1::DATA_CALL_SVC;
+ uint8_t siteInfo2 = SiteInformation2::SHORT_DATA_CALL_SVC;
if (m_enableControl) {
- serviceClass |= SiteInformation1::GRP_REG_SVC;
+ siteInfo1 |= SiteInformation1::LOC_REG_SVC;//| SiteInformation1::GRP_REG_SVC;
}
/*
@@ -274,7 +275,7 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw
locId = (locId << 10) + (sysId & 0x3FFU);
locId = (locId << 12) + (siteId & 0xFFFU);
- m_siteData = SiteData(locId, channelId, (channelNo & 0x3FF), serviceClass, false);
+ m_siteData = SiteData(locId, channelId, (channelNo & 0x3FF), siteInfo1, siteInfo2, false);
m_siteData.setCallsign(cwCallsign);
m_controlChData = controlChData;
@@ -492,6 +493,14 @@ 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 3e0d4826..292bdea3 100644
--- a/src/host/nxdn/packet/ControlSignaling.cpp
+++ b/src/host/nxdn/packet/ControlSignaling.cpp
@@ -137,7 +137,7 @@ bool ControlSignaling::process(FuncChannelType::E fct, ChOption::E option, uint8
assert(data != nullptr);
channel::CAC cac;
- bool validCAC = cac.decode(data + 2U);
+ bool validCAC = cac.decode(data + 2U, (fct == FuncChannelType::CAC_INBOUND_LONG));
if (m_nxdn->m_rfState == RS_RF_LISTENING && !validCAC)
return false;