diff --git a/config.example.yml b/config.example.yml index 73a24ab8..41a4a005 100644 --- a/config.example.yml +++ b/config.example.yml @@ -22,6 +22,7 @@ network: updateLookups: false allowActivityTransfer: false allowDiagnosticTransfer: false + handleChGrants: false debug: false protocols: dmr: diff --git a/host/Host.cpp b/host/Host.cpp index 9fccb983..d06947c6 100644 --- a/host/Host.cpp +++ b/host/Host.cpp @@ -1750,6 +1750,7 @@ bool Host::createNetwork() bool allowActivityTransfer = networkConf["allowActivityTransfer"].as(false); bool allowDiagnosticTransfer = networkConf["allowDiagnosticTransfer"].as(false); bool updateLookup = networkConf["updateLookups"].as(false); + bool handleChGrants = networkConf["handleChGrants"].as(false); bool debug = networkConf["debug"].as(false); if (rconPassword.length() > 64) { @@ -1784,12 +1785,13 @@ bool Host::createNetwork() LogInfo(" Allow Activity Log Transfer: %s", allowActivityTransfer ? "yes" : "no"); LogInfo(" Allow Diagnostic Log Transfer: %s", allowDiagnosticTransfer ? "yes" : "no"); LogInfo(" Update Lookups: %s", updateLookup ? "yes" : "no"); + LogInfo(" Handle Channel Grants: %s", handleChGrants ? "yes" : "no"); if (debug) { LogInfo(" Debug: yes"); } - m_network = new Network(address, port, local, id, password, m_duplex, debug, m_dmrEnabled, m_p25Enabled, slot1, slot2, allowActivityTransfer, allowDiagnosticTransfer, updateLookup); + m_network = new Network(address, port, local, id, password, m_duplex, debug, m_dmrEnabled, m_p25Enabled, slot1, slot2, allowActivityTransfer, allowDiagnosticTransfer, updateLookup, handleChGrants); m_network->setLookups(m_ridLookup, m_tidLookup); m_network->setMetadata(m_identity, m_rxFrequency, m_txFrequency, entry.txOffsetMhz(), entry.chBandwidthKhz(), m_channelId, m_channelNo, diff --git a/network/BaseNetwork.cpp b/network/BaseNetwork.cpp index 9e70d420..9c4114f0 100644 --- a/network/BaseNetwork.cpp +++ b/network/BaseNetwork.cpp @@ -54,12 +54,14 @@ using namespace network; /// Flag indicating whether DMR slot 2 is enabled for network traffic. /// 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. -BaseNetwork::BaseNetwork(uint16_t localPort, uint32_t id, bool duplex, bool debug, bool slot1, bool slot2, bool allowActivityTransfer, bool allowDiagnosticTransfer) : +/// Flag indicating that the system will handle channel grants from the network. +BaseNetwork::BaseNetwork(uint16_t localPort, uint32_t id, bool duplex, bool debug, bool slot1, bool slot2, bool allowActivityTransfer, bool allowDiagnosticTransfer, bool handleChGrants) : m_id(id), m_slot1(slot1), m_slot2(slot2), m_allowActivityTransfer(allowActivityTransfer), m_allowDiagnosticTransfer(allowDiagnosticTransfer), + m_handleChGrants(handleChGrants), m_duplex(duplex), m_debug(debug), m_addr(), @@ -74,6 +76,7 @@ BaseNetwork::BaseNetwork(uint16_t localPort, uint32_t id, bool duplex, bool debu m_p25StreamId(0U), m_rxDMRData(4000U, "DMR Net Buffer"), m_rxP25Data(4000U, "P25 Net Buffer"), + m_rxGrantData(4000U, "Grant Net Buffer"), m_audio(), m_random() { @@ -247,6 +250,39 @@ uint8_t* BaseNetwork::readP25(bool& ret, p25::lc::LC& control, p25::data::LowSpe return data; } +/// +/// Reads a channel grant request from the network. +/// +/// +/// +/// +/// +/// +bool BaseNetwork::readGrantRsp(bool& grp, uint32_t& srcId, uint32_t& dstId, uint32_t& grpVchNo) +{ + if (!m_handleChGrants) + return false; + + if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING) + return false; + + if (m_rxGrantData.isEmpty()) + return false; + + uint8_t length = 0U; + m_rxGrantData.getData(&length, 1U); + m_rxGrantData.getData(m_buffer, length); + + srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0); + dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0); + + grp = m_buffer[11U] == 1U; + + grpVchNo = (m_buffer[12U] << 16) | (m_buffer[13U] << 8) | (m_buffer[14U] << 0); + + return true; +} + /// /// Writes DMR frame data to the network. /// @@ -387,6 +423,40 @@ bool BaseNetwork::writeP25PDU(const p25::data::DataHeader& header, const p25::da return writeP25PDU(m_id, m_p25StreamId, header, secHeader, currentBlock, data, len); } +/// +/// Writes a channel grant request to the network. +/// +/// +/// +/// +/// +bool BaseNetwork::writeGrantReq(const bool grp, const uint32_t srcId, const uint32_t dstId) +{ + if (!m_handleChGrants) + return false; + + if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING) + return false; + + uint8_t buffer[DATA_PACKET_LENGTH]; + ::memset(buffer, 0x00U, DATA_PACKET_LENGTH); + + ::memcpy(buffer + 0U, TAG_REPEATER_GRANT, 7U); + + __SET_UINT16(srcId, buffer, 5U); // Source Address + __SET_UINT16(dstId, buffer, 8U); // Target Address + + buffer[11U] = (grp) ? 1U : 0U; // Group/Individual Grant + + __SET_UINT32(m_id, buffer, 12U); // Peer ID + + + if (m_debug) + Utils::dump(1U, "Network Transmitted, DMR", buffer, (32U + PACKET_PAD)); + + return write(buffer, (32U + PACKET_PAD)); +} + /// /// Writes the local activity log to the network. /// diff --git a/network/BaseNetwork.h b/network/BaseNetwork.h index a6254a66..13f6ba62 100644 --- a/network/BaseNetwork.h +++ b/network/BaseNetwork.h @@ -68,6 +68,8 @@ #define TAG_MASTER_CLOSING "MSTCL" #define TAG_MASTER_PONG "MSTPONG" +#define TAG_MASTER_GRANT "MSTGRNT" + #define TAG_REPEATER_LOGIN "RPTL" #define TAG_REPEATER_AUTH "RPTK" #define TAG_REPEATER_CONFIG "RPTC" @@ -76,6 +78,8 @@ #define TAG_REPEATER_CLOSING "RPTCL" #define TAG_REPEATER_PING "RPTPING" +#define TAG_REPEATER_GRANT "RPTGRNT" + #define TAG_TRANSFER_ACT_LOG "TRNSLOG" #define TAG_TRANSFER_DIAG_LOG "TRNSDIAG" @@ -118,18 +122,24 @@ namespace network class HOST_SW_API BaseNetwork { public: /// Initializes a new instance of the BaseNetwork class. - BaseNetwork(uint16_t localPort, uint32_t id, bool duplex, bool debug, bool slot1, bool slot2, bool transferActivityLog, bool transferDiagnosticLog); + BaseNetwork(uint16_t localPort, uint32_t id, bool duplex, bool debug, bool slot1, bool slot2, bool allowActivityTransfer, bool allowDiagnosticTransfer, bool handleChGrants); /// Finalizes a instance of the BaseNetwork class. virtual ~BaseNetwork(); /// Gets the current status of the network. NET_CONN_STATUS getStatus() { return m_status; } + /// Gets the flag indicating if the network is handling channel grants. + bool isHandlingChGrants() { return m_handleChGrants; } + /// Reads DMR frame data from the DMR ring buffer. virtual bool readDMR(dmr::data::Data& data); /// Reads P25 frame data from the P25 ring buffer. virtual uint8_t* readP25(bool& ret, p25::lc::LC& control, p25::data::LowSpeedData& lsd, uint8_t& duid, uint32_t& len); + /// Reads a channel grant request from the network. + virtual bool readGrantRsp(bool& grp, uint32_t& srcId, uint32_t& dstId, uint32_t& grpVchNo); + /// Writes DMR frame data to the network. virtual bool writeDMR(const dmr::data::Data& data); /// Writes P25 LDU1 frame data to the network. @@ -144,6 +154,9 @@ namespace network virtual bool writeP25PDU(const p25::data::DataHeader& header, const p25::data::DataHeader& secHeader, const uint8_t currentBlock, const uint8_t* data, const uint32_t len); + /// Writes a channel grant request to the network. + virtual bool writeGrantReq(const bool grp, const uint32_t srcId, const uint32_t dstId); + /// Writes the local activity log to the network. virtual bool writeActLog(const char* message); @@ -172,6 +185,7 @@ namespace network bool m_allowActivityTransfer; bool m_allowDiagnosticTransfer; + bool m_handleChGrants; bool m_duplex; bool m_debug; @@ -193,6 +207,8 @@ namespace network RingBuffer m_rxDMRData; RingBuffer m_rxP25Data; + RingBuffer m_rxGrantData; + p25::Audio m_audio; std::mt19937 m_random; diff --git a/network/Network.cpp b/network/Network.cpp index 1ac7d8a7..572f38d5 100644 --- a/network/Network.cpp +++ b/network/Network.cpp @@ -61,9 +61,10 @@ using namespace network; /// 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 that the system will accept radio ID and talkgroup ID lookups from the network. +/// Flag indicating that the system will handle channel grants from the network. Network::Network(const std::string& address, uint16_t port, uint16_t local, uint32_t id, const std::string& password, - bool duplex, bool debug, bool dmr, bool p25, bool slot1, bool slot2, bool allowActivityTransfer, bool allowDiagnosticTransfer, bool updateLookup) : - BaseNetwork(local, id, duplex, debug, slot1, slot2, allowActivityTransfer, allowDiagnosticTransfer), + bool duplex, bool debug, bool dmr, bool p25, bool slot1, bool slot2, bool allowActivityTransfer, bool allowDiagnosticTransfer, bool updateLookup, bool handleChGrants) : + BaseNetwork(local, id, duplex, debug, slot1, slot2, allowActivityTransfer, allowDiagnosticTransfer, handleChGrants), m_address(address), m_port(port), m_password(password), @@ -351,6 +352,16 @@ void Network::clock(uint32_t ms) else if (::memcmp(m_buffer, TAG_MASTER_PONG, 7U) == 0) { m_timeoutTimer.start(); } + else if (::memcmp(m_buffer, TAG_MASTER_GRANT, 7U) == 0) { + if (m_enabled && m_handleChGrants) { + if (m_debug) + Utils::dump(1U, "Network Received, Channel Grant", m_buffer, length); + + uint8_t len = length; + m_rxGrantData.addData(&len, 1U); + m_rxGrantData.addData(m_buffer, len); + } + } else { Utils::dump("Unknown packet from the master", m_buffer, length); } diff --git a/network/Network.h b/network/Network.h index 4fbec0eb..ae187bb5 100644 --- a/network/Network.h +++ b/network/Network.h @@ -50,7 +50,7 @@ namespace network public: /// Initializes a new instance of the Network class. Network(const std::string& address, uint16_t port, uint16_t local, uint32_t id, const std::string& password, - bool duplex, bool debug, bool dmr, bool p25, bool slot1, bool slot2, bool transferActivityLog, bool transferDiagnosticLog, bool updateLookup); + bool duplex, bool debug, bool dmr, bool p25, bool slot1, bool slot2, bool transferActivityLog, bool transferDiagnosticLog, bool updateLookup, bool handleChGrants); /// Finalizes a instance of the Network class. ~Network(); diff --git a/p25/TrunkPacket.cpp b/p25/TrunkPacket.cpp index fe087372..f54fa0bf 100644 --- a/p25/TrunkPacket.cpp +++ b/p25/TrunkPacket.cpp @@ -1054,6 +1054,24 @@ void TrunkPacket::clearGrpAff(uint32_t dstId, bool releaseAll) void TrunkPacket::clock(uint32_t ms) { if (m_p25->m_control) { + if (m_p25->m_network != NULL) { + if (m_p25->m_network->isHandlingChGrants() && m_p25->m_siteData.netActive()) { + bool grp = true; + uint32_t srcId = 0U; + uint32_t dstId = 0U; + uint32_t grpVchNo = 0U; + + // do we have a grant response? + if (m_p25->m_network->readGrantRsp(grp, srcId, dstId, grpVchNo)) { + m_rfTSBK.setSrcId(srcId); + m_rfTSBK.setDstId(dstId); + m_rfTSBK.setGrpVchNo(grpVchNo); + + writeRF_TSDU_Grant(grp, true, true, true); + } + } + } + // clock all the grant timers std::vector gntsToRel = std::vector(); for (auto it = m_grantChTable.begin(); it != m_grantChTable.end(); ++it) { @@ -2021,8 +2039,9 @@ void TrunkPacket::queueRF_TSBK_Ctrl(uint8_t lco) /// /// /// +/// /// -bool TrunkPacket::writeRF_TSDU_Grant(bool grp, bool skip, bool net) +bool TrunkPacket::writeRF_TSDU_Grant(bool grp, bool skip, bool net, bool skipNetCheck) { uint8_t lco = m_rfTSBK.getLCO(); @@ -2030,6 +2049,13 @@ bool TrunkPacket::writeRF_TSDU_Grant(bool grp, bool skip, bool net) return true; // do not generate grant packets for $FFFF (All Call) TGID } + // do we have a network connection and are we handling grants at the network? + if (m_p25->m_network != NULL) { + if (m_p25->m_network->isHandlingChGrants() && m_p25->m_siteData.netActive() && !skipNetCheck) { + return m_p25->m_network->writeGrantReq(grp, m_rfTSBK.getSrcId(), m_rfTSBK.getDstId()); + } + } + // are we skipping checking? if (!skip) { if (m_p25->m_rfState != RS_RF_LISTENING && m_p25->m_rfState != RS_RF_DATA) { diff --git a/p25/TrunkPacket.h b/p25/TrunkPacket.h index b93233f7..4f7376d0 100644 --- a/p25/TrunkPacket.h +++ b/p25/TrunkPacket.h @@ -198,7 +198,7 @@ namespace p25 void queueRF_TSBK_Ctrl(uint8_t lco); /// Helper to write a grant packet. - bool writeRF_TSDU_Grant(bool grp, bool skip = false, bool net = false); + bool writeRF_TSDU_Grant(bool grp, bool skip = false, bool net = false, bool skipNetCheck = false); /// Helper to write a SNDCP grant packet. bool writeRF_TSDU_SNDCP_Grant(bool skip = false, bool net = false); /// Helper to write a unit to unit answer request packet.