refactor common affiliations class to have a release grant callback; implement proper release grant callbacks for P25 and NXDN to call the permit TG API with a TGID 0 to ensure permits are released at the end of a call; update DMR release grant callback in the same way; allow permit TG API call to accept 0 as a valid TGID;

pull/25/head
Bryan Biedenkapp 3 years ago
parent f69443c2eb
commit 590aeb0bea

@ -671,6 +671,8 @@ void Slot::init(Control* dmr, bool authoritative, uint32_t colorCode, SiteData s
m_ridLookup = ridLookup; m_ridLookup = ridLookup;
m_tidLookup = tidLookup; m_tidLookup = tidLookup;
m_affiliations = new dmr::lookups::DMRAffiliationLookup(verbose); m_affiliations = new dmr::lookups::DMRAffiliationLookup(verbose);
// set the grant release callback
m_affiliations->setReleaseGrantCallback([=](uint32_t chNo, uint32_t dstId, uint8_t slot) { m_affiliations->setReleaseGrantCallback([=](uint32_t chNo, uint32_t dstId, uint8_t slot) {
Slot* tscc = m_dmr->getTSCCSlot(); Slot* tscc = m_dmr->getTSCCSlot();
if (tscc != nullptr) { if (tscc != nullptr) {
@ -690,7 +692,25 @@ void Slot::init(Control* dmr, bool authoritative, uint32_t colorCode, SiteData s
HTTP_PUT, PUT_DMR_TSCC_PAYLOAD_ACT, req, tscc->m_debug); HTTP_PUT, PUT_DMR_TSCC_PAYLOAD_ACT, req, tscc->m_debug);
} }
else { else {
::LogError(LOG_DMR, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), failed to clear payload channel, chNo = %u", tscc->m_slotNo, chNo); ::LogError(LOG_DMR, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), failed to clear payload channel, chNo = %u, slot = %u", tscc->m_slotNo, chNo, slot);
}
// callback REST API to clear TG permit for the granted TG on the specified voice channel
if (m_authoritative && m_dmr->m_supervisor) {
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0) {
json::object req = json::object();
int state = modem::DVM_STATE::STATE_DMR;
req["state"].set<int>(state);
dstId = 0U; // clear TG value
req["dstId"].set<uint32_t>(dstId);
req["slot"].set<uint8_t>(slot);
RESTClient::send(voiceChData.address(), voiceChData.port(), voiceChData.password(),
HTTP_PUT, PUT_PERMIT_TG, req, m_dmr->m_debug);
}
else {
::LogError(LOG_DMR, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), failed to clear TG permit, chNo = %u, slot = %u", tscc->m_slotNo, chNo, slot);
}
} }
} }
}); });

@ -44,8 +44,7 @@ using namespace dmr::lookups;
DMRAffiliationLookup::DMRAffiliationLookup(bool verbose) : ::lookups::AffiliationLookup("DMR Affiliation", verbose), DMRAffiliationLookup::DMRAffiliationLookup(bool verbose) : ::lookups::AffiliationLookup("DMR Affiliation", verbose),
m_grantChSlotTable(), m_grantChSlotTable(),
m_tsccChNo(0U), m_tsccChNo(0U),
m_tsccSlot(0U), m_tsccSlot(0U)
m_releaseGrant(nullptr)
{ {
/* stub */ /* stub */
} }

@ -30,7 +30,6 @@
#include "lookups/AffiliationLookup.h" #include "lookups/AffiliationLookup.h"
#include <tuple> #include <tuple>
#include <functional>
namespace dmr namespace dmr
{ {
@ -66,16 +65,11 @@ namespace dmr
/// <summary>Helper to determine the first available slot for given the channel number.</summary> /// <summary>Helper to determine the first available slot for given the channel number.</summary>
uint8_t getAvailableSlotForChannel(uint32_t chNo) const; uint8_t getAvailableSlotForChannel(uint32_t chNo) const;
/// <summary>Helper to set the release grant callback.</summary>
void setReleaseGrantCallback(std::function<void(uint32_t, uint32_t, uint8_t)>&& callback) { m_releaseGrant = callback; }
protected: protected:
std::unordered_map<uint32_t, std::tuple<uint32_t, uint8_t>> m_grantChSlotTable; std::unordered_map<uint32_t, std::tuple<uint32_t, uint8_t>> m_grantChSlotTable;
uint32_t m_tsccChNo; uint32_t m_tsccChNo;
uint8_t m_tsccSlot; uint8_t m_tsccSlot;
std::function<void(uint32_t, uint32_t, uint8_t)> m_releaseGrant;
}; };
} // namespace lookups } // namespace lookups
} // namespace dmr } // namespace dmr

@ -51,6 +51,7 @@ AffiliationLookup::AffiliationLookup(const char* name, bool verbose) :
m_grantChTable(), m_grantChTable(),
m_grantSrcIdTable(), m_grantSrcIdTable(),
m_grantTimers(), m_grantTimers(),
m_releaseGrant(nullptr),
m_name(name), m_name(name),
m_verbose(verbose) m_verbose(verbose)
{ {
@ -325,6 +326,10 @@ bool AffiliationLookup::releaseGrant(uint32_t dstId, bool releaseAll)
m_name, chNo, dstId); m_name, chNo, dstId);
} }
if (m_releaseGrant != nullptr) {
m_releaseGrant(chNo, dstId, 0U);
}
m_grantChTable.erase(dstId); m_grantChTable.erase(dstId);
m_grantSrcIdTable.erase(dstId); m_grantSrcIdTable.erase(dstId);
m_rfChTable.push_back(chNo); m_rfChTable.push_back(chNo);

@ -33,6 +33,7 @@
#include <unordered_map> #include <unordered_map>
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include <functional>
namespace lookups namespace lookups
{ {
@ -170,6 +171,9 @@ namespace lookups
/// <summary>Updates the processor by the passed number of milliseconds.</summary> /// <summary>Updates the processor by the passed number of milliseconds.</summary>
void clock(uint32_t ms); void clock(uint32_t ms);
/// <summary>Helper to set the release grant callback.</summary>
void setReleaseGrantCallback(std::function<void(uint32_t, uint32_t, uint8_t)>&& callback) { m_releaseGrant = callback; }
protected: protected:
std::vector<uint32_t> m_rfChTable; std::vector<uint32_t> m_rfChTable;
std::unordered_map<uint32_t, VoiceChData> m_rfChDataTable; std::unordered_map<uint32_t, VoiceChData> m_rfChDataTable;
@ -182,6 +186,9 @@ namespace lookups
std::unordered_map<uint32_t, uint32_t> m_grantSrcIdTable; std::unordered_map<uint32_t, uint32_t> m_grantSrcIdTable;
std::unordered_map<uint32_t, Timer> m_grantTimers; std::unordered_map<uint32_t, Timer> m_grantTimers;
// chNo dstId slot
std::function<void(uint32_t, uint32_t, uint8_t)> m_releaseGrant;
const char *m_name; const char *m_name;
bool m_verbose; bool m_verbose;

@ -900,11 +900,6 @@ void RESTAPI::restAPI_PutPermitTG(const HTTPPayload& request, HTTPPayload& reply
uint32_t dstId = req["dstId"].get<uint32_t>(); uint32_t dstId = req["dstId"].get<uint32_t>();
if (dstId == 0U) {
errorPayload(reply, "destination ID is an illegal TGID");
return;
}
switch (state) { switch (state) {
case STATE_DMR: case STATE_DMR:
#if defined(ENABLE_DMR) #if defined(ENABLE_DMR)

@ -39,6 +39,7 @@
#include "nxdn/Sync.h" #include "nxdn/Sync.h"
#include "nxdn/NXDNUtils.h" #include "nxdn/NXDNUtils.h"
#include "edac/AMBEFEC.h" #include "edac/AMBEFEC.h"
#include "remote/RESTClient.h"
#include "HostMain.h" #include "HostMain.h"
#include "Log.h" #include "Log.h"
#include "Utils.h" #include "Utils.h"
@ -275,6 +276,28 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw
std::unordered_map<uint32_t, ::lookups::VoiceChData> chData = std::unordered_map<uint32_t, ::lookups::VoiceChData>(voiceChData); std::unordered_map<uint32_t, ::lookups::VoiceChData> chData = std::unordered_map<uint32_t, ::lookups::VoiceChData>(voiceChData);
m_affiliations.setRFChData(chData); m_affiliations.setRFChData(chData);
// set the grant release callback
m_affiliations.setReleaseGrantCallback([=](uint32_t chNo, uint32_t dstId, uint8_t slot) {
// callback REST API to clear TG permit for the granted TG on the specified voice channel
if (m_authoritative && m_supervisor) {
::lookups::VoiceChData voiceChData = m_affiliations.getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0 &&
chNo != m_siteData.channelNo()) {
json::object req = json::object();
int state = modem::DVM_STATE::STATE_NXDN;
req["state"].set<int>(state);
dstId = 0U; // clear TG value
req["dstId"].set<uint32_t>(dstId);
RESTClient::send(voiceChData.address(), voiceChData.port(), voiceChData.password(),
HTTP_PUT, PUT_PERMIT_TG, req, m_debug);
}
else {
::LogError(LOG_NXDN, "NXDN, " NXDN_RTCH_MSG_TYPE_VCALL_RESP ", failed to clear TG permit, chNo = %u", chNo);
}
}
});
lc::RCCH::setSiteData(m_siteData); lc::RCCH::setSiteData(m_siteData);
lc::RCCH::setCallsign(cwCallsign); lc::RCCH::setCallsign(cwCallsign);

@ -37,6 +37,7 @@
#include "p25/P25Utils.h" #include "p25/P25Utils.h"
#include "p25/Sync.h" #include "p25/Sync.h"
#include "edac/CRC.h" #include "edac/CRC.h"
#include "remote/RESTClient.h"
#include "HostMain.h" #include "HostMain.h"
#include "Log.h" #include "Log.h"
#include "Utils.h" #include "Utils.h"
@ -319,6 +320,28 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw
std::unordered_map<uint32_t, ::lookups::VoiceChData> chData = std::unordered_map<uint32_t, ::lookups::VoiceChData>(voiceChData); std::unordered_map<uint32_t, ::lookups::VoiceChData> chData = std::unordered_map<uint32_t, ::lookups::VoiceChData>(voiceChData);
m_affiliations.setRFChData(chData); m_affiliations.setRFChData(chData);
// set the grant release callback
m_affiliations.setReleaseGrantCallback([=](uint32_t chNo, uint32_t dstId, uint8_t slot) {
// callback REST API to clear TG permit for the granted TG on the specified voice channel
if (m_authoritative && m_supervisor) {
::lookups::VoiceChData voiceChData = m_affiliations.getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0 &&
chNo != m_siteData.channelNo()) {
json::object req = json::object();
int state = modem::DVM_STATE::STATE_P25;
req["state"].set<int>(state);
dstId = 0U; // clear TG value
req["dstId"].set<uint32_t>(dstId);
RESTClient::send(voiceChData.address(), voiceChData.port(), voiceChData.password(),
HTTP_PUT, PUT_PERMIT_TG, req, m_debug);
}
else {
::LogError(LOG_P25, P25_TSDU_STR ", TSBK_IOSP_GRP_VCH (Group Voice Channel Grant), failed to clear TG permit, chNo = %u", chNo);
}
}
});
uint32_t ccBcstInterval = p25Protocol["control"]["interval"].as<uint32_t>(300U); uint32_t ccBcstInterval = p25Protocol["control"]["interval"].as<uint32_t>(300U);
m_trunk->m_adjSiteUpdateInterval += ccBcstInterval; m_trunk->m_adjSiteUpdateInterval += ccBcstInterval;

Loading…
Cancel
Save

Powered by TurnKey Linux.