Add DTMF controlled temporary monitoring

It is now possible to use DTMF command <prefix>4<tg> to temporarily
monitor a talk group on a node. The monitored talk group will time out
after one hour.
This commit is contained in:
Tobias Blomberg 2019-11-03 17:38:57 +01:00
parent 1f5011e700
commit 5ac348bece
4 changed files with 108 additions and 10 deletions

View File

@ -135,7 +135,8 @@ ReflectorLogic::ReflectorLogic(Async::Config& cfg, const std::string& name)
m_event_handler(0),
m_report_tg_timer(500, Async::Timer::TYPE_ONESHOT, false),
m_tg_local_activity(false), m_last_qsy(0), m_logic_con_in_valve(0),
m_mute_first_tx_loc(true), m_mute_first_tx_rem(false)
m_mute_first_tx_loc(true), m_mute_first_tx_rem(false),
m_tmp_monitor_timer(1000, Async::Timer::TYPE_PERIODIC)
{
m_reconnect_timer.expired.connect(
sigc::hide(mem_fun(*this, &ReflectorLogic::reconnect)));
@ -149,6 +150,8 @@ ReflectorLogic::ReflectorLogic(Async::Config& cfg, const std::string& name)
sigc::mem_fun(*this, &ReflectorLogic::tgSelectTimerExpired)));
m_report_tg_timer.expired.connect(sigc::hide(
sigc::mem_fun(*this, &ReflectorLogic::processTgSelectionEvent)));
m_tmp_monitor_timer.expired.connect(sigc::hide(
sigc::mem_fun(*this, &ReflectorLogic::checkTmpMonitorTimeout)));
} /* ReflectorLogic::ReflectorLogic */
@ -441,6 +444,43 @@ void ReflectorLogic::remoteCmdReceived(LogicBase* src_logic,
processEvent(std::string("command_failed ") + cmd);
}
}
else if (cmd[0] == '4') // Temporarily monitor talk group
{
const std::string subcmd(cmd.substr(1));
if (!subcmd.empty())
{
istringstream is(subcmd);
uint32_t tg = 0;
if (is >> tg)
{
const MonitorTgsSet::iterator it = m_monitor_tgs.find(tg);
if (it != m_monitor_tgs.end())
{
// NOTE: (*it).timeout is mutable
(*it).timeout = TMP_MONITOR_TIMEOUT;
}
else
{
MonitorTgEntry mte(tg);
mte.timeout = TMP_MONITOR_TIMEOUT;
m_monitor_tgs.insert(mte);
sendMsg(MsgTgMonitor(std::set<uint32_t>(
m_monitor_tgs.begin(), m_monitor_tgs.end())));
}
std::ostringstream os;
os << "tmp_monitor_add " << tg;
processEvent(os.str());
}
else
{
processEvent(std::string("command_failed ") + cmd);
}
}
else
{
processEvent(std::string("command_failed ") + cmd);
}
}
else
{
processEvent(std::string("unknown_command ") + cmd);
@ -1554,6 +1594,37 @@ void ReflectorLogic::processTgSelectionEvent(void)
} /* ReflectorLogic::processTgSelectionEvent */
void ReflectorLogic::checkTmpMonitorTimeout(void)
{
bool changed = false;
MonitorTgsSet::iterator it = m_monitor_tgs.begin();
while (it != m_monitor_tgs.end())
{
MonitorTgsSet::iterator next=it;
++next;
const MonitorTgEntry& mte = *it;
if (mte.timeout > 0)
{
// NOTE: mte.timeout is mutable
if (--mte.timeout <= 0)
{
changed = true;
m_monitor_tgs.erase(it);
std::ostringstream os;
os << "tmp_monitor_remove " << mte.tg;
processEvent(os.str());
}
}
it = next;
}
if (changed)
{
sendMsg(MsgTgMonitor(std::set<uint32_t>(
m_monitor_tgs.begin(), m_monitor_tgs.end())));
}
} /* ReflectorLogic::checkTmpMonitorTimeout */
/*
* This file has not been truncated
*/

View File

@ -186,9 +186,10 @@ class ReflectorLogic : public LogicBase
private:
struct MonitorTgEntry
{
uint32_t tg;
uint8_t prio;
MonitorTgEntry(uint32_t tg=0) : tg(tg), prio(0) {}
uint32_t tg;
uint8_t prio;
mutable int timeout;
MonitorTgEntry(uint32_t tg=0) : tg(tg), prio(0), timeout(0) {}
bool operator<(const MonitorTgEntry& mte) const { return tg < mte.tg; }
bool operator==(const MonitorTgEntry& mte) const { return tg == mte.tg; }
operator uint32_t(void) const { return tg; }
@ -203,11 +204,12 @@ class ReflectorLogic : public LogicBase
typedef Async::TcpClient<Async::FramedTcpConnection> FramedTcpClient;
typedef std::set<MonitorTgEntry> MonitorTgsSet;
static const unsigned UDP_HEARTBEAT_TX_CNT_RESET = 15;
static const unsigned UDP_HEARTBEAT_RX_CNT_RESET = 60;
static const unsigned TCP_HEARTBEAT_TX_CNT_RESET = 10;
static const unsigned TCP_HEARTBEAT_RX_CNT_RESET = 15;
static const unsigned DEFAULT_TG_SELECT_TIMEOUT = 30;
static const unsigned UDP_HEARTBEAT_TX_CNT_RESET = 15;
static const unsigned UDP_HEARTBEAT_RX_CNT_RESET = 60;
static const unsigned TCP_HEARTBEAT_TX_CNT_RESET = 10;
static const unsigned TCP_HEARTBEAT_RX_CNT_RESET = 15;
static const unsigned DEFAULT_TG_SELECT_TIMEOUT = 30;
static const int TMP_MONITOR_TIMEOUT = 3600;
std::string m_reflector_host;
uint16_t m_reflector_port;
@ -249,6 +251,7 @@ class ReflectorLogic : public LogicBase
Async::AudioValve* m_logic_con_in_valve;
bool m_mute_first_tx_loc;
bool m_mute_first_tx_rem;
Async::Timer m_tmp_monitor_timer;
ReflectorLogic(const ReflectorLogic&);
ReflectorLogic& operator=(const ReflectorLogic&);
@ -290,6 +293,7 @@ class ReflectorLogic : public LogicBase
void selectTg(uint32_t tg, const std::string& event, bool unmute);
void processEvent(const std::string& event);
void processTgSelectionEvent(void);
void checkTmpMonitorTimeout(void);
}; /* class ReflectorLogic */

View File

@ -272,6 +272,29 @@ proc talker_stop {tg callsign} {
}
#
# A talk group was added for temporary monitoring
#
# tg -- The added talk group
#
proc tmp_monitor_add {tg} {
#puts "### tmp_monitor_add: $tg"
playSilence 100
playMsg "Core" "monitor"
spellNumber $tg
}
#
# A talk group was removed from temporary monitoring
#
# tg -- The removed talk group
#
proc tmp_monitor_remove {tg} {
#puts "### tmp_monitor_remove: $tg"
}
if [info exists ::Logic::CFG_ANNOUNCE_REMOTE_MIN_INTERVAL] {
set announce_remote_min_interval $::Logic::CFG_ANNOUNCE_REMOTE_MIN_INTERVAL
}

View File

@ -11,7 +11,7 @@ LIBECHOLIB=1.3.3
LIBASYNC=1.6.0.99.3-reflector_tg
# SvxLink versions
SVXLINK=1.7.99.16-reflector_tg
SVXLINK=1.7.99.17-reflector_tg
MODULE_HELP=1.0.0
MODULE_PARROT=1.1.1
MODULE_ECHO_LINK=1.5.0