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.
dvmhost/lookups/AffiliationLookup.cpp

426 lines
11 KiB

/**
* 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) 2022 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 "lookups/AffiliationLookup.h"
#include "Log.h"
using namespace lookups;
#include <cassert>
#include <cstdio>
#include <cstring>
#include <ctime>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the AffiliationLookup class.
/// </summary>
/// <param name="name">Name of lookup table.</param>
/// <param name="verbose">Flag indicating whether verbose logging is enabled.</param>
AffiliationLookup::AffiliationLookup(const char* name, bool verbose) :
m_rfChTable(),
m_rfGrantChCnt(0U),
m_unitRegTable(),
m_grpAffTable(),
m_grantChTable(),
m_grantTimers(),
m_name(name),
m_verbose(verbose)
{
m_rfChTable.clear();
m_unitRegTable.clear();
m_grpAffTable.clear();
m_grantChTable.clear();
m_grantTimers.clear();
}
/// <summary>
/// Finalizes a instance of the AffiliationLookup class.
/// </summary>
AffiliationLookup::~AffiliationLookup()
{
/* stub */
}
/// <summary>
/// Helper to group affiliate a source ID.
/// </summary>
/// <param name="srcId"></param>
void AffiliationLookup::unitReg(uint32_t srcId)
{
if (isUnitReg(srcId)) {
return;
}
m_unitRegTable.push_back(srcId);
if (m_verbose) {
LogMessage(LOG_HOST, "%s, unit registration, srcId = %u",
m_name, srcId);
}
}
/// <summary>
/// Helper to group unaffiliate a source ID.
/// </summary>
/// <param name="srcId"></param>
bool AffiliationLookup::unitDereg(uint32_t srcId)
{
bool ret = false;
if (!isUnitReg(srcId)) {
return false;
}
if (m_verbose) {
LogMessage(LOG_HOST, "%s, unit deregistration, srcId = %u",
m_name, srcId);
}
groupUnaff(srcId);
// remove dynamic unit registration table entry
if (std::find(m_unitRegTable.begin(), m_unitRegTable.end(), srcId) != m_unitRegTable.end()) {
auto it = std::find(m_unitRegTable.begin(), m_unitRegTable.end(), srcId);
m_unitRegTable.erase(it);
ret = true;
}
return ret;
}
/// <summary>
/// Helper to determine if the source ID has unit registered.
/// </summary>
/// <param name="srcId"></param>
/// <returns></returns>
bool AffiliationLookup::isUnitReg(uint32_t srcId) const
{
// lookup dynamic unit registration table entry
if (std::find(m_unitRegTable.begin(), m_unitRegTable.end(), srcId) != m_unitRegTable.end()) {
return true;
}
else {
return false;
}
}
/// <summary>
/// Helper to group affiliate a source ID.
/// </summary>
/// <param name="srcId"></param>
/// <param name="dstId"></param>
void AffiliationLookup::groupAff(uint32_t srcId, uint32_t dstId)
{
if (!isGroupAff(srcId, dstId)) {
// update dynamic affiliation table
m_grpAffTable[srcId] = dstId;
if (m_verbose) {
LogMessage(LOG_HOST, "%s, group affiliation, srcId = %u, dstId = %u",
m_name, srcId, dstId);
}
}
}
/// <summary>
/// Helper to group unaffiliate a source ID.
/// </summary>
/// <param name="srcId"></param>
bool AffiliationLookup::groupUnaff(uint32_t srcId)
{
// lookup dynamic affiliation table entry
try {
uint32_t tblDstId = m_grpAffTable.at(srcId);
if (m_verbose) {
LogMessage(LOG_HOST, "%s, group unaffiliation, srcId = %u, dstId = %u",
m_name, srcId, tblDstId);
}
} catch (...) {
return false;
}
// remove dynamic affiliation table entry
try {
m_grpAffTable.at(srcId);
m_grpAffTable.erase(srcId);
return true;
}
catch (...) {
return false;
}
}
/// <summary>
/// Helper to determine if the source ID has affiliated to the group destination ID.
/// </summary>
/// <param name="srcId"></param>
/// <param name="dstId"></param>
/// <returns></returns>
bool AffiliationLookup::isGroupAff(uint32_t srcId, uint32_t dstId) const
{
// lookup dynamic affiliation table entry
try {
uint32_t tblDstId = m_grpAffTable.at(srcId);
if (tblDstId == dstId) {
return true;
}
else {
return false;
}
} catch (...) {
return false;
}
}
/// <summary>
/// Helper to release group affiliations.
/// </summary>
/// <param name="dstId"></param>
/// <param name="releaseAll"></param>
std::vector<uint32_t> AffiliationLookup::clearGroupAff(uint32_t dstId, bool releaseAll)
{
std::vector<uint32_t> srcToRel = std::vector<uint32_t>();
if (dstId == 0U && !releaseAll) {
return srcToRel;
}
if (dstId == 0U && releaseAll) {
LogWarning(LOG_HOST, "%s, releasing all group affiliations", m_name);
for (auto it = m_grpAffTable.begin(); it != m_grpAffTable.end(); ++it) {
uint32_t srcId = it->first;
srcToRel.push_back(srcId);
}
}
else {
LogWarning(LOG_HOST, "%s, releasing group affiliations, dstId = %u", m_name, dstId);
for (auto it = m_grpAffTable.begin(); it != m_grpAffTable.end(); ++it) {
uint32_t srcId = it->first;
uint32_t grpId = it->second;
if (grpId == dstId) {
srcToRel.push_back(srcId);
}
}
}
return srcToRel;
}
/// <summary>
/// Helper to grant a channel.
/// </summary>
/// <param name="dstId"></param>
/// <param name="grantTimeout"></param>
/// <returns></returns>
bool AffiliationLookup::grantCh(uint32_t dstId, uint32_t grantTimeout)
{
if (dstId == 0U) {
return false;
}
if (!isRFChAvailable()) {
return false;
}
uint32_t chNo = m_rfChTable.at(0);
auto it = std::find(m_rfChTable.begin(), m_rfChTable.end(), chNo);
m_rfChTable.erase(it);
m_grantChTable[dstId] = chNo;
m_rfGrantChCnt++;
m_grantTimers[dstId] = Timer(1000U, grantTimeout);
m_grantTimers[dstId].start();
if (m_verbose) {
LogMessage(LOG_HOST, "%s, granting channel, chNo = %u, dstId = %u",
m_name, chNo, dstId);
}
return true;
}
/// <summary>
/// Helper to start the destination ID grant timer.
/// </summary>
/// <param name="dstId"></param>
/// <returns></returns>
void AffiliationLookup::touchGrant(uint32_t dstId)
{
if (dstId == 0U) {
return;
}
if (isGranted(dstId)) {
m_grantTimers[dstId].start();
}
}
/// <summary>
/// Helper to release the channel grant for the destination ID.
/// </summary>
/// <param name="dstId"></param>
/// <param name="releaseAll"></param>
bool AffiliationLookup::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);
if (m_verbose) {
LogMessage(LOG_HOST, "%s, releasing channel grant, chNo = %u, dstId = %u",
m_name, chNo, dstId);
}
m_grantChTable[dstId] = 0U;
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 AffiliationLookup::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) {
return true;
}
}
return false;
}
/// <summary>
/// Helper to determine if the destination ID is already granted.
/// </summary>
/// <param name="dstId"></param>
/// <returns></returns>
bool AffiliationLookup::isGranted(uint32_t dstId) const
{
if (dstId == 0U) {
return false;
}
// lookup dynamic channel grant table entry
try {
uint32_t chNo = m_grantChTable.at(dstId);
if (chNo != 0U) {
return true;
}
else {
return false;
}
} catch (...) {
return false;
}
}
/// <summary>
/// Helper to get the channel granted for the given destination ID.
/// </summary>
/// <param name="dstId"></param>
/// <returns></returns>
uint32_t AffiliationLookup::getGrantedCh(uint32_t dstId)
{
if (dstId == 0U) {
return 0U;
}
if (isGranted(dstId)) {
return m_grantChTable[dstId];
}
return 0U;
}
/// <summary>
/// Updates the processor by the passed number of milliseconds.
/// </summary>
/// <param name="ms"></param>
void AffiliationLookup::clock(uint32_t ms)
{
// clock all the grant timers
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;
m_grantTimers[dstId].clock(ms);
if (m_grantTimers[dstId].isRunning() && m_grantTimers[dstId].hasExpired()) {
gntsToRel.push_back(dstId);
}
}
// release grants that have timed out
for (auto it = gntsToRel.begin(); it != gntsToRel.end(); ++it) {
releaseGrant(*it, false);
}
}

Powered by TurnKey Linux.