diff --git a/src/dmr/Slot.cpp b/src/dmr/Slot.cpp index 9c0962a3..65405dbc 100644 --- a/src/dmr/Slot.cpp +++ b/src/dmr/Slot.cpp @@ -49,7 +49,7 @@ using namespace dmr::packet; // Constants // --------------------------------------------------------------------------- -const uint8_t MAX_LOST_FRAMES = 4U; +const uint8_t MAX_LOST_FRAMES = 2U; // --------------------------------------------------------------------------- // Static Class Members @@ -206,51 +206,7 @@ bool Slot::processFrame(uint8_t *data, uint32_t len) 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()); - } - - if (m_rfTimeout) { - writeEndRF(); - return false; - } - else { - writeEndRF(true); - return true; - } - } - - if (m_rfState == RS_RF_DATA) { - ::ActivityLog("DMR", true, "Slot %u, RF data transmission lost", m_slotNo); - writeEndRF(); - return false; - } - - m_rfState = RS_RF_LISTENING; - - m_rfLastDstId = 0U; - m_rfTGHang.stop(); + processFrameLoss(); return false; } @@ -341,6 +297,7 @@ bool Slot::processFrame(uint8_t *data, uint32_t len) case DT_VOICE_PI_HEADER: return m_voice->process(data, len); case DT_TERMINATOR_WITH_LC: + m_frameLossCnt = 0U; case DT_DATA_HEADER: case DT_RATE_12_DATA: case DT_RATE_34_DATA: @@ -603,6 +560,12 @@ void Slot::clock() m_rfState = RS_RF_LISTENING; } + + if (m_frameLossCnt > 0U && m_rfState == RS_RF_LISTENING) + m_frameLossCnt = 0U; + if (m_frameLossCnt >= MAX_LOST_FRAMES && (m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA)) { + processFrameLoss(); + } } /// @@ -938,6 +901,55 @@ void Slot::addFrame(const uint8_t *data, bool net, bool imm) m_txQueue.addData(data, len); } +/// +/// Helper to process loss of frame stream from modem. +/// +void Slot::processFrameLoss() +{ + 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, loss count: %u", + m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount, m_frameLossCnt); + } + else { + ::ActivityLog("DMR", true, "Slot %u RF voice transmission lost, %.1f seconds, BER: %.1f%%, loss count: %u", + m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits), m_frameLossCnt); + } + + 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()); + } + + if (m_rfTimeout) { + writeEndRF(); + } + else { + writeEndRF(true); + } + } + + if (m_rfState == RS_RF_DATA) { + ::ActivityLog("DMR", true, "Slot %u, RF data transmission lost", m_slotNo); + writeEndRF(); + } + + m_rfState = RS_RF_LISTENING; + + m_rfLastDstId = 0U; + m_rfTGHang.stop(); +} + /// /// Helper to send a REST API request to the CC to release a channel grant at the end of a call. /// diff --git a/src/dmr/Slot.h b/src/dmr/Slot.h index 025d880f..8a715e9d 100644 --- a/src/dmr/Slot.h +++ b/src/dmr/Slot.h @@ -268,6 +268,9 @@ namespace dmr /// Add data frame to the data ring buffer. void addFrame(const uint8_t* data, bool net = false, bool imm = false); + /// Helper to process loss of frame stream from modem. + void processFrameLoss(); + /// Helper to send a REST API request to the CC to release a channel grant at the end of a call. void notifyCC_ReleaseGrant(uint32_t dstId); /// Helper to send a REST API request to the CC to "touch" a channel grant to refresh grant timers. diff --git a/src/nxdn/Control.cpp b/src/nxdn/Control.cpp index 479048b8..588d29f7 100644 --- a/src/nxdn/Control.cpp +++ b/src/nxdn/Control.cpp @@ -365,37 +365,7 @@ bool Control::processFrame(uint8_t* data, uint32_t len) 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(); + processFrameLoss(); return false; } @@ -676,6 +646,12 @@ void Control::clock(uint32_t ms) m_rfState = RS_RF_LISTENING; } + if (m_frameLossCnt > 0U && m_rfState == RS_RF_LISTENING) + m_frameLossCnt = 0U; + if (m_frameLossCnt >= MAX_LOST_FRAMES && (m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA)) { + processFrameLoss(); + } + // clock data and trunking if (m_trunk != nullptr) { m_trunk->clock(ms); @@ -915,6 +891,42 @@ void Control::processNetwork() } } +/// +/// Helper to process loss of frame stream from modem. +/// +void Control::processFrameLoss() +{ + if (m_rfState == RS_RF_AUDIO) { + if (m_rssi != 0U) { + ::ActivityLog("NXDN", true, "transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm, loss count: %u", + 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, m_frameLossCnt); + } + else { + ::ActivityLog("NXDN", true, "transmission lost, %.1f seconds, BER: %.1f%%, loss count: %u", + float(m_voice->m_rfFrames) / 12.5F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits), m_frameLossCnt); + } + + 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(); + } + + if (m_rfState == RS_RF_DATA) { + writeEndRF(); + } + + m_rfState = RS_RF_LISTENING; + + m_rfMask = 0x00U; + m_rfLC.reset(); +} + /// /// Helper to send a REST API request to the CC to release a channel grant at the end of a call. /// diff --git a/src/nxdn/Control.h b/src/nxdn/Control.h index 07b4e19e..59ef27c4 100644 --- a/src/nxdn/Control.h +++ b/src/nxdn/Control.h @@ -214,6 +214,8 @@ namespace nxdn /// Process a data frames from the network. void processNetwork(); + /// Helper to process loss of frame stream from modem. + void processFrameLoss(); /// Helper to send a REST API request to the CC to release a channel grant at the end of a call. void notifyCC_ReleaseGrant(uint32_t dstId); diff --git a/src/nxdn/packet/Voice.cpp b/src/nxdn/packet/Voice.cpp index e4f77bdc..81222a3b 100644 --- a/src/nxdn/packet/Voice.cpp +++ b/src/nxdn/packet/Voice.cpp @@ -235,6 +235,7 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len) m_nxdn->m_rfState = RS_RF_LISTENING; m_nxdn->m_rfMask = 0x00U; m_nxdn->m_rfLC.reset(); + m_nxdn->m_frameLossCnt = 0U; return false; } } else if (type == RTCH_MESSAGE_TYPE_VCALL) { diff --git a/src/p25/Control.cpp b/src/p25/Control.cpp index dffc9300..cefab0bc 100644 --- a/src/p25/Control.cpp +++ b/src/p25/Control.cpp @@ -58,7 +58,7 @@ 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; +const uint8_t MAX_LOST_FRAMES = 6U; // --------------------------------------------------------------------------- // Public Class Members @@ -448,63 +448,7 @@ bool Control::processFrame(uint8_t* data, uint32_t len) if (m_frameLossCnt > MAX_LOST_FRAMES) { m_frameLossCnt = 0U; - 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)); - } - - 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)); - - 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()); - - writeRF_TDU(false); - m_voice->m_lastDUID = P25_DUID_TDU; - m_voice->writeNetwork(data + 2U, P25_DUID_TDU); - - m_rfState = RS_RF_LISTENING; - m_rfLastDstId = 0U; - m_rfTGHang.stop(); - - m_tailOnIdle = true; - - m_rfTimeout.stop(); - m_txQueue.clear(); - - if (m_network != nullptr) - m_network->resetP25(); - - return false; - } - - if (m_rfState == RS_RF_DATA) { - m_rfState = RS_RF_LISTENING; - m_rfLastDstId = 0U; - m_rfTGHang.stop(); - - m_tailOnIdle = true; - - m_data->resetRF(); - - m_rfTimeout.stop(); - m_txQueue.clear(); - - return false; - } - - m_rfState = RS_RF_LISTENING; - - m_voice->resetRF(); - m_data->resetRF(); + processFrameLoss(); return false; } @@ -613,6 +557,7 @@ bool Control::processFrame(uint8_t* data, uint32_t len) case P25_DUID_TDU: case P25_DUID_TDULC: + m_frameLossCnt = 0U; ret = m_voice->process(data, len); break; @@ -849,6 +794,12 @@ void Control::clock(uint32_t ms) m_rfState = RS_RF_LISTENING; } + if (m_frameLossCnt > 0U && m_rfState == RS_RF_LISTENING) + m_frameLossCnt = 0U; + if (m_frameLossCnt >= MAX_LOST_FRAMES && (m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA)) { + processFrameLoss(); + } + // clock data and trunking if (m_data != nullptr) { m_data->clock(ms); @@ -1294,6 +1245,65 @@ void Control::processNetwork() } } +/// +/// Helper to process loss of frame stream from modem. +/// +void Control::processFrameLoss() +{ + if (m_rfState == RS_RF_AUDIO) { + if (m_rssi != 0U) { + ::ActivityLog("P25", true, "transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm, loss count: %u", + 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, m_frameLossCnt); + } + else { + ::ActivityLog("P25", true, "transmission lost, %.1f seconds, BER: %.1f%%, loss count: %u", + float(m_voice->m_rfFrames) / 5.56F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits), m_frameLossCnt); + } + + 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)); + + 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()); + + writeRF_TDU(false); + m_voice->m_lastDUID = P25_DUID_TDU; + //m_voice->writeNetwork(data + 2U, P25_DUID_TDU); + m_voice->writeNet_TDU(); + + m_rfState = RS_RF_LISTENING; + m_rfLastDstId = 0U; + m_rfTGHang.stop(); + + m_tailOnIdle = true; + + m_rfTimeout.stop(); + m_txQueue.clear(); + + if (m_network != nullptr) + m_network->resetP25(); + } + + if (m_rfState == RS_RF_DATA) { + m_rfState = RS_RF_LISTENING; + m_rfLastDstId = 0U; + m_rfTGHang.stop(); + + m_tailOnIdle = true; + + m_data->resetRF(); + + m_rfTimeout.stop(); + m_txQueue.clear(); + } + + m_voice->resetRF(); + m_data->resetRF(); +} + /// /// Helper to send a REST API request to the CC to release a channel grant at the end of a call. /// diff --git a/src/p25/Control.h b/src/p25/Control.h index 6f066186..671b67f3 100644 --- a/src/p25/Control.h +++ b/src/p25/Control.h @@ -237,6 +237,8 @@ namespace p25 /// Process a data frames from the network. void processNetwork(); + /// Helper to process loss of frame stream from modem. + void processFrameLoss(); /// Helper to send a REST API request to the CC to release a channel grant at the end of a call. void notifyCC_ReleaseGrant(uint32_t dstId);