diff --git a/p25/dfsi/DFSIDefines.h b/p25/dfsi/DFSIDefines.h
index baaf0d41..ce799b28 100644
--- a/p25/dfsi/DFSIDefines.h
+++ b/p25/dfsi/DFSIDefines.h
@@ -79,9 +79,11 @@ namespace p25
const uint8_t P25_DFSI_RT_DISABLED = 0x04U; //
const uint8_t P25_DFSI_START_FLAG = 0x0CU; //
- const uint8_t P25_DFSI_STOP_FLAG = 0x00U; //
+ const uint8_t P25_DFSI_STOP_FLAG = 0x25U; //
+ const uint8_t P25_DFSI_TYPE_DATA_PAYLOAD = 0x06U; //
const uint8_t P25_DFSI_TYPE_VOICE = 0x0BU; //
+ const uint8_t P25_DFSI_TYPE_DATA = 0x0CU; //
const uint8_t P25_DFSI_TYPE_TSBK = 0x0FU; //
const uint8_t P25_DFSI_DEF_ICW_SOURCE = 0x00U; // Infrastructure Source - Default Source
diff --git a/p25/dfsi/DFSITrunkPacket.cpp b/p25/dfsi/DFSITrunkPacket.cpp
index ccaafb31..9a7c9935 100644
--- a/p25/dfsi/DFSITrunkPacket.cpp
+++ b/p25/dfsi/DFSITrunkPacket.cpp
@@ -137,9 +137,14 @@ void DFSITrunkPacket::writeRF_TSDU_SBF(bool noNetwork, bool clearBeforeWrite, bo
if (!m_p25->m_control)
return;
+ writeRF_DFSI_Start(P25_DFSI_TYPE_TSBK);
+
uint8_t data[P25_TSDU_FRAME_LENGTH_BYTES + 2U];
::memset(data + 2U, 0x00U, P25_TSDU_FRAME_LENGTH_BYTES);
+ m_rfDFSILC.setFrameType(P25_DFSI_TSBK);
+ m_rfDFSILC.setStartStop(P25_DFSI_START_FLAG);
+ m_rfDFSILC.setType(P25_DFSI_TYPE_TSBK);
m_rfDFSILC.tsbk(m_rfTSBK);
// Generate Sync
@@ -181,12 +186,12 @@ void DFSITrunkPacket::writeRF_TSDU_SBF(bool noNetwork, bool clearBeforeWrite, bo
// Generate DFSI TSBK block
m_rfDFSILC.encodeTSBK(data + 2U);
- if (m_p25->m_duplex) {
- data[0U] = modem::TAG_DATA;
- data[1U] = 0x00U;
+ data[0U] = modem::TAG_DATA;
+ data[1U] = 0x00U;
- m_p25->writeQueueRF(data, P25_DFSI_TSBK_FRAME_LENGTH_BYTES + 2U);
- }
+ m_p25->writeQueueRF(data, P25_DFSI_TSBK_FRAME_LENGTH_BYTES + 2U);
+
+ writeRF_DSFI_Stop(P25_DFSI_TYPE_TSBK);
}
///
@@ -209,3 +214,52 @@ void DFSITrunkPacket::writeNet_TSDU()
if (m_network != NULL)
m_network->resetP25();
}
+
+///
+/// Helper to write start DFSI data.
+///
+///
+void DFSITrunkPacket::writeRF_DFSI_Start(uint8_t type)
+{
+ uint8_t buffer[P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U];
+ ::memset(buffer, 0x00U, P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U);
+
+ // Generate Start/Stop
+ m_rfDFSILC.setFrameType(P25_DFSI_START_STOP);
+ m_rfDFSILC.setStartStop(P25_DFSI_START_FLAG);
+ m_rfDFSILC.setType(type);
+
+ // Generate Identifier Data
+ m_rfDFSILC.encodeNID(buffer + 2U);
+
+ buffer[0U] = modem::TAG_DATA;
+ buffer[1U] = 0x00U;
+
+ m_p25->writeQueueRF(buffer, P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U);
+}
+
+///
+/// Helper to write stop DFSI data.
+///
+///
+void DFSITrunkPacket::writeRF_DSFI_Stop(uint8_t type)
+{
+ uint8_t buffer[P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U];
+ ::memset(buffer, 0x00U, P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U);
+
+ // Generate Start/Stop
+ m_rfDFSILC.setFrameType(P25_DFSI_START_STOP);
+ m_rfDFSILC.setStartStop(P25_DFSI_STOP_FLAG);
+ m_rfDFSILC.setType(type);
+
+ // Generate Identifier Data
+ m_rfDFSILC.encodeNID(buffer + 2U);
+
+ buffer[0U] = modem::TAG_EOT;
+ buffer[1U] = 0x00U;
+
+ // 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);
+ }
+}
diff --git a/p25/dfsi/DFSITrunkPacket.h b/p25/dfsi/DFSITrunkPacket.h
index 84b56537..8e7612ae 100644
--- a/p25/dfsi/DFSITrunkPacket.h
+++ b/p25/dfsi/DFSITrunkPacket.h
@@ -78,6 +78,11 @@ namespace p25
/// Helper to write a network single-block P25 TSDU packet.
virtual void writeNet_TSDU();
+ /// Helper to write start DFSI data.
+ void writeRF_DFSI_Start(uint8_t type);
+ /// Helper to write stop DFSI data.
+ void writeRF_DSFI_Stop(uint8_t type);
+
private:
friend class DFSIVoicePacket;
friend class p25::Control;
diff --git a/p25/dfsi/DFSIVoicePacket.cpp b/p25/dfsi/DFSIVoicePacket.cpp
index 247e2dd0..ca422480 100644
--- a/p25/dfsi/DFSIVoicePacket.cpp
+++ b/p25/dfsi/DFSIVoicePacket.cpp
@@ -559,6 +559,60 @@ bool DFSIVoicePacket::process(uint8_t* data, uint32_t len)
}
}
}
+ else if (frameType == P25_DFSI_START_STOP) {
+ if (m_rfDFSILC.getType() == P25_DFSI_TYPE_VOICE && m_rfDFSILC.getStartStop() == P25_DFSI_STOP_FLAG) {
+ if (m_p25->m_control) {
+ m_p25->m_trunk->releaseDstIdGrant(m_rfLC.getDstId(), false);
+ }
+
+ uint8_t data[P25_TDU_FRAME_LENGTH_BYTES + 2U];
+ ::memset(data + 2U, 0x00U, P25_TDU_FRAME_LENGTH_BYTES);
+
+ // Generate Sync
+ Sync::addP25Sync(data + 2U);
+
+ // Generate NID
+ m_p25->m_nid.encode(data + 2U, P25_DUID_TDU);
+
+ // Add busy bits
+ m_p25->addBusyBits(data + 2U, P25_TDU_FRAME_LENGTH_BITS, true, true);
+
+ writeNetworkRF(data + 2U, P25_DUID_TDU);
+
+ m_lastDUID = P25_DUID_TDU;
+
+ m_p25->m_rfTimeout.stop();
+
+ if (m_p25->m_rfState == RS_RF_AUDIO) {
+ if (m_p25->m_rssi != 0U) {
+ ::ActivityLog("P25", true, "RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI : -%u / -%u / -%u dBm",
+ float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits), m_p25->m_minRSSI, m_p25->m_maxRSSI,
+ m_p25->m_aveRSSI / m_p25->m_rssiCount);
+ }
+ else {
+ ::ActivityLog("P25", true, "RF end of transmission, %.1f seconds, BER: %.1f%%",
+ float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits));
+ }
+
+ LogMessage(LOG_RF, P25_TDU_STR " DFSI, 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_dedicatedControl) {
+ m_p25->m_tailOnIdle = false;
+ writeRF_EndOfVoice();
+ }
+ else {
+ m_p25->m_tailOnIdle = true;
+ }
+ }
+
+ m_p25->m_rfState = RS_RF_LISTENING;
+ return true;
+ }
+ }
+ else {
+ LogError(LOG_RF, "P25 unhandled DFSI frame type, frameType = $%02X", frameType);
+ }
return false;
}
@@ -743,6 +797,7 @@ bool DFSIVoicePacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& contro
/// Flag indicating whether P25 verbose logging is enabled.
DFSIVoicePacket::DFSIVoicePacket(Control* p25, network::BaseNetwork* network, bool debug, bool verbose) :
VoicePacket(p25, network, debug, verbose),
+ m_trunk(NULL),
m_rfDFSILC(),
m_netDFSILC(),
m_dfsiLDU1(NULL),
@@ -753,6 +808,9 @@ DFSIVoicePacket::DFSIVoicePacket(Control* p25, network::BaseNetwork* network, bo
::memset(m_dfsiLDU1, 0x00U, 9U * 25U);
::memset(m_dfsiLDU2, 0x00U, 9U * 25U);
+
+ // hmmm...this should hopefully be a safe cast...right?
+ m_trunk = (DFSITrunkPacket *)p25->m_trunk;
}
///
@@ -773,21 +831,7 @@ void DFSIVoicePacket::writeNet_TDU()
m_p25->m_trunk->releaseDstIdGrant(m_netLC.getDstId(), false);
}
- m_rfDFSILC.setFrameType(P25_DFSI_START_STOP);
-
- uint8_t buffer[P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U];
- ::memset(buffer, 0x00U, P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U);
-
- buffer[0U] = modem::TAG_EOT;
- buffer[1U] = 0x00U;
-
- // Generate DFSI NID
- m_rfDFSILC.encodeNID(buffer + 2U);
-
- // stop writes the NID twice...
- for (uint8_t i = 0; i < 2; i++) {
- m_p25->writeQueueNet(buffer, P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U);
- }
+ m_trunk->writeRF_DSFI_Stop(P25_DFSI_TYPE_VOICE);
if (m_verbose) {
LogMessage(LOG_NET, P25_TDU_STR ", srcId = %u", m_netLC.getSrcId());
@@ -998,42 +1042,29 @@ void DFSIVoicePacket::writeNet_LDU1()
m_netDFSILC.control(m_netLC);
m_netDFSILC.lsd(lsd);
- if (!m_p25->m_disableNetworkHDU) {
- uint8_t buffer[P25_DFSI_VHDR1_FRAME_LENGTH_BYTES + 2U];
- ::memset(buffer, 0x00U, P25_DFSI_VHDR1_FRAME_LENGTH_BYTES + 2U);
-
- // Generate Start/Stop
- m_netDFSILC.setFrameType(P25_DFSI_START_STOP);
- m_netDFSILC.encodeNID(buffer + 2U);
+ m_trunk->writeRF_DFSI_Start(P25_DFSI_TYPE_VOICE);
- buffer[0U] = modem::TAG_DATA;
- buffer[1U] = 0x00U;
- m_p25->writeQueueNet(buffer, P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U);
+ uint8_t buffer[P25_DFSI_VHDR1_FRAME_LENGTH_BYTES + 2U];
+ ::memset(buffer, 0x00U, P25_DFSI_VHDR1_FRAME_LENGTH_BYTES + 2U);
- // Generate Voice Header 1
- m_netDFSILC.setFrameType(P25_DFSI_VHDR1);
- m_netDFSILC.encodeVHDR1(buffer + 2U);
+ // Generate Voice Header 1
+ m_netDFSILC.setFrameType(P25_DFSI_VHDR1);
+ m_netDFSILC.encodeVHDR1(buffer + 2U);
- buffer[0U] = modem::TAG_DATA;
- buffer[1U] = 0x00U;
- m_p25->writeQueueNet(buffer, P25_DFSI_VHDR1_FRAME_LENGTH_BYTES + 2U);
+ buffer[0U] = modem::TAG_DATA;
+ buffer[1U] = 0x00U;
+ m_p25->writeQueueNet(buffer, P25_DFSI_VHDR1_FRAME_LENGTH_BYTES + 2U);
- // Generate Voice Header 2
- m_netDFSILC.setFrameType(P25_DFSI_VHDR2);
- m_netDFSILC.encodeVHDR2(buffer + 2U);
+ // Generate Voice Header 2
+ m_netDFSILC.setFrameType(P25_DFSI_VHDR2);
+ m_netDFSILC.encodeVHDR2(buffer + 2U);
- buffer[0U] = modem::TAG_DATA;
- buffer[1U] = 0x00U;
- m_p25->writeQueueNet(buffer, P25_DFSI_VHDR2_FRAME_LENGTH_BYTES + 2U);
+ buffer[0U] = modem::TAG_DATA;
+ buffer[1U] = 0x00U;
+ m_p25->writeQueueNet(buffer, P25_DFSI_VHDR2_FRAME_LENGTH_BYTES + 2U);
- 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());
- }
- }
- else {
- if (m_verbose) {
- LogMessage(LOG_NET, P25_HDU_STR " DFSI, not transmitted; network HDU disabled, dstId = %u, algo = $%02X, kid = $%04X", m_netLC.getDstId(), m_netLC.getAlgId(), m_netLC.getKId());
- }
+ 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());
}
}
diff --git a/p25/dfsi/DFSIVoicePacket.h b/p25/dfsi/DFSIVoicePacket.h
index 393ca56b..bb6f371a 100644
--- a/p25/dfsi/DFSIVoicePacket.h
+++ b/p25/dfsi/DFSIVoicePacket.h
@@ -32,6 +32,7 @@
#include "Defines.h"
#include "p25/dfsi/LC.h"
+#include "p25/dfsi/DFSITrunkPacket.h"
#include "p25/TrunkPacket.h"
#include "p25/Control.h"
#include "network/BaseNetwork.h"
@@ -65,6 +66,8 @@ namespace p25
virtual bool processNetwork(uint8_t* data, uint32_t len, lc::LC& control, data::LowSpeedData& lsd, uint8_t& duid);
protected:
+ DFSITrunkPacket* m_trunk;
+
LC m_rfDFSILC;
LC m_netDFSILC;
diff --git a/p25/dfsi/LC.cpp b/p25/dfsi/LC.cpp
index 7c53e0fd..4925e8c1 100644
--- a/p25/dfsi/LC.cpp
+++ b/p25/dfsi/LC.cpp
@@ -817,8 +817,8 @@ void LC::encodeStart(uint8_t* data)
uint8_t rawFrame[P25_DFSI_START_LENGTH_BYTES];
::memset(rawFrame, 0x00U, P25_DFSI_START_LENGTH_BYTES);
- rawFrame[0U] = 0x02U;
- rawFrame[1U] = m_rtModeFlag; // RT Mode Flag
+ rawFrame[0U] = 0x02U; //
+ rawFrame[1U] = m_rtModeFlag; // RT/RT Mode Flag
rawFrame[2U] = m_startStopFlag; // Start/Stop Flag
rawFrame[3U] = m_typeFlag; // Type flag