Implement talk group priority

Now possible to set priority on monitored talk groups so that a switch
is made to the higher priority talk group if there are activity on it
while being a passive listener on a lower priority talk group.
This commit is contained in:
Tobias Blomberg 2019-08-29 20:30:35 +02:00
parent 6217a41389
commit ac6698f50d
5 changed files with 86 additions and 8 deletions

View File

@ -608,11 +608,21 @@ talk group is currently selected. Default: 0 (no talk group).
.TP
.B MONITOR_TGS
A space separated list of talk groups which the node will monitor for activity
when no other talk group is selected. Default: no monitoring. Example:
when no other talk group is selected.
MONITOR_TGS=240 2403 2403123
It is also possible to mark talk groups as more prioritized than others by
adding one or more plus signs after the talk group number. More plus signs mean
higher priority. While a talk group is selected, and there are activity on a
talk group with higher priority, the higher prio talk group will be selected
unless there have been local activity on the node.
will monitor the TGs for Sweden, Sweden district 3 and a specific node ID.
Example:
MONITOR_TGS=112++ 240 2403+ 2403123
will monitor the TGs for Sweden, Sweden district 3 and a specific TG #2403123.
Traffic on talk group 2403 will be prioritized and 112 will have the highest
priority.
.TP
.B TG_SELECT_TIMEOUT
The number of seconds after which a selected talk group will be unselected. The

View File

@ -205,6 +205,31 @@ bool ReflectorLogic::initialize(void)
return false;
}
std::vector<std::string> monitor_tgs;
cfg().getValue(name(), "MONITOR_TGS", monitor_tgs);
for (std::vector<std::string>::iterator it=monitor_tgs.begin();
it!=monitor_tgs.end(); ++it)
{
std::istringstream is(*it);
MonitorTgEntry mte;
is >> mte.tg;
char modifier;
while (is >> modifier)
{
if (modifier == '+')
{
mte.prio += 1;
}
else
{
cerr << "*** ERROR: Illegal format for config variable MONITOR_TGS "
<< "entry \"" << *it << "\"" << endl;
return false;
}
}
m_monitor_tgs.insert(mte);
}
#if 0
string audio_codec("GSM");
if (AudioDecoder::isAvailable("OPUS") && AudioEncoder::isAvailable("OPUS"))
@ -681,11 +706,10 @@ void ReflectorLogic::handleMsgServerInfo(std::istream& is)
sendMsg(MsgSelectTG(m_selected_tg));
}
std::set<uint32_t> tgs;
cfg().getValue(name(), "MONITOR_TGS", tgs);
if (!tgs.empty())
if (!m_monitor_tgs.empty())
{
sendMsg(MsgTgMonitor(tgs));
sendMsg(MsgTgMonitor(
std::set<uint32_t>(m_monitor_tgs.begin(), m_monitor_tgs.end())));
}
sendUdpMsg(MsgUdpHeartbeat());
@ -759,6 +783,26 @@ void ReflectorLogic::handleMsgTalkerStart(std::istream& is)
{
selectTg(msg.tg(), "tg_remote_activation");
}
else
{
uint32_t selected_tg_prio = 0;
MonitorTgsSet::const_iterator selected_tg_it =
m_monitor_tgs.find(MonitorTgEntry(m_selected_tg));
if (selected_tg_it != m_monitor_tgs.end())
{
selected_tg_prio = selected_tg_it->prio;
}
MonitorTgsSet::const_iterator talker_tg_it =
m_monitor_tgs.find(MonitorTgEntry(msg.tg()));
if ((talker_tg_it != m_monitor_tgs.end()) &&
(talker_tg_it->prio > selected_tg_prio) &&
!m_tg_local_activity)
{
std::cout << name() << ": Activity on prioritized TG #"
<< msg.tg() << ". Switching!" << std::endl;
selectTg(msg.tg(), "tg_remote_prio_activation");
}
}
std::ostringstream ss;
ss << "talker_start " << msg.tg() << " " << msg.callsign();

View File

@ -166,6 +166,16 @@ class ReflectorLogic : public LogicBase
protected:
private:
struct MonitorTgEntry
{
uint32_t tg;
uint8_t prio;
MonitorTgEntry(uint32_t tg=0) : tg(tg), prio(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; }
};
typedef enum
{
STATE_DISCONNECTED, STATE_EXPECT_AUTH_CHALLENGE, STATE_EXPECT_AUTH_OK,
@ -173,6 +183,7 @@ class ReflectorLogic : public LogicBase
} ConState;
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;
@ -214,6 +225,7 @@ class ReflectorLogic : public LogicBase
std::string m_tg_selection_event;
bool m_tg_local_activity;
uint32_t m_last_qsy;
MonitorTgsSet m_monitor_tgs;
ReflectorLogic(const ReflectorLogic&);
ReflectorLogic& operator=(const ReflectorLogic&);

View File

@ -106,6 +106,18 @@ proc tg_remote_activation {new_tg old_tg} {
}
#
# Executed when a TG has been selected due to remote activity on a prioritized
# monitored talk group while a lower prio talk group is selected
#
# new_tg -- The talk group that has been activated
# old_tg -- The talk group that was active
#
proc tg_remote_prio_activation {new_tg old_tg} {
tg_remote_activation $new_tg $old_tg
}
#
# Executed when a TG has been selected by DTMF command
#

View File

@ -11,7 +11,7 @@ LIBECHOLIB=1.3.3
LIBASYNC=1.5.99.4
# SvxLink versions
SVXLINK=1.6.99.23-reflector_tg
SVXLINK=1.6.99.24-reflector_tg
MODULE_HELP=1.0.0
MODULE_PARROT=1.1.1
MODULE_ECHOLINK=1.4.99.1