add experimental support for DMR TIII (note this will not accept registrations or grant requests);

pull/12/head
Bryan Biedenkapp 4 years ago
parent 3fa0cbc150
commit 8b5a7ae7ec

@ -30,6 +30,10 @@ protocols:
enable: false
interval: 60
duration: 3
control:
dedicated: false
enable: false
slot: 1
embeddedLCOnly: false
dumpTAData: true
dumpDataPacket: false

@ -73,6 +73,8 @@ Control::Control(uint32_t colorCode, uint32_t callHang, uint32_t queueSize, bool
m_idenTable(idenTable),
m_ridLookup(ridLookup),
m_tidLookup(tidLookup),
m_tsccSlotNo(0U),
m_ccRunning(false),
m_dumpCSBKData(dumpCSBKData),
m_verbose(verbose),
m_debug(debug)
@ -107,12 +109,60 @@ Control::~Control()
/// <param name="siteId"></param>
/// <param name="channelId"></param>
/// <param name="channelNo"></param>
void Control::setOptions(yaml::Node& conf, uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo)
/// <param name="printOptions"></param>
void Control::setOptions(yaml::Node& conf, uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, bool printOptions)
{
yaml::Node systemConf = conf["system"];
yaml::Node dmrProtocol = conf["protocols"]["dmr"];
Slot::setSiteData(netId, siteId, channelId, channelNo);
yaml::Node control = dmrProtocol["control"];
bool enableTSCC = control["enable"].as<bool>(false);
bool dedicatedTSCC = false;
if (enableTSCC) {
dedicatedTSCC = control["dedicated"].as<bool>(false);
}
else {
dedicatedTSCC = false;
}
m_tsccSlotNo = (uint8_t)control["slot"].as<uint32_t>(0U);
switch (m_tsccSlotNo) {
case 1U:
m_slot1->setTSCC(enableTSCC, dedicatedTSCC);
break;
case 2U:
m_slot2->setTSCC(enableTSCC, dedicatedTSCC);
break;
default:
LogError(LOG_NET, "DMR, invalid slot, TSCC disabled, slotNo = %u", m_tsccSlotNo);
break;
}
if (printOptions) {
LogInfo(" TSCC Slot: %u", m_tsccSlotNo);
}
}
/// <summary>
/// Sets a flag indicating whether the DMR control channel is running.
/// </summary>
/// <param name="ccRunning"></param>
void Control::setCCRunning(bool ccRunning)
{
m_ccRunning = ccRunning;
switch (m_tsccSlotNo) {
case 1U:
m_slot1->setCCRunning(ccRunning);
break;
case 2U:
m_slot2->setCCRunning(ccRunning);
break;
default:
LogError(LOG_NET, "DMR, invalid slot, TSCC disabled, slotNo = %u", m_tsccSlotNo);
break;
}
}
/// <summary>
@ -151,6 +201,7 @@ bool Control::processWakeup(const uint8_t* data)
if (m_verbose) {
LogMessage(LOG_RF, "DMR, CSBKO_BSDWNACT, srcId = %u", srcId);
}
return true;
}

@ -66,7 +66,11 @@ namespace dmr
~Control();
/// <summary>Helper to set DMR configuration options.</summary>
void setOptions(yaml::Node& conf, uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo);
void setOptions(yaml::Node& conf, uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, bool printOptions);
/// <summary>Gets a flag indicating whether the DMR control channel is running.</summary>
bool getCCRunning() { return m_ccRunning; }
/// <summary>Sets a flag indicating whether the DMR control channel is running.</summary>
void setCCRunning(bool ccRunning);
/// <summary>Helper to process wakeup frames from the RF interface.</summary>
bool processWakeup(const uint8_t* data);
@ -104,6 +108,9 @@ namespace dmr
lookups::RadioIdLookup* m_ridLookup;
lookups::TalkgroupIdLookup* m_tidLookup;
uint8_t m_tsccSlotNo;
bool m_ccRunning;
bool m_dumpCSBKData;
bool m_verbose;
bool m_debug;

@ -503,18 +503,16 @@ ControlPacket::~ControlPacket()
}
/// <summary>
/// Helper to write a TSCC Ann-Wd broadcast packet on the RF interface.
/// Helper to write a TSCC Aloha broadcast packet on the RF interface.
/// </summary>
/// <param name="channelNo"></param>
/// <param name="annWd"></param>
void ControlPacket::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd)
void ControlPacket::writeRF_TSCC_Aloha()
{
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_slot->m_slotNo, channelNo, annWd);
if (m_debug) {
LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_ALOHA (Aloha)", m_slot->m_slotNo);
}
m_slot->m_rfSeqNo = 0U;
uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U];
::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES);
SlotType slotType;
slotType.setColorCode(m_slot->m_colorCode);
@ -522,19 +520,9 @@ void ControlPacket::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd)
lc::CSBK csbk = lc::CSBK(m_slot->m_siteData, m_slot->m_idenEntry, m_slot->m_dumpCSBKData);
csbk.setVerbose(m_dumpCSBKData);
csbk.setCSBKO(CSBKO_BROADCAST);
csbk.setCSBKO(CSBKO_ALOHA);
csbk.setFID(FID_ETSI);
csbk.setAnncType(BCAST_ANNC_ANN_WD_TSCC);
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);
@ -544,17 +532,45 @@ void ControlPacket::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd)
// Convert the Data Sync to be from the BS or MS as needed
Sync::addDMRDataSync(data + 2U, m_slot->m_duplex);
m_slot->m_rfSeqNo = 0U;
data[0U] = TAG_DATA;
data[1U] = 0x00U;
if (m_slot->m_duplex)
m_slot->writeQueueRF(data);
}
::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES);
/// <summary>
/// Helper to write a TSCC Ann-Wd broadcast packet on the RF interface.
/// </summary>
/// <param name="channelNo"></param>
/// <param name="annWd"></param>
void ControlPacket::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd)
{
if (m_debug) {
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_slot->m_slotNo, channelNo, annWd);
}
// MBC frame 2
csbk.setLastBlock(false);
csbk.setCdef(true);
m_slot->m_rfSeqNo = 0U;
SlotType slotType;
slotType.setColorCode(m_slot->m_colorCode);
slotType.setDataType(DT_CSBK);
lc::CSBK csbk = lc::CSBK(m_slot->m_siteData, m_slot->m_idenEntry, m_slot->m_dumpCSBKData);
csbk.setCdef(false);
csbk.setVerbose(m_dumpCSBKData);
csbk.setCSBKO(CSBKO_BROADCAST);
csbk.setFID(FID_ETSI);
csbk.setAnncType(BCAST_ANNC_ANN_WD_TSCC);
csbk.setLogicalCh1(channelNo);
csbk.setAnnWdCh1(annWd);
uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U];
::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES);
// Regenerate the CSBK data
csbk.encode(data + 2U);
@ -577,7 +593,7 @@ void ControlPacket::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd)
/// </summary>
void ControlPacket::writeRF_TSCC_Bcast_Sys_Parm()
{
if (m_verbose) {
if (m_debug) {
LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_BROADCAST (Broadcast), BCAST_ANNC_SITE_PARMS (Announce Site Parms)", m_slot->m_slotNo);
}

@ -83,6 +83,8 @@ namespace dmr
/// <summary>Finalizes a instance of the DataPacket class.</summary>
~ControlPacket();
/// <summary>Helper to write a TSCC Aloha broadcast packet on the RF interface.</summary>
void writeRF_TSCC_Aloha();
/// <summary>Helper to write a TSCC Ann-Wd broadcast packet on the RF interface.</summary>
void writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd);
/// <summary>Helper to write a TSCC Sys_Parm broadcast packet on the RF interface.</summary>

@ -128,6 +128,8 @@ namespace dmr
const uint8_t DMR_ALOHA_VER_151 = 0x00U;
const uint8_t DMR_CHNULL = 0x00U;
const uint16_t DMR_LOGICAL_CH_ABSOLUTE = 0xFFFU;
// PDU Data Formats
const uint8_t DPF_UDT = 0x00U;
const uint8_t DPF_RESPONSE = 0x01U;
@ -235,6 +237,9 @@ 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 PDUs
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
const uint8_t CSBKO_BTV_GRANT = 0x32U; // BTV_GRANT - Broadcast Talkgroup Voice Channel Grant
const uint8_t CSBKO_BSDWNACT = 0x38U; // BS DWN ACT - BS Outbound Activation
const uint8_t CSBKO_PRECCSBK = 0x3DU; // PRE CSBK - Preamble CSBK

@ -56,6 +56,7 @@ const uint16_t TSCC_MAX_CNT = 511U;
uint32_t Slot::m_colorCode = 0U;
SiteData Slot::m_siteData = SiteData();
uint32_t Slot::m_channelNo = 0U;
bool Slot::m_embeddedLCOnly = false;
bool Slot::m_dumpTAData = true;
@ -141,6 +142,9 @@ Slot::Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSiz
m_minRSSI(0U),
m_aveRSSI(0U),
m_rssiCount(0U),
m_ccSeq(0U),
m_ccRunning(false),
m_enableTSCC(false),
m_dumpCSBKData(dumpCSBKData),
m_verbose(verbose),
m_debug(debug)
@ -162,6 +166,15 @@ Slot::~Slot()
delete m_control;
}
/// <summary>
/// Sets a flag indicating whether the DMR control channel is running.
/// </summary>
/// <param name="ccRunning"></param>
void Slot::setCCRunning(bool ccRunning)
{
m_ccRunning = ccRunning;
}
/// <summary>
/// Process DMR data frame from the RF interface.
/// </summary>
@ -260,6 +273,24 @@ bool Slot::processFrame(uint8_t *data, uint32_t len)
if ((dataSync || voiceSync) && m_rfState != RS_RF_LISTENING)
m_rfTGHang.start();
// write and process TSCC CSBKs and short LC
if (m_enableTSCC && m_dedicatedTSCC)
{
if (dataSync) {
uint8_t dataType = data[1U] & 0x0FU;
switch (dataType)
{
case DT_CSBK:
return m_control->process(data, len);
default:
break;
}
}
return false;
}
if (dataSync) {
uint8_t dataType = data[1U] & 0x0FU;
@ -369,12 +400,30 @@ void Slot::clock()
}
}
if (m_enableTSCC)
{
// increment the TSCC counter on every slot 1 clock
if (m_slotNo == 1U) {
m_tsccCnt++;
if (m_tsccCnt == TSCC_MAX_CNT) {
m_tsccCnt = 0U;
}
if (m_ccSeq == 3U) {
m_ccSeq = 0U;
}
if (m_dedicatedTSCC) {
setShortLC_TSCC(m_siteData, m_tsccCnt);
writeRF_ControlData(m_tsccCnt, m_ccSeq);
}
else {
if (m_ccRunning) {
setShortLC_TSCC(m_siteData, m_tsccCnt);
writeRF_ControlData(m_tsccCnt, m_ccSeq);
}
}
m_ccSeq++;
}
m_rfTimeoutTimer.clock(ms);
@ -450,6 +499,17 @@ void Slot::setDebugVerbose(bool debug, bool verbose)
m_verbose = m_voice->m_verbose = m_data->m_verbose = verbose = m_control->m_verbose;
}
/// <summary>
/// Helper to enable and configure TSCC support for this slot.
/// </summary>
/// <param name="enable">Flag indicating whether DMR TSCC is enabled on this slot.</param>
/// <param name="enable">Flag indicating whether DMR TSCC is dedicated on this slot.</param>
void Slot::setTSCC(bool enable, bool dedicated)
{
m_enableTSCC = enable;
m_dedicatedTSCC = dedicated;
}
/// <summary>
/// Helper to initialize the DMR slot processor.
/// </summary>
@ -521,6 +581,7 @@ void Slot::init(uint32_t colorCode, SiteData siteData, bool embeddedLCOnly, bool
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);
m_channelNo = channelNo;
std::vector<lookups::IdenTable> entries = m_idenTable->list();
for (auto it = entries.begin(); it != entries.end(); ++it) {
@ -650,6 +711,9 @@ void Slot::writeEndRF(bool writeEnd)
m_rfState = RS_RF_LISTENING;
if (m_netState == RS_NET_IDLE) {
if (m_enableTSCC)
setShortLC_TSCC(m_siteData, m_tsccCnt);
else
setShortLC(m_slotNo, 0U);
}
@ -765,6 +829,49 @@ void Slot::writeEndNet(bool writeEnd)
m_netDataHeader = NULL;
}
/// <summary>
/// Helper to write control channel packet data.
/// </summary>
/// <param name="frameCnt"></param>
/// <param name="n"></param>
void Slot::writeRF_ControlData(uint16_t frameCnt, uint8_t n)
{
uint8_t i = 0U, seqCnt = 0U;
if (!m_enableTSCC)
return;
// loop to generate 2 control sequences
if (frameCnt == 511U) {
seqCnt = 3U;
}
do
{
if (m_debug) {
LogDebug(LOG_DMR, "writeRF_ControlData, frameCnt = %u, seq = %u", frameCnt, n);
}
switch (n)
{
case 2:
m_control->writeRF_TSCC_Bcast_Ann_Wd(m_channelNo, true);
break;
case 1:
m_control->writeRF_TSCC_Aloha();
break;
case 0:
default:
m_control->writeRF_TSCC_Bcast_Sys_Parm();
break;
}
if (seqCnt > 0U)
n++;
i++;
} while (i <= seqCnt);
}
/// <summary>
///
/// </summary>

@ -71,6 +71,9 @@ namespace dmr
/// <summary>Finalizes a instance of the Slot class.</summary>
~Slot();
/// <summary>Sets a flag indicating whether the DMR control channel is running.</summary>
void setCCRunning(bool ccRunning);
/// <summary>Process a data frame from the RF interface.</summary>
bool processFrame(uint8_t* data, uint32_t len);
/// <summary>Get frame data from data ring buffer.</summary>
@ -88,6 +91,9 @@ namespace dmr
/// <summary>Helper to change the debug and verbose state.</summary>
void setDebugVerbose(bool debug, bool verbose);
/// <summary>Helper to enable and configure TSCC support for this slot.</summary>
void setTSCC(bool enable, bool dedicated);
/// <summary>Helper to initialize the slot processor.</summary>
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,
@ -150,6 +156,12 @@ namespace dmr
uint32_t m_aveRSSI;
uint32_t m_rssiCount;
uint8_t m_ccSeq;
bool m_ccRunning;
bool m_enableTSCC;
bool m_dedicatedTSCC;
bool m_dumpCSBKData;
bool m_verbose;
bool m_debug;
@ -157,6 +169,7 @@ namespace dmr
static uint32_t m_colorCode;
static SiteData m_siteData;
static uint32_t m_channelNo;
static bool m_embeddedLCOnly;
static bool m_dumpTAData;
@ -206,6 +219,9 @@ namespace dmr
/// <summary>Helper to write network end of frame data.</summary>
void writeEndNet(bool writeEnd = false);
/// <summary>Helper to write control channel packet data.</summary>
void writeRF_ControlData(uint16_t frameCnt, uint8_t n);
/// <summary>Helper to set the DMR short LC.</summary>
static void setShortLC(uint32_t slotNo, uint32_t id, uint8_t flco = FLCO_GROUP, bool voice = true);
/// <summary>Helper to set the DMR short LC for TSCC.</summary>

@ -211,6 +211,9 @@ void CSBK::encode(uint8_t* bytes)
if (!m_Cdef) {
m_data[1U] = m_FID; // Feature ID
}
else {
m_data[1U] = m_colorCode & 0x0FU; // Cdef uses Color Code
}
switch (m_CSBKO) {
case CSBKO_ACK_RSP:
@ -267,26 +270,6 @@ void CSBK::encode(uint8_t* bytes)
m_data[9U] = (m_dstId >> 0) & 0xFFU;
break;
default:
if (m_GI) {
m_data[2U] |= 0x40U; // Group or Individual
}
if (m_dataContent) {
m_data[2U] |= 0x80U; //
}
m_data[3U] = m_CBF; //
m_data[4U] = (m_dstId >> 16) & 0xFFU; // Destination ID
m_data[5U] = (m_dstId >> 8) & 0xFFU;
m_data[6U] = (m_dstId >> 0) & 0xFFU;
m_data[7U] = (m_srcId >> 16) & 0xFFU; // Source ID
m_data[8U] = (m_srcId >> 8) & 0xFFU;
m_data[9U] = (m_srcId >> 0) & 0xFFU;
break;
/* Tier III */
case CSBKO_ALOHA:
{
@ -313,9 +296,56 @@ void CSBK::encode(uint8_t* bytes)
m_data[7U] = (uint8_t)((csbkValue >> 16) & 0xFFU);
m_data[8U] = (uint8_t)((csbkValue >> 8) & 0xFFU);
m_data[9U] = (uint8_t)((csbkValue >> 0) & 0xFFU);
}
break;
case CSBKO_PV_GRANT:
{
ulong64_t csbkValue = 0U;
csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Physical Channel 1
csbkValue = (csbkValue << 1) + (m_slotNo & 0x3U); // Logical Slot Number
csbkValue = (csbkValue << 1) + 0U; // Reserved
csbkValue = (csbkValue << 1) + 0U; // Emergency
csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset
csbkValue = (csbkValue << 24) + m_dstId; // Talkgroup ID
csbkValue = (csbkValue << 24) + m_srcId; // Source ID
// split value into bytes
m_data[2U] = (uint8_t)((csbkValue >> 56) & 0xFFU);
m_data[3U] = (uint8_t)((csbkValue >> 48) & 0xFFU);
m_data[4U] = (uint8_t)((csbkValue >> 40) & 0xFFU);
m_data[5U] = (uint8_t)((csbkValue >> 32) & 0xFFU);
m_data[6U] = (uint8_t)((csbkValue >> 24) & 0xFFU);
m_data[7U] = (uint8_t)((csbkValue >> 16) & 0xFFU);
m_data[8U] = (uint8_t)((csbkValue >> 8) & 0xFFU);
m_data[9U] = (uint8_t)((csbkValue >> 0) & 0xFFU);
}
break;
case CSBKO_TV_GRANT:
case CSBKO_BTV_GRANT:
{
ulong64_t csbkValue = 0U;
csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Physical Channel 1
csbkValue = (csbkValue << 1) + (m_slotNo & 0x3U); // Logical Slot Number
csbkValue = (csbkValue << 1) + 0U; // Late Entry
csbkValue = (csbkValue << 1) + 0U; // Emergency
csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset
csbkValue = (csbkValue << 24) + m_dstId; // Talkgroup ID
csbkValue = (csbkValue << 24) + m_srcId; // Source ID
// split value into bytes
m_data[2U] = (uint8_t)((csbkValue >> 56) & 0xFFU);
m_data[3U] = (uint8_t)((csbkValue >> 48) & 0xFFU);
m_data[4U] = (uint8_t)((csbkValue >> 40) & 0xFFU);
m_data[5U] = (uint8_t)((csbkValue >> 32) & 0xFFU);
m_data[6U] = (uint8_t)((csbkValue >> 24) & 0xFFU);
m_data[7U] = (uint8_t)((csbkValue >> 16) & 0xFFU);
m_data[8U] = (uint8_t)((csbkValue >> 8) & 0xFFU);
m_data[9U] = (uint8_t)((csbkValue >> 0) & 0xFFU);
}
break;
case CSBKO_BROADCAST:
{
ulong64_t csbkValue = 0U;
@ -326,7 +356,7 @@ void CSBK::encode(uint8_t* bytes)
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
@ -342,7 +372,9 @@ void CSBK::encode(uint8_t* bytes)
csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Channel 1
csbkValue = (csbkValue << 12) + (m_logicalCh2 & 0xFFFU); // Logical Channel 2
}
else {
break;
case BCAST_ANNC_CHAN_FREQ:
{
uint32_t calcSpace = (uint32_t)(m_siteIdenEntry.chSpaceKhz() / 0.125);
float calcTxOffset = m_siteIdenEntry.txOffsetMhz() * 1000000;
const uint32_t multiple = 100000;
@ -369,17 +401,17 @@ void CSBK::encode(uint8_t* bytes)
// 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 = 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
csbkValue = (csbkValue << 10) + (txFreqMhz & 0x7FFU); // Transmit Freq Mhz
csbkValue = (csbkValue << 13) + (txFreqKhz & 0x3FFFU); // Transmit Freq Offset Khz
csbkValue = (csbkValue << 10) + (rxFreqMhz & 0x7FFU); // Receive Freq Mhz
csbkValue = (csbkValue << 13) + (rxFreqKhz & 0x3FFFU); // Receive Freq Khz
}
break;
case BCAST_ANNC_SITE_PARMS:
{
// Broadcast Parms 1
csbkValue = (csbkValue << 14) + m_siteData.systemIdentity(true); // Site Identity (Broadcast Parms 1)
@ -391,6 +423,7 @@ void CSBK::encode(uint8_t* bytes)
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)
}
break;
}
@ -405,6 +438,26 @@ void CSBK::encode(uint8_t* bytes)
m_data[9U] = (uint8_t)((csbkValue >> 0) & 0xFFU);
}
break;
default:
if (m_GI) {
m_data[2U] |= 0x40U; // Group or Individual
}
if (m_dataContent) {
m_data[2U] |= 0x80U; //
}
m_data[3U] = m_CBF; //
m_data[4U] = (m_dstId >> 16) & 0xFFU; // Destination ID
m_data[5U] = (m_dstId >> 8) & 0xFFU;
m_data[6U] = (m_dstId >> 0) & 0xFFU;
m_data[7U] = (m_srcId >> 16) & 0xFFU; // Source ID
m_data[8U] = (m_srcId >> 8) & 0xFFU;
m_data[9U] = (m_srcId >> 0) & 0xFFU;
break;
}
m_data[10U] ^= CSBK_CRC_MASK[0U];
@ -455,6 +508,7 @@ CSBK::CSBK(SiteData siteData) :
m_logicalCh1(DMR_CHNULL),
m_annWdCh2(false),
m_logicalCh2(DMR_CHNULL),
m_slotNo(0U),
m_siteTSSync(false),
m_siteOffsetTiming(false),
m_alohaMask(0U),

@ -125,6 +125,9 @@ namespace dmr
/// <summary>Broadcast Logical Channel ID 2.</summary>
__PROPERTY(uint16_t, logicalCh2, LogicalCh2);
/// <summary>Logical Channel Slot Number.</summary>
__PROPERTY(uint8_t, slotNo, SlotNo);
/// <summary>Aloha Site Time Slot Synchronization.</summary>
__PROPERTY(bool, siteTSSync, SiteTSSync);
/// <summary>Aloha site users offset timing.</summary>

@ -91,6 +91,7 @@ Host::Host(const std::string& confFile) :
m_dmrEnabled(false),
m_p25Enabled(false),
m_p25CtrlChannel(false),
m_dmrCtrlChannel(false),
m_duplex(false),
m_fixedMode(false),
m_timeout(180U),
@ -108,9 +109,13 @@ Host::Host(const std::string& confFile) :
m_rxFrequency(0U),
m_txFrequency(0U),
m_channelId(0U),
m_channelNo(0U),
m_idenTable(NULL),
m_ridLookup(NULL),
m_tidLookup(NULL),
m_dmrBeacons(false),
m_dmrTSCCData(false),
m_controlData(false),
m_remoteControl(NULL)
{
UDPSocket::startup();
@ -338,6 +343,8 @@ int Host::run()
if (m_dmrEnabled) {
yaml::Node dmrProtocol = protocolConf["dmr"];
m_dmrBeacons = dmrProtocol["beacons"]["enable"].as<bool>(false);
m_dmrTSCCData = dmrProtocol["control"]["enable"].as<bool>(false);
bool dmrCtrlChannel = dmrProtocol["control"]["dedicated"].as<bool>(false);
bool embeddedLCOnly = dmrProtocol["embeddedLCOnly"].as<bool>(false);
bool dmrDumpDataPacket = dmrProtocol["dumpDataPacket"].as<bool>(false);
bool dmrRepeatDataPacket = dmrProtocol["repeatDataPacket"].as<bool>(true);
@ -384,10 +391,19 @@ int Host::run()
g_fireDMRBeacon = true;
}
LogInfo(" TSCC Control: %s", m_dmrTSCCData ? "yes" : "no");
if (m_dmrTSCCData) {
LogInfo(" TSCC Control Channel: %s", dmrCtrlChannel ? "yes" : "no");
if (dmrCtrlChannel) {
m_dmrCtrlChannel = dmrCtrlChannel;
}
}
dmr = new dmr::Control(m_dmrColorCode, callHang, dmrQueueSize, embeddedLCOnly, dumpTAData, m_timeout, m_rfTalkgroupHang,
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);
dmr->setOptions(m_conf, m_dmrNetId, m_siteId, m_channelId, m_channelNo, true);
m_dmrTXTimer.setTimeout(txHang);
@ -479,16 +495,42 @@ int Host::run()
g_killed = true;
}
if (m_fixedMode && m_dmrEnabled && m_p25Enabled) {
::LogError(LOG_HOST, "Cannot have DMR enabled and P25 enabled when using fixed state! Choose one protocol for fixed state operation.");
g_killed = true;
}
// P25 control channel checks
if (m_dmrEnabled && m_p25CtrlChannel) {
::LogError(LOG_HOST, "Cannot have DMR enabled when using dedicated P25 control!");
g_killed = true;
}
if (m_fixedMode && m_dmrEnabled && m_p25Enabled) {
::LogError(LOG_HOST, "Cannot have DMR enabled and P25 enabled when using fixed state! Choose one protocol for fixed state operation.");
if (!m_fixedMode && m_p25CtrlChannel) {
::LogWarning(LOG_HOST, "Fixed mode should be enabled when using dedicated P25 control!");
}
if (!m_duplex && m_controlData) {
::LogError(LOG_HOST, "Cannot have P25 control and simplex mode at the same time.");
g_killed = true;
}
// DMR TSCC checks
if (m_p25Enabled && m_dmrCtrlChannel) {
::LogError(LOG_HOST, "Cannot have P25 enabled when using dedicated DMR TSCC control!");
g_killed = true;
}
if (!m_fixedMode && m_dmrCtrlChannel) {
::LogWarning(LOG_HOST, "Fixed mode should be enabled when using dedicated DMR TSCC control!");
}
if (!m_duplex && m_dmrTSCCData) {
::LogError(LOG_HOST, "Cannot have DMR TSCC control and simplex mode at the same time.");
g_killed = true;
}
// DMR beacon checks
if (m_dmrBeacons && m_controlData) {
::LogError(LOG_HOST, "Cannot have DMR roaming becaons and P25 control at the same time.");
g_killed = true;
@ -499,11 +541,6 @@ int Host::run()
g_killed = true;
}
if (!m_duplex && m_controlData) {
::LogError(LOG_HOST, "Cannot have P25 control and simplex mode at the same time.");
g_killed = true;
}
if (!g_killed) {
// fixed more or P25 control channel will force a state change
if (m_fixedMode || m_p25CtrlChannel) {
@ -561,6 +598,16 @@ int Host::run()
} \
}
// Macro to interrupt a running DMR roaming beacon
#define INTERRUPT_DMR_BEACON \
if (dmr != NULL) { \
if (dmrBeaconDurationTimer.isRunning() && !dmrBeaconDurationTimer.hasExpired()) { \
if (m_dmrTSCCData && !m_dmrCtrlChannel) \
dmr->setCCRunning(false); \
} \
dmrBeaconDurationTimer.stop(); \
}
// Macro to start DMR duplex idle transmission (or beacon)
#define START_DMR_DUPLEX_IDLE(x) \
if (dmr != NULL) { \
@ -630,10 +677,14 @@ int Host::run()
m_modem->writeDMRData1(data, len);
dmrBeaconDurationTimer.stop();
if (!dmr->getCCRunning()) {
INTERRUPT_DMR_BEACON;
}
if (g_interruptP25Control && p25CCDurationTimer.isRunning()) {
p25CCDurationTimer.pause();
}
m_modeTimer.start();
}
/*
@ -661,10 +712,14 @@ int Host::run()
m_modem->writeDMRData2(data, len);
dmrBeaconDurationTimer.stop();
if (!dmr->getCCRunning()) {
INTERRUPT_DMR_BEACON;
}
if (g_interruptP25Control && p25CCDurationTimer.isRunning()) {
p25CCDurationTimer.pause();
}
m_modeTimer.start();
}
/*
@ -693,7 +748,8 @@ int Host::run()
if (m_state == STATE_P25) {
m_modem->writeP25Data(data, len);
dmrBeaconDurationTimer.stop();
INTERRUPT_DMR_BEACON;
if (g_interruptP25Control && p25CCDurationTimer.isRunning()) {
p25CCDurationTimer.pause();
}
@ -775,7 +831,7 @@ int Host::run()
setState(STATE_DMR);
START_DMR_DUPLEX_IDLE(true);
dmrBeaconDurationTimer.stop();
INTERRUPT_DMR_BEACON;
INTERRUPT_P25_CONTROL;
}
}
@ -787,7 +843,7 @@ int Host::run()
dmr->processFrame1(data, len);
dmrBeaconDurationTimer.stop();
INTERRUPT_DMR_BEACON;
p25CCDurationTimer.stop();
}
}
@ -805,7 +861,7 @@ int Host::run()
// process slot 1 frames
bool ret = dmr->processFrame1(data, len);
if (ret) {
dmrBeaconDurationTimer.stop();
INTERRUPT_DMR_BEACON;
INTERRUPT_P25_CONTROL;
m_modeTimer.start();
@ -832,7 +888,7 @@ int Host::run()
setState(STATE_DMR);
START_DMR_DUPLEX_IDLE(true);
dmrBeaconDurationTimer.stop();
INTERRUPT_DMR_BEACON;
INTERRUPT_P25_CONTROL;
}
}
@ -844,7 +900,7 @@ int Host::run()
dmr->processFrame2(data, len);
dmrBeaconDurationTimer.stop();
INTERRUPT_DMR_BEACON;
INTERRUPT_P25_CONTROL;
}
}
@ -862,7 +918,7 @@ int Host::run()
// process slot 2 frames
bool ret = dmr->processFrame2(data, len);
if (ret) {
dmrBeaconDurationTimer.stop();
INTERRUPT_DMR_BEACON;
INTERRUPT_P25_CONTROL;
m_modeTimer.start();
@ -889,13 +945,13 @@ int Host::run()
m_modeTimer.setTimeout(m_rfModeHang);
setState(STATE_P25);
dmrBeaconDurationTimer.stop();
INTERRUPT_DMR_BEACON;
INTERRUPT_P25_CONTROL;
}
else {
ret = p25->writeEndRF();
if (ret) {
dmrBeaconDurationTimer.stop();
INTERRUPT_DMR_BEACON;
if (m_state == STATE_IDLE) {
m_modeTimer.setTimeout(m_rfModeHang);
@ -1027,6 +1083,15 @@ int Host::run()
/** DMR */
if (dmr != NULL) {
if (m_dmrTSCCData && m_dmrCtrlChannel) {
if (m_state != STATE_DMR)
setState(STATE_DMR);
if (!m_modem->hasTX()) {
START_DMR_DUPLEX_IDLE(true);
}
}
// clock and check DMR roaming beacon interval timer
dmrBeaconIntervalTimer.clock(ms);
if ((dmrBeaconIntervalTimer.isRunning() && dmrBeaconIntervalTimer.hasExpired()) || g_fireDMRBeacon) {
@ -1035,12 +1100,17 @@ int Host::run()
m_modeTimer.stop();
}
if (m_fixedMode)
START_DMR_DUPLEX_IDLE(true);
if (m_state != STATE_DMR)
setState(STATE_DMR);
if (m_fixedMode) {
START_DMR_DUPLEX_IDLE(true);
}
if (m_dmrTSCCData) {
dmr->setCCRunning(true);
}
g_fireDMRBeacon = false;
LogDebug(LOG_HOST, "DMR, roaming beacon burst");
dmrBeaconIntervalTimer.start();
@ -1059,6 +1129,10 @@ int Host::run()
m_modeTimer.start();
}
}
if (m_dmrTSCCData) {
dmr->setCCRunning(false);
}
}
// clock and check DMR Tx timer

@ -84,6 +84,7 @@ private:
bool m_p25CtrlChannel;
bool m_p25CtrlBroadcast;
bool m_dmrCtrlChannel;
bool m_duplex;
bool m_fixedMode;
@ -114,6 +115,7 @@ private:
lookups::TalkgroupIdLookup* m_tidLookup;
bool m_dmrBeacons;
bool m_dmrTSCCData;
bool m_controlData;
uint8_t m_siteId;

@ -94,7 +94,7 @@ Control::Control(uint32_t nac, uint32_t callHang, uint32_t queueSize, modem::Mod
m_legacyGroupReg(false),
m_duplex(duplex),
m_control(false),
m_continuousControl(false),
m_dedicatedControl(false),
m_voiceOnControl(false),
m_ackTSBKRequests(true),
m_disableNetworkHDU(false),
@ -204,10 +204,10 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s
yaml::Node control = p25Protocol["control"];
m_control = control["enable"].as<bool>(false);
if (m_control) {
m_continuousControl = control["continuous"].as<bool>(false);
m_dedicatedControl = control["dedicated"].as<bool>(false);
}
else {
m_continuousControl = false;
m_dedicatedControl = false;
}
m_voiceOnControl = p25Protocol["voiceOnControl"].as<bool>(false);
@ -609,7 +609,7 @@ void Control::clock(uint32_t ms)
m_trunk->releaseDstIdGrant(m_voice->m_netLC.getDstId(), false);
}
if (m_continuousControl) {
if (m_dedicatedControl) {
if (m_network != NULL)
m_network->resetP25();
}

@ -130,7 +130,7 @@ namespace p25
bool m_duplex;
bool m_control;
bool m_continuousControl;
bool m_dedicatedControl;
bool m_voiceOnControl;
bool m_ackTSBKRequests;
bool m_disableNetworkHDU;

@ -1408,7 +1408,7 @@ void TrunkPacket::writeRF_TSDU_SBF(bool noNetwork, bool clearBeforeWrite)
if (!noNetwork)
writeNetworkRF(data + 2U, true);
if (m_p25->m_continuousControl) {
if (m_p25->m_dedicatedControl) {
writeRF_TSDU_MBF(clearBeforeWrite);
return;
}

@ -651,7 +651,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
LogMessage(LOG_RF, P25_TDU_STR ", total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%",
m_rfFrames, m_rfBits, m_rfUndecodableLC, m_rfErrs, float(m_rfErrs * 100U) / float(m_rfBits));
if (m_p25->m_continuousControl) {
if (m_p25->m_dedicatedControl) {
m_p25->m_tailOnIdle = false;
writeRF_EndOfVoice();
}

Loading…
Cancel
Save

Powered by TurnKey Linux.