diff --git a/config.yml b/config.yml index d3d64b37..0015ca29 100644 --- a/config.yml +++ b/config.yml @@ -92,6 +92,7 @@ system: config: channelId: 2 channelNo: 1 + dmrNetId: 1 voiceChNo: - 1 colorCode: 5 diff --git a/dmr/Control.cpp b/dmr/Control.cpp index 7260117f..29020809 100644 --- a/dmr/Control.cpp +++ b/dmr/Control.cpp @@ -12,7 +12,7 @@ // /* * Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX -* Copyright (C) 2017,2020 by Bryan Biedenkapp +* Copyright (C) 2017-2021 by Bryan Biedenkapp * * 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 @@ -53,7 +53,8 @@ using namespace dmr; /// Flag indicating full-duplex operation. /// Instance of the RadioIdLookup class. /// Instance of the TalkgroupIdLookup class. -/// Instance of the CRSSIInterpolator class. +/// Instance of the IdenTableLookup class. +/// Instance of the RSSIInterpolator class. /// /// /// @@ -62,13 +63,14 @@ using namespace dmr; /// Flag indicating whether DMR verbose logging is enabled. Control::Control(uint32_t colorCode, uint32_t callHang, uint32_t queueSize, bool embeddedLCOnly, bool dumpTAData, uint32_t timeout, uint32_t tgHang, modem::Modem* modem, network::BaseNetwork* network, bool duplex, - lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup, lookups::RSSIInterpolator* rssi, + lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup, lookups::IdenTableLookup* idenTable, lookups::RSSIInterpolator* rssiMapper, uint32_t jitter, bool dumpDataPacket, bool repeatDataPacket, bool dumpCSBKData, bool debug, bool verbose) : m_colorCode(colorCode), m_modem(modem), m_network(network), m_slot1(NULL), m_slot2(NULL), + m_idenTable(idenTable), m_ridLookup(ridLookup), m_tidLookup(tidLookup), m_dumpCSBKData(dumpCSBKData), @@ -78,10 +80,11 @@ Control::Control(uint32_t colorCode, uint32_t callHang, uint32_t queueSize, bool assert(modem != NULL); assert(ridLookup != NULL); assert(tidLookup != NULL); - assert(rssi != NULL); + assert(idenTable != NULL); + assert(rssiMapper != NULL); acl::AccessControl::init(m_ridLookup, m_tidLookup); - Slot::init(colorCode, SiteData(), embeddedLCOnly, dumpTAData, callHang, modem, network, duplex, m_ridLookup, m_tidLookup, rssi, jitter); + Slot::init(colorCode, SiteData(), embeddedLCOnly, dumpTAData, callHang, modem, network, duplex, m_ridLookup, m_tidLookup, m_idenTable, rssiMapper, jitter); 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); @@ -96,6 +99,22 @@ Control::~Control() delete m_slot1; } +/// +/// Helper to set DMR configuration options. +/// +/// Instance of the ConfigINI class. +/// +/// +/// +/// +void Control::setOptions(yaml::Node& conf, uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo) +{ + yaml::Node systemConf = conf["system"]; + yaml::Node dmrProtocol = conf["protocols"]["dmr"]; + + Slot::setSiteData(netId, siteId, channelId, channelNo); +} + /// /// Helper to process wakeup frames from the RF interface. /// diff --git a/dmr/Control.h b/dmr/Control.h index d481ec2a..d04d1904 100644 --- a/dmr/Control.h +++ b/dmr/Control.h @@ -38,8 +38,10 @@ #include "network/BaseNetwork.h" #include "network/RemoteControl.h" #include "lookups/RSSIInterpolator.h" +#include "lookups/IdenTableLookup.h" #include "lookups/RadioIdLookup.h" #include "lookups/TalkgroupIdLookup.h" +#include "yaml/Yaml.h" namespace dmr { @@ -58,11 +60,14 @@ namespace dmr /// Initializes a new instance of the Control class. Control(uint32_t colorCode, uint32_t callHang, uint32_t queueSize, bool embeddedLCOnly, bool dumpTAData, uint32_t timeout, uint32_t tgHang, modem::Modem* modem, network::BaseNetwork* network, bool duplex, - lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup, lookups::RSSIInterpolator* rssi, + lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup, lookups::IdenTableLookup* idenTable, lookups::RSSIInterpolator* rssi, uint32_t jitter, bool dumpDataPacket, bool repeatDataPacket, bool dumpCSBKData, bool debug, bool verbose); /// Finalizes a instance of the Control class. ~Control(); + /// Helper to set DMR configuration options. + void setOptions(yaml::Node& conf, uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo); + /// Helper to process wakeup frames from the RF interface. bool processWakeup(const uint8_t* data); @@ -95,6 +100,7 @@ namespace dmr Slot* m_slot1; Slot* m_slot2; + lookups::IdenTableLookup* m_idenTable; lookups::RadioIdLookup* m_ridLookup; lookups::TalkgroupIdLookup* m_tidLookup; diff --git a/dmr/DMRDefines.h b/dmr/DMRDefines.h index a83787bc..13cdb8dd 100644 --- a/dmr/DMRDefines.h +++ b/dmr/DMRDefines.h @@ -131,6 +131,7 @@ namespace dmr const uint32_t DMR_EXT_FNCT_INHIBIT_ACK = 0x00FFU; // Radio Inhibit Ack const uint8_t DMR_ALOHA_VER_151 = 0x00U; + const uint8_t DMR_CHNULL = 0x00U; // Data Type(s) const uint8_t DT_VOICE_PI_HEADER = 0x00U; @@ -163,7 +164,7 @@ namespace dmr const uint8_t SLCO_TSCC = 0x02U; // Broadcast Announcement Type(s) - const uint8_t BCAST_ANNC_ANN_WD_TSCC = 0x00U; // Announce/Withdraw TSCC + const uint8_t BCAST_ANNC_ANN_WD_TSCC = 0x00U; // Announce-WD TSCC Channel const uint8_t BCAST_ANNC_CALL_TIMER_PARMS = 0x01U; // Specify Call Timer Parameters const uint8_t BCAST_ANNC_VOTE_NOW = 0x02U; // Vote Now Advice const uint8_t BCAST_ANNC_LOCAL_TIME = 0x03U; // Broadcast Local Time @@ -192,9 +193,9 @@ namespace dmr const uint8_t CSBKO_ACK_RSP = 0x20U; // ACK RSP - Acknowledge Response 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 PDUs const uint8_t CSBKO_BSDWNACT = 0x38U; // BS DWN ACT - BS Outbound Activation const uint8_t CSBKO_PRECCSBK = 0x3DU; // PRE CSBK - Preamble CSBK - const uint8_t CSBKO_BROADCAST = 0x40U; // BCAST - Announcement PDUs const uint8_t TALKER_ID_NONE = 0x00U; const uint8_t TALKER_ID_HEADER = 0x01U; diff --git a/dmr/Slot.cpp b/dmr/Slot.cpp index 454bfdd9..979f8a7f 100644 --- a/dmr/Slot.cpp +++ b/dmr/Slot.cpp @@ -43,6 +43,12 @@ using namespace dmr; #include #include +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +const uint16_t TSCC_MAX_CNT = 511U; + // --------------------------------------------------------------------------- // Static Class Members // --------------------------------------------------------------------------- @@ -56,9 +62,15 @@ bool Slot::m_dumpTAData = true; modem::Modem* Slot::m_modem = NULL; network::BaseNetwork* Slot::m_network = NULL; + bool Slot::m_duplex = true; + +lookups::IdenTableLookup* Slot::m_idenTable = NULL; lookups::RadioIdLookup* Slot::m_ridLookup = NULL; lookups::TalkgroupIdLookup* Slot::m_tidLookup = NULL; + +lookups::IdenTable Slot::m_idenEntry = lookups::IdenTable(); + uint32_t Slot::m_hangCount = 3U * 17U; lookups::RSSIInterpolator* Slot::m_rssiMapper = NULL; @@ -75,6 +87,8 @@ uint8_t Slot::m_flco2; uint8_t Slot::m_id2 = 0U; bool Slot::m_voice2 = true; +uint16_t Slot::m_tsccCnt = 0U; + // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- @@ -321,6 +335,14 @@ void Slot::clock() uint32_t ms = m_interval.elapsed(); m_interval.start(); + // increment the TSCC counter on every slot 1 clock + if (m_slotNo == 1U) { + m_tsccCnt++; + if (m_tsccCnt == TSCC_MAX_CNT) { + m_tsccCnt = 0U; + } + } + m_rfTimeoutTimer.clock(ms); if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) { if (!m_rfTimeout) { @@ -396,26 +418,35 @@ void Slot::clock() /// Flag indicating full-duplex operation. /// Instance of the RadioIdLookup class. /// Instance of the TalkgroupIdLookup class. -/// Instance of the CRSSIInterpolator class. +/// Instance of the IdenTableLookup class. +/// Instance of the RSSIInterpolator class. /// void Slot::init(uint32_t colorCode, SiteData siteData, bool embeddedLCOnly, bool dumpTAData, uint32_t callHang, modem::Modem* modem, network::BaseNetwork* network, bool duplex, lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup, - lookups::RSSIInterpolator* rssiMapper, uint32_t jitter) + lookups::IdenTableLookup* idenTable, lookups::RSSIInterpolator* rssiMapper, uint32_t jitter) { assert(modem != NULL); assert(ridLookup != NULL); assert(tidLookup != NULL); + assert(idenTable != NULL); assert(rssiMapper != NULL); m_colorCode = colorCode; + m_siteData = siteData; + m_embeddedLCOnly = embeddedLCOnly; m_dumpTAData = dumpTAData; + m_modem = modem; m_network = network; + m_duplex = duplex; + + m_idenTable = idenTable; m_ridLookup = ridLookup; m_tidLookup = tidLookup; + m_hangCount = callHang * 17U; m_rssiMapper = rssiMapper; @@ -435,6 +466,28 @@ void Slot::init(uint32_t colorCode, SiteData siteData, bool embeddedLCOnly, bool slotType.encode(m_idle + 2U); } +/// +/// Sets local configured site data. +/// +/// DMR Network ID. +/// DMR Site ID. +/// Channel ID. +/// Channel Number. +void Slot::setSiteData(uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo) +{ + m_siteData = SiteData(SITE_MODEL_SMALL, netId, siteId, 3U, false); + + std::vector entries = m_idenTable->list(); + uint8_t i = 0U; + for (auto it = entries.begin(); it != entries.end(); ++it) { + lookups::IdenTable entry = *it; + if (entry.channelId == channelId) { + m_idenEntry = entry; + break; + } + } +} + // --------------------------------------------------------------------------- // Private Class Members // --------------------------------------------------------------------------- @@ -655,14 +708,84 @@ void Slot::writeRF_Call_Alrt(uint32_t srcId, uint32_t dstId) } /// -/// Helper to write a TSCC broadcast packet on the RF interface. +/// Helper to write a TSCC Ann-Wd broadcast packet on the RF interface. +/// +/// +/// +void Slot::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd) +{ + if (m_verbose) { + LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_BROADCAST (Broadcast), BCAST_ANNC_ANN_WD_TSCC (Announce-WD TSCC Channel), channelNo = %u, annWd = %u", + m_slotNo, channelNo, annWd); + } + + m_rfSeqNo = 0U; + + SlotType slotType; + slotType.setColorCode(m_colorCode); + slotType.setDataType(DT_CSBK); + + lc::CSBK csbk = lc::CSBK(); + csbk.setVerbose(m_dumpCSBKData); + csbk.setCSBKO(CSBKO_BROADCAST); + csbk.setFID(FID_ETSI); + + csbk.setAnncType(BCAST_ANNC_ANN_WD_TSCC); + csbk.setSiteData(m_siteData); + csbk.setLogicalCh1(channelNo); + csbk.setAnnWdCh1(annWd); + + uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U]; + ::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES); + + // MBC frame 1 + csbk.setLastBlock(false); + + // Regenerate the CSBK data + csbk.encode(data + 2U); + + // Regenerate the Slot Type + slotType.encode(data + 2U); + + // Convert the Data Sync to be from the BS or MS as needed + Sync::addDMRDataSync(data + 2U, m_duplex); + + data[0U] = TAG_DATA; + data[1U] = 0x00U; + + if (m_duplex) + writeQueueRF(data); + + ::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES); + + // MBC frame 2 + csbk.setLastBlock(false); + csbk.setCdef(true); + csbk.setIdenTable(m_idenEntry); + + // Regenerate the CSBK data + csbk.encode(data + 2U); + + // Regenerate the Slot Type + slotType.encode(data + 2U); + + // Convert the Data Sync to be from the BS or MS as needed + Sync::addDMRDataSync(data + 2U, m_duplex); + + data[0U] = TAG_DATA; + data[1U] = 0x00U; + + if (m_duplex) + writeQueueRF(data); +} + +/// +/// Helper to write a TSCC Sys_Parm broadcast packet on the RF interface. /// -/// Broadcast announcement type. -void Slot::writeRF_TSCC_Broadcast(uint8_t anncType) +void Slot::writeRF_TSCC_Bcast_Sys_Parm() { if (m_verbose) { - LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_BROADCAST (Broadcast), anncType = %u", - m_slotNo, anncType); + LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_BROADCAST (Broadcast), BCAST_ANNC_SITE_PARMS (Announce Site Parms)", m_slotNo); } uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U]; @@ -677,7 +800,7 @@ void Slot::writeRF_TSCC_Broadcast(uint8_t anncType) csbk.setCSBKO(CSBKO_BROADCAST); csbk.setFID(FID_ETSI); - csbk.setAnncType(anncType); + csbk.setAnncType(BCAST_ANNC_SITE_PARMS); csbk.setSiteData(m_siteData); // Regenerate the CSBK data diff --git a/dmr/Slot.h b/dmr/Slot.h index 88364484..ea4b5c3f 100644 --- a/dmr/Slot.h +++ b/dmr/Slot.h @@ -39,6 +39,7 @@ #include "modem/Modem.h" #include "network/BaseNetwork.h" #include "lookups/RSSIInterpolator.h" +#include "lookups/IdenTableLookup.h" #include "lookups/RadioIdLookup.h" #include "lookups/TalkgroupIdLookup.h" #include "RingBuffer.h" @@ -83,7 +84,9 @@ namespace dmr /// Helper to initialize the slot processor. static void init(uint32_t colorCode, SiteData siteData, bool embeddedLCOnly, bool dumpTAData, uint32_t callHang, modem::Modem* modem, network::BaseNetwork* network, bool duplex, lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup, - lookups::RSSIInterpolator* rssiMapper, uint32_t jitter); + lookups::IdenTableLookup* idenTable, lookups::RSSIInterpolator* rssiMapper, uint32_t jitter); + /// Sets local configured site data. + static void setSiteData(uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo); private: friend class Control; @@ -147,9 +150,12 @@ namespace dmr static bool m_duplex; + static lookups::IdenTableLookup* m_idenTable; static lookups::RadioIdLookup* m_ridLookup; static lookups::TalkgroupIdLookup* m_tidLookup; + static lookups::IdenTable m_idenEntry; + static uint32_t m_hangCount; static lookups::RSSIInterpolator* m_rssiMapper; @@ -167,6 +173,8 @@ namespace dmr static uint8_t m_id2; static bool m_voice2; + static uint16_t m_tsccCnt; + /// Helper to change the debug and verbose state. void setDebugVerbose(bool debug, bool verbose); @@ -184,8 +192,10 @@ namespace dmr void writeRF_Ext_Func(uint32_t func, uint32_t arg, uint32_t dstId); /// Helper to write a call alert packet on the RF interface. void writeRF_Call_Alrt(uint32_t srcId, uint32_t dstId); - /// Helper to write a TSCC broadcast packet on the RF interface. - void writeRF_TSCC_Broadcast(uint8_t anncType); + /// Helper to write a TSCC Ann-Wd broadcast packet on the RF interface. + void writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd); + /// Helper to write a TSCC Sys_Parm broadcast packet on the RF interface. + void writeRF_TSCC_Bcast_Sys_Parm(); /// static void setShortLC(uint32_t slotNo, uint32_t id, uint8_t flco = FLCO_GROUP, bool voice = true); diff --git a/dmr/lc/CSBK.cpp b/dmr/lc/CSBK.cpp index e4f92379..e2e47f9d 100644 --- a/dmr/lc/CSBK.cpp +++ b/dmr/lc/CSBK.cpp @@ -54,6 +54,7 @@ CSBK::CSBK() : m_lastBlock(true), m_bsId(0U), m_GI(false), + m_Cdef(false), m_srcId(0U), m_dstId(0U), m_dataContent(false), @@ -209,7 +210,9 @@ void CSBK::encode(uint8_t* bytes) m_data[0U] = m_CSBKO; // CSBKO m_data[0U] |= (m_lastBlock) ? 0x80U : 0x00U; // Last Block Marker - m_data[1U] = m_FID; // Feature ID + if (!m_Cdef) { + m_data[1U] = m_FID; // Feature ID + } switch (m_CSBKO) { case CSBKO_ACK_RSP: @@ -318,14 +321,75 @@ void CSBK::encode(uint8_t* bytes) case CSBKO_BROADCAST: { ulong64_t csbkValue = 0U; - csbkValue = m_anncType; // Announcement Type + if (!m_Cdef) { + csbkValue = m_anncType; // Announcement Type + } switch (m_anncType) { + case BCAST_ANNC_ANN_WD_TSCC: + if (!m_Cdef) { + // Broadcast Parms 1 + csbkValue = (csbkValue << 4) + 0U; // Reserved + csbkValue = (csbkValue << 4) + (m_colorCode & 0x0FU); // Color Code 1 + csbkValue = (csbkValue << 4) + (m_colorCode & 0x0FU); // Color Code 2 + csbkValue = (csbkValue << 1) + ((m_annWdCh1) ? 1U : 0U); // Announce/Withdraw Channel 1 + csbkValue = (csbkValue << 1) + ((m_annWdCh2) ? 1U : 0U); // Announce/Withdraw Channel 2 + + csbkValue = (csbkValue << 1) + ((m_siteData.requireReg()) ? 1U : 0U); // Require Registration + csbkValue = (csbkValue << 4) + (m_backoffNo & 0x0FU); // Backoff Number + csbkValue = (csbkValue << 16) + m_siteData.systemIdentity(); // Site Identity + + // Broadcast Parms 2 + csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Channel 1 + csbkValue = (csbkValue << 12) + (m_logicalCh2 & 0xFFFU); // Logical Channel 2 + } + else { + uint32_t calcSpace = (uint32_t)(m_siteIdenEntry.chSpaceKhz() / 0.125); + float calcTxOffset = m_siteIdenEntry.txOffsetMhz() * 1000000; + const uint32_t multiple = 100000; + + // calculate Rx frequency + uint32_t rxFrequency = (uint32_t)((m_siteIdenEntry.baseFrequency() + ((calcSpace * 125) * m_logicalCh1)) + calcTxOffset); + + // generate frequency in mhz + uint32_t rxFreqMhz = rxFrequency + multiple / 2; + rxFreqMhz -= rxFreqMhz % multiple; + rxFreqMhz /= multiple * 10; + + // generate khz offset + uint32_t rxFreqKhz = rxFrequency - (rxFreqMhz * 1000000); + + // calculate Tx Frequency + uint32_t txFrequency = (uint32_t)((m_siteIdenEntry.baseFrequency() + ((calcSpace * 125) * m_logicalCh1))); + + // generate frequency in mhz + uint32_t txFreqMhz = txFrequency + multiple / 2; + txFreqMhz -= txFreqMhz % multiple; + txFreqMhz /= multiple * 10; + + // generate khz offset + uint32_t txFreqKhz = txFrequency - (txFreqMhz * 1000000); + + csbkValue = (csbkValue << 8) + 0U; // Reserved + csbkValue = (csbkValue << 4) + 0U; // Cdef Type (always 0 for ANN_WD_TSCC) + csbkValue = (csbkValue << 2) + 0U; // Reserved + csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Channel + csbkValue = (csbkValue << 10) + txFreqMhz; // Transmit Freq Mhz + csbkValue = (csbkValue << 13) + txFreqKhz; // Transmit Freq Offset Khz + csbkValue = (csbkValue << 10) + rxFreqMhz; // Receive Freq Mhz + csbkValue = (csbkValue << 13) + rxFreqKhz; // Receive Freq Khz + } + break; case BCAST_ANNC_SITE_PARMS: + // Broadcast Parms 1 csbkValue = (csbkValue << 14) + m_siteData.systemIdentity(true); // Site Identity (Broadcast Parms 1) + + csbkValue = (csbkValue << 1) + ((m_siteData.requireReg()) ? 1U : 0U); // Require Registration csbkValue = (csbkValue << 4) + (m_backoffNo & 0x0FU); // Backoff Number csbkValue = (csbkValue << 16) + m_siteData.systemIdentity(); // Site Identity + + // Broadcast Parms 2 csbkValue = (csbkValue << 1) + 0U; // Roaming TG Subscription/Attach csbkValue = (csbkValue << 1) + ((m_hibernating) ? 1U : 0U); // TSCC Hibernating csbkValue = (csbkValue << 22) + 0U; // Broadcast Parms 2 (Reserved) @@ -367,6 +431,8 @@ void CSBK::encode(uint8_t* bytes) /// void CSBK::reset() { + m_colorCode = 0U; + m_backoffNo = 1U; m_serviceType = 0U; m_serviceOptions = 0U; @@ -378,6 +444,11 @@ void CSBK::reset() m_anncType = BCAST_ANNC_SITE_PARMS; m_hibernating = false; + m_annWdCh1 = false; + m_logicalCh1 = DMR_CHNULL; + m_annWdCh2 = false; + m_logicalCh2 = DMR_CHNULL; + /* Aloha */ m_siteTSSync = false; m_siteOffsetTiming = false; @@ -391,6 +462,13 @@ void CSBK::setSiteData(SiteData siteData) m_siteData = siteData; } +/// +/// +void CSBK::setIdenTable(lookups::IdenTable entry) +{ + m_siteIdenEntry = entry; +} + /// Sets a flag indicating whether or not networking is active. /// void CSBK::setNetActive(bool netActive) diff --git a/dmr/lc/CSBK.h b/dmr/lc/CSBK.h index dc7d136a..e6a63ea4 100644 --- a/dmr/lc/CSBK.h +++ b/dmr/lc/CSBK.h @@ -34,6 +34,7 @@ #include "Defines.h" #include "dmr/DMRDefines.h" #include "dmr/SiteData.h" +#include "lookups/IdenTableLookup.h" namespace dmr { @@ -62,6 +63,8 @@ namespace dmr /** Local Site data */ /// Sets local configured site data. void setSiteData(SiteData siteData); + /// + void setIdenTable(lookups::IdenTable entry); /// Sets a flag indicating whether or not networking is active. void setNetActive(bool netActive); @@ -85,6 +88,10 @@ namespace dmr /// Flag indicating whether the CSBK is group or individual. __PROPERTY(bool, GI, GI); + // For Cdef blocks + /// Flag indicating whether the CSBK is a Cdef block. + __PROPERTY(bool, Cdef, Cdef); + /// Source ID. __PROPERTY(uint32_t, srcId, SrcId); /// Destination ID. @@ -96,6 +103,9 @@ namespace dmr /// Sets the number of blocks to follow. __PROPERTY(uint8_t, CBF, CBF); + /// DMR access color code. + __PROPERTY(uint8_t, colorCode, ColorCode); + // Tier III /// Backoff Number. __PROPERTY(uint8_t, backoffNo, BackoffNo); @@ -115,6 +125,15 @@ namespace dmr /// Broadcast Hibernation Flag. __PROPERTY(bool, hibernating, Hibernating); + /// Broadcast Announce/Withdraw Channel 1 Flag. + __PROPERTY(bool, annWdCh1, AnnWdCh1); + /// Broadcast Logical Channel ID 1. + __PROPERTY(uint16_t, logicalCh1, LogicalCh1); + /// Broadcast Announce/Withdraw Channel 2 Flag. + __PROPERTY(bool, annWdCh2, AnnWdCh2); + /// Broadcast Logical Channel ID 2. + __PROPERTY(uint16_t, logicalCh2, LogicalCh2); + /// Aloha Site Time Slot Synchronization. __PROPERTY(bool, siteTSSync, SiteTSSync); /// Aloha site users offset timing. @@ -127,6 +146,7 @@ namespace dmr /** Local Site data */ SiteData m_siteData; + lookups::IdenTable m_siteIdenEntry; bool m_siteNetActive; }; } // namespace lc diff --git a/host/Host.cpp b/host/Host.cpp index 2a1249bf..369d9d46 100644 --- a/host/Host.cpp +++ b/host/Host.cpp @@ -319,8 +319,10 @@ int Host::run() } dmr = new dmr::Control(m_dmrColorCode, callHang, dmrQueueSize, embeddedLCOnly, dumpTAData, m_timeout, m_rfTalkgroupHang, - m_modem, m_network, m_duplex, m_ridLookup, m_tidLookup, rssi, jitter, dmrDumpDataPacket, dmrRepeatDataPacket, + m_modem, m_network, m_duplex, m_ridLookup, m_tidLookup, m_idenTable, rssi, jitter, dmrDumpDataPacket, dmrRepeatDataPacket, dmrDumpCsbkData, dmrDebug, dmrVerbose); + dmr->setOptions(m_conf, m_dmrNetId, m_siteId, m_channelId, m_channelNo); + m_dmrTXTimer.setTimeout(txHang); if (dmrVerbose) { @@ -396,7 +398,7 @@ int Host::run() p25ControlBcstInterval, m_duplex, m_ridLookup, m_tidLookup, m_idenTable, rssi, p25DumpDataPacket, p25RepeatDataPacket, p25DumpTsbkData, p25Debug, p25Verbose); p25->setOptions(m_conf, m_cwCallsign, m_voiceChNo, m_p25PatchSuperGroup, m_p25NetId, m_p25SysId, m_p25RfssId, - m_p25SiteId, m_channelId, m_channelNo, true); + m_siteId, m_channelId, m_channelNo, true); if (p25Verbose) { LogInfo(" Verbose: yes"); @@ -1186,7 +1188,22 @@ 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_dmrColorCode = rfssConfig["colorCode"].as(2U); + 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_p25NAC = (uint32_t)::strtoul(rfssConfig["nac"].as("293").c_str(), NULL, 16); m_p25PatchSuperGroup = (uint32_t)::strtoul(rfssConfig["pSuperGroup"].as("FFFF").c_str(), NULL, 16); @@ -1211,13 +1228,6 @@ bool Host::readParams() if (m_p25RfssId > 0xFEU) { // clamp to $FE m_p25RfssId = 0xFEU; } - m_p25SiteId = (uint8_t)::strtoul(rfssConfig["siteId"].as("1").c_str(), NULL, 16); - if (m_p25SiteId == 0U) { // clamp to 1 - m_p25SiteId = 1U; - } - if (m_p25SiteId > 0xFEU) { // clamp to $FE - m_p25SiteId = 0xFEU; - } LogInfo("System Config Parameters"); LogInfo(" RX Frequency: %uHz", m_rxFrequency); @@ -1229,13 +1239,14 @@ bool Host::readParams() LogInfo(" Channel Id: %u", m_channelId); LogInfo(" Channel No.: $%04X", m_channelNo); LogInfo(" Voice Channel No(s).: %s", strVoiceChNo.c_str()); + LogInfo(" Site Id: $%02X", m_siteId); LogInfo(" DMR Color Code: %u", m_dmrColorCode); + LogInfo(" DMR Network Id: $%05X", m_dmrNetId); LogInfo(" P25 NAC: $%03X", m_p25NAC); LogInfo(" P25 Patch Super Group: $%04X", m_p25PatchSuperGroup); LogInfo(" P25 Network Id: $%05X", m_p25NetId); LogInfo(" P25 System Id: $%03X", m_p25SysId); LogInfo(" P25 RFSS Id: $%02X", m_p25RfssId); - LogInfo(" P25 Site Id: $%02X", m_p25SiteId); return true; } diff --git a/host/Host.h b/host/Host.h index cc0d2140..afec92ac 100644 --- a/host/Host.h +++ b/host/Host.h @@ -113,13 +113,14 @@ private: bool m_dmrBeacons; bool m_controlData; + uint8_t m_siteId; + uint32_t m_dmrNetId; uint32_t m_dmrColorCode; uint32_t m_p25NAC; uint32_t m_p25PatchSuperGroup; uint32_t m_p25NetId; uint32_t m_p25SysId; uint8_t m_p25RfssId; - uint8_t m_p25SiteId; friend class RemoteControl; RemoteControl* m_remoteControl; diff --git a/p25/Control.cpp b/p25/Control.cpp index 3d7fe8c9..0b9761dd 100644 --- a/p25/Control.cpp +++ b/p25/Control.cpp @@ -72,7 +72,7 @@ const uint32_t MAX_PREAMBLE_TDU_CNT = 64U; /// Instance of the RadioIdLookup class. /// Instance of the TalkgroupIdLookup class. /// Instance of the IdenTableLookup class. -/// Instance of the CRSSIInterpolator class. +/// Instance of the RSSIInterpolator class. /// /// /// @@ -169,7 +169,16 @@ void Control::reset() /// Helper to set P25 configuration options. /// /// Instance of the ConfigINI class. -/// Flag indicating this instance should operate in network only mode. +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const std::vector voiceChNo, uint32_t pSuperGroup, uint32_t netId, uint32_t sysId, uint8_t rfssId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, bool printOptions)