cherrypick changes from tsawyer/dvmhost/p25-consolidation into ModemV24;

pull/126/head
Bryan Biedenkapp 4 months ago
parent 8b7f5cee72
commit 0d45869bc4

@ -31,4 +31,17 @@
#undef __EXE_NAME__
#define __EXE_NAME__ "dvmhost"
/**
* @brief RF Frame Loss Types
*/
enum RPT_RF_LOSS_TYPE {
RF_LOSS_TYPE_TG_HANG_NOT_LISTENING,
RF_LOSS_TYPE_LOSS_WATCHDOG,
RF_LOSS_TYPE_EXCEEDED_FRAME_THRESHOLD,
RF_LOSS_TYPE_IN_CALL_CONTROL,
RF_LOSS_TYPE_UNKNOWN
};
#endif // __DEFINES_H__

@ -204,7 +204,7 @@ bool Slot::processFrame(uint8_t *data, uint32_t len)
if (m_frameLossCnt > m_frameLossThreshold) {
m_frameLossCnt = 0U;
processFrameLoss();
processFrameLoss(RF_LOSS_TYPE_EXCEEDED_FRAME_THRESHOLD);
return false;
}
@ -545,7 +545,7 @@ void Slot::processInCallCtrl(network::NET_ICC::ENUM command, uint32_t dstId)
}
}
processFrameLoss();
processFrameLoss(RF_LOSS_TYPE_IN_CALL_CONTROL);
m_rfLastDstId = 0U;
m_rfLastSrcId = 0U;
@ -701,7 +701,7 @@ void Slot::clock()
if (m_rfLossWatchdog.hasExpired()) {
m_rfLossWatchdog.stop();
processFrameLoss();
processFrameLoss(RF_LOSS_TYPE_LOSS_WATCHDOG);
}
}
}
@ -790,7 +790,7 @@ void Slot::clock()
if (m_frameLossCnt > 0U && m_rfState == RS_RF_LISTENING)
m_frameLossCnt = 0U;
if (m_frameLossCnt >= m_frameLossThreshold && (m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA)) {
processFrameLoss();
processFrameLoss(RF_LOSS_TYPE_EXCEEDED_FRAME_THRESHOLD);
}
}
@ -1226,20 +1226,40 @@ void Slot::addFrame(const uint8_t *data, bool net, bool imm)
/* Helper to process loss of frame stream from modem. */
void Slot::processFrameLoss()
void Slot::processFrameLoss(RPT_RF_LOSS_TYPE type)
{
// resolve the type of RF frame loss into a human-readable string
std::string typeStr;
switch (type) {
case RF_LOSS_TYPE_EXCEEDED_FRAME_THRESHOLD:
typeStr = "exceeded frame loss threshold";
break;
case RF_LOSS_TYPE_LOSS_WATCHDOG:
typeStr = "loss watchdog timeout";
break;
case RF_LOSS_TYPE_IN_CALL_CONTROL:
typeStr = "in-call control request";
break;
case RF_LOSS_TYPE_TG_HANG_NOT_LISTENING:
typeStr = "TG hang, RF not listening";
break;
default:
typeStr = "no loss type set BUGBUG";
break;
}
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);
::ActivityLog("DMR", true, "Slot %u RF voice transmission lost, %s, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm, loss count: %u",
m_slotNo, typeStr.c_str(), 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);
::ActivityLog("DMR", true, "Slot %u RF voice transmission lost, %s, %.1f seconds, BER: %.1f%%, loss count: %u",
m_slotNo, typeStr.c_str(), float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits), m_frameLossCnt);
}
LogInfoEx(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));
LogInfoEx(LOG_RF, "DMR Slot %u, transmission lost, %s, total frames: %d, total bits: %d, errors: %d, BER: %.4f%%",
m_slotNo, typeStr.c_str(), m_rfFrames, m_rfBits, m_rfErrs, float(m_rfErrs * 100U) / float(m_rfBits));
// release trunked grant (if necessary)
Slot* tscc = s_dmr->getTSCCSlot();
@ -1272,6 +1292,9 @@ void Slot::processFrameLoss()
m_rfLastDstId = 0U;
m_rfTGHang.stop();
m_rfLossWatchdog.stop();
m_txQueue.clear();
}
/* Helper to send a REST API request to the CC to release a channel grant at the end of a call. */

@ -515,8 +515,9 @@ namespace dmr
/**
* @brief Helper to process loss of frame stream from modem.
* @param type Type of RF frame loss.
*/
void processFrameLoss();
void processFrameLoss(RPT_RF_LOSS_TYPE type);
/**
* @brief Helper to send a REST API request to the CC to release a channel grant at the end of a call.

@ -686,6 +686,101 @@ void ModemV24::create_TDU(uint8_t* buffer)
::memcpy(buffer, data, P25_TDU_FRAME_LENGTH_BYTES + 2U);
}
/* Advances RX voice frame sequencing and reports when an LDU is ready to emit. */
DUID::E ModemV24::updateLDUSequence(DFSIFrameType::E frameType)
{
// determine the LDU1 N
uint8_t n = 0U;
switch (frameType) {
case DFSIFrameType::LDU1_VOICE1:
n = 1U;
break;
case DFSIFrameType::LDU1_VOICE2:
n = 2U;
break;
case DFSIFrameType::LDU1_VOICE3:
n = 3U;
break;
case DFSIFrameType::LDU1_VOICE4:
n = 4U;
break;
case DFSIFrameType::LDU1_VOICE5:
n = 5U;
break;
case DFSIFrameType::LDU1_VOICE6:
n = 6U;
break;
case DFSIFrameType::LDU1_VOICE7:
n = 7U;
break;
case DFSIFrameType::LDU1_VOICE8:
n = 8U;
break;
case DFSIFrameType::LDU1_VOICE9:
n = 9U;
break;
default:
break;
}
// advance LDU1 sequence if applicable
if (n != 0U) {
if (n == 1U || n > m_rxCall->ldu1N) {
m_rxCall->ldu1N = n;
return (n == 9U) ? DUID::LDU1 : (DUID::E)0xFFU;
}
return (DUID::E)0xFFU;
}
// determine the LDU2 N
n = 0U;
switch (frameType) {
case DFSIFrameType::LDU2_VOICE10:
n = 1U;
break;
case DFSIFrameType::LDU2_VOICE11:
n = 2U;
break;
case DFSIFrameType::LDU2_VOICE12:
n = 3U;
break;
case DFSIFrameType::LDU2_VOICE13:
n = 4U;
break;
case DFSIFrameType::LDU2_VOICE14:
n = 5U;
break;
case DFSIFrameType::LDU2_VOICE15:
n = 6U;
break;
case DFSIFrameType::LDU2_VOICE16:
n = 7U;
break;
case DFSIFrameType::LDU2_VOICE17:
n = 8U;
break;
case DFSIFrameType::LDU2_VOICE18:
n = 9U;
break;
default:
break;
}
// advance LDU2 sequence if applicable
if (n != 0U) {
if (n == 1U || n > m_rxCall->ldu2N) {
m_rxCall->ldu2N = n;
return (n == 9U) ? DUID::LDU2 : (DUID::E)0xFFU;
}
return (DUID::E)0xFFU;
}
return (DUID::E)0xFFU;
}
/* Internal helper to convert from V.24/DFSI to TIA-102 air interface. */
void ModemV24::convertToAirV24(const uint8_t *data, uint32_t length)
@ -706,6 +801,7 @@ void ModemV24::convertToAirV24(const uint8_t *data, uint32_t length)
}
DFSIFrameType::E frameType = (DFSIFrameType::E)dfsiData[0U];
bool rxVoiceFrameSeen = false;
m_rxLastFrameTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
// Switch based on DFSI frame type
@ -721,14 +817,18 @@ void ModemV24::convertToAirV24(const uint8_t *data, uint32_t length)
}
} else {
if (m_rxCallInProgress) {
m_rxCall->resetCallData();
m_rxCallInProgress = false;
if (m_debug) {
::LogDebugEx(LOG_MODEM, "ModemV24::convertToAirV24()", "V.24 RX, ICW, opcode = $%02X, type = $%02X", start.getOpcode(), start.getArgument1());
::LogDebugEx(LOG_MODEM, "ModemV24::convertToAirV24()", "V.24 RX, ICW, opcode = $%02X, type = $%02X, srcId = %u, dstId = %u", start.getOpcode(), start.getArgument1(), m_rxCall->srcId, m_rxCall->dstId);
}
if (m_rxCall->srcId != 0U || m_rxCall->dstId != 0U) {
// generate a TDU
create_TDU(buffer);
storeConvertedRx(buffer, P25_TDU_FRAME_LENGTH_BYTES + 2U);
}
// generate a TDU
create_TDU(buffer);
storeConvertedRx(buffer, P25_TDU_FRAME_LENGTH_BYTES + 2U);
m_rxCall->resetCallData();
}
}
}
@ -895,7 +995,7 @@ void ModemV24::convertToAirV24(const uint8_t *data, uint32_t length)
m_rxCall->errors += svf.fullRateVoice->getTotalErrors();
}
m_rxCall->n++;
rxVoiceFrameSeen = true;
}
break;
case DFSIFrameType::LDU2_VOICE10:
@ -947,7 +1047,7 @@ void ModemV24::convertToAirV24(const uint8_t *data, uint32_t length)
m_rxCall->errors += svf.fullRateVoice->getTotalErrors();
}
m_rxCall->n++;
rxVoiceFrameSeen = true;
}
break;
@ -1561,169 +1661,175 @@ void ModemV24::convertToAirV24(const uint8_t *data, uint32_t length)
break;
}
// increment our voice frame counter
m_rxCall->n++;
rxVoiceFrameSeen = true;
}
break;
}
// encode LDU1 if ready
if (m_rxCall->n == 9U) {
// decode RS (24,12,13) FEC
// bryanb: for now this won't abort the frame if RS fails, but maybe it should in the future, for now
// we'll just log the error
try {
bool ret = m_rs.decode241213(m_rxCall->LDULC);
if (!ret) {
LogError(LOG_MODEM, "V.24/DFSI LDU1, failed to decode RS (24,12,13) FEC");
// process received voice frame
if (rxVoiceFrameSeen) {
DUID::E duid = updateLDUSequence(frameType);
// encode LDU1 if ready
if (duid == DUID::LDU1) {
// decode RS (24,12,13) FEC
// bryanb: for now this won't abort the frame if RS fails, but maybe it should in the future, for now
// we'll just log the error
try {
bool ret = m_rs.decode241213(m_rxCall->LDULC);
if (!ret) {
LogError(LOG_MODEM, "V.24/DFSI LDU1, failed to decode RS (24,12,13) FEC");
}
}
catch (...) {
Utils::dump(2U, "Modem, V.24 LDU1 RS excepted with input data", m_rxCall->LDULC, P25_LDU_LC_FEC_LENGTH_BYTES);
}
}
catch (...) {
Utils::dump(2U, "Modem, V.24 LDU1 RS excepted with input data", m_rxCall->LDULC, P25_LDU_LC_FEC_LENGTH_BYTES);
}
if (m_rxCall->errors > 0U) {
LogWarning(LOG_MODEM, P25_DFSI_LDU1_STR ", V.24, errs = %u/1233 (%.1f%%)", m_rxCall->errors, float(m_rxCall->errors) / 12.33F);
m_rxCall->errors = 0U;
}
if (m_rxCall->errors > 0U) {
LogWarning(LOG_MODEM, P25_DFSI_LDU1_STR ", V.24, errs = %u/1233 (%.1f%%)", m_rxCall->errors, float(m_rxCall->errors) / 12.33F);
m_rxCall->errors = 0U;
}
lc::LC lc = lc::LC();
lc.setLCO(m_rxCall->lco);
lc.setMFId(m_rxCall->mfId);
m_rxCall->ldu1N = 0U;
if (lc.isStandardMFId()) {
lc.setSrcId(m_rxCall->srcId);
lc.setDstId(m_rxCall->dstId);
} else {
uint8_t rsBuffer[P25_LDU_LC_FEC_LENGTH_BYTES];
::memset(rsBuffer, 0x00U, P25_LDU_LC_FEC_LENGTH_BYTES);
rsBuffer[0U] = m_rxCall->LDULC[0U];
rsBuffer[1U] = m_rxCall->LDULC[1U];
rsBuffer[2U] = m_rxCall->LDULC[2U];
rsBuffer[3U] = m_rxCall->LDULC[3U];
rsBuffer[4U] = m_rxCall->LDULC[4U];
rsBuffer[5U] = m_rxCall->LDULC[5U];
rsBuffer[6U] = m_rxCall->LDULC[6U];
rsBuffer[7U] = m_rxCall->LDULC[7U];
rsBuffer[8U] = m_rxCall->LDULC[8U];
// combine bytes into ulong64_t (8 byte) value
ulong64_t rsValue = 0U;
rsValue = rsBuffer[1U];
rsValue = (rsValue << 8) + rsBuffer[2U];
rsValue = (rsValue << 8) + rsBuffer[3U];
rsValue = (rsValue << 8) + rsBuffer[4U];
rsValue = (rsValue << 8) + rsBuffer[5U];
rsValue = (rsValue << 8) + rsBuffer[6U];
rsValue = (rsValue << 8) + rsBuffer[7U];
rsValue = (rsValue << 8) + rsBuffer[8U];
lc.setRS(rsValue);
}
lc::LC lc = lc::LC();
lc.setLCO(m_rxCall->lco);
lc.setMFId(m_rxCall->mfId);
bool emergency = ((m_rxCall->serviceOptions & 0xFFU) & 0x80U) == 0x80U; // Emergency Flag
bool encryption = ((m_rxCall->serviceOptions & 0xFFU) & 0x40U) == 0x40U; // Encryption Flag
uint8_t priority = ((m_rxCall->serviceOptions & 0xFFU) & 0x07U); // Priority
lc.setEmergency(emergency);
lc.setEncrypted(encryption);
lc.setPriority(priority);
data::LowSpeedData lsd = data::LowSpeedData();
lsd.setLSD1(m_rxCall->lsd1);
lsd.setLSD2(m_rxCall->lsd2);
// generate Sync
Sync::addP25Sync(buffer + 2U);
// generate NID
m_nid->encode(buffer + 2U, DUID::LDU1);
// generate LDU1 Data
lc.encodeLDU1(buffer + 2U);
// generate Low Speed Data
lsd.process(buffer + 2U);
// generate audio
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 10U, 0U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 26U, 1U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 55U, 2U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 80U, 3U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 105U, 4U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 130U, 5U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 155U, 6U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 180U, 7U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 204U, 8U);
// add status bits
P25Utils::addStatusBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, true, false);
buffer[0U] = modem::TAG_DATA;
buffer[1U] = 0x01U;
storeConvertedRx(buffer, P25_LDU_FRAME_LENGTH_BYTES + 2U);
}
// encode LDU2 if ready
if (m_rxCall->n == 18U) {
// decode RS (24,16,9) FEC
// bryanb: for now this won't abort the frame if RS fails, but maybe it should in the future, for now
// we'll just log the error
try {
bool ret = m_rs.decode24169(m_rxCall->LDULC);
if (!ret) {
LogError(LOG_MODEM, "V.24/DFSI LDU2, failed to decode RS (24,16,9) FEC");
}
}
catch (...) {
Utils::dump(2U, "Modem, V.24 LDU2 RS excepted with input data", m_rxCall->LDULC, P25_LDU_LC_FEC_LENGTH_BYTES);
}
if (lc.isStandardMFId()) {
lc.setSrcId(m_rxCall->srcId);
lc.setDstId(m_rxCall->dstId);
} else {
uint8_t rsBuffer[P25_LDU_LC_FEC_LENGTH_BYTES];
::memset(rsBuffer, 0x00U, P25_LDU_LC_FEC_LENGTH_BYTES);
rsBuffer[0U] = m_rxCall->LDULC[0U];
rsBuffer[1U] = m_rxCall->LDULC[1U];
rsBuffer[2U] = m_rxCall->LDULC[2U];
rsBuffer[3U] = m_rxCall->LDULC[3U];
rsBuffer[4U] = m_rxCall->LDULC[4U];
rsBuffer[5U] = m_rxCall->LDULC[5U];
rsBuffer[6U] = m_rxCall->LDULC[6U];
rsBuffer[7U] = m_rxCall->LDULC[7U];
rsBuffer[8U] = m_rxCall->LDULC[8U];
// combine bytes into ulong64_t (8 byte) value
ulong64_t rsValue = 0U;
rsValue = rsBuffer[1U];
rsValue = (rsValue << 8) + rsBuffer[2U];
rsValue = (rsValue << 8) + rsBuffer[3U];
rsValue = (rsValue << 8) + rsBuffer[4U];
rsValue = (rsValue << 8) + rsBuffer[5U];
rsValue = (rsValue << 8) + rsBuffer[6U];
rsValue = (rsValue << 8) + rsBuffer[7U];
rsValue = (rsValue << 8) + rsBuffer[8U];
lc.setRS(rsValue);
}
bool emergency = ((m_rxCall->serviceOptions & 0xFFU) & 0x80U) == 0x80U; // Emergency Flag
bool encryption = ((m_rxCall->serviceOptions & 0xFFU) & 0x40U) == 0x40U; // Encryption Flag
uint8_t priority = ((m_rxCall->serviceOptions & 0xFFU) & 0x07U); // Priority
lc.setEmergency(emergency);
lc.setEncrypted(encryption);
lc.setPriority(priority);
data::LowSpeedData lsd = data::LowSpeedData();
lsd.setLSD1(m_rxCall->lsd1);
lsd.setLSD2(m_rxCall->lsd2);
if (m_rxCall->errors > 0U) {
LogWarning(LOG_MODEM, P25_DFSI_LDU2_STR ", V.24, errs = %u/1233 (%.1f%%)", m_rxCall->errors, float(m_rxCall->errors) / 12.33F);
m_rxCall->errors = 0U;
// generate Sync
Sync::addP25Sync(buffer + 2U);
// generate NID
m_nid->encode(buffer + 2U, DUID::LDU1);
// generate LDU1 Data
lc.encodeLDU1(buffer + 2U);
// generate Low Speed Data
lsd.process(buffer + 2U);
// generate audio
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 10U, 0U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 26U, 1U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 55U, 2U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 80U, 3U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 105U, 4U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 130U, 5U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 155U, 6U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 180U, 7U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 204U, 8U);
// add status bits
P25Utils::addStatusBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, true, false);
buffer[0U] = modem::TAG_DATA;
buffer[1U] = 0x01U;
storeConvertedRx(buffer, P25_LDU_FRAME_LENGTH_BYTES + 2U);
}
// encode LDU2 if ready
if (duid == DUID::LDU2) {
// decode RS (24,16,9) FEC
// bryanb: for now this won't abort the frame if RS fails, but maybe it should in the future, for now
// we'll just log the error
try {
bool ret = m_rs.decode24169(m_rxCall->LDULC);
if (!ret) {
LogError(LOG_MODEM, "V.24/DFSI LDU2, failed to decode RS (24,16,9) FEC");
}
}
catch (...) {
Utils::dump(2U, "Modem, V.24 LDU2 RS excepted with input data", m_rxCall->LDULC, P25_LDU_LC_FEC_LENGTH_BYTES);
}
lc::LC lc = lc::LC();
lc.setMI(m_rxCall->MI);
lc.setAlgId(m_rxCall->algoId);
lc.setKId(m_rxCall->kId);
if (m_rxCall->errors > 0U) {
LogWarning(LOG_MODEM, P25_DFSI_LDU2_STR ", V.24, errs = %u/1233 (%.1f%%)", m_rxCall->errors, float(m_rxCall->errors) / 12.33F);
m_rxCall->errors = 0U;
}
data::LowSpeedData lsd = data::LowSpeedData();
lsd.setLSD1(m_rxCall->lsd1);
lsd.setLSD2(m_rxCall->lsd2);
m_rxCall->ldu2N = 0U;
// generate Sync
Sync::addP25Sync(buffer + 2U);
lc::LC lc = lc::LC();
lc.setMI(m_rxCall->MI);
lc.setAlgId(m_rxCall->algoId);
lc.setKId(m_rxCall->kId);
// generate NID
m_nid->encode(buffer + 2U, DUID::LDU2);
data::LowSpeedData lsd = data::LowSpeedData();
lsd.setLSD1(m_rxCall->lsd1);
lsd.setLSD2(m_rxCall->lsd2);
// generate LDU2 data
lc.encodeLDU2(buffer + 2U);
// generate Sync
Sync::addP25Sync(buffer + 2U);
// generate Low Speed Data
lsd.process(buffer + 2U);
// generate NID
m_nid->encode(buffer + 2U, DUID::LDU2);
// generate audio
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 10U, 0U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 26U, 1U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 55U, 2U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 80U, 3U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 105U, 4U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 130U, 5U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 155U, 6U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 180U, 7U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 204U, 8U);
// generate LDU2 data
lc.encodeLDU2(buffer + 2U);
// add status bits
P25Utils::addStatusBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, true, false);
// generate Low Speed Data
lsd.process(buffer + 2U);
buffer[0U] = modem::TAG_DATA;
buffer[1U] = 0x01U;
storeConvertedRx(buffer, P25_LDU_FRAME_LENGTH_BYTES + 2U);
// generate audio
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 10U, 0U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 26U, 1U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 55U, 2U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 80U, 3U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 105U, 4U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 130U, 5U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 155U, 6U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 180U, 7U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 204U, 8U);
m_rxCall->n = 0;
// add status bits
P25Utils::addStatusBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, true, false);
buffer[0U] = modem::TAG_DATA;
buffer[1U] = 0x01U;
storeConvertedRx(buffer, P25_LDU_FRAME_LENGTH_BYTES + 2U);
}
}
}
@ -1785,18 +1891,22 @@ void ModemV24::convertToAirTIA(const uint8_t *data, uint32_t length)
{
dataOffs += 1U;
// generate Sync
Sync::addP25Sync(buffer + 2U);
if (m_rxCall->srcId != 0U || m_rxCall->dstId != 0U) {
// generate Sync
Sync::addP25Sync(buffer + 2U);
// generate NID
m_nid->encode(buffer + 2U, DUID::TDU);
// generate NID
m_nid->encode(buffer + 2U, DUID::TDU);
// add status bits
P25Utils::setStatusBitsAllIdle(buffer + 2U, P25_TDU_FRAME_LENGTH_BITS);
// add status bits
P25Utils::setStatusBitsAllIdle(buffer + 2U, P25_TDU_FRAME_LENGTH_BITS);
buffer[0U] = modem::TAG_DATA;
buffer[1U] = 0x01U;
storeConvertedRx(buffer, P25_TDU_FRAME_LENGTH_BITS + 2U);
buffer[0U] = modem::TAG_DATA;
buffer[1U] = 0x01U;
storeConvertedRx(buffer, P25_TDU_FRAME_LENGTH_BITS + 2U);
}
m_rxCall->resetCallData();
}
break;
@ -2165,178 +2275,179 @@ void ModemV24::convertToAirTIA(const uint8_t *data, uint32_t length)
break;
}
// increment our voice frame counter
m_rxCall->n++;
}
break;
default:
break;
}
DUID::E duid = updateLDUSequence(frameType);
hdrOffs += BlockHeader::LENGTH;
}
// encode LDU1 if ready
if (duid == DUID::LDU1) {
// decode RS (24,12,13) FEC
// bryanb: for now this won't abort the frame if RS fails, but maybe it should in the future, for now
// we'll just log the error
try {
bool ret = m_rs.decode241213(m_rxCall->LDULC);
if (!ret) {
LogError(LOG_MODEM, "TIA/DFSI LDU1, failed to decode RS (24,12,13) FEC");
}
}
catch (...) {
Utils::dump(2U, "Modem, TIA LDU1, RS excepted with input data", m_rxCall->LDULC, P25_LDU_LC_FEC_LENGTH_BYTES);
}
m_rxLastFrameTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
if (m_rxCall->errors > 0U) {
LogWarning(LOG_MODEM, P25_DFSI_LDU1_STR ", TIA, errs = %u/1233 (%.1f%%)", m_rxCall->errors, float(m_rxCall->errors) / 12.33F);
m_rxCall->errors = 0U;
}
// encode LDU1 if ready
if (m_rxCall->n == 9U) {
// decode RS (24,12,13) FEC
// bryanb: for now this won't abort the frame if RS fails, but maybe it should in the future, for now
// we'll just log the error
try {
bool ret = m_rs.decode241213(m_rxCall->LDULC);
if (!ret) {
LogError(LOG_MODEM, "TIA/DFSI LDU1, failed to decode RS (24,12,13) FEC");
}
}
catch (...) {
Utils::dump(2U, "Modem, TIA LDU1, RS excepted with input data", m_rxCall->LDULC, P25_LDU_LC_FEC_LENGTH_BYTES);
}
m_rxCall->ldu1N = 0U;
if (m_rxCall->errors > 0U) {
LogWarning(LOG_MODEM, P25_DFSI_LDU1_STR ", TIA, errs = %u/1233 (%.1f%%)", m_rxCall->errors, float(m_rxCall->errors) / 12.33F);
m_rxCall->errors = 0U;
}
lc::LC lc = lc::LC();
lc.setLCO(m_rxCall->lco);
lc.setMFId(m_rxCall->mfId);
lc::LC lc = lc::LC();
lc.setLCO(m_rxCall->lco);
lc.setMFId(m_rxCall->mfId);
if (lc.isStandardMFId()) {
lc.setSrcId(m_rxCall->srcId);
lc.setDstId(m_rxCall->dstId);
} else {
uint8_t rsBuffer[P25_LDU_LC_FEC_LENGTH_BYTES];
::memset(rsBuffer, 0x00U, P25_LDU_LC_FEC_LENGTH_BYTES);
rsBuffer[0U] = m_rxCall->LDULC[0U];
rsBuffer[1U] = m_rxCall->LDULC[1U];
rsBuffer[2U] = m_rxCall->LDULC[2U];
rsBuffer[3U] = m_rxCall->LDULC[3U];
rsBuffer[4U] = m_rxCall->LDULC[4U];
rsBuffer[5U] = m_rxCall->LDULC[5U];
rsBuffer[6U] = m_rxCall->LDULC[6U];
rsBuffer[7U] = m_rxCall->LDULC[7U];
rsBuffer[8U] = m_rxCall->LDULC[8U];
// combine bytes into ulong64_t (8 byte) value
ulong64_t rsValue = 0U;
rsValue = rsBuffer[1U];
rsValue = (rsValue << 8) + rsBuffer[2U];
rsValue = (rsValue << 8) + rsBuffer[3U];
rsValue = (rsValue << 8) + rsBuffer[4U];
rsValue = (rsValue << 8) + rsBuffer[5U];
rsValue = (rsValue << 8) + rsBuffer[6U];
rsValue = (rsValue << 8) + rsBuffer[7U];
rsValue = (rsValue << 8) + rsBuffer[8U];
lc.setRS(rsValue);
}
bool emergency = ((m_rxCall->serviceOptions & 0xFFU) & 0x80U) == 0x80U; // Emergency Flag
bool encryption = ((m_rxCall->serviceOptions & 0xFFU) & 0x40U) == 0x40U; // Encryption Flag
uint8_t priority = ((m_rxCall->serviceOptions & 0xFFU) & 0x07U); // Priority
lc.setEmergency(emergency);
lc.setEncrypted(encryption);
lc.setPriority(priority);
data::LowSpeedData lsd = data::LowSpeedData();
lsd.setLSD1(m_rxCall->lsd1);
lsd.setLSD2(m_rxCall->lsd2);
if (lc.isStandardMFId()) {
lc.setSrcId(m_rxCall->srcId);
lc.setDstId(m_rxCall->dstId);
} else {
uint8_t rsBuffer[P25_LDU_LC_FEC_LENGTH_BYTES];
::memset(rsBuffer, 0x00U, P25_LDU_LC_FEC_LENGTH_BYTES);
rsBuffer[0U] = m_rxCall->LDULC[0U];
rsBuffer[1U] = m_rxCall->LDULC[1U];
rsBuffer[2U] = m_rxCall->LDULC[2U];
rsBuffer[3U] = m_rxCall->LDULC[3U];
rsBuffer[4U] = m_rxCall->LDULC[4U];
rsBuffer[5U] = m_rxCall->LDULC[5U];
rsBuffer[6U] = m_rxCall->LDULC[6U];
rsBuffer[7U] = m_rxCall->LDULC[7U];
rsBuffer[8U] = m_rxCall->LDULC[8U];
// combine bytes into ulong64_t (8 byte) value
ulong64_t rsValue = 0U;
rsValue = rsBuffer[1U];
rsValue = (rsValue << 8) + rsBuffer[2U];
rsValue = (rsValue << 8) + rsBuffer[3U];
rsValue = (rsValue << 8) + rsBuffer[4U];
rsValue = (rsValue << 8) + rsBuffer[5U];
rsValue = (rsValue << 8) + rsBuffer[6U];
rsValue = (rsValue << 8) + rsBuffer[7U];
rsValue = (rsValue << 8) + rsBuffer[8U];
lc.setRS(rsValue);
}
// generate Sync
Sync::addP25Sync(buffer + 2U);
bool emergency = ((m_rxCall->serviceOptions & 0xFFU) & 0x80U) == 0x80U; // Emergency Flag
bool encryption = ((m_rxCall->serviceOptions & 0xFFU) & 0x40U) == 0x40U; // Encryption Flag
uint8_t priority = ((m_rxCall->serviceOptions & 0xFFU) & 0x07U); // Priority
lc.setEmergency(emergency);
lc.setEncrypted(encryption);
lc.setPriority(priority);
data::LowSpeedData lsd = data::LowSpeedData();
lsd.setLSD1(m_rxCall->lsd1);
lsd.setLSD2(m_rxCall->lsd2);
// generate Sync
Sync::addP25Sync(buffer + 2U);
// generate NID
m_nid->encode(buffer + 2U, DUID::LDU1);
// generate LDU1 Data
lc.encodeLDU1(buffer + 2U);
// generate Low Speed Data
lsd.process(buffer + 2U);
// generate audio
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 10U, 0U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 26U, 1U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 55U, 2U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 80U, 3U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 105U, 4U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 130U, 5U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 155U, 6U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 180U, 7U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 204U, 8U);
// add status bits
P25Utils::addStatusBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, true, false);
buffer[0U] = modem::TAG_DATA;
buffer[1U] = 0x01U;
storeConvertedRx(buffer, P25_LDU_FRAME_LENGTH_BYTES + 2U);
}
// encode LDU2 if ready
if (m_rxCall->n == 18U) {
// decode RS (24,16,9) FEC
// bryanb: for now this won't abort the frame if RS fails, but maybe it should in the future, for now
// we'll just log the error
try {
bool ret = m_rs.decode24169(m_rxCall->LDULC);
if (!ret) {
LogError(LOG_MODEM, "TIA/DFSI LDU2, failed to decode RS (24,16,9) FEC");
// generate NID
m_nid->encode(buffer + 2U, DUID::LDU1);
// generate LDU1 Data
lc.encodeLDU1(buffer + 2U);
// generate Low Speed Data
lsd.process(buffer + 2U);
// generate audio
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 10U, 0U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 26U, 1U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 55U, 2U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 80U, 3U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 105U, 4U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 130U, 5U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 155U, 6U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 180U, 7U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU1 + 204U, 8U);
// add status bits
P25Utils::addStatusBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, true, false);
buffer[0U] = modem::TAG_DATA;
buffer[1U] = 0x01U;
storeConvertedRx(buffer, P25_LDU_FRAME_LENGTH_BYTES + 2U);
}
}
catch (...) {
Utils::dump(2U, "Modem, TIA LDU2, RS excepted with input data", m_rxCall->LDULC, P25_LDU_LC_FEC_LENGTH_BYTES);
}
// encode LDU2 if ready
if (duid == DUID::LDU2) {
// decode RS (24,16,9) FEC
// bryanb: for now this won't abort the frame if RS fails, but maybe it should in the future, for now
// we'll just log the error
try {
bool ret = m_rs.decode24169(m_rxCall->LDULC);
if (!ret) {
LogError(LOG_MODEM, "TIA/DFSI LDU2, failed to decode RS (24,16,9) FEC");
}
}
catch (...) {
Utils::dump(2U, "Modem, TIA LDU2, RS excepted with input data", m_rxCall->LDULC, P25_LDU_LC_FEC_LENGTH_BYTES);
}
if (m_rxCall->errors > 0U) {
LogWarning(LOG_MODEM, P25_DFSI_LDU2_STR ", TIA, errs = %u/1233 (%.1f%%)", m_rxCall->errors, float(m_rxCall->errors) / 12.33F);
m_rxCall->errors = 0U;
}
if (m_rxCall->errors > 0U) {
LogWarning(LOG_MODEM, P25_DFSI_LDU2_STR ", TIA, errs = %u/1233 (%.1f%%)", m_rxCall->errors, float(m_rxCall->errors) / 12.33F);
m_rxCall->errors = 0U;
}
lc::LC lc = lc::LC();
lc.setMI(m_rxCall->MI);
lc.setAlgId(m_rxCall->algoId);
lc.setKId(m_rxCall->kId);
m_rxCall->ldu2N = 0U;
data::LowSpeedData lsd = data::LowSpeedData();
lsd.setLSD1(m_rxCall->lsd1);
lsd.setLSD2(m_rxCall->lsd2);
lc::LC lc = lc::LC();
lc.setMI(m_rxCall->MI);
lc.setAlgId(m_rxCall->algoId);
lc.setKId(m_rxCall->kId);
// generate Sync
Sync::addP25Sync(buffer + 2U);
data::LowSpeedData lsd = data::LowSpeedData();
lsd.setLSD1(m_rxCall->lsd1);
lsd.setLSD2(m_rxCall->lsd2);
// generate NID
m_nid->encode(buffer + 2U, DUID::LDU2);
// generate Sync
Sync::addP25Sync(buffer + 2U);
// generate LDU2 data
lc.encodeLDU2(buffer + 2U);
// generate NID
m_nid->encode(buffer + 2U, DUID::LDU2);
// generate Low Speed Data
lsd.process(buffer + 2U);
// generate LDU2 data
lc.encodeLDU2(buffer + 2U);
// generate audio
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 10U, 0U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 26U, 1U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 55U, 2U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 80U, 3U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 105U, 4U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 130U, 5U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 155U, 6U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 180U, 7U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 204U, 8U);
// generate Low Speed Data
lsd.process(buffer + 2U);
// add status bits
P25Utils::addStatusBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, true, false);
// generate audio
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 10U, 0U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 26U, 1U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 55U, 2U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 80U, 3U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 105U, 4U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 130U, 5U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 155U, 6U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 180U, 7U);
m_audio.encode(buffer + 2U, m_rxCall->netLDU2 + 204U, 8U);
buffer[0U] = modem::TAG_DATA;
buffer[1U] = 0x01U;
storeConvertedRx(buffer, P25_LDU_FRAME_LENGTH_BYTES + 2U);
// add status bits
P25Utils::addStatusBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, true, false);
m_rxCall->n = 0;
buffer[0U] = modem::TAG_DATA;
buffer[1U] = 0x01U;
storeConvertedRx(buffer, P25_LDU_FRAME_LENGTH_BYTES + 2U);
}
}
break;
default:
break;
}
hdrOffs += BlockHeader::LENGTH;
}
m_rxLastFrameTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}
/* Helper to add a V.24 data frame to the P25 TX queue with the proper timestamp and formatting */

@ -82,7 +82,8 @@ namespace modem
VHDR2(nullptr),
LDULC(nullptr),
seqNo(0U),
n(0U),
ldu1N(0U),
ldu2N(0U),
netLDU1(nullptr),
netLDU2(nullptr),
pduUserData(nullptr),
@ -180,7 +181,8 @@ namespace modem
if (netLDU2 != nullptr)
::memset(netLDU2, 0x00U, 9U * 25U);
n = 0U;
ldu1N = 0U;
ldu2N = 0U;
seqNo = 0U;
if (pduUserData != nullptr)
@ -260,9 +262,13 @@ namespace modem
*/
uint32_t seqNo;
/**
* @brief
* @brief Number of LDU1 blocks.
*/
uint8_t n;
uint8_t ldu1N;
/**
* @brief Number of LDU2 blocks.
*/
uint8_t ldu2N;
/**
* @brief LDU1 Buffer.
@ -603,6 +609,7 @@ namespace modem
uint64_t m_rxLastFrameTime;
uint16_t m_callTimeout;
uint32_t m_silenceThreshold;
uint16_t m_jitter;
uint64_t m_lastP25Tx;
@ -638,6 +645,12 @@ namespace modem
*/
void create_TDU(uint8_t* buffer);
/**
* @brief Advances LDU voice frame sequencing.
* @param frameType Type of DFSI frame received.
* @returns DUID::E LDU1 if LDU1 is ready, LDU2 if LDU2 is ready, NONE if no LDU is ready.
*/
P25DEF::DUID::E updateLDUSequence(P25DFSIDEF::DFSIFrameType::E frameType);
/**
* @brief Internal helper to convert from V.24/DFSI to TIA-102 air interface.
* @param data Buffer containing data to convert.

@ -379,7 +379,7 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
if (m_frameLossCnt > m_frameLossThreshold) {
m_frameLossCnt = 0U;
processFrameLoss();
processFrameLoss(RF_LOSS_TYPE_EXCEEDED_FRAME_THRESHOLD);
return false;
}
@ -692,7 +692,7 @@ void Control::clock()
if (m_rfLossWatchdog.hasExpired()) {
m_rfLossWatchdog.stop();
processFrameLoss();
processFrameLoss(RF_LOSS_TYPE_LOSS_WATCHDOG);
}
}
}
@ -754,7 +754,7 @@ void Control::clock()
if (m_frameLossCnt > 0U && m_rfState == RS_RF_LISTENING)
m_frameLossCnt = 0U;
if (m_frameLossCnt >= m_frameLossThreshold && (m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA)) {
processFrameLoss();
processFrameLoss(RF_LOSS_TYPE_EXCEEDED_FRAME_THRESHOLD);
}
}
@ -1029,20 +1029,40 @@ void Control::processNetwork()
/* Helper to process loss of frame stream from modem. */
void Control::processFrameLoss()
void Control::processFrameLoss(RPT_RF_LOSS_TYPE type)
{
// resolve the type of RF frame loss into a human-readable string
std::string typeStr;
switch (type) {
case RF_LOSS_TYPE_EXCEEDED_FRAME_THRESHOLD:
typeStr = "exceeded frame loss threshold";
break;
case RF_LOSS_TYPE_LOSS_WATCHDOG:
typeStr = "loss watchdog timeout";
break;
case RF_LOSS_TYPE_IN_CALL_CONTROL:
typeStr = "in-call control request";
break;
case RF_LOSS_TYPE_TG_HANG_NOT_LISTENING:
typeStr = "TG hang RF not listening";
break;
default:
typeStr = "no loss type set BUGBUG";
break;
}
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);
::ActivityLog("NXDN", true, "transmission lost, %s, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm, loss count: %u",
typeStr.c_str(), 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);
::ActivityLog("NXDN", true, "transmission lost, %s, %.1f seconds, BER: %.1f%%, loss count: %u",
typeStr.c_str(), float(m_voice->m_rfFrames) / 12.5F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits), m_frameLossCnt);
}
LogInfoEx(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));
LogInfoEx(LOG_RF, "NXDN, " NXDN_RTCH_MSG_TYPE_TX_REL ", transmission lost, %s, total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%",
typeStr.c_str(), 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_notifyCC) {
@ -1057,6 +1077,16 @@ void Control::processFrameLoss()
}
m_rfState = RS_RF_LISTENING;
m_rfLastDstId = 0U;
m_rfLastSrcId = 0U;
m_rfTGHang.stop();
m_rfLossWatchdog.stop();
m_rfTimeout.stop();
m_txQueue.clear();
if (m_network != nullptr)
m_network->resetNXDN();
m_rfMask = 0x00U;
m_rfLC.reset();
@ -1078,7 +1108,7 @@ void Control::processInCallCtrl(network::NET_ICC::ENUM command, uint32_t dstId)
}
}
processFrameLoss();
processFrameLoss(RF_LOSS_TYPE_IN_CALL_CONTROL);
m_rfLastDstId = 0U;
m_rfLastSrcId = 0U;

@ -366,8 +366,9 @@ namespace nxdn
void processNetwork();
/**
* @brief Helper to process loss of frame stream from modem.
* @param type Type of RF frame loss.
*/
void processFrameLoss();
void processFrameLoss(RPT_RF_LOSS_TYPE type);
/**
* @brief Helper to process an In-Call Control message.
* @param command In-Call Control Command.

@ -588,7 +588,7 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
if (m_frameLossCnt > m_frameLossThreshold) {
m_frameLossCnt = 0U;
processFrameLoss();
processFrameLoss(RF_LOSS_TYPE_EXCEEDED_FRAME_THRESHOLD);
return false;
}
@ -936,7 +936,7 @@ void Control::clock()
// has the talkgroup hang timer expired while the modem is in a non-listening state?
if (m_rfState != RS_RF_LISTENING) {
processFrameLoss();
processFrameLoss(RF_LOSS_TYPE_TG_HANG_NOT_LISTENING);
}
}
}
@ -948,7 +948,7 @@ void Control::clock()
if (m_rfLossWatchdog.hasExpired()) {
m_rfLossWatchdog.stop();
processFrameLoss();
processFrameLoss(RF_LOSS_TYPE_LOSS_WATCHDOG);
}
}
}
@ -1038,7 +1038,7 @@ void Control::clock()
if (m_frameLossCnt > 0U && m_rfState == RS_RF_LISTENING)
m_frameLossCnt = 0U;
if (m_frameLossCnt >= m_frameLossThreshold && (m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA)) {
processFrameLoss();
processFrameLoss(RF_LOSS_TYPE_EXCEEDED_FRAME_THRESHOLD);
}
// clock data and trunking
@ -1693,20 +1693,40 @@ void Control::processNetwork()
/* Helper to process loss of frame stream from modem. */
void Control::processFrameLoss()
void Control::processFrameLoss(RPT_RF_LOSS_TYPE type)
{
// resolve the type of RF frame loss into a human-readable string
std::string typeStr;
switch (type) {
case RF_LOSS_TYPE_EXCEEDED_FRAME_THRESHOLD:
typeStr = "exceeded frame loss threshold";
break;
case RF_LOSS_TYPE_LOSS_WATCHDOG:
typeStr = "loss watchdog timeout";
break;
case RF_LOSS_TYPE_IN_CALL_CONTROL:
typeStr = "in-call control request";
break;
case RF_LOSS_TYPE_TG_HANG_NOT_LISTENING:
typeStr = "TG hang RF not listening";
break;
default:
typeStr = "no loss type set BUGBUG";
break;
}
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);
::ActivityLog("P25", true, "transmission lost, %s, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm, loss count: %u",
typeStr.c_str(), 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);
::ActivityLog("P25", true, "transmission lost, %s, %.1f seconds, BER: %.1f%%, loss count: %u",
typeStr.c_str(), float(m_voice->m_rfFrames) / 5.56F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits), m_frameLossCnt);
}
LogInfoEx(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));
LogInfoEx(LOG_RF, P25_TDU_STR ", transmission lost, %s, total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%",
typeStr.c_str(), 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_enableControl) {
@ -1722,6 +1742,7 @@ void Control::processFrameLoss()
m_rfLastDstId = 0U;
m_rfLastSrcId = 0U;
m_rfTGHang.stop();
m_rfLossWatchdog.stop();
m_rfVoiceCallTermTimeout.stop();
m_rfCallTermSrcId = 0U;
@ -1741,6 +1762,7 @@ void Control::processFrameLoss()
m_rfLastDstId = 0U;
m_rfLastSrcId = 0U;
m_rfTGHang.stop();
m_rfLossWatchdog.stop();
m_tailOnIdle = true;
@ -1782,7 +1804,7 @@ void Control::processInCallCtrl(network::NET_ICC::ENUM command, uint32_t dstId)
m_voice->m_rfLC.setDstId(dstId);
}
processFrameLoss();
processFrameLoss(RF_LOSS_TYPE_IN_CALL_CONTROL);
m_rfLastDstId = 0U;
m_rfLastSrcId = 0U;

@ -428,8 +428,9 @@ namespace p25
void processNetwork();
/**
* @brief Helper to process loss of frame stream from modem.
* @param type Type of RF frame loss.
*/
void processFrameLoss();
void processFrameLoss(RPT_RF_LOSS_TYPE type);
/**
* @brief Helper to process an In-Call Control message.
* @param command In-Call Control Command.

Loading…
Cancel
Save

Powered by TurnKey Linux.