You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
694 lines
27 KiB
694 lines
27 KiB
/**
|
|
* Digital Voice Modem - Host Software
|
|
* GPLv2 Open Source. Use is subject to license terms.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* @package DVM / Host Software
|
|
*
|
|
*/
|
|
//
|
|
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
|
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
|
//
|
|
/*
|
|
* Copyright (C) 2019 by Jonathan Naylor G4KLX
|
|
* Copyright (C) 2019 by Bryan Biedenkapp N2PLL
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
#include "Defines.h"
|
|
#include "RemoteControl.h"
|
|
#include "HostMain.h"
|
|
#include "Log.h"
|
|
#include "Utils.h"
|
|
|
|
using namespace network;
|
|
using namespace modem;
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cassert>
|
|
#include <cstring>
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Constants
|
|
// ---------------------------------------------------------------------------
|
|
|
|
#define BAD_CMD_STR "Bad or invalid remote command."
|
|
#define INVALID_OPT_STR "Invalid command arguments: "
|
|
#define CMD_FAILED_STR "Remote command failed: "
|
|
|
|
#define RCD_MODE_CMD "mdm-mode"
|
|
#define RCD_MODE_OPT_IDLE "idle"
|
|
#define RCD_MODE_OPT_LCKOUT "lockout"
|
|
#define RCD_MODE_OPT_FDMR "dmr"
|
|
#define RCD_MODE_OPT_FP25 "p25"
|
|
|
|
#define RCD_KILL_CMD "mdm-kill"
|
|
|
|
#define RCD_RID_WLIST_CMD "rid-whitelist"
|
|
#define RCD_RID_BLIST_CMD "rid-blacklist"
|
|
|
|
#define RCD_DMR_BEACON_CMD "dmr-beacon"
|
|
#define RCD_P25_CC_CMD "p25-cc"
|
|
|
|
#define RCD_DMRD_MDM_INJ_CMD "dmrd-mdm-inj"
|
|
#define RCD_P25D_MDM_INJ_CMD "p25d-mdm-inj"
|
|
|
|
#define RCD_DMR_RID_PAGE_CMD "dmr-rid-page"
|
|
#define RCD_DMR_RID_CHECK_CMD "dmr-rid-check"
|
|
#define RCD_DMR_RID_INHIBIT_CMD "dmr-rid-inhibit"
|
|
#define RCD_DMR_RID_UNINHIBIT_CMD "dmr-rid-uninhibit"
|
|
|
|
#define RCD_P25_SET_MFID_CMD "p25-set-mfid"
|
|
#define RCD_P25_RID_PAGE_CMD "p25-rid-page"
|
|
#define RCD_P25_RID_CHECK_CMD "p25-rid-check"
|
|
#define RCD_P25_RID_INHIBIT_CMD "p25-rid-inhibit"
|
|
#define RCD_P25_RID_UNINHIBIT_CMD "p25-rid-uninhibit"
|
|
#define RCD_P25_RID_GAQ_CMD "p25-rid-gaq"
|
|
#define RCD_P25_RID_UREG_CMD "p25-rid-ureg"
|
|
|
|
#define RCD_P25_PATCH_CMD "p25-patch"
|
|
|
|
#define RCD_P25_RELEASE_GRANTS "p25-rel-grnts"
|
|
|
|
const uint32_t RC_BUFFER_LENGTH = 100U;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Public Class Members
|
|
// ---------------------------------------------------------------------------
|
|
/// <summary>
|
|
/// Initializes a new instance of the RemoteControl class.
|
|
/// </summary>
|
|
/// <param name="address">Network Hostname/IP address to connect to.</param>
|
|
/// <param name="port">Network port number.</param>
|
|
RemoteControl::RemoteControl(const std::string& address, uint32_t port) :
|
|
m_socket(address, port),
|
|
m_p25MFId(p25::P25_MFG_STANDARD)
|
|
{
|
|
assert(!address.empty());
|
|
assert(port > 0U);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finalizes a instance of the RemoteControl class.
|
|
/// </summary>
|
|
RemoteControl::~RemoteControl()
|
|
{
|
|
/* stub */
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the instances of the Radio ID and Talkgroup ID lookup tables.
|
|
/// </summary>
|
|
/// <param name="ridLookup">Radio ID Lookup Table Instance</param>
|
|
/// <param name="tidLookup">Talkgroup ID Lookup Table Instance</param>
|
|
void RemoteControl::setLookups(lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup)
|
|
{
|
|
m_ridLookup = ridLookup;
|
|
m_tidLookup = tidLookup;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Process remote network command data.
|
|
/// </summary>
|
|
/// <param name="host">Instance of the Host class.</param>
|
|
/// <param name="dmr">Instance of the Control class.</param>
|
|
/// <param name="p25">Instance of the Control class.</param>
|
|
void RemoteControl::process(Host* host, dmr::Control* dmr, p25::Control* p25)
|
|
{
|
|
std::vector<std::string> args = std::vector<std::string>();
|
|
args.clear();
|
|
|
|
char buffer[RC_BUFFER_LENGTH];
|
|
in_addr address;
|
|
uint32_t port;
|
|
|
|
int ret = m_socket.read((uint8_t*)buffer, RC_BUFFER_LENGTH, address, port);
|
|
if (ret > 0) {
|
|
buffer[ret] = '\0';
|
|
|
|
// parse the original command into a vector of strings.
|
|
char* b = buffer;
|
|
char* p = NULL;
|
|
while ((p = ::strtok(b, " ")) != NULL) {
|
|
b = NULL;
|
|
args.push_back(std::string(p));
|
|
}
|
|
|
|
if (args.size() < 1 || args.at(0U) == "") {
|
|
args.clear();
|
|
LogWarning(LOG_RCON, BAD_CMD_STR);
|
|
}
|
|
else {
|
|
std::string rcom = args.at(0);
|
|
|
|
// process command
|
|
if (rcom == RCD_MODE_CMD && args.size() >= 1U) {
|
|
// Command is in the form of: "mode <mode>"
|
|
if (args.at(1U) == RCD_MODE_OPT_IDLE) {
|
|
host->m_fixedMode = false;
|
|
host->setMode(STATE_IDLE);
|
|
}
|
|
else if (args.at(1U) == RCD_MODE_OPT_LCKOUT) {
|
|
host->m_fixedMode = false;
|
|
host->setMode(HOST_STATE_LOCKOUT);
|
|
}
|
|
else if (args.at(1U) == RCD_MODE_OPT_FDMR) {
|
|
if (dmr != NULL) {
|
|
host->m_fixedMode = true;
|
|
host->setMode(STATE_DMR);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "DMR mode is not enabled!");
|
|
}
|
|
}
|
|
else if (args.at(1U) == RCD_MODE_OPT_FP25) {
|
|
if (p25 != NULL) {
|
|
host->m_fixedMode = true;
|
|
host->setMode(STATE_P25);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!");
|
|
}
|
|
}
|
|
}
|
|
else if (rcom == RCD_KILL_CMD) {
|
|
// Command is in the form of: "kill"
|
|
g_killed = true;
|
|
host->setMode(HOST_STATE_QUIT);
|
|
}
|
|
else if (rcom == RCD_RID_WLIST_CMD && args.size() >= 1U) {
|
|
// Command is in the form of: "rid-whitelist <RID>"
|
|
uint32_t srcId = getArgUInt32(args, 0U);
|
|
if (srcId != 0U) {
|
|
m_ridLookup->toggleEntry(srcId, true);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "tried to whitelist RID 0!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_RID_BLIST_CMD && args.size() >= 1U) {
|
|
// Command is in the form of: "rid-blacklist <RID>"
|
|
uint32_t srcId = getArgUInt32(args, 0U);
|
|
if (srcId != 0U) {
|
|
m_ridLookup->toggleEntry(srcId, false);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "tried to blacklist RID 0!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_DMR_BEACON_CMD) {
|
|
// Command is in the form of: "dmr-beacon"
|
|
if (dmr != NULL) {
|
|
g_fireDMRBeacon = true;
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "DMR mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_P25_CC_CMD) {
|
|
// Command is in the form of: "p25-cc"
|
|
if (p25 != NULL) {
|
|
g_fireP25Control = true;
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_DMRD_MDM_INJ_CMD && args.size() >= 1U) {
|
|
// Command is in the form of: "dmrd-mdm-inj <slot> <bin file>
|
|
if (dmr != NULL) {
|
|
uint8_t slot = getArgUInt32(args, 0U);
|
|
const char* fileName = getArgString(args, 1U).c_str();
|
|
if (fileName != NULL) {
|
|
FILE* file = ::fopen(fileName, "r");
|
|
if (file != NULL) {
|
|
uint8_t* buffer = NULL;
|
|
int32_t fileSize = 0;
|
|
|
|
// obtain file size
|
|
::fseek(file, 0, SEEK_END);
|
|
fileSize = ::ftell(file);
|
|
::rewind(file);
|
|
|
|
// allocate a buffer and read file
|
|
buffer = new uint8_t[fileSize];
|
|
if (buffer != NULL) {
|
|
int32_t bytes = ::fread(buffer, 1U, fileSize, file);
|
|
if (bytes == fileSize) {
|
|
uint8_t sync[dmr::DMR_SYNC_LENGTH_BYTES];
|
|
::memcpy(sync, buffer, dmr::DMR_SYNC_LENGTH_BYTES);
|
|
|
|
// count data sync errors
|
|
uint8_t dataErrs = 0U;
|
|
for (uint8_t i = 0U; i < dmr::DMR_SYNC_LENGTH_BYTES; i++)
|
|
dataErrs += Utils::countBits8(sync[i] ^ dmr::DMR_MS_DATA_SYNC_BYTES[i]);
|
|
|
|
// count voice sync errors
|
|
uint8_t voiceErrs = 0U;
|
|
for (uint8_t i = 0U; i < dmr::DMR_SYNC_LENGTH_BYTES; i++)
|
|
voiceErrs += Utils::countBits8(sync[i] ^ dmr::DMR_MS_VOICE_SYNC_BYTES[i]);
|
|
|
|
if ((dataErrs <= 4U) || (voiceErrs <= 4U)) {
|
|
if (slot == 0U) {
|
|
host->m_modem->injectDMRData1(buffer, fileSize);
|
|
}
|
|
else if (slot == 1U) {
|
|
host->m_modem->injectDMRData2(buffer, fileSize);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "invalid DMR slot!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "DMR data has too many errors!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "DMR failed to open DMR data!");
|
|
}
|
|
|
|
delete buffer;
|
|
}
|
|
|
|
::fclose(file);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "DMR mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_P25D_MDM_INJ_CMD && args.size() >= 1U) {
|
|
// Command is in the form of: "p25d-mdm-inj <bin file>
|
|
if (p25 != NULL) {
|
|
const char* fileName = getArgString(args, 0U).c_str();
|
|
if (fileName != NULL) {
|
|
FILE* file = ::fopen(fileName, "r");
|
|
if (file != NULL) {
|
|
uint8_t* buffer = NULL;
|
|
int32_t fileSize = 0;
|
|
|
|
// obtain file size
|
|
::fseek(file, 0, SEEK_END);
|
|
fileSize = ::ftell(file);
|
|
::rewind(file);
|
|
|
|
// allocate a buffer and read file
|
|
buffer = new uint8_t[fileSize];
|
|
if (buffer != NULL) {
|
|
int32_t bytes = ::fread(buffer, 1U, fileSize, file);
|
|
if (bytes == fileSize) {
|
|
uint8_t sync[p25::P25_SYNC_LENGTH_BYTES];
|
|
::memcpy(sync, buffer, p25::P25_SYNC_LENGTH_BYTES);
|
|
|
|
uint8_t errs = 0U;
|
|
for (uint8_t i = 0U; i < p25::P25_SYNC_LENGTH_BYTES; i++)
|
|
errs += Utils::countBits8(sync[i] ^ p25::P25_SYNC_BYTES[i]);
|
|
|
|
if (errs <= 4U) {
|
|
bool valid = p25->nid().decode(buffer);
|
|
if (valid) {
|
|
host->m_modem->injectP25Data(buffer, fileSize);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "P25 data did not contain a valid NID!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "P25 data has too many errors!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "P25 failed to open P25 data!");
|
|
}
|
|
|
|
delete buffer;
|
|
}
|
|
|
|
::fclose(file);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_DMR_RID_PAGE_CMD && args.size() >= 2U) {
|
|
// Command is in the form of: "dmr-rid-page <slot> <RID>"
|
|
if (dmr != NULL) {
|
|
uint32_t slotNo = getArgUInt32(args, 0U);
|
|
uint32_t dstId = getArgUInt32(args, 1U);
|
|
if (slotNo > 0U && slotNo < 3U) {
|
|
if (dstId != 0U) {
|
|
dmr->writeRF_Call_Alrt(slotNo, p25::P25_WUID_SYS, dstId);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "tried to DMR call alert RID 0!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "invalid DMR slot number for call alert!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "DMR mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_DMR_RID_CHECK_CMD && args.size() >= 2U) {
|
|
// Command is in the form of: "dmr-rid-check <slot> <RID>"
|
|
if (dmr != NULL) {
|
|
uint32_t slotNo = getArgUInt32(args, 0U);
|
|
uint32_t dstId = getArgUInt32(args, 1U);
|
|
if (slotNo > 0U && slotNo < 3U) {
|
|
if (dstId != 0U) {
|
|
dmr->writeRF_Ext_Func(slotNo, dmr::DMR_EXT_FNCT_CHECK, p25::P25_WUID_SYS, dstId);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "tried to DMR radio check RID 0!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "invalid DMR slot number for radio check!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "DMR mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_DMR_RID_INHIBIT_CMD && args.size() >= 2U) {
|
|
// Command is in the form of: "dmr-rid-inhibit <slot> <RID>"
|
|
if (dmr != NULL) {
|
|
uint32_t slotNo = getArgUInt32(args, 0U);
|
|
uint32_t dstId = getArgUInt32(args, 1U);
|
|
if (slotNo > 0U && slotNo < 3U) {
|
|
if (dstId != 0U) {
|
|
dmr->writeRF_Ext_Func(slotNo, dmr::DMR_EXT_FNCT_INHIBIT, p25::P25_WUID_SYS, dstId);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "tried to DMR radio inhibit RID 0!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "invalid DMR slot number for radio inhibit!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "DMR mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_DMR_RID_UNINHIBIT_CMD && args.size() >= 2U) {
|
|
// Command is in the form of: "dmr-rid-uninhibit <slot> <RID>"
|
|
if (dmr != NULL) {
|
|
uint32_t slotNo = getArgUInt32(args, 0U);
|
|
uint32_t dstId = getArgUInt32(args, 1U);
|
|
if (slotNo > 0U && slotNo < 3U) {
|
|
if (dstId != 0U) {
|
|
dmr->writeRF_Ext_Func(slotNo, dmr::DMR_EXT_FNCT_UNINHIBIT, p25::P25_WUID_SYS, dstId);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "tried to DMR radio uninhibit RID 0!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "invalid DMR slot number for radio uninhibit!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "DMR mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_P25_SET_MFID_CMD && args.size() >= 1U) {
|
|
// Command is in the form of: "p25-set-mfid <Mfg. ID>
|
|
if (p25 != NULL) {
|
|
uint8_t mfId = getArgUInt8(args, 0U);
|
|
if (mfId != 0U) {
|
|
LogMessage(LOG_RCON, "Remote P25, mfgId = $%02X", mfId);
|
|
m_p25MFId = mfId;
|
|
}
|
|
else {
|
|
LogMessage(LOG_RCON, "Remote P25, mfgId reset, mfgId = $%02X", mfId);
|
|
m_p25MFId = p25::P25_MFG_STANDARD;
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_P25_RID_PAGE_CMD && args.size() >= 1U) {
|
|
// Command is in the form of: "p25-rid-page <RID>"
|
|
if (p25 != NULL) {
|
|
uint32_t dstId = getArgUInt32(args, 0U);
|
|
if (dstId != 0U) {
|
|
p25->trunk()->setMFId(m_p25MFId);
|
|
p25->trunk()->writeRF_TSDU_Call_Alrt(p25::P25_WUID_SYS, dstId);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "tried to P25 call alert RID 0!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_P25_RID_CHECK_CMD && args.size() >= 1U) {
|
|
// Command is in the form of: "p25-rid-check <RID>"
|
|
if (p25 != NULL) {
|
|
uint32_t dstId = getArgUInt32(args, 0U);
|
|
if (dstId != 0U) {
|
|
p25->trunk()->setMFId(m_p25MFId);
|
|
p25->trunk()->writeRF_TSDU_Ext_Func(p25::P25_EXT_FNCT_CHECK, p25::P25_WUID_SYS, dstId);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "tried to P25 radio check RID 0!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_P25_RID_INHIBIT_CMD && args.size() >= 1U) {
|
|
// Command is in the form of: "p25-rid-inhibit <RID>"
|
|
if (p25 != NULL) {
|
|
uint32_t dstId = getArgUInt32(args, 0U);
|
|
if (dstId != 0U) {
|
|
p25->trunk()->setMFId(m_p25MFId);
|
|
p25->trunk()->writeRF_TSDU_Ext_Func(p25::P25_EXT_FNCT_INHIBIT, p25::P25_WUID_SYS, dstId);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "tried to P25 inhibit RID 0!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_P25_RID_UNINHIBIT_CMD && args.size() >= 1U) {
|
|
// Command is in the form of: "p25-rid-uninhibit <RID>"
|
|
if (p25 != NULL) {
|
|
uint32_t dstId = getArgUInt32(args, 0U);
|
|
if (dstId != 0U) {
|
|
p25->trunk()->setMFId(m_p25MFId);
|
|
p25->trunk()->writeRF_TSDU_Ext_Func(p25::P25_EXT_FNCT_UNINHIBIT, p25::P25_WUID_SYS, dstId);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "tried to P25 uninhibit RID 0!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_P25_RID_GAQ_CMD && args.size() >= 1U) {
|
|
// Command is in the form of: "p25-rid-gaq <RID>"
|
|
if (p25 != NULL) {
|
|
uint32_t dstId = getArgUInt32(args, 0U);
|
|
if (dstId != 0U) {
|
|
p25->trunk()->setMFId(m_p25MFId);
|
|
p25->trunk()->writeRF_TSDU_Grp_Aff_Q(dstId);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "tried to P25 grp aff. query RID 0!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_P25_RID_UREG_CMD && args.size() >= 1U) {
|
|
// Command is in the form of: "p25-rid-ureg <RID>"
|
|
if (p25 != NULL) {
|
|
uint32_t dstId = getArgUInt32(args, 0U);
|
|
if (dstId != 0U) {
|
|
p25->trunk()->setMFId(m_p25MFId);
|
|
p25->trunk()->writeRF_TSDU_U_Reg_Cmd(dstId);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "tried to P25 unit reg. command RID 0!");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_P25_PATCH_CMD && args.size() >= 1U) {
|
|
// Command is in the form of: "p25-patch <group 1> <group 2> <group 3>"
|
|
if (p25 != NULL) {
|
|
uint32_t group1 = getArgUInt32(args, 0U);
|
|
uint32_t group2 = getArgUInt32(args, 1U);
|
|
uint32_t group3 = getArgUInt32(args, 2U);
|
|
|
|
if (group1 != 0U) {
|
|
p25->trunk()->setMFId(m_p25MFId);
|
|
p25->trunk()->writeRF_TSDU_Mot_Patch(group1, group2, group3);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, INVALID_OPT_STR "tried to add P25 group patch with no TGID?");
|
|
}
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!");
|
|
}
|
|
}
|
|
else if (rcom == RCD_P25_RELEASE_GRANTS) {
|
|
// Command is in the form of: "p25-rel-grnts"
|
|
if (p25 != NULL) {
|
|
p25->trunk()->releaseDstIdGrant(0, true);
|
|
}
|
|
else {
|
|
LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!");
|
|
}
|
|
}
|
|
else {
|
|
args.clear();
|
|
LogError(LOG_RCON, BAD_CMD_STR " (\"%s\")", rcom.c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Opens connection to the network.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
bool RemoteControl::open()
|
|
{
|
|
return m_socket.open();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Closes connection to the network.
|
|
/// </summary>
|
|
void RemoteControl::close()
|
|
{
|
|
m_socket.close();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Private Class Members
|
|
// ---------------------------------------------------------------------------
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="args"></param>
|
|
/// <param name="n"></param>
|
|
/// <returns></returns>
|
|
std::string RemoteControl::getArgString(std::vector<std::string> args, uint32_t n) const
|
|
{
|
|
n += 1;
|
|
if (n >= args.size())
|
|
return "";
|
|
|
|
return args.at(n);
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="args"></param>
|
|
/// <param name="n"></param>
|
|
/// <returns></returns>
|
|
uint64_t RemoteControl::getArgUInt64(std::vector<std::string> args, uint32_t n) const
|
|
{
|
|
return (uint64_t)::atol(getArgString(args, n).c_str());
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="args"></param>
|
|
/// <param name="n"></param>
|
|
/// <returns></returns>
|
|
uint32_t RemoteControl::getArgUInt32(std::vector<std::string> args, uint32_t n) const
|
|
{
|
|
return (uint32_t)::atoi(getArgString(args, n).c_str());
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="args"></param>
|
|
/// <param name="n"></param>
|
|
/// <returns></returns>
|
|
int32_t RemoteControl::getArgInt32(std::vector<std::string> args, uint32_t n) const
|
|
{
|
|
return ::atoi(getArgString(args, n).c_str());
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="args"></param>
|
|
/// <param name="n"></param>
|
|
/// <returns></returns>
|
|
uint16_t RemoteControl::getArgUInt16(std::vector<std::string> args, uint32_t n) const
|
|
{
|
|
return (uint16_t)::atoi(getArgString(args, n).c_str());
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="args"></param>
|
|
/// <param name="n"></param>
|
|
/// <returns></returns>
|
|
int16_t RemoteControl::getArgInt16(std::vector<std::string> args, uint32_t n) const
|
|
{
|
|
return (int16_t)::atoi(getArgString(args, n).c_str());
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="args"></param>
|
|
/// <param name="n"></param>
|
|
/// <returns></returns>
|
|
uint8_t RemoteControl::getArgUInt8(std::vector<std::string> args, uint32_t n) const
|
|
{
|
|
return (uint8_t)::atoi(getArgString(args, n).c_str());
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="args"></param>
|
|
/// <param name="n"></param>
|
|
/// <returns></returns>
|
|
int8_t RemoteControl::getArgInt8(std::vector<std::string> args, uint32_t n) const
|
|
{
|
|
return (int8_t)::atoi(getArgString(args, n).c_str());
|
|
}
|