implement CAC long puncturing for NXDN; correct issues with NXDN site information data;

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

@ -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, //

@ -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
/// <param name="locId">NXDN Location ID.</param>
/// <param name="channelId">Channel ID.</param>
/// <param name="channelNo">Channel Number.</param>
/// <param name="serviceClass">Service class.</param>
/// <param name="siteInfo1">Site Information 1.</param>
/// <param name="siteInfo2">Site Information 2.</param>
/// <param name="requireReg"></param>
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;
}
/// <summary>Helper to set the site callsign.</summary>
@ -90,8 +94,9 @@ namespace nxdn
/// <param name="locId">NXDN Location ID.</param>
/// <param name="channelId">Channel ID.</param>
/// <param name="channelNo">Channel Number.</param>
/// <param name="serviceClass">Service class.</param>
void setAdjSite(uint32_t locId, uint8_t rfssId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, uint8_t serviceClass)
/// <param name="siteInfo1">Site Information 1.</param>
/// <param name="siteInfo2">Site Information 2.</param>
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);
/// <summary>Channel number.</summary>
__READONLY_PROPERTY_PLAIN(uint32_t, channelNo);
/// <summary>Service class.</summary>
__READONLY_PROPERTY_PLAIN(uint8_t, serviceClass);
/// <summary>Site Information 1.</summary>
__READONLY_PROPERTY_PLAIN(uint8_t, siteInfo1);
/// <summary>Site Information 2.</summary>
__READONLY_PROPERTY_PLAIN(uint8_t, siteInfo2);
/// <summary>Flag indicating whether this site data is for an adjacent site.</summary>
__READONLY_PROPERTY_PLAIN(bool, isAdjSite);
/// <summary>Callsign.</summary>

@ -164,8 +164,9 @@ CAC& CAC::operator=(const CAC& data)
/// Decode a common access channel.
/// </summary>
/// <param name="data"></param>
/// <param name="longInbound"></param>
/// <returns>True, if CAC was decoded, otherwise false.</returns>
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);

@ -38,7 +38,7 @@ namespace nxdn
CAC& operator=(const CAC& data);
/// <summary>Decode a common access channel.</summary>
bool decode(const uint8_t* data);
bool decode(const uint8_t* data, bool longInbound = false);
/// <summary>Encode a common access channel.</summary>
void encode(uint8_t* data) const;

@ -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

@ -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

@ -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;

@ -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;

Loading…
Cancel
Save

Powered by TurnKey Linux.