diff --git a/configs/bridge-config.example.yml b/configs/bridge-config.example.yml index a48d0085..41b6e169 100644 --- a/configs/bridge-config.example.yml +++ b/configs/bridge-config.example.yml @@ -180,3 +180,5 @@ system: rtsPttEnable: false # Serial port device for RTS PTT control (e.g., /dev/ttyUSB0). rtsPttPort: "/dev/ttyUSB0" + # Hold-off time (ms) before clearing RTS PTT after last audio output. + rtsPttHoldoffMs: 250 diff --git a/src/bridge/HostBridge.cpp b/src/bridge/HostBridge.cpp index b20125f5..10a2c68e 100644 --- a/src/bridge/HostBridge.cpp +++ b/src/bridge/HostBridge.cpp @@ -6,6 +6,7 @@ * * Copyright (C) 2024-2025 Bryan Biedenkapp, N2PLL * Copyright (C) 2025 Caleb, K4PHP + * Copyright (C) 2025 Lorenzo L Romero, K2LLR * */ #include "Defines.h" @@ -114,12 +115,9 @@ void audioCallback(ma_device* device, void* output, const void* input, ma_uint32 pcmIdx += 2; } - // Assert RTS PTT when audio is being sent to output + // Assert RTS PTT when audio is being sent to output and record last output time bridge->assertRtsPtt(); - } - else { - // Deassert RTS PTT when no audio is being sent to output - bridge->deassertRtsPtt(); + bridge->m_lastAudioOut = system_clock::hrc::now(); } } @@ -285,6 +283,10 @@ HostBridge::HostBridge(const std::string& confFile) : ::memset(m_netLDU2, 0x00U, 9U * 25U); m_p25Crypto = new p25::crypto::P25Crypto(); + + // initialize RTS PTT timing + m_lastAudioOut = system_clock::hrc::now(); + m_rtsPttHoldoffMs = 250U; } /* Finalizes a instance of the HostBridge class. */ @@ -946,6 +948,7 @@ bool HostBridge::readParams() // RTS PTT Configuration m_rtsPttEnable = systemConf["rtsPttEnable"].as(false); m_rtsPttPort = systemConf["rtsPttPort"].as("/dev/ttyUSB0"); + m_rtsPttHoldoffMs = (uint32_t)systemConf["rtsPttHoldoffMs"].as(m_rtsPttHoldoffMs); std::string txModeStr = "DMR"; if (m_txMode == TX_MODE_P25) @@ -975,6 +978,7 @@ bool HostBridge::readParams() LogInfo(" RTS PTT Enable: %s", m_rtsPttEnable ? "yes" : "no"); if (m_rtsPttEnable) { LogInfo(" RTS PTT Port: %s", m_rtsPttPort.c_str()); + LogInfo(" RTS PTT Hold-off: %ums", m_rtsPttHoldoffMs); } if (m_debug) { @@ -2970,6 +2974,11 @@ void HostBridge::callEnd(uint32_t srcId, uint32_t dstId) m_trafficFromUDP = false; m_udpFrameCnt = 0U; + // ensure PTT is dropped at call end + if (m_rtsPttEnable) { + deassertRtsPtt(); + } + m_dmrSeqNo = 0U; m_dmrN = 0U; m_p25SeqNo = 0U; @@ -3758,6 +3767,14 @@ void* HostBridge::threadCallWatchdog(void* arg) bridge->m_udpDropTime.clock(ms); } + // Debounce RTS PTT clear using hold-off after last audio output + if (bridge->m_rtsPttEnable && bridge->m_rtsPttActive) { + uint64_t sinceLastOut = system_clock::hrc::diffNow(bridge->m_lastAudioOut); + if (sinceLastOut >= bridge->m_rtsPttHoldoffMs) { + bridge->deassertRtsPtt(); + } + } + std::string trafficType = LOCAL_CALL; if (bridge->m_trafficFromUDP) trafficType = UDP_CALL; diff --git a/src/bridge/HostBridge.h b/src/bridge/HostBridge.h index 5694fe77..f3c73efe 100644 --- a/src/bridge/HostBridge.h +++ b/src/bridge/HostBridge.h @@ -26,6 +26,7 @@ #include "common/yaml/Yaml.h" #include "common/RingBuffer.h" #include "common/Timer.h" +#include "common/Clock.h" #include "vocoder/MBEDecoder.h" #include "vocoder/MBEEncoder.h" #define MINIAUDIO_IMPLEMENTATION @@ -260,6 +261,9 @@ class HOST_SW_API HostBridge { std::string m_rtsPttPort; RtsPttController* m_rtsPttController; bool m_rtsPttActive; + // Timestamp of last audio written to output and hold-off before clearing PTT + system_clock::hrc::hrc_t m_lastAudioOut; + uint32_t m_rtsPttHoldoffMs; uint16_t m_rtpSeqNo; uint32_t m_rtpTimestamp;