implement remaining code required for permit-tg and embedded STC support [untested, considered experimental]; implement proper DMR T3 grant fixes to handle slot granting properly;

3.0-rcon_maint 2023-03-02
Bryan Biedenkapp 3 years ago
parent a2b1f37b56
commit 2ae52143ab

@ -41,6 +41,8 @@ file(GLOB dvmhost_SRC
"dmr/lc/*.cpp"
"dmr/lc/csbk/*.h"
"dmr/lc/csbk/*.cpp"
"dmr/lookups/*.h"
"dmr/lookups/*.cpp"
"dmr/packet*.h"
"dmr/packet/*.cpp"

@ -307,6 +307,10 @@ system:
# (By default this should be true, unless you are operating in a mode that will dynamically permit
# TGIDs via the permit-tg RCON command.)
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
# 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).

@ -66,7 +66,7 @@ using namespace dmr;
/// <param name="verbose">Flag indicating whether DMR verbose logging is enabled.</param>
Control::Control(bool authoritative, uint32_t colorCode, uint32_t callHang, uint32_t queueSize, bool embeddedLCOnly,
bool dumpTAData, uint32_t timeout, uint32_t tgHang, modem::Modem* modem, network::BaseNetwork* network, bool duplex,
lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup, lookups::IdenTableLookup* idenTable, lookups::RSSIInterpolator* rssiMapper,
::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_colorCode(colorCode),
@ -110,6 +110,7 @@ Control::~Control()
/// Helper to set DMR configuration options.
/// </summary>
/// <param name="conf">Instance of the ConfigINI class.</param>
/// <param name="controlPermitTG"></param>
/// <param name="voiceChNo">Voice Channel Number list.</param>
/// <param name="voiceChData">Voice Channel data map.</param>
/// <param name="netId">DMR Network ID.</param>
@ -117,12 +118,14 @@ Control::~Control()
/// <param name="channelId">Channel ID.</param>
/// <param name="channelNo">Channel Number.</param>
/// <param name="printOptions"></param>
void Control::setOptions(yaml::Node& conf, const std::vector<uint32_t> voiceChNo, const std::unordered_map<uint32_t, lookups::VoiceChData> voiceChData,
void Control::setOptions(yaml::Node& conf, bool controlPermitTG, const std::vector<uint32_t> voiceChNo, const std::unordered_map<uint32_t, ::lookups::VoiceChData> 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;
Slot::m_verifyReg = dmrProtocol["verifyReg"].as<bool>(false);
uint8_t nRandWait = (uint8_t)dmrProtocol["nRandWait"].as<uint32_t>(dmr::DEFAULT_NRAND_WAIT);
@ -149,9 +152,11 @@ void Control::setOptions(yaml::Node& conf, const std::vector<uint32_t> voiceChNo
switch (m_tsccSlotNo) {
case 1U:
m_slot1->setTSCC(enableTSCC, dedicatedTSCC);
m_slot1->setControlPermitTG(m_controlPermitTG);
break;
case 2U:
m_slot2->setTSCC(enableTSCC, dedicatedTSCC);
m_slot2->setControlPermitTG(m_controlPermitTG);
break;
default:
LogError(LOG_DMR, "DMR, invalid slot, TSCC disabled, slotNo = %u", m_tsccSlotNo);

@ -63,13 +63,13 @@ namespace dmr
/// <summary>Initializes a new instance of the Control class.</summary>
Control(bool authoritative, uint32_t colorCode, uint32_t callHang, uint32_t queueSize, bool embeddedLCOnly,
bool dumpTAData, uint32_t timeout, uint32_t tgHang, modem::Modem* modem, network::BaseNetwork* network, bool duplex,
lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup, lookups::IdenTableLookup* idenTable, lookups::RSSIInterpolator* rssi,
::lookups::RadioIdLookup* ridLookup, ::lookups::TalkgroupIdLookup* tidLookup, ::lookups::IdenTableLookup* idenTable, ::lookups::RSSIInterpolator* rssi,
uint32_t jitter, bool dumpDataPacket, bool repeatDataPacket, bool dumpCSBKData, bool debug, bool verbose);
/// <summary>Finalizes a instance of the Control class.</summary>
~Control();
/// <summary>Helper to set DMR configuration options.</summary>
void setOptions(yaml::Node& conf, const std::vector<uint32_t> voiceChNo, const std::unordered_map<uint32_t, lookups::VoiceChData> voiceChData,
void setOptions(yaml::Node& conf, bool controlPermitTG, const std::vector<uint32_t> voiceChNo, const std::unordered_map<uint32_t, ::lookups::VoiceChData> voiceChData,
uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, bool printOptions);
/// <summary>Gets a flag indicating whether the DMR control channel is running.</summary>
@ -121,6 +121,7 @@ namespace dmr
friend class Slot;
bool m_authoritative;
bool m_controlPermitTG;
uint32_t m_colorCode;
@ -130,9 +131,9 @@ namespace dmr
Slot* m_slot1;
Slot* m_slot2;
lookups::IdenTableLookup* m_idenTable;
lookups::RadioIdLookup* m_ridLookup;
lookups::TalkgroupIdLookup* m_tidLookup;
::lookups::IdenTableLookup* m_idenTable;
::lookups::RadioIdLookup* m_ridLookup;
::lookups::TalkgroupIdLookup* m_tidLookup;
uint8_t m_tsccSlotNo;
bool m_ccRunning;

@ -71,16 +71,16 @@ network::BaseNetwork* Slot::m_network = nullptr;
bool Slot::m_duplex = true;
lookups::IdenTableLookup* Slot::m_idenTable = nullptr;
lookups::RadioIdLookup* Slot::m_ridLookup = nullptr;
lookups::TalkgroupIdLookup* Slot::m_tidLookup = nullptr;
lookups::AffiliationLookup *Slot::m_affiliations = nullptr;
::lookups::IdenTableLookup* Slot::m_idenTable = nullptr;
::lookups::RadioIdLookup* Slot::m_ridLookup = nullptr;
::lookups::TalkgroupIdLookup* Slot::m_tidLookup = nullptr;
dmr::lookups::DMRAffiliationLookup *Slot::m_affiliations = nullptr;
lookups::IdenTable Slot::m_idenEntry = lookups::IdenTable();
::lookups::IdenTable Slot::m_idenEntry = ::lookups::IdenTable();
uint32_t Slot::m_hangCount = 3U * 17U;
lookups::RSSIInterpolator* Slot::m_rssiMapper = nullptr;
::lookups::RSSIInterpolator* Slot::m_rssiMapper = nullptr;
uint32_t Slot::m_jitterTime = 360U;
uint32_t Slot::m_jitterSlots = 6U;
@ -574,6 +574,7 @@ void Slot::setTSCC(bool enable, bool dedicated)
m_dedicatedTSCC = dedicated;
if (m_enableTSCC) {
m_modem->setDMRIgnoreCACH_AT(m_slotNo);
m_affiliations->setSlotForChannelTSCC(m_channelNo, m_slotNo);
}
}
@ -606,8 +607,8 @@ void Slot::setSilenceThreshold(uint32_t threshold)
/// <param name="jitter"></param>
/// <param name="verbose"></param>
void Slot::init(Control* dmr, bool authoritative, uint32_t colorCode, SiteData siteData, bool embeddedLCOnly, bool dumpTAData, uint32_t callHang, modem::Modem* modem,
network::BaseNetwork* network, bool duplex, lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup,
lookups::IdenTableLookup* idenTable, lookups::RSSIInterpolator* rssiMapper, uint32_t jitter, bool verbose)
network::BaseNetwork* network, bool duplex, ::lookups::RadioIdLookup* ridLookup, ::lookups::TalkgroupIdLookup* tidLookup,
::lookups::IdenTableLookup* idenTable, ::lookups::RSSIInterpolator* rssiMapper, uint32_t jitter, bool verbose)
{
assert(dmr != nullptr);
assert(modem != nullptr);
@ -635,7 +636,7 @@ void Slot::init(Control* dmr, bool authoritative, uint32_t colorCode, SiteData s
m_idenTable = idenTable;
m_ridLookup = ridLookup;
m_tidLookup = tidLookup;
m_affiliations = new lookups::AffiliationLookup("DMR Affiliations", verbose);
m_affiliations = new dmr::lookups::DMRAffiliationLookup(verbose);
m_hangCount = callHang * 17U;
@ -666,15 +667,15 @@ void Slot::init(Control* dmr, bool authoritative, uint32_t colorCode, SiteData s
/// <param name="channelId">Channel ID.</param>
/// <param name="channelNo">Channel Number.</param>
/// <param name="requireReg"></param>
void Slot::setSiteData(const std::vector<uint32_t> voiceChNo, const std::unordered_map<uint32_t, lookups::VoiceChData> voiceChData,
void Slot::setSiteData(const std::vector<uint32_t> voiceChNo, const std::unordered_map<uint32_t, ::lookups::VoiceChData> voiceChData,
uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, bool requireReg)
{
m_siteData = SiteData(SITE_MODEL_SMALL, netId, siteId, 3U, requireReg);
m_channelNo = channelNo;
std::vector<lookups::IdenTable> entries = m_idenTable->list();
std::vector<::lookups::IdenTable> entries = m_idenTable->list();
for (auto it = entries.begin(); it != entries.end(); ++it) {
lookups::IdenTable entry = *it;
::lookups::IdenTable entry = *it;
if (entry.channelId() == channelId) {
m_idenEntry = entry;
break;

@ -34,6 +34,7 @@
#include "Defines.h"
#include "dmr/Control.h"
#include "dmr/SiteData.h"
#include "dmr/lookups/DMRAffiliationLookup.h"
#include "dmr/packet/ControlSignaling.h"
#include "dmr/packet/Data.h"
#include "dmr/packet/Voice.h"
@ -43,7 +44,6 @@
#include "lookups/IdenTableLookup.h"
#include "lookups/RadioIdLookup.h"
#include "lookups/TalkgroupIdLookup.h"
#include "lookups/AffiliationLookup.h"
#include "RingBuffer.h"
#include "StopWatch.h"
#include "Timer.h"
@ -105,15 +105,17 @@ namespace dmr
/// <summary>Helper to enable and configure TSCC support for this slot.</summary>
void setTSCC(bool enable, bool dedicated);
/// <summary>Sets a flag indicating whether the DMR control channel can send permit-tg to voice channels.</summary>
void setControlPermitTG(bool controlPermitTG) { m_controlPermitTG = controlPermitTG; }
/// <summary>Helper to set the voice error silence threshold.</summary>
void setSilenceThreshold(uint32_t threshold);
/// <summary>Helper to initialize the slot processor.</summary>
static void init(Control* dmr, bool authoritative, uint32_t colorCode, SiteData siteData, bool embeddedLCOnly, bool dumpTAData, uint32_t callHang, modem::Modem* modem,
network::BaseNetwork* network, bool duplex, lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup,
lookups::IdenTableLookup* idenTable, lookups::RSSIInterpolator* rssiMapper, uint32_t jitter, bool verbose);
network::BaseNetwork* network, bool duplex, ::lookups::RadioIdLookup* ridLookup, ::lookups::TalkgroupIdLookup* tidLookup,
::lookups::IdenTableLookup* idenTable, ::lookups::RSSIInterpolator* rssiMapper, uint32_t jitter, bool verbose);
/// <summary>Sets local configured site data.</summary>
static void setSiteData(const std::vector<uint32_t> voiceChNo, const std::unordered_map<uint32_t, lookups::VoiceChData> voiceChData,
static void setSiteData(const std::vector<uint32_t> voiceChNo, const std::unordered_map<uint32_t, ::lookups::VoiceChData> voiceChData,
uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, bool requireReq);
/// <summary>Sets TSCC Aloha configuration.</summary>
static void setAlohaConfig(uint8_t nRandWait, uint8_t backOff);
@ -188,6 +190,8 @@ namespace dmr
bool m_enableTSCC;
bool m_dedicatedTSCC;
bool m_controlPermitTG;
bool m_verbose;
bool m_debug;
@ -208,16 +212,16 @@ namespace dmr
static bool m_duplex;
static lookups::IdenTableLookup* m_idenTable;
static lookups::RadioIdLookup* m_ridLookup;
static lookups::TalkgroupIdLookup* m_tidLookup;
static lookups::AffiliationLookup* m_affiliations;
static ::lookups::IdenTableLookup* m_idenTable;
static ::lookups::RadioIdLookup* m_ridLookup;
static ::lookups::TalkgroupIdLookup* m_tidLookup;
static lookups::DMRAffiliationLookup* m_affiliations;
static lookups::IdenTable m_idenEntry;
static ::lookups::IdenTable m_idenEntry;
static uint32_t m_hangCount;
static lookups::RSSIInterpolator* m_rssiMapper;
static ::lookups::RSSIInterpolator* m_rssiMapper;
static uint32_t m_jitterTime;
static uint32_t m_jitterSlots;

@ -88,7 +88,7 @@ CSBK::CSBK() :
m_logicalCh1(DMR_CHNULL),
m_logicalCh2(DMR_CHNULL),
m_slotNo(0U),
m_siteIdenEntry(lookups::IdenTable())
m_siteIdenEntry(::lookups::IdenTable())
{
/* stub */
}

@ -133,7 +133,7 @@ namespace dmr
/** Local Site data */
/// <summary>Local Site Identity Entry.</summary>
__PROTECTED_PROPERTY_PLAIN(lookups::IdenTable, siteIdenEntry, siteIdenEntry);
__PROTECTED_PROPERTY_PLAIN(::lookups::IdenTable, siteIdenEntry, siteIdenEntry);
protected:
static bool m_verbose;

@ -0,0 +1,316 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
/*
* Copyright (C) 2023 by Bryan Biedenkapp N2PLL
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "dmr/lookups/DMRAffiliationLookup.h"
#include "Log.h"
using namespace dmr::lookups;
#include <cassert>
#include <cstdio>
#include <cstring>
#include <ctime>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the DMRAffiliationLookup class.
/// </summary>
/// <param name="verbose">Flag indicating whether verbose logging is enabled.</param>
DMRAffiliationLookup::DMRAffiliationLookup(bool verbose) : ::lookups::AffiliationLookup("DMR Affiliation", verbose),
m_grantChSlotTable(),
m_tsccChNo(0U),
m_tsccSlot(0U)
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the DMRAffiliationLookup class.
/// </summary>
DMRAffiliationLookup::~DMRAffiliationLookup()
{
/* stub */
}
/// <summary>
/// Helper to grant a channel.
/// </summary>
/// <param name="dstId"></param>
/// <param name="grantTimeout"></param>
/// <returns></returns>
bool DMRAffiliationLookup::grantCh(uint32_t dstId, uint32_t grantTimeout)
{
uint32_t chNo = m_rfChTable.at(0);
uint8_t slot = getAvailableSlotForChannel(chNo);
if (slot == 0U) {
return false;
}
return grantChSlot(dstId, slot, grantTimeout);
}
/// <summary>
/// Helper to grant a channel and slot.
/// </summary>
/// <param name="dstId"></param>
/// <param name="slot"></param>
/// <param name="grantTimeout"></param>
/// <returns></returns>
bool DMRAffiliationLookup::grantChSlot(uint32_t dstId, uint8_t slot, uint32_t grantTimeout)
{
if (dstId == 0U) {
return false;
}
if (!isRFChAvailable()) {
return false;
}
uint32_t chNo = m_rfChTable.at(0);
if (chNo == m_tsccChNo && slot == m_tsccSlot) {
return false;
}
if (getAvailableSlotForChannel(chNo) == 0U || chNo == m_tsccChNo) {
auto it = std::find(m_rfChTable.begin(), m_rfChTable.end(), chNo);
m_rfChTable.erase(it);
}
m_grantChTable[dstId] = chNo;
m_grantChSlotTable[dstId] = std::make_tuple(chNo, slot);
m_rfGrantChCnt++;
m_grantTimers[dstId] = Timer(1000U, grantTimeout);
m_grantTimers[dstId].start();
if (m_verbose) {
LogMessage(LOG_HOST, "%s, granting channel, chNo = %u, slot = %u, dstId = %u",
m_name, chNo, slot, dstId);
}
return true;
}
/// <summary>
/// Helper to release the channel grant for the destination ID.
/// </summary>
/// <param name="dstId"></param>
/// <param name="releaseAll"></param>
bool DMRAffiliationLookup::releaseGrant(uint32_t dstId, bool releaseAll)
{
if (dstId == 0U && !releaseAll) {
return false;
}
// are we trying to release all grants?
if (dstId == 0U && releaseAll) {
LogWarning(LOG_HOST, "%s, force releasing all channel grants", m_name);
std::vector<uint32_t> gntsToRel = std::vector<uint32_t>();
for (auto it = m_grantChTable.begin(); it != m_grantChTable.end(); ++it) {
uint32_t dstId = it->first;
gntsToRel.push_back(dstId);
}
// release grants
for (auto it = gntsToRel.begin(); it != gntsToRel.end(); ++it) {
releaseGrant(*it, false);
}
return true;
}
if (isGranted(dstId)) {
uint32_t chNo = m_grantChTable.at(dstId);
std::tuple<uint32_t, uint8_t> slotData = m_grantChSlotTable.at(dstId);
uint8_t slot = std::get<1>(slotData);
if (m_verbose) {
LogMessage(LOG_HOST, "%s, releasing channel grant, chNo = %u, slot = %u, dstId = %u",
m_name, chNo, slot, dstId);
}
m_grantChTable[dstId] = 0U;
m_grantChSlotTable.erase(dstId);
auto it = std::find(m_rfChTable.begin(), m_rfChTable.end(), chNo);
if (it == m_rfChTable.end()) {
m_rfChTable.push_back(chNo);
}
if (m_rfGrantChCnt > 0U) {
m_rfGrantChCnt--;
}
else {
m_rfGrantChCnt = 0U;
}
m_grantTimers[dstId].stop();
return true;
}
return false;
}
/// <summary>
/// Helper to determine if the channel number is busy.
/// </summary>
/// <param name="chNo"></param>
/// <returns></returns>
bool DMRAffiliationLookup::isChBusy(uint32_t chNo) const
{
if (chNo == 0U) {
return false;
}
// lookup dynamic channel grant table entry
for (auto it = m_grantChTable.begin(); it != m_grantChTable.end(); ++it) {
if (it->second == chNo) {
uint8_t slotCount = 0U;
if (chNo == m_tsccChNo) {
slotCount++; // one slot is *always* used for TSCC
}
for (auto it = m_grantChSlotTable.begin(); it != m_grantChSlotTable.end(); ++it) {
uint32_t foundChNo = std::get<0>(it->second);
if (foundChNo == chNo)
slotCount++;
}
if (slotCount == 2U) {
return true;
} else {
return false;
}
}
}
return false;
}
/// <summary>
/// Helper to get the slot granted for the given destination ID.
/// </summary>
/// <param name="dstId"></param>
/// <returns></returns>
uint8_t DMRAffiliationLookup::getGrantedSlot(uint32_t dstId) const
{
if (dstId == 0U) {
return 0U;
}
// lookup dynamic channel grant table entry
for (auto it = m_grantChSlotTable.begin(); it != m_grantChSlotTable.end(); ++it) {
if (it->first == dstId) {
uint8_t slot = std::get<1>(it->second);
return slot;
}
}
return 0U;
}
/// <summary>
/// Helper to set a slot for the given channel as being the TSCC.
/// </summary>
/// <param name="chNo"></param>
/// <param name="slot"></param>
/// <returns></returns>
void DMRAffiliationLookup::setSlotForChannelTSCC(uint32_t chNo, uint8_t slot)
{
assert(chNo != 0U);
if ((slot == 0U) || (slot > 2U)) {
return;
}
m_tsccChNo = chNo;
m_tsccSlot = slot;
}
/// <summary>
/// Helper to determine the first available slot for given the channel number.
/// </summary>
/// <param name="chNo"></param>
/// <returns></returns>
uint8_t DMRAffiliationLookup::getAvailableSlotForChannel(uint32_t chNo) const
{
if (chNo == 0U) {
return 0U;
}
uint8_t slot = 1U;
// lookup dynamic channel slot grant table entry
bool grantedSlot = false;
int slotCount = 0U;
for (auto it = m_grantChSlotTable.begin(); it != m_grantChSlotTable.end(); ++it) {
uint32_t foundChNo = std::get<0>(it->second);
if (foundChNo == chNo)
{
uint8_t foundSlot = std::get<1>(it->second);
if (slot == foundSlot) {
switch (foundSlot) {
case 1U:
slot = 2U;
break;
case 2U:
slot = 1U;
break;
}
grantedSlot = true;
slotCount++;
}
}
}
if (slotCount == 2U) {
slot = 0U;
return slot;
}
// are we trying to assign the TSCC slot?
if (chNo == m_tsccChNo && slot == m_tsccSlot) {
if (!grantedSlot) {
// since we didn't find a slot being granted out -- utilize the slot opposing the TSCC
switch (m_tsccSlot) {
case 1U:
slot = 2U;
break;
case 2U:
slot = 1U;
break;
}
} else {
slot = 0U; // TSCC is not assignable
}
}
return slot;
}

@ -0,0 +1,77 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
/*
* Copyright (C) 2023 by Bryan Biedenkapp N2PLL
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__DMR_AFFILIATION_LOOKUP_H__)
#define __DMR_AFFILIATION_LOOKUP_H__
#include "Defines.h"
#include "lookups/AffiliationLookup.h"
#include <tuple>
namespace dmr
{
namespace lookups
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements a lookup table class that contains DMR slot grant
// information.
// ---------------------------------------------------------------------------
class HOST_SW_API DMRAffiliationLookup : public ::lookups::AffiliationLookup {
public:
/// <summary>Initializes a new instance of the DMRAffiliationLookup class.</summary>
DMRAffiliationLookup(bool verbose);
/// <summary>Finalizes a instance of the DMRAffiliationLookup class.</summary>
virtual ~DMRAffiliationLookup();
/// <summary>Helper to grant a channel.</summary>
virtual bool grantCh(uint32_t dstId, uint32_t grantTimeout);
/// <summary>Helper to grant a channel and slot.</summary>
bool grantChSlot(uint32_t dstId, uint8_t slot, uint32_t grantTimeout);
/// <summary>Helper to release the channel grant for the destination ID.</summary>
virtual bool releaseGrant(uint32_t dstId, bool releaseAll);
/// <summary>Helper to determine if the channel number is busy.</summary>
virtual bool isChBusy(uint32_t chNo) const;
/// <summary>Helper to get the slot granted for the given destination ID.</summary>
uint8_t getGrantedSlot(uint32_t dstId) const;
/// <summary>Helper to set a slot for the given channel as being the TSCC.</summary>
void setSlotForChannelTSCC(uint32_t chNo, uint8_t slot);
/// <summary>Helper to determine the first available slot for given the channel number.</summary>
uint8_t getAvailableSlotForChannel(uint32_t chNo) const;
protected:
std::unordered_map<uint32_t, std::tuple<uint32_t, uint8_t>> m_grantChSlotTable;
uint32_t m_tsccChNo;
uint8_t m_tsccSlot;
};
} // namespace lookups
} // namespace dmr
#endif // __DMR_AFFILIATION_LOOKUP_H__

@ -38,6 +38,7 @@
#include "dmr/Sync.h"
#include "edac/BPTC19696.h"
#include "edac/CRC.h"
#include "remote/RemoteCommand.h"
#include "Log.h"
#include "Utils.h"
@ -737,6 +738,8 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_
{
Slot *m_tscc = m_slot->m_dmr->getTSCCSlot();
uint8_t slot = 0U;
bool emergency = ((serviceOptions & 0xFFU) & 0x80U) == 0x80U; // Emergency Flag
bool privacy = ((serviceOptions & 0xFFU) & 0x40U) == 0x40U; // Privacy Flag
bool broadcast = ((serviceOptions & 0xFFU) & 0x10U) == 0x10U; // Broadcast Flag
@ -812,13 +815,14 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_
else {
if (m_tscc->m_affiliations->grantCh(dstId, GRANT_TIMER_TIMEOUT)) {
chNo = m_tscc->m_affiliations->getGrantedCh(dstId);
slot = m_tscc->m_affiliations->getGrantedSlot(dstId);
//m_tscc->m_siteData.setChCnt(m_tscc->m_affiliations->getRFChCnt() + m_tscc->m_affiliations->getGrantedRFChCnt());
}
}
}
else {
chNo = m_tscc->m_affiliations->getGrantedCh(dstId);
slot = m_tscc->m_affiliations->getGrantedSlot(dstId);
m_tscc->m_affiliations->touchGrant(dstId);
}
@ -829,15 +833,23 @@ 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);
}
//
// TODO TODO: Implement RCON callback for authoritative CC to trigger permit-tg
//
// callback RCON to permit-tg on the specified voice channel
if (m_tscc->m_authoritative && m_tscc->m_controlPermitTG) {
::lookups::VoiceChData voiceChData = m_tscc->m_affiliations->getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0) {
std::stringstream ss;
ss << "permit-tg " << modem::DVM_STATE::STATE_DMR << " " << dstId << " " << slot;
RemoteCommand::send(voiceChData.address(), voiceChData.port(), voiceChData.password(),
ss.str(), m_tscc->m_debug);
}
}
std::unique_ptr<CSBK_TV_GRANT> csbk = new_unique(CSBK_TV_GRANT);
if (broadcast)
csbk->setCSBKO(CSBKO_BTV_GRANT);
csbk->setLogicalCh1(chNo);
csbk->setSlotNo(1U); // eah? this can't be okay...
csbk->setSlotNo(slot);
if (m_verbose) {
LogMessage((net) ? LOG_NET : LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_GRP_VOICE_CALL (Group Voice Call), emerg = %u, privacy = %u, broadcast = %u, prio = %u, chNo = %u, slot = %u, srcId = %u, dstId = %u",
@ -856,13 +868,21 @@ 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);
}
//
// TODO TODO: Implement RCON callback for authoritative CC to trigger permit-tg
//
// callback RCON to permit-tg on the specified voice channel
if (m_tscc->m_authoritative && m_tscc->m_controlPermitTG) {
::lookups::VoiceChData voiceChData = m_tscc->m_affiliations->getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0) {
std::stringstream ss;
ss << "permit-tg " << modem::DVM_STATE::STATE_DMR << " " << dstId << " " << slot;
RemoteCommand::send(voiceChData.address(), voiceChData.port(), voiceChData.password(),
ss.str(), m_tscc->m_debug);
}
}
std::unique_ptr<CSBK_PV_GRANT> csbk = new_unique(CSBK_PV_GRANT);
csbk->setLogicalCh1(chNo);
csbk->setSlotNo(1U); // eah? this can't be okay...
csbk->setSlotNo(slot);
if (m_verbose) {
LogMessage((net) ? LOG_NET : LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_VOICE_CALL (Individual Voice Call), emerg = %u, privacy = %u, broadcast = %u, prio = %u, chNo = %u, slot = %u, srcId = %u, dstId = %u",
@ -895,6 +915,8 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u
{
Slot *m_tscc = m_slot->m_dmr->getTSCCSlot();
uint8_t slot = 0U;
bool emergency = ((serviceOptions & 0xFFU) & 0x80U) == 0x80U; // Emergency Flag
bool privacy = ((serviceOptions & 0xFFU) & 0x40U) == 0x40U; // Privacy Flag
bool broadcast = ((serviceOptions & 0xFFU) & 0x10U) == 0x10U; // Broadcast Flag
@ -970,6 +992,7 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u
else {
if (m_tscc->m_affiliations->grantCh(dstId, GRANT_TIMER_TIMEOUT)) {
chNo = m_tscc->m_affiliations->getGrantedCh(dstId);
slot = m_tscc->m_affiliations->getGrantedSlot(dstId);
//m_tscc->m_siteData.setChCnt(m_tscc->m_affiliations->getRFChCnt() + m_tscc->m_affiliations->getGrantedRFChCnt());
}
@ -977,6 +1000,7 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u
}
else {
chNo = m_tscc->m_affiliations->getGrantedCh(dstId);
slot = m_tscc->m_affiliations->getGrantedSlot(dstId);
m_tscc->m_affiliations->touchGrant(dstId);
}
@ -990,7 +1014,7 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u
std::unique_ptr<CSBK_TD_GRANT> csbk = new_unique(CSBK_TD_GRANT);
csbk->setLogicalCh1(chNo);
csbk->setSlotNo(1U); // eah? this can't be okay...
csbk->setSlotNo(slot);
if (m_verbose) {
LogMessage((net) ? LOG_NET : LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_GRP_DATA_CALL (Group Data Call), emerg = %u, privacy = %u, broadcast = %u, prio = %u, chNo = %u, slot = %u, srcId = %u, dstId = %u",
@ -1011,7 +1035,7 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u
std::unique_ptr<CSBK_PD_GRANT> csbk = new_unique(CSBK_PD_GRANT);
csbk->setLogicalCh1(chNo);
csbk->setSlotNo(1U); // eah? this can't be okay...
csbk->setSlotNo(slot);
if (m_verbose) {
LogMessage((net) ? LOG_NET : LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_RAND (Random Access), SVC_KIND_IND_DATA_CALL (Individual Data Call), emerg = %u, privacy = %u, broadcast = %u, prio = %u, chNo = %u, slot = %u, srcId = %u, dstId = %u",

@ -140,6 +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_activeTickDelay(5U),
m_idleTickDelay(5U),
m_remoteControl(nullptr)
@ -433,7 +434,7 @@ int Host::run()
dmr = std::unique_ptr<dmr::Control>(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_voiceChNo, m_voiceChData, m_dmrNetId, m_siteId, m_channelId, m_channelNo, true);
dmr->setOptions(m_conf, m_controlPermitTG, m_voiceChNo, m_voiceChData, m_dmrNetId, m_siteId, m_channelId, m_channelNo, true);
if (dmrCtrlChannel) {
dmr->setCCRunning(true);
@ -506,7 +507,7 @@ int Host::run()
p25 = std::unique_ptr<p25::Control>(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_cwCallsign, m_voiceChNo, m_voiceChData, m_p25PatchSuperGroup, m_p25NetId, m_p25SysId, m_p25RfssId,
p25->setOptions(m_conf, m_controlPermitTG, m_cwCallsign, m_voiceChNo, m_voiceChData, m_p25PatchSuperGroup, m_p25NetId, m_p25SysId, m_p25RfssId,
m_siteId, m_channelId, m_channelNo, true);
if (p25CtrlChannel) {
@ -571,7 +572,7 @@ int Host::run()
nxdn = std::unique_ptr<nxdn::Control>(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_cwCallsign, m_voiceChNo, m_voiceChData, m_siteId, m_channelId, m_channelNo, true);
nxdn->setOptions(m_conf, m_controlPermitTG, m_cwCallsign, m_voiceChNo, m_voiceChData, m_siteId, m_channelId, m_channelNo, true);
if (nxdnCtrlChannel) {
nxdn->setCCRunning(true);
@ -1925,7 +1926,11 @@ bool Host::readParams()
LogInfo(" P25 RFSS Id: $%02X", m_p25RfssId);
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<bool>(false);
LogInfo(" Control Permit TG: %s", m_controlPermitTG ? "yes" : "no");
}
}
else {

@ -147,6 +147,7 @@ private:
uint32_t m_nxdnQueueSizeBytes;
bool m_authoritative;
bool m_controlPermitTG;
uint8_t m_activeTickDelay;
uint8_t m_idleTickDelay;

@ -94,6 +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_ran(ran),
m_timeout(timeout),
m_modem(modem),
@ -203,6 +204,7 @@ void Control::reset()
/// Helper to set NXDN configuration options.
/// </summary>
/// <param name="conf">Instance of the yaml::Node class.</param>
/// <param name="controlPermitTG"></param>
/// <param name="cwCallsign"></param>
/// <param name="voiceChNo">Voice Channel Number list.</param>
/// <param name="voiceChData">Voice Channel data map.</param>
@ -210,13 +212,15 @@ void Control::reset()
/// <param name="channelId">Channel ID.</param>
/// <param name="channelNo">Channel Number.</param>
/// <param name="printOptions"></param>
void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const std::vector<uint32_t> voiceChNo,
void Control::setOptions(yaml::Node& conf, bool controlPermitTG, const std::string cwCallsign, const std::vector<uint32_t> voiceChNo,
const std::unordered_map<uint32_t, lookups::VoiceChData> voiceChData, uint16_t locId,
uint8_t channelId, uint32_t channelNo, bool printOptions)
{
yaml::Node systemConf = conf["system"];
yaml::Node nxdnProtocol = conf["protocols"]["nxdn"];
m_controlPermitTG = controlPermitTG;
m_trunk->m_verifyAff = nxdnProtocol["verifyAff"].as<bool>(false);
m_trunk->m_verifyReg = nxdnProtocol["verifyReg"].as<bool>(false);

@ -83,7 +83,7 @@ namespace nxdn
void reset();
/// <summary>Helper to set NXDN configuration options.</summary>
void setOptions(yaml::Node& conf, const std::string cwCallsign, const std::vector<uint32_t> voiceChNo,
void setOptions(yaml::Node& conf, bool controlPermitTG, const std::string cwCallsign, const std::vector<uint32_t> voiceChNo,
const std::unordered_map<uint32_t, lookups::VoiceChData> voiceChData, uint16_t locId,
uint8_t channelId, uint32_t channelNo, bool printOptions);
@ -130,6 +130,7 @@ namespace nxdn
packet::Trunk* m_trunk;
bool m_authoritative;
bool m_controlPermitTG;
uint32_t m_ran;
uint32_t m_timeout;

@ -36,6 +36,7 @@
#include "nxdn/Sync.h"
#include "nxdn/NXDNUtils.h"
#include "edac/CRC.h"
#include "remote/RemoteCommand.h"
#include "HostMain.h"
#include "Log.h"
#include "Utils.h"
@ -508,9 +509,18 @@ bool Trunk::writeRF_Message_Grant(uint32_t srcId, uint32_t dstId, uint8_t servic
}
}
//
// TODO TODO: Implement RCON callback for authoritative CC to trigger permit-tg
//
// callback RCON to permit-tg on the specified voice channel
if (m_nxdn->m_authoritative && m_nxdn->m_controlPermitTG) {
::lookups::VoiceChData voiceChData = m_nxdn->m_affiliations.getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0 &&
chNo != m_nxdn->m_siteData.channelNo()) {
std::stringstream ss;
ss << "permit-tg " << modem::DVM_STATE::STATE_NXDN << " " << dstId;
RemoteCommand::send(voiceChData.address(), voiceChData.port(), voiceChData.password(),
ss.str(), m_nxdn->m_debug);
}
}
std::unique_ptr<rcch::MESSAGE_TYPE_VCALL_CONN> rcch = new_unique(rcch::MESSAGE_TYPE_VCALL_CONN);
rcch->setMessageType(RTCH_MESSAGE_TYPE_VCALL);

@ -90,6 +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_nac(nac),
m_txNAC(nac),
m_timeout(timeout),
@ -207,6 +208,7 @@ void Control::reset()
/// Helper to set P25 configuration options.
/// </summary>
/// <param name="conf">Instance of the yaml::Node class.</param>
/// <param name="controlPermitTG"></param>
/// <param name="cwCallsign"></param>
/// <param name="voiceChNo">Voice Channel Number list.</param>
/// <param name="voiceChData">Voice Channel data map.</param>
@ -218,13 +220,15 @@ void Control::reset()
/// <param name="channelId">Channel ID.</param>
/// <param name="channelNo">Channel Number.</param>
/// <param name="printOptions"></param>
void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const std::vector<uint32_t> voiceChNo,
void Control::setOptions(yaml::Node& conf, bool controlPermitTG, const std::string cwCallsign, const std::vector<uint32_t> voiceChNo,
const std::unordered_map<uint32_t, ::lookups::VoiceChData> 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_tduPreambleCount = p25Protocol["tduPreambleCount"].as<uint32_t>(8U);
m_trunk->m_patchSuperGroup = pSuperGroup;

@ -85,7 +85,7 @@ namespace p25
void reset();
/// <summary>Helper to set P25 configuration options.</summary>
void setOptions(yaml::Node& conf, const std::string cwCallsign, const std::vector<uint32_t> voiceChNo,
void setOptions(yaml::Node& conf, bool controlPermitTG, const std::string cwCallsign, const std::vector<uint32_t> voiceChNo,
const std::unordered_map<uint32_t, ::lookups::VoiceChData> voiceChData, uint32_t pSuperGroup, uint32_t netId,
uint32_t sysId, uint8_t rfssId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, bool printOptions);
@ -146,6 +146,7 @@ namespace p25
friend class lookups::P25AffiliationLookup;
bool m_authoritative;
bool m_controlPermitTG;
uint32_t m_nac;
uint32_t m_txNAC;

@ -35,6 +35,7 @@
#include "p25/P25Utils.h"
#include "p25/Sync.h"
#include "edac/CRC.h"
#include "remote/RemoteCommand.h"
#include "Log.h"
#include "Utils.h"
@ -2221,9 +2222,18 @@ 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);
}
//
// TODO TODO: Implement RCON callback for authoritative CC to trigger permit-tg
//
// callback RCON to permit-tg on the specified voice channel
if (m_p25->m_authoritative && m_p25->m_controlPermitTG) {
::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0 &&
chNo != m_p25->m_siteData.channelNo()) {
std::stringstream ss;
ss << "permit-tg " << modem::DVM_STATE::STATE_P25 << " " << dstId;
RemoteCommand::send(voiceChData.address(), voiceChData.port(), voiceChData.password(),
ss.str(), m_p25->m_debug);
}
}
std::unique_ptr<IOSP_GRP_VCH> iosp = new_unique(IOSP_GRP_VCH);
iosp->setMFId(m_lastMFID);
@ -2247,9 +2257,18 @@ 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);
}
//
// TODO TODO: Implement RCON callback for authoritative CC to trigger permit-tg
//
// callback RCON to permit-tg on the specified voice channel
if (m_p25->m_authoritative && m_p25->m_controlPermitTG) {
::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0 &&
chNo != m_p25->m_siteData.channelNo()) {
std::stringstream ss;
ss << "permit-tg " << modem::DVM_STATE::STATE_P25 << " " << dstId;
RemoteCommand::send(voiceChData.address(), voiceChData.port(), voiceChData.password(),
ss.str(), m_p25->m_debug);
}
}
std::unique_ptr<IOSP_UU_VCH> iosp = new_unique(IOSP_UU_VCH);
iosp->setMFId(m_lastMFID);

@ -96,6 +96,25 @@ RemoteCommand::~RemoteCommand()
/// <returns>EXIT_SUCCESS, if command was sent, otherwise EXIT_FAILURE.</returns>
int RemoteCommand::send(const std::string& command)
{
assert(!m_address.empty());
assert(m_port > 0U);
return send(m_address, m_port, m_password, command, m_debug);
}
/// <summary>
/// Sends remote control command to the specified modem.
/// </summary>
/// <param name="address">Network Hostname/IP address to connect to.</param>
/// <param name="port">Network port number.</param>
/// <param name="password">Authentication password.</param>
/// <param name="command">Command string to send to remote modem.</param>
/// <param name="debug">Flag indicating whether debug is enabled.</param>
/// <returns>EXIT_SUCCESS, if command was sent, otherwise EXIT_FAILURE.</returns>
int RemoteCommand::send(const std::string& address, uint32_t port, const std::string& password, const std::string& command, bool debug)
{
assert(!address.empty());
assert(port > 0U);
UDPSocket socket(0U);
bool ret = socket.open();
@ -108,22 +127,22 @@ int RemoteCommand::send(const std::string& command)
sockaddr_storage addr;
uint32_t addrLen;
if (UDPSocket::lookup(m_address, m_port, addr, addrLen) != 0) {
if (UDPSocket::lookup(address, port, addr, addrLen) != 0) {
::LogError(LOG_HOST, "Could not lookup the address of remote");
return ERRNO_ADDR_LOOKUP;
}
::LogInfoEx(LOG_HOST, "sending RCON command \"%s\" to %s:%u", command.c_str(), m_address.c_str(), m_port);
::LogInfoEx(LOG_HOST, "sending RCON command \"%s\" to %s:%u", command.c_str(), address.c_str(), port);
buffer[0U] = RCON_FRAME_START;
buffer[1U] = START_OF_TEXT;
if (!m_password.empty()) {
size_t size = m_password.size();
if (!password.empty()) {
size_t size = password.size();
uint8_t* in = new uint8_t[size];
for (size_t i = 0U; i < size; i++)
in[i] = m_password.at(i);
in[i] = password.at(i);
uint8_t out[32U];
::memset(out, 0x00U, 32U);
@ -139,7 +158,7 @@ int RemoteCommand::send(const std::string& command)
buffer[35U + command.size()] = END_OF_TEXT;
if (m_debug)
if (debug)
Utils::dump(1U, "RCON Sent", (uint8_t*)buffer, 36U + command.size());
ret = socket.write((uint8_t *)buffer, 36U + command.size(), addr, addrLen);
@ -166,23 +185,23 @@ int RemoteCommand::send(const std::string& command)
if (offs + len > RESPONSE_BUFFER_LEN)
break;
if (m_debug)
if (debug)
::LogDebug(LOG_RCON, "RemoteCommand::send() block len = %u, offs = %u", len - 3, offs);
buffer[len] = '\0';
if (m_debug)
if (debug)
Utils::dump(1U, "RCON Received", (uint8_t*)buffer, len);
// make sure this is an RCON response
if (buffer[0U] != RCON_FRAME_START) {
::LogError(LOG_HOST, "Invalid response from host %s:%u", m_address.c_str(), m_port);
::LogError(LOG_HOST, "Invalid response from host %s:%u", address.c_str(), port);
socket.close();
return EXIT_FAILURE;
}
if (buffer[1U] != START_OF_TEXT) {
::LogError(LOG_HOST, "Invalid response from host %s:%u", m_address.c_str(), m_port);
::LogError(LOG_HOST, "Invalid response from host %s:%u", address.c_str(), port);
socket.close();
return EXIT_FAILURE;
}

@ -51,6 +51,9 @@ public:
/// <summary>Sends remote control command to the specified modem.</summary>
int send(const std::string& command);
/// <summary>Sends remote control command to the specified modem.</summary>
static int send(const std::string& address, uint32_t port, const std::string& password, const std::string& command, bool debug = false);
private:
std::string m_address;
uint32_t m_port;

Loading…
Cancel
Save

Powered by TurnKey Linux.