mirror of https://github.com/nostar/urfd.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
4.3 KiB
144 lines
4.3 KiB
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
|
|
|
// urfd -- The universal reflector
|
|
// Copyright © 2021 Thomas A. Early N7TAE
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
#include "DMRMMDVMClient.h"
|
|
#include "Global.h"
|
|
#include "Configure.h"
|
|
#include "DMRMMDVMProtocol.h" // For mapping logic if accessible, or we reimplement
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
// constructors
|
|
|
|
CDmrmmdvmClient::CDmrmmdvmClient()
|
|
{
|
|
}
|
|
|
|
CDmrmmdvmClient::CDmrmmdvmClient(const CCallsign &callsign, const CIp &ip, char reflectorModule)
|
|
: CClient(callsign, ip, reflectorModule)
|
|
{
|
|
}
|
|
|
|
CDmrmmdvmClient::CDmrmmdvmClient(const CDmrmmdvmClient &client)
|
|
: CClient(client)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
// status
|
|
|
|
bool CDmrmmdvmClient::IsAlive(void) const
|
|
{
|
|
return (m_LastKeepaliveTime.time() < DMRMMDVM_KEEPALIVE_TIMEOUT);
|
|
}
|
|
|
|
// Multi-Module Reporting for Dashboard
|
|
void CDmrmmdvmClient::JsonReport(nlohmann::json &report)
|
|
{
|
|
// DEBUG: Check XLX Mode
|
|
// std::cout << "DEBUG: XLX Mode Comp: " << g_Configure.GetBoolean(g_Keys.dmr.xlx) << std::endl;
|
|
|
|
if (g_Configure.GetBoolean(g_Keys.dmr.xlx)) {
|
|
// Legacy behavior
|
|
CClient::JsonReport(report);
|
|
return;
|
|
}
|
|
|
|
// Mini DMR Mode
|
|
bool anySub = false;
|
|
|
|
// Collect Subscriptions Info
|
|
nlohmann::json jSubs = nlohmann::json::array();
|
|
|
|
std::vector<unsigned int> tgs;
|
|
m_Scanner.GetActiveTalkgroups(tgs);
|
|
|
|
std::time_t now = std::time(nullptr);
|
|
|
|
// Collect TS1
|
|
for(const auto& s : m_Scanner.GetSubscriptions(1)) {
|
|
nlohmann::json sub;
|
|
sub["TG"] = s.tgid;
|
|
sub["Slot"] = 1;
|
|
sub["Type"] = s.isStatic ? "Static" : "Dynamic";
|
|
if (!s.isStatic && s.timeout > 0) {
|
|
sub["TimeoutLeft"] = (s.expiry > now) ? (s.expiry - now) : 0;
|
|
} else {
|
|
sub["TimeoutLeft"] = -1; // Infinite or Static
|
|
}
|
|
jSubs.push_back(sub);
|
|
}
|
|
// Collect TS2
|
|
for(const auto& s : m_Scanner.GetSubscriptions(2)) {
|
|
nlohmann::json sub;
|
|
sub["TG"] = s.tgid;
|
|
sub["Slot"] = 2;
|
|
sub["Type"] = s.isStatic ? "Static" : "Dynamic";
|
|
if (!s.isStatic && s.timeout > 0) {
|
|
sub["TimeoutLeft"] = (s.expiry > now) ? (s.expiry - now) : 0;
|
|
} else {
|
|
sub["TimeoutLeft"] = -1;
|
|
}
|
|
jSubs.push_back(sub);
|
|
}
|
|
|
|
// Helper to add node entry
|
|
auto addNode = [&](char module) {
|
|
nlohmann::json jclient;
|
|
jclient["Callsign"] = m_Callsign.GetCS();
|
|
jclient["DMRID"] = m_Callsign.GetDmrid();
|
|
jclient["OnModule"] = std::string(1, module);
|
|
jclient["Protocol"] = GetProtocolName();
|
|
jclient["Subscriptions"] = jSubs;
|
|
char s[100];
|
|
if (std::strftime(s, sizeof(s), "%FT%TZ", std::gmtime(&m_ConnectTime)))
|
|
jclient["ConnectTime"] = s;
|
|
report["Clients"].push_back(jclient);
|
|
};
|
|
|
|
// Reimplement logic using global config.
|
|
auto dmrdstToMod = [&](uint32_t tg) -> char {
|
|
for (char c = 'A'; c <= 'Z'; c++) {
|
|
std::string key = g_Keys.dmr.map_prefix + c;
|
|
if (g_Configure.Contains(key)) {
|
|
if (g_Configure.GetUnsigned(key) == tg) return c;
|
|
} else {
|
|
if (tg == (uint32_t)(4001 + (c - 'A'))) return c;
|
|
}
|
|
}
|
|
return ' ';
|
|
};
|
|
|
|
// Process unique modules: valid, but we only want ONE entry per client for the dashboard to prevent duplicates.
|
|
// Pick the *first* mapped module as the "visual" module, or space if none.
|
|
char visualModule = ' ';
|
|
|
|
for(unsigned int tg : tgs) {
|
|
char mod = dmrdstToMod(tg);
|
|
if (mod != ' ') {
|
|
visualModule = mod;
|
|
anySub = true;
|
|
break; // Found one, good enough for display
|
|
}
|
|
}
|
|
|
|
// Always report the client once
|
|
addNode(visualModule);
|
|
}
|