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;

pull/32/head
Bryan Biedenkapp 3 years ago
parent d5aa4c2cd9
commit b99ecefd6a

@ -45,6 +45,12 @@ using namespace dmr::packet;
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const uint8_t MAX_LOST_FRAMES = 4U;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Static Class Members // 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_aveRSSI(0U),
m_rssiCount(0U), m_rssiCount(0U),
m_silenceThreshold(DEFAULT_SILENCE_THRESHOLD), m_silenceThreshold(DEFAULT_SILENCE_THRESHOLD),
m_frameLossCnt(0U),
m_ccSeq(0U), m_ccSeq(0U),
m_ccRunning(false), m_ccRunning(false),
m_ccPrevRunning(false), m_ccPrevRunning(false),
@ -195,52 +202,75 @@ bool Slot::processFrame(uint8_t *data, uint32_t len)
{ {
assert(data != nullptr); assert(data != nullptr);
if (data[0U] == modem::TAG_LOST && m_rfState == RS_RF_AUDIO) { if (data[0U] == modem::TAG_LOST) {
if (m_rssi != 0U) { if (m_frameLossCnt > MAX_LOST_FRAMES) {
::ActivityLog("DMR", true, "Slot %u RF voice transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", m_frameLossCnt = 0U;
m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
} if (m_rfState == RS_RF_AUDIO) {
else { if (m_rssi != 0U) {
::ActivityLog("DMR", true, "Slot %u RF voice transmission lost, %.1f seconds, BER: %.1f%%", ::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_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%%", if (m_rfTimeout) {
m_slotNo, m_rfFrames, m_rfBits, m_rfErrs, float(m_rfErrs * 100U) / float(m_rfBits)); writeEndRF();
return false;
}
else {
writeEndRF(true);
return true;
}
}
// release trunked grant (if necessary) if (m_rfState == RS_RF_DATA) {
Slot *m_tscc = m_dmr->getTSCCSlot(); ::ActivityLog("DMR", true, "Slot %u, RF data transmission lost", m_slotNo);
if (m_tscc != nullptr) { writeEndRF();
if (m_tscc->m_enableTSCC && m_rfLC != nullptr) { return false;
m_tscc->m_affiliations->releaseGrant(m_rfLC->getDstId(), false);
} }
}
if (!m_tscc->m_enableTSCC) { m_rfState = RS_RF_LISTENING;
notifyCC_ReleaseGrant(m_rfLC->getDstId());
} m_rfLastDstId = 0U;
m_rfTGHang.stop();
if (m_rfTimeout) {
writeEndRF();
return false; return false;
} }
else { else {
writeEndRF(true); // increment the frame loss count by one for audio or data; otherwise drop
return true; // 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) { m_rfLastDstId = 0U;
::ActivityLog("DMR", true, "Slot %u, RF data transmission lost", m_slotNo); m_rfTGHang.stop();
writeEndRF();
return false;
}
if (data[0U] == modem::TAG_LOST) { return false;
m_rfState = RS_RF_LISTENING; }
m_rfLastDstId = 0U; }
m_rfTGHang.stop();
return false;
} }
// Have we got RSSI bytes on the end? // Have we got RSSI bytes on the end?

@ -194,6 +194,8 @@ namespace dmr
uint32_t m_silenceThreshold; uint32_t m_silenceThreshold;
uint8_t m_frameLossCnt;
uint8_t m_ccSeq; uint8_t m_ccSeq;
bool m_ccRunning; bool m_ccRunning;
bool m_ccPrevRunning; bool m_ccPrevRunning;

@ -58,6 +58,8 @@ using namespace nxdn::packet;
const uint8_t MAX_SYNC_BYTES_ERRS = 0U; const uint8_t MAX_SYNC_BYTES_ERRS = 0U;
const uint8_t MAX_LOST_FRAMES = 4U;
const uint8_t SCRAMBLER[] = { const uint8_t SCRAMBLER[] = {
0x00U, 0x00U, 0x00U, 0x82U, 0xA0U, 0x88U, 0x8AU, 0x00U, 0xA2U, 0xA8U, 0x82U, 0x8AU, 0x82U, 0x02U, 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, 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_netTimeout(1000U, timeout),
m_networkWatchdog(1000U, 0U, 1500U), m_networkWatchdog(1000U, 0U, 1500U),
m_ccPacketInterval(1000U, 0U, 80U), m_ccPacketInterval(1000U, 0U, 80U),
m_frameLossCnt(0U),
m_ccFrameCnt(0U), m_ccFrameCnt(0U),
m_ccSeq(0U), m_ccSeq(0U),
m_siteData(), m_siteData(),
@ -355,44 +358,65 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
{ {
assert(data != nullptr); assert(data != nullptr);
uint8_t type = data[0U];
bool sync = data[1U] == 0x01U; bool sync = data[1U] == 0x01U;
if (type == modem::TAG_LOST && m_rfState == RS_RF_AUDIO) { if (data[0U] == modem::TAG_LOST) {
if (m_rssi != 0U) { if (m_frameLossCnt > MAX_LOST_FRAMES) {
::ActivityLog("NXDN", true, "transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", m_frameLossCnt = 0U;
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 (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 { else {
::ActivityLog("NXDN", true, "transmission lost, %.1f seconds, BER: %.1f%%", // increment the frame loss count by one for audio or data; otherwise drop
float(m_voice->m_rfFrames) / 12.5F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits)); // 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_rfMask = 0x00U;
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_rfLC.reset();
m_affiliations.releaseGrant(m_rfLC.getDstId(), false); return false;
if (!m_control) { }
notifyCC_ReleaseGrant(m_rfLC.getDstId());
} }
writeEndRF();
return false;
} }
if (type == modem::TAG_LOST && m_rfState == RS_RF_DATA) { // have we got RSSI bytes on the end?
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?
if (len == (NXDN_FRAME_LENGTH_BYTES + 4U)) { if (len == (NXDN_FRAME_LENGTH_BYTES + 4U)) {
uint16_t raw = 0U; uint16_t raw = 0U;
raw |= (data[50U] << 8) & 0xFF00U; raw |= (data[50U] << 8) & 0xFF00U;

@ -188,6 +188,8 @@ namespace nxdn
Timer m_ccPacketInterval; Timer m_ccPacketInterval;
uint8_t m_frameLossCnt;
uint8_t m_ccFrameCnt; uint8_t m_ccFrameCnt;
uint8_t m_ccSeq; uint8_t m_ccSeq;

@ -58,6 +58,8 @@ const uint8_t MAX_SYNC_BYTES_ERRS = 4U;
const uint32_t TSBK_PCH_CCH_CNT = 6U; const uint32_t TSBK_PCH_CCH_CNT = 6U;
const uint32_t MAX_PREAMBLE_TDU_CNT = 64U; const uint32_t MAX_PREAMBLE_TDU_CNT = 64U;
const uint8_t MAX_LOST_FRAMES = 4U;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Public Class Members // 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_ccPacketInterval(1000U, 0U, 10U),
m_hangCount(3U * 8U), m_hangCount(3U * 8U),
m_tduPreambleCount(8U), m_tduPreambleCount(8U),
m_frameLossCnt(0U),
m_ccFrameCnt(0U), m_ccFrameCnt(0U),
m_ccSeq(0U), m_ccSeq(0U),
m_nid(nac), m_nid(nac),
@ -440,66 +443,86 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
bool sync = data[1U] == 0x01U; bool sync = data[1U] == 0x01U;
if (data[0U] == modem::TAG_LOST && m_rfState == RS_RF_AUDIO) { if (data[0U] == modem::TAG_LOST) {
if (m_rssi != 0U) { if (m_frameLossCnt > MAX_LOST_FRAMES) {
::ActivityLog("P25", true, "transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", m_frameLossCnt = 0U;
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%%", if (m_rfState == RS_RF_AUDIO) {
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_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); LogMessage(LOG_RF, P25_TDU_STR ", total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%",
if (!m_control) { 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));
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_affiliations.releaseGrant(m_voice->m_rfLC.getDstId(), false);
m_voice->m_lastDUID = P25_DUID_TDU; if (!m_control) {
m_voice->writeNetwork(data + 2U, P25_DUID_TDU); 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; writeRF_TDU(false);
m_rfLastDstId = 0U; m_voice->m_lastDUID = P25_DUID_TDU;
m_rfTGHang.stop(); 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_tailOnIdle = true;
m_txQueue.clear();
if (m_network != nullptr) m_rfTimeout.stop();
m_network->resetP25(); m_txQueue.clear();
return false; if (m_network != nullptr)
} m_network->resetP25();
if (data[0U] == modem::TAG_LOST && m_rfState == RS_RF_DATA) { return false;
m_rfState = RS_RF_LISTENING; }
m_rfLastDstId = 0U;
m_rfTGHang.stop();
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_data->resetRF();
m_txQueue.clear();
return false; m_rfTimeout.stop();
} m_txQueue.clear();
if (data[0U] == modem::TAG_LOST) { return false;
m_rfState = RS_RF_LISTENING; }
m_voice->resetRF(); m_rfState = RS_RF_LISTENING;
m_data->resetRF();
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) { if (!sync && m_rfState == RS_RF_LISTENING) {

@ -206,6 +206,8 @@ namespace p25
uint32_t m_hangCount; uint32_t m_hangCount;
uint32_t m_tduPreambleCount; uint32_t m_tduPreambleCount;
uint8_t m_frameLossCnt;
uint8_t m_ccFrameCnt; uint8_t m_ccFrameCnt;
uint8_t m_ccSeq; uint8_t m_ccSeq;

Loading…
Cancel
Save

Powered by TurnKey Linux.