State event for TX status
Information about TX status, e.g. if transmitting or not, is now published as a state event and is also sent to the reflector server.
This commit is contained in:
parent
a52e87f124
commit
378fd3d8d5
|
|
@ -704,6 +704,25 @@ void Reflector::httpRequestReceived(Async::HttpServerConnection *con,
|
|||
}
|
||||
}
|
||||
}
|
||||
if (qth.isMember("tx") && qth["tx"].isObject())
|
||||
{
|
||||
//std::cout << "### Found tx" << std::endl;
|
||||
Json::Value::Members txs(qth["tx"].getMemberNames());
|
||||
for (Json::Value::Members::const_iterator it=txs.begin(); it!=txs.end(); ++it)
|
||||
{
|
||||
//std::cout << "### member=" << *it << std::endl;
|
||||
const std::string& tx_id_str(*it);
|
||||
if (tx_id_str.size() == 1)
|
||||
{
|
||||
char tx_id(tx_id_str[0]);
|
||||
Json::Value& tx(qth["tx"][tx_id_str]);
|
||||
if (client->txExist(tx_id))
|
||||
{
|
||||
tx["transmit"] = client->txTransmit(tx_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
status["nodes"][client->callsign()] = node;
|
||||
|
|
|
|||
|
|
@ -318,6 +318,9 @@ void ReflectorClient::onFrameReceived(FramedTcpConnection *con,
|
|||
case MsgSignalStrengthValues::TYPE:
|
||||
handleMsgSignalStrengthValues(ss);
|
||||
break;
|
||||
case MsgTxStatus::TYPE:
|
||||
handleMsgTxStatus(ss);
|
||||
break;
|
||||
#if 0
|
||||
case MsgNodeInfo::TYPE:
|
||||
handleNodeInfo(ss);
|
||||
|
|
@ -555,6 +558,28 @@ void ReflectorClient::handleMsgSignalStrengthValues(std::istream& is)
|
|||
} /* ReflectorClient::handleMsgSignalStrengthValues */
|
||||
|
||||
|
||||
void ReflectorClient::handleMsgTxStatus(std::istream& is)
|
||||
{
|
||||
MsgTxStatus msg;
|
||||
if (!msg.unpack(is))
|
||||
{
|
||||
cerr << "*** WARNING[" << callsign()
|
||||
<< "]: Could not unpack incoming MsgTxStatus message" << endl;
|
||||
return;
|
||||
}
|
||||
typedef MsgTxStatus::Txs::const_iterator TxsIter;
|
||||
for (TxsIter it = msg.txs().begin(); it != msg.txs().end(); ++it)
|
||||
{
|
||||
const MsgTxStatus::Tx& tx = *it;
|
||||
std::cout << "### MsgTxStatus:"
|
||||
<< " id=" << tx.id()
|
||||
<< " transmit=" << tx.transmit()
|
||||
<< std::endl;
|
||||
setTxTransmit(tx.id(), tx.transmit());
|
||||
}
|
||||
} /* ReflectorClient::handleMsgTxStatus */
|
||||
|
||||
|
||||
void ReflectorClient::handleRequestQsy(std::istream& is)
|
||||
{
|
||||
MsgRequestQsy msg;
|
||||
|
|
|
|||
|
|
@ -127,6 +127,13 @@ class ReflectorClient
|
|||
};
|
||||
typedef std::map<char, Rx> RxMap;
|
||||
|
||||
struct Tx
|
||||
{
|
||||
std::string name;
|
||||
bool transmit;
|
||||
};
|
||||
typedef std::map<char, Tx> TxMap;
|
||||
|
||||
class Filter
|
||||
{
|
||||
public:
|
||||
|
|
@ -394,6 +401,14 @@ class ReflectorClient
|
|||
bool rxActive(char id) { return m_rx_map[id].active; }
|
||||
//RxMap& rxMap(void) { return m_rx_map; }
|
||||
//const RxMap& rxMap(void) const { return m_rx_map; }
|
||||
|
||||
bool txExist(char tx_id) const
|
||||
{
|
||||
return m_tx_map.find(tx_id) != m_tx_map.end();
|
||||
}
|
||||
void setTxTransmit(char id, bool transmit) { m_tx_map[id].transmit = transmit; }
|
||||
bool txTransmit(char id) { return m_tx_map[id].transmit; }
|
||||
|
||||
const Json::Value& nodeInfo(void) const { return m_node_info; }
|
||||
|
||||
private:
|
||||
|
|
@ -429,6 +444,7 @@ class ReflectorClient
|
|||
uint32_t m_current_tg;
|
||||
std::set<uint32_t> m_monitored_tgs;
|
||||
RxMap m_rx_map;
|
||||
TxMap m_tx_map;
|
||||
Json::Value m_node_info;
|
||||
|
||||
ReflectorClient(const ReflectorClient&);
|
||||
|
|
@ -441,6 +457,7 @@ class ReflectorClient
|
|||
void handleTgMonitor(std::istream& is);
|
||||
void handleNodeInfo(std::istream& is);
|
||||
void handleMsgSignalStrengthValues(std::istream& is);
|
||||
void handleMsgTxStatus(std::istream& is);
|
||||
void handleRequestQsy(std::istream& is);
|
||||
void handleStateEvent(std::istream& is);
|
||||
void handleMsgError(std::istream& is);
|
||||
|
|
|
|||
|
|
@ -1021,6 +1021,57 @@ struct MsgSignalStrengthValues
|
|||
}; /* MsgSignalStrengthValues */
|
||||
|
||||
|
||||
/**
|
||||
@brief Tx status message
|
||||
@author Tobias Blomberg / SM0SVX
|
||||
@date 2019-10-19
|
||||
|
||||
This message is used by a client to send tx status to the reflector server.
|
||||
*/
|
||||
class MsgTxStatus : public ReflectorMsgBase<113>
|
||||
{
|
||||
public:
|
||||
class Tx : public Async::Msg
|
||||
{
|
||||
public:
|
||||
Tx(void) : m_id('?'), m_flags(0) {}
|
||||
Tx(char id) : m_id(id), m_flags(0) {}
|
||||
void setTransmit(bool transmit) { setBit(BIT_TRANSMIT, transmit); }
|
||||
bool transmit(void) const { return getBit(BIT_TRANSMIT); }
|
||||
char id(void) const { return m_id; }
|
||||
|
||||
ASYNC_MSG_MEMBERS(m_id, m_flags)
|
||||
|
||||
private:
|
||||
typedef enum {BIT_TRANSMIT=0} Bit;
|
||||
|
||||
char m_id;
|
||||
uint8_t m_flags;
|
||||
|
||||
bool getBit(Bit bitno) const
|
||||
{
|
||||
uint8_t bit = 1 << static_cast<size_t>(bitno);
|
||||
return (m_flags & bit) != 0;
|
||||
}
|
||||
void setBit(Bit bitno, bool is_enabled)
|
||||
{
|
||||
uint8_t bit = 1 << static_cast<size_t>(bitno);
|
||||
m_flags = (m_flags & ~bit) | (is_enabled ? bit : 0);
|
||||
}
|
||||
};
|
||||
typedef std::vector<Tx> Txs;
|
||||
|
||||
MsgTxStatus(void) {}
|
||||
MsgTxStatus(const Txs& txs) : m_txs(txs) {}
|
||||
Txs& txs(void) { return m_txs; }
|
||||
void pushBack(const Tx& tx) { m_txs.push_back(tx); }
|
||||
|
||||
ASYNC_MSG_MEMBERS(m_txs)
|
||||
|
||||
private:
|
||||
Txs m_txs;
|
||||
}; /* class MsgTxStatus */
|
||||
|
||||
|
||||
/***************************** UDP Messages *****************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -557,6 +557,7 @@ bool Logic::initialize(void)
|
|||
}
|
||||
tx().transmitterStateChange.connect(
|
||||
mem_fun(*this, &Logic::transmitterStateChange));
|
||||
tx().publishStateEvent.connect(mem_fun(*this, &Logic::onPublishStateEvent));
|
||||
prev_tx_src->registerSink(m_tx);
|
||||
prev_tx_src = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -512,6 +512,54 @@ void ReflectorLogic::remoteReceivedPublishStateEvent(
|
|||
//sendUdpMsg(msg);
|
||||
sendMsg(msg);
|
||||
}
|
||||
else if (event_name == "Tx:state")
|
||||
{
|
||||
MsgTxStatus msg;
|
||||
std::istringstream is(data);
|
||||
Json::Value tx_data;
|
||||
is >> tx_data;
|
||||
std::string name = tx_data.get("name", "").asString();
|
||||
std::string id_str = tx_data.get("id", "?").asString();
|
||||
if (id_str.size() != 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
char id = id_str[0];
|
||||
if (id != '\0')
|
||||
{
|
||||
bool transmit = tx_data.get("transmit", false).asBool();
|
||||
MsgTxStatus::Tx tx(id);
|
||||
tx.setTransmit(transmit);
|
||||
msg.pushBack(tx);
|
||||
sendMsg(msg);
|
||||
}
|
||||
}
|
||||
else if (event_name == "MultiTx:state")
|
||||
{
|
||||
MsgTxStatus msg;
|
||||
std::istringstream is(data);
|
||||
Json::Value tx_arr;
|
||||
is >> tx_arr;
|
||||
for (Json::Value::ArrayIndex i = 0; i != tx_arr.size(); i++)
|
||||
{
|
||||
Json::Value& tx_data = tx_arr[i];
|
||||
std::string name = tx_data.get("name", "").asString();
|
||||
std::string id_str = tx_data.get("id", "").asString();
|
||||
if (id_str.size() != 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
char id = id_str[0];
|
||||
if (id != '\0')
|
||||
{
|
||||
bool transmit = tx_data.get("transmit", false).asBool();
|
||||
MsgTxStatus::Tx tx(id);
|
||||
tx.setTransmit(transmit);
|
||||
msg.pushBack(tx);
|
||||
}
|
||||
}
|
||||
sendMsg(msg);
|
||||
}
|
||||
} /* ReflectorLogic::remoteReceivedPublishStateEvent */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -247,6 +247,7 @@ DTMF_SERIAL=/dev/ttyS0
|
|||
|
||||
[Tx1]
|
||||
TYPE=Local
|
||||
TX_ID=T
|
||||
AUDIO_DEV=alsa:plughw:0
|
||||
AUDIO_CHANNEL=0
|
||||
#AUDIO_DEV_KEEP_OPEN=0
|
||||
|
|
|
|||
|
|
@ -286,7 +286,13 @@ LocalTx::~LocalTx(void)
|
|||
bool LocalTx::initialize(void)
|
||||
{
|
||||
string value;
|
||||
|
||||
|
||||
char tx_id = '\0';
|
||||
if (cfg.getValue(name(), "TX_ID", tx_id))
|
||||
{
|
||||
setId(tx_id);
|
||||
}
|
||||
|
||||
string audio_dev;
|
||||
if (!cfg.getValue(name(), "AUDIO_DEV", audio_dev))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
****************************************************************************/
|
||||
|
||||
#include <AsyncAudioSplitter.h>
|
||||
#include <json/json.h>
|
||||
|
||||
|
||||
|
||||
|
|
@ -115,9 +116,11 @@ using namespace Async;
|
|||
****************************************************************************/
|
||||
|
||||
MultiTx::MultiTx(Config& cfg, const string& name)
|
||||
: Tx(name), cfg(cfg), splitter(0)
|
||||
: Tx(name), cfg(cfg), splitter(0),
|
||||
m_tx_state_delay_timer(100, Async::Timer::TYPE_ONESHOT, false)
|
||||
{
|
||||
|
||||
m_tx_state_delay_timer.expired.connect(
|
||||
sigc::hide(sigc::mem_fun(*this, &MultiTx::txStateDelayExpired)));
|
||||
} /* MultiTx::MultiTx */
|
||||
|
||||
|
||||
|
|
@ -139,6 +142,12 @@ MultiTx::~MultiTx(void)
|
|||
|
||||
bool MultiTx::initialize(void)
|
||||
{
|
||||
char tx_id = '\0';
|
||||
if (cfg.getValue(name(), "TX_ID", tx_id))
|
||||
{
|
||||
setId(tx_id);
|
||||
}
|
||||
|
||||
string transmitters;
|
||||
if (!cfg.getValue(name(), "TRANSMITTERS", transmitters))
|
||||
{
|
||||
|
|
@ -270,19 +279,50 @@ void MultiTx::sendData(const std::vector<uint8_t> &msg)
|
|||
|
||||
void MultiTx::onTransmitterStateChange(void)
|
||||
{
|
||||
bool is_transmitting = false;
|
||||
list<Tx *>::const_iterator it;
|
||||
for (it=txs.begin(); it!=txs.end(); ++it)
|
||||
{
|
||||
if ((*it)->isTransmitting())
|
||||
{
|
||||
setIsTransmitting(true);
|
||||
return;
|
||||
is_transmitting = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
setIsTransmitting(false);
|
||||
setIsTransmitting(is_transmitting);
|
||||
m_tx_state_delay_timer.setEnable(true);
|
||||
m_tx_state_delay_timer.reset();
|
||||
} /* MultiTx::onTransmitterStateChange */
|
||||
|
||||
|
||||
void MultiTx::txStateDelayExpired(void)
|
||||
{
|
||||
Json::Value event(Json::arrayValue);
|
||||
list<Tx *>::const_iterator it;
|
||||
for (it=txs.begin(); it!=txs.end(); ++it)
|
||||
{
|
||||
Tx *tx = *it;
|
||||
char tx_id = tx->id();
|
||||
if (tx_id != '\0')
|
||||
{
|
||||
Json::Value tx_state(Json::objectValue);
|
||||
tx_state["name"] = tx->name();
|
||||
tx_state["id"] = std::string(&tx_id, &tx_id+1);
|
||||
tx_state["transmit"] = tx->isTransmitting();
|
||||
event.append(tx_state);
|
||||
}
|
||||
}
|
||||
Json::StreamWriterBuilder builder;
|
||||
builder["commentStyle"] = "None";
|
||||
builder["indentation"] = ""; //The JSON document is written on a single line
|
||||
Json::StreamWriter* writer = builder.newStreamWriter();
|
||||
std::stringstream os;
|
||||
writer->write(event, &os);
|
||||
delete writer;
|
||||
//std::cout << "### " << os.str() << std::endl;
|
||||
publishStateEvent("MultiTx:state", os.str());
|
||||
} /* MultiTx::txStateDelayExpired */
|
||||
|
||||
|
||||
/*
|
||||
* This file has not been truncated
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <AsyncTimer.h>
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -190,10 +191,12 @@ class MultiTx : public Tx
|
|||
Async::Config &cfg;
|
||||
std::list<Tx *> txs;
|
||||
Async::AudioSplitter *splitter;
|
||||
Async::Timer m_tx_state_delay_timer;
|
||||
|
||||
MultiTx(const MultiTx&);
|
||||
MultiTx& operator=(const MultiTx&);
|
||||
void onTransmitterStateChange(void);
|
||||
void txStateDelayExpired(void);
|
||||
|
||||
}; /* class MultiTx */
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
****************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <json/json.h>
|
||||
|
||||
|
||||
|
||||
|
|
@ -57,7 +59,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
#include "DummyRxTx.h"
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Namespaces to use
|
||||
|
|
@ -242,6 +243,23 @@ void Tx::setIsTransmitting(bool is_transmitting)
|
|||
}
|
||||
m_is_transmitting = is_transmitting;
|
||||
transmitterStateChange(is_transmitting);
|
||||
|
||||
char tx_id = id();
|
||||
if (tx_id != '\0')
|
||||
{
|
||||
Json::Value tx(Json::objectValue);
|
||||
tx["name"] = name();
|
||||
tx["id"] = std::string(&tx_id, &tx_id+1);
|
||||
tx["transmit"] = is_transmitting;
|
||||
Json::StreamWriterBuilder builder;
|
||||
builder["commentStyle"] = "None";
|
||||
builder["indentation"] = ""; //The JSON document is written on a single line
|
||||
Json::StreamWriter* writer = builder.newStreamWriter();
|
||||
std::stringstream os;
|
||||
writer->write(tx, &os);
|
||||
delete writer;
|
||||
publishStateEvent("Tx:state", os.str());
|
||||
}
|
||||
}
|
||||
} /* Tx::setIsTransmitting */
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,8 @@ class Tx : public sigc::trackable, public Async::AudioSink
|
|||
* @param tx_name The name of the transmitter
|
||||
*/
|
||||
Tx(std::string tx_name)
|
||||
: m_name(tx_name), m_verbose(true), m_is_transmitting(false)
|
||||
: m_name(tx_name), m_tx_id('\0'), m_verbose(true),
|
||||
m_is_transmitting(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -157,6 +158,12 @@ class Tx : public sigc::trackable, public Async::AudioSink
|
|||
*/
|
||||
const std::string& name(void) const { return m_name; }
|
||||
|
||||
/**
|
||||
* @brief Return the ID of the transmitter
|
||||
* @return The transmitter ID is returned
|
||||
*/
|
||||
char id(void) const { return m_tx_id; }
|
||||
|
||||
/*
|
||||
* @brief Set the verbosity level of the transmitter
|
||||
* @param verbose Set to \em false to keep the rx from printing things
|
||||
|
|
@ -246,11 +253,27 @@ class Tx : public sigc::trackable, public Async::AudioSink
|
|||
*/
|
||||
sigc::signal<void, bool> transmitterStateChange;
|
||||
|
||||
/**
|
||||
* @brief A signal that is emitted to publish a state update event
|
||||
* @param event_name The name of the event
|
||||
* @param msg The state update message
|
||||
*
|
||||
* This signal is emitted when a receiver wish to publish a state update
|
||||
* message. A state update message is a free text message that can be used
|
||||
* by subscribers to act on certain state changes within SvxLink. The
|
||||
* event name must be unique within SvxLink. The recommended format is
|
||||
* <context>:<name>, e.g. Tx:tx_state.
|
||||
*/
|
||||
sigc::signal<void, const std::string&,
|
||||
const std::string&> publishStateEvent;
|
||||
|
||||
protected:
|
||||
void setId(char id) { m_tx_id = id; }
|
||||
void setIsTransmitting(bool is_transmitting);
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
char m_tx_id;
|
||||
bool m_verbose;
|
||||
bool m_is_transmitting;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ LIBECHOLIB=1.3.3
|
|||
LIBASYNC=1.6.0.99.3-reflector_tg
|
||||
|
||||
# SvxLink versions
|
||||
SVXLINK=1.7.99.9-reflector_tg
|
||||
SVXLINK=1.7.99.10-reflector_tg
|
||||
MODULE_HELP=1.0.0
|
||||
MODULE_PARROT=1.1.1
|
||||
MODULE_ECHO_LINK=1.5.0
|
||||
|
|
|
|||
Loading…
Reference in New Issue