From b99ecefd6af71c1e716c8fbb929eb79a7749109a Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Sat, 24 Jun 2023 20:11:47 +0000 Subject: [PATCH] experimental alteration to handling modem TAG_LOST during an active call for DMR, P25 and NXDN, instead of immediately dropping the call stream holding the call in progress, this will likely require additional thought and implementation, but the intention is to correct odd behavior for fringe or silghtly weak signals which would cause strange call behavior; --- src/dmr/Slot.cpp | 102 +++++++++++++++++++++++++-------------- src/dmr/Slot.h | 2 + src/nxdn/Control.cpp | 82 +++++++++++++++++++++----------- src/nxdn/Control.h | 2 + src/p25/Control.cpp | 111 ++++++++++++++++++++++++++----------------- src/p25/Control.h | 2 + 6 files changed, 192 insertions(+), 109 deletions(-) diff --git a/src/dmr/Slot.cpp b/src/dmr/Slot.cpp index fbbdaca2..486e4c43 100644 --- a/src/dmr/Slot.cpp +++ b/src/dmr/Slot.cpp @@ -45,6 +45,12 @@ using namespace dmr::packet; #include #include +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +const uint8_t MAX_LOST_FRAMES = 4U; + // --------------------------------------------------------------------------- // Static Class Members // --------------------------------------------------------------------------- @@ -152,6 +158,7 @@ Slot::Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSiz m_aveRSSI(0U), m_rssiCount(0U), m_silenceThreshold(DEFAULT_SILENCE_THRESHOLD), + m_frameLossCnt(0U), m_ccSeq(0U), m_ccRunning(false), m_ccPrevRunning(false), @@ -195,52 +202,75 @@ bool Slot::processFrame(uint8_t *data, uint32_t len) { assert(data != nullptr); - if (data[0U] == modem::TAG_LOST && m_rfState == RS_RF_AUDIO) { - if (m_rssi != 0U) { - ::ActivityLog("DMR", true, "Slot %u RF voice transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", - m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); - } - else { - ::ActivityLog("DMR", true, "Slot %u RF voice transmission lost, %.1f seconds, BER: %.1f%%", - m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits)); - } + if (data[0U] == modem::TAG_LOST) { + if (m_frameLossCnt > MAX_LOST_FRAMES) { + m_frameLossCnt = 0U; + + if (m_rfState == RS_RF_AUDIO) { + if (m_rssi != 0U) { + ::ActivityLog("DMR", true, "Slot %u RF voice transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", + m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); + } + else { + ::ActivityLog("DMR", true, "Slot %u RF voice transmission lost, %.1f seconds, BER: %.1f%%", + m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits)); + } + + LogMessage(LOG_RF, "DMR Slot %u, total frames: %d, total bits: %d, errors: %d, BER: %.4f%%", + m_slotNo, m_rfFrames, m_rfBits, m_rfErrs, float(m_rfErrs * 100U) / float(m_rfBits)); + + // release trunked grant (if necessary) + Slot *m_tscc = m_dmr->getTSCCSlot(); + if (m_tscc != nullptr) { + if (m_tscc->m_enableTSCC && m_rfLC != nullptr) { + m_tscc->m_affiliations->releaseGrant(m_rfLC->getDstId(), false); + } + } + + if (!m_tscc->m_enableTSCC) { + notifyCC_ReleaseGrant(m_rfLC->getDstId()); + } - LogMessage(LOG_RF, "DMR Slot %u, total frames: %d, total bits: %d, errors: %d, BER: %.4f%%", - m_slotNo, m_rfFrames, m_rfBits, m_rfErrs, float(m_rfErrs * 100U) / float(m_rfBits)); + if (m_rfTimeout) { + writeEndRF(); + return false; + } + else { + writeEndRF(true); + return true; + } + } - // release trunked grant (if necessary) - Slot *m_tscc = m_dmr->getTSCCSlot(); - if (m_tscc != nullptr) { - if (m_tscc->m_enableTSCC && m_rfLC != nullptr) { - m_tscc->m_affiliations->releaseGrant(m_rfLC->getDstId(), false); + if (m_rfState == RS_RF_DATA) { + ::ActivityLog("DMR", true, "Slot %u, RF data transmission lost", m_slotNo); + writeEndRF(); + return false; } - } - if (!m_tscc->m_enableTSCC) { - notifyCC_ReleaseGrant(m_rfLC->getDstId()); - } + m_rfState = RS_RF_LISTENING; + + m_rfLastDstId = 0U; + m_rfTGHang.stop(); - if (m_rfTimeout) { - writeEndRF(); return false; } else { - writeEndRF(true); - return true; - } - } + // increment the frame loss count by one for audio or data; otherwise drop + // packets + if (m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA) { + ++m_frameLossCnt; + } + else { + // drop normally + m_frameLossCnt = 0U; + m_rfState = RS_RF_LISTENING; - if (data[0U] == modem::TAG_LOST && m_rfState == RS_RF_DATA) { - ::ActivityLog("DMR", true, "Slot %u, RF data transmission lost", m_slotNo); - writeEndRF(); - return false; - } + m_rfLastDstId = 0U; + m_rfTGHang.stop(); - if (data[0U] == modem::TAG_LOST) { - m_rfState = RS_RF_LISTENING; - m_rfLastDstId = 0U; - m_rfTGHang.stop(); - return false; + return false; + } + } } // Have we got RSSI bytes on the end? diff --git a/src/dmr/Slot.h b/src/dmr/Slot.h index 2134ab38..025d880f 100644 --- a/src/dmr/Slot.h +++ b/src/dmr/Slot.h @@ -194,6 +194,8 @@ namespace dmr uint32_t m_silenceThreshold; + uint8_t m_frameLossCnt; + uint8_t m_ccSeq; bool m_ccRunning; bool m_ccPrevRunning; diff --git a/src/nxdn/Control.cpp b/src/nxdn/Control.cpp index 990615da..d2806875 100644 --- a/src/nxdn/Control.cpp +++ b/src/nxdn/Control.cpp @@ -58,6 +58,8 @@ using namespace nxdn::packet; const uint8_t MAX_SYNC_BYTES_ERRS = 0U; +const uint8_t MAX_LOST_FRAMES = 4U; + const uint8_t SCRAMBLER[] = { 0x00U, 0x00U, 0x00U, 0x82U, 0xA0U, 0x88U, 0x8AU, 0x00U, 0xA2U, 0xA8U, 0x82U, 0x8AU, 0x82U, 0x02U, 0x20U, 0x08U, 0x8AU, 0x20U, 0xAAU, 0xA2U, 0x82U, 0x08U, 0x22U, 0x8AU, 0xAAU, 0x08U, 0x28U, 0x88U, @@ -130,6 +132,7 @@ Control::Control(bool authoritative, uint32_t ran, uint32_t callHang, uint32_t q m_netTimeout(1000U, timeout), m_networkWatchdog(1000U, 0U, 1500U), m_ccPacketInterval(1000U, 0U, 80U), + m_frameLossCnt(0U), m_ccFrameCnt(0U), m_ccSeq(0U), m_siteData(), @@ -355,44 +358,65 @@ bool Control::processFrame(uint8_t* data, uint32_t len) { assert(data != nullptr); - uint8_t type = data[0U]; bool sync = data[1U] == 0x01U; - if (type == modem::TAG_LOST && m_rfState == RS_RF_AUDIO) { - if (m_rssi != 0U) { - ::ActivityLog("NXDN", true, "transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", - float(m_voice->m_rfFrames) / 12.5F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); + if (data[0U] == modem::TAG_LOST) { + if (m_frameLossCnt > MAX_LOST_FRAMES) { + m_frameLossCnt = 0U; + + if (m_rfState == RS_RF_AUDIO) { + if (m_rssi != 0U) { + ::ActivityLog("NXDN", true, "transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", + float(m_voice->m_rfFrames) / 12.5F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); + } + else { + ::ActivityLog("NXDN", true, "transmission lost, %.1f seconds, BER: %.1f%%", + float(m_voice->m_rfFrames) / 12.5F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits)); + } + + LogMessage(LOG_RF, "NXDN, " NXDN_RTCH_MSG_TYPE_TX_REL ", total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%", + m_voice->m_rfFrames, m_voice->m_rfBits, m_voice->m_rfUndecodableLC, m_voice->m_rfErrs, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits)); + + m_affiliations.releaseGrant(m_rfLC.getDstId(), false); + if (!m_control) { + notifyCC_ReleaseGrant(m_rfLC.getDstId()); + } + + writeEndRF(); + return false; + } + + if (m_rfState == RS_RF_DATA) { + writeEndRF(); + return false; + } + + m_rfState = RS_RF_LISTENING; + + m_rfMask = 0x00U; + m_rfLC.reset(); + + return false; } else { - ::ActivityLog("NXDN", true, "transmission lost, %.1f seconds, BER: %.1f%%", - float(m_voice->m_rfFrames) / 12.5F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits)); - } + // increment the frame loss count by one for audio or data; otherwise drop + // packets + if (m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA) { + ++m_frameLossCnt; + } + else { + m_frameLossCnt = 0U; + m_rfState = RS_RF_LISTENING; - LogMessage(LOG_RF, "NXDN, " NXDN_RTCH_MSG_TYPE_TX_REL ", total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%", - m_voice->m_rfFrames, m_voice->m_rfBits, m_voice->m_rfUndecodableLC, m_voice->m_rfErrs, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits)); + m_rfMask = 0x00U; + m_rfLC.reset(); - m_affiliations.releaseGrant(m_rfLC.getDstId(), false); - if (!m_control) { - notifyCC_ReleaseGrant(m_rfLC.getDstId()); + return false; + } } - - writeEndRF(); - return false; } - if (type == modem::TAG_LOST && m_rfState == RS_RF_DATA) { - writeEndRF(); - return false; - } - - if (type == modem::TAG_LOST) { - m_rfState = RS_RF_LISTENING; - m_rfMask = 0x00U; - m_rfLC.reset(); - return false; - } - - // Have we got RSSI bytes on the end? + // have we got RSSI bytes on the end? if (len == (NXDN_FRAME_LENGTH_BYTES + 4U)) { uint16_t raw = 0U; raw |= (data[50U] << 8) & 0xFF00U; diff --git a/src/nxdn/Control.h b/src/nxdn/Control.h index 98d11ffa..07b4e19e 100644 --- a/src/nxdn/Control.h +++ b/src/nxdn/Control.h @@ -188,6 +188,8 @@ namespace nxdn Timer m_ccPacketInterval; + uint8_t m_frameLossCnt; + uint8_t m_ccFrameCnt; uint8_t m_ccSeq; diff --git a/src/p25/Control.cpp b/src/p25/Control.cpp index e4b0d148..da881a21 100644 --- a/src/p25/Control.cpp +++ b/src/p25/Control.cpp @@ -58,6 +58,8 @@ const uint8_t MAX_SYNC_BYTES_ERRS = 4U; const uint32_t TSBK_PCH_CCH_CNT = 6U; const uint32_t MAX_PREAMBLE_TDU_CNT = 64U; +const uint8_t MAX_LOST_FRAMES = 4U; + // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- @@ -130,6 +132,7 @@ Control::Control(bool authoritative, uint32_t nac, uint32_t callHang, uint32_t q m_ccPacketInterval(1000U, 0U, 10U), m_hangCount(3U * 8U), m_tduPreambleCount(8U), + m_frameLossCnt(0U), m_ccFrameCnt(0U), m_ccSeq(0U), m_nid(nac), @@ -440,66 +443,86 @@ bool Control::processFrame(uint8_t* data, uint32_t len) bool sync = data[1U] == 0x01U; - if (data[0U] == modem::TAG_LOST && m_rfState == RS_RF_AUDIO) { - if (m_rssi != 0U) { - ::ActivityLog("P25", true, "transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", - float(m_voice->m_rfFrames) / 5.56F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); - } - else { - ::ActivityLog("P25", true, "transmission lost, %.1f seconds, BER: %.1f%%", - float(m_voice->m_rfFrames) / 5.56F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits)); - } + if (data[0U] == modem::TAG_LOST) { + if (m_frameLossCnt > MAX_LOST_FRAMES) { + m_frameLossCnt = 0U; - LogMessage(LOG_RF, P25_TDU_STR ", total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%", - m_voice->m_rfFrames, m_voice->m_rfBits, m_voice->m_rfUndecodableLC, m_voice->m_rfErrs, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits)); + if (m_rfState == RS_RF_AUDIO) { + if (m_rssi != 0U) { + ::ActivityLog("P25", true, "transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", + float(m_voice->m_rfFrames) / 5.56F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); + } + else { + ::ActivityLog("P25", true, "transmission lost, %.1f seconds, BER: %.1f%%", + float(m_voice->m_rfFrames) / 5.56F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits)); + } - m_affiliations.releaseGrant(m_voice->m_rfLC.getDstId(), false); - if (!m_control) { - notifyCC_ReleaseGrant(m_voice->m_rfLC.getDstId()); - } - m_trunk->writeNet_TSDU_Call_Term(m_voice->m_rfLC.getSrcId(), m_voice->m_rfLC.getDstId()); + LogMessage(LOG_RF, P25_TDU_STR ", total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%", + m_voice->m_rfFrames, m_voice->m_rfBits, m_voice->m_rfUndecodableLC, m_voice->m_rfErrs, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits)); - writeRF_TDU(false); - m_voice->m_lastDUID = P25_DUID_TDU; - m_voice->writeNetwork(data + 2U, P25_DUID_TDU); + m_affiliations.releaseGrant(m_voice->m_rfLC.getDstId(), false); + if (!m_control) { + notifyCC_ReleaseGrant(m_voice->m_rfLC.getDstId()); + } + m_trunk->writeNet_TSDU_Call_Term(m_voice->m_rfLC.getSrcId(), m_voice->m_rfLC.getDstId()); - m_rfState = RS_RF_LISTENING; - m_rfLastDstId = 0U; - m_rfTGHang.stop(); + writeRF_TDU(false); + m_voice->m_lastDUID = P25_DUID_TDU; + m_voice->writeNetwork(data + 2U, P25_DUID_TDU); - m_tailOnIdle = true; + m_rfState = RS_RF_LISTENING; + m_rfLastDstId = 0U; + m_rfTGHang.stop(); - m_rfTimeout.stop(); - m_txQueue.clear(); + m_tailOnIdle = true; - if (m_network != nullptr) - m_network->resetP25(); + m_rfTimeout.stop(); + m_txQueue.clear(); - return false; - } + if (m_network != nullptr) + m_network->resetP25(); - if (data[0U] == modem::TAG_LOST && m_rfState == RS_RF_DATA) { - m_rfState = RS_RF_LISTENING; - m_rfLastDstId = 0U; - m_rfTGHang.stop(); + return false; + } - m_tailOnIdle = true; + if (m_rfState == RS_RF_DATA) { + m_rfState = RS_RF_LISTENING; + m_rfLastDstId = 0U; + m_rfTGHang.stop(); - m_data->resetRF(); + m_tailOnIdle = true; - m_rfTimeout.stop(); - m_txQueue.clear(); + m_data->resetRF(); - return false; - } + m_rfTimeout.stop(); + m_txQueue.clear(); - if (data[0U] == modem::TAG_LOST) { - m_rfState = RS_RF_LISTENING; + return false; + } - m_voice->resetRF(); - m_data->resetRF(); + m_rfState = RS_RF_LISTENING; - return false; + m_voice->resetRF(); + m_data->resetRF(); + + return false; + } + else { + // increment the frame loss count by one for audio or data; otherwise drop + // packets + if (m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA) { + ++m_frameLossCnt; + } + else { + m_frameLossCnt = 0U; + m_rfState = RS_RF_LISTENING; + + m_voice->resetRF(); + m_data->resetRF(); + + return false; + } + } } if (!sync && m_rfState == RS_RF_LISTENING) { diff --git a/src/p25/Control.h b/src/p25/Control.h index 16e34352..6f066186 100644 --- a/src/p25/Control.h +++ b/src/p25/Control.h @@ -206,6 +206,8 @@ namespace p25 uint32_t m_hangCount; uint32_t m_tduPreambleCount; + uint8_t m_frameLossCnt; + uint8_t m_ccFrameCnt; uint8_t m_ccSeq;