From b3c803e918ee745f25976f9575a4d93ca66d2377 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Wed, 13 Dec 2023 10:54:32 -0500 Subject: [PATCH] implement fix for CSBK verbosity not being set; during CC stream hide CSBK/TSBK/RCCH verbosity; implement CSBKO_MAINT CSBK; correct missing behavior to perform DMR payload activation; add CRC handling for MBC; --- src/dmr/Control.cpp | 3 +- src/dmr/DMRDefines.h | 4 ++ src/dmr/Slot.cpp | 14 ++++ src/dmr/data/DataHeader.cpp | 27 ++++--- src/dmr/lc/CSBK.cpp | 102 ++++++++++++++++++++++----- src/dmr/lc/CSBK.h | 9 ++- src/dmr/lc/csbk/CSBKFactory.cpp | 29 ++++++-- src/dmr/lc/csbk/CSBKFactory.h | 3 +- src/dmr/lc/csbk/CSBK_MAINT.cpp | 98 +++++++++++++++++++++++++ src/dmr/lc/csbk/CSBK_MAINT.h | 60 ++++++++++++++++ src/dmr/packet/ControlSignaling.cpp | 27 ++++--- src/dmr/packet/ControlSignaling.h | 4 +- src/nxdn/lc/RCCH.h | 2 + src/nxdn/packet/ControlSignaling.cpp | 7 ++ src/p25/lc/TSBK.h | 2 + src/p25/packet/ControlSignaling.cpp | 7 ++ 16 files changed, 352 insertions(+), 46 deletions(-) create mode 100644 src/dmr/lc/csbk/CSBK_MAINT.cpp create mode 100644 src/dmr/lc/csbk/CSBK_MAINT.h diff --git a/src/dmr/Control.cpp b/src/dmr/Control.cpp index afa15ab6..3f0812df 100644 --- a/src/dmr/Control.cpp +++ b/src/dmr/Control.cpp @@ -97,6 +97,7 @@ Control::Control(bool authoritative, uint32_t colorCode, uint32_t callHang, uint acl::AccessControl::init(m_ridLookup, m_tidLookup); Slot::init(this, authoritative, colorCode, SiteData(), embeddedLCOnly, dumpTAData, callHang, modem, network, duplex, m_ridLookup, m_tidLookup, m_idenTable, rssiMapper, jitter, verbose); + lc::CSBK::setVerbose(m_dumpCSBKData); m_slot1 = new Slot(1U, timeout, tgHang, queueSize, dumpDataPacket, repeatDataPacket, dumpCSBKData, debug, verbose); m_slot2 = new Slot(2U, timeout, tgHang, queueSize, dumpDataPacket, repeatDataPacket, dumpCSBKData, debug, verbose); @@ -297,7 +298,7 @@ bool Control::processWakeup(const uint8_t* data) return false; // generate a new CSBK and check validity - std::unique_ptr csbk = lc::csbk::CSBKFactory::createCSBK(data + 2U); + std::unique_ptr csbk = lc::csbk::CSBKFactory::createCSBK(data + 2U, DT_CSBK); if (csbk == nullptr) return false; diff --git a/src/dmr/DMRDefines.h b/src/dmr/DMRDefines.h index 72c80888..12183805 100644 --- a/src/dmr/DMRDefines.h +++ b/src/dmr/DMRDefines.h @@ -99,6 +99,7 @@ namespace dmr const uint8_t PI_HEADER_CRC_MASK[] = { 0x69U, 0x69U }; const uint8_t DATA_HEADER_CRC_MASK[] = { 0xCCU, 0xCCU }; const uint8_t CSBK_CRC_MASK[] = { 0xA5U, 0xA5U }; + const uint8_t CSBK_MBC_CRC_MASK[] = { 0xAAU, 0xAAU }; const uint16_t TSCC_MAX_CSC_CNT = 511U; @@ -193,6 +194,8 @@ namespace dmr const uint8_t DT_TERMINATOR_WITH_LC = 0x02U; #define DMR_DT_TERMINATOR_WITH_LC "DMR_DT_TERMINATOR_WITH_LC (Terminator with Link Control)" const uint8_t DT_CSBK = 0x03U; + const uint8_t DT_MBC_HEADER = 0x04U; + const uint8_t DT_MBC_DATA = 0x05U; const uint8_t DT_DATA_HEADER = 0x06U; #define DMR_DT_DATA_HEADER "DMR_DT_DATA_HEADER (Data Header)" const uint8_t DT_RATE_12_DATA = 0x07U; @@ -303,6 +306,7 @@ namespace dmr const uint8_t CSBKO_EXT_FNCT = 0x24U; // (DMRA) EXT FNCT - Extended Function const uint8_t CSBKO_NACK_RSP = 0x26U; // NACK RSP - Negative Acknowledgement Response const uint8_t CSBKO_BROADCAST = 0x28U; // BCAST - Announcement PDU + const uint8_t CSBKO_MAINT = 0x2AU; // MAINT - Call Maintainence PDU const uint8_t CSBKO_P_CLEAR = 0x2EU; // P_CLEAR - Payload Channel Clear const uint8_t CSBKO_PV_GRANT = 0x30U; // PV_GRANT - Private Voice Channel Grant const uint8_t CSBKO_TV_GRANT = 0x31U; // TV_GRANT - Talkgroup Voice Channel Grant diff --git a/src/dmr/Slot.cpp b/src/dmr/Slot.cpp index 11d67311..1f82af18 100644 --- a/src/dmr/Slot.cpp +++ b/src/dmr/Slot.cpp @@ -751,6 +751,13 @@ void Slot::setTSCCActivated(uint32_t dstId, uint32_t srcId, bool group, bool voi m_tsccPayloadDstId = dstId; m_tsccPayloadGroup = group; m_tsccPayloadVoice = voice; + + // start payload channel transmit + if (!m_modem->hasTX()) { + m_modem->writeDMRStart(true); + } + + m_control->writeRF_CSBK_Payload_Activate(dstId, srcId, group, voice); } /// @@ -1312,6 +1319,11 @@ void Slot::writeRF_ControlData(uint16_t frameCnt, uint8_t n) if (!m_enableTSCC) return; + // disable verbose CSBK dumping during control data writes (if necessary) + bool csbkVerbose = lc::CSBK::getVerbose(); + if (csbkVerbose) + lc::CSBK::setVerbose(false); + // don't add any frames if the queue is full uint8_t len = DMR_FRAME_LENGTH_BYTES + 2U; uint32_t space = m_txQueue.freeSpace(); @@ -1393,6 +1405,8 @@ void Slot::writeRF_ControlData(uint16_t frameCnt, uint8_t n) n++; i++; } while (i <= seqCnt); + + lc::CSBK::setVerbose(csbkVerbose); } /// diff --git a/src/dmr/data/DataHeader.cpp b/src/dmr/data/DataHeader.cpp index 3218b16f..5e82c445 100644 --- a/src/dmr/data/DataHeader.cpp +++ b/src/dmr/data/DataHeader.cpp @@ -13,7 +13,7 @@ /* * Copyright (C) 2012 by Ian Wraith * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX -* Copyright (C) 2021 Bryan Biedenkapp N2PLL +* Copyright (C) 2021,2023 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 @@ -371,15 +371,26 @@ void DataHeader::encode(uint8_t* data) const break; } - // compute CRC-CCITT 16 - m_data[10U] ^= DATA_HEADER_CRC_MASK[0U]; - m_data[11U] ^= DATA_HEADER_CRC_MASK[1U]; + if (m_DPF == DPF_UDT) { + m_data[9U] &= 0xFEU; - edac::CRC::addCCITT162(m_data, DMR_LC_HEADER_LENGTH_BYTES); + edac::CRC::addCCITT162(m_data, DMR_LC_HEADER_LENGTH_BYTES); + + // restore the checksum + m_data[10U] ^= DATA_HEADER_CRC_MASK[0U]; + m_data[11U] ^= DATA_HEADER_CRC_MASK[1U]; + } + else { + // compute CRC-CCITT 16 + m_data[10U] ^= DATA_HEADER_CRC_MASK[0U]; + m_data[11U] ^= DATA_HEADER_CRC_MASK[1U]; + + edac::CRC::addCCITT162(m_data, DMR_LC_HEADER_LENGTH_BYTES); - // restore the checksum - m_data[10U] ^= DATA_HEADER_CRC_MASK[0U]; - m_data[11U] ^= DATA_HEADER_CRC_MASK[1U]; + // restore the checksum + m_data[10U] ^= DATA_HEADER_CRC_MASK[0U]; + m_data[11U] ^= DATA_HEADER_CRC_MASK[1U]; + } // encode BPTC (196,96) FEC edac::BPTC19696 bptc; diff --git a/src/dmr/lc/CSBK.cpp b/src/dmr/lc/CSBK.cpp index f3fd0d50..2f3c6465 100644 --- a/src/dmr/lc/CSBK.cpp +++ b/src/dmr/lc/CSBK.cpp @@ -12,7 +12,7 @@ // /* * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX -* Copyright (C) 2019-2021 by Bryan Biedenkapp N2PLL +* Copyright (C) 2019-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 @@ -76,6 +76,7 @@ CSBK::CSBK() : m_dstId(0U), m_dataContent(false), m_CBF(0U), + m_dataType(DT_CSBK), m_emergency(false), m_privacy(false), m_supplementData(false), @@ -114,8 +115,9 @@ std::string CSBK::toString() /// Regenerate a DMR CSBK without decoding. /// /// +/// /// True, if TSBK was decoded, otherwise false. -bool CSBK::regenerate(uint8_t* data) +bool CSBK::regenerate(uint8_t* data, uint8_t dataType) { uint8_t csbk[DMR_CSBK_LENGTH_BYTES]; ::memset(csbk, 0x00U, DMR_CSBK_LENGTH_BYTES); @@ -125,8 +127,16 @@ bool CSBK::regenerate(uint8_t* data) bptc.decode(data, csbk); // validate the CRC-CCITT 16 - csbk[10U] ^= CSBK_CRC_MASK[0U]; - csbk[11U] ^= CSBK_CRC_MASK[1U]; + switch (dataType) { + case DT_CSBK: + csbk[10U] ^= CSBK_CRC_MASK[0U]; + csbk[11U] ^= CSBK_CRC_MASK[1U]; + break; + case DT_MBC_HEADER: + csbk[10U] ^= CSBK_MBC_CRC_MASK[0U]; + csbk[11U] ^= CSBK_MBC_CRC_MASK[1U]; + break; + } bool valid = edac::CRC::checkCCITT162(csbk, DMR_CSBK_LENGTH_BYTES); if (!valid) { @@ -135,17 +145,41 @@ bool CSBK::regenerate(uint8_t* data) } // restore the checksum - csbk[10U] ^= CSBK_CRC_MASK[0U]; - csbk[11U] ^= CSBK_CRC_MASK[1U]; + switch (dataType) { + case DT_CSBK: + csbk[10U] ^= CSBK_CRC_MASK[0U]; + csbk[11U] ^= CSBK_CRC_MASK[1U]; + break; + case DT_MBC_HEADER: + csbk[10U] ^= CSBK_MBC_CRC_MASK[0U]; + csbk[11U] ^= CSBK_MBC_CRC_MASK[1U]; + break; + } // calculate checksum - csbk[10U] ^= CSBK_CRC_MASK[0U]; - csbk[11U] ^= CSBK_CRC_MASK[1U]; + switch (dataType) { + case DT_CSBK: + csbk[10U] ^= CSBK_CRC_MASK[0U]; + csbk[11U] ^= CSBK_CRC_MASK[1U]; + break; + case DT_MBC_HEADER: + csbk[10U] ^= CSBK_MBC_CRC_MASK[0U]; + csbk[11U] ^= CSBK_MBC_CRC_MASK[1U]; + break; + } edac::CRC::addCCITT162(csbk, 12U); - csbk[10U] ^= CSBK_CRC_MASK[0U]; - csbk[11U] ^= CSBK_CRC_MASK[1U]; + switch (dataType) { + case DT_CSBK: + csbk[10U] ^= CSBK_CRC_MASK[0U]; + csbk[11U] ^= CSBK_CRC_MASK[1U]; + break; + case DT_MBC_HEADER: + csbk[10U] ^= CSBK_MBC_CRC_MASK[0U]; + csbk[11U] ^= CSBK_MBC_CRC_MASK[1U]; + break; + } // encode BPTC (196,96) FEC bptc.encode(csbk, data); @@ -217,8 +251,16 @@ bool CSBK::decode(const uint8_t* data, uint8_t* csbk) bptc.decode(data, csbk); // validate the CRC-CCITT 16 - csbk[10U] ^= CSBK_CRC_MASK[0U]; - csbk[11U] ^= CSBK_CRC_MASK[1U]; + switch (m_dataType) { + case DT_CSBK: + csbk[10U] ^= CSBK_CRC_MASK[0U]; + csbk[11U] ^= CSBK_CRC_MASK[1U]; + break; + case DT_MBC_HEADER: + csbk[10U] ^= CSBK_MBC_CRC_MASK[0U]; + csbk[11U] ^= CSBK_MBC_CRC_MASK[1U]; + break; + } bool valid = edac::CRC::checkCCITT162(csbk, DMR_CSBK_LENGTH_BYTES); if (!valid) { @@ -227,8 +269,16 @@ bool CSBK::decode(const uint8_t* data, uint8_t* csbk) } // restore the checksum - csbk[10U] ^= CSBK_CRC_MASK[0U]; - csbk[11U] ^= CSBK_CRC_MASK[1U]; + switch (m_dataType) { + case DT_CSBK: + csbk[10U] ^= CSBK_CRC_MASK[0U]; + csbk[11U] ^= CSBK_CRC_MASK[1U]; + break; + case DT_MBC_HEADER: + csbk[10U] ^= CSBK_MBC_CRC_MASK[0U]; + csbk[11U] ^= CSBK_MBC_CRC_MASK[1U]; + break; + } if (m_verbose) { Utils::dump(2U, "Decoded CSBK", csbk, DMR_CSBK_LENGTH_BYTES); @@ -269,13 +319,29 @@ void CSBK::encode(uint8_t* data, const uint8_t* csbk) outCsbk[1U] = m_colorCode & 0x0FU; // Cdef uses Color Code } - outCsbk[10U] ^= CSBK_CRC_MASK[0U]; - outCsbk[11U] ^= CSBK_CRC_MASK[1U]; + switch (m_dataType) { + case DT_CSBK: + outCsbk[10U] ^= CSBK_CRC_MASK[0U]; + outCsbk[11U] ^= CSBK_CRC_MASK[1U]; + break; + case DT_MBC_HEADER: + outCsbk[10U] ^= CSBK_MBC_CRC_MASK[0U]; + outCsbk[11U] ^= CSBK_MBC_CRC_MASK[1U]; + break; + } edac::CRC::addCCITT162(outCsbk, 12U); - outCsbk[10U] ^= CSBK_CRC_MASK[0U]; - outCsbk[11U] ^= CSBK_CRC_MASK[1U]; + switch (m_dataType) { + case DT_CSBK: + outCsbk[10U] ^= CSBK_CRC_MASK[0U]; + outCsbk[11U] ^= CSBK_CRC_MASK[1U]; + break; + case DT_MBC_HEADER: + outCsbk[10U] ^= CSBK_MBC_CRC_MASK[0U]; + outCsbk[11U] ^= CSBK_MBC_CRC_MASK[1U]; + break; + } if (m_verbose) { Utils::dump(2U, "Encoded CSBK", outCsbk, DMR_CSBK_LENGTH_BYTES); diff --git a/src/dmr/lc/CSBK.h b/src/dmr/lc/CSBK.h index eca81351..e584ead7 100644 --- a/src/dmr/lc/CSBK.h +++ b/src/dmr/lc/CSBK.h @@ -12,7 +12,7 @@ // /* * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX -* Copyright (C) 2019-2021 by Bryan Biedenkapp N2PLL +* Copyright (C) 2019-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 @@ -64,8 +64,10 @@ namespace dmr /// Regenerate a DMR CSBK without decoding. /// This is because the DMR archeticture allows fall-thru of unsupported CSBKs. - static bool regenerate(uint8_t* data); + static bool regenerate(uint8_t* data, uint8_t dataType); + /// Gets the flag indicating verbose log output. + static bool getVerbose() { return m_verbose; } /// Sets the flag indicating verbose log output. static void setVerbose(bool verbose) { m_verbose = verbose; } @@ -104,6 +106,9 @@ namespace dmr /// Number of blocks to follow. __PROTECTED_PROPERTY(uint8_t, CBF, CBF); + /// Data type for this CSBK. + __PROTECTED_PROPERTY(uint8_t, dataType, DataType); + /** Common Service Options */ /// Flag indicating the emergency bits are set. __PROTECTED_PROPERTY(bool, emergency, Emergency); diff --git a/src/dmr/lc/csbk/CSBKFactory.cpp b/src/dmr/lc/csbk/CSBKFactory.cpp index 5be55ad6..9125bc5d 100644 --- a/src/dmr/lc/csbk/CSBKFactory.cpp +++ b/src/dmr/lc/csbk/CSBKFactory.cpp @@ -60,8 +60,9 @@ CSBKFactory::~CSBKFactory() /// Create an instance of a CSBK. /// /// +/// /// True, if CSBK was decoded, otherwise false. -std::unique_ptr CSBKFactory::createCSBK(const uint8_t* data) +std::unique_ptr CSBKFactory::createCSBK(const uint8_t* data, uint8_t dataType) { assert(data != nullptr); @@ -72,8 +73,16 @@ std::unique_ptr CSBKFactory::createCSBK(const uint8_t* data) bptc.decode(data, csbk); // validate the CRC-CCITT 16 - csbk[10U] ^= CSBK_CRC_MASK[0U]; - csbk[11U] ^= CSBK_CRC_MASK[1U]; + switch (dataType) { + case DT_CSBK: + csbk[10U] ^= CSBK_CRC_MASK[0U]; + csbk[11U] ^= CSBK_CRC_MASK[1U]; + break; + case DT_MBC_HEADER: + csbk[10U] ^= CSBK_MBC_CRC_MASK[0U]; + csbk[11U] ^= CSBK_MBC_CRC_MASK[1U]; + break; + } bool valid = edac::CRC::checkCCITT162(csbk, DMR_CSBK_LENGTH_BYTES); if (!valid) { @@ -82,8 +91,16 @@ std::unique_ptr CSBKFactory::createCSBK(const uint8_t* data) } // restore the checksum - csbk[10U] ^= CSBK_CRC_MASK[0U]; - csbk[11U] ^= CSBK_CRC_MASK[1U]; + switch (dataType) { + case DT_CSBK: + csbk[10U] ^= CSBK_CRC_MASK[0U]; + csbk[11U] ^= CSBK_CRC_MASK[1U]; + break; + case DT_MBC_HEADER: + csbk[10U] ^= CSBK_MBC_CRC_MASK[0U]; + csbk[11U] ^= CSBK_MBC_CRC_MASK[1U]; + break; + } uint8_t CSBKO = csbk[0U] & 0x3FU; // CSBKO uint8_t FID = csbk[1U]; // Feature ID @@ -114,6 +131,8 @@ std::unique_ptr CSBKFactory::createCSBK(const uint8_t* data) /** Tier 3 */ case CSBKO_ACK_RSP: return decode(new CSBK_ACK_RSP(), data); + case CSBKO_MAINT: + return decode(new CSBK_MAINT(), data); default: LogError(LOG_DMR, "CSBKFactory::create(), unknown CSBK type, csbko = $%02X", CSBKO); diff --git a/src/dmr/lc/csbk/CSBKFactory.h b/src/dmr/lc/csbk/CSBKFactory.h index fc46eaed..4dae6da0 100644 --- a/src/dmr/lc/csbk/CSBKFactory.h +++ b/src/dmr/lc/csbk/CSBKFactory.h @@ -36,6 +36,7 @@ #include "dmr/lc/csbk/CSBK_CALL_ALRT.h" #include "dmr/lc/csbk/CSBK_DVM_GIT_HASH.h" #include "dmr/lc/csbk/CSBK_EXT_FNCT.h" +#include "dmr/lc/csbk/CSBK_MAINT.h" #include "dmr/lc/csbk/CSBK_NACK_RSP.h" #include "dmr/lc/csbk/CSBK_P_CLEAR.h" #include "dmr/lc/csbk/CSBK_P_GRANT.h" @@ -68,7 +69,7 @@ namespace dmr ~CSBKFactory(); /// Create an instance of a CSBK. - static std::unique_ptr createCSBK(const uint8_t* data); + static std::unique_ptr createCSBK(const uint8_t* data, uint8_t dataType); private: /// diff --git a/src/dmr/lc/csbk/CSBK_MAINT.cpp b/src/dmr/lc/csbk/CSBK_MAINT.cpp new file mode 100644 index 00000000..042323cc --- /dev/null +++ b/src/dmr/lc/csbk/CSBK_MAINT.cpp @@ -0,0 +1,98 @@ +/** +* 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 "Defines.h" +#include "dmr/lc/csbk/CSBK_MAINT.h" +#include "Log.h" +#include "Utils.h" + +using namespace dmr::lc::csbk; +using namespace dmr::lc; +using namespace dmr; + +#include +#include + +// --------------------------------------------------------------------------- +// Public Class Members +// --------------------------------------------------------------------------- + +/// +/// Initializes a new instance of the CSBK_MAINT class. +/// +CSBK_MAINT::CSBK_MAINT() : CSBK() +{ + m_CSBKO = CSBKO_MAINT; +} + +/// +/// Decode a control signalling block. +/// +/// +/// True, if CSBK was decoded, otherwise false. +bool CSBK_MAINT::decode(const uint8_t* data) +{ + assert(data != NULL); + + uint8_t csbk[DMR_CSBK_LENGTH_BYTES]; + ::memset(csbk, 0x00U, DMR_CSBK_LENGTH_BYTES); + + bool ret = CSBK::decode(data, csbk); + if (!ret) + return false; + + ulong64_t csbkValue = CSBK::toValue(csbk); + + m_dstId = (uint32_t)((csbkValue >> 24) & 0xFFFFU); // Target Radio Address + m_srcId = (uint32_t)(csbkValue & 0xFFFFFFU); // Source Radio Address + + return true; +} + +/// +/// Encode a control signalling block. +/// +/// +void CSBK_MAINT::encode(uint8_t* data) +{ + assert(data != NULL); + + ulong64_t csbkValue = 0U; + + csbkValue = (csbkValue << 25) + m_dstId; // Target Radio Address + csbkValue = (csbkValue << 24) + m_srcId; // Source Radio Address + + std::unique_ptr csbk = CSBK::fromValue(csbkValue); + CSBK::encode(data, csbk.get()); +} + +/// +/// Returns a string that represents the current CSBK. +/// +/// +std::string CSBK_MAINT::toString() +{ + return std::string("CSBKO_MAINT (Call Maintainence)"); +} diff --git a/src/dmr/lc/csbk/CSBK_MAINT.h b/src/dmr/lc/csbk/CSBK_MAINT.h new file mode 100644 index 00000000..ac1fb9ff --- /dev/null +++ b/src/dmr/lc/csbk/CSBK_MAINT.h @@ -0,0 +1,60 @@ +/** +* 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_LC_CSBK__CSBK_MAINT_H__) +#define __DMR_LC_CSBK__CSBK_MAINT_H__ + +#include "Defines.h" +#include "dmr/lc/CSBK.h" + +namespace dmr +{ + namespace lc + { + namespace csbk + { + // --------------------------------------------------------------------------- + // Class Declaration + // Implements MAINT - Call Maintainence + // --------------------------------------------------------------------------- + + class HOST_SW_API CSBK_MAINT : public CSBK { + public: + /// Initializes a new instance of the CSBK_MAINT class. + CSBK_MAINT(); + + /// Decode a control signalling block. + bool decode(const uint8_t* data); + /// Encode a control signalling block. + void encode(uint8_t* data); + + /// Returns a string that represents the current CSBK. + virtual std::string toString() override; + }; + } // namespace csbk + } // namespace lc +} // namespace dmr + +#endif // __DMR_LC_CSBK__CSBK_MAINT_H__ diff --git a/src/dmr/packet/ControlSignaling.cpp b/src/dmr/packet/ControlSignaling.cpp index f062e557..6c9974b6 100644 --- a/src/dmr/packet/ControlSignaling.cpp +++ b/src/dmr/packet/ControlSignaling.cpp @@ -161,7 +161,7 @@ bool ControlSignaling::process(uint8_t* data, uint32_t len) if (dataType == DT_CSBK) { // generate a new CSBK and check validity - std::unique_ptr csbk = CSBKFactory::createCSBK(data + 2U); + std::unique_ptr csbk = CSBKFactory::createCSBK(data + 2U, dataType); if (csbk == nullptr) return false; @@ -367,7 +367,7 @@ bool ControlSignaling::process(uint8_t* data, uint32_t len) if (!handled) { // regenerate the CSBK data - lc::CSBK::regenerate(data + 2U); + lc::CSBK::regenerate(data + 2U, dataType); // regenerate the Slot Type slotType.encode(data + 2U); @@ -404,7 +404,7 @@ void ControlSignaling::processNetwork(const data::Data & dmrData) dmrData.getData(data + 2U); if (dataType == DT_CSBK) { - std::unique_ptr csbk = CSBKFactory::createCSBK(data + 2U); + std::unique_ptr csbk = CSBKFactory::createCSBK(data + 2U, dataType); if (csbk == nullptr) { LogError(LOG_NET, "DMR Slot %u, DT_CSBK, unable to decode the network CSBK", m_slot->m_slotNo); return; @@ -555,7 +555,7 @@ void ControlSignaling::processNetwork(const data::Data & dmrData) if (!handled) { // regenerate the CSBK data - lc::CSBK::regenerate(data + 2U); + lc::CSBK::regenerate(data + 2U, dataType); // regenerate the Slot Type SlotType slotType; @@ -1341,11 +1341,13 @@ void ControlSignaling::writeRF_CSBK_Grant_LateEntry(uint32_t dstId, uint32_t src } /// -/// Helper to write a payload grant to a TSCC payload channel on the RF interface. +/// Helper to write a payload random access to a TSCC payload channel on the RF interface. /// /// /// -void ControlSignaling::writeRF_CSBK_Payload_Grant(uint32_t dstId, uint32_t srcId, bool grp, bool voice) +/// +/// +void ControlSignaling::writeRF_CSBK_Payload_Activate(uint32_t dstId, uint32_t srcId, bool grp, bool voice) { std::unique_ptr csbk = new_unique(CSBK_P_GRANT); if (voice) { @@ -1365,6 +1367,8 @@ void ControlSignaling::writeRF_CSBK_Payload_Grant(uint32_t dstId, uint32_t srcId } } + csbk->setLastBlock(true); + csbk->setLogicalCh1(m_slot->m_channelNo); csbk->setSlotNo(m_slot->m_slotNo); @@ -1372,11 +1376,16 @@ void ControlSignaling::writeRF_CSBK_Payload_Grant(uint32_t dstId, uint32_t srcId csbk->setDstId(dstId); if (m_verbose) { - LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, %s, chNo = %u, slot = %u, srcId = %u, dstId = %u", - m_slot->m_slotNo, csbk->toString().c_str(), csbk->getLogicalCh1(), csbk->getSlotNo(), srcId, dstId); + LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, %s, csbko = $%02X, chNo = %u, slot = %u, srcId = %u, dstId = %u", + m_slot->m_slotNo, csbk->toString().c_str(), csbk->getCSBKO(), csbk->getLogicalCh1(), csbk->getSlotNo(), srcId, dstId); } - writeRF_CSBK(csbk.get()); + m_slot->setShortLC_Payload(m_slot->m_siteData, 1U); + for (int i = 0; i < 3; i++) { + writeRF_CSBK(csbk.get(), false, true); + for (int i = 0; i < 3; i++) + writeRF_CSBK(csbk.get()); + } } /// diff --git a/src/dmr/packet/ControlSignaling.h b/src/dmr/packet/ControlSignaling.h index dd0f1918..ebc99647 100644 --- a/src/dmr/packet/ControlSignaling.h +++ b/src/dmr/packet/ControlSignaling.h @@ -111,8 +111,8 @@ namespace dmr /// Helper to write a TSCC late entry channel grant packet on the RF interface. void writeRF_CSBK_Grant_LateEntry(uint32_t dstId, uint32_t srcId); - /// Helper to write a payload grant to a TSCC payload channel on the RF interface. - void writeRF_CSBK_Payload_Grant(uint32_t dstId, uint32_t srcId, bool grp, bool voice); + /// Helper to write a payload random access to a TSCC payload channel on the RF interface. + void writeRF_CSBK_Payload_Activate(uint32_t dstId, uint32_t srcId, bool grp, bool voice); /// Helper to write a TSCC Aloha broadcast packet on the RF interface. void writeRF_TSCC_Aloha(); diff --git a/src/nxdn/lc/RCCH.h b/src/nxdn/lc/RCCH.h index 9c623288..c8b8e6a1 100644 --- a/src/nxdn/lc/RCCH.h +++ b/src/nxdn/lc/RCCH.h @@ -61,6 +61,8 @@ namespace nxdn /// Returns a string that represents the current RCCH. virtual std::string toString(bool isp = false); + /// Gets the flag indicating verbose log output. + static bool getVerbose() { return m_verbose; } /// Sets the flag indicating verbose log output. static void setVerbose(bool verbose) { m_verbose = verbose; } diff --git a/src/nxdn/packet/ControlSignaling.cpp b/src/nxdn/packet/ControlSignaling.cpp index dc24e282..19aa9bdd 100644 --- a/src/nxdn/packet/ControlSignaling.cpp +++ b/src/nxdn/packet/ControlSignaling.cpp @@ -451,6 +451,11 @@ void ControlSignaling::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adj if (!m_nxdn->m_enableControl) return; + // disable verbose RCCH dumping during control data writes (if necessary) + bool rcchVerbose = lc::RCCH::getVerbose(); + if (rcchVerbose) + lc::RCCH::setVerbose(false); + // don't add any frames if the queue is full uint8_t len = NXDN_FRAME_LENGTH_BYTES + 2U; uint32_t space = m_nxdn->m_txQueue.freeSpace(); @@ -478,6 +483,8 @@ void ControlSignaling::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adj n++; i++; } while (i <= seqCnt); + + lc::RCCH::setVerbose(rcchVerbose); } /// diff --git a/src/p25/lc/TSBK.h b/src/p25/lc/TSBK.h index 7600dbe1..f244a989 100644 --- a/src/p25/lc/TSBK.h +++ b/src/p25/lc/TSBK.h @@ -80,6 +80,8 @@ namespace p25 /// Returns a string that represents the current TSBK. virtual std::string toString(bool isp = false); + /// Gets the flag indicating verbose log output. + static bool getVerbose() { return m_verbose; } /// Sets the flag indicating verbose log output. static void setVerbose(bool verbose) { m_verbose = verbose; } /// Sets the flag indicating CRC-errors should be warnings and not errors. diff --git a/src/p25/packet/ControlSignaling.cpp b/src/p25/packet/ControlSignaling.cpp index 0274343d..4c228e06 100644 --- a/src/p25/packet/ControlSignaling.cpp +++ b/src/p25/packet/ControlSignaling.cpp @@ -1795,6 +1795,11 @@ void ControlSignaling::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adj if (!m_p25->m_enableControl) return; + // disable verbose tSBK dumping during control data writes (if necessary) + bool tsbkVerbose = lc::TSBK::getVerbose(); + if (tsbkVerbose) + lc::TSBK::setVerbose(false); + if (m_convFallback) { bool fallbackTx = (frameCnt % 253U) == 0U; if (fallbackTx && n == 8U) { @@ -1935,6 +1940,8 @@ void ControlSignaling::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adj // reset MBF count m_mbfCnt = 0U; } + + lc::TSBK::setVerbose(tsbkVerbose); } ///