diff --git a/src/fne/network/RESTAPI.cpp b/src/fne/network/RESTAPI.cpp index 638edbc3..576e4de0 100644 --- a/src/fne/network/RESTAPI.cpp +++ b/src/fne/network/RESTAPI.cpp @@ -17,6 +17,8 @@ #include "common/network/json/json.h" #include "common/Log.h" #include "common/Utils.h" +#include "fne/network/fne/TagDMRData.h" +#include "fne/network/fne/TagP25Data.h" #include "fne/network/RESTAPI.h" #include "HostFNE.h" @@ -549,6 +551,18 @@ void RESTAPI::initializeEndpoints() m_dispatcher.match(FNE_GET_FORCE_UPDATE).get(REST_API_BIND(RESTAPI::restAPI_GetForceUpdate, this)); m_dispatcher.match(FNE_GET_AFF_LIST).get(REST_API_BIND(RESTAPI::restAPI_GetAffList, this)); + + /* + ** Digital Mobile Radio + */ + + m_dispatcher.match(PUT_DMR_RID).put(REST_API_BIND(RESTAPI::restAPI_PutDMRRID, this)); + + /* + ** Project 25 + */ + + m_dispatcher.match(PUT_P25_RID).put(REST_API_BIND(RESTAPI::restAPI_PutP25RID, this)); } /// @@ -1185,3 +1199,166 @@ void RESTAPI::restAPI_GetAffList(const HTTPPayload& request, HTTPPayload& reply, response["affiliations"].set(affs); reply.payload(response); } + +/* +** Digital Mobile Radio +*/ + +/// +/// +/// +/// +/// +/// +void RESTAPI::restAPI_PutDMRRID(const HTTPPayload& request, HTTPPayload& reply, const RequestMatch& match) +{ + if (!validateAuth(request, reply)) { + return; + } + + json::object req = json::object(); + if (!parseRequestBody(request, reply, req)) { + return; + } + + // validate state is a string within the JSON blob + if (!req["command"].is()) { + errorPayload(reply, "command was not valid"); + return; + } + + // validate peer ID is a integer within the JSON blob + if (!req["peerId"].is()) { + errorPayload(reply, "peer ID was not valid"); + return; + } + + // validate destination ID is a integer within the JSON blob + if (!req["dstId"].is()) { + errorPayload(reply, "destination ID was not valid"); + return; + } + + // validate destination ID is a integer within the JSON blob + if (!req["slot"].is()) { + errorPayload(reply, "slot was not valid"); + return; + } + + uint32_t peerId = req["peerId"].get(); + uint32_t dstId = req["dstId"].get(); + uint8_t slot = req["slot"].get(); + + if (peerId == 0U) { + errorPayload(reply, "peer ID was not valid"); + return; + } + + if (dstId == 0U) { + errorPayload(reply, "destination ID was not valid"); + return; + } + + if (slot == 0U || slot >= 3U) { + errorPayload(reply, "invalid DMR slot number (slot == 0 or slot > 3)"); + return; + } + + errorPayload(reply, "OK", HTTPPayload::OK); + std::string command = req["command"].get(); + if (::strtolower(command) == RID_CMD_PAGE) { + m_network->m_tagDMR->write_Call_Alrt(peerId, slot, p25::P25_WUID_FNE, dstId); + } + else if (::strtolower(command) == RID_CMD_CHECK) { + m_network->m_tagDMR->write_Ext_Func(peerId, slot, dmr::DMR_EXT_FNCT_CHECK, p25::P25_WUID_FNE, dstId); + } + else if (::strtolower(command) == RID_CMD_INHIBIT) { + m_network->m_tagDMR->write_Ext_Func(peerId, slot, dmr::DMR_EXT_FNCT_INHIBIT, p25::P25_WUID_FNE, dstId); + } + else if (::strtolower(command) == RID_CMD_UNINHIBIT) { + m_network->m_tagDMR->write_Ext_Func(peerId, slot, dmr::DMR_EXT_FNCT_UNINHIBIT, p25::P25_WUID_FNE, dstId); + } + else { + errorPayload(reply, "invalid command"); + return; + } +} + +/* +** Project 25 +*/ + +/// +/// +/// +/// +/// +/// +void RESTAPI::restAPI_PutP25RID(const HTTPPayload& request, HTTPPayload& reply, const RequestMatch& match) +{ + if (!validateAuth(request, reply)) { + return; + } + + json::object req = json::object(); + if (!parseRequestBody(request, reply, req)) { + return; + } + + // validate state is a string within the JSON blob + if (!req["command"].is()) { + errorPayload(reply, "command was not valid"); + return; + } + + // validate peer ID is a integer within the JSON blob + if (!req["peerId"].is()) { + errorPayload(reply, "peer ID was not valid"); + return; + } + + // validate destination ID is a integer within the JSON blob + if (!req["dstId"].is()) { + errorPayload(reply, "destination ID was not valid"); + return; + } + + uint32_t peerId = req["peerId"].get(); + uint32_t dstId = req["dstId"].get(); + + if (peerId == 0U) { + errorPayload(reply, "peer ID was not valid"); + return; + } + + if (dstId == 0U) { + errorPayload(reply, "destination ID was not valid"); + return; + } + + std::string command = req["command"].get(); + + errorPayload(reply, "OK", HTTPPayload::OK); + if (::strtolower(command) == RID_CMD_PAGE) { + m_network->m_tagP25->write_TSDU_Call_Alrt(peerId, p25::P25_WUID_FNE, dstId); + } + else if (::strtolower(command) == RID_CMD_CHECK) { + m_network->m_tagP25->write_TSDU_Ext_Func(peerId, p25::P25_EXT_FNCT_CHECK, p25::P25_WUID_FNE, dstId); + } + else if (::strtolower(command) == RID_CMD_INHIBIT) { + m_network->m_tagP25->write_TSDU_Ext_Func(peerId, p25::P25_EXT_FNCT_INHIBIT, p25::P25_WUID_FNE, dstId); + } + else if (::strtolower(command) == RID_CMD_UNINHIBIT) { + m_network->m_tagP25->write_TSDU_Ext_Func(peerId, p25::P25_EXT_FNCT_UNINHIBIT, p25::P25_WUID_FNE, dstId); + } + else if (::strtolower(command) == RID_CMD_GAQ) { + m_network->m_tagP25->write_TSDU_Grp_Aff_Q(peerId, dstId); + } + else if (::strtolower(command) == RID_CMD_UREG) { + m_network->m_tagP25->write_TSDU_U_Reg_Cmd(peerId, dstId); + } + else { + errorPayload(reply, "invalid command"); + return; + } +} diff --git a/src/fne/network/RESTAPI.h b/src/fne/network/RESTAPI.h index 4a5f6ac7..ff8279d9 100644 --- a/src/fne/network/RESTAPI.h +++ b/src/fne/network/RESTAPI.h @@ -74,7 +74,7 @@ private: bool m_debug; HostFNE* m_host; - network::FNENetwork *m_network; + network::FNENetwork* m_network; ::lookups::RadioIdLookup* m_ridLookup; ::lookups::TalkgroupRulesLookup* m_tidLookup; @@ -129,6 +129,20 @@ private: /// void restAPI_GetAffList(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match); + + /* + ** Digital Mobile Radio + */ + + /// + void restAPI_PutDMRRID(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match); + + /* + ** Project 25 + */ + + /// + void restAPI_PutP25RID(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match); }; #endif // __REST_API_H__ diff --git a/src/fne/network/fne/TagDMRData.cpp b/src/fne/network/fne/TagDMRData.cpp index 37551d28..e19d8bf4 100644 --- a/src/fne/network/fne/TagDMRData.cpp +++ b/src/fne/network/fne/TagDMRData.cpp @@ -336,6 +336,48 @@ void TagDMRData::playbackParrot() m_parrotFrames.pop_front(); } +/// +/// Helper to write a extended function packet on the RF interface. +/// +/// +/// +/// Extended function opcode. +/// Extended function argument. +/// Destination radio ID. +void TagDMRData::write_Ext_Func(uint32_t peerId, uint8_t slot, uint32_t func, uint32_t arg, uint32_t dstId) +{ + std::unique_ptr csbk = std::make_unique(); + csbk->setGI(false); + csbk->setExtendedFunction(func); + csbk->setSrcId(arg); + csbk->setDstId(dstId); + + LogMessage(LOG_NET, "DMR Slot %u, DT_CSBK, %s, op = $%02X, arg = %u, tgt = %u", + slot, csbk->toString().c_str(), func, arg, dstId); + + write_CSBK(peerId, slot, csbk.get()); +} + +/// +/// Helper to write a call alert packet on the RF interface. +/// +/// +/// +/// Source radio ID. +/// Destination radio ID. +void TagDMRData::write_Call_Alrt(uint32_t peerId, uint8_t slot, uint32_t srcId, uint32_t dstId) +{ + std::unique_ptr csbk = std::make_unique(); + csbk->setGI(false); + csbk->setSrcId(srcId); + csbk->setDstId(dstId); + + LogMessage(LOG_NET, "DMR Slot %u, DT_CSBK, %s, srcId = %u, dstId = %u", + slot, csbk->toString().c_str(), srcId, dstId); + + write_CSBK(peerId, slot, csbk.get()); +} + // --------------------------------------------------------------------------- // Private Class Members // --------------------------------------------------------------------------- @@ -561,15 +603,16 @@ void TagDMRData::write_CSBK_NACK_RSP(uint32_t peerId, uint32_t dstId, uint8_t re csbk->setSrcId(DMR_WUID_ALL); // hmmm... csbk->setDstId(dstId); - write_CSBK(peerId, csbk.get()); + write_CSBK(peerId, 1U, csbk.get()); } /// /// Helper to write a network CSBK. /// /// +/// /// -void TagDMRData::write_CSBK(uint32_t peerId, lc::CSBK* csbk) +void TagDMRData::write_CSBK(uint32_t peerId, uint8_t slot, lc::CSBK* csbk) { uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U]; ::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES); @@ -588,7 +631,7 @@ void TagDMRData::write_CSBK(uint32_t peerId, lc::CSBK* csbk) Sync::addDMRDataSync(data + 2U, true); data::Data dmrData; - dmrData.setSlotNo(1U); + dmrData.setSlotNo(slot); dmrData.setDataType(DT_CSBK); dmrData.setSrcId(csbk->getSrcId()); dmrData.setDstId(csbk->getDstId()); diff --git a/src/fne/network/fne/TagDMRData.h b/src/fne/network/fne/TagDMRData.h index 7551c02f..d5faab71 100644 --- a/src/fne/network/fne/TagDMRData.h +++ b/src/fne/network/fne/TagDMRData.h @@ -48,6 +48,11 @@ namespace network /// Helper to determine if there are stored parrot frames. bool hasParrotFrames() const { return m_parrotFramesReady && !m_parrotFrames.empty(); } + /// Helper to write a extended function packet on the RF interface. + void write_Ext_Func(uint32_t peerId, uint8_t slot, uint32_t func, uint32_t arg, uint32_t dstId); + /// Helper to write a call alert packet on the RF interface. + void write_Call_Alrt(uint32_t peerId, uint8_t slot, uint32_t srcId, uint32_t dstId); + private: FNENetwork* m_network; @@ -81,7 +86,7 @@ namespace network void write_CSBK_NACK_RSP(uint32_t peerId, uint32_t dstId, uint8_t reason, uint8_t service); /// Helper to write a network CSBK. - void write_CSBK(uint32_t peerId, dmr::lc::CSBK* csbk); + void write_CSBK(uint32_t peerId, uint8_t slot, dmr::lc::CSBK* csbk); }; } // namespace fne } // namespace network diff --git a/src/fne/network/fne/TagP25Data.cpp b/src/fne/network/fne/TagP25Data.cpp index d399e9c9..f0a41517 100644 --- a/src/fne/network/fne/TagP25Data.cpp +++ b/src/fne/network/fne/TagP25Data.cpp @@ -405,6 +405,94 @@ void TagP25Data::playbackParrot() m_parrotFrames.pop_front(); } +/// +/// Helper to write a call alert packet. +/// +/// +/// +/// +void TagP25Data::write_TSDU_Call_Alrt(uint32_t peerId, uint32_t srcId, uint32_t dstId) +{ + std::unique_ptr iosp = std::make_unique(); + iosp->setSrcId(srcId); + iosp->setDstId(dstId); + + LogMessage(LOG_NET, P25_TSDU_STR ", %s, srcId = %u, dstId = %u, txMult = %u", iosp->toString().c_str(), srcId, dstId); + + write_TSDU(peerId, iosp.get()); +} + +/// +/// Helper to write a radio monitor packet. +/// +/// +/// +/// +/// +void TagP25Data::write_TSDU_Radio_Mon(uint32_t peerId, uint32_t srcId, uint32_t dstId, uint8_t txMult) +{ + std::unique_ptr iosp = std::make_unique(); + iosp->setSrcId(srcId); + iosp->setDstId(dstId); + iosp->setTxMult(txMult); + + LogMessage(LOG_NET, P25_TSDU_STR ", %s, srcId = %u, dstId = %u, txMult = %u", iosp->toString().c_str(), srcId, dstId, txMult); + + write_TSDU(peerId, iosp.get()); +} + +/// +/// Helper to write a extended function packet. +/// +/// +/// +/// +/// +void TagP25Data::write_TSDU_Ext_Func(uint32_t peerId, uint32_t func, uint32_t arg, uint32_t dstId) +{ + std::unique_ptr iosp = std::make_unique(); + iosp->setExtendedFunction(func); + iosp->setSrcId(arg); + iosp->setDstId(dstId); + + LogMessage(LOG_NET, P25_TSDU_STR ", %s, op = $%02X, arg = %u, tgt = %u", + iosp->toString().c_str(), iosp->getExtendedFunction(), iosp->getSrcId(), iosp->getDstId()); + + write_TSDU(peerId, iosp.get()); +} + +/// +/// Helper to write a group affiliation query packet. +/// +/// +/// +void TagP25Data::write_TSDU_Grp_Aff_Q(uint32_t peerId, uint32_t dstId) +{ + std::unique_ptr osp = std::make_unique(); + osp->setSrcId(P25_WUID_FNE); + osp->setDstId(dstId); + + LogMessage(LOG_NET, P25_TSDU_STR ", %s, dstId = %u", osp->toString().c_str(), dstId); + + write_TSDU(peerId, osp.get()); +} + +/// +/// Helper to write a unit registration command packet. +/// +/// +/// +void TagP25Data::write_TSDU_U_Reg_Cmd(uint32_t peerId, uint32_t dstId) +{ + std::unique_ptr osp = std::make_unique(); + osp->setSrcId(P25_WUID_FNE); + osp->setDstId(dstId); + + LogMessage(LOG_NET, P25_TSDU_STR ", %s, dstId = %u", osp->toString().c_str(), dstId); + + write_TSDU(peerId, osp.get()); +} + // --------------------------------------------------------------------------- // Private Class Members // --------------------------------------------------------------------------- diff --git a/src/fne/network/fne/TagP25Data.h b/src/fne/network/fne/TagP25Data.h index 819fc3f1..cd7c83e9 100644 --- a/src/fne/network/fne/TagP25Data.h +++ b/src/fne/network/fne/TagP25Data.h @@ -53,6 +53,17 @@ namespace network /// Helper to determine if there are stored parrot frames. bool hasParrotFrames() const { return m_parrotFramesReady && !m_parrotFrames.empty(); } + /// Helper to write a call alert packet. + void write_TSDU_Call_Alrt(uint32_t peerId, uint32_t srcId, uint32_t dstId); + /// Helper to write a radio monitor packet. + void write_TSDU_Radio_Mon(uint32_t peerId, uint32_t srcId, uint32_t dstId, uint8_t txMult); + /// Helper to write a extended function packet. + void write_TSDU_Ext_Func(uint32_t peerId, uint32_t func, uint32_t arg, uint32_t dstId); + /// Helper to write a group affiliation query packet. + void write_TSDU_Grp_Aff_Q(uint32_t peerId, uint32_t dstId); + /// Helper to write a unit registration command packet. + void write_TSDU_U_Reg_Cmd(uint32_t peerId, uint32_t dstId); + private: FNENetwork* m_network; diff --git a/src/host/network/RESTAPI.cpp b/src/host/network/RESTAPI.cpp index 3ed65697..be488e1e 100644 --- a/src/host/network/RESTAPI.cpp +++ b/src/host/network/RESTAPI.cpp @@ -1675,7 +1675,7 @@ void RESTAPI::restAPI_PutTSCCPayloadActivate(const HTTPPayload& request, HTTPPay uint8_t slot = req["slot"].get(); bool clear = req["clear"].get(); - if (slot == 0U && slot >= 3U) { + if (slot == 0U || slot >= 3U) { errorPayload(reply, "invalid DMR slot number (slot == 0 or slot > 3)"); return; } diff --git a/src/remote/RESTClientMain.cpp b/src/remote/RESTClientMain.cpp index 1bac4df1..cf4069e1 100644 --- a/src/remote/RESTClientMain.cpp +++ b/src/remote/RESTClientMain.cpp @@ -75,6 +75,10 @@ #define RCD_DMR_RID_CHECK "dmr-rid-check" #define RCD_DMR_RID_INHIBIT "dmr-rid-inhibit" #define RCD_DMR_RID_UNINHIBIT "dmr-rid-uninhibit" +#define RCD_FNE_DMR_RID_PAGE "fne-dmr-rid-page" +#define RCD_FNE_DMR_RID_CHECK "fne-dmr-rid-check" +#define RCD_FNE_DMR_RID_INHIBIT "fne-dmr-rid-inhibit" +#define RCD_FNE_DMR_RID_UNINHIBIT "fne-dmr-rid-uninhibit" #define RCD_P25_SET_MFID "p25-set-mfid" #define RCD_P25_RID_PAGE "p25-rid-page" @@ -83,6 +87,12 @@ #define RCD_P25_RID_UNINHIBIT "p25-rid-uninhibit" #define RCD_P25_RID_GAQ "p25-rid-gaq" #define RCD_P25_RID_UREG "p25-rid-ureg" +#define RCD_FNE_P25_RID_PAGE "fne-p25-rid-page" +#define RCD_FNE_P25_RID_CHECK "fne-p25-rid-check" +#define RCD_FNE_P25_RID_INHIBIT "fne-p25-rid-inhibit" +#define RCD_FNE_P25_RID_UNINHIBIT "fne-p25-rid-uninhibit" +#define RCD_FNE_P25_RID_GAQ "fne-p25-rid-gaq" +#define RCD_FNE_P25_RID_UREG "fne-p25-rid-ureg" #define RCD_DMR_CC_DEDICATED "dmr-cc-dedicated" #define RCD_DMR_CC_BCAST "dmr-cc-bcast" @@ -217,10 +227,10 @@ void usage(const char* message, const char* arg) reply += " nxdn-debug \r\n"; reply += " nxdn-dump-rcch <0/1>\r\n"; reply += "\r\nDMR Commands:\r\n"; - reply += " dmr-rid-page Pages/Calls the specified RID\r\n"; - reply += " dmr-rid-check Radio Checks the specified RID\r\n"; - reply += " dmr-rid-inhibit Inhibits the specified RID\r\n"; - reply += " dmr-rid-uninhibit Uninhibits the specified RID\r\n"; + reply += " dmr-rid-page Pages/Calls the specified RID\r\n"; + reply += " dmr-rid-check Radio Checks the specified RID\r\n"; + reply += " dmr-rid-inhibit Inhibits the specified RID\r\n"; + reply += " dmr-rid-uninhibit Uninhibits the specified RID\r\n"; reply += "\r\n"; reply += " dmr-cc-dedicated Enables or disables dedicated control channel\r\n"; reply += " dmr-cc-bcast Enables or disables broadcast of the control channel\r\n"; @@ -558,7 +568,7 @@ int main(int argc, char** argv) retCode = client->send(HTTP_GET, GET_DMR_DUMP_CSBK_BASE + std::to_string(verbose), json::object(), response); } } - else if (rcom == RCD_DMR_RID_PAGE && argCnt >= 2U) { + else if ((rcom == RCD_DMR_RID_PAGE || rcom == RCD_FNE_DMR_RID_PAGE) && argCnt >= 2U) { json::object req = json::object(); req["command"].set(std::string(RID_CMD_PAGE)); uint8_t slotNo = getArgInt8(args, 0U); @@ -566,9 +576,14 @@ int main(int argc, char** argv) uint32_t dstId = getArgUInt32(args, 1U); req["dstId"].set(dstId); + if (rcom == RCD_FNE_DMR_RID_PAGE) { + uint32_t peerId = getArgUInt32(args, 2U); + req["peerId"].set(peerId); + } + retCode = client->send(HTTP_PUT, PUT_DMR_RID, req, response); } - else if (rcom == RCD_DMR_RID_CHECK && argCnt >= 2U) { + else if ((rcom == RCD_DMR_RID_CHECK || rcom == RCD_FNE_DMR_RID_CHECK) && argCnt >= 2U) { json::object req = json::object(); req["command"].set(std::string(RID_CMD_CHECK)); uint8_t slotNo = getArgInt8(args, 0U); @@ -576,9 +591,14 @@ int main(int argc, char** argv) uint32_t dstId = getArgUInt32(args, 1U); req["dstId"].set(dstId); + if (rcom == RCD_FNE_DMR_RID_CHECK) { + uint32_t peerId = getArgUInt32(args, 2U); + req["peerId"].set(peerId); + } + retCode = client->send(HTTP_PUT, PUT_DMR_RID, req, response); } - else if (rcom == RCD_DMR_RID_INHIBIT && argCnt >= 2U) { + else if ((rcom == RCD_DMR_RID_INHIBIT || rcom == RCD_FNE_DMR_RID_INHIBIT) && argCnt >= 2U) { json::object req = json::object(); req["command"].set(std::string(RID_CMD_INHIBIT)); uint8_t slotNo = getArgInt8(args, 0U); @@ -586,9 +606,14 @@ int main(int argc, char** argv) uint32_t dstId = getArgUInt32(args, 1U); req["dstId"].set(dstId); + if (rcom == RCD_FNE_DMR_RID_INHIBIT) { + uint32_t peerId = getArgUInt32(args, 2U); + req["peerId"].set(peerId); + } + retCode = client->send(HTTP_PUT, PUT_DMR_RID, req, response); } - else if (rcom == RCD_DMR_RID_UNINHIBIT && argCnt >= 2U) { + else if ((rcom == RCD_DMR_RID_UNINHIBIT || rcom == RCD_FNE_DMR_RID_UNINHIBIT) && argCnt >= 2U) { json::object req = json::object(); req["command"].set(std::string(RID_CMD_UNINHIBIT)); uint8_t slotNo = getArgInt8(args, 0U); @@ -596,6 +621,11 @@ int main(int argc, char** argv) uint32_t dstId = getArgUInt32(args, 1U); req["dstId"].set(dstId); + if (rcom == RCD_FNE_DMR_RID_UNINHIBIT) { + uint32_t peerId = getArgUInt32(args, 2U); + req["peerId"].set(peerId); + } + retCode = client->send(HTTP_PUT, PUT_DMR_RID, req, response); } else if (rcom == RCD_DMR_CC_DEDICATED) { @@ -642,52 +672,82 @@ int main(int argc, char** argv) retCode = client->send(HTTP_PUT, PUT_P25_RID, req, response); } - else if (rcom == RCD_P25_RID_PAGE && argCnt >= 1U) { + else if ((rcom == RCD_P25_RID_PAGE || rcom == RCD_FNE_P25_RID_PAGE) && argCnt >= 1U) { json::object req = json::object(); req["command"].set(std::string(RID_CMD_PAGE)); uint32_t dstId = getArgUInt32(args, 0U); req["dstId"].set(dstId); + if (rcom == RCD_FNE_P25_RID_PAGE) { + uint32_t peerId = getArgUInt32(args, 2U); + req["peerId"].set(peerId); + } + retCode = client->send(HTTP_PUT, PUT_P25_RID, req, response); } - else if (rcom == RCD_P25_RID_CHECK && argCnt >= 1U) { + else if ((rcom == RCD_P25_RID_CHECK || rcom == RCD_FNE_P25_RID_CHECK) && argCnt >= 1U) { json::object req = json::object(); req["command"].set(std::string(RID_CMD_CHECK)); uint32_t dstId = getArgUInt32(args, 0U); req["dstId"].set(dstId); + if (rcom == RCD_P25_RID_CHECK) { + uint32_t peerId = getArgUInt32(args, 2U); + req["peerId"].set(peerId); + } + retCode = client->send(HTTP_PUT, PUT_P25_RID, req, response); } - else if (rcom == RCD_P25_RID_INHIBIT && argCnt >= 1U) { + else if ((rcom == RCD_P25_RID_INHIBIT || rcom == RCD_FNE_P25_RID_INHIBIT) && argCnt >= 1U) { json::object req = json::object(); req["command"].set(std::string(RID_CMD_INHIBIT)); uint32_t dstId = getArgUInt32(args, 0U); req["dstId"].set(dstId); + if (rcom == RCD_FNE_P25_RID_INHIBIT) { + uint32_t peerId = getArgUInt32(args, 2U); + req["peerId"].set(peerId); + } + retCode = client->send(HTTP_PUT, PUT_P25_RID, req, response); } - else if (rcom == RCD_P25_RID_UNINHIBIT && argCnt >= 1U) { + else if ((rcom == RCD_P25_RID_UNINHIBIT || rcom == RCD_FNE_P25_RID_UNINHIBIT) && argCnt >= 1U) { json::object req = json::object(); req["command"].set(std::string(RID_CMD_UNINHIBIT)); uint32_t dstId = getArgUInt32(args, 0U); req["dstId"].set(dstId); + if (rcom == RCD_FNE_P25_RID_UNINHIBIT) { + uint32_t peerId = getArgUInt32(args, 2U); + req["peerId"].set(peerId); + } + retCode = client->send(HTTP_PUT, PUT_P25_RID, req, response); } - else if (rcom == RCD_P25_RID_GAQ && argCnt >= 1U) { + else if ((rcom == RCD_P25_RID_GAQ || rcom == RCD_FNE_P25_RID_GAQ) && argCnt >= 1U) { json::object req = json::object(); req["command"].set(std::string(RID_CMD_GAQ)); uint32_t dstId = getArgUInt32(args, 0U); req["dstId"].set(dstId); + if (rcom == RCD_FNE_P25_RID_GAQ) { + uint32_t peerId = getArgUInt32(args, 2U); + req["peerId"].set(peerId); + } + retCode = client->send(HTTP_PUT, PUT_P25_RID, req, response); } - else if (rcom == RCD_P25_RID_UREG && argCnt >= 1U) { + else if ((rcom == RCD_P25_RID_UREG || rcom == RCD_FNE_P25_RID_UREG) && argCnt >= 1U) { json::object req = json::object(); req["command"].set(std::string(RID_CMD_UREG)); uint32_t dstId = getArgUInt32(args, 0U); req["dstId"].set(dstId); + if (rcom == RCD_FNE_P25_RID_UREG) { + uint32_t peerId = getArgUInt32(args, 2U); + req["peerId"].set(peerId); + } + retCode = client->send(HTTP_PUT, PUT_P25_RID, req, response); } else if (rcom == RCD_P25_CC_DEDICATED) {