From c1d6d4ad7fee671e0043903f611b802b4ed0c14d Mon Sep 17 00:00:00 2001 From: Dave Behnke <916775+dbehnke@users.noreply.github.com> Date: Sun, 4 Jan 2026 17:58:58 -0500 Subject: [PATCH] fix(dmr): generic gateway forwarding and custom TG maps --- reflector/DMRMMDVMProtocol.cpp | 25 +++++++++++++++++++++++-- reflector/Protocol.cpp | 13 ++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/reflector/DMRMMDVMProtocol.cpp b/reflector/DMRMMDVMProtocol.cpp index a44edd3..7b8dc8b 100644 --- a/reflector/DMRMMDVMProtocol.cpp +++ b/reflector/DMRMMDVMProtocol.cpp @@ -305,8 +305,29 @@ void CDmrmmdvmProtocol::OnDvHeaderPacketIn(std::unique_ptr &Hea // Helper: module 'A' -> TG X. // Header->GetRpt2Callsign() call has Module set by DmrDstIdToModule. - char mod = rpt2.GetCSModule(); - uint32_t tg = ModuleToDmrDestId(mod); + // Mini DMR Fix: Derive TG from Packet Header (Destination), NOT from RPT2 Module Suffix. + // RPT2 suffix (e.g. 'A') is good for DroidStar/XLX, but DMRGateway raw rewrites + // might not set RPT2 correctly (e.g. just "N8ZA" or "DMRGW"). + uint32_t tg = 0; + try { + std::string destStr = Header->GetUrCallsign().GetCallsign(); + // Remove spaces + destStr.erase(std::remove(destStr.begin(), destStr.end(), ' '), destStr.end()); + if (!destStr.empty() && std::all_of(destStr.begin(), destStr.end(), ::isdigit)) { + tg = std::stoul(destStr); + } + } catch (...) { + tg = 0; + } + + // Fallback to Module mapping if TG is 0 (e.g. "CQCQCQ" or parse error) + char mod = ' '; + if (tg > 0) { + mod = DmrDstIdToModule(tg); + } else { + mod = rpt2.GetCSModule(); + tg = ModuleToDmrDestId(mod); + } // Mini DMR: Explicit Disconnect (TG 4000 or specific unlink cmd) if (tg == 4000 || cmd == CMD_UNLINK) diff --git a/reflector/Protocol.cpp b/reflector/Protocol.cpp index 236204b..31baddb 100644 --- a/reflector/Protocol.cpp +++ b/reflector/Protocol.cpp @@ -224,7 +224,18 @@ bool CProtocol::IsSpace(char c) const char CProtocol::DmrDstIdToModule(uint32_t tg) const { - return ((char)((tg % 26)-1) + 'A'); + // Check for custom mapping first (Mini DMR Mode) + // Iterate A-Z to find if this TG is mapped + for (char m = 'A'; m <= 'Z'; m++) { + std::string key = g_Keys.dmr.map_prefix + std::string(1, m); + if (g_Configure.Contains(key)) { + if (g_Configure.GetUnsigned(key) == tg) { + return m; + } + } + } + + return ((char)((tg % 26U)-1U) + 'A'); } uint32_t CProtocol::ModuleToDmrDestId(char m) const