initial bare-bones implementation of dvmmon; enhance REST API to return more detailed status information (for use by dvmmon); cleanup file code style;
parent
298cd8da1f
commit
d45af90c07
@ -0,0 +1,25 @@
|
|||||||
|
#
|
||||||
|
# Digital Voice Modem - Monitor Configuration
|
||||||
|
#
|
||||||
|
# @package DVM / Monitor
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Channel Identity Table Configuration
|
||||||
|
#
|
||||||
|
iden_table:
|
||||||
|
# Full path to the identity table file.
|
||||||
|
file: iden_table.dat
|
||||||
|
# Amount of time between updates of identity table file. (minutes)
|
||||||
|
time: 30
|
||||||
|
|
||||||
|
#
|
||||||
|
# DVM Channels to Monitor
|
||||||
|
#
|
||||||
|
channels:
|
||||||
|
# REST API IP Address for channel.
|
||||||
|
- restAddress: 127.0.0.1
|
||||||
|
# REST API Port number for channel.
|
||||||
|
restPort: 9990
|
||||||
|
# REST API access password for channel.
|
||||||
|
restPassword: "PASSWORD"
|
||||||
@ -0,0 +1,144 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.
|
||||||
|
*/
|
||||||
|
#if !defined(__INHIBIT_SUBSCRIBER_WND_H__)
|
||||||
|
#define __INHIBIT_SUBSCRIBER_WND_H__
|
||||||
|
|
||||||
|
#include "monitor/TransmitWndBase.h"
|
||||||
|
|
||||||
|
#include <final/final.h>
|
||||||
|
using namespace finalcut;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// This class implements the inhibit subscriber window.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class HOST_SW_API InhibitSubscriberWnd final : public TransmitWndBase {
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the InhibitSubscriberWnd class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel"></param>
|
||||||
|
/// <param name="widget"></param>
|
||||||
|
explicit InhibitSubscriberWnd(lookups::VoiceChData channel, FWidget* widget = nullptr) : TransmitWndBase{channel, widget}
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FLabel m_dialogLabel{"Inhibit Subscriber", this};
|
||||||
|
|
||||||
|
FLabel m_subscriberLabel{"Subscriber ID: ", this};
|
||||||
|
FSpinBox m_subscriber{this};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void initLayout() override
|
||||||
|
{
|
||||||
|
FDialog::setText("Inhibit Subscriber");
|
||||||
|
FDialog::setSize(FSize{60, 16});
|
||||||
|
|
||||||
|
TransmitWndBase::initLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void initControls() override
|
||||||
|
{
|
||||||
|
TransmitWndBase::initControls();
|
||||||
|
|
||||||
|
if (m_hideModeSelect) {
|
||||||
|
FDialog::setSize(FSize{60, 12});
|
||||||
|
resizeControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
// subscriber entry
|
||||||
|
{
|
||||||
|
if (!m_hideModeSelect) {
|
||||||
|
m_dialogLabel.setGeometry(FPoint(2, 6), FSize(20, 2));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_dialogLabel.setGeometry(FPoint(2, 2), FSize(20, 2));
|
||||||
|
}
|
||||||
|
m_dialogLabel.setEmphasis();
|
||||||
|
m_dialogLabel.setAlignment(Align::Center);
|
||||||
|
|
||||||
|
if (!m_hideModeSelect) {
|
||||||
|
m_subscriberLabel.setGeometry(FPoint(2, 8), FSize(25, 1));
|
||||||
|
m_subscriber.setGeometry(FPoint(28, 8), FSize(20, 1));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_subscriberLabel.setGeometry(FPoint(2, 4), FSize(25, 1));
|
||||||
|
m_subscriber.setGeometry(FPoint(28, 4), FSize(20, 1));
|
||||||
|
}
|
||||||
|
m_subscriber.setRange(1, 16777211);
|
||||||
|
m_subscriber.setValue(1);
|
||||||
|
m_subscriber.setShadow(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_subscriberLabel.redraw();
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void setTransmit() override
|
||||||
|
{
|
||||||
|
std::string method = PUT_DMR_RID;
|
||||||
|
json::object req = json::object();
|
||||||
|
req["command"].set<std::string>(RID_CMD_INHIBIT);
|
||||||
|
uint32_t dstId = m_subscriber.getValue();
|
||||||
|
req["dstId"].set<uint32_t>(dstId);
|
||||||
|
|
||||||
|
switch (m_mode) {
|
||||||
|
case modem::STATE_DMR:
|
||||||
|
{
|
||||||
|
uint8_t slot = m_dmrSlot.getValue();
|
||||||
|
req["slot"].set<uint8_t>(slot);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case modem::STATE_P25:
|
||||||
|
{
|
||||||
|
method = PUT_P25_RID;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case modem::STATE_NXDN:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback REST API
|
||||||
|
int ret = RESTClient::send(m_selectedCh.address(), m_selectedCh.port(), m_selectedCh.password(),
|
||||||
|
HTTP_PUT, method, req, g_debug);
|
||||||
|
if (ret != network::rest::http::HTTPPayload::StatusType::OK) {
|
||||||
|
::LogError(LOG_HOST, "failed to send request to %s:%u", m_selectedCh.address().c_str(), m_selectedCh.port());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __INHIBIT_SUBSCRIBER_WND_H__
|
||||||
@ -0,0 +1,144 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.
|
||||||
|
*/
|
||||||
|
#if !defined(__PAGE_SUBSCRIBER_WND_H__)
|
||||||
|
#define __PAGE_SUBSCRIBER_WND_H__
|
||||||
|
|
||||||
|
#include "monitor/TransmitWndBase.h"
|
||||||
|
|
||||||
|
#include <final/final.h>
|
||||||
|
using namespace finalcut;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// This class implements the page subscriber window.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class HOST_SW_API PageSubscriberWnd final : public TransmitWndBase {
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the PageSubscriberWnd class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel"></param>
|
||||||
|
/// <param name="widget"></param>
|
||||||
|
explicit PageSubscriberWnd(lookups::VoiceChData channel, FWidget* widget = nullptr) : TransmitWndBase{channel, widget}
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FLabel m_dialogLabel{"Page Subscriber", this};
|
||||||
|
|
||||||
|
FLabel m_subscriberLabel{"Subscriber ID: ", this};
|
||||||
|
FSpinBox m_subscriber{this};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void initLayout() override
|
||||||
|
{
|
||||||
|
FDialog::setText("Page Subscriber");
|
||||||
|
FDialog::setSize(FSize{60, 16});
|
||||||
|
|
||||||
|
TransmitWndBase::initLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void initControls() override
|
||||||
|
{
|
||||||
|
TransmitWndBase::initControls();
|
||||||
|
|
||||||
|
if (m_hideModeSelect) {
|
||||||
|
FDialog::setSize(FSize{60, 12});
|
||||||
|
resizeControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
// subscriber entry
|
||||||
|
{
|
||||||
|
if (!m_hideModeSelect) {
|
||||||
|
m_dialogLabel.setGeometry(FPoint(2, 6), FSize(20, 2));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_dialogLabel.setGeometry(FPoint(2, 2), FSize(20, 2));
|
||||||
|
}
|
||||||
|
m_dialogLabel.setEmphasis();
|
||||||
|
m_dialogLabel.setAlignment(Align::Center);
|
||||||
|
|
||||||
|
if (!m_hideModeSelect) {
|
||||||
|
m_subscriberLabel.setGeometry(FPoint(2, 8), FSize(25, 1));
|
||||||
|
m_subscriber.setGeometry(FPoint(28, 8), FSize(20, 1));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_subscriberLabel.setGeometry(FPoint(2, 4), FSize(25, 1));
|
||||||
|
m_subscriber.setGeometry(FPoint(28, 4), FSize(20, 1));
|
||||||
|
}
|
||||||
|
m_subscriber.setRange(1, 16777211);
|
||||||
|
m_subscriber.setValue(1);
|
||||||
|
m_subscriber.setShadow(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_subscriberLabel.redraw();
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void setTransmit() override
|
||||||
|
{
|
||||||
|
std::string method = PUT_DMR_RID;
|
||||||
|
json::object req = json::object();
|
||||||
|
req["command"].set<std::string>(RID_CMD_PAGE);
|
||||||
|
uint32_t dstId = m_subscriber.getValue();
|
||||||
|
req["dstId"].set<uint32_t>(dstId);
|
||||||
|
|
||||||
|
switch (m_mode) {
|
||||||
|
case modem::STATE_DMR:
|
||||||
|
{
|
||||||
|
uint8_t slot = m_dmrSlot.getValue();
|
||||||
|
req["slot"].set<uint8_t>(slot);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case modem::STATE_P25:
|
||||||
|
{
|
||||||
|
method = PUT_P25_RID;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case modem::STATE_NXDN:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback REST API
|
||||||
|
int ret = RESTClient::send(m_selectedCh.address(), m_selectedCh.port(), m_selectedCh.password(),
|
||||||
|
HTTP_PUT, method, req, g_debug);
|
||||||
|
if (ret != network::rest::http::HTTPPayload::StatusType::OK) {
|
||||||
|
::LogError(LOG_HOST, "failed to send request to %s:%u", m_selectedCh.address().c_str(), m_selectedCh.port());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __PAGE_SUBSCRIBER_WND_H__
|
||||||
@ -0,0 +1,144 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.
|
||||||
|
*/
|
||||||
|
#if !defined(__RADIO_CHECK_SUBSCRIBER_WND_H__)
|
||||||
|
#define __RADIO_CHECK_SUBSCRIBER_WND_H__
|
||||||
|
|
||||||
|
#include "monitor/TransmitWndBase.h"
|
||||||
|
|
||||||
|
#include <final/final.h>
|
||||||
|
using namespace finalcut;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// This class implements the radio check subscriber window.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class HOST_SW_API RadioCheckSubscriberWnd final : public TransmitWndBase {
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the RadioCheckSubscriberWnd class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel"></param>
|
||||||
|
/// <param name="widget"></param>
|
||||||
|
explicit RadioCheckSubscriberWnd(lookups::VoiceChData channel, FWidget* widget = nullptr) : TransmitWndBase{channel, widget}
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FLabel m_dialogLabel{"Radio Check Subscriber", this};
|
||||||
|
|
||||||
|
FLabel m_subscriberLabel{"Subscriber ID: ", this};
|
||||||
|
FSpinBox m_subscriber{this};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void initLayout() override
|
||||||
|
{
|
||||||
|
FDialog::setText("Radio Check Subscriber");
|
||||||
|
FDialog::setSize(FSize{60, 16});
|
||||||
|
|
||||||
|
TransmitWndBase::initLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void initControls() override
|
||||||
|
{
|
||||||
|
TransmitWndBase::initControls();
|
||||||
|
|
||||||
|
if (m_hideModeSelect) {
|
||||||
|
FDialog::setSize(FSize{60, 12});
|
||||||
|
resizeControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
// subscriber entry
|
||||||
|
{
|
||||||
|
if (!m_hideModeSelect) {
|
||||||
|
m_dialogLabel.setGeometry(FPoint(2, 6), FSize(20, 2));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_dialogLabel.setGeometry(FPoint(2, 2), FSize(20, 2));
|
||||||
|
}
|
||||||
|
m_dialogLabel.setEmphasis();
|
||||||
|
m_dialogLabel.setAlignment(Align::Center);
|
||||||
|
|
||||||
|
if (!m_hideModeSelect) {
|
||||||
|
m_subscriberLabel.setGeometry(FPoint(2, 8), FSize(25, 1));
|
||||||
|
m_subscriber.setGeometry(FPoint(28, 8), FSize(20, 1));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_subscriberLabel.setGeometry(FPoint(2, 4), FSize(25, 1));
|
||||||
|
m_subscriber.setGeometry(FPoint(28, 4), FSize(20, 1));
|
||||||
|
}
|
||||||
|
m_subscriber.setRange(1, 16777211);
|
||||||
|
m_subscriber.setValue(1);
|
||||||
|
m_subscriber.setShadow(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_subscriberLabel.redraw();
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void setTransmit() override
|
||||||
|
{
|
||||||
|
std::string method = PUT_DMR_RID;
|
||||||
|
json::object req = json::object();
|
||||||
|
req["command"].set<std::string>(RID_CMD_CHECK);
|
||||||
|
uint32_t dstId = m_subscriber.getValue();
|
||||||
|
req["dstId"].set<uint32_t>(dstId);
|
||||||
|
|
||||||
|
switch (m_mode) {
|
||||||
|
case modem::STATE_DMR:
|
||||||
|
{
|
||||||
|
uint8_t slot = m_dmrSlot.getValue();
|
||||||
|
req["slot"].set<uint8_t>(slot);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case modem::STATE_P25:
|
||||||
|
{
|
||||||
|
method = PUT_P25_RID;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case modem::STATE_NXDN:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback REST API
|
||||||
|
int ret = RESTClient::send(m_selectedCh.address(), m_selectedCh.port(), m_selectedCh.password(),
|
||||||
|
HTTP_PUT, method, req, g_debug);
|
||||||
|
if (ret != network::rest::http::HTTPPayload::StatusType::OK) {
|
||||||
|
::LogError(LOG_HOST, "failed to send request to %s:%u", m_selectedCh.address().c_str(), m_selectedCh.port());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __RADIO_CHECK_SUBSCRIBER_WND_H__
|
||||||
@ -0,0 +1,124 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - Monitor
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / Monitor
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.
|
||||||
|
*/
|
||||||
|
#if !defined(__SELECTED_NODE_WND_H__)
|
||||||
|
#define __SELECTED_NODE_WND_H__
|
||||||
|
|
||||||
|
#include "monitor/MonitorMainWnd.h"
|
||||||
|
|
||||||
|
#include <final/final.h>
|
||||||
|
using namespace finalcut;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// This class implements the selected node display window.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class HOST_SW_API SelectedNodeWnd final : public finalcut::FDialog {
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the SelectedNodeWnd class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="widget"></param>
|
||||||
|
explicit SelectedNodeWnd(FWidget* widget = nullptr) : FDialog{widget}
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
/// <summary>Copy constructor.</summary>
|
||||||
|
SelectedNodeWnd(const SelectedNodeWnd&) = delete;
|
||||||
|
/// <summary>Move constructor.</summary>
|
||||||
|
SelectedNodeWnd(SelectedNodeWnd&&) noexcept = delete;
|
||||||
|
/// <summary>Finalizes an instance of the SelectedNodeWnd class.</summary>
|
||||||
|
~SelectedNodeWnd() noexcept override = default;
|
||||||
|
|
||||||
|
/// <summary>Disable copy assignment operator (=).</summary>
|
||||||
|
auto operator= (const SelectedNodeWnd&) -> SelectedNodeWnd& = delete;
|
||||||
|
/// <summary>Disable move assignment operator (=).</summary>
|
||||||
|
auto operator= (SelectedNodeWnd&&) noexcept -> SelectedNodeWnd& = delete;
|
||||||
|
|
||||||
|
/// <summary>Disable set X coordinate.</summary>
|
||||||
|
void setX(int, bool = true) override { }
|
||||||
|
/// <summary>Disable set Y coordinate.</summary>
|
||||||
|
void setY(int, bool = true) override { }
|
||||||
|
/// <summary>Disable set position.</summary>
|
||||||
|
void setPos(const FPoint&, bool = true) override { }
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void setSelectedText(std::string str)
|
||||||
|
{
|
||||||
|
m_selectedHost.setText(str);
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FLabel m_selectedHostLabel{"Selected Host: ", this};
|
||||||
|
FLabel m_selectedHost{this};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void initLayout() override
|
||||||
|
{
|
||||||
|
std::size_t maxWidth;
|
||||||
|
const auto& rootWidget = getRootWidget();
|
||||||
|
|
||||||
|
if (rootWidget) {
|
||||||
|
maxWidth = rootWidget->getClientWidth() - 3;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// fallback to xterm default size
|
||||||
|
maxWidth = 77;
|
||||||
|
}
|
||||||
|
|
||||||
|
FDialog::setGeometry(FPoint{2, 2}, FSize{maxWidth, 2});
|
||||||
|
FDialog::setMinimumSize(FSize{80, 5});
|
||||||
|
FDialog::setResizeable(false);
|
||||||
|
FDialog::setMinimizable(false);
|
||||||
|
FDialog::setTitlebarButtonVisibility(false);
|
||||||
|
FDialog::setShadow(false);
|
||||||
|
|
||||||
|
m_selectedHostLabel.setGeometry(FPoint(2, 1), FSize(18, 1));
|
||||||
|
m_selectedHost.setGeometry(FPoint(20, 1), FSize(30, 1));
|
||||||
|
m_selectedHost.setText("None");
|
||||||
|
|
||||||
|
FDialog::initLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void draw() override
|
||||||
|
{
|
||||||
|
setColor();
|
||||||
|
clearArea();
|
||||||
|
|
||||||
|
const auto& wc = getColorTheme();
|
||||||
|
setColor(wc->dialog_resize_fg, getBackgroundColor());
|
||||||
|
|
||||||
|
finalcut::drawBorder(this, FRect(FPoint{1, 1}, FPoint{(int)getWidth(), (int)getHeight()}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __SELECTED_NODE_WND_H__
|
||||||
@ -0,0 +1,285 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.
|
||||||
|
*/
|
||||||
|
#if !defined(__TRANSMIT_WND_BASE_H__)
|
||||||
|
#define __TRANSMIT_WND_BASE_H__
|
||||||
|
|
||||||
|
#include "lookups/AffiliationLookup.h"
|
||||||
|
#include "network/RESTDefines.h"
|
||||||
|
#include "remote/RESTClient.h"
|
||||||
|
|
||||||
|
#include <final/final.h>
|
||||||
|
using namespace finalcut;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// This class implements the base class for transmit windows.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class HOST_SW_API TransmitWndBase : public finalcut::FDialog {
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the TransmitWndBase class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel"></param>
|
||||||
|
/// <param name="widget"></param>
|
||||||
|
explicit TransmitWndBase(lookups::VoiceChData channel, FWidget* widget = nullptr) : FDialog{widget},
|
||||||
|
m_selectedCh(channel)
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool m_hideModeSelect = false;
|
||||||
|
lookups::VoiceChData m_selectedCh;
|
||||||
|
|
||||||
|
uint8_t m_mode = modem::STATE_DMR;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
virtual void initLayout() override
|
||||||
|
{
|
||||||
|
FDialog::setMinimizable(true);
|
||||||
|
FDialog::setShadow();
|
||||||
|
|
||||||
|
std::size_t maxWidth, maxHeight;
|
||||||
|
const auto& rootWidget = getRootWidget();
|
||||||
|
|
||||||
|
if (rootWidget) {
|
||||||
|
maxWidth = rootWidget->getClientWidth();
|
||||||
|
maxHeight = rootWidget->getClientHeight();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// fallback to xterm default size
|
||||||
|
maxWidth = 80;
|
||||||
|
maxHeight = 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int x = 1 + int((maxWidth - getWidth()) / 2);
|
||||||
|
const int y = 1 + int((maxHeight - getHeight()) / 3);
|
||||||
|
FWindow::setPos(FPoint{x, y}, false);
|
||||||
|
FDialog::adjustSize();
|
||||||
|
|
||||||
|
FDialog::setModal();
|
||||||
|
|
||||||
|
initControls();
|
||||||
|
|
||||||
|
FDialog::initLayout();
|
||||||
|
|
||||||
|
rootWidget->redraw(); // bryanb: wtf?
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
virtual void initControls()
|
||||||
|
{
|
||||||
|
resizeControls();
|
||||||
|
|
||||||
|
m_dmrSlotLabel.setGeometry(FPoint(2, 4), FSize(10, 1));
|
||||||
|
m_dmrSlot.setGeometry(FPoint(18, 4), FSize(5, 1));
|
||||||
|
m_dmrSlot.setRange(1, 2);
|
||||||
|
m_dmrSlot.setValue(1);
|
||||||
|
m_dmrSlot.setShadow(false);
|
||||||
|
|
||||||
|
// callback REST API to get status of the channel
|
||||||
|
json::object req = json::object();
|
||||||
|
json::object rsp = json::object();
|
||||||
|
|
||||||
|
int ret = RESTClient::send(m_selectedCh.address(), m_selectedCh.port(), m_selectedCh.password(),
|
||||||
|
HTTP_GET, GET_STATUS, req, rsp, g_debug);
|
||||||
|
if (ret != network::rest::http::HTTPPayload::StatusType::OK) {
|
||||||
|
::LogError(LOG_HOST, "failed to get status for %s:%u", m_selectedCh.address().c_str(), m_selectedCh.port());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (rsp["fixedMode"].get<bool>()) {
|
||||||
|
m_mode = rsp["state"].is<uint8_t>();
|
||||||
|
m_hideModeSelect = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dmrCC = rsp["dmrCC"].get<bool>();
|
||||||
|
bool p25CC = rsp["p25CC"].get<bool>();
|
||||||
|
bool nxdnCC = rsp["nxdnCC"].get<bool>();
|
||||||
|
|
||||||
|
// are we a dedicated control channel?
|
||||||
|
if (dmrCC || p25CC || nxdnCC) {
|
||||||
|
m_hideModeSelect = true;
|
||||||
|
if (dmrCC) {
|
||||||
|
m_mode = modem::STATE_DMR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p25CC) {
|
||||||
|
m_mode = modem::STATE_P25;
|
||||||
|
m_dmrSlot.setEnable(false);
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nxdnCC) {
|
||||||
|
m_mode = modem::STATE_NXDN;
|
||||||
|
m_dmrSlot.setEnable(false);
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// are we hiding the mode select?
|
||||||
|
if (!m_hideModeSelect) {
|
||||||
|
bool dmrEnabled = rsp["dmrEnabled"].get<bool>();
|
||||||
|
bool p25Enabled = rsp["p25Enabled"].get<bool>();
|
||||||
|
bool nxdnEnabled = rsp["nxdnEnabled"].get<bool>();
|
||||||
|
|
||||||
|
m_digModeGroup.setGeometry(FPoint(2, 1), FSize(56, 2));
|
||||||
|
if (dmrEnabled) {
|
||||||
|
m_modeDMR.setPos(FPoint(1, 1));
|
||||||
|
m_modeDMR.addCallback("toggled", [&]() {
|
||||||
|
if (m_modeDMR.isChecked()) {
|
||||||
|
m_mode = modem::STATE_DMR;
|
||||||
|
m_dmrSlot.setEnable(true);
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_modeDMR.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p25Enabled) {
|
||||||
|
m_modeP25.setPos(FPoint(13, 1));
|
||||||
|
m_modeP25.addCallback("toggled", [&]() {
|
||||||
|
if (m_modeP25.isChecked()) {
|
||||||
|
m_mode = modem::STATE_P25;
|
||||||
|
m_dmrSlot.setEnable(false);
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_modeP25.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nxdnEnabled) {
|
||||||
|
m_modeNXDN.setPos(FPoint(22, 1));
|
||||||
|
m_modeNXDN.addCallback("toggled", [&]() {
|
||||||
|
if (m_modeNXDN.isChecked()) {
|
||||||
|
m_mode = modem::STATE_NXDN;
|
||||||
|
m_dmrSlot.setEnable(false);
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_modeNXDN.setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_digModeGroup.setVisible(false);
|
||||||
|
m_modeDMR.setVisible(false);
|
||||||
|
m_modeP25.setVisible(false);
|
||||||
|
m_modeNXDN.setVisible(false);
|
||||||
|
m_dmrSlotLabel.setVisible(false);
|
||||||
|
m_dmrSlot.setVisible(false);
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception&) {
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
focusFirstChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void resizeControls()
|
||||||
|
{
|
||||||
|
// transmit button and close button logic
|
||||||
|
m_txButton.setGeometry(FPoint(3, int(getHeight()) - 6), FSize(10, 3));
|
||||||
|
m_txButton.addCallback("clicked", [&]() { setTransmit(); });
|
||||||
|
|
||||||
|
m_closeButton.setGeometry(FPoint(17, int(getHeight()) - 6), FSize(9, 3));
|
||||||
|
m_closeButton.addCallback("clicked", [&]() { hide(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
virtual void adjustSize() override
|
||||||
|
{
|
||||||
|
FDialog::adjustSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Event Handlers
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
virtual void onKeyPress(finalcut::FKeyEvent* e)
|
||||||
|
{
|
||||||
|
const auto key = e->key();
|
||||||
|
if (key == FKey::F12) {
|
||||||
|
setTransmit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
virtual void onClose(FCloseEvent* e) override
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
virtual void setTransmit()
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FButton m_txButton{"Transmit", this};
|
||||||
|
FButton m_closeButton{"Close", this};
|
||||||
|
|
||||||
|
FButtonGroup m_digModeGroup{"Digital Mode", this};
|
||||||
|
FRadioButton m_modeDMR{"DMR", &m_digModeGroup};
|
||||||
|
FRadioButton m_modeP25{"P25", &m_digModeGroup};
|
||||||
|
FRadioButton m_modeNXDN{"NXDN", &m_digModeGroup};
|
||||||
|
|
||||||
|
FLabel m_dmrSlotLabel{"DMR Slot: ", this};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
FSpinBox m_dmrSlot{this};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __TRANSMIT_WND_BASE_H__
|
||||||
@ -0,0 +1,144 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.
|
||||||
|
*/
|
||||||
|
#if !defined(__UNINHIBIT_SUBSCRIBER_WND_H__)
|
||||||
|
#define __UNINHIBIT_SUBSCRIBER_WND_H__
|
||||||
|
|
||||||
|
#include "monitor/TransmitWndBase.h"
|
||||||
|
|
||||||
|
#include <final/final.h>
|
||||||
|
using namespace finalcut;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// This class implements the uninhibit subscriber window.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class HOST_SW_API UninhibitSubscriberWnd final : public TransmitWndBase {
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the UninhibitSubscriberWnd class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel"></param>
|
||||||
|
/// <param name="widget"></param>
|
||||||
|
explicit UninhibitSubscriberWnd(lookups::VoiceChData channel, FWidget* widget = nullptr) : TransmitWndBase{channel, widget}
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FLabel m_dialogLabel{"Uninhibit Subscriber", this};
|
||||||
|
|
||||||
|
FLabel m_subscriberLabel{"Subscriber ID: ", this};
|
||||||
|
FSpinBox m_subscriber{this};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void initLayout() override
|
||||||
|
{
|
||||||
|
FDialog::setText("Uninhibit Subscriber");
|
||||||
|
FDialog::setSize(FSize{60, 16});
|
||||||
|
|
||||||
|
TransmitWndBase::initLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void initControls() override
|
||||||
|
{
|
||||||
|
TransmitWndBase::initControls();
|
||||||
|
|
||||||
|
if (m_hideModeSelect) {
|
||||||
|
FDialog::setSize(FSize{60, 12});
|
||||||
|
resizeControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
// subscriber entry
|
||||||
|
{
|
||||||
|
if (!m_hideModeSelect) {
|
||||||
|
m_dialogLabel.setGeometry(FPoint(2, 6), FSize(20, 2));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_dialogLabel.setGeometry(FPoint(2, 2), FSize(20, 2));
|
||||||
|
}
|
||||||
|
m_dialogLabel.setEmphasis();
|
||||||
|
m_dialogLabel.setAlignment(Align::Center);
|
||||||
|
|
||||||
|
if (!m_hideModeSelect) {
|
||||||
|
m_subscriberLabel.setGeometry(FPoint(2, 8), FSize(25, 1));
|
||||||
|
m_subscriber.setGeometry(FPoint(28, 8), FSize(20, 1));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_subscriberLabel.setGeometry(FPoint(2, 4), FSize(25, 1));
|
||||||
|
m_subscriber.setGeometry(FPoint(28, 4), FSize(20, 1));
|
||||||
|
}
|
||||||
|
m_subscriber.setRange(1, 16777211);
|
||||||
|
m_subscriber.setValue(1);
|
||||||
|
m_subscriber.setShadow(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_subscriberLabel.redraw();
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void setTransmit() override
|
||||||
|
{
|
||||||
|
std::string method = PUT_DMR_RID;
|
||||||
|
json::object req = json::object();
|
||||||
|
req["command"].set<std::string>(RID_CMD_UNINHIBIT);
|
||||||
|
uint32_t dstId = m_subscriber.getValue();
|
||||||
|
req["dstId"].set<uint32_t>(dstId);
|
||||||
|
|
||||||
|
switch (m_mode) {
|
||||||
|
case modem::STATE_DMR:
|
||||||
|
{
|
||||||
|
uint8_t slot = m_dmrSlot.getValue();
|
||||||
|
req["slot"].set<uint8_t>(slot);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case modem::STATE_P25:
|
||||||
|
{
|
||||||
|
method = PUT_P25_RID;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case modem::STATE_NXDN:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback REST API
|
||||||
|
int ret = RESTClient::send(m_selectedCh.address(), m_selectedCh.port(), m_selectedCh.password(),
|
||||||
|
HTTP_PUT, method, req, g_debug);
|
||||||
|
if (ret != network::rest::http::HTTPPayload::StatusType::OK) {
|
||||||
|
::LogError(LOG_HOST, "failed to send request to %s:%u", m_selectedCh.address().c_str(), m_selectedCh.port());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __UNINHIBIT_SUBSCRIBER_WND_H__
|
||||||
Loading…
Reference in new issue