From 08dd49d51f2d9f20961e5a4eb80d7c4bed1ca21a Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Wed, 1 Dec 2021 22:56:50 +0000 Subject: [PATCH] fix incorrect handling of channel number as decimal in setup; enhance setup to make it more comprehensive (essentially all "system" configuration parameters can be modified in setup mode); add support to calibration to set the FDMA preambles, P25 correlation count, DMR Rx Delay as well as setting the Rx and Tx frequency offsets; --- DVMHost.vcxproj | 1 + DVMHost.vcxproj.filters | 3 + Defines.h | 6 + dmr/DMRUtils.h | 143 ++++++++++++++ dmr/SiteData.h | 66 +------ host/Host.cpp | 63 ++----- host/calibrate/HostCal.cpp | 172 +++++++++++++++-- host/calibrate/HostCal.h | 5 + host/setup/HostSetup.cpp | 373 +++++++++++++++++++++++++++---------- host/setup/HostSetup.h | 2 - p25/P25Utils.h | 70 ++++++- p25/SiteData.h | 56 ++---- 12 files changed, 692 insertions(+), 268 deletions(-) create mode 100644 dmr/DMRUtils.h diff --git a/DVMHost.vcxproj b/DVMHost.vcxproj index 5b709d4b..2f218a70 100644 --- a/DVMHost.vcxproj +++ b/DVMHost.vcxproj @@ -163,6 +163,7 @@ + diff --git a/DVMHost.vcxproj.filters b/DVMHost.vcxproj.filters index e413b15e..b5ff3973 100644 --- a/DVMHost.vcxproj.filters +++ b/DVMHost.vcxproj.filters @@ -362,6 +362,9 @@ Header Files\host\setup + + Header Files\dmr + diff --git a/Defines.h b/Defines.h index 04f45862..3578db84 100644 --- a/Defines.h +++ b/Defines.h @@ -178,6 +178,12 @@ inline std::string __INT_STR(const int& value) { return ss.str(); } +inline std::string __INT_HEX_STR(const int& value) { + std::stringstream ss; + ss << std::hex << value; + return ss.str(); +} + inline std::string __FLOAT_STR(const float& value) { std::stringstream ss; ss << value; diff --git a/dmr/DMRUtils.h b/dmr/DMRUtils.h new file mode 100644 index 00000000..d8493c3e --- /dev/null +++ b/dmr/DMRUtils.h @@ -0,0 +1,143 @@ +/** +* 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 +* +*/ +// +// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost) +// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) +// +/* +* Copyright (C) 2021 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_UTILS_H__) +#define __DMR_UTILS_H__ + +#include "Defines.h" +#include "dmr/DMRDefines.h" + +namespace dmr +{ + // --------------------------------------------------------------------------- + // Class Declaration + // This class implements various helper functions for validating DMR data. + // --------------------------------------------------------------------------- + + class HOST_SW_API DMRUtils { + public: + /// Helper to test and clamp a DMR color code. + static uint32_t colorCode(uint32_t colorCode) + { + if (colorCode < 0U) { // clamp to 0 + colorCode = 0U; + } + if (colorCode > 15U) { // clamp to 15 + colorCode = 15U; + } + + return colorCode; + } + + /// Helper to test and clamp a DMR site ID. + static uint32_t siteId(uint32_t id, uint8_t siteModel) + { + if (id == 0U) { // clamp to 1 + id = 1U; + } + + switch (siteModel) + { + case SITE_MODEL_TINY: + { + if (id > 0x07U) { // clamp to $7 + id = 0x07U; + } + } + break; + case SITE_MODEL_SMALL: + { + if (id > 0x1FU) { // clamp to $1F + id = 0x1FU; + } + } + break; + case SITE_MODEL_LARGE: + { + if (id > 0xFFU) { // clamp to $FF + id = 0xFFU; + } + } + break; + case SITE_MODEL_HUGE: + { + if (id > 0x7FFU) { // clamp to $7FF + id = 0x7FFU; + } + } + break; + } + + return id; + } + + /// Helper to test and clamp a DMR network ID. + static uint32_t netId(uint32_t id, uint8_t siteModel) + { + if (id == 0U) { // clamp to 1 + id = 1U; + } + + switch (siteModel) { + case SITE_MODEL_TINY: + { + if (id > 0x1FFU) { // clamp to $1FF + id = 0x1FFU; + } + } + break; + case SITE_MODEL_SMALL: + { + if (id > 0x7FU) { // clamp to $7F + id = 0x7FU; + } + } + break; + case SITE_MODEL_LARGE: + { + if (id > 0x1FU) { // clamp to $1F + id = 0x1FU; + } + } + break; + case SITE_MODEL_HUGE: + { + if (id > 0x03U) { // clamp to $3 + id = 0x03U; + } + } + break; + } + + return id; + } + }; +} // namespace dmr + +#endif // __DMR_UTILS_H__ diff --git a/dmr/SiteData.h b/dmr/SiteData.h index 3c637a74..704842d6 100644 --- a/dmr/SiteData.h +++ b/dmr/SiteData.h @@ -32,6 +32,7 @@ #include "Defines.h" #include "dmr/DMRDefines.h" +#include "dmr/DMRUtils.h" namespace dmr { @@ -72,71 +73,10 @@ namespace dmr siteModel = SITE_MODEL_SMALL; // netId clamping - if (netId == 0U) // clamp to 1 - netId = 1U; - - switch (siteModel) { - case SITE_MODEL_TINY: - { - if (netId > 0x1FFU) // clamp to $1FF - netId = 0x1FFU; - } - break; - case SITE_MODEL_SMALL: - { - if (netId > 0x7FU) // clamp to $7F - netId = 0x7FU; - } - break; - case SITE_MODEL_LARGE: - { - if (netId > 0x1FU) // clamp to $1F - netId = 0x1FU; - } - break; - case SITE_MODEL_HUGE: - { - if (netId > 0x03U) // clamp to $3 - netId = 0x03U; - } - break; - } - - m_netId = netId; + m_netId = DMRUtils::netId(netId, siteModel); // siteId clamping - if (siteId == 0U) // clamp to 1 - siteId = 1U; - - switch (siteModel) - { - case SITE_MODEL_TINY: - { - if (siteId > 0x07U) // clamp to $7 - siteId = 0x07U; - } - break; - case SITE_MODEL_SMALL: - { - if (siteId > 0x1FU) // clamp to $1F - siteId = 0x1FU; - } - break; - case SITE_MODEL_LARGE: - { - if (siteId > 0xFFU) // clamp to $FF - siteId = 0xFFU; - } - break; - case SITE_MODEL_HUGE: - { - if (siteId > 0x7FFU) // clamp to $7FF - siteId = 0x7FFU; - } - break; - } - - m_siteId = siteId; + m_siteId = DMRUtils::siteId(siteId, siteModel); // parId clamping if (parId == 0U) diff --git a/host/Host.cpp b/host/Host.cpp index a3afdfeb..67f0831c 100644 --- a/host/Host.cpp +++ b/host/Host.cpp @@ -31,7 +31,9 @@ */ #include "Defines.h" #include "dmr/Control.h" +#include "dmr/DMRUtils.h" #include "p25/Control.h" +#include "p25/P25Utils.h" #include "modem/port/ModemNullPort.h" #include "modem/port/UARTPort.h" #include "modem/port/UDPPort.h" @@ -1410,59 +1412,26 @@ bool Host::readParams() strVoiceChNo.erase(strVoiceChNo.find_last_of(",")); m_siteId = (uint8_t)::strtoul(rfssConfig["siteId"].as("1").c_str(), NULL, 16); - if (m_siteId == 0U) { // clamp to 1 - m_siteId = 1U; - } - if (m_siteId > 0xFEU) { // clamp to $FE - m_siteId = 0xFEU; - } + m_siteId = p25::P25Utils::siteId(m_siteId); m_dmrColorCode = rfssConfig["colorCode"].as(2U); - if (m_dmrColorCode < 0U) { // clamp to 0 - m_dmrColorCode = 0U; - } - if (m_dmrColorCode > 15U) { // clamp to 15 - m_dmrColorCode = 15U; - } + m_dmrColorCode = dmr::DMRUtils::colorCode(m_dmrColorCode); m_dmrNetId = (uint32_t)::strtoul(rfssConfig["dmrNetId"].as("1").c_str(), NULL, 16); - if (m_dmrNetId == 0U) { // clamp to 1 - m_dmrNetId = 1U; - } - if (m_dmrNetId > 0x1FFU) { // clamp to $1FF - m_dmrNetId = 0x1FFU; - } + m_dmrNetId = dmr::DMRUtils::netId(m_dmrNetId, dmr::SITE_MODEL_TINY); m_p25NAC = (uint32_t)::strtoul(rfssConfig["nac"].as("293").c_str(), NULL, 16); - if (m_p25NAC < 0U) { // clamp to $000 - m_p25NAC = 0U; - } - if (m_p25NAC > 0xF7DU) { // clamp to $F7D - m_p25NAC = 0xF7DU; - } + m_p25NAC = p25::P25Utils::nac(m_p25NAC); m_p25PatchSuperGroup = (uint32_t)::strtoul(rfssConfig["pSuperGroup"].as("FFFF").c_str(), NULL, 16); m_p25NetId = (uint32_t)::strtoul(rfssConfig["netId"].as("BB800").c_str(), NULL, 16); - if (m_p25NetId == 0U) { // clamp to 1 - m_p25NetId = 1U; - } - if (m_p25NetId > 0xFFFFEU) { // clamp to $FFFFE - m_p25NetId = 0xFFFFEU; - } + m_p25NetId = p25::P25Utils::netId(m_p25NetId); + m_p25SysId = (uint32_t)::strtoul(rfssConfig["sysId"].as("001").c_str(), NULL, 16); - if (m_p25SysId == 0U) { // clamp to 1 - m_p25SysId = 1U; - } - if (m_p25SysId > 0xFFEU) { // clamp to $FFE - m_p25SysId = 0xFFEU; - } + m_p25SysId = p25::P25Utils::sysId(m_p25SysId); + m_p25RfssId = (uint8_t)::strtoul(rfssConfig["rfssId"].as("1").c_str(), NULL, 16); - if (m_p25RfssId == 0U) { // clamp to 1 - m_p25RfssId = 1U; - } - if (m_p25RfssId > 0xFEU) { // clamp to $FE - m_p25RfssId = 0xFEU; - } + m_p25RfssId = p25::P25Utils::rfssId(m_p25RfssId); LogInfo("System Config Parameters"); LogInfo(" RX Frequency: %uHz", m_rxFrequency); @@ -1625,8 +1594,8 @@ bool Host::createModem() } // apply the frequency tuning offsets - int adjustedRx = m_rxFrequency + rxTuning; - int adjustedTx = m_txFrequency + txTuning; + uint32_t rxActualFreq = m_rxFrequency + rxTuning; + uint32_t txActualFreq = m_txFrequency + txTuning; LogInfo(" RX Invert: %s", rxInvert ? "yes" : "no"); LogInfo(" TX Invert: %s", txInvert ? "yes" : "no"); @@ -1640,8 +1609,8 @@ bool Host::createModem() LogInfo(" TX DC Offset: %d", txDCOffset); LogInfo(" RX Tuning Offset: %dhz", rxTuning); LogInfo(" TX Tuning Offset: %dhz", txTuning); - LogInfo(" RX Effective Frequency: %dhz", adjustedRx); - LogInfo(" TX Effective Frequency: %dhz", adjustedTx); + LogInfo(" RX Effective Frequency: %uhz", rxActualFreq); + LogInfo(" TX Effective Frequency: %uhz", txActualFreq); LogInfo(" RF Power Level: %u", rfPower); LogInfo(" RX Level: %.1f%%", rxLevel); LogInfo(" CW Id TX Level: %.1f%%", cwIdTXLevel); @@ -1659,7 +1628,7 @@ bool Host::createModem() m_modem->setLevels(rxLevel, cwIdTXLevel, dmrTXLevel, p25TXLevel); m_modem->setSymbolAdjust(dmrSymLevel3Adj, dmrSymLevel1Adj, p25SymLevel3Adj, p25SymLevel1Adj); m_modem->setDCOffsetParams(txDCOffset, rxDCOffset); - m_modem->setRFParams(adjustedRx, adjustedTx, rfPower); + m_modem->setRFParams(rxActualFreq, txActualFreq, rfPower); m_modem->setDMRColorCode(m_dmrColorCode); m_modem->setP25NAC(m_p25NAC); diff --git a/host/calibrate/HostCal.cpp b/host/calibrate/HostCal.cpp index d14d82d3..f682254f 100644 --- a/host/calibrate/HostCal.cpp +++ b/host/calibrate/HostCal.cpp @@ -152,8 +152,12 @@ HostCal::HostCal(const std::string& confFile) : m_debug(false), m_mode(STATE_DMR_CAL), m_modeStr(DMR_CAL_STR), + m_rxTuning(0), + m_txTuning(0), m_rxFrequency(0U), + m_rxAdjustedFreq(0U), m_txFrequency(0U), + m_txAdjustedFreq(0U), m_channelId(0U), m_channelNo(0U), m_idenTable(NULL), @@ -269,6 +273,18 @@ int HostCal::run() yaml::Node modemConf = systemConf["modem"]; + m_rxTuning = modemConf["rxTuning"].as(0); + m_txTuning = modemConf["txTuning"].as(0); + + // apply the frequency tuning offsets + m_rxAdjustedFreq = m_rxFrequency + m_rxTuning; + m_txAdjustedFreq = m_txFrequency + m_txTuning; + + LogInfo(" RX Tuning Offset: %dhz", m_rxTuning); + LogInfo(" TX Tuning Offset: %dhz", m_txTuning); + LogInfo(" RX Effective Frequency: %uhz", m_rxAdjustedFreq); + LogInfo(" TX Effective Frequency: %uhz", m_txAdjustedFreq); + yaml::Node modemProtocol = modemConf["protocol"]; std::string portType = modemProtocol["type"].as("null"); @@ -443,6 +459,105 @@ int HostCal::run() setTXDCOffset(1); break; + case 'N': + { + char value[5] = { '\0' }; + ::fprintf(stdout, "> FDMA Preambles [%u] ? ", m_fdmaPreamble); + ::fflush(stdout); + + m_console.getLine(value, 5, 0); + if (value[0] != '\0') { + // bryanb: appease the compiler... + uint32_t fdmaPreamble = m_fdmaPreamble; + sscanf(value, "%u", &fdmaPreamble); + + m_fdmaPreamble = (uint8_t)fdmaPreamble; + + writeConfig(); + } + } + break; + + case 'W': + { + char value[5] = { '\0' }; + ::fprintf(stdout, "> DMR Rx Delay [%u] ? ", m_dmrRxDelay); + ::fflush(stdout); + + m_console.getLine(value, 5, 0); + if (value[0] != '\0') { + // bryanb: appease the compiler... + uint32_t dmrRxDelay = m_dmrRxDelay; + sscanf(value, "%u", &dmrRxDelay); + + m_dmrRxDelay = (uint8_t)dmrRxDelay; + + writeConfig(); + } + } + break; + + case 'w': + { + char value[5] = { '\0' }; + ::fprintf(stdout, "> P25 Correlation Count [%u] ? ", m_p25CorrCount); + ::fflush(stdout); + + m_console.getLine(value, 5, 0); + if (value[0] != '\0') { + // bryanb: appease the compiler... + uint32_t p25CorrCount = m_p25CorrCount; + sscanf(value, "%u", &p25CorrCount); + + m_p25CorrCount = (uint8_t)p25CorrCount; + + writeConfig(); + } + } + break; + + case 'F': + { + char value[10] = { '\0' }; + ::fprintf(stdout, "> Rx Frequency Offset [%dHz] (Hz) ? ", m_rxTuning); + ::fflush(stdout); + + m_console.getLine(value, 10, 0); + if (value[0] != '\0') { + int rxTuning = m_rxTuning; + sscanf(value, "%d", &rxTuning); + + m_rxTuning = rxTuning; + m_rxAdjustedFreq = m_rxFrequency + m_rxTuning; + + writeRFParams(); + } + + printStatus(); + } + break; + + case 'f': + { + char value[10] = { '\0' }; + ::fprintf(stdout, "> Tx Frequency Offset [%dHz] (Hz) ? ", m_txTuning); + ::fflush(stdout); + + m_console.getLine(value, 10, 0); + if (value[0] != '\0') { + int txTuning = m_txTuning; + sscanf(value, "%d", &txTuning); + + m_txTuning = txTuning; + m_txAdjustedFreq = m_txFrequency + m_txTuning; + + writeRFParams(); + } + + printStatus(); + } + break; + /** Engineering Commands */ case '-': setDMRSymLevel3Adj(-1); @@ -860,6 +975,11 @@ void HostCal::displayHelp() LogMessage(LOG_CAL, " T/t Increase/Decrease transmit level"); LogMessage(LOG_CAL, " C/c Increase/Decrease RX DC offset level"); LogMessage(LOG_CAL, " O/o Increase/Decrease TX DC offset level"); + LogMessage(LOG_CAL, " N Set FDMA Preambles"); + LogMessage(LOG_CAL, " W Set DMR Rx Delay"); + LogMessage(LOG_CAL, " w Set P25 Correlation Count"); + LogMessage(LOG_CAL, " F Set Rx Frequency Adjustment (affects hotspots only!)"); + LogMessage(LOG_CAL, " f Set Tx Frequency Adjustment (affects hotspots only!)"); LogMessage(LOG_CAL, "Mode Commands:"); LogMessage(LOG_CAL, " Z %s", DMR_CAL_STR); LogMessage(LOG_CAL, " z %s", P25_CAL_STR); @@ -1601,6 +1721,7 @@ bool HostCal::writeConfig(uint8_t modeOverride) m_fdmaPreamble = MAX_FDMA_PREAMBLE; } + m_conf["system"]["modem"]["fdmaPreamble"] = __INT_STR(m_fdmaPreamble); buffer[5U] = m_fdmaPreamble; buffer[6U] = modeOverride; @@ -1613,6 +1734,7 @@ bool HostCal::writeConfig(uint8_t modeOverride) buffer[9U] = 1U; + m_conf["system"]["modem"]["dmrRxDelay"] = __INT_STR(m_dmrRxDelay); buffer[10U] = m_dmrRxDelay; uint32_t nac = 0xF7EU; @@ -1627,6 +1749,7 @@ bool HostCal::writeConfig(uint8_t modeOverride) m_conf["system"]["modem"]["rxDCOffset"] = __INT_STR(m_rxDCOffset); buffer[17U] = (uint8_t)(m_rxDCOffset + 128); + m_conf["system"]["modem"]["p25CorrCount"] = __INT_STR(m_p25CorrCount); buffer[14U] = (uint8_t)m_p25CorrCount; int ret = m_modem->write(buffer, 17U); @@ -1653,15 +1776,15 @@ bool HostCal::writeRFParams() buffer[3U] = 0x00U; - buffer[4U] = (m_rxFrequency >> 0) & 0xFFU; - buffer[5U] = (m_rxFrequency >> 8) & 0xFFU; - buffer[6U] = (m_rxFrequency >> 16) & 0xFFU; - buffer[7U] = (m_rxFrequency >> 24) & 0xFFU; + buffer[4U] = (m_rxAdjustedFreq >> 0) & 0xFFU; + buffer[5U] = (m_rxAdjustedFreq >> 8) & 0xFFU; + buffer[6U] = (m_rxAdjustedFreq >> 16) & 0xFFU; + buffer[7U] = (m_rxAdjustedFreq >> 24) & 0xFFU; - buffer[8U] = (m_txFrequency >> 0) & 0xFFU; - buffer[9U] = (m_txFrequency >> 8) & 0xFFU; - buffer[10U] = (m_txFrequency >> 16) & 0xFFU; - buffer[11U] = (m_txFrequency >> 24) & 0xFFU; + buffer[8U] = (m_txAdjustedFreq >> 0) & 0xFFU; + buffer[9U] = (m_txAdjustedFreq >> 8) & 0xFFU; + buffer[10U] = (m_txAdjustedFreq >> 16) & 0xFFU; + buffer[11U] = (m_txAdjustedFreq >> 24) & 0xFFU; buffer[12U] = (unsigned char)(100 * 2.55F + 0.5F); // cal sets power fixed to 100 @@ -1766,15 +1889,30 @@ void HostCal::timerStop() /// void HostCal::printStatus() { - LogMessage(LOG_CAL, " - PTT Invert: %s, RX Invert: %s, TX Invert: %s, DC Blocker: %s", - m_pttInvert ? "yes" : "no", m_rxInvert ? "yes" : "no", m_txInvert ? "yes" : "no", m_dcBlocker ? "yes" : "no"); - LogMessage(LOG_CAL, " - RX Level: %.1f%%, TX Level: %.1f%%, TX DC Offset: %d, RX DC Offset: %d", - m_rxLevel, m_txLevel, m_txDCOffset, m_rxDCOffset); - LogMessage(LOG_CAL, " - DMR Symbol +/- 3 Level Adj.: %d, DMR Symbol +/- 1 Level Adj.: %d, P25 Symbol +/- 3 Level Adj.: %d, P25 Symbol +/- 1 Level Adj.: %d", - m_dmrSymLevel3Adj, m_dmrSymLevel1Adj, m_p25SymLevel3Adj, m_p25SymLevel1Adj); - LogMessage(LOG_CAL, " - FDMA Preambles: %u (%.1fms), DMR Rx Delay: %u (%.1fms), P25 Corr. Count: %u (%.1fms)", m_fdmaPreamble, float(m_fdmaPreamble) * 0.2083F, m_dmrRxDelay, float(m_dmrRxDelay) * 0.0416666F, - m_p25CorrCount, float(m_p25CorrCount) * 0.667F); - LogMessage(LOG_CAL, " - Rx Freq: %uHz, Tx Freq: %uHz, Operating Mode: %s", m_rxFrequency, m_txFrequency, m_modeStr.c_str()); + yaml::Node systemConf = m_conf["system"]; + { + yaml::Node modemConfig = m_conf["system"]["modem"]; + std::string type = modemConfig["protocol"]["type"].as(); + + yaml::Node uartConfig = modemConfig["protocol"]["uart"]; + std::string modemPort = uartConfig["port"].as(); + uint32_t portSpeed = uartConfig["speed"].as(115200U); + + LogMessage(LOG_CAL, " - Operating Mode: %s, Port Type: %s, Modem Port: %s, Port Speed: %u", m_modeStr.c_str(), type.c_str(), modemPort.c_str(), portSpeed); + } + + { + LogMessage(LOG_CAL, " - PTT Invert: %s, RX Invert: %s, TX Invert: %s, DC Blocker: %s", + m_pttInvert ? "yes" : "no", m_rxInvert ? "yes" : "no", m_txInvert ? "yes" : "no", m_dcBlocker ? "yes" : "no"); + LogMessage(LOG_CAL, " - RX Level: %.1f%%, TX Level: %.1f%%, TX DC Offset: %d, RX DC Offset: %d", + m_rxLevel, m_txLevel, m_txDCOffset, m_rxDCOffset); + LogMessage(LOG_CAL, " - DMR Symbol +/- 3 Level Adj.: %d, DMR Symbol +/- 1 Level Adj.: %d, P25 Symbol +/- 3 Level Adj.: %d, P25 Symbol +/- 1 Level Adj.: %d", + m_dmrSymLevel3Adj, m_dmrSymLevel1Adj, m_p25SymLevel3Adj, m_p25SymLevel1Adj); + LogMessage(LOG_CAL, " - FDMA Preambles: %u (%.1fms), DMR Rx Delay: %u (%.1fms), P25 Corr. Count: %u (%.1fms)", m_fdmaPreamble, float(m_fdmaPreamble) * 0.2083F, m_dmrRxDelay, float(m_dmrRxDelay) * 0.0416666F, + m_p25CorrCount, float(m_p25CorrCount) * 0.667F); + LogMessage(LOG_CAL, " - Rx Freq: %uHz, Tx Freq: %uHz, Rx Offset: %dHz, Tx Offset: %dHz", m_rxFrequency, m_txFrequency, m_rxTuning, m_txTuning); + LogMessage(LOG_CAL, " - Rx Effective Freq: %uHz, Tx Effective Freq: %uHz", m_rxAdjustedFreq, m_txAdjustedFreq); + } uint8_t buffer[50U]; diff --git a/host/calibrate/HostCal.h b/host/calibrate/HostCal.h index 8b84c765..2d57b2c5 100644 --- a/host/calibrate/HostCal.h +++ b/host/calibrate/HostCal.h @@ -99,8 +99,13 @@ private: uint8_t m_mode; std::string m_modeStr; + int m_rxTuning; + int m_txTuning; + uint32_t m_rxFrequency; + uint32_t m_rxAdjustedFreq; uint32_t m_txFrequency; + uint32_t m_txAdjustedFreq; uint8_t m_channelId; uint32_t m_channelNo; diff --git a/host/setup/HostSetup.cpp b/host/setup/HostSetup.cpp index 1a53852b..f0fc451e 100644 --- a/host/setup/HostSetup.cpp +++ b/host/setup/HostSetup.cpp @@ -27,6 +27,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "dmr/DMRUtils.h" +#include "p25/P25Utils.h" #include "host/setup/HostSetup.h" #include "HostMain.h" #include "Log.h" @@ -92,6 +94,7 @@ int HostSetup::run() ::LogInfo(">> Modem Setup"); yaml::Node systemConf = m_conf["system"]; + yaml::Node modemConfig = systemConf["modem"]; m_duplex = systemConf["duplex"].as(true); // try to load bandplan identity table @@ -111,20 +114,7 @@ int HostSetup::run() m_idenTable = new IdenTableLookup(idenLookupFile, idenReloadTime); m_idenTable->read(); - LogInfo("General Parameters"); - - std::string identity = systemConf["identity"].as(); - ::LogInfo(" Identity: %s", identity.c_str()); - yaml::Node cwId = systemConf["cwId"]; - bool cwEnabled = cwId["enable"].as(false); - uint32_t cwTime = cwId["time"].as(10U); - std::string callsign = cwId["callsign"].as(); - - LogInfo("CW Id Parameters"); - LogInfo(" Enabled: %s", cwEnabled ? "enabled" : "disabled"); - LogInfo(" Time: %u mins", cwTime); - LogInfo(" Callsign: %s", callsign.c_str()); yaml::Node rfssConfig = systemConf["config"]; m_channelId = (uint8_t)rfssConfig["channelId"].as(0U); @@ -150,12 +140,6 @@ int HostSetup::run() return false; } - LogInfo("System Config Parameters"); - LogInfo(" RX Frequency: %uHz", m_rxFrequency); - LogInfo(" TX Frequency: %uHz", m_txFrequency); - LogInfo(" Base Frequency: %uHz", entry.baseFrequency()); - LogInfo(" TX Offset: %fMHz", entry.txOffsetMhz()); - // open terminal console ret = m_console.open(); if (!ret) { @@ -172,37 +156,75 @@ int HostSetup::run() switch (c) { /** Setup Commands */ + case 'M': + { + modemConfig = m_conf["system"]["modem"]; + m_conf["system"]["modem"]["protocol"]["type"] = std::string("uart"); // configuring modem, always sets type to UART + + yaml::Node uartConfig = modemConfig["protocol"]["uart"]; + + std::string modemPort = uartConfig["port"].as("/dev/ttyUSB0"); + uint32_t portSpeed = uartConfig["speed"].as(115200); + + char value[21] = { '\0' }; + ::fprintf(stdout, "> Modem UART Port [%s] ? ", modemPort.c_str()); + ::fflush(stdout); + + m_console.getLine(value, 21, 0); + if (value[0] != '\0') { + modemPort = std::string(value); + m_conf["system"]["modem"]["protocol"]["uart"]["port"] = modemPort; + } + + ::fprintf(stdout, "> Port Speed [%u] ? ", portSpeed); + ::fflush(stdout); + + m_console.getLine(value, 7, 0); + if (value[0] != '\0') { + sscanf(value, "%u", &portSpeed); + m_conf["system"]["modem"]["protocol"]["uart"]["speed"] = __INT_STR(portSpeed); + } + + printStatus(); + } + break; + case 'I': { + std::string identity = m_conf["system"]["identity"].as(); + char value[9] = { '\0' }; - ::fprintf(stdout, "> Identity ? "); + ::fprintf(stdout, "> Identity [%s] ? ", identity.c_str()); ::fflush(stdout); m_console.getLine(value, 9, 0); - std::string identity = std::string(value); + identity = std::string(value); if (identity.length() > 0) { m_conf["system"]["identity"] = identity; } - writeConfig(); + printStatus(); } break; case 'C': { + cwId = m_conf["system"]["cwId"]; bool enabled = cwId["enable"].as(false); + uint32_t cwTime = cwId["time"].as(10U); + std::string callsign = cwId["callsign"].as(); char value[9] = { '\0' }; - ::fprintf(stdout, "> Callsign ? "); + ::fprintf(stdout, "> Callsign [%s] ? ", callsign.c_str()); ::fflush(stdout); m_console.getLine(value, 9, 0); - std::string callsign = std::string(value); + callsign = std::string(value); if (callsign.length() > 0) { m_conf["system"]["cwId"]["callsign"] = callsign; } - ::fprintf(stdout, "> CW Enabled (Y/N) ? "); + ::fprintf(stdout, "> CW Enabled [%u] (Y/N) ? ", enabled); ::fflush(stdout); m_console.getLine(value, 2, 0); @@ -212,7 +234,7 @@ int HostSetup::run() m_conf["system"]["cwId"]["enable"] = __BOOL_STR(enabled); - ::fprintf(stdout, "> CW Interval (minutes) ? "); + ::fprintf(stdout, "> CW Interval [%u] (minutes) ? ", cwTime); ::fflush(stdout); m_console.getLine(value, 4, 0); @@ -222,98 +244,224 @@ int HostSetup::run() m_conf["system"]["cwId"]["time"] = __INT_STR(time); } - writeConfig(); + printStatus(); + } + break; + + case 'N': + { + rfssConfig = m_conf["system"]["config"]; + uint32_t siteId = (uint8_t)::strtoul(rfssConfig["siteId"].as("1").c_str(), NULL, 16); + uint32_t dmrNetId = (uint32_t)::strtoul(rfssConfig["dmrNetId"].as("1").c_str(), NULL, 16); + uint32_t p25NetId = (uint32_t)::strtoul(rfssConfig["netId"].as("BB800").c_str(), NULL, 16); + uint32_t p25SysId = (uint32_t)::strtoul(rfssConfig["sysId"].as("001").c_str(), NULL, 16); + uint32_t p25RfssId = (uint8_t)::strtoul(rfssConfig["rfssId"].as("1").c_str(), NULL, 16); + + char value[6] = { '\0' }; + ::fprintf(stdout, "> Site ID [$%02X] ? ", siteId); + ::fflush(stdout); + + m_console.getLine(value, 3, 0); + if (value[0] != '\0') { + siteId = (uint32_t)::strtoul(std::string(value).c_str(), NULL, 16); + siteId = p25::P25Utils::siteId(siteId); + + m_conf["system"]["config"]["siteId"] = __INT_HEX_STR(siteId); + } + + ::fprintf(stdout, "> DMR Network ID [$%05X] ? ", dmrNetId); + ::fflush(stdout); + + m_console.getLine(value, 6, 0); + if (value[0] != '\0') { + dmrNetId = (uint32_t)::strtoul(std::string(value).c_str(), NULL, 16); + dmrNetId = dmr::DMRUtils::netId(dmrNetId, dmr::SITE_MODEL_TINY); + + m_conf["system"]["config"]["dmrNetId"] = __INT_HEX_STR(dmrNetId); + } + + ::fprintf(stdout, "> P25 Network ID [$%05X] ? ", p25NetId); + ::fflush(stdout); + + m_console.getLine(value, 6, 0); + if (value[0] != '\0') { + p25NetId = (uint32_t)::strtoul(std::string(value).c_str(), NULL, 16); + p25NetId = p25::P25Utils::netId(p25NetId); + + m_conf["system"]["config"]["netId"] = __INT_HEX_STR(p25NetId); + } + + ::fprintf(stdout, "> P25 System ID [$%03X] ? ", p25SysId); + ::fflush(stdout); + + m_console.getLine(value, 4, 0); + if (value[0] != '\0') { + p25SysId = (uint32_t)::strtoul(std::string(value).c_str(), NULL, 16); + p25SysId = p25::P25Utils::sysId(p25SysId); + + m_conf["system"]["config"]["sysId"] = __INT_HEX_STR(p25SysId); + } + + ::fprintf(stdout, "> P25 RFSS ID [$%02X] ? ", p25RfssId); + ::fflush(stdout); + + m_console.getLine(value, 3, 0); + if (value[0] != '\0') { + p25RfssId = (uint8_t)::strtoul(std::string(value).c_str(), NULL, 16); + p25RfssId = p25::P25Utils::rfssId(p25RfssId); + + m_conf["system"]["config"]["rfssId"] = __INT_HEX_STR(p25RfssId); + } + + printStatus(); + } + break; + + case 'a': + { + rfssConfig = m_conf["system"]["config"]; + uint32_t dmrColorCode = rfssConfig["colorCode"].as(2U); + uint32_t p25NAC = (uint32_t)::strtoul(rfssConfig["nac"].as("293").c_str(), NULL, 16); + + char value[6] = { '\0' }; + ::fprintf(stdout, "> DMR Color Code [%u] ? ", dmrColorCode); + ::fflush(stdout); + + m_console.getLine(value, 2, 0); + if (value[0] != '\0') { + sscanf(value, "%u", &dmrColorCode); + dmrColorCode = dmr::DMRUtils::colorCode(dmrColorCode); + + m_conf["system"]["config"]["colorCode"] = __INT_STR(dmrColorCode); + } + + ::fprintf(stdout, "> P25 NAC [$%03X] ? ", p25NAC); + ::fflush(stdout); + + m_console.getLine(value, 4, 0); + if (value[0] != '\0') { + p25NAC = (uint32_t)::strtoul(std::string(value).c_str(), NULL, 16); + p25NAC = p25::P25Utils::nac(p25NAC); + + m_conf["system"]["config"]["nac"] = __INT_HEX_STR(p25NAC); + } + + printStatus(); } break; case 'i': { + rfssConfig = m_conf["system"]["config"]; + m_channelId = (uint8_t)rfssConfig["channelId"].as(0U); + char value[3] = { '\0' }; - ::fprintf(stdout, "> Channel ID ? "); + ::fprintf(stdout, "> Channel ID [%u] ? ", m_channelId); ::fflush(stdout); m_console.getLine(value, 3, 0); + if (value[0] != '\0') { + uint8_t prevChannelId = m_channelId; - uint8_t prevChannelId = m_channelId; + // bryanb: appease the compiler... + uint32_t channelId = m_channelId; + sscanf(value, "%u", &channelId); - // bryanb: appease the compiler... - uint32_t channelId = m_channelId; - sscanf(value, "%u", &channelId); + m_channelId = (uint8_t)channelId; - m_channelId = (uint8_t)channelId; + IdenTable entry = m_idenTable->find(m_channelId); + if (entry.baseFrequency() == 0U) { + ::LogError(LOG_SETUP, "Channel Id %u has an invalid base frequency.", m_channelId); + m_channelId = prevChannelId; + } - IdenTable entry = m_idenTable->find(m_channelId); - if (entry.baseFrequency() == 0U) { - ::LogError(LOG_SETUP, "Channel Id %u has an invalid base frequency.", m_channelId); - m_channelId = prevChannelId; + m_conf["system"]["config"]["channelId"] = __INT_STR(m_channelId); } - writeConfig(); + printStatus(); } break; case 'c': { + rfssConfig = m_conf["system"]["config"]; + m_channelNo = (uint32_t)::strtoul(rfssConfig["channelNo"].as("1").c_str(), NULL, 16); + char value[5] = { '\0' }; - ::fprintf(stdout, "> Channel No ? "); + ::fprintf(stdout, "> Channel No [%u] ? ", m_channelNo); ::fflush(stdout); m_console.getLine(value, 5, 0); + if (value[0] != '\0') { + uint8_t prevChannelNo = m_channelNo; + sscanf(value, "%u", &m_channelNo); - uint8_t prevChannelNo = m_channelNo; - sscanf(value, "%u", &m_channelNo); + if (m_channelNo < 0 || m_channelNo > 4096) { + ::LogError(LOG_SETUP, "Channel No %u is invalid.", m_channelNo); + m_channelNo = prevChannelNo; + } - if (m_channelNo < 0 || m_channelNo > 4096) { - ::LogError(LOG_SETUP, "Channel No %u is invalid.", m_channelNo); - m_channelNo = prevChannelNo; + m_conf["system"]["config"]["channelNo"] = __INT_HEX_STR(m_channelNo); } - writeConfig(); + printStatus(); } break; case 'f': { + rfssConfig = m_conf["system"]["config"]; + m_channelNo = (uint32_t)::strtoul(rfssConfig["channelNo"].as("1").c_str(), NULL, 16); + char value[10] = { '\0' }; - ::fprintf(stdout, "> Tx Frequency (Hz) ? "); + ::fprintf(stdout, "> Tx Frequency [%uHz] (Hz) ? ", m_txFrequency); ::fflush(stdout); m_console.getLine(value, 10, 0); - - uint32_t txFrequency = m_txFrequency; - sscanf(value, "%u", &txFrequency); - - IdenTable entry = m_idenTable->find(m_channelId); - if (txFrequency < entry.baseFrequency()) { - ::LogError(LOG_SETUP, "Tx Frequency %uHz is out of band range for base frequency %uHz. Tx Frequency must be greater then base frequency!", txFrequency, entry.baseFrequency()); - break; - } - - if (txFrequency > entry.baseFrequency() + 25500000) { - ::LogError(LOG_SETUP, "Tx Frequency %uHz is out of band range for base frequency %uHz. Tx Frequency must be no more then 25.5 Mhz higher then base frequency!", txFrequency, entry.baseFrequency()); - break; + if (value[0] != '\0') { + uint32_t txFrequency = m_txFrequency; + sscanf(value, "%u", &txFrequency); + + IdenTable entry = m_idenTable->find(m_channelId); + if (txFrequency < entry.baseFrequency()) { + ::LogError(LOG_SETUP, "Tx Frequency %uHz is out of band range for base frequency %uHz. Tx Frequency must be greater then base frequency!", txFrequency, entry.baseFrequency()); + break; + } + + if (txFrequency > entry.baseFrequency() + 25500000) { + ::LogError(LOG_SETUP, "Tx Frequency %uHz is out of band range for base frequency %uHz. Tx Frequency must be no more then 25.5 Mhz higher then base frequency!", txFrequency, entry.baseFrequency()); + break; + } + + uint32_t prevTxFrequency = m_txFrequency; + m_txFrequency = txFrequency; + uint32_t prevRxFrequency = m_rxFrequency; + m_rxFrequency = m_txFrequency + (uint32_t)(entry.txOffsetMhz() * 1000000); + + float spaceHz = entry.chSpaceKhz() * 1000; + + uint32_t rootFreq = m_txFrequency - entry.baseFrequency(); + uint8_t prevChannelNo = m_channelNo; + m_channelNo = (uint32_t)(rootFreq / spaceHz); + + if (m_channelNo < 0 || m_channelNo > 4096) { + ::LogError(LOG_SETUP, "Channel No %u is invalid.", m_channelNo); + m_channelNo = prevChannelNo; + m_txFrequency = prevTxFrequency; + m_rxFrequency = prevRxFrequency; + break; + } } - uint32_t prevTxFrequency = m_txFrequency; - m_txFrequency = txFrequency; - uint32_t prevRxFrequency = m_rxFrequency; - m_rxFrequency = m_txFrequency + (uint32_t)(entry.txOffsetMhz() * 1000000); - - float spaceHz = entry.chSpaceKhz() * 1000; - - uint32_t rootFreq = m_txFrequency - entry.baseFrequency(); - uint8_t prevChannelNo = m_channelNo; - m_channelNo = (uint32_t)(rootFreq / spaceHz); - - if (m_channelNo < 0 || m_channelNo > 4096) { - ::LogError(LOG_SETUP, "Channel No %u is invalid.", m_channelNo); - m_channelNo = prevChannelNo; - m_txFrequency = prevTxFrequency; - m_rxFrequency = prevRxFrequency; - break; - } + printStatus(); + } + break; - writeConfig(); + case '!': + { + modemConfig = m_conf["system"]["modem"]; + m_conf["system"]["modem"]["protocol"]["type"] = std::string("null"); // configuring modem, always sets type to UART + printStatus(); } break; @@ -369,11 +517,15 @@ void HostSetup::displayHelp() LogMessage(LOG_SETUP, " ` Display current settings"); LogMessage(LOG_SETUP, " V Display version of host"); LogMessage(LOG_SETUP, " H/h Display help"); + LogMessage(LOG_SETUP, " ! Set \"null\" modem (disables modem communication)"); LogMessage(LOG_SETUP, " S/s Save settings to configuration file"); LogMessage(LOG_SETUP, " Q/q Quit"); LogMessage(LOG_SETUP, "Setup Commands:"); + LogMessage(LOG_SETUP, " M Set modem port and speed"); LogMessage(LOG_SETUP, " I Set identity (logical name)"); LogMessage(LOG_SETUP, " C Set callsign and CW configuration"); + LogMessage(LOG_SETUP, " N Set site and network configuration"); + LogMessage(LOG_SETUP, " a Set NAC and Color Code"); LogMessage(LOG_SETUP, " i Set logical channel ID"); LogMessage(LOG_SETUP, " c Set logical channel number (by channel number)"); LogMessage(LOG_SETUP, " f Set logical channel number (by Tx frequency)"); @@ -419,19 +571,6 @@ bool HostSetup::calculateRxTxFreq() return true; } -/// -/// Write configuration file. -/// -/// True, if configuration is written, otherwise false. -bool HostSetup::writeConfig() -{ - m_conf["system"]["config"]["channelId"] = __INT_STR(m_channelId); - m_conf["system"]["config"]["channelNo"] = __INT_STR(m_channelNo); - - printStatus(); - return true; -} - /// /// Helper to sleep the thread. /// @@ -451,20 +590,33 @@ void HostSetup::sleep(uint32_t ms) void HostSetup::printStatus() { yaml::Node systemConf = m_conf["system"]; - std::string identity = systemConf["identity"].as(); + { + yaml::Node modemConfig = m_conf["system"]["modem"]; + std::string type = modemConfig["protocol"]["type"].as(); - IdenTable entry = m_idenTable->find(m_channelId); - if (entry.baseFrequency() == 0U) { - ::LogError(LOG_HOST, "Channel Id %u has an invalid base frequency.", m_channelId); + yaml::Node uartConfig = modemConfig["protocol"]["uart"]; + std::string modemPort = uartConfig["port"].as(); + uint32_t portSpeed = uartConfig["speed"].as(115200U); + + LogMessage(LOG_SETUP, " - Port Type: %s, Modem Port: %s, Port Speed: %u", type.c_str(), modemPort.c_str(), portSpeed); } - calculateRxTxFreq(); + { + std::string identity = systemConf["identity"].as(); + + IdenTable entry = m_idenTable->find(m_channelId); + if (entry.baseFrequency() == 0U) { + ::LogError(LOG_HOST, "Channel Id %u has an invalid base frequency.", m_channelId); + } + + calculateRxTxFreq(); + + LogMessage(LOG_SETUP, " - Identity: %s", identity.c_str()); + LogMessage(LOG_SETUP, " - Channel Id: %u, Channel No: %u", m_channelId, m_channelNo); + LogMessage(LOG_SETUP, " - Base Freq: %uHz, TX Offset: %fMHz, Bandwidth: %fKHz, Channel Spacing: %fKHz", entry.baseFrequency(), entry.txOffsetMhz(), entry.chBandwidthKhz(), entry.chSpaceKhz()); + LogMessage(LOG_SETUP, " - Rx Freq: %uHz, Tx Freq: %uHz", m_rxFrequency, m_txFrequency); + } - LogMessage(LOG_SETUP, " - Identity: %s", identity.c_str()); - LogMessage(LOG_SETUP, " - Channel ID: %u, Channel No: %u", m_channelId, m_channelNo); - LogMessage(LOG_SETUP, " - Base Freq: %uHz, TX Offset: %fMHz, Bandwidth: %fKHz, Channel Spacing: %fKHz", entry.baseFrequency(), entry.txOffsetMhz(), entry.chBandwidthKhz(), entry.chSpaceKhz()); - LogMessage(LOG_SETUP, " - Rx Freq: %uHz, Tx Freq: %uHz", m_rxFrequency, m_txFrequency); - { yaml::Node cwId = systemConf["cwId"]; bool enabled = cwId["enable"].as(false); @@ -473,4 +625,23 @@ void HostSetup::printStatus() LogMessage(LOG_SETUP, " - Callsign: %s, CW Interval: %u mins, CW Enabled: %u", callsign.c_str(), cwTime, enabled); } + + { + yaml::Node rfssConfig = systemConf["config"]; + uint32_t dmrColorCode = rfssConfig["colorCode"].as(2U); + uint32_t p25NAC = (uint32_t)::strtoul(rfssConfig["nac"].as("293").c_str(), NULL, 16); + + LogMessage(LOG_SETUP, " - DMR Color Code: %u, P25 NAC: $%03X", dmrColorCode, p25NAC); + } + + { + yaml::Node rfssConfig = systemConf["config"]; + uint32_t siteId = (uint8_t)::strtoul(rfssConfig["siteId"].as("1").c_str(), NULL, 16); + uint32_t dmrNetId = (uint32_t)::strtoul(rfssConfig["dmrNetId"].as("1").c_str(), NULL, 16); + uint32_t p25NetId = (uint32_t)::strtoul(rfssConfig["netId"].as("BB800").c_str(), NULL, 16); + uint32_t p25SysId = (uint32_t)::strtoul(rfssConfig["sysId"].as("001").c_str(), NULL, 16); + uint32_t p25RfssId = (uint8_t)::strtoul(rfssConfig["rfssId"].as("1").c_str(), NULL, 16); + + LogMessage(LOG_SETUP, " - Site Id: $%02X, DMR Network Id: $%05X, P25 Network Id: $%05X, P25 System Id: $%03X, P25 RFSS Id: $%02X", siteId, dmrNetId, p25NetId, p25SysId, p25RfssId); + } } diff --git a/host/setup/HostSetup.h b/host/setup/HostSetup.h index d20f57af..943a97d5 100644 --- a/host/setup/HostSetup.h +++ b/host/setup/HostSetup.h @@ -74,8 +74,6 @@ private: /// Helper to calculate the Rx/Tx frequencies. bool calculateRxTxFreq(); - /// Write configuration file. - bool writeConfig(); /// Helper to sleep the thread. void sleep(uint32_t ms); diff --git a/p25/P25Utils.h b/p25/P25Utils.h index e127c03d..d93a1319 100644 --- a/p25/P25Utils.h +++ b/p25/P25Utils.h @@ -12,6 +12,7 @@ // /* * Copyright (C) 2016 by Jonathan Naylor G4KLX +* Copyright (C) 2021 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 @@ -36,12 +37,77 @@ namespace p25 { // --------------------------------------------------------------------------- // Class Declaration - // This class implements various helper functions for interleaving P25 - // data. + // This class implements various helper functions for validating and + // for interleaving P25 data. // --------------------------------------------------------------------------- class HOST_SW_API P25Utils { public: + /// Helper to test and clamp a P25 NAC. + static uint32_t nac(uint32_t nac) + { + if (nac < 0U) { // clamp to $000 + nac = 0U; + } + if (nac > 0xF7DU) { // clamp to $F7D + nac = 0xF7DU; + } + + return nac; + } + + /// Helper to test and clamp a P25 site ID. + static uint8_t siteId(uint8_t id) + { + if (id == 0U) { // clamp to 1 + id = 1U; + } + if (id > 0xFEU) { // clamp to $FE + id = 0xFEU; + } + + return id; + } + + /// Helper to test and clamp a P25 network ID. + static uint32_t netId(uint32_t id) + { + if (id == 0U) { // clamp to 1 + id = 1U; + } + if (id > 0xFFFFEU) { // clamp to $FFFFE + id = 0xFFFFEU; + } + + return id; + } + + /// Helper to test and clamp a P25 system ID. + static uint32_t sysId(uint32_t id) + { + if (id == 0U) { // clamp to 1 + id = 1U; + } + if (id > 0xFFEU) { // clamp to $FFE + id = 0xFFEU; + } + + return id; + } + + /// Helper to test and clamp a P25 RFSS ID. + static uint8_t rfssId(uint8_t id) + { + if (id == 0U) { // clamp to 1 + id = 1U; + } + if (id > 0xFEU) { // clamp to $FE + id = 0xFEU; + } + + return id; + } + /// Decode bit interleaving. static uint32_t decode(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t stop); /// Encode bit interleaving. diff --git a/p25/SiteData.h b/p25/SiteData.h index 3d9d413b..16d8102e 100644 --- a/p25/SiteData.h +++ b/p25/SiteData.h @@ -32,6 +32,7 @@ #include "Defines.h" #include "p25/P25Defines.h" +#include "p25/P25Utils.h" namespace p25 { @@ -87,38 +88,28 @@ namespace p25 lra = 0xFFU; // netId clamping - if (netId == 0U) // clamp to 1 - netId = 1U; - if (netId > 0xFFFFEU) // clamp to $FFFFE - netId = 0xFFFFEU; + netId = P25Utils::netId(netId); // sysId clamping - if (sysId == 0U) // clamp to 1 - sysId = 1U; - if (sysId > 0xFFEU) // clamp to $FFE - sysId = 0xFFEU; + sysId = P25Utils::sysId(sysId); // rfssId clamping - if (rfssId == 0U) // clamp to 1 - rfssId = 1U; - if (rfssId > 0xFEU) // clamp to $FE - rfssId = 0xFEU; + rfssId = P25Utils::rfssId(rfssId); // siteId clamping - if (siteId == 0U) // clamp to 1 - siteId = 1U; - if (siteId > 0xFEU) // clamp to $FE - siteId = 0xFEU; + siteId = P25Utils::siteId(siteId); // channel id clamping if (channelId > 15U) channelId = 15U; // channel number clamping - if (channelNo == 0U) // clamp to 1 - channelNo = 1U; - if (channelNo > 4095U) // clamp to 4096 - channelNo = 4095U; + if (m_channelNo == 0U) { // clamp to 1 + m_channelNo = 1U; + } + if (m_channelNo > 4095U) { // clamp to 4095 + m_channelNo = 4095U; + } m_lra = lra; @@ -165,32 +156,25 @@ namespace p25 void setAdjSite(uint32_t sysId, uint8_t rfssId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, uint8_t serviceClass) { // sysId clamping - if (sysId == 0U) // clamp to 1 - sysId = 1U; - if (sysId > 0xFFEU) // clamp to $FFE - sysId = 0xFFEU; + sysId = P25Utils::sysId(sysId); // rfssId clamping - if (rfssId == 0U) // clamp to 1 - rfssId = 1U; - if (rfssId > 0xFEU) // clamp to $FE - rfssId = 0xFEU; + rfssId = P25Utils::rfssId(rfssId); // siteId clamping - if (siteId == 0U) // clamp to 1 - siteId = 1U; - if (siteId > 0xFEU) // clamp to $FE - siteId = 0xFEU; + siteId = P25Utils::siteId(siteId); // channel id clamping if (channelId > 15U) channelId = 15U; // channel number clamping - if (channelNo == 0U) // clamp to 1 - channelNo = 1U; - if (channelNo > 4095U) // clamp to 4096 - channelNo = 4095U; + if (m_channelNo == 0U) { // clamp to 1 + m_channelNo = 1U; + } + if (m_channelNo > 4095U) { // clamp to 4095 + m_channelNo = 4095U; + } m_lra = 0U;