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;