From 66e6787f33fb6a6e787e8ad7278b081b9961aa9f Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Mon, 9 May 2022 21:18:09 -0400 Subject: [PATCH] clarify buffer overflow message; refactor DMR and P25 code for clarity regarding how the queue buffer for the digital protocols works; refactor P25 control channel processing code into the p25::Control class clock function proper; refactor the naming of the network write functions (the naming was confusing); refactor how queue sizes are calculated, instead of using raw bytes an input, use the number of desired frames as input from config.yml; adjust the internal intermediate modem buffer sizes; implement a short delay between P25 CC packets of ~5ms, this is to give the processor time to handle packets inbetween generating CC data frames; refactor PDU handling, we no longer instantly transmit the registration response, instead following spec transmit it ~1 second after the request; implement and use the modem write immediate support for P25 PDUs and some P25 TSDUs; in the case of P25 voice call late entry, ensure we perform the appropriate queue clear and state resets; refactor and consolidate how the end of frame data is written after a voice call on P25; --- Defines.h | 2 - HostMain.cpp | 1 - HostMain.h | 1 - RingBuffer.h | 2 +- config.example.yml | 4 +- dmr/Control.cpp | 53 +++---- dmr/Control.h | 12 +- dmr/ControlPacket.cpp | 20 +-- dmr/DataPacket.cpp | 27 ++-- dmr/Slot.cpp | 68 ++++---- dmr/Slot.h | 18 +-- dmr/VoicePacket.cpp | 53 ++++--- host/Host.cpp | 296 +++++++++++++++++++--------------- host/Host.h | 9 +- modem/Modem.cpp | 12 +- network/RemoteControl.cpp | 14 +- p25/Control.cpp | 300 ++++++++++++++++++++--------------- p25/Control.h | 39 +++-- p25/DataPacket.cpp | 100 +++++++++--- p25/DataPacket.h | 12 +- p25/TrunkPacket.cpp | 17 +- p25/VoicePacket.cpp | 88 ++++------ p25/VoicePacket.h | 5 +- p25/dfsi/DFSITrunkPacket.cpp | 10 +- p25/dfsi/DFSIVoicePacket.cpp | 31 ++-- 25 files changed, 656 insertions(+), 538 deletions(-) diff --git a/Defines.h b/Defines.h index 938d50ae..3a166803 100644 --- a/Defines.h +++ b/Defines.h @@ -128,8 +128,6 @@ const uint32_t REMOTE_MODEM_PORT = 3334; const uint32_t TRAFFIC_DEFAULT_PORT = 62031; const uint32_t RCON_DEFAULT_PORT = 9990; -const uint32_t QUEUE_RESIZE_SIZE = 500; - const uint8_t BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; enum HOST_STATE { diff --git a/HostMain.cpp b/HostMain.cpp index ad23dfaf..cf0c8d65 100644 --- a/HostMain.cpp +++ b/HostMain.cpp @@ -73,7 +73,6 @@ bool g_killed = false; bool g_fireDMRBeacon = false; bool g_fireP25Control = false; -bool g_interruptP25Control = false; // --------------------------------------------------------------------------- // Global Functions diff --git a/HostMain.h b/HostMain.h index 50198a1e..62461119 100644 --- a/HostMain.h +++ b/HostMain.h @@ -49,7 +49,6 @@ extern bool g_killed; extern bool g_fireDMRBeacon; extern bool g_fireP25Control; -extern bool g_interruptP25Control; extern HOST_SW_API void fatal(const char* msg, ...); diff --git a/RingBuffer.h b/RingBuffer.h index dd240e85..482532a6 100644 --- a/RingBuffer.h +++ b/RingBuffer.h @@ -76,7 +76,7 @@ public: bool addData(const T* buffer, uint32_t length) { if (length >= freeSpace()) { - LogError(LOG_HOST, "%s buffer overflow, clearing the buffer. (%u >= %u)", m_name, length, freeSpace()); + LogError(LOG_HOST, "[%s] buffer overflow, clearing the buffer. (%u >= %u)", m_name, length, freeSpace()); clear(); return false; } diff --git a/config.example.yml b/config.example.yml index 41a4a005..ccf04a75 100644 --- a/config.example.yml +++ b/config.example.yml @@ -43,7 +43,7 @@ protocols: callHang: 5 txHang: 8 silenceThreshold: 21 - queueSize: 5000 + queueSize: 31 verbose: true debug: false p25: @@ -73,7 +73,7 @@ protocols: sndcpGrant: false silenceThreshold: 124 disableNetworkHDU: false - queueSize: 5000 + queueSize: 12 verbose: true debug: false system: diff --git a/dmr/Control.cpp b/dmr/Control.cpp index 5bf6df4b..bdfe1e46 100644 --- a/dmr/Control.cpp +++ b/dmr/Control.cpp @@ -217,53 +217,44 @@ bool Control::processWakeup(const uint8_t* data) } /// -/// Process a data frame for slot 1, from the RF interface. +/// Process a data frame for slot, from the RF interface. /// /// DMR data frame buffer. /// Length of data frame buffer. /// True, if data frame was processed, otherwise false. -bool Control::processFrame1(uint8_t *data, uint32_t len) +bool Control::processFrame(uint32_t slotNo, uint8_t *data, uint32_t len) { assert(data != NULL); - return m_slot1->processFrame(data, len); -} - -/// -/// Get a frame data for slot 1, from data ring buffer. -/// -/// Buffer to put retrieved DMR data frame data. -/// Length of data retrieved from DMR ring buffer. -uint32_t Control::getFrame1(uint8_t* data) -{ - assert(data != NULL); - - return m_slot1->getFrame(data); -} - -/// -/// Process a data frame for slot 2, from the RF interface. -/// -/// DMR data frame buffer. -/// Length of data frame buffer. -/// True, if data frame was processed, otherwise false. -bool Control::processFrame2(uint8_t *data, uint32_t len) -{ - assert(data != NULL); - - return m_slot2->processFrame(data, len); + switch (slotNo) { + case 1U: + return m_slot1->processFrame(data, len); + case 2U: + return m_slot2->processFrame(data, len); + default: + LogError(LOG_NET, "DMR, invalid slot, slotNo = %u", slotNo); + return false; + } } /// -/// Get a frame data for slot 2, from data ring buffer. +/// Get a data frame for slot, from data ring buffer. /// /// Buffer to put retrieved DMR data frame data. /// Length of data retrieved from DMR ring buffer. -uint32_t Control::getFrame2(uint8_t *data) +uint32_t Control::getFrame(uint32_t slotNo, uint8_t* data) { assert(data != NULL); - return m_slot2->getFrame(data); + switch (slotNo) { + case 1U: + return m_slot1->getFrame(data); + case 2U: + return m_slot2->getFrame(data); + default: + LogError(LOG_NET, "DMR, invalid slot, slotNo = %u", slotNo); + return 0U; + } } /// diff --git a/dmr/Control.h b/dmr/Control.h index 2c455643..d6c0b18a 100644 --- a/dmr/Control.h +++ b/dmr/Control.h @@ -76,14 +76,10 @@ namespace dmr /// Helper to process wakeup frames from the RF interface. bool processWakeup(const uint8_t* data); - /// Process a data frame for slot 1, from the RF interface. - bool processFrame1(uint8_t* data, uint32_t len); - /// Get a frame data for slot 1, from data ring buffer. - uint32_t getFrame1(uint8_t* data); - /// Process a data frame for slot 2, from the RF interface. - bool processFrame2(uint8_t* data, uint32_t len); - /// Get a frame data for slot 2, from data ring buffer. - uint32_t getFrame2(uint8_t* data); + /// Process a data frame for slot, from the RF interface. + bool processFrame(uint32_t slotNo, uint8_t* data, uint32_t len); + /// Get a data frame for slot, from data ring buffer. + uint32_t getFrame(uint32_t slotNo, uint8_t* data); /// Updates the processor. void clock(); diff --git a/dmr/ControlPacket.cpp b/dmr/ControlPacket.cpp index 60ba4f37..7a8a6797 100644 --- a/dmr/ControlPacket.cpp +++ b/dmr/ControlPacket.cpp @@ -67,6 +67,7 @@ using namespace dmr; // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- + /// /// Process DMR data frame from the RF interface. /// @@ -135,9 +136,9 @@ bool ControlPacket::process(uint8_t* data, uint32_t len) data[1U] = 0x00U; if (m_slot->m_duplex) - m_slot->writeQueueRF(data); + m_slot->addFrame(data); - m_slot->writeNetworkRF(data, DT_CSBK, gi ? FLCO_GROUP : FLCO_PRIVATE, srcId, dstId); + m_slot->writeNetwork(data, DT_CSBK, gi ? FLCO_GROUP : FLCO_PRIVATE, srcId, dstId); if (m_verbose) { switch (csbko) { @@ -283,11 +284,11 @@ void ControlPacket::processNetwork(const data::Data & dmrData) // Convert the Data Sync to be from the BS or MS as needed Sync::addDMRDataSync(data + 2U, m_slot->m_duplex); - m_slot->writeQueueNet(data); + m_slot->addFrame(data, true); } } else - m_slot->writeQueueNet(data); + m_slot->addFrame(data, true); if (m_verbose) { switch (csbko) { @@ -425,7 +426,7 @@ void ControlPacket::writeRF_Ext_Func(uint32_t func, uint32_t arg, uint32_t dstId data[1U] = 0x00U; if (m_slot->m_duplex) - m_slot->writeQueueRF(data); + m_slot->addFrame(data); } /// @@ -473,12 +474,13 @@ void ControlPacket::writeRF_Call_Alrt(uint32_t srcId, uint32_t dstId) data[1U] = 0x00U; if (m_slot->m_duplex) - m_slot->writeQueueRF(data); + m_slot->addFrame(data); } // --------------------------------------------------------------------------- // Private Class Members // --------------------------------------------------------------------------- + /// /// Initializes a new instance of the ControlPacket class. /// @@ -540,7 +542,7 @@ void ControlPacket::writeRF_TSCC_Aloha() data[1U] = 0x00U; if (m_slot->m_duplex) - m_slot->writeQueueRF(data); + m_slot->addFrame(data); } /// @@ -587,7 +589,7 @@ void ControlPacket::writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd) data[1U] = 0x00U; if (m_slot->m_duplex) - m_slot->writeQueueRF(data); + m_slot->addFrame(data); } /// @@ -628,5 +630,5 @@ void ControlPacket::writeRF_TSCC_Bcast_Sys_Parm() data[1U] = 0x00U; if (m_slot->m_duplex) - m_slot->writeQueueRF(data); + m_slot->addFrame(data); } diff --git a/dmr/DataPacket.cpp b/dmr/DataPacket.cpp index d7c6e0c6..3f11a8ce 100644 --- a/dmr/DataPacket.cpp +++ b/dmr/DataPacket.cpp @@ -48,6 +48,7 @@ using namespace dmr; // --------------------------------------------------------------------------- // Macros // --------------------------------------------------------------------------- + // Don't process RF frames if the network isn't in a idle state. #define CHECK_TRAFFIC_COLLISION(_DST_ID) \ if (m_slot->m_netState != RS_NET_IDLE && _DST_ID == m_slot->m_netLastDstId) { \ @@ -65,6 +66,7 @@ using namespace dmr; // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- + /// /// Process DMR data frame from the RF interface. /// @@ -100,11 +102,11 @@ bool DataPacket::process(uint8_t* data, uint32_t len) data[0U] = modem::TAG_EOT; data[1U] = 0x00U; - m_slot->writeNetworkRF(data, DT_TERMINATOR_WITH_LC); + m_slot->writeNetwork(data, DT_TERMINATOR_WITH_LC); if (m_slot->m_duplex) { for (uint32_t i = 0U; i < m_slot->m_hangCount; i++) - m_slot->writeQueueRF(data); + m_slot->addFrame(data); } } @@ -184,9 +186,9 @@ bool DataPacket::process(uint8_t* data, uint32_t len) data[1U] = 0x00U; if (m_slot->m_duplex && m_repeatDataPacket) - m_slot->writeQueueRF(data); + m_slot->addFrame(data); - m_slot->writeNetworkRF(data, DT_DATA_HEADER); + m_slot->writeNetwork(data, DT_DATA_HEADER); m_slot->m_rfState = RS_RF_DATA; m_slot->m_rfLastDstId = dstId; @@ -263,10 +265,10 @@ bool DataPacket::process(uint8_t* data, uint32_t len) // convert the Data Sync to be from the BS or MS as needed Sync::addDMRDataSync(data + 2U, m_slot->m_duplex); - m_slot->writeNetworkRF(data, dataType); + m_slot->writeNetwork(data, dataType); if (m_slot->m_duplex && m_repeatDataPacket) { - m_slot->writeQueueRF(data); + m_slot->addFrame(data); } if (m_slot->m_rfFrames == 0U) { @@ -330,11 +332,11 @@ void DataPacket::processNetwork(const data::Data& dmrData) if (m_slot->m_duplex) { for (uint32_t i = 0U; i < m_slot->m_hangCount; i++) - m_slot->writeQueueNet(data); + m_slot->addFrame(data, true); } else { for (uint32_t i = 0U; i < 3U; i++) - m_slot->writeQueueNet(data); + m_slot->addFrame(data, true); } } @@ -387,10 +389,10 @@ void DataPacket::processNetwork(const data::Data& dmrData) data[1U] = 0x00U; // Put a small delay into starting transmission - m_slot->writeQueueNet(m_slot->m_idle); - m_slot->writeQueueNet(m_slot->m_idle); + m_slot->addFrame(m_slot->m_idle, true); + m_slot->addFrame(m_slot->m_idle, true); - m_slot->writeQueueNet(data); + m_slot->addFrame(data, true); m_slot->m_netState = RS_NET_DATA; m_slot->m_netLastDstId = dstId; @@ -469,7 +471,7 @@ void DataPacket::processNetwork(const data::Data& dmrData) data[0U] = m_slot->m_netFrames == 0U ? modem::TAG_EOT : modem::TAG_DATA; data[1U] = 0x00U; - m_slot->writeQueueNet(data); + m_slot->addFrame(data, true); if (m_verbose) { if (dataType == DT_RATE_12_DATA) { @@ -502,6 +504,7 @@ void DataPacket::processNetwork(const data::Data& dmrData) // --------------------------------------------------------------------------- // Private Class Members // --------------------------------------------------------------------------- + /// /// Initializes a new instance of the DataPacket class. /// diff --git a/dmr/Slot.cpp b/dmr/Slot.cpp index d5405a41..aa0ec85e 100644 --- a/dmr/Slot.cpp +++ b/dmr/Slot.cpp @@ -93,6 +93,7 @@ uint16_t Slot::m_tsccCnt = 0U; // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- + /// /// Initializes a new instance of the Slot class. /// @@ -108,7 +109,7 @@ uint16_t Slot::m_tsccCnt = 0U; Slot::Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSize, bool dumpDataPacket, bool repeatDataPacket, bool dumpCSBKData, bool debug, bool verbose) : m_slotNo(slotNo), - m_queue(queueSize, "DMR Slot"), + m_queue(queueSize, "DMR Slot Frame"), m_rfState(RS_RF_LISTENING), m_rfLastDstId(0U), m_netState(RS_NET_IDLE), @@ -621,49 +622,34 @@ void Slot::setSiteData(uint32_t netId, uint8_t siteId, uint8_t channelId, uint32 // --------------------------------------------------------------------------- // Private Class Members // --------------------------------------------------------------------------- + /// -/// Write data processed from RF to the data ring buffer. +/// Add data frame to the data ring buffer. /// /// -void Slot::writeQueueRF(const uint8_t *data) +/// +void Slot::addFrame(const uint8_t *data, bool net) { assert(data != NULL); - if (m_netState != RS_NET_IDLE) - return; - - uint8_t len = DMR_FRAME_LENGTH_BYTES + 2U; - - uint32_t space = m_queue.freeSpace(); - if (space < (len + 1U)) { - uint32_t queueLen = m_queue.length(); - m_queue.resize(queueLen + QUEUE_RESIZE_SIZE); - LogError(LOG_DMR, "Slot %u, overflow in the DMR slot queue; queue free is %u, needed %u; resized was %u is %u", m_slotNo, space, len, queueLen, m_queue.length()); - return; - } - - if (m_debug) { - Utils::symbols("!!! *Tx DMR", data + 2U, len - 2U); + if (!net) { + if (m_netState != RS_NET_IDLE) + return; } - m_queue.addData(&len, 1U); - m_queue.addData(data, len); -} - -/// -/// Write data processed from the network to the data ring buffer. -/// -/// -void Slot::writeQueueNet(const uint8_t *data) -{ - assert(data != NULL); - uint8_t len = DMR_FRAME_LENGTH_BYTES + 2U; - uint32_t space = m_queue.freeSpace(); if (space < (len + 1U)) { - LogError(LOG_DMR, "Slot %u, overflow in the DMR slot queue while writing network data; queue free is %u, needed %u", m_slotNo, space, len); - return; + if (!net) { + uint32_t queueLen = m_queue.length(); + m_queue.resize(queueLen + (DMR_FRAME_LENGTH_BYTES + 2U)); + LogError(LOG_DMR, "Slot %u, overflow in the DMR slot queue; queue free is %u, needed %u; resized was %u is %u", m_slotNo, space, len, queueLen, m_queue.length()); + return; + } + else { + LogError(LOG_DMR, "Slot %u, overflow in the DMR slot queue while writing network data; queue free is %u, needed %u", m_slotNo, space, len); + return; + } } if (m_debug) { @@ -675,21 +661,21 @@ void Slot::writeQueueNet(const uint8_t *data) } /// -/// Write data processed from RF to the network. +/// Write data frame to the network. /// /// /// /// -void Slot::writeNetworkRF(const uint8_t* data, uint8_t dataType, uint8_t errors) +void Slot::writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t errors) { assert(data != NULL); assert(m_rfLC != NULL); - writeNetworkRF(data, dataType, m_rfLC->getFLCO(), m_rfLC->getSrcId(), m_rfLC->getDstId(), errors); + writeNetwork(data, dataType, m_rfLC->getFLCO(), m_rfLC->getSrcId(), m_rfLC->getDstId(), errors); } /// -/// Write data processed from RF to the network. +/// Write data frame to the network. /// /// /// @@ -697,7 +683,7 @@ void Slot::writeNetworkRF(const uint8_t* data, uint8_t dataType, uint8_t errors) /// /// /// -void Slot::writeNetworkRF(const uint8_t* data, uint8_t dataType, uint8_t flco, uint32_t srcId, +void Slot::writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t flco, uint32_t srcId, uint32_t dstId, uint8_t errors) { assert(data != NULL); @@ -760,7 +746,7 @@ void Slot::writeEndRF(bool writeEnd) data[1U] = 0x00U; for (uint32_t i = 0U; i < m_hangCount; i++) - writeQueueRF(data); + addFrame(data); } } @@ -818,11 +804,11 @@ void Slot::writeEndNet(bool writeEnd) if (m_duplex) { for (uint32_t i = 0U; i < m_hangCount; i++) - writeQueueNet(data); + addFrame(data, true); } else { for (uint32_t i = 0U; i < 3U; i++) - writeQueueNet(data); + addFrame(data, true); } } diff --git a/dmr/Slot.h b/dmr/Slot.h index eb15385d..f47f127b 100644 --- a/dmr/Slot.h +++ b/dmr/Slot.h @@ -54,6 +54,7 @@ namespace dmr // --------------------------------------------------------------------------- // Class Prototypes // --------------------------------------------------------------------------- + class HOST_SW_API VoicePacket; class HOST_SW_API DataPacket; class HOST_SW_API ControlPacket; @@ -76,7 +77,7 @@ namespace dmr /// Process a data frame from the RF interface. bool processFrame(uint8_t* data, uint32_t len); - /// Get frame data from data ring buffer. + /// Get data frame from data ring buffer. uint32_t getFrame(uint8_t* data); /// Process a data frames from the network. @@ -208,14 +209,13 @@ namespace dmr static uint16_t m_tsccCnt; - /// Write data processed from RF to the data ring buffer. - void writeQueueRF(const uint8_t* data); - /// Write data processed from the network to the data ring buffer. - void writeQueueNet(const uint8_t* data); - /// Write data processed from RF to the network. - void writeNetworkRF(const uint8_t* data, uint8_t dataType, uint8_t errors = 0U); - /// Write data processed from RF to the network. - void writeNetworkRF(const uint8_t* data, uint8_t dataType, uint8_t flco, uint32_t srcId, + /// Add data frame to the data ring buffer. + void addFrame(const uint8_t* data, bool net = false); + + /// Write data frame to the network. + void writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t errors = 0U); + /// Write data frame to the network. + void writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t flco, uint32_t srcId, uint32_t dstId, uint8_t errors = 0U); /// Helper to write RF end of frame data. diff --git a/dmr/VoicePacket.cpp b/dmr/VoicePacket.cpp index fb2bc526..c0912293 100644 --- a/dmr/VoicePacket.cpp +++ b/dmr/VoicePacket.cpp @@ -49,6 +49,7 @@ using namespace dmr; // --------------------------------------------------------------------------- // Macros // --------------------------------------------------------------------------- + #define CHECK_TRAFFIC_COLLISION_DELLC(_DST_ID) \ if (m_slot->m_netState != RS_NET_IDLE && _DST_ID == m_slot->m_netLastDstId) { \ LogWarning(LOG_RF, "DMR Slot %u, Traffic collision detect, preempting new RF traffic to existing network traffic!", m_slot->m_slotNo); \ @@ -67,6 +68,7 @@ using namespace dmr; // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- + /// /// Process DMR voice frame from the RF interface. /// @@ -183,10 +185,10 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) m_slot->m_modem->writeDMRAbort(m_slot->m_slotNo); for (uint32_t i = 0U; i < NO_HEADERS_DUPLEX; i++) - m_slot->writeQueueRF(data); + m_slot->addFrame(data); } - m_slot->writeNetworkRF(data, DT_VOICE_LC_HEADER); + m_slot->writeNetwork(data, DT_VOICE_LC_HEADER); m_slot->m_rfState = RS_RF_AUDIO; m_slot->m_rfLastDstId = dstId; @@ -229,9 +231,9 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) data[1U] = 0x00U; if (m_slot->m_duplex) - m_slot->writeQueueRF(data); + m_slot->addFrame(data); - m_slot->writeNetworkRF(data, DT_VOICE_PI_HEADER); + m_slot->writeNetwork(data, DT_VOICE_PI_HEADER); if (m_verbose) { LogMessage(LOG_RF, DMR_DT_VOICE_PI_HEADER ", slot = %u, algId = %u, kId = %u, dstId = %u", m_slot->m_slotNo, lc->getAlgId(), lc->getKId(), lc->getDstId()); @@ -284,9 +286,9 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) data[1U] = 0x00U; if (m_slot->m_duplex) - m_slot->writeQueueRF(data); + m_slot->addFrame(data); - m_slot->writeNetworkRF(data, DT_VOICE_SYNC, errors); + m_slot->writeNetwork(data, DT_VOICE_SYNC, errors); return true; } @@ -438,7 +440,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) data[0U] = modem::TAG_DATA; data[1U] = 0x00U; - m_slot->writeNetworkRF(data, DT_VOICE, errors); + m_slot->writeNetwork(data, DT_VOICE, errors); if (m_embeddedLCOnly) { // Only send the previously received LC @@ -451,7 +453,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) } if (m_slot->m_duplex) - m_slot->writeQueueRF(data); + m_slot->addFrame(data); return true; } @@ -539,10 +541,10 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) m_slot->m_modem->writeDMRAbort(m_slot->m_slotNo); for (uint32_t i = 0U; i < NO_HEADERS_DUPLEX; i++) - m_slot->writeQueueRF(start); + m_slot->addFrame(start); } - m_slot->writeNetworkRF(start, DT_VOICE_LC_HEADER); + m_slot->writeNetwork(start, DT_VOICE_LC_HEADER); m_rfN = data[1U] & 0x0FU; @@ -589,9 +591,9 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) data[1U] = 0x00U; if (m_slot->m_duplex) - m_slot->writeQueueRF(data); + m_slot->addFrame(data); - m_slot->writeNetworkRF(data, DT_VOICE, errors); + m_slot->writeNetwork(data, DT_VOICE, errors); m_slot->m_rfState = RS_RF_AUDIO; @@ -690,15 +692,15 @@ void VoicePacket::processNetwork(const data::Data& dmrData) } for (uint32_t i = 0U; i < m_slot->m_jitterSlots; i++) - m_slot->writeQueueNet(m_slot->m_idle); + m_slot->addFrame(m_slot->m_idle, true); if (m_slot->m_duplex) { for (uint32_t i = 0U; i < NO_HEADERS_DUPLEX; i++) - m_slot->writeQueueNet(data); + m_slot->addFrame(data, true); } else { for (uint32_t i = 0U; i < NO_HEADERS_SIMPLEX; i++) - m_slot->writeQueueNet(data); + m_slot->addFrame(data, true); } m_slot->m_netState = RS_NET_AUDIO; @@ -734,7 +736,7 @@ void VoicePacket::processNetwork(const data::Data& dmrData) } for (uint32_t i = 0U; i < m_slot->m_jitterSlots; i++) - m_slot->writeQueueNet(m_slot->m_idle); + m_slot->addFrame(m_slot->m_idle, true); // Create a dummy start frame uint8_t start[DMR_FRAME_LENGTH_BYTES + 2U]; @@ -754,11 +756,11 @@ void VoicePacket::processNetwork(const data::Data& dmrData) if (m_slot->m_duplex) { for (uint32_t i = 0U; i < NO_HEADERS_DUPLEX; i++) - m_slot->writeQueueRF(start); + m_slot->addFrame(start); } else { for (uint32_t i = 0U; i < NO_HEADERS_SIMPLEX; i++) - m_slot->writeQueueRF(start); + m_slot->addFrame(start); } m_slot->m_netFrames = 0U; @@ -800,7 +802,7 @@ void VoicePacket::processNetwork(const data::Data& dmrData) data[0U] = modem::TAG_DATA; data[1U] = 0x00U; - m_slot->writeQueueNet(data); + m_slot->addFrame(data, true); if (m_verbose) { LogMessage(LOG_NET, DMR_DT_VOICE_PI_HEADER ", slot = %u, algId = %u, kId = %u, dstId = %u", m_slot->m_slotNo, lc->getAlgId(), lc->getKId(), lc->getDstId()); @@ -831,7 +833,7 @@ void VoicePacket::processNetwork(const data::Data& dmrData) } for (uint32_t i = 0U; i < m_slot->m_jitterSlots; i++) - m_slot->writeQueueNet(m_slot->m_idle); + m_slot->addFrame(m_slot->m_idle, true); // Create a dummy start frame uint8_t start[DMR_FRAME_LENGTH_BYTES + 2U]; @@ -851,11 +853,11 @@ void VoicePacket::processNetwork(const data::Data& dmrData) if (m_slot->m_duplex) { for (uint32_t i = 0U; i < NO_HEADERS_DUPLEX; i++) - m_slot->writeQueueRF(start); + m_slot->addFrame(start); } else { for (uint32_t i = 0U; i < NO_HEADERS_SIMPLEX; i++) - m_slot->writeQueueRF(start); + m_slot->addFrame(start); } m_slot->m_netFrames = 0U; @@ -902,7 +904,7 @@ void VoicePacket::processNetwork(const data::Data& dmrData) } if (!m_slot->m_netTimeout) - m_slot->writeQueueNet(data); + m_slot->addFrame(data, true); m_netEmbeddedReadN = (m_netEmbeddedReadN + 1U) % 2U; m_netEmbeddedWriteN = (m_netEmbeddedWriteN + 1U) % 2U; @@ -1035,7 +1037,7 @@ void VoicePacket::processNetwork(const data::Data& dmrData) if (insertSilence(data, dmrData.getN())) { if (!m_slot->m_netTimeout) - m_slot->writeQueueNet(data); + m_slot->addFrame(data, true); } m_slot->m_packetTimer.start(); @@ -1055,6 +1057,7 @@ void VoicePacket::processNetwork(const data::Data& dmrData) // --------------------------------------------------------------------------- // Private Class Members // --------------------------------------------------------------------------- + /// /// Initializes a new instance of the VoicePacket class. /// @@ -1255,7 +1258,7 @@ void VoicePacket::insertSilence(uint32_t count) emb.encode(data + 2U); } - m_slot->writeQueueNet(data); + m_slot->addFrame(data, true); m_netN = n; diff --git a/host/Host.cpp b/host/Host.cpp index e79c28bc..f62cf593 100644 --- a/host/Host.cpp +++ b/host/Host.cpp @@ -95,8 +95,6 @@ Host::Host(const std::string& confFile) : m_cwIdTimer(1000U), m_dmrEnabled(false), m_p25Enabled(false), - m_p25CtrlChannel(false), - m_dmrCtrlChannel(false), m_duplex(false), m_fixedMode(false), m_timeout(180U), @@ -120,7 +118,10 @@ Host::Host(const std::string& confFile) : m_tidLookup(NULL), m_dmrBeacons(false), m_dmrTSCCData(false), - m_controlData(false), + m_dmrCtrlChannel(false), + m_p25CCData(false), + m_p25CtrlChannel(false), + m_p25CtrlBroadcast(false), m_remoteControl(NULL) { UDPSocket::startup(); @@ -357,10 +358,25 @@ int Host::run() bool dumpTAData = dmrProtocol["dumpTAData"].as(true); uint32_t callHang = dmrProtocol["callHang"].as(3U); uint32_t txHang = dmrProtocol["txHang"].as(4U); - uint32_t dmrQueueSize = dmrProtocol["queueSize"].as(5120U); + uint32_t queueSize = dmrProtocol["queueSize"].as(31U); bool dmrVerbose = dmrProtocol["verbose"].as(true); bool dmrDebug = dmrProtocol["debug"].as(false); + // clamp queue size to no less then 24 and no greater the 100 + if (queueSize <= 24U) { + LogWarning(LOG_HOST, "DMR queue size must be greater then 24 frames, defaulting to 24 frames!"); + queueSize = 24U; + } + if (queueSize > 100U) { + LogWarning(LOG_HOST, "DMR queue size must be less then 100 frames, defaulting to 100 frames!"); + queueSize = 100U; + } + if (queueSize > 60U) { + LogWarning(LOG_HOST, "DMR queue size is excessive, >60 frames!"); + } + + uint32_t queueSizeBytes = queueSize * (dmr::DMR_FRAME_LENGTH_BYTES * 5U); + uint32_t jitter = m_conf["network"]["jitter"].as(360U); if (txHang > m_rfModeHang) @@ -378,7 +394,7 @@ int Host::run() LogInfo(" Dump CSBK Data: %s", dmrDumpCsbkData ? "yes" : "no"); LogInfo(" Call Hang: %us", callHang); LogInfo(" TX Hang: %us", txHang); - LogInfo(" Queue Size: %u", dmrQueueSize); + LogInfo(" Queue Size: %u (%u bytes)", queueSize, queueSizeBytes); LogInfo(" Roaming Beacons: %s", m_dmrBeacons ? "yes" : "no"); if (m_dmrBeacons) { @@ -403,13 +419,19 @@ int Host::run() if (dmrCtrlChannel) { m_dmrCtrlChannel = dmrCtrlChannel; } + + g_fireDMRBeacon = true; } - dmr = new dmr::Control(m_dmrColorCode, callHang, dmrQueueSize, embeddedLCOnly, dumpTAData, m_timeout, m_rfTalkgroupHang, + dmr = new dmr::Control(m_dmrColorCode, callHang, queueSizeBytes, 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, true); + if (dmrCtrlChannel) { + dmr->setCCRunning(true); + } + m_dmrTXTimer.setTimeout(txHang); if (dmrVerbose) { @@ -421,8 +443,8 @@ int Host::run() } // initialize P25 - Timer p25CCIntervalTimer(1000U); - Timer p25CCDurationTimer(1000U); + Timer p25BcastIntervalTimer(1000U); + Timer p25BcastDurationTimer(1000U); p25::Control* p25 = NULL; LogInfo("P25 Parameters"); @@ -430,34 +452,47 @@ int Host::run() if (m_p25Enabled) { yaml::Node p25Protocol = protocolConf["p25"]; uint32_t tduPreambleCount = p25Protocol["tduPreambleCount"].as(8U); - m_controlData = p25Protocol["control"]["enable"].as(false); + m_p25CCData = p25Protocol["control"]["enable"].as(false); bool p25CtrlChannel = p25Protocol["control"]["dedicated"].as(false); bool p25CtrlBroadcast = p25Protocol["control"]["broadcast"].as(true); bool p25DumpDataPacket = p25Protocol["dumpDataPacket"].as(false); bool p25RepeatDataPacket = p25Protocol["repeatDataPacket"].as(true); bool p25DumpTsbkData = p25Protocol["dumpTsbkData"].as(false); uint32_t callHang = p25Protocol["callHang"].as(3U); - uint32_t p25QueueSize = p25Protocol["queueSize"].as(8192U); + uint16_t queueSize = p25Protocol["queueSize"].as(12U); bool p25Verbose = p25Protocol["verbose"].as(true); bool p25Debug = p25Protocol["debug"].as(false); + // clamp queue size to no less then 5 and no greater the 100 frames + if (queueSize <= 10U) { + LogWarning(LOG_HOST, "P25 queue size must be greater then 10 frames, defaulting to 10 frames!"); + queueSize = 10U; + } + if (queueSize > 100U) { + LogWarning(LOG_HOST, "P25 queue size must be less then 100 frames, defaulting to 100 frames!"); + queueSize = 100U; + } + if (queueSize > 30U) { + LogWarning(LOG_HOST, "P25 queue size is excessive, >30 frames!"); + } + + uint32_t queueSizeBytes = queueSize * p25::P25_LDU_FRAME_LENGTH_BYTES; + LogInfo(" TDU Preamble before Voice: %u", tduPreambleCount); LogInfo(" Dump Packet Data: %s", p25DumpDataPacket ? "yes" : "no"); LogInfo(" Repeat Packet Data: %s", p25RepeatDataPacket ? "yes" : "no"); LogInfo(" Dump TSBK Data: %s", p25DumpTsbkData ? "yes" : "no"); LogInfo(" Call Hang: %us", callHang); - LogInfo(" Queue Size: %u", p25QueueSize); + LogInfo(" Queue Size: %u (%u bytes)", queueSize, queueSizeBytes); - LogInfo(" Control: %s", m_controlData ? "yes" : "no"); + LogInfo(" Control: %s", m_p25CCData ? "yes" : "no"); uint32_t p25ControlBcstInterval = p25Protocol["control"]["interval"].as(300U); uint32_t p25ControlBcstDuration = p25Protocol["control"]["duration"].as(1U); - if (m_controlData) { + if (m_p25CCData) { LogInfo(" Control Broadcast: %s", p25CtrlBroadcast ? "yes" : "no"); LogInfo(" Control Channel: %s", p25CtrlChannel ? "yes" : "no"); if (p25CtrlChannel) { - p25ControlBcstInterval = 30U; - p25ControlBcstDuration = 120U; m_p25CtrlChannel = p25CtrlChannel; } else { @@ -465,28 +500,27 @@ int Host::run() LogInfo(" Control Broadcast Duration: %us", p25ControlBcstDuration); } - m_p25CtrlBroadcast = p25CtrlBroadcast; - p25CCIntervalTimer.setTimeout(p25ControlBcstInterval); - p25CCIntervalTimer.start(); + p25BcastDurationTimer.setTimeout(p25ControlBcstDuration); - p25CCDurationTimer.setTimeout(p25ControlBcstDuration); + p25BcastIntervalTimer.setTimeout(p25ControlBcstInterval); + p25BcastIntervalTimer.start(); + m_p25CtrlBroadcast = p25CtrlBroadcast; if (p25CtrlBroadcast) { g_fireP25Control = true; - g_interruptP25Control = false; - } - else { - g_fireP25Control = false; - g_interruptP25Control = false; } } - p25 = new p25::Control(m_p25NAC, callHang, p25QueueSize, m_modem, m_network, m_timeout, m_rfTalkgroupHang, - p25ControlBcstInterval, m_duplex, m_ridLookup, m_tidLookup, m_idenTable, rssi, p25DumpDataPacket, p25RepeatDataPacket, + p25 = new p25::Control(m_p25NAC, callHang, queueSizeBytes, m_modem, m_network, m_timeout, m_rfTalkgroupHang, + 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_siteId, m_channelId, m_channelNo, true); + if (p25CtrlChannel) { + p25->setCCRunning(true); + } + if (p25Verbose) { LogInfo(" Verbose: yes"); } @@ -513,7 +547,7 @@ int Host::run() } #endif - // P25 control channel checks + // P25 CC checks if (m_dmrEnabled && m_p25CtrlChannel) { ::LogError(LOG_HOST, "Cannot have DMR enabled when using dedicated P25 control!"); g_killed = true; @@ -523,7 +557,7 @@ int Host::run() ::LogWarning(LOG_HOST, "Fixed mode should be enabled when using dedicated P25 control!"); } - if (!m_duplex && m_controlData) { + if (!m_duplex && m_p25CCData) { ::LogError(LOG_HOST, "Cannot have P25 control and simplex mode at the same time."); g_killed = true; } @@ -544,7 +578,7 @@ int Host::run() } // DMR beacon checks - if (m_dmrBeacons && m_controlData) { + if (m_dmrBeacons && m_p25CCData) { ::LogError(LOG_HOST, "Cannot have DMR roaming becaons and P25 control at the same time."); g_killed = true; } @@ -618,13 +652,9 @@ int Host::run() // Macro to interrupt a running P25 control channel transmission #define INTERRUPT_P25_CONTROL \ if (p25 != NULL) { \ - if (g_interruptP25Control) { \ - p25CCDurationTimer.stop(); \ - if (p25CCDurationTimer.isRunning() && !p25CCDurationTimer.hasExpired()) { \ - LogDebug(LOG_HOST, "traffic interrupts P25 CC, g_interruptP25Control = %u", g_interruptP25Control); \ - m_modem->clearP25Data(); \ - p25->reset(); \ - } \ + p25->setCCHalted(true); \ + if (p25BcastDurationTimer.isRunning() && !p25BcastDurationTimer.isPaused()) { \ + p25BcastDurationTimer.pause(); \ } \ } @@ -695,33 +725,37 @@ int Host::run() // to the modem ret = m_modem->hasDMRSpace1(); if (ret) { - len = dmr->getFrame1(data); + len = dmr->getFrame(1U, data); if (len > 0U) { + // if the state is idle; set to DMR, start mode timer and start DMR idle frames if (m_state == STATE_IDLE) { m_modeTimer.setTimeout(m_netModeHang); setState(STATE_DMR); START_DMR_DUPLEX_IDLE(true); } + + // if the state is DMR; start DMR idle frames and write DMR slot 1 data if (m_state == STATE_DMR) { START_DMR_DUPLEX_IDLE(true); m_modem->writeDMRData1(data, len); + // if there is no DMR CC running; run the interrupt macro to stop + // any running DMR beacon if (!dmr->getCCRunning()) { INTERRUPT_DMR_BEACON; } - if (g_interruptP25Control && p25CCDurationTimer.isRunning()) { - p25CCDurationTimer.pause(); + // if there is a P25 CC running; halt the CC + if (p25 != NULL) { + if (p25->getCCRunning() && !p25->getCCHalted()) { + p25->setCCHalted(true); + INTERRUPT_P25_CONTROL; + } } m_modeTimer.start(); } -/* - else if (m_state != HOST_STATE_LOCKOUT) { - LogWarning(LOG_HOST, "DMR data received, state = %u", m_state); - } -*/ } } @@ -730,33 +764,35 @@ int Host::run() // to the modem ret = m_modem->hasDMRSpace2(); if (ret) { - len = dmr->getFrame2(data); + len = dmr->getFrame(2U, data); if (len > 0U) { + // if the state is idle; set to DMR, start mode timer and start DMR idle frames if (m_state == STATE_IDLE) { m_modeTimer.setTimeout(m_netModeHang); setState(STATE_DMR); START_DMR_DUPLEX_IDLE(true); } + + // if the state is DMR; start DMR idle frames and write DMR slot 2 data if (m_state == STATE_DMR) { START_DMR_DUPLEX_IDLE(true); m_modem->writeDMRData2(data, len); + // if there is no DMR CC running; run the interrupt macro to stop + // any running DMR beacon if (!dmr->getCCRunning()) { INTERRUPT_DMR_BEACON; } - if (g_interruptP25Control && p25CCDurationTimer.isRunning()) { - p25CCDurationTimer.pause(); + // if there is a P25 CC running; halt the CC + if (p25->getCCRunning() && !p25->getCCHalted()) { + p25->setCCHalted(true); + INTERRUPT_P25_CONTROL; } m_modeTimer.start(); } -/* - else if (m_state != HOST_STATE_LOCKOUT) { - LogWarning(LOG_HOST, "DMR data received, state = %u", m_state); - } -*/ } } } @@ -770,38 +806,31 @@ int Host::run() if (ret) { len = p25->getFrame(data); if (len > 0U) { + // if the state is idle; set to P25 and start mode timer if (m_state == STATE_IDLE) { m_modeTimer.setTimeout(m_netModeHang); setState(STATE_P25); } + // if the state is P25; write P25 data if (m_state == STATE_P25) { m_modem->writeP25Data(data, len); - + INTERRUPT_DMR_BEACON; - - if (g_interruptP25Control && p25CCDurationTimer.isRunning()) { - p25CCDurationTimer.pause(); - } - + m_modeTimer.start(); } -/* - else if (m_state != HOST_STATE_LOCKOUT) { - LogWarning(LOG_HOST, "P25 data received, state = %u", m_state); - } -*/ } else { + // if we have no P25 data, and we're either idle or P25 state, check if we + // need to be starting the CC running flag or writing end of voice call data if (m_state == STATE_IDLE || m_state == STATE_P25) { - // P25 control data, if control data is being transmitted - if (p25CCDurationTimer.isRunning() && !p25CCDurationTimer.hasExpired()) { - p25->setCCRunning(true); - p25->writeControlRF(); + if (p25->getCCHalted()) { + p25->setCCHalted(false); } - // P25 status data, tail on idle - ret = p25->writeEndRF(); + // write end of voice if necessary + ret = p25->writeRF_VoiceEnd(); if (ret) { if (m_state == STATE_IDLE) { m_modeTimer.setTimeout(m_netModeHang); @@ -817,13 +846,12 @@ int Host::run() // if the modem is in duplex -- handle P25 CC burst control if (m_duplex) { - if (p25CCDurationTimer.isPaused() && !g_interruptP25Control) { - LogDebug(LOG_HOST, "traffic complete, resume P25 CC, g_interruptP25Control = %u", g_interruptP25Control); - p25CCDurationTimer.resume(); + if (p25BcastDurationTimer.isPaused() && !p25->getCCHalted()) { + p25BcastDurationTimer.resume(); } - if (g_interruptP25Control) { - g_fireP25Control = true; + if (p25->getCCHalted()) { + p25->setCCHalted(false); } if (g_fireP25Control) { @@ -859,8 +887,9 @@ int Host::run() if (ret) { m_modeTimer.setTimeout(m_rfModeHang); setState(STATE_DMR); + START_DMR_DUPLEX_IDLE(true); - + INTERRUPT_DMR_BEACON; INTERRUPT_P25_CONTROL; } @@ -871,10 +900,10 @@ int Host::run() setState(STATE_DMR); START_DMR_DUPLEX_IDLE(true); - dmr->processFrame1(data, len); + dmr->processFrame(1U, data, len); INTERRUPT_DMR_BEACON; - p25CCDurationTimer.stop(); + p25BcastDurationTimer.stop(); } } else if (m_state == STATE_DMR) { @@ -889,7 +918,7 @@ int Host::run() } else { // process slot 1 frames - bool ret = dmr->processFrame1(data, len); + bool ret = dmr->processFrame(1U, data, len); if (ret) { INTERRUPT_DMR_BEACON; INTERRUPT_P25_CONTROL; @@ -928,7 +957,7 @@ int Host::run() setState(STATE_DMR); START_DMR_DUPLEX_IDLE(true); - dmr->processFrame2(data, len); + dmr->processFrame(2U, data, len); INTERRUPT_DMR_BEACON; INTERRUPT_P25_CONTROL; @@ -946,7 +975,7 @@ int Host::run() } else { // process slot 2 frames - bool ret = dmr->processFrame2(data, len); + bool ret = dmr->processFrame(2U, data, len); if (ret) { INTERRUPT_DMR_BEACON; INTERRUPT_P25_CONTROL; @@ -970,6 +999,7 @@ int Host::run() len = m_modem->readP25Data(data); if (len > 0U) { if (m_state == STATE_IDLE) { + // process P25 frames bool ret = p25->processFrame(data, len); if (ret) { m_modeTimer.setTimeout(m_rfModeHang); @@ -979,7 +1009,7 @@ int Host::run() INTERRUPT_P25_CONTROL; } else { - ret = p25->writeEndRF(); + ret = p25->writeRF_VoiceEnd(); if (ret) { INTERRUPT_DMR_BEACON; @@ -994,13 +1024,12 @@ int Host::run() // if the modem is in duplex -- handle P25 CC burst control if (m_duplex) { - if (p25CCDurationTimer.isPaused() && !g_interruptP25Control) { - LogDebug(LOG_HOST, "traffic complete, resume P25 CC, g_interruptP25Control = %u", g_interruptP25Control); - p25CCDurationTimer.resume(); + if (p25BcastDurationTimer.isPaused() && !p25->getCCHalted()) { + p25BcastDurationTimer.resume(); } - if (g_interruptP25Control) { - g_fireP25Control = true; + if (p25->getCCHalted()) { + p25->setCCHalted(false); } if (g_fireP25Control) { @@ -1008,20 +1037,20 @@ int Host::run() } } else { - p25CCDurationTimer.stop(); - g_interruptP25Control = false; + p25BcastDurationTimer.stop(); } } } } else if (m_state == STATE_P25) { + // process P25 frames bool ret = p25->processFrame(data, len); if (ret) { m_modeTimer.start(); INTERRUPT_P25_CONTROL; } else { - ret = p25->writeEndRF(); + ret = p25->writeRF_VoiceEnd(); if (ret) { m_modeTimer.start(); } @@ -1061,11 +1090,11 @@ int Host::run() m_cwIdTimer.clock(ms); if (m_cwIdTimer.isRunning() && m_cwIdTimer.hasExpired()) { if (!m_modem->hasTX() && !m_p25CtrlChannel && !m_dmrCtrlChannel) { - if (dmrBeaconDurationTimer.isRunning() || p25CCDurationTimer.isRunning()) { + if (dmrBeaconDurationTimer.isRunning() || p25BcastDurationTimer.isRunning()) { LogDebug(LOG_HOST, "CW, beacon or CC timer running, ceasing"); dmrBeaconDurationTimer.stop(); - p25CCDurationTimer.stop(); + p25BcastDurationTimer.stop(); } LogDebug(LOG_HOST, "CW, start transmitting"); @@ -1135,7 +1164,12 @@ int Host::run() } g_fireDMRBeacon = false; - LogDebug(LOG_HOST, "DMR, roaming beacon burst"); + if (m_dmrTSCCData) { + LogDebug(LOG_HOST, "DMR, start CC broadcast"); + } + else { + LogDebug(LOG_HOST, "DMR, roaming beacon burst"); + } dmrBeaconIntervalTimer.start(); dmrBeaconDurationTimer.start(); } @@ -1168,11 +1202,12 @@ int Host::run() /** P25 */ if (p25 != NULL) { - if (m_controlData) { - p25CCIntervalTimer.clock(ms); + if (m_p25CCData) { + p25BcastIntervalTimer.clock(ms); - if (m_p25CtrlBroadcast) { - if ((p25CCIntervalTimer.isRunning() && p25CCIntervalTimer.hasExpired()) || g_fireP25Control) { + if (!m_p25CtrlChannel && m_p25CtrlBroadcast) { + // clock and check P25 CC broadcast interval timer + if ((p25BcastIntervalTimer.isRunning() && p25BcastIntervalTimer.hasExpired()) || g_fireP25Control) { if ((m_state == STATE_IDLE || m_state == STATE_P25) && !m_modem->hasTX()) { if (m_modeTimer.isRunning()) { m_modeTimer.stop(); @@ -1181,11 +1216,6 @@ int Host::run() if (m_state != STATE_P25) setState(STATE_P25); - if (g_interruptP25Control) { - g_interruptP25Control = false; - LogDebug(LOG_HOST, "traffic complete, restart P25 CC broadcast, g_interruptP25Control = %u", g_interruptP25Control); - } - p25->writeAdjSSNetwork(); p25->setCCRunning(true); @@ -1195,45 +1225,40 @@ int Host::run() } g_fireP25Control = false; - p25CCIntervalTimer.start(); - p25CCDurationTimer.start(); + p25BcastIntervalTimer.start(); + p25BcastDurationTimer.start(); // if the CC is continuous -- clock one cycle into the duration timer if (m_p25CtrlChannel) { - p25CCDurationTimer.clock(ms); + p25BcastDurationTimer.clock(ms); } } } - // if the CC is continuous -- we don't clock the CC duration timer (which results in the CC - // broadcast running infinitely until stopped) - if (!m_p25CtrlChannel) { - // clock and check P25 CC duration timer - p25CCDurationTimer.clock(ms); - if (p25CCDurationTimer.isRunning() && p25CCDurationTimer.hasExpired()) { - p25CCDurationTimer.stop(); + if (p25BcastDurationTimer.isPaused()) { + p25BcastDurationTimer.resume(); + } - p25->writeControlEndRF(); - p25->setCCRunning(false); + // clock and check P25 CC broadcast duration timer + p25BcastDurationTimer.clock(ms); + if (p25BcastDurationTimer.isRunning() && p25BcastDurationTimer.hasExpired()) { + p25BcastDurationTimer.stop(); - if (m_state == STATE_P25 && !m_modeTimer.isRunning()) { - m_modeTimer.setTimeout(m_rfModeHang); - m_modeTimer.start(); - } - } + p25->setCCRunning(false); - if (p25CCDurationTimer.isPaused()) { - p25CCDurationTimer.resume(); + if (m_state == STATE_P25 && !m_modeTimer.isRunning()) { + m_modeTimer.setTimeout(m_rfModeHang); + m_modeTimer.start(); } } } else { // simply use the P25 CC interval timer in a non-broadcast state to transmit adjacent site data over // the network - if (p25CCIntervalTimer.isRunning() && p25CCIntervalTimer.hasExpired()) { + if (p25BcastIntervalTimer.isRunning() && p25BcastIntervalTimer.hasExpired()) { if ((m_state == STATE_IDLE || m_state == STATE_P25) && !m_modem->hasTX()) { p25->writeAdjSSNetwork(); - p25CCIntervalTimer.start(); + p25BcastIntervalTimer.start(); } } } @@ -1241,16 +1266,31 @@ int Host::run() } if (g_killed) { + if (dmr != NULL) { + if (m_dmrCtrlChannel) { + if (!hasTxShutdown) { + m_modem->clearDMRData1(); + m_modem->clearDMRData2(); + } + + dmr->setCCRunning(false); + + dmrBeaconDurationTimer.stop(); + dmrBeaconIntervalTimer.stop(); + } + } + if (p25 != NULL) { - if (m_p25CtrlChannel && !hasTxShutdown) { - m_modem->clearP25Data(); - p25->reset(); + if (m_p25CtrlChannel) { + if (!hasTxShutdown) { + m_modem->clearP25Data(); + p25->reset(); + } - p25->writeControlEndRF(); p25->setCCRunning(false); - p25CCDurationTimer.stop(); - p25CCIntervalTimer.stop(); + p25BcastDurationTimer.stop(); + p25BcastIntervalTimer.stop(); } } diff --git a/host/Host.h b/host/Host.h index 76465bd0..5084058d 100644 --- a/host/Host.h +++ b/host/Host.h @@ -83,10 +83,6 @@ private: bool m_dmrEnabled; bool m_p25Enabled; - bool m_p25CtrlChannel; - bool m_p25CtrlBroadcast; - bool m_dmrCtrlChannel; - bool m_duplex; bool m_fixedMode; bool m_useDFSI; @@ -118,7 +114,10 @@ private: bool m_dmrBeacons; bool m_dmrTSCCData; - bool m_controlData; + bool m_dmrCtrlChannel; + bool m_p25CCData; + bool m_p25CtrlChannel; + bool m_p25CtrlBroadcast; uint8_t m_siteId; uint32_t m_dmrNetId; diff --git a/modem/Modem.cpp b/modem/Modem.cpp index 84b90859..40b3f75d 100644 --- a/modem/Modem.cpp +++ b/modem/Modem.cpp @@ -160,12 +160,12 @@ Modem::Modem(port::IModemPort* port, bool duplex, bool rxInvert, bool txInvert, m_openPortHandler(NULL), m_closePortHandler(NULL), m_rspHandler(NULL), - m_rxDMRData1(1110U, "Modem RX DMR1"), - m_rxDMRData2(1110U, "Modem RX DMR2"), - m_txDMRData1(740U, "Modem TX DMR1"), - m_txDMRData2(740U, "Modem TX DMR2"), - m_rxP25Data(6000U, "Modem RX P25"), - m_txP25Data(864U, "Modem TX P25"), + m_rxDMRData1(1089U, "Modem RX DMR1"), // 1089 bytes = 33 DMR Frames + m_rxDMRData2(1089U, "Modem RX DMR2"), + m_txDMRData1(792U, "Modem TX DMR1"), // 792 bytes = 24 DMR Frames + m_txDMRData2(792U, "Modem TX DMR2"), + m_rxP25Data(6048U, "Modem RX P25"), // 6048 bytes = 28 P25 Frames + m_txP25Data(864U, "Modem TX P25"), // 864 = 4 P25 Frames m_useDFSI(false), m_statusTimer(1000U, 0U, 250U), m_inactivityTimer(1000U, 4U), diff --git a/network/RemoteControl.cpp b/network/RemoteControl.cpp index eaf8cdf2..3baf1df5 100644 --- a/network/RemoteControl.cpp +++ b/network/RemoteControl.cpp @@ -306,7 +306,7 @@ void RemoteControl::process(Host* host, dmr::Control* dmr, p25::Control* p25) else if (rcom == RCD_P25_CC_CMD) { // Command is in the form of: "p25-cc" if (p25 != NULL) { - if (host->m_controlData) { + if (host->m_p25CCData) { g_fireP25Control = true; } else { @@ -321,7 +321,7 @@ void RemoteControl::process(Host* host, dmr::Control* dmr, p25::Control* p25) // Command is in the form of: "p25-cc-fallback 0/1" uint8_t fallback = getArgUInt8(args, 0U); if (p25 != NULL) { - if (host->m_controlData) { + if (host->m_p25CCData) { p25->trunk()->setConvFallback((fallback == 1U) ? true : false); } else { @@ -727,7 +727,7 @@ void RemoteControl::process(Host* host, dmr::Control* dmr, p25::Control* p25) else if (rcom == RCD_P25_CC_DEDICATED_CMD) { // Command is in the form of: "p25-cc-dedicated" if (p25 != NULL) { - if (host->m_controlData) { + if (host->m_p25CCData) { if (dmr != NULL) { LogError(LOG_RCON, CMD_FAILED_STR "Can't enable P25 control channel while DMR is enabled!"); } @@ -735,7 +735,7 @@ void RemoteControl::process(Host* host, dmr::Control* dmr, p25::Control* p25) host->m_p25CtrlChannel = !host->m_p25CtrlChannel; host->m_p25CtrlBroadcast = true; g_fireP25Control = true; - g_interruptP25Control = false; + p25->setCCHalted(false); LogInfoEx(LOG_RCON, "P25 CC is %s", host->m_p25CtrlChannel ? "enabled" : "disabled"); } @@ -751,16 +751,16 @@ void RemoteControl::process(Host* host, dmr::Control* dmr, p25::Control* p25) else if (rcom == RCD_P25_CC_BCAST_CMD) { // Command is in the form of: "p25-cc-bcast" if (p25 != NULL) { - if (host->m_controlData) { + if (host->m_p25CCData) { host->m_p25CtrlBroadcast = !host->m_p25CtrlBroadcast; if (!host->m_p25CtrlBroadcast) { g_fireP25Control = false; - g_interruptP25Control = true; + p25->setCCHalted(true); } else { g_fireP25Control = true; - g_interruptP25Control = false; + p25->setCCHalted(false); } LogInfoEx(LOG_RCON, "P25 CC broadcast is %s", host->m_p25CtrlBroadcast ? "enabled" : "disabled"); diff --git a/p25/Control.cpp b/p25/Control.cpp index eb7b3988..1d6356f0 100644 --- a/p25/Control.cpp +++ b/p25/Control.cpp @@ -59,6 +59,7 @@ const uint32_t MAX_PREAMBLE_TDU_CNT = 64U; // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- + /// /// Initializes a new instance of the Control class. /// @@ -69,7 +70,6 @@ const uint32_t MAX_PREAMBLE_TDU_CNT = 64U; /// Instance of the BaseNetwork class. /// Transmit timeout. /// Amount of time to hang on the last talkgroup mode from RF. -/// Control Channel Broadcast Interval. /// Flag indicating full-duplex operation. /// Instance of the RadioIdLookup class. /// Instance of the TalkgroupIdLookup class. @@ -81,7 +81,7 @@ const uint32_t MAX_PREAMBLE_TDU_CNT = 64U; /// Flag indicating whether P25 debug is enabled. /// Flag indicating whether P25 verbose logging is enabled. Control::Control(uint32_t nac, uint32_t callHang, uint32_t queueSize, modem::Modem* modem, network::BaseNetwork* network, - uint32_t timeout, uint32_t tgHang, uint32_t ccBcstInterval, bool duplex, lookups::RadioIdLookup* ridLookup, + uint32_t timeout, uint32_t tgHang, bool duplex, lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup, lookups::IdenTableLookup* idenTable, lookups::RSSIInterpolator* rssiMapper, bool dumpPDUData, bool repeatPDU, bool dumpTSBKData, bool debug, bool verbose) : m_voice(NULL), @@ -105,19 +105,20 @@ Control::Control(uint32_t nac, uint32_t callHang, uint32_t queueSize, modem::Mod m_ridLookup(ridLookup), m_tidLookup(tidLookup), m_idenEntry(), - m_queue(queueSize, "P25 Control"), + m_queue(queueSize, "P25 Frame"), m_rfState(RS_RF_LISTENING), m_rfLastDstId(0U), m_netState(RS_NET_IDLE), m_netLastDstId(0U), m_tailOnIdle(false), - m_ccOnIdle(false), m_ccRunning(false), - m_ccBcstInterval(ccBcstInterval), + m_ccPrevRunning(false), + m_ccHalted(false), m_rfTimeout(1000U, timeout), m_rfTGHang(1000U, tgHang), m_netTimeout(1000U, timeout), m_networkWatchdog(1000U, 0U, 1500U), + m_ccPacketInterval(1000U, 0U, 5U), m_hangCount(3U * 8U), m_tduPreambleCount(8U), m_ccFrameCnt(0U), @@ -130,6 +131,7 @@ Control::Control(uint32_t nac, uint32_t callHang, uint32_t queueSize, modem::Mod m_minRSSI(0U), m_aveRSSI(0U), m_rssiCount(0U), + m_writeImmediate(false), m_verbose(verbose), m_debug(debug) { @@ -184,6 +186,7 @@ Control::~Control() void Control::reset() { m_rfState = RS_RF_LISTENING; + m_ccHalted = false; if (m_voice != NULL) { m_voice->resetRF(); @@ -293,6 +296,9 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s m_trunk->m_voiceChTable.push_back(*it); } + uint32_t ccBcstInterval = p25Protocol["control"]["interval"].as(300U); + m_trunk->m_adjSiteUpdateInterval += ccBcstInterval; + if (printOptions) { LogInfo(" Silence Threshold: %u (%.1f%%)", m_voice->m_silenceThreshold, float(m_voice->m_silenceThreshold) / 12.33F); @@ -342,15 +348,6 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s } } -/// -/// Sets a flag indicating whether the P25 control channel is running. -/// -/// -void Control::setCCRunning(bool ccRunning) -{ - m_ccRunning = ccRunning; -} - /// /// Process a data frame from the RF interface. /// @@ -388,7 +385,7 @@ bool Control::processFrame(uint8_t* data, uint32_t len) writeRF_TDU(false); m_voice->m_lastDUID = P25_DUID_TDU; - m_voice->writeNetworkRF(data + 2U, P25_DUID_TDU); + m_voice->writeNetwork(data + 2U, P25_DUID_TDU); m_rfState = RS_RF_LISTENING; m_rfLastDstId = 0U; @@ -496,7 +493,7 @@ bool Control::processFrame(uint8_t* data, uint32_t len) // are we interrupting a running CC? if (m_ccRunning) { if (duid != P25_DUID_TSDU) { - g_interruptP25Control = true; + m_ccHalted = true; } } @@ -557,7 +554,6 @@ uint32_t Control::getFrame(uint8_t* data) uint8_t len = 0U; m_queue.getData(&len, 1U); - m_queue.getData(data, len); return len; @@ -572,81 +568,36 @@ void Control::writeAdjSSNetwork() } /// -/// Helper to write control channel frame data. +/// Helper to write end of voice call frame data. /// /// -bool Control::writeControlRF() +bool Control::writeRF_VoiceEnd() { - if (!m_control) { - return false; - } - - const uint8_t maxSeq = 8U; - if (m_ccSeq == maxSeq) { - m_ccSeq = 0U; - } - - if (m_ccFrameCnt == 254U) { - m_trunk->writeAdjSSNetwork(); - m_ccFrameCnt = 0U; - } - if (m_netState == RS_NET_IDLE && m_rfState == RS_RF_LISTENING) { - m_trunk->writeRF_ControlData(m_ccFrameCnt, m_ccSeq, true); - - m_ccSeq++; - if (m_ccSeq == maxSeq) { - m_ccFrameCnt++; - } - - return true; - } - - return false; -} - -/// -/// Helper to write end of control channel frame data. -/// -/// -bool Control::writeControlEndRF() -{ - if (!m_control) { - return false; - } - - if (m_netState == RS_NET_IDLE && m_rfState == RS_RF_LISTENING) { - for (uint32_t i = 0; i < TSBK_PCH_CCH_CNT; i++) { - m_trunk->queueRF_TSBK_Ctrl(TSBK_OSP_MOT_PSH_CCH); - } + if (m_tailOnIdle) { + bool ret = false; + if (m_netState == RS_NET_IDLE && m_rfState == RS_RF_LISTENING) { + m_voice->writeRF_EndOfVoice(); + + // this should have been cleared by writeRF_EndOfVoice; but if it hasn't clear it + // to prevent badness + if (m_voice->m_hadVoice) { + m_voice->m_hadVoice = false; + } - writeRF_Nulls(); - return true; - } + m_tailOnIdle = false; + if (m_network != NULL) + m_network->resetP25(); - return false; -} + ret = true; + } -/// -/// Helper to write end of frame data. -/// -/// -bool Control::writeEndRF() -{ - if (m_netState == RS_NET_IDLE && m_rfState == RS_RF_LISTENING) { - if (m_tailOnIdle) { - bool ret = m_voice->writeEndRF(); if (!m_control && m_duplex) { writeRF_Nulls(); } return ret; } - - if (m_ccOnIdle) { - g_fireP25Control = true; - m_ccOnIdle = false; - } } return false; @@ -669,6 +620,40 @@ void Control::clock(uint32_t ms) } } + // if we have control enabled; do clocking to generate a CC data stream + if (m_control) { + if (m_ccRunning && !m_ccPacketInterval.isRunning()) { + m_ccPacketInterval.start(); + } + + if (m_ccHalted) { + if (!m_ccRunning) { + m_ccHalted = false; + m_ccPrevRunning = m_ccRunning; + } + } + else { + m_ccPacketInterval.clock(ms); + if (!m_ccPacketInterval.isRunning()) { + m_ccPacketInterval.start(); + } + + if (m_ccPacketInterval.isRunning() && m_ccPacketInterval.hasExpired()) { + if (m_ccRunning) { + writeRF_ControlData(); + } + + m_ccPacketInterval.start(); + } + } + + if (m_ccPrevRunning && !m_ccRunning) { + writeRF_ControlEnd(); + m_ccPrevRunning = m_ccRunning; + } + } + + // handle timeouts and hang timers m_rfTimeout.clock(ms); m_netTimeout.clock(ms); @@ -718,6 +703,7 @@ void Control::clock(uint32_t ms) } } + // reset states if we're in a rejected state if (m_rfState == RS_RF_REJECTED) { m_queue.clear(); @@ -735,7 +721,14 @@ void Control::clock(uint32_t ms) m_rfState = RS_RF_LISTENING; } - m_trunk->clock(ms); + // clock data and trunking + if (m_data != NULL) { + m_data->clock(ms); + } + + if (m_trunk != NULL) { + m_trunk->clock(ms); + } } /// @@ -752,63 +745,52 @@ void Control::setDebugVerbose(bool debug, bool verbose) // --------------------------------------------------------------------------- // Private Class Members // --------------------------------------------------------------------------- -/// -/// Write data processed from RF to the data ring buffer. -/// -/// -/// -void Control::writeQueueRF(const uint8_t* data, uint32_t length) -{ - assert(data != NULL); - - if (m_rfTimeout.isRunning() && m_rfTimeout.hasExpired()) - return; - - uint32_t space = m_queue.freeSpace(); - if (space < (length + 1U)) { - uint32_t queueLen = m_queue.length(); - m_queue.resize(queueLen + QUEUE_RESIZE_SIZE); - - LogError(LOG_P25, "overflow in the P25 RF queue; queue resized was %u is %u", queueLen, m_queue.length()); - return; - } - - if (m_debug) { - Utils::symbols("!!! *Tx P25", data + 2U, length - 2U); - } - - uint8_t len = length; - m_queue.addData(&len, 1U); - - m_queue.addData(data, len); -} /// -/// Write data processed from the network to the data ring buffer. +/// Add data frame to the data ring buffer. /// /// /// -void Control::writeQueueNet(const uint8_t* data, uint32_t length) +/// +void Control::addFrame(const uint8_t* data, uint32_t length, bool net) { assert(data != NULL); - if (m_netTimeout.isRunning() && m_netTimeout.hasExpired()) - return; - - uint32_t space = m_queue.freeSpace(); - if (space < (length + 1U)) { - LogError(LOG_P25, "network overflow in the P25 RF queue"); - return; + if (!net) { + if (m_rfTimeout.isRunning() && m_rfTimeout.hasExpired()) + return; + } else { + if (m_netTimeout.isRunning() && m_netTimeout.hasExpired()) + return; } - if (m_debug) { - Utils::symbols("!!! *Tx P25", data + 2U, length - 2U); + if (m_writeImmediate && m_modem->hasP25Space() && m_modem->getState() == modem::STATE_P25) { + m_writeImmediate = false; + m_modem->writeP25Data(data, length, true); } + else { + uint32_t space = m_queue.freeSpace(); + if (space < (length + 1U)) { + if (!net) { + uint32_t queueLen = m_queue.length(); + m_queue.resize(queueLen + P25_LDU_FRAME_LENGTH_BYTES); + LogError(LOG_P25, "overflow in the P25 queue while writing data; queue free is %u, needed %u; resized was %u is %u", space, length, queueLen, m_queue.length()); + return; + } + else { + LogError(LOG_P25, "overflow in the P25 queue while writing network data; queue free is %u, needed %u", space, length); + return; + } + } - uint8_t len = length; - m_queue.addData(&len, 1U); + if (m_debug) { + Utils::symbols("!!! *Tx P25", data + 2U, length - 2U); + } - m_queue.addData(data, len); + uint8_t len = length; + m_queue.addData(&len, 1U); + m_queue.addData(data, len); + } } #if ENABLE_DFSI_SUPPORT @@ -1031,6 +1013,70 @@ void Control::processNetwork() delete data; } +/// +/// Helper to write control channel frame data. +/// +/// +bool Control::writeRF_ControlData() +{ + if (!m_control) + return false; + + if (m_ccFrameCnt == 254U) { + m_trunk->writeAdjSSNetwork(); + m_ccFrameCnt = 0U; + } + + // don't add any frames if the queue is full + uint8_t len = (P25_TSDU_TRIPLE_FRAME_LENGTH_BYTES * 2U) + 2U; + uint32_t space = m_queue.freeSpace(); + if (space < (len + 1U)) { + return false; + } + + const uint8_t maxSeq = 8U; + if (m_ccSeq == maxSeq) { + m_ccSeq = 0U; + } + + if (m_netState == RS_NET_IDLE && m_rfState == RS_RF_LISTENING) { + m_trunk->writeRF_ControlData(m_ccFrameCnt, m_ccSeq, true); + + m_ccSeq++; + if (m_ccSeq == maxSeq) { + m_ccFrameCnt++; + } + + return true; + } + + return false; +} + +/// +/// Helper to write end of control channel frame data. +/// +/// +bool Control::writeRF_ControlEnd() +{ + if (!m_control) + return false; + + m_queue.clear(); + m_ccPacketInterval.stop(); + + if (m_netState == RS_NET_IDLE && m_rfState == RS_RF_LISTENING) { + for (uint32_t i = 0; i < TSBK_PCH_CCH_CNT; i++) { + m_trunk->queueRF_TSBK_Ctrl(TSBK_OSP_MOT_PSH_CCH); + } + + writeRF_Nulls(); + return true; + } + + return false; +} + /// /// Helper to write data nulls. /// @@ -1049,7 +1095,7 @@ void Control::writeRF_Nulls() LogDebug(LOG_P25, "writeRF_Nulls()"); } - writeQueueRF(data, NULLS_LENGTH_BYTES + 2U); + addFrame(data, NULLS_LENGTH_BYTES + 2U); } /// @@ -1110,13 +1156,13 @@ void Control::writeRF_TDU(bool noNetwork) addBusyBits(data + 2U, P25_TDU_FRAME_LENGTH_BITS, true, true); if (!noNetwork) - m_voice->writeNetworkRF(data + 2U, P25_DUID_TDU); + m_voice->writeNetwork(data + 2U, P25_DUID_TDU); if (m_duplex) { data[0U] = modem::TAG_EOT; data[1U] = 0x00U; - writeQueueRF(data, P25_TDU_FRAME_LENGTH_BYTES + 2U); + addFrame(data, P25_TDU_FRAME_LENGTH_BYTES + 2U); } } diff --git a/p25/Control.h b/p25/Control.h index afa71bde..07496fe8 100644 --- a/p25/Control.h +++ b/p25/Control.h @@ -55,6 +55,7 @@ namespace p25 // --------------------------------------------------------------------------- // Class Prototypes // --------------------------------------------------------------------------- + class HOST_SW_API VoicePacket; namespace dfsi { class HOST_SW_API DFSIVoicePacket; } class HOST_SW_API DataPacket; @@ -70,7 +71,7 @@ namespace p25 public: /// Initializes a new instance of the Control class. Control(uint32_t nac, uint32_t callHang, uint32_t queueSize, modem::Modem* modem, network::BaseNetwork* network, - uint32_t timeout, uint32_t tgHang, uint32_t ccBcstInterval, bool duplex, lookups::RadioIdLookup* ridLookup, + uint32_t timeout, uint32_t tgHang, bool duplex, lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup, lookups::IdenTableLookup* idenTable, lookups::RSSIInterpolator* rssiMapper, bool dumpPDUData, bool repeatPDU, bool dumpTSBKData, bool debug, bool verbose); /// Finalizes a instance of the Control class. @@ -83,8 +84,15 @@ namespace p25 void 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); + + /// Gets a flag indicating whether the P25 control channel is running. + bool getCCRunning() { return m_ccRunning; } /// Sets a flag indicating whether the P25 control channel is running. - void setCCRunning(bool ccRunning); + void setCCRunning(bool ccRunning) { m_ccPrevRunning = m_ccRunning; m_ccRunning = ccRunning; } + /// Gets a flag indicating whether the P25 control channel is running. + bool getCCHalted() { return m_ccHalted; } + /// Sets a flag indicating whether the P25 control channel is halted. + void setCCHalted(bool ccHalted) { m_ccHalted = ccHalted; } /// Process a data frame from the RF interface. bool processFrame(uint8_t* data, uint32_t len); @@ -94,12 +102,8 @@ namespace p25 /// Helper to write P25 adjacent site information to the network. void writeAdjSSNetwork(); - /// Helper to write control channel frame data. - bool writeControlRF(); - /// Helper to write end of control channel frame data. - bool writeControlEndRF(); - /// Helper to write end of frame data. - bool writeEndRF(); + /// Helper to write end of voice call frame data. + bool writeRF_VoiceEnd(); /// Updates the processor by the passed number of milliseconds. void clock(uint32_t ms); @@ -154,15 +158,17 @@ namespace p25 uint32_t m_netLastDstId; bool m_tailOnIdle; - bool m_ccOnIdle; bool m_ccRunning; - uint32_t m_ccBcstInterval; + bool m_ccPrevRunning; + bool m_ccHalted; Timer m_rfTimeout; Timer m_rfTGHang; Timer m_netTimeout; Timer m_networkWatchdog; + Timer m_ccPacketInterval; + uint32_t m_hangCount; uint32_t m_tduPreambleCount; @@ -180,13 +186,13 @@ namespace p25 uint32_t m_aveRSSI; uint32_t m_rssiCount; + bool m_writeImmediate; // This is essentially a "latch" that will auto-reset after a writeRF_Queue() call. + bool m_verbose; bool m_debug; - /// Write data processed from RF to the data ring buffer. - void writeQueueRF(const uint8_t* data, uint32_t length); - /// Write data processed from the network to the data ring buffer. - void writeQueueNet(const uint8_t* data, uint32_t length); + /// Add data frame to the data ring buffer. + void addFrame(const uint8_t* data, uint32_t length, bool net = false); #if ENABLE_DFSI_SUPPORT /// Process a DFSI data frame from the RF interface. @@ -196,6 +202,11 @@ namespace p25 /// Process a data frames from the network. void processNetwork(); + /// Helper to write control channel frame data. + bool writeRF_ControlData(); + /// Helper to write end of control channel frame data. + bool writeRF_ControlEnd(); + /// Helper to write data nulls. void writeRF_Nulls(); /// Helper to write TDU preamble packet burst. diff --git a/p25/DataPacket.cpp b/p25/DataPacket.cpp index 57bb4acc..0f3ca9eb 100644 --- a/p25/DataPacket.cpp +++ b/p25/DataPacket.cpp @@ -47,9 +47,16 @@ using namespace p25::data; #include #include +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +const uint32_t CONN_WAIT_TIMEOUT = 1U; + // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- + /// /// Resets the data states for the RF interface. /// @@ -86,7 +93,7 @@ bool DataPacket::process(uint8_t* data, uint32_t len) // are we interrupting a running CC? if (m_p25->m_ccRunning) { - g_interruptP25Control = true; + m_p25->m_ccHalted = true; } // handle individual DUIDs @@ -227,7 +234,7 @@ bool DataPacket::process(uint8_t* data, uint32_t len) } } - writeNetworkRF(m_rfDataBlockCnt, m_pduUserData + dataOffset, (m_rfDataHeader.getFormat() == PDU_FMT_CONFIRMED) ? P25_PDU_CONFIRMED_DATA_LENGTH_BYTES : P25_PDU_UNCONFIRMED_LENGTH_BYTES); + writeNetwork(m_rfDataBlockCnt, m_pduUserData + dataOffset, (m_rfDataHeader.getFormat() == PDU_FMT_CONFIRMED) ? P25_PDU_CONFIRMED_DATA_LENGTH_BYTES : P25_PDU_UNCONFIRMED_LENGTH_BYTES); m_rfDataBlockCnt++; } else { @@ -273,34 +280,30 @@ bool DataPacket::process(uint8_t* data, uint32_t len) ulong64_t ipAddr = (m_pduUserData[8U] << 24) + (m_pduUserData[9U] << 16) + (m_pduUserData[10U] << 8) + m_pduUserData[11U]; + if (m_rfDataHeader.getAckNeeded()) { + m_p25->m_writeImmediate = true; + writeRF_PDU_Ack_Response(PDU_ACK_CLASS_ACK, PDU_ACK_TYPE_ACK, llId); + } + if (m_verbose) { LogMessage(LOG_RF, P25_PDU_STR ", PDU_REG_TYPE_REQ_CNCT (Registration Request Connect), llId = %u, ipAddr = %s", llId, __IP_FROM_ULONG(ipAddr).c_str()); } - writeRF_PDU_Ack_Response(PDU_ACK_CLASS_ACK, PDU_ACK_TYPE_ACK, llId); + m_connQueueTable[llId] = ipAddr; - if (!acl::AccessControl::validateSrcId(llId)) { - LogWarning(LOG_RF, P25_PDU_STR ", PDU_REG_TYPE_RSP_DENY (Registration Response Deny), llId = %u, ipAddr = %s", llId, __IP_FROM_ULONG(ipAddr).c_str()); - writeRF_PDU_Reg_Response(PDU_REG_TYPE_RSP_DENY, llId, ipAddr); - } - else { - if (!hasLLIdFNEReg(llId)) { - // update dynamic FNE registration table entry - m_fneRegTable[llId] = ipAddr; - } - - if (m_verbose) { - LogMessage(LOG_RF, P25_PDU_STR ", PDU_REG_TYPE_RSP_ACCPT (Registration Response Accept), llId = %u, ipAddr = %s", llId, __IP_FROM_ULONG(ipAddr).c_str()); - } - - writeRF_PDU_Reg_Response(PDU_REG_TYPE_RSP_ACCPT, llId, ipAddr); - } + m_connTimerTable[llId] = Timer(1000U, CONN_WAIT_TIMEOUT); + m_connTimerTable[llId].start(); } break; case PDU_REG_TYPE_REQ_DISCNCT: { uint32_t llId = (m_pduUserData[1U] << 16) + (m_pduUserData[2U] << 8) + m_pduUserData[3U]; + if (m_rfDataHeader.getAckNeeded()) { + m_p25->m_writeImmediate = true; + writeRF_PDU_Ack_Response(PDU_ACK_CLASS_ACK, PDU_ACK_TYPE_ACK, llId); + } + if (m_verbose) { LogMessage(LOG_RF, P25_PDU_STR ", PDU_REG_TYPE_REQ_DISCNCT (Registration Request Disconnect), llId = %u", llId); } @@ -502,9 +505,54 @@ bool DataPacket::hasLLIdFNEReg(uint32_t llId) const } } +/// +/// Updates the processor by the passed number of milliseconds. +/// +/// +void DataPacket::clock(uint32_t ms) +{ + // clock all the connect timers + std::vector connToClear = std::vector(); + for (auto it = m_connQueueTable.begin(); it != m_connQueueTable.end(); ++it) { + uint32_t llId = it->first; + + m_connTimerTable[llId].clock(ms); + if (m_connTimerTable[llId].isRunning() && m_connTimerTable[llId].hasExpired()) { + connToClear.push_back(llId); + } + } + + // handle PDU connection registration + for (auto it = connToClear.begin(); it != connToClear.end(); ++it) { + uint32_t llId = *it; + uint64_t ipAddr = m_connQueueTable[llId]; + + m_p25->m_writeImmediate = true; + if (!acl::AccessControl::validateSrcId(llId)) { + LogWarning(LOG_RF, P25_PDU_STR ", PDU_REG_TYPE_RSP_DENY (Registration Response Deny), llId = %u, ipAddr = %s", llId, __IP_FROM_ULONG(ipAddr).c_str()); + writeRF_PDU_Reg_Response(PDU_REG_TYPE_RSP_DENY, llId, ipAddr); + } + else { + if (!hasLLIdFNEReg(llId)) { + // update dynamic FNE registration table entry + m_fneRegTable[llId] = ipAddr; + } + + if (m_verbose) { + LogMessage(LOG_RF, P25_PDU_STR ", PDU_REG_TYPE_RSP_ACCPT (Registration Response Accept), llId = %u, ipAddr = %s", llId, __IP_FROM_ULONG(ipAddr).c_str()); + } + + writeRF_PDU_Reg_Response(PDU_REG_TYPE_RSP_ACCPT, llId, ipAddr); + } + + m_connQueueTable.erase(llId); + } +} + // --------------------------------------------------------------------------- // Private Class Members // --------------------------------------------------------------------------- + /// /// Initializes a new instance of the DataPacket class. /// @@ -537,6 +585,8 @@ DataPacket::DataPacket(Control* p25, network::BaseNetwork* network, bool dumpPDU m_pduUserData(NULL), m_pduUserDataLength(0U), m_fneRegTable(), + m_connQueueTable(), + m_connTimerTable(), m_dumpPDUData(dumpPDUData), m_repeatPDU(repeatPDU), m_verbose(verbose), @@ -556,6 +606,8 @@ DataPacket::DataPacket(Control* p25, network::BaseNetwork* network, bool dumpPDU ::memset(m_pduUserData, 0x00U, P25_MAX_PDU_COUNT * P25_PDU_CONFIRMED_LENGTH_BYTES + 2U); m_fneRegTable.clear(); + m_connQueueTable.clear(); + m_connTimerTable.clear(); } /// @@ -574,7 +626,7 @@ DataPacket::~DataPacket() /// /// /// -void DataPacket::writeNetworkRF(const uint8_t currentBlock, const uint8_t *data, uint32_t len) +void DataPacket::writeNetwork(const uint8_t currentBlock, const uint8_t *data, uint32_t len) { assert(data != NULL); @@ -624,7 +676,8 @@ void DataPacket::writeRF_PDU(const uint8_t* pdu, uint32_t bitLength, bool noNull if (m_p25->m_duplex) { data[0U] = modem::TAG_DATA; data[1U] = 0x00U; - m_p25->writeQueueRF(data, newByteLength + 2U); + + m_p25->addFrame(data, newByteLength + 2U); } // add trailing null pad; only if control data isn't being transmitted @@ -805,7 +858,8 @@ void DataPacket::writeRF_PDU_Reg_Response(uint8_t regType, uint32_t llId, ulong6 /// /// /// -void DataPacket::writeRF_PDU_Ack_Response(uint8_t ackClass, uint8_t ackType, uint32_t llId) +/// +void DataPacket::writeRF_PDU_Ack_Response(uint8_t ackClass, uint8_t ackType, uint32_t llId, bool noNulls) { if (ackClass == PDU_ACK_CLASS_ACK && ackType != PDU_ACK_TYPE_ACK) return; @@ -839,6 +893,6 @@ void DataPacket::writeRF_PDU_Ack_Response(uint8_t ackClass, uint8_t ackType, uin rspHeader.encode(block); Utils::setBitRange(block, data, offset, P25_PDU_FEC_LENGTH_BITS); - writeRF_PDU(data, bitLength, true); + writeRF_PDU(data, bitLength, noNulls); delete[] data; } diff --git a/p25/DataPacket.h b/p25/DataPacket.h index 8a77c34e..b321f8a8 100644 --- a/p25/DataPacket.h +++ b/p25/DataPacket.h @@ -38,6 +38,7 @@ #include "p25/lc/LC.h" #include "p25/Control.h" #include "network/BaseNetwork.h" +#include "Timer.h" #include #include @@ -48,6 +49,7 @@ namespace p25 // --------------------------------------------------------------------------- // Class Prototypes // --------------------------------------------------------------------------- + class HOST_SW_API Control; // --------------------------------------------------------------------------- @@ -68,6 +70,9 @@ namespace p25 /// Helper to check if a logical link ID has registered with data services. bool hasLLIdFNEReg(uint32_t llId) const; + /// Updates the processor by the passed number of milliseconds. + void clock(uint32_t ms); + private: friend class Control; Control* m_p25; @@ -99,6 +104,9 @@ namespace p25 std::unordered_map m_fneRegTable; + std::unordered_map m_connQueueTable; + std::unordered_map m_connTimerTable; + bool m_dumpPDUData; bool m_repeatPDU; @@ -111,7 +119,7 @@ namespace p25 ~DataPacket(); /// Write data processed from RF to the network. - void writeNetworkRF(const uint8_t currentBlock, const uint8_t* data, uint32_t len); + void writeNetwork(const uint8_t currentBlock, const uint8_t* data, uint32_t len); /// Helper to write a P25 PDU packet. void writeRF_PDU(const uint8_t* pdu, uint32_t bitLength, bool noNulls = false); @@ -122,7 +130,7 @@ namespace p25 /// Helper to write a PDU registration response. void writeRF_PDU_Reg_Response(uint8_t regType, uint32_t llId, ulong64_t ipAddr); /// Helper to write a PDU acknowledge response. - void writeRF_PDU_Ack_Response(uint8_t ackClass, uint8_t ackType, uint32_t llId); + void writeRF_PDU_Ack_Response(uint8_t ackClass, uint8_t ackType, uint32_t llId, bool noNulls = false); }; } // namespace p25 diff --git a/p25/TrunkPacket.cpp b/p25/TrunkPacket.cpp index f54fa0bf..5e686426 100644 --- a/p25/TrunkPacket.cpp +++ b/p25/TrunkPacket.cpp @@ -44,6 +44,7 @@ using namespace p25::data; // --------------------------------------------------------------------------- // Macros // --------------------------------------------------------------------------- + // Make sure control data is supported. #define IS_SUPPORT_CONTROL_CHECK(_PCKT_STR, _PCKT, _SRCID) \ if (!m_p25->m_control) { \ @@ -136,6 +137,7 @@ const uint8_t CONV_FALLBACK_PACKET_DELAY = 8U; // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- + /// /// Resets the data states for the RF interface. /// @@ -1290,6 +1292,7 @@ void TrunkPacket::setTSBKVerbose(bool verbose) // --------------------------------------------------------------------------- // Protected Class Members // --------------------------------------------------------------------------- + /// /// Initializes a new instance of the TrunkPacket class. /// @@ -1353,7 +1356,7 @@ TrunkPacket::TrunkPacket(Control* p25, network::BaseNetwork* network, bool dumpT m_grantChTable.clear(); m_grantTimers.clear(); - m_adjSiteUpdateInterval = ADJ_SITE_TIMER_TIMEOUT + m_p25->m_ccBcstInterval; + m_adjSiteUpdateInterval = ADJ_SITE_TIMER_TIMEOUT; m_adjSiteUpdateTimer.setTimeout(m_adjSiteUpdateInterval); m_adjSiteUpdateTimer.start(); } @@ -1548,7 +1551,7 @@ void TrunkPacket::writeRF_TDULC(lc::TDULC lc, bool noNetwork) data[0U] = modem::TAG_EOT; data[1U] = 0x00U; - m_p25->writeQueueRF(data, P25_TDULC_FRAME_LENGTH_BYTES + 2U); + m_p25->addFrame(data, P25_TDULC_FRAME_LENGTH_BYTES + 2U); } //if (m_verbose) { @@ -1669,7 +1672,7 @@ void TrunkPacket::writeRF_TSDU_SBF(bool noNetwork, bool clearBeforeWrite, bool f data[0U] = modem::TAG_DATA; data[1U] = 0x00U; - m_p25->writeQueueRF(data, P25_TSDU_FRAME_LENGTH_BYTES + 2U); + m_p25->addFrame(data, P25_TSDU_FRAME_LENGTH_BYTES + 2U); } } @@ -1768,7 +1771,7 @@ void TrunkPacket::writeRF_TSDU_MBF(bool clearBeforeWrite) m_p25->m_queue.clear(); } - m_p25->writeQueueRF(data, P25_TSDU_TRIPLE_FRAME_LENGTH_BYTES + 2U); + m_p25->addFrame(data, P25_TSDU_TRIPLE_FRAME_LENGTH_BYTES + 2U); ::memset(m_rfMBF, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U); m_mbfCnt = 0U; @@ -2161,6 +2164,7 @@ bool TrunkPacket::writeRF_TSDU_Grant(bool grp, bool skip, bool net, bool skipNet // transmit group grant m_rfTSBK.setLCO(TSBK_IOSP_GRP_VCH); + m_p25->m_writeImmediate = true; writeRF_TSDU_SBF(false, true, net); } else { @@ -2175,6 +2179,7 @@ bool TrunkPacket::writeRF_TSDU_Grant(bool grp, bool skip, bool net, bool skipNet // transmit private grant m_rfTSBK.setLCO(TSBK_IOSP_UU_VCH); + m_p25->m_writeImmediate = true; writeRF_TSDU_SBF(false, true, net); } @@ -2652,7 +2657,7 @@ void TrunkPacket::writeNet_TDULC(lc::TDULC lc) // Add busy bits m_p25->addBusyBits(buffer + 2U, P25_TDULC_FRAME_LENGTH_BITS, true, true); - m_p25->writeQueueNet(buffer, P25_TDULC_FRAME_LENGTH_BYTES + 2U); + m_p25->addFrame(buffer, P25_TDULC_FRAME_LENGTH_BYTES + 2U, true); if (m_verbose) { LogMessage(LOG_NET, P25_TDULC_STR ", lc = $%02X, srcId = %u", lc.getLCO(), lc.getSrcId()); @@ -2702,7 +2707,7 @@ void TrunkPacket::writeNet_TSDU() // Set first busy bits to 1,1 m_p25->setBusyBits(buffer + 2U, P25_SS0_START, true, true); - m_p25->writeQueueNet(buffer, P25_TSDU_FRAME_LENGTH_BYTES + 2U); + m_p25->addFrame(buffer, P25_TSDU_FRAME_LENGTH_BYTES + 2U, true); if (m_network != NULL) m_network->resetP25(); diff --git a/p25/VoicePacket.cpp b/p25/VoicePacket.cpp index 39cb78e8..74162536 100644 --- a/p25/VoicePacket.cpp +++ b/p25/VoicePacket.cpp @@ -56,6 +56,7 @@ const uint32_t VOC_LDU1_COUNT = 3U; // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- + /// /// Resets the data states for the RF interface. /// @@ -123,7 +124,7 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) // are we interrupting a running CC? if (m_p25->m_ccRunning) { - g_interruptP25Control = true; + m_p25->m_ccHalted = true; } if (m_p25->m_rfState != RS_RF_LISTENING) { @@ -138,8 +139,10 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) if (duid == P25_DUID_HDU) { m_lastDUID = P25_DUID_HDU; - if (m_p25->m_rfState == RS_RF_LISTENING && m_p25->m_ccRunning) { - m_p25->m_modem->clearP25Data(); + if (m_p25->m_rfState == RS_RF_LISTENING) { + if (!m_p25->m_dedicatedControl) { + m_p25->m_modem->clearP25Data(); + } m_p25->m_queue.clear(); resetRF(); resetNet(); @@ -196,6 +199,16 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) m_lastDUID = P25_DUID_LDU1; if (m_p25->m_rfState == RS_RF_LISTENING) { + // if this is a late entry call, clear states + if (m_rfLastHDU.getDstId() == 0U) { + if (!m_p25->m_dedicatedControl) { + m_p25->m_modem->clearP25Data(); + } + m_p25->m_queue.clear(); + resetRF(); + resetNet(); + } + if (m_p25->m_control) { if (!m_p25->m_ccRunning && m_p25->m_voiceOnControl) { m_p25->m_trunk->writeRF_ControlData(255U, 0U, false); @@ -350,7 +363,6 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) // single-channel trunking or voice on control support? if (m_p25->m_control && m_p25->m_voiceOnControl) { - m_p25->m_ccRunning = false; // otherwise the grant will be bundled with other packets m_p25->m_trunk->writeRF_TSDU_Grant(group, true); } @@ -390,12 +402,13 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) // Add busy bits m_p25->addBusyBits(buffer + 2U, P25_HDU_FRAME_LENGTH_BITS, false, true); - writeNetworkRF(buffer, P25_DUID_HDU); + writeNetwork(buffer, P25_DUID_HDU); if (m_p25->m_duplex) { buffer[0U] = modem::TAG_DATA; buffer[1U] = 0x00U; - m_p25->writeQueueRF(buffer, P25_HDU_FRAME_LENGTH_BYTES + 2U); + + m_p25->addFrame(buffer, P25_HDU_FRAME_LENGTH_BYTES + 2U); } if (m_verbose) { @@ -515,12 +528,13 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) // Add busy bits m_p25->addBusyBits(data + 2U, P25_LDU_FRAME_LENGTH_BITS, false, true); - writeNetworkRF(data + 2U, P25_DUID_LDU1); + writeNetwork(data + 2U, P25_DUID_LDU1); if (m_p25->m_duplex) { data[0U] = modem::TAG_DATA; data[1U] = 0x00U; - m_p25->writeQueueRF(data, P25_LDU_FRAME_LENGTH_BYTES + 2U); + + m_p25->addFrame(data, P25_LDU_FRAME_LENGTH_BYTES + 2U); } if (m_verbose) { @@ -593,12 +607,13 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) // Add busy bits m_p25->addBusyBits(data + 2U, P25_LDU_FRAME_LENGTH_BITS, false, true); - writeNetworkRF(data + 2U, P25_DUID_LDU2); + writeNetwork(data + 2U, P25_DUID_LDU2); if (m_p25->m_duplex) { data[0U] = modem::TAG_DATA; data[1U] = 0x00U; - m_p25->writeQueueRF(data, P25_LDU_FRAME_LENGTH_BYTES + 2U); + + m_p25->addFrame(data, P25_LDU_FRAME_LENGTH_BYTES + 2U); } if (m_verbose) { @@ -729,12 +744,7 @@ bool VoicePacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d if (m_p25->m_netState == RS_NET_IDLE) { // are we interrupting a running CC? if (m_p25->m_ccRunning) { - g_interruptP25Control = true; - } - - // single-channel trunking or voice on control support? - if (m_p25->m_control && m_p25->m_voiceOnControl) { - m_p25->m_ccRunning = false; // otherwise the grant will be bundled with other packets + m_p25->m_ccHalted = true; } } @@ -833,40 +843,10 @@ bool VoicePacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d return true; } -/// -/// Helper to write end of frame data. -/// -/// -bool VoicePacket::writeEndRF() -{ - if (m_p25->m_netState == RS_NET_IDLE && m_p25->m_rfState == RS_RF_LISTENING) { - writeRF_EndOfVoice(); - - // this should have been cleared by writeRF_EndOfVoice; but if it hasn't clear it - // to prevent badness - if (m_hadVoice) { - m_hadVoice = false; - } - - if (m_p25->m_control && !m_p25->m_ccRunning) { - m_p25->m_trunk->writeRF_ControlData(255U, 0U, false); - m_p25->writeControlEndRF(); - } - - m_p25->m_tailOnIdle = false; - - if (m_network != NULL) - m_network->resetP25(); - - return true; - } - - return false; -} - // --------------------------------------------------------------------------- // Protected Class Members // --------------------------------------------------------------------------- + /// /// Initializes a new instance of the VoicePacket class. /// @@ -929,7 +909,7 @@ VoicePacket::~VoicePacket() /// /// /// -void VoicePacket::writeNetworkRF(const uint8_t *data, uint8_t duid) +void VoicePacket::writeNetwork(const uint8_t *data, uint8_t duid) { assert(data != NULL); @@ -1004,7 +984,7 @@ void VoicePacket::writeNet_TDU() // Add busy bits m_p25->addBusyBits(buffer + 2U, P25_TDU_FRAME_LENGTH_BITS, true, true); - m_p25->writeQueueNet(buffer, P25_TDU_FRAME_LENGTH_BYTES + 2U); + m_p25->addFrame(buffer, P25_TDU_FRAME_LENGTH_BYTES + 2U, true); if (m_verbose) { LogMessage(LOG_NET, P25_TDU_STR ", srcId = %u", m_netLC.getSrcId()); @@ -1188,7 +1168,6 @@ void VoicePacket::writeNet_LDU1() // single-channel trunking or voice on control support? if (m_p25->m_control && m_p25->m_voiceOnControl) { - m_p25->m_ccRunning = false; // otherwise the grant will be bundled with other packets if (!m_p25->m_trunk->writeRF_TSDU_Grant(group, false, true)) { if (m_network != NULL) m_network->resetP25(); @@ -1241,7 +1220,8 @@ void VoicePacket::writeNet_LDU1() buffer[0U] = modem::TAG_DATA; buffer[1U] = 0x00U; - m_p25->writeQueueNet(buffer, P25_HDU_FRAME_LENGTH_BYTES + 2U); + + m_p25->addFrame(buffer, P25_HDU_FRAME_LENGTH_BYTES + 2U, true); if (m_verbose) { LogMessage(LOG_NET, P25_HDU_STR ", dstId = %u, algo = $%02X, kid = $%04X", m_netLC.getDstId(), m_netLC.getAlgId(), m_netLC.getKId()); @@ -1299,7 +1279,8 @@ void VoicePacket::writeNet_LDU1() buffer[0U] = modem::TAG_DATA; buffer[1U] = 0x00U; - m_p25->writeQueueNet(buffer, P25_LDU_FRAME_LENGTH_BYTES + 2U); + + m_p25->addFrame(buffer, P25_LDU_FRAME_LENGTH_BYTES + 2U, true); if (m_verbose) { uint32_t loss = 0; @@ -1403,7 +1384,8 @@ void VoicePacket::writeNet_LDU2() buffer[0U] = modem::TAG_DATA; buffer[1U] = 0x00U; - m_p25->writeQueueNet(buffer, P25_LDU_FRAME_LENGTH_BYTES + 2U); + + m_p25->addFrame(buffer, P25_LDU_FRAME_LENGTH_BYTES + 2U, true); if (m_verbose) { uint32_t loss = 0; diff --git a/p25/VoicePacket.h b/p25/VoicePacket.h index 86dc584c..f2974768 100644 --- a/p25/VoicePacket.h +++ b/p25/VoicePacket.h @@ -68,9 +68,6 @@ namespace p25 /// Process a data frame from the network. virtual bool processNetwork(uint8_t* data, uint32_t len, lc::LC& control, data::LowSpeedData& lsd, uint8_t& duid); - /// Helper to write end of frame data. - bool writeEndRF(); - protected: friend class TrunkPacket; friend class Control; @@ -121,7 +118,7 @@ namespace p25 virtual ~VoicePacket(); /// Write data processed from RF to the network. - void writeNetworkRF(const uint8_t* data, uint8_t duid); + void writeNetwork(const uint8_t* data, uint8_t duid); /// Helper to write end of voice frame data. void writeRF_EndOfVoice(); diff --git a/p25/dfsi/DFSITrunkPacket.cpp b/p25/dfsi/DFSITrunkPacket.cpp index 9a7c9935..301ad89d 100644 --- a/p25/dfsi/DFSITrunkPacket.cpp +++ b/p25/dfsi/DFSITrunkPacket.cpp @@ -38,6 +38,7 @@ using namespace p25::dfsi; // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- + /// /// Resets the data states for the RF interface. /// @@ -94,6 +95,7 @@ bool DFSITrunkPacket::process(uint8_t* data, uint32_t len, bool preDecoded) // --------------------------------------------------------------------------- // Protected Class Members // --------------------------------------------------------------------------- + /// /// Initializes a new instance of the DFSITrunkPacket class. /// @@ -189,7 +191,7 @@ void DFSITrunkPacket::writeRF_TSDU_SBF(bool noNetwork, bool clearBeforeWrite, bo data[0U] = modem::TAG_DATA; data[1U] = 0x00U; - m_p25->writeQueueRF(data, P25_DFSI_TSBK_FRAME_LENGTH_BYTES + 2U); + m_p25->addFrame(data, P25_DFSI_TSBK_FRAME_LENGTH_BYTES + 2U); writeRF_DSFI_Stop(P25_DFSI_TYPE_TSBK); } @@ -209,7 +211,7 @@ void DFSITrunkPacket::writeNet_TSDU() m_netDFSILC.tsbk(m_netTSBK); m_netDFSILC.encodeTSBK(buffer + 2U); - m_p25->writeQueueNet(buffer, P25_DFSI_TSBK_FRAME_LENGTH_BYTES + 2U); + m_p25->addFrame(buffer, P25_DFSI_TSBK_FRAME_LENGTH_BYTES + 2U, true); if (m_network != NULL) m_network->resetP25(); @@ -235,7 +237,7 @@ void DFSITrunkPacket::writeRF_DFSI_Start(uint8_t type) buffer[0U] = modem::TAG_DATA; buffer[1U] = 0x00U; - m_p25->writeQueueRF(buffer, P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U); + m_p25->addFrame(buffer, P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U); } /// @@ -260,6 +262,6 @@ void DFSITrunkPacket::writeRF_DSFI_Stop(uint8_t type) // for whatever reason this is almost always sent twice for (uint8_t i = 0; i < 2;i ++) { - m_p25->writeQueueRF(buffer, P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U); + m_p25->addFrame(buffer, P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U); } } diff --git a/p25/dfsi/DFSIVoicePacket.cpp b/p25/dfsi/DFSIVoicePacket.cpp index 0b8322f7..2ad913d7 100644 --- a/p25/dfsi/DFSIVoicePacket.cpp +++ b/p25/dfsi/DFSIVoicePacket.cpp @@ -50,6 +50,7 @@ const uint32_t VOC_LDU1_COUNT = 3U; // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- + /// /// Resets the data states for the RF interface. /// @@ -90,7 +91,7 @@ bool DFSIVoicePacket::process(uint8_t* data, uint32_t len) uint8_t frameType = m_rfDFSILC.getFrameType(); if (frameType == P25_DFSI_VHDR2) { if (m_p25->m_rfState == RS_RF_LISTENING && m_p25->m_ccRunning) { - m_p25->m_modem->clearP25Data(); + //m_p25->m_modem->clearP25Data(); m_p25->m_queue.clear(); resetRF(); resetNet(); @@ -333,7 +334,6 @@ bool DFSIVoicePacket::process(uint8_t* data, uint32_t len) // single-channel trunking or voice on control support? if (m_p25->m_control && m_p25->m_voiceOnControl) { - m_p25->m_ccRunning = false; // otherwise the grant will be bundled with other packets m_p25->m_trunk->writeRF_TSDU_Grant(group, true); } @@ -373,7 +373,7 @@ bool DFSIVoicePacket::process(uint8_t* data, uint32_t len) // Add busy bits m_p25->addBusyBits(buffer + 2U, P25_HDU_FRAME_LENGTH_BITS, false, true); - writeNetworkRF(buffer, P25_DUID_HDU); + writeNetwork(buffer, P25_DUID_HDU); if (m_verbose) { LogMessage(LOG_RF, P25_HDU_STR " DFSI, dstId = %u, algo = $%02X, kid = $%04X", m_rfLC.getDstId(), m_rfLC.getAlgId(), m_rfLC.getKId()); @@ -448,7 +448,7 @@ bool DFSIVoicePacket::process(uint8_t* data, uint32_t len) // Add busy bits m_p25->addBusyBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, false, true); - writeNetworkRF(buffer + 2U, P25_DUID_LDU1); + writeNetwork(buffer + 2U, P25_DUID_LDU1); if (m_verbose) { LogMessage(LOG_RF, P25_LDU1_STR " DFSI, audio, srcId = %u, dstId = %u, group = %u, emerg = %u, encrypt = %u, prio = %u", @@ -540,7 +540,7 @@ bool DFSIVoicePacket::process(uint8_t* data, uint32_t len) // Add busy bits m_p25->addBusyBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, false, true); - writeNetworkRF(buffer + 2U, P25_DUID_LDU2); + writeNetwork(buffer + 2U, P25_DUID_LDU2); if (m_verbose) { LogMessage(LOG_RF, P25_LDU2_STR " DFSI, audio, algo = $%02X, kid = $%04X", @@ -571,7 +571,7 @@ bool DFSIVoicePacket::process(uint8_t* data, uint32_t len) // Add busy bits m_p25->addBusyBits(data + 2U, P25_TDU_FRAME_LENGTH_BITS, true, true); - writeNetworkRF(data + 2U, P25_DUID_TDU); + writeNetwork(data + 2U, P25_DUID_TDU); m_lastDUID = P25_DUID_TDU; @@ -675,12 +675,7 @@ bool DFSIVoicePacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& contro if (m_p25->m_netState == RS_NET_IDLE) { // are we interrupting a running CC? if (m_p25->m_ccRunning) { - g_interruptP25Control = true; - } - - // single-channel trunking or voice on control support? - if (m_p25->m_control && m_p25->m_voiceOnControl) { - m_p25->m_ccRunning = false; // otherwise the grant will be bundled with other packets + m_p25->m_ccHalted = true; } } @@ -782,6 +777,7 @@ bool DFSIVoicePacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& contro // --------------------------------------------------------------------------- // Protected Class Members // --------------------------------------------------------------------------- + /// /// Initializes a new instance of the DFSIVoicePacket class. /// @@ -990,7 +986,6 @@ void DFSIVoicePacket::writeNet_LDU1() // single-channel trunking or voice on control support? if (m_p25->m_control && m_p25->m_voiceOnControl) { - m_p25->m_ccRunning = false; // otherwise the grant will be bundled with other packets if (!m_p25->m_trunk->writeRF_TSDU_Grant(group, false, true)) { if (m_network != NULL) m_network->resetP25(); @@ -1039,7 +1034,7 @@ void DFSIVoicePacket::writeNet_LDU1() buffer[0U] = modem::TAG_DATA; buffer[1U] = 0x00U; - m_p25->writeQueueNet(buffer, P25_DFSI_VHDR1_FRAME_LENGTH_BYTES + 2U); + m_p25->addFrame(buffer, P25_DFSI_VHDR1_FRAME_LENGTH_BYTES + 2U, true); // Generate Voice Header 2 m_netDFSILC.setFrameType(P25_DFSI_VHDR2); @@ -1047,7 +1042,7 @@ void DFSIVoicePacket::writeNet_LDU1() buffer[0U] = modem::TAG_DATA; buffer[1U] = 0x00U; - m_p25->writeQueueNet(buffer, P25_DFSI_VHDR2_FRAME_LENGTH_BYTES + 2U); + m_p25->addFrame(buffer, P25_DFSI_VHDR2_FRAME_LENGTH_BYTES + 2U, true); if (m_verbose) { LogMessage(LOG_NET, P25_HDU_STR " DFSI, dstId = %u, algo = $%02X, kid = $%04X", m_netLC.getDstId(), m_netLC.getAlgId(), m_netLC.getKId()); @@ -1124,7 +1119,8 @@ void DFSIVoicePacket::writeNet_LDU1() buffer[0U] = modem::TAG_DATA; buffer[1U] = 0x00U; - m_p25->writeQueueNet(buffer, len + 2U); + + m_p25->addFrame(buffer, len + 2U, true); } if (m_verbose) { @@ -1239,7 +1235,8 @@ void DFSIVoicePacket::writeNet_LDU2() buffer[0U] = modem::TAG_DATA; buffer[1U] = 0x00U; - m_p25->writeQueueNet(buffer, len + 2U); + + m_p25->addFrame(buffer, len + 2U, true); } if (m_verbose) {