/** * 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 #include #include #include // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- /// /// Initializes a new instance of the AffiliationLookup class. /// /// Name of lookup table. /// Flag indicating whether verbose logging is enabled. AffiliationLookup::AffiliationLookup(const char* name, bool verbose) : m_rfChTable(), m_rfChDataTable(), 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(); } /// /// Finalizes a instance of the AffiliationLookup class. /// AffiliationLookup::~AffiliationLookup() { /* stub */ } /// /// Helper to group affiliate a source ID. /// /// 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); } } /// /// Helper to group unaffiliate a source ID. /// /// 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; } /// /// Helper to determine if the source ID has unit registered. /// /// /// 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; } } /// /// Helper to group affiliate a source ID. /// /// /// 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); } } } /// /// Helper to group unaffiliate a source ID. /// /// 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; } } /// /// Helper to determine if the source ID has affiliated to the group destination ID. /// /// /// /// 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; } } /// /// Helper to release group affiliations. /// /// /// std::vector AffiliationLookup::clearGroupAff(uint32_t dstId, bool releaseAll) { std::vector srcToRel = std::vector(); 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; } /// /// Helper to grant a channel. /// /// /// /// 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; } /// /// Helper to start the destination ID grant timer. /// /// /// void AffiliationLookup::touchGrant(uint32_t dstId) { if (dstId == 0U) { return; } if (isGranted(dstId)) { m_grantTimers[dstId].start(); } } /// /// Helper to release the channel grant for the destination ID. /// /// /// 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 gntsToRel = std::vector(); 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; } /// /// Helper to determine if the channel number is busy. /// /// /// 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; } /// /// Helper to determine if the destination ID is already granted. /// /// /// 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; } } /// /// Helper to get the channel granted for the given destination ID. /// /// /// uint32_t AffiliationLookup::getGrantedCh(uint32_t dstId) { if (dstId == 0U) { return 0U; } if (isGranted(dstId)) { return m_grantChTable[dstId]; } return 0U; } /// /// Helper to get RF channel data. /// /// /// VoiceChData AffiliationLookup::getRFChData(uint32_t chNo) const { if (chNo == 0U) { return VoiceChData(); } VoiceChData data; try { data = m_rfChDataTable.at(chNo); } catch (...) { data = VoiceChData(); } return VoiceChData(); } /// /// Updates the processor by the passed number of milliseconds. /// /// void AffiliationLookup::clock(uint32_t ms) { // clock all the grant timers std::vector gntsToRel = std::vector(); 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); } }