diff --git a/configs/config.example.yml b/configs/config.example.yml
index 0aab755a..284b8023 100644
--- a/configs/config.example.yml
+++ b/configs/config.example.yml
@@ -57,16 +57,16 @@ network:
allowDiagnosticTransfer: true
# Flag indicating whether or not verbose debug logging is enabled.
debug: false
- # Flag indicating whether or not RCON (remote control) is enabled.
- rconEnable: false
- # IP address of the network interface to listen for RCON commands on (or 0.0.0.0 for all).
- rconAddress: 127.0.0.1
- # Port number for RCON to listen on.
- rconPort: 9990
- # RCON access password.
- rconPassword: "PASSWORD"
- # Flag indicating whether or not verbose RCON debug logging is enabled.
- rconDebug: false
+ # Flag indicating whether or not REST API is enabled.
+ restEnable: false
+ # IP address of the network interface to listen for REST API on (or 0.0.0.0 for all).
+ restAddress: 127.0.0.1
+ # Port number for REST API to listen on.
+ restPort: 9990
+ # REST API authentication password.
+ restPassword: "PASSWORD"
+ # Flag indicating whether or not verbose REST API debug logging is enabled.
+ restDebug: false
#
# Digital Protocol Configuration
@@ -303,14 +303,11 @@ system:
# Site Configuration
#
config:
- # Flag indicating whether or not this host is authoritative for TGID operations.
- # (By default this should be true, unless you are operating in a mode that will dynamically permit
- # TGIDs via the permit-tg RCON command.)
+ # Flag indicating whether or not this host is authoritative (i.e. will automatically handle channel grant) for TGID operations.
authoritative: true
- # Flag indicating whether or not this host sends permit-tg commands to voice channels for TGID operations.
- # (By default this should be false, unless you are operating in a mode that will dynamically permit
- # TGIDs via the permit-tg RCON command.)
- controlPermitTG: false
+ # Flag indicating whether or not this host acts as a supervisor (i.e. will automatically handle permission) for voice channel TGID permission.
+ supervisor: false
+
# Channel Identity (corresponds to the appropriate entry in the iden_table file).
channelId: 2
# Channel Number (used to calculate actual host frequency based on the identity table).
@@ -322,12 +319,12 @@ system:
voiceChNo:
# Channel Number (used to calculate actual host frequency based on the identity table).
- channelNo: 1
- # RCON IP Address for voice channel.
- rconAddress: 127.0.0.1
- # RCON Port number for voice channel.
- rconPort: 9990
- # RCON access password for voice channel.
- rconPassword: "PASSWORD"
+ # REST API IP Address for voice channel.
+ restAddress: 127.0.0.1
+ # REST API Port number for voice channel.
+ restPort: 9990
+ # REST API access password for voice channel.
+ restPassword: "PASSWORD"
# DMR Color Code.
colorCode: 1
diff --git a/src/dmr/Control.cpp b/src/dmr/Control.cpp
index baa0d231..d44adff6 100644
--- a/src/dmr/Control.cpp
+++ b/src/dmr/Control.cpp
@@ -69,6 +69,7 @@ Control::Control(bool authoritative, uint32_t colorCode, uint32_t callHang, uint
::lookups::RadioIdLookup* ridLookup, ::lookups::TalkgroupIdLookup* tidLookup, ::lookups::IdenTableLookup* idenTable, ::lookups::RSSIInterpolator* rssiMapper,
uint32_t jitter, bool dumpDataPacket, bool repeatDataPacket, bool dumpCSBKData, bool debug, bool verbose) :
m_authoritative(authoritative),
+ m_supervisor(false),
m_colorCode(colorCode),
m_modem(modem),
m_network(network),
@@ -116,7 +117,7 @@ Control::~Control()
/// Helper to set DMR configuration options.
///
/// Instance of the ConfigINI class.
-///
+/// Flag indicating whether the DMR has supervisory functions.
/// Voice Channel Number list.
/// Voice Channel data map.
/// DMR Network ID.
@@ -124,13 +125,13 @@ Control::~Control()
/// Channel ID.
/// Channel Number.
///
-void Control::setOptions(yaml::Node& conf, bool controlPermitTG, const std::vector voiceChNo, const std::unordered_map voiceChData,
+void Control::setOptions(yaml::Node& conf, bool supervisor, const std::vector voiceChNo, const std::unordered_map voiceChData,
uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, bool printOptions)
{
yaml::Node systemConf = conf["system"];
yaml::Node dmrProtocol = conf["protocols"]["dmr"];
- m_controlPermitTG = controlPermitTG;
+ m_supervisor = supervisor;
Slot::m_verifyReg = dmrProtocol["verifyReg"].as(false);
@@ -159,11 +160,11 @@ void Control::setOptions(yaml::Node& conf, bool controlPermitTG, const std::vect
switch (m_tsccSlotNo) {
case 1U:
m_slot1->setTSCC(enableTSCC, dedicatedTSCC);
- m_slot1->setControlPermitTG(m_controlPermitTG);
+ m_slot1->setSupervisor(m_supervisor);
break;
case 2U:
m_slot2->setTSCC(enableTSCC, dedicatedTSCC);
- m_slot2->setControlPermitTG(m_controlPermitTG);
+ m_slot2->setSupervisor(m_supervisor);
break;
default:
LogError(LOG_DMR, "DMR, invalid slot, TSCC disabled, slotNo = %u", m_tsccSlotNo);
@@ -369,6 +370,29 @@ void Control::clock(uint32_t ms)
m_slot2->clock();
}
+///
+/// Sets a flag indicating whether DMR has supervisory functions and can send permit TG to voice channels.
+///
+///
+void Control::setSupervisor(bool supervisor)
+{
+ if (!m_enableTSCC) {
+ return;
+ }
+
+ switch (m_tsccSlotNo) {
+ case 1U:
+ m_slot1->setSupervisor(supervisor);
+ break;
+ case 2U:
+ m_slot2->setSupervisor(supervisor);
+ break;
+ default:
+ LogError(LOG_DMR, "DMR, invalid slot, slotNo = %u", m_tsccSlotNo);
+ break;
+ }
+}
+
///
/// Permits a TGID on a non-authoritative host.
///
diff --git a/src/dmr/Control.h b/src/dmr/Control.h
index 6f07a88f..c61b153c 100644
--- a/src/dmr/Control.h
+++ b/src/dmr/Control.h
@@ -68,7 +68,7 @@ namespace dmr
~Control();
/// Helper to set DMR configuration options.
- void setOptions(yaml::Node& conf, bool controlPermitTG, const std::vector voiceChNo, const std::unordered_map voiceChData,
+ void setOptions(yaml::Node& conf, bool supervisor, const std::vector voiceChNo, const std::unordered_map voiceChData,
uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, bool printOptions);
/// Gets a flag indicating whether the DMR control channel is running.
@@ -91,6 +91,8 @@ namespace dmr
/// Updates the processor.
void clock(uint32_t ms);
+ /// Sets a flag indicating whether DMR has supervisory functions and can send permit TG to voice channels.
+ void setSupervisor(bool supervisor);
/// Permits a TGID on a non-authoritative host.
void permittedTG(uint32_t dstId, uint8_t slot);
@@ -127,7 +129,7 @@ namespace dmr
friend class Slot;
bool m_authoritative;
- bool m_controlPermitTG;
+ bool m_supervisor;
uint32_t m_colorCode;
diff --git a/src/dmr/Slot.cpp b/src/dmr/Slot.cpp
index 140c40c3..57a73555 100644
--- a/src/dmr/Slot.cpp
+++ b/src/dmr/Slot.cpp
@@ -160,6 +160,7 @@ Slot::Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSiz
m_tsccPayloadGroup(false),
m_tsccPayloadVoice(true),
m_lastLateEntry(0U),
+ m_supervisor(false),
m_verbose(verbose),
m_debug(debug)
{
diff --git a/src/dmr/Slot.h b/src/dmr/Slot.h
index a3ae083c..afed14e8 100644
--- a/src/dmr/Slot.h
+++ b/src/dmr/Slot.h
@@ -107,8 +107,8 @@ namespace dmr
void setTSCC(bool enable, bool dedicated);
/// Helper to activate a TSCC payload slot.
void setTSCCActivated(uint32_t dstId, uint32_t srcId, bool group, bool voice);
- /// Sets a flag indicating whether the DMR control channel can send permit-tg to voice channels.
- void setControlPermitTG(bool controlPermitTG) { m_controlPermitTG = controlPermitTG; }
+ /// Sets a flag indicating whether the slot has supervisory functions and can send permit TG to voice channels.
+ void setSupervisor(bool supervisor) { m_supervisor = supervisor; }
/// Helper to set the voice error silence threshold.
void setSilenceThreshold(uint32_t threshold);
@@ -198,7 +198,7 @@ namespace dmr
uint32_t m_lastLateEntry;
- bool m_controlPermitTG;
+ bool m_supervisor;
bool m_verbose;
bool m_debug;
diff --git a/src/dmr/packet/ControlSignaling.cpp b/src/dmr/packet/ControlSignaling.cpp
index 56cfcbe8..6de71005 100644
--- a/src/dmr/packet/ControlSignaling.cpp
+++ b/src/dmr/packet/ControlSignaling.cpp
@@ -872,8 +872,8 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_
::ActivityLog("DMR", true, "Slot %u group grant request from %u to TG %u", m_tscc->m_slotNo, srcId, dstId);
}
- // callback RCON to permit-tg on the specified voice channel
- if (m_tscc->m_authoritative && m_tscc->m_controlPermitTG) {
+ // callback REST API to permit the granted TG on the specified voice channel
+ if (m_tscc->m_authoritative && m_tscc->m_supervisor) {
::lookups::VoiceChData voiceChData = m_tscc->m_affiliations->getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0) {
json::object req = json::object();
@@ -939,8 +939,8 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_
::ActivityLog("DMR", true, "Slot %u individual grant request from %u to TG %u", m_tscc->m_slotNo, srcId, dstId);
}
- // callback RCON to permit-tg on the specified voice channel
- if (m_tscc->m_authoritative && m_tscc->m_controlPermitTG) {
+ // callback REST API to permit the granted TG on the specified voice channel
+ if (m_tscc->m_authoritative && m_tscc->m_supervisor) {
::lookups::VoiceChData voiceChData = m_tscc->m_affiliations->getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0) {
json::object req = json::object();
diff --git a/src/host/Host.cpp b/src/host/Host.cpp
index d0754d3d..e5d52f46 100644
--- a/src/host/Host.cpp
+++ b/src/host/Host.cpp
@@ -140,7 +140,7 @@ Host::Host(const std::string& confFile) :
m_p25QueueSizeBytes(2592U), // 12 frames
m_nxdnQueueSizeBytes(1488U), // 31 frames
m_authoritative(true),
- m_controlPermitTG(false),
+ m_supervisor(false),
m_activeTickDelay(5U),
m_idleTickDelay(5U),
m_RESTAPI(nullptr)
@@ -434,7 +434,7 @@ int Host::run()
dmr = std::unique_ptr(new dmr::Control(m_authoritative, m_dmrColorCode, callHang, m_dmrQueueSizeBytes, embeddedLCOnly, dumpTAData, m_timeout, m_rfTalkgroupHang,
m_modem, m_network, m_duplex, m_ridLookup, m_tidLookup, m_idenTable, rssi, jitter, dmrDumpDataPacket, dmrRepeatDataPacket,
dmrDumpCsbkData, dmrDebug, dmrVerbose));
- dmr->setOptions(m_conf, m_controlPermitTG, m_voiceChNo, m_voiceChData, m_dmrNetId, m_siteId, m_channelId, m_channelNo, true);
+ dmr->setOptions(m_conf, m_supervisor, m_voiceChNo, m_voiceChData, m_dmrNetId, m_siteId, m_channelId, m_channelNo, true);
if (dmrCtrlChannel) {
dmr->setCCRunning(true);
@@ -507,7 +507,7 @@ int Host::run()
p25 = std::unique_ptr(new p25::Control(m_authoritative, m_p25NAC, callHang, m_p25QueueSizeBytes, m_modem, m_network, m_timeout, m_rfTalkgroupHang,
m_duplex, m_ridLookup, m_tidLookup, m_idenTable, rssi, p25DumpDataPacket, p25RepeatDataPacket,
p25DumpTsbkData, p25Debug, p25Verbose));
- p25->setOptions(m_conf, m_controlPermitTG, m_cwCallsign, m_voiceChNo, m_voiceChData, m_p25PatchSuperGroup, m_p25NetId, m_sysId, m_p25RfssId,
+ p25->setOptions(m_conf, m_supervisor, m_cwCallsign, m_voiceChNo, m_voiceChData, m_p25PatchSuperGroup, m_p25NetId, m_sysId, m_p25RfssId,
m_siteId, m_channelId, m_channelNo, true);
if (p25CtrlChannel) {
@@ -572,7 +572,7 @@ int Host::run()
nxdn = std::unique_ptr(new nxdn::Control(m_authoritative, m_nxdnRAN, callHang, m_nxdnQueueSizeBytes, m_timeout, m_rfTalkgroupHang,
m_modem, m_network, m_duplex, m_ridLookup, m_tidLookup, m_idenTable, rssi,
nxdnDumpRcchData, nxdnDebug, nxdnVerbose));
- nxdn->setOptions(m_conf, m_controlPermitTG, m_cwCallsign, m_voiceChNo, m_voiceChData, m_siteId, m_sysId, m_channelId, m_channelNo, true);
+ nxdn->setOptions(m_conf, m_supervisor, m_cwCallsign, m_voiceChNo, m_voiceChData, m_siteId, m_sysId, m_channelId, m_channelNo, true);
if (nxdnCtrlChannel) {
nxdn->setCCRunning(true);
@@ -1840,9 +1840,9 @@ bool Host::readParams()
chNo = 4095U;
}
- std::string restApiAddress = channel["rconAddress"].as("127.0.0.1");
- uint16_t restApiPort = (uint16_t)channel["rconPort"].as(REST_API_DEFAULT_PORT);
- std::string restApiPassword = channel["rconPassword"].as();
+ std::string restApiAddress = channel["restAddress"].as("127.0.0.1");
+ uint16_t restApiPort = (uint16_t)channel["restPort"].as(REST_API_DEFAULT_PORT);
+ std::string restApiPassword = channel["restPassword"].as();
::LogInfoEx(LOG_HOST, "Voice Channel Id %u Channel No $%04X REST API Adddress %s:%u", m_channelId, chNo, restApiAddress.c_str(), restApiPort);
@@ -1896,6 +1896,10 @@ bool Host::readParams()
LogInfo("System Config Parameters");
LogInfo(" Authoritative: %s", m_authoritative ? "yes" : "no");
+ if (m_authoritative) {
+ m_supervisor = rfssConfig["supervisor"].as(false);
+ LogInfo(" Supervisor: %s", m_supervisor ? "yes" : "no");
+ }
LogInfo(" RX Frequency: %uHz", m_rxFrequency);
LogInfo(" TX Frequency: %uHz", m_txFrequency);
LogInfo(" Base Frequency: %uHz", entry.baseFrequency());
@@ -1921,11 +1925,8 @@ bool Host::readParams()
LogInfo(" NXDN RAN: %u", m_nxdnRAN);
if (!m_authoritative) {
- m_controlPermitTG = false;
- LogWarning(LOG_HOST, "Host is non-authoritative, this requires RCON to \"permit-tg\" for VCs and \"grant-tg\" for CCs!");
- } else {
- m_controlPermitTG = rfssConfig["controlPermitTG"].as(false);
- LogInfo(" Control Permit TG: %s", m_controlPermitTG ? "yes" : "no");
+ m_supervisor = false;
+ LogWarning(LOG_HOST, "Host is non-authoritative! This requires REST API to handle permit TG for VCs and grant TG for CCs!");
}
}
else {
@@ -2252,7 +2253,7 @@ bool Host::createNetwork()
{
yaml::Node networkConf = m_conf["network"];
bool netEnable = networkConf["enable"].as(false);
- bool restApiEnable = networkConf["rconEnable"].as(false);
+ bool restApiEnable = networkConf["restEnable"].as(false);
// dump out if both networking and REST API are disabled
if (!netEnable && !restApiEnable) {
@@ -2262,10 +2263,10 @@ bool Host::createNetwork()
std::string address = networkConf["address"].as();
uint16_t port = (uint16_t)networkConf["port"].as(TRAFFIC_DEFAULT_PORT);
uint16_t local = (uint16_t)networkConf["local"].as(0U);
- std::string restApiAddress = networkConf["rconAddress"].as("127.0.0.1");
- uint16_t restApiPort = (uint16_t)networkConf["rconPort"].as(REST_API_DEFAULT_PORT);
- std::string restApiPassword = networkConf["rconPassword"].as();
- bool restApiDebug = networkConf["rconDebug"].as(false);
+ std::string restApiAddress = networkConf["restAddress"].as("127.0.0.1");
+ uint16_t restApiPort = (uint16_t)networkConf["restPort"].as(REST_API_DEFAULT_PORT);
+ std::string restApiPassword = networkConf["restPassword"].as();
+ bool restApiDebug = networkConf["restDebug"].as(false);
uint32_t id = networkConf["id"].as(0U);
uint32_t jitter = networkConf["talkgroupHang"].as(360U);
std::string password = networkConf["password"].as();
diff --git a/src/host/Host.h b/src/host/Host.h
index b3b1bc29..79193515 100644
--- a/src/host/Host.h
+++ b/src/host/Host.h
@@ -147,7 +147,7 @@ private:
uint32_t m_nxdnQueueSizeBytes;
bool m_authoritative;
- bool m_controlPermitTG;
+ bool m_supervisor;
uint8_t m_activeTickDelay;
uint8_t m_idleTickDelay;
diff --git a/src/network/RESTAPI.cpp b/src/network/RESTAPI.cpp
index e36362af..ea783531 100644
--- a/src/network/RESTAPI.cpp
+++ b/src/network/RESTAPI.cpp
@@ -273,6 +273,7 @@ void RESTAPI::initializeEndpoints()
m_dispatcher.match(PUT_MDM_MODE).put(REST_API_BIND(RESTAPI::restAPI_PutModemMode, this));
m_dispatcher.match(PUT_MDM_KILL).put(REST_API_BIND(RESTAPI::restAPI_PutModemKill, this));
+ m_dispatcher.match(PUT_SET_SUPERVISOR).put(REST_API_BIND(RESTAPI::restAPI_PutSetSupervisor, this));
m_dispatcher.match(PUT_PERMIT_TG).put(REST_API_BIND(RESTAPI::restAPI_PutPermitTG, this));
m_dispatcher.match(PUT_GRANT_TG).put(REST_API_BIND(RESTAPI::restAPI_PutGrantTG, this));
m_dispatcher.match(GET_RELEASE_GRNTS).get(REST_API_BIND(RESTAPI::restAPI_GetReleaseGrants, this));
@@ -764,6 +765,101 @@ void RESTAPI::restAPI_PutModemKill(const HTTPPayload& request, HTTPPayload& repl
}
}
+///
+///
+///
+///
+///
+///
+void RESTAPI::restAPI_PutSetSupervisor(const HTTPPayload& request, HTTPPayload& reply, const RequestMatch& match)
+{
+ if (!validateAuth(request, reply)) {
+ return;
+ }
+
+ json::object req = json::object();
+ if (!parseRequestBody(request, reply, req)) {
+ return;
+ }
+
+ errorPayload(reply, "OK", HTTPPayload::OK);
+
+ if (!m_host->m_authoritative) {
+ errorPayload(reply, "Host is not authoritative, cannot set supervisory state");
+ return;
+ }
+
+ // validate state is a string within the JSON blob
+ if (!req["state"].is()) {
+ errorPayload(reply, "state was not a valid integer");
+ return;
+ }
+
+ DVM_STATE state = (DVM_STATE)req["state"].get();
+
+ // validate destination ID is a integer within the JSON blob
+ if (!req["enable"].is()) {
+ errorPayload(reply, "enable was not a boolean");
+ return;
+ }
+
+ bool enable = req["enable"].get();
+
+ switch (state) {
+ case STATE_DMR:
+#if defined(ENABLE_DMR)
+ {
+ if (m_dmr != nullptr) {
+ m_dmr->setSupervisor(enable);
+ }
+ else {
+ errorPayload(reply, "DMR mode is not enabled", HTTPPayload::SERVICE_UNAVAILABLE);
+ }
+ }
+#else
+ {
+ errorPayload(reply, "DMR operations are unavailable", HTTPPayload::SERVICE_UNAVAILABLE);
+ }
+#endif // defined(ENABLE_DMR)
+ break;
+ case STATE_P25:
+#if defined(ENABLE_P25)
+ {
+ if (m_p25 != nullptr) {
+ m_p25->setSupervisor(enable);
+ }
+ else {
+ errorPayload(reply, "P25 mode is not enabled", HTTPPayload::SERVICE_UNAVAILABLE);
+ }
+ }
+#else
+ {
+ errorPayload(reply, "P25 operations are unavailable", HTTPPayload::SERVICE_UNAVAILABLE);
+ }
+#endif // defined(ENABLE_P25)
+ break;
+ case STATE_NXDN:
+#if defined(ENABLE_NXDN)
+ {
+ if (m_nxdn != nullptr) {
+ m_nxdn->setSupervisor(enable);
+ }
+ else {
+ errorPayload(reply, "NXDN mode is not enabled", HTTPPayload::SERVICE_UNAVAILABLE);
+ }
+ }
+#else
+ {
+ errorPayload(reply, "NXDN operations are unavailable", HTTPPayload::SERVICE_UNAVAILABLE);
+ }
+#endif // defined(ENABLE_NXDN)
+ break;
+ default:
+ errorPayload(reply, "invalid mode");
+ break;
+ }
+}
+
///
///
///
diff --git a/src/network/RESTAPI.h b/src/network/RESTAPI.h
index 08c32767..012e7e83 100644
--- a/src/network/RESTAPI.h
+++ b/src/network/RESTAPI.h
@@ -122,6 +122,8 @@ private:
///
void restAPI_PutModemKill(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match);
+ ///
+ void restAPI_PutSetSupervisor(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match);
///
void restAPI_PutPermitTG(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match);
///
diff --git a/src/network/RESTDefines.h b/src/network/RESTDefines.h
index 826e56fc..e6a05510 100644
--- a/src/network/RESTDefines.h
+++ b/src/network/RESTDefines.h
@@ -58,6 +58,7 @@
#define PUT_MDM_KILL "/mdm/kill"
+#define PUT_SET_SUPERVISOR "/set-supervisor"
#define PUT_PERMIT_TG "/permit-tg"
#define PUT_GRANT_TG "/grant-tg"
#define GET_RELEASE_GRNTS "/release-grants"
diff --git a/src/nxdn/Control.cpp b/src/nxdn/Control.cpp
index be89e2d3..afc049e0 100644
--- a/src/nxdn/Control.cpp
+++ b/src/nxdn/Control.cpp
@@ -94,7 +94,7 @@ Control::Control(bool authoritative, uint32_t ran, uint32_t callHang, uint32_t q
m_voice(nullptr),
m_data(nullptr),
m_authoritative(authoritative),
- m_controlPermitTG(false),
+ m_supervisor(false),
m_ran(ran),
m_timeout(timeout),
m_modem(modem),
@@ -204,8 +204,8 @@ void Control::reset()
/// Helper to set NXDN configuration options.
///
/// Instance of the yaml::Node class.
-///
-///
+/// Flag indicating whether the DMR has supervisory functions.
+/// CW callsign of this host.
/// Voice Channel Number list.
/// Voice Channel data map.
/// NXDN Site Code.
@@ -213,14 +213,14 @@ void Control::reset()
/// Channel ID.
/// Channel Number.
///
-void Control::setOptions(yaml::Node& conf, bool controlPermitTG, const std::string cwCallsign, const std::vector voiceChNo,
+void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cwCallsign, const std::vector voiceChNo,
const std::unordered_map voiceChData, uint16_t siteId, uint32_t sysId,
uint8_t channelId, uint32_t channelNo, bool printOptions)
{
yaml::Node systemConf = conf["system"];
yaml::Node nxdnProtocol = conf["protocols"]["nxdn"];
- m_controlPermitTG = controlPermitTG;
+ m_supervisor = supervisor;
m_trunk->m_verifyAff = nxdnProtocol["verifyAff"].as(false);
m_trunk->m_verifyReg = nxdnProtocol["verifyReg"].as(false);
diff --git a/src/nxdn/Control.h b/src/nxdn/Control.h
index 53bf62a8..9803faa1 100644
--- a/src/nxdn/Control.h
+++ b/src/nxdn/Control.h
@@ -82,7 +82,7 @@ namespace nxdn
void reset();
/// Helper to set NXDN configuration options.
- void setOptions(yaml::Node& conf, bool controlPermitTG, const std::string cwCallsign, const std::vector voiceChNo,
+ void setOptions(yaml::Node& conf, bool supervisor, const std::string cwCallsign, const std::vector voiceChNo,
const std::unordered_map voiceChData, uint16_t siteId, uint32_t sysId,
uint8_t channelId, uint32_t channelNo, bool printOptions);
@@ -103,6 +103,8 @@ namespace nxdn
/// Updates the processor by the passed number of milliseconds.
void clock(uint32_t ms);
+ /// Sets a flag indicating whether NXDN has supervisory functions and can send permit TG to voice channels.
+ void setSupervisor(bool supervisor) { m_supervisor = supervisor; }
/// Permits a TGID on a non-authoritative host.
void permittedTG(uint32_t dstId);
@@ -132,7 +134,7 @@ namespace nxdn
packet::Trunk* m_trunk;
bool m_authoritative;
- bool m_controlPermitTG;
+ bool m_supervisor;
uint32_t m_ran;
uint32_t m_timeout;
diff --git a/src/nxdn/packet/Trunk.cpp b/src/nxdn/packet/Trunk.cpp
index bce765b3..50d725d9 100644
--- a/src/nxdn/packet/Trunk.cpp
+++ b/src/nxdn/packet/Trunk.cpp
@@ -550,8 +550,8 @@ bool Trunk::writeRF_Message_Grant(uint32_t srcId, uint32_t dstId, uint8_t servic
}
}
- // callback RCON to permit-tg on the specified voice channel
- if (m_nxdn->m_authoritative && m_nxdn->m_controlPermitTG) {
+ // callback REST API to permit the granted TG on the specified voice channel
+ if (m_nxdn->m_authoritative && m_nxdn->m_supervisor) {
::lookups::VoiceChData voiceChData = m_nxdn->m_affiliations.getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0 &&
chNo != m_nxdn->m_siteData.channelNo()) {
diff --git a/src/p25/Control.cpp b/src/p25/Control.cpp
index 0ea072fa..4134357a 100644
--- a/src/p25/Control.cpp
+++ b/src/p25/Control.cpp
@@ -90,7 +90,7 @@ Control::Control(bool authoritative, uint32_t nac, uint32_t callHang, uint32_t q
m_data(nullptr),
m_trunk(nullptr),
m_authoritative(authoritative),
- m_controlPermitTG(false),
+ m_supervisor(false),
m_nac(nac),
m_txNAC(nac),
m_timeout(timeout),
@@ -208,8 +208,8 @@ void Control::reset()
/// Helper to set P25 configuration options.
///
/// Instance of the yaml::Node class.
-///
-///
+/// Flag indicating whether the DMR has supervisory functions.
+/// CW callsign of this host.
/// Voice Channel Number list.
/// Voice Channel data map.
///
@@ -220,14 +220,14 @@ void Control::reset()
/// Channel ID.
/// Channel Number.
///
-void Control::setOptions(yaml::Node& conf, bool controlPermitTG, const std::string cwCallsign, const std::vector voiceChNo,
+void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cwCallsign, const std::vector voiceChNo,
const std::unordered_map voiceChData, uint32_t pSuperGroup, uint32_t netId,
uint32_t sysId, uint8_t rfssId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, bool printOptions)
{
yaml::Node systemConf = conf["system"];
yaml::Node p25Protocol = conf["protocols"]["p25"];
- m_controlPermitTG = controlPermitTG;
+ m_supervisor = supervisor;
m_tduPreambleCount = p25Protocol["tduPreambleCount"].as(8U);
diff --git a/src/p25/Control.h b/src/p25/Control.h
index ca1b0851..f8bcbfd6 100644
--- a/src/p25/Control.h
+++ b/src/p25/Control.h
@@ -84,7 +84,7 @@ namespace p25
void reset();
/// Helper to set P25 configuration options.
- void setOptions(yaml::Node& conf, bool controlPermitTG, const std::string cwCallsign, const std::vector voiceChNo,
+ void setOptions(yaml::Node& conf, bool supervisor, const std::string cwCallsign, const std::vector voiceChNo,
const std::unordered_map voiceChData, uint32_t pSuperGroup, uint32_t netId,
uint32_t sysId, uint8_t rfssId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, bool printOptions);
@@ -113,6 +113,8 @@ namespace p25
/// Updates the processor by the passed number of milliseconds.
void clock(uint32_t ms);
+ /// Sets a flag indicating whether P25 has supervisory functions and can send permit TG to voice channels.
+ void setSupervisor(bool supervisor) { m_supervisor = supervisor; }
/// Permits a TGID on a non-authoritative host.
void permittedTG(uint32_t dstId);
@@ -145,7 +147,7 @@ namespace p25
friend class lookups::P25AffiliationLookup;
bool m_authoritative;
- bool m_controlPermitTG;
+ bool m_supervisor;
uint32_t m_nac;
uint32_t m_txNAC;
diff --git a/src/p25/packet/Trunk.cpp b/src/p25/packet/Trunk.cpp
index a62890e0..cd52a865 100644
--- a/src/p25/packet/Trunk.cpp
+++ b/src/p25/packet/Trunk.cpp
@@ -2232,8 +2232,8 @@ bool Trunk::writeRF_TSDU_Grant(uint32_t srcId, uint32_t dstId, uint8_t serviceOp
::ActivityLog("P25", true, "group grant request from %u to TG %u", srcId, dstId);
}
- // callback RCON to permit-tg on the specified voice channel
- if (m_p25->m_authoritative && m_p25->m_controlPermitTG) {
+ // callback REST API to permit the granted TG on the specified voice channel
+ if (m_p25->m_authoritative && m_p25->m_supervisor) {
::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0 &&
chNo != m_p25->m_siteData.channelNo()) {
@@ -2272,8 +2272,8 @@ bool Trunk::writeRF_TSDU_Grant(uint32_t srcId, uint32_t dstId, uint8_t serviceOp
::ActivityLog("P25", true, "unit-to-unit grant request from %u to %u", srcId, dstId);
}
- // callback RCON to permit-tg on the specified voice channel
- if (m_p25->m_authoritative && m_p25->m_controlPermitTG) {
+ // callback REST API to permit the granted TG on the specified voice channel
+ if (m_p25->m_authoritative && m_p25->m_supervisor) {
::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0 &&
chNo != m_p25->m_siteData.channelNo()) {