diff --git a/dmr/ControlPacket.cpp b/dmr/ControlPacket.cpp index 94c6b7ed..f943a92b 100644 --- a/dmr/ControlPacket.cpp +++ b/dmr/ControlPacket.cpp @@ -106,6 +106,7 @@ bool ControlPacket::process(uint8_t* data, uint32_t len) // validate the source RID if (!acl::AccessControl::validateSrcId(srcId)) { LogWarning(LOG_RF, "DMR Slot %u, DT_CSBK denial, RID rejection, srcId = %u", m_slot->m_slotNo, srcId); + m_slot->m_rfState = RS_RF_REJECTED; return false; } @@ -113,6 +114,7 @@ bool ControlPacket::process(uint8_t* data, uint32_t len) if (gi) { if (!acl::AccessControl::validateTGId(m_slot->m_slotNo, dstId)) { LogWarning(LOG_RF, "DMR Slot %u, DT_CSBK denial, TGID rejection, srcId = %u, dstId = %u", m_slot->m_slotNo, srcId, dstId); + m_slot->m_rfState = RS_RF_REJECTED; return false; } } diff --git a/dmr/DataPacket.cpp b/dmr/DataPacket.cpp index b8a62104..90c08667 100644 --- a/dmr/DataPacket.cpp +++ b/dmr/DataPacket.cpp @@ -154,6 +154,7 @@ bool DataPacket::process(uint8_t* data, uint32_t len) // validate the source RID if (!acl::AccessControl::validateSrcId(srcId)) { LogWarning(LOG_RF, "DMR Slot %u, DT_DATA_HEADER denial, RID rejection, srcId = %u", m_slot->m_slotNo, srcId); + m_slot->m_rfState = RS_RF_REJECTED; return false; } @@ -161,6 +162,7 @@ bool DataPacket::process(uint8_t* data, uint32_t len) if (gi) { if (!acl::AccessControl::validateTGId(m_slot->m_slotNo, dstId)) { LogWarning(LOG_RF, "DMR Slot %u, DT_DATA_HEADER denial, TGID rejection, srcId = %u, dstId = %u", m_slot->m_slotNo, srcId, dstId); + m_slot->m_rfState = RS_RF_REJECTED; return false; } } diff --git a/dmr/Slot.cpp b/dmr/Slot.cpp index a200c93e..5d0da21a 100644 --- a/dmr/Slot.cpp +++ b/dmr/Slot.cpp @@ -400,8 +400,7 @@ void Slot::clock() } } - if (m_enableTSCC) - { + if (m_enableTSCC) { // increment the TSCC counter on every slot 1 clock m_tsccCnt++; if (m_tsccCnt == TSCC_MAX_CNT) { @@ -486,6 +485,22 @@ void Slot::clock() m_packetTimer.start(); } } + + if (m_rfState == RS_RF_REJECTED) { + m_queue.clear(); + + m_rfFrames = 0U; + m_rfErrs = 0U; + m_rfBits = 1U; + + m_netFrames = 0U; + m_netLost = 0U; + + if (m_network != NULL) + m_network->resetDMR(m_slotNo); + + m_rfState = RS_RF_LISTENING; + } } /// @@ -841,6 +856,16 @@ void Slot::writeRF_ControlData(uint16_t frameCnt, uint8_t n) if (!m_enableTSCC) return; + // don't add any frames if the queue is full + uint8_t len = DMR_FRAME_LENGTH_BYTES + 2U; + uint32_t space = m_queue.freeSpace(); + if (space < (len + 1U)) { + m_ccSeq--; + if (m_ccSeq < 0U) + m_ccSeq = 0U; + return; + } + // loop to generate 2 control sequences if (frameCnt == 511U) { seqCnt = 3U; diff --git a/dmr/VoicePacket.cpp b/dmr/VoicePacket.cpp index f1d076d6..8962d05b 100644 --- a/dmr/VoicePacket.cpp +++ b/dmr/VoicePacket.cpp @@ -113,6 +113,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) m_slot->m_rfTGHang.stop(); delete lc; + m_slot->m_rfState = RS_RF_REJECTED; return false; } @@ -128,6 +129,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) m_slot->m_rfTGHang.stop(); delete lc; + m_slot->m_rfState = RS_RF_REJECTED; return false; } } @@ -457,6 +459,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) if (!acl::AccessControl::validateSrcId(srcId)) { LogWarning(LOG_RF, "DMR Slot %u, DT_VOICE denial, RID rejection, srcId = %u", m_slot->m_slotNo, srcId); delete lc; + m_slot->m_rfState = RS_RF_REJECTED; return false; } @@ -465,6 +468,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) if (!acl::AccessControl::validateTGId(m_slot->m_slotNo, dstId)) { LogWarning(LOG_RF, "DMR Slot %u, DT_VOICE denial, TGID rejection, srcId = %u, dstId = %u", m_slot->m_slotNo, srcId, dstId); delete lc; + m_slot->m_rfState = RS_RF_REJECTED; return false; } } diff --git a/host/Host.cpp b/host/Host.cpp index 9ea6f5c6..e9a986f3 100644 --- a/host/Host.cpp +++ b/host/Host.cpp @@ -13,6 +13,7 @@ /* * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2017-2021 by Bryan Biedenkapp N2PLL +* Copyright (C) 2021 by Nat Moore * * 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 @@ -1504,6 +1505,7 @@ bool Host::createModem() uint8_t p25CorrCount = (uint8_t)modemConf["p25CorrCount"].as(4U); int rxDCOffset = modemConf["rxDCOffset"].as(0); int txDCOffset = modemConf["txDCOffset"].as(0); + uint8_t rfPower = (uint8_t)modemConf["rfPower"].as(100U); int dmrSymLevel3Adj = modemConf["dmrSymLvl3Adj"].as(0); int dmrSymLevel1Adj = modemConf["dmrSymLvl1Adj"].as(0); int p25SymLevel3Adj = modemConf["p25SymLvl3Adj"].as(0); @@ -1524,6 +1526,13 @@ bool Host::createModem() if (packetPlayoutTime < 1U) packetPlayoutTime = 1U; + if (rfPower == 0U) { // clamp to 1 + rfPower = 1U; + } + if (rfPower > 100U) { // clamp to 100 + rfPower = 100U; + } + LogInfo("Modem Parameters"); LogInfo(" Port Type: %s", portType.c_str()); @@ -1609,6 +1618,7 @@ bool Host::createModem() LogInfo(" P25 Corr. Count: %u (%.1fms)", p25CorrCount, float(p25CorrCount) * 0.667F); LogInfo(" RX DC Offset: %d", rxDCOffset); LogInfo(" TX DC Offset: %d", txDCOffset); + LogInfo(" RF Power Level: %u", rfPower); LogInfo(" RX Level: %.1f%%", rxLevel); LogInfo(" CW Id TX Level: %.1f%%", cwIdTXLevel); LogInfo(" DMR TX Level: %.1f%%", dmrTXLevel); @@ -1624,7 +1634,8 @@ bool Host::createModem() m_modem->setModeParams(m_dmrEnabled, m_p25Enabled); m_modem->setLevels(rxLevel, cwIdTXLevel, dmrTXLevel, p25TXLevel); m_modem->setSymbolAdjust(dmrSymLevel3Adj, dmrSymLevel1Adj, p25SymLevel3Adj, p25SymLevel1Adj); - m_modem->setRFParams(m_rxFrequency, m_txFrequency, txDCOffset, rxDCOffset); + m_modem->setDCOffsetParams(txDCOffset, rxDCOffset); + m_modem->setRFParams(m_rxFrequency, m_txFrequency, rfPower); m_modem->setDMRColorCode(m_dmrColorCode); m_modem->setP25NAC(m_p25NAC); diff --git a/host/calibrate/HostCal.cpp b/host/calibrate/HostCal.cpp index 5b00c041..0c169b4e 100644 --- a/host/calibrate/HostCal.cpp +++ b/host/calibrate/HostCal.cpp @@ -41,6 +41,7 @@ #include "Utils.h" using namespace modem; +using namespace lookups; #include #include @@ -151,6 +152,11 @@ HostCal::HostCal(const std::string& confFile) : m_debug(false), m_mode(STATE_DMR_CAL), m_modeStr(DMR_CAL_STR), + m_rxFrequency(0U), + m_txFrequency(0U), + m_channelId(0U), + m_channelNo(0U), + m_idenTable(NULL), m_berFrames(0U), m_berBits(0U), m_berErrs(0U), @@ -191,12 +197,75 @@ int HostCal::run() getHostVersion(); ::LogInfo(">> Modem Calibration"); + yaml::Node systemConf = m_conf["system"]; + + // try to load bandplan identity table + std::string idenLookupFile = systemConf["iden_table"]["file"].as(); + uint32_t idenReloadTime = systemConf["iden_table"]["time"].as(0U); + + if (idenLookupFile.length() <= 0U) { + ::LogError(LOG_HOST, "No bandplan identity table? This must be defined!"); + return 1; + } + + LogInfo("Iden Table Lookups"); + LogInfo(" File: %s", idenLookupFile.length() > 0U ? idenLookupFile.c_str() : "None"); + if (idenReloadTime > 0U) + LogInfo(" Reload: %u mins", idenReloadTime); + + m_idenTable = new IdenTableLookup(idenLookupFile, idenReloadTime); + m_idenTable->read(); + LogInfo("General Parameters"); - yaml::Node systemConf = m_conf["system"]; std::string identity = systemConf["identity"].as(); ::LogInfo(" Identity: %s", identity.c_str()); + yaml::Node rfssConfig = systemConf["config"]; + m_channelId = (uint8_t)rfssConfig["channelId"].as(0U); + if (m_channelId > 15U) { // clamp to 15 + m_channelId = 15U; + } + + IdenTable entry = m_idenTable->find(m_channelId); + if (entry.baseFrequency() == 0U) { + ::LogError(LOG_HOST, "Channel Id %u has an invalid base frequency.", m_channelId); + return false; + } + + m_channelNo = (uint32_t)::strtoul(rfssConfig["channelNo"].as("1").c_str(), NULL, 16); + if (m_channelNo == 0U) { // clamp to 1 + m_channelNo = 1U; + } + if (m_channelNo > 4095U) { // clamp to 4095 + m_channelNo = 4095U; + } + + if (m_duplex) { + if (entry.txOffsetMhz() == 0U) { + ::LogError(LOG_HOST, "Channel Id %u has an invalid Tx offset.", m_channelId); + return false; + } + + uint32_t calcSpace = (uint32_t)(entry.chSpaceKhz() / 0.125); + float calcTxOffset = entry.txOffsetMhz() * 1000000; + + m_rxFrequency = (uint32_t)((entry.baseFrequency() + ((calcSpace * 125) * m_channelNo)) + calcTxOffset); + m_txFrequency = (uint32_t)((entry.baseFrequency() + ((calcSpace * 125) * m_channelNo))); + } + else { + uint32_t calcSpace = (uint32_t)(entry.chSpaceKhz() / 0.125); + + m_rxFrequency = (uint32_t)((entry.baseFrequency() + ((calcSpace * 125) * m_channelNo))); + m_txFrequency = m_rxFrequency; + } + + 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()); + yaml::Node modemConf = systemConf["modem"]; yaml::Node modemProtocol = modemConf["protocol"]; @@ -617,7 +686,17 @@ bool HostCal::portModemOpen(Modem* modem) { sleep(2000U); - bool ret = writeConfig(); + bool ret = writeRFParams(); + if (!ret) { + ret = writeRFParams(); + if (!ret) { + LogError(LOG_MODEM, "Modem unresponsive to RF parameters set after 2 attempts. Stopping."); + m_modem->close(); + return false; + } + } + + ret = writeConfig(); if (!ret) { ret = writeConfig(); if (!ret) { @@ -1558,6 +1637,44 @@ bool HostCal::writeConfig(uint8_t modeOverride) return true; } +/// +/// Write RF parameters to the air interface modem. +/// +/// +bool HostCal::writeRFParams() +{ + unsigned char buffer[13U]; + + buffer[0U] = DVM_FRAME_START; + buffer[1U] = 13U; + buffer[2U] = CMD_SET_RFPARAMS; + + 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[8U] = (m_txFrequency >> 0) & 0xFFU; + buffer[9U] = (m_txFrequency >> 8) & 0xFFU; + buffer[10U] = (m_txFrequency >> 16) & 0xFFU; + buffer[11U] = (m_txFrequency >> 24) & 0xFFU; + + buffer[12U] = (unsigned char)(100 * 2.55F + 0.5F); // cal sets power fixed to 100 + + // CUtils::dump(1U, "Written", buffer, len); + + int ret = m_modem->write(buffer, 13U); + if (ret <= 0) + return false; + + sleep(10U); + + m_modem->clock(0U); + return true; +} + /// /// Write symbol level adjustments to the modem DSP. /// @@ -1655,7 +1772,7 @@ void HostCal::printStatus() 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, " - Operating Mode: %s", m_modeStr.c_str()); + LogMessage(LOG_CAL, " - Rx Freq: %uHz, Tx Freq: %uHz, Operating Mode: %s", m_rxFrequency, m_txFrequency, m_modeStr.c_str()); uint8_t buffer[50U]; diff --git a/host/calibrate/HostCal.h b/host/calibrate/HostCal.h index 1ce54215..8b84c765 100644 --- a/host/calibrate/HostCal.h +++ b/host/calibrate/HostCal.h @@ -37,6 +37,7 @@ #include "modem/Modem.h" #include "host/calibrate/Console.h" #include "host/Host.h" +#include "lookups/IdenTableLookup.h" #include "yaml/Yaml.h" #include @@ -98,6 +99,13 @@ private: uint8_t m_mode; std::string m_modeStr; + uint32_t m_rxFrequency; + uint32_t m_txFrequency; + uint8_t m_channelId; + uint32_t m_channelNo; + + lookups::IdenTableLookup* m_idenTable; + uint32_t m_berFrames; uint32_t m_berBits; uint32_t m_berErrs; @@ -150,6 +158,8 @@ private: bool writeConfig(); /// Write configuration to the modem DSP. bool writeConfig(uint8_t modeOverride); + /// Write RF parameters to the air interface modem. + bool writeRFParams(); /// Write symbol level adjustments to the modem DSP. bool writeSymbolAdjust(); /// Helper to sleep the calibration thread. diff --git a/modem/Modem.cpp b/modem/Modem.cpp index c37bf17b..093e188b 100644 --- a/modem/Modem.cpp +++ b/modem/Modem.cpp @@ -13,6 +13,7 @@ /* * Copyright (C) 2011-2021 by Jonathan Naylor G4KLX * Copyright (C) 2017-2021 by Bryan Biedenkapp N2PLL +* Copyright (C) 2021 by Nat Moore * * 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 @@ -96,6 +97,7 @@ Modem::Modem(port::IModemPort* port, bool duplex, bool rxInvert, bool txInvert, m_txDCOffset(0), m_rxFrequency(0U), m_txFrequency(0U), + m_rfPower(0U), m_dmrSymLevel3Adj(0), m_dmrSymLevel1Adj(0), m_p25SymLevel3Adj(0), @@ -218,6 +220,19 @@ void Modem::setSymbolAdjust(int dmrSymLevel3Adj, int dmrSymLevel1Adj, int p25Sym m_p25SymLevel1Adj = 0; } +/// +/// Sets the RF parameters. +/// +/// +/// +/// +void Modem::setRFParams(uint32_t rxFreq, uint32_t txFreq, uint8_t rfPower) +{ + m_rfPower = rfPower; + m_rxFrequency = rxFreq; + m_txFrequency = txFreq; +} + /// /// Sets the DMR color code. /// @@ -362,11 +377,11 @@ bool Modem::open() return true; } - ret = writeFrequency(); + ret = writeRFParams(); if (!ret) { - ret = writeFrequency(); + ret = writeRFParams(); if (!ret) { - LogError(LOG_MODEM, "Modem unresponsive to frequency set after 2 attempts. Stopping."); + LogError(LOG_MODEM, "Modem unresponsive to RF parameters set after 2 attempts. Stopping."); m_port->close(); return false; } @@ -1513,6 +1528,63 @@ bool Modem::writeSymbolAdjust() return true; } +/// +/// Write RF parameters to the air interface modem. +/// +/// +bool Modem::writeRFParams() +{ + unsigned char buffer[13U]; + + buffer[0U] = DVM_FRAME_START; + buffer[1U] = 13U; + buffer[2U] = CMD_SET_RFPARAMS; + + 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[8U] = (m_txFrequency >> 0) & 0xFFU; + buffer[9U] = (m_txFrequency >> 8) & 0xFFU; + buffer[10U] = (m_txFrequency >> 16) & 0xFFU; + buffer[11U] = (m_txFrequency >> 24) & 0xFFU; + + buffer[12U] = (unsigned char)(m_rfPower * 2.55F + 0.5F); + + // CUtils::dump(1U, "Written", buffer, len); + + int ret = m_port->write(buffer, 13U); + if (ret <= 0) + return false; + + unsigned int count = 0U; + RESP_TYPE_DVM resp; + do { + Thread::sleep(10U); + + resp = getResponse(); + if (resp == RTM_OK && m_buffer[2U] != RSN_OK && m_buffer[2U] != RSN_NAK) { + count++; + if (count >= MAX_RESPONSES) { + LogError(LOG_MODEM, "The DVM is not responding to the SET_RFPARAMS command"); + return false; + } + } + } while (resp == RTM_OK && m_buffer[2U] != RSN_OK && m_buffer[2U] != RSN_NAK); + + // CUtils::dump(1U, "Response", m_buffer, m_length); + + if (resp == RTM_OK && m_buffer[2U] == RSN_NAK) { + LogError(LOG_MODEM, "Received a NAK to the SET_RFPARAMS command from the modem"); + return false; + } + + return true; +} + /// /// Print debug air interface messages to the host log. /// diff --git a/modem/Modem.h b/modem/Modem.h index 61801eee..d159994d 100644 --- a/modem/Modem.h +++ b/modem/Modem.h @@ -13,6 +13,7 @@ /* * Copyright (C) 2011-2021 by Jonathan Naylor G4KLX * Copyright (C) 2017-2021 by Bryan Biedenkapp N2PLL +* Copyright (C) 2021 by Nat Moore * * 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 @@ -100,7 +101,7 @@ namespace modem CMD_SET_SYMLVLADJ = 0x04U, CMD_SET_RXLEVEL = 0x05U, - CMD_SET_FREQUENCY = 0x06U, + CMD_SET_RFPARAMS = 0x06U, CMD_CAL_DATA = 0x08U, CMD_RSSI_DATA = 0x09U, @@ -191,6 +192,8 @@ namespace modem void setLevels(float rxLevel, float cwIdTXLevel, float dmrTXLevel, float p25TXLevel); /// Sets the symbol adjustment levels. void setSymbolAdjust(int dmrSymLevel3Adj, int dmrSymLevel1Adj, int p25SymLevel3Adj, int p25SymLevel1Adj); + /// Sets the RF parameters. + void setRFParams(uint32_t rxFreq, uint32_t txFreq, uint8_t rfPower); /// Sets the DMR color code. void setDMRColorCode(uint32_t colorCode); /// Sets the P25 NAC. @@ -315,6 +318,7 @@ namespace modem uint32_t m_rxFrequency; uint32_t m_txFrequency; + uint8_t m_rfPower; int m_dmrSymLevel3Adj; int m_dmrSymLevel1Adj; @@ -364,7 +368,8 @@ namespace modem bool writeConfig(); /// Write symbol level adjustments to the air interface modem. bool writeSymbolAdjust(); - bool writeFrequency(); + /// Write RF parameters to the air interface modem. + bool writeRFParams(); /// Print debug air interface messages to the host log. void printDebug(const uint8_t* buffer, uint16_t len);