diff --git a/configs/fne-config.example.yml b/configs/fne-config.example.yml index be7524ca..b9542137 100644 --- a/configs/fne-config.example.yml +++ b/configs/fne-config.example.yml @@ -55,6 +55,8 @@ master: # Delay from when a call on a parrot TG ends to when the playback starts (in milliseconds). parrotDelay: 2000 + # Flag indicating whether or not a parrot TG call will generate a grant demand. + parrotGrantDemand: true # # Talkgroup Rules Configuration diff --git a/src/host/fne/HostFNE.cpp b/src/host/fne/HostFNE.cpp index c5f8daec..94c14e2c 100644 --- a/src/host/fne/HostFNE.cpp +++ b/src/host/fne/HostFNE.cpp @@ -333,6 +333,7 @@ bool HostFNE::createMasterNetwork() LogWarning(LOG_HOST, "Parrot delay cannot be longer then the ping time of a peer. Reducing parrot delay to half the ping time."); parrotDelay = (m_pingTime * 1000U) / 2U; } + bool parrotGrantDemand = masterConf["parrotGrantDemand"].as(true); LogInfo("Network Parameters"); LogInfo(" Peer ID: %u", id); @@ -342,6 +343,7 @@ bool HostFNE::createMasterNetwork() LogInfo(" Allow P25 Traffic: %s", m_p25Enabled ? "yes" : "no"); LogInfo(" Allow NXDN Traffic: %s", m_nxdnEnabled ? "yes" : "no"); LogInfo(" Parrot Repeat Delay: %u ms", parrotDelay); + LogInfo(" Parrot Grant Demand: %s", parrotGrantDemand ? "yes" : "no"); if (verbose) { LogInfo(" Verbose: yes"); @@ -352,8 +354,8 @@ bool HostFNE::createMasterNetwork() } // initialize networking - m_network = new FNENetwork(this, address, port, id, password, debug, verbose, m_dmrEnabled, m_p25Enabled, m_nxdnEnabled, parrotDelay, - m_allowActivityTransfer, m_allowDiagnosticTransfer, m_pingTime, m_updateLookupTime); + m_network = new FNENetwork(this, address, port, id, password, debug, verbose, m_dmrEnabled, m_p25Enabled, m_nxdnEnabled, + parrotDelay, parrotGrantDemand, m_allowActivityTransfer, m_allowDiagnosticTransfer, m_pingTime, m_updateLookupTime); m_network->setLookups(m_ridLookup, m_tidLookup); diff --git a/src/network/BaseNetwork.cpp b/src/network/BaseNetwork.cpp index 84eb00a8..64f5b400 100644 --- a/src/network/BaseNetwork.cpp +++ b/src/network/BaseNetwork.cpp @@ -438,8 +438,9 @@ bool BaseNetwork::writeP25LDU2(const p25::lc::LC& control, const p25::data::LowS /// /// /// +/// /// -bool BaseNetwork::writeP25TDU(const p25::lc::LC& control, const p25::data::LowSpeedData& lsd) +bool BaseNetwork::writeP25TDU(const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, const uint8_t controlByte) { if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING) return false; @@ -451,7 +452,7 @@ bool BaseNetwork::writeP25TDU(const p25::lc::LC& control, const p25::data::LowSp } uint32_t messageLength = 0U; - UInt8Array message = createP25_TDUMessage(messageLength, control, lsd); + UInt8Array message = createP25_TDUMessage(messageLength, control, lsd, controlByte); if (message == nullptr) { return false; } @@ -916,8 +917,9 @@ UInt8Array BaseNetwork::createP25_LDU2Message(uint32_t& length, const p25::lc::L /// /// /// +/// /// -UInt8Array BaseNetwork::createP25_TDUMessage(uint32_t& length, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd) +UInt8Array BaseNetwork::createP25_TDUMessage(uint32_t& length, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, const uint8_t controlByte) { uint8_t* buffer = new uint8_t[MSG_HDR_SIZE + PACKET_PAD]; ::memset(buffer, 0x00U, MSG_HDR_SIZE + PACKET_PAD); @@ -925,6 +927,7 @@ UInt8Array BaseNetwork::createP25_TDUMessage(uint32_t& length, const p25::lc::LC // construct P25 message header createP25_MessageHdr(buffer, p25::P25_DUID_TDU, control, lsd, p25::P25_FT_TERMINATOR); + buffer[14U] = controlByte; buffer[23U] = MSG_HDR_SIZE; if (m_debug) diff --git a/src/network/BaseNetwork.h b/src/network/BaseNetwork.h index 618bb56f..08f941cf 100644 --- a/src/network/BaseNetwork.h +++ b/src/network/BaseNetwork.h @@ -212,7 +212,7 @@ namespace network /// Writes P25 LDU2 frame data to the network. bool writeP25LDU2(const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, const uint8_t* data); /// Writes P25 TDU frame data to the network. - bool writeP25TDU(const p25::lc::LC& control, const p25::data::LowSpeedData& lsd); + bool writeP25TDU(const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, const uint8_t controlByte = 0U); /// Writes P25 TSDU frame data to the network. bool writeP25TSDU(const p25::lc::LC& control, const uint8_t* data); /// Writes P25 PDU frame data to the network. @@ -286,7 +286,8 @@ namespace network const uint8_t* data); /// Creates an P25 TDU frame message. - UInt8Array createP25_TDUMessage(uint32_t& length, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd); + UInt8Array createP25_TDUMessage(uint32_t& length, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, + const uint8_t controlByte); /// Creates an P25 TSDU frame message. UInt8Array createP25_TSDUMessage(uint32_t& length, const p25::lc::LC& control, const uint8_t* data); diff --git a/src/network/FNENetwork.cpp b/src/network/FNENetwork.cpp index e03f2032..74579b51 100644 --- a/src/network/FNENetwork.cpp +++ b/src/network/FNENetwork.cpp @@ -61,14 +61,15 @@ using namespace network::fne; /// Flag indicating whether P25 is enabled. /// Flag indicating whether NXDN is enabled. /// Delay for end of call to parrot TG playback. +/// Flag indicating whether a parrot TG will generate a grant demand. /// Flag indicating that the system activity logs will be sent to the network. /// Flag indicating that the system diagnostic logs will be sent to the network. /// Flag indicating if traffic should be repeated from this master. /// /// FNENetwork::FNENetwork(HostFNE* host, const std::string& address, uint16_t port, uint32_t peerId, const std::string& password, - bool debug, bool verbose, bool dmr, bool p25, bool nxdn, uint32_t parrotDelay, bool allowActivityTransfer, bool allowDiagnosticTransfer, - uint32_t pingTime, uint32_t updateLookupTime) : + bool debug, bool verbose, bool dmr, bool p25, bool nxdn, uint32_t parrotDelay, bool parrotGrantDemand, + bool allowActivityTransfer, bool allowDiagnosticTransfer, uint32_t pingTime, uint32_t updateLookupTime) : BaseNetwork(peerId, true, debug, true, true, allowActivityTransfer, allowDiagnosticTransfer), m_tagDMR(nullptr), m_tagP25(nullptr), @@ -81,6 +82,7 @@ FNENetwork::FNENetwork(HostFNE* host, const std::string& address, uint16_t port, m_p25Enabled(p25), m_nxdnEnabled(nxdn), m_parrotDelay(parrotDelay), + m_parrotGrantDemand(parrotGrantDemand), m_ridLookup(nullptr), m_tidLookup(nullptr), m_status(NET_STAT_INVALID), diff --git a/src/network/FNENetwork.h b/src/network/FNENetwork.h index bc637f76..080db6b2 100644 --- a/src/network/FNENetwork.h +++ b/src/network/FNENetwork.h @@ -177,8 +177,8 @@ namespace network public: /// Initializes a new instance of the FNENetwork class. FNENetwork(HostFNE* host, const std::string& address, uint16_t port, uint32_t peerId, const std::string& password, - bool debug, bool verbose, bool dmr, bool p25, bool nxdn, uint32_t parrotDelay, bool allowActivityTransfer, - bool allowDiagnosticTransfer, uint32_t pingTime, uint32_t updateLookupTime); + bool debug, bool verbose, bool dmr, bool p25, bool nxdn, uint32_t parrotDelay, bool parrotGrantDemand, + bool allowActivityTransfer, bool allowDiagnosticTransfer, uint32_t pingTime, uint32_t updateLookupTime); /// Finalizes a instance of the FNENetwork class. ~FNENetwork(); @@ -224,6 +224,7 @@ namespace network bool m_nxdnEnabled; uint32_t m_parrotDelay; + bool m_parrotGrantDemand; lookups::RadioIdLookup* m_ridLookup; lookups::TalkgroupRulesLookup* m_tidLookup; diff --git a/src/network/fne/TagP25Data.cpp b/src/network/fne/TagP25Data.cpp index 8ccdc221..28672b64 100644 --- a/src/network/fne/TagP25Data.cpp +++ b/src/network/fne/TagP25Data.cpp @@ -36,6 +36,7 @@ using namespace system_clock; using namespace network; using namespace network::fne; +using namespace p25; #include #include @@ -55,6 +56,7 @@ TagP25Data::TagP25Data(FNENetwork* network, bool debug) : m_network(network), m_parrotFrames(), m_parrotFramesReady(false), + m_parrotFirstFrame(true), m_status(), m_debug(debug) { @@ -160,6 +162,7 @@ bool TagP25Data::processFrame(const uint8_t* data, uint32_t len, uint32_t peerId if (tg.config().parrot()) { if (m_parrotFrames.size() > 0) { m_parrotFramesReady = true; + m_parrotFirstFrame = true; Thread::sleep(m_network->m_parrotDelay); LogMessage(LOG_NET, "P25, Parrot Playback will Start, peer = %u, srcId = %u", peerId, srcId); } @@ -213,7 +216,7 @@ bool TagP25Data::processFrame(const uint8_t* data, uint32_t len, uint32_t peerId if (tg.config().parrot()) { uint8_t *copy = new uint8_t[len]; ::memcpy(copy, data, len); - m_parrotFrames.push_back(std::make_tuple(copy, len, pktSeq, streamId)); + m_parrotFrames.push_back(std::make_tuple(copy, len, pktSeq, streamId, srcId, dstId)); } // repeat traffic to the connected peers @@ -253,11 +256,42 @@ void TagP25Data::playbackParrot() { if (m_parrotFrames.size() == 0) { m_parrotFramesReady = false; + m_parrotFirstFrame = true; return; } auto& pkt = m_parrotFrames[0]; if (std::get<0>(pkt) != nullptr) { + if (m_parrotFirstFrame) { + if (m_network->m_parrotGrantDemand) { + uint32_t srcId = std::get<4>(pkt); + uint32_t dstId = std::get<5>(pkt); + + // create control data + lc::LC control = lc::LC(); + control.setSrcId(srcId); + control.setDstId(dstId); + + // create empty LSD + data::LowSpeedData lsd = data::LowSpeedData(); + + uint8_t controlByte = 0x80U; + + // send grant demand + uint32_t messageLength = 0U; + UInt8Array message = m_network->createP25_TDUMessage(messageLength, control, lsd, controlByte); + if (message != nullptr) { + // repeat traffic to the connected peers + for (auto peer : m_network->m_peers) { + LogMessage(LOG_NET, "P25, Parrot Grant Demand, peer = %u, srcId = %u, dstId = %u", peer.first, srcId, dstId); + m_network->writePeer(peer.first, { NET_FUNC_PROTOCOL, NET_PROTOCOL_SUBFUNC_P25 }, message.get(), messageLength, 0U, false); + } + } + } + + m_parrotFirstFrame = false; + } + // repeat traffic to the connected peers for (auto peer : m_network->m_peers) { m_network->writePeer(peer.first, { NET_FUNC_PROTOCOL, NET_PROTOCOL_SUBFUNC_P25 }, std::get<0>(pkt), std::get<1>(pkt), std::get<2>(pkt), std::get<3>(pkt), false); diff --git a/src/network/fne/TagP25Data.h b/src/network/fne/TagP25Data.h index 901d5039..509daa0f 100644 --- a/src/network/fne/TagP25Data.h +++ b/src/network/fne/TagP25Data.h @@ -67,8 +67,9 @@ namespace network private: FNENetwork* m_network; - std::deque> m_parrotFrames; + std::deque> m_parrotFrames; bool m_parrotFramesReady; + bool m_parrotFirstFrame; class RxStatus { public: diff --git a/src/p25/Control.cpp b/src/p25/Control.cpp index e86a3471..ba092573 100644 --- a/src/p25/Control.cpp +++ b/src/p25/Control.cpp @@ -1282,7 +1282,7 @@ void Control::processNetwork() (control.getPriority() & 0x07U); // Priority if (m_verbose) { - LogMessage(LOG_NET, P25_TSDU_STR " remote grant demand, srcId = %u, dstId = %u", srcId, dstId); + LogMessage(LOG_NET, P25_TSDU_STR " remote grant demand, srcId = %u, dstId = %u, unitToUnit = %u", srcId, dstId, unitToUnit); } // are we denying the grant? @@ -1292,7 +1292,7 @@ void Control::processNetwork() } // perform grant response logic - if (!m_control->writeRF_TSDU_Grant(srcId, dstId, serviceOptions, unitToUnit, true)) + if (!m_control->writeRF_TSDU_Grant(srcId, dstId, serviceOptions, !unitToUnit, true)) { LogError(LOG_NET, P25_TSDU_STR " call failure, network call not granted, dstId = %u", dstId); return;