From 0db63a6534b8f16c536a7844d8e577f85c991a35 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Wed, 15 Jul 2026 10:03:58 -0400 Subject: [PATCH] fix missing stream ID for call events; add call duration on call end event; --- src/sysview/SysViewMain.cpp | 34 +++++++++++++++++++++-------- src/sysview/network/PeerNetwork.cpp | 28 ++++++++++++++++++++++++ src/sysview/network/PeerNetwork.h | 30 ++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 10 deletions(-) diff --git a/src/sysview/SysViewMain.cpp b/src/sysview/SysViewMain.cpp index aa2913ee..ae701e0d 100644 --- a/src/sysview/SysViewMain.cpp +++ b/src/sysview/SysViewMain.cpp @@ -85,10 +85,10 @@ class RxStatus { public: ::system_clock::hrc::hrc_t callStartTime; ::system_clock::hrc::hrc_t lastPacket; - uint32_t srcId; - uint32_t dstId; - uint8_t slotNo; - uint32_t streamId; + uint32_t srcId = 0U; + uint32_t dstId = 0U; + uint8_t slotNo = 0U; + uint32_t streamId = 0U; }; typedef std::pair StatusMapPair; std::unordered_map g_dmrStatus; @@ -183,7 +183,7 @@ std::string resolveTGID(uint32_t id) /* Helper to emit a call start or end event. */ void emitCallStartEndEvent(uint32_t srcId, uint32_t dstId, uint8_t slotNo, uint32_t streamId, const std::string& mode, - bool callEnd = false) + bool callEnd = false, uint64_t duration = 0U) { if (g_netDataEvent == nullptr) return; @@ -208,6 +208,10 @@ void emitCallStartEndEvent(uint32_t srcId, uint32_t dstId, uint8_t slotNo, uint3 event["streamId"].set(streamId); + if (callEnd) { + event["duration"].set(duration); + } + g_netDataEvent(event); } @@ -380,6 +384,8 @@ void* threadNetworkPump(void* arg) uint32_t slotNo = (dmrBuffer[15U] & 0x80U) == 0x80U ? 2U : 1U; + uint32_t streamId = g_network->getRxDMRStreamId(slotNo); + DMRDEF::DataType::E dataType = (DMRDEF::DataType::E)(dmrBuffer[15U] & 0x0FU); data::NetData dmrData; @@ -433,7 +439,7 @@ void* threadNetworkPump(void* arg) LogInfoEx(LOG_NET, "DMR, Call End, srcId = %u (%s), dstId = %u (%s), duration = %u", srcId, resolveRID(srcId).c_str(), dstId, resolveTGID(dstId).c_str(), duration / 1000); - emitCallStartEndEvent(srcId, dstId, slotNo, status.streamId, "dmr", true); + emitCallStartEndEvent(srcId, dstId, slotNo, status.streamId, "dmr", true, duration / 1000); } } @@ -452,6 +458,7 @@ void* threadNetworkPump(void* arg) status.srcId = srcId; status.dstId = dstId; status.slotNo = slotNo; + status.streamId = streamId; g_dmrStatus[dstId] = status; // this *could* be an issue if a dstId appears on both slots somehow... LogInfoEx(LOG_NET, "DMR, Call Start, srcId = %u (%s), dstId = %u (%s)", @@ -528,6 +535,8 @@ void* threadNetworkPump(void* arg) if (netReadRet) { using namespace p25; + uint32_t streamId = g_network->getRxP25StreamId(); + uint8_t duid = p25Buffer[22U]; uint8_t MFId = p25Buffer[15U]; @@ -577,7 +586,7 @@ void* threadNetworkPump(void* arg) LogInfoEx(LOG_NET, "P25, Call End, srcId = %u (%s), dstId = %u (%s), sysId = $%03X, netId = $%05X, duration = %u", srcId, resolveRID(srcId).c_str(), dstId, resolveTGID(dstId).c_str(), sysId, netId, duration / 1000); - emitCallStartEndEvent(srcId, dstId, 0U, status.streamId, "p25", true); + emitCallStartEndEvent(srcId, dstId, 0U, status.streamId, "p25", true, duration / 1000); } } @@ -595,6 +604,7 @@ void* threadNetworkPump(void* arg) status.callStartTime = pktTime; status.srcId = srcId; status.dstId = dstId; + status.streamId = streamId; g_p25Status[dstId] = status; LogInfoEx(LOG_NET, "P25, Call Start, srcId = %u (%s), dstId = %u (%s), sysId = $%03X, netId = $%05X", @@ -984,6 +994,8 @@ void* threadNetworkPump(void* arg) if (netReadRet) { using namespace nxdn; + uint32_t streamId = g_network->getRxNXDNStreamId(); + uint8_t messageType = nxdnBuffer[4U]; uint32_t srcId = GET_UINT24(nxdnBuffer, 5U); @@ -1017,7 +1029,7 @@ void* threadNetworkPump(void* arg) LogInfoEx(LOG_NET, "NXDN, Call End, srcId = %u (%s), dstId = %u (%s), duration = %u", srcId, resolveRID(srcId).c_str(), dstId, resolveTGID(dstId).c_str(), duration / 1000); - emitCallStartEndEvent(srcId, dstId, 0U, status.streamId, "nxdn", true); + emitCallStartEndEvent(srcId, dstId, 0U, status.streamId, "nxdn", true, duration / 1000); } } @@ -1035,6 +1047,7 @@ void* threadNetworkPump(void* arg) status.callStartTime = pktTime; status.srcId = srcId; status.dstId = dstId; + status.streamId = streamId; g_nxdnStatus[dstId] = status; LogInfoEx(LOG_NET, "NXDN, Call Start, srcId = %u (%s), dstId = %u (%s)", @@ -1052,6 +1065,8 @@ void* threadNetworkPump(void* arg) if (netReadRet) { using namespace analog; + uint32_t streamId = g_network->getRxAnalogStreamId(); + uint32_t srcId = GET_UINT24(analogBuffer, 5U); uint32_t dstId = GET_UINT24(analogBuffer, 8U); @@ -1072,7 +1087,7 @@ void* threadNetworkPump(void* arg) LogInfoEx(LOG_NET, "Analog, Call End, srcId = %u (%s), dstId = %u (%s), duration = %u", srcId, resolveRID(srcId).c_str(), dstId, resolveTGID(dstId).c_str(), duration / 1000); - emitCallStartEndEvent(srcId, dstId, 0U, status.streamId, "analog", true); + emitCallStartEndEvent(srcId, dstId, 0U, status.streamId, "analog", true, duration / 1000); } } @@ -1090,6 +1105,7 @@ void* threadNetworkPump(void* arg) status.callStartTime = pktTime; status.srcId = srcId; status.dstId = dstId; + status.streamId = streamId; g_analogStatus[dstId] = status; LogInfoEx(LOG_NET, "Analog, Call Start, srcId = %u (%s), dstId = %u (%s)", diff --git a/src/sysview/network/PeerNetwork.cpp b/src/sysview/network/PeerNetwork.cpp index 60738faf..911c7272 100644 --- a/src/sysview/network/PeerNetwork.cpp +++ b/src/sysview/network/PeerNetwork.cpp @@ -57,6 +57,34 @@ PeerNetwork::PeerNetwork(const std::string& address, uint16_t port, uint16_t loc m_promiscuousPeer = true; } +/* Gets the current DMR stream ID. */ + +uint32_t PeerNetwork::getRxDMRStreamId(uint32_t slotNo) const +{ + assert(slotNo == 1U || slotNo == 2U); + + if (slotNo == 1U) { + return m_rxDMRStreamId[0U]; + } + else { + return m_rxDMRStreamId[1U]; + } +} + +/* Gets the current P25 Phase 2 stream ID. */ + +uint32_t PeerNetwork::getRxP25P2StreamId(uint32_t slotNo) const +{ + assert(slotNo == 1U || slotNo == 2U); + + if (slotNo == 1U) { + return m_rxP25P2StreamId[0U]; + } + else { + return m_rxP25P2StreamId[1U]; + } +} + // --------------------------------------------------------------------------- // Protected Class Members // --------------------------------------------------------------------------- diff --git a/src/sysview/network/PeerNetwork.h b/src/sysview/network/PeerNetwork.h index aa321fd9..648c786b 100644 --- a/src/sysview/network/PeerNetwork.h +++ b/src/sysview/network/PeerNetwork.h @@ -4,7 +4,7 @@ * GPLv2 Open Source. Use is subject to license terms. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright (C) 2024-2025 Bryan Biedenkapp, N2PLL + * Copyright (C) 2024-2026 Bryan Biedenkapp, N2PLL * */ /** @@ -70,6 +70,34 @@ namespace network */ void unlockPeerStatus() { s_peerStatusMutex.unlock(); } + /** + * @brief Gets the current DMR stream ID. + * @param slotNo DMR slot to get stream ID for. + * @return uint32_t Stream ID for the given DMR slot. + */ + uint32_t getRxDMRStreamId(uint32_t slotNo) const; + /** + * @brief Gets the current P25 stream ID. + * @return uint32_t Stream ID. + */ + uint32_t getRxP25StreamId() const { return m_rxP25StreamId; } + /** + * @brief Gets the current P25 Phase 2 stream ID. + * @param slotNo P25 Phase 2 slot to get stream ID for. + * @return uint32_t Stream ID for the given P25 Phase 2 slot. + */ + uint32_t getRxP25P2StreamId(uint32_t slotNo) const; + /** + * @brief Gets the current NXDN stream ID. + * @return uint32_t Stream ID. + */ + uint32_t getRxNXDNStreamId() const { return m_rxNXDNStreamId; } + /** + * @brief Gets the current analog stream ID. + * @return uint32_t Stream ID. + */ + uint32_t getRxAnalogStreamId() const { return m_rxAnalogStreamId; } + /** * @brief Map of peer status. */