ReflectorLogic: QSY on squelch activity

Follow a remote initiated QSY on squelch open some short time after
missing out on a QSY due to no local activity. Use configuration
variable QSY_PENDING_TIMEOUT to set the time.

Also, go to TG #0 immediately on ignored or pending QSY
This commit is contained in:
Tobias Blomberg 2021-01-04 17:19:10 +01:00
parent 7a843f549c
commit c3c591a7c9
8 changed files with 157 additions and 23 deletions

View File

@ -260,7 +260,7 @@ blocks:
alias: ''
begin_tag: pmt.PMT_NIL
comment: ''
file: /tmp/rtl_vx6.raw
file: file
length: '0'
maxoutbuf: '0'
minoutbuf: '0'
@ -428,6 +428,23 @@ blocks:
coordinate: [24, 580.0]
rotation: 0
state: enabled
- name: file
id: parameter
parameters:
alias: ''
comment: ''
hide: none
label: File
short_id: f
type: str
value: /dev/zero
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [872, 12.0]
rotation: 0
state: true
- name: qtgui_freq_sink_x_0
id: qtgui_freq_sink_x
parameters:
@ -460,7 +477,7 @@ blocks:
comment: ''
ctrlpanel: 'False'
fc: '0'
fftsize: '1024'
fftsize: '2048'
freqhalf: 'False'
grid: 'True'
gui_hint: ''
@ -498,7 +515,7 @@ blocks:
width7: '1'
width8: '1'
width9: '1'
wintype: firdes.WIN_RECTANGULAR
wintype: firdes.WIN_BLACKMAN_hARRIS
ymax: '10'
ymin: '-110'
states:

View File

@ -651,7 +651,8 @@ priority.
.B TG_SELECT_TIMEOUT
The number of seconds after which a selected talk group will be unselected. The
node will return to talk group 0 (no talk group) and start monitoring the
configured talk groups again. Default: 30 seconds.
configured talk groups again. The value must be larger than zero. Default: 30
seconds.
.TP
.B ANNOUNCE_REMOTE_MIN_INTERVAL
The minimum number of seconds between announcements of the same TG for remote
@ -700,6 +701,15 @@ The number of seconds between UDP heartbeat messages sent to the reflector
server. This configuration variable can normally be left at the default value
but if you get frequent disconnects due to UDP heartbeat timeout it may help to
lower this value. Default: 15
.TP
.B QSY_PENDING_TIMEOUT
Set to the number of seconds to enable following a QSY request on squelch
activity. That is, after a remote QSY request, during the configured number of
seconds, it will be possible to follow a QSY request by just pushing the PTT
instead of having to use DTMF commands. Note that the timer starts when the QSY
request is received so the time it takes to play the QSY announcement is also
included in the timeout time. A good value is within 10 to 15 seconds.
Default is -1 (disabled).
.P
It is also possible to set audio codec parameters using the same configuration
variables as documented for networked receivers and transmitters. For example,

View File

@ -105,6 +105,9 @@
supposed to default to a timeout of 30 seconds if TIMEOUT is not set. That
did not work though.
* ReflectorLogic: Use the QSY_PENDING_TIMEOUT configuration variable to enable
following a just ignored QSY request on squelch open.
1.7.0 -- 01 Sep 2019

View File

@ -138,7 +138,8 @@ ReflectorLogic::ReflectorLogic(Async::Config& cfg, const std::string& name)
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_tmp_monitor_timer(1000, Async::Timer::TYPE_PERIODIC),
m_tmp_monitor_timeout(DEFAULT_TMP_MONITOR_TIMEOUT), m_use_prio(true)
m_tmp_monitor_timeout(DEFAULT_TMP_MONITOR_TIMEOUT), m_use_prio(true),
m_qsy_pending_timer(-1)
{
m_reconnect_timer.expired.connect(
sigc::hide(mem_fun(*this, &ReflectorLogic::reconnect)));
@ -154,6 +155,8 @@ ReflectorLogic::ReflectorLogic(Async::Config& cfg, const std::string& name)
sigc::mem_fun(*this, &ReflectorLogic::processTgSelectionEvent)));
m_tmp_monitor_timer.expired.connect(sigc::hide(
sigc::mem_fun(*this, &ReflectorLogic::checkTmpMonitorTimeout)));
m_qsy_pending_timer.expired.connect(sigc::hide(
sigc::mem_fun(*this, &ReflectorLogic::qsyPendingTimeout)));
} /* ReflectorLogic::ReflectorLogic */
@ -293,7 +296,22 @@ bool ReflectorLogic::initialize(void)
prev_src = 0;
cfg().getValue(name(), "DEFAULT_TG", m_default_tg);
cfg().getValue(name(), "TG_SELECT_TIMEOUT", m_tg_select_timeout);
if (!cfg().getValue(name(), "TG_SELECT_TIMEOUT", 1U,
std::numeric_limits<unsigned>::max(),
m_tg_select_timeout, true))
{
std::cout << "*** ERROR[" << name()
<< "]: Illegal value (" << m_tg_select_timeout
<< ") for TG_SELECT_TIMEOUT" << std::endl;
return false;
}
int qsy_pending_timeout = -1;
if (cfg().getValue(name(), "QSY_PENDING_TIMEOUT", qsy_pending_timeout) &&
(qsy_pending_timeout > 0))
{
m_qsy_pending_timer.setTimeout(1000 * qsy_pending_timeout);
}
m_event_handler = new EventHandler(event_handler_str, name());
if (LinkManager::hasInstance())
@ -1116,10 +1134,24 @@ void ReflectorLogic::handleMsgRequestQsy(std::istream& is)
else
{
m_last_qsy = msg.tg();
cout << name()
<< ": Server QSY request ignored. No local activity." << endl;
selectTg(0, "", false);
std::ostringstream os;
os << "tg_qsy_ignored " << msg.tg();
if (m_qsy_pending_timer.timeout() > 0)
{
cout << name() << ": Server QSY request pending" << endl;
os << "tg_qsy_pending " << msg.tg();
m_qsy_pending_timer.setEnable(true);
m_use_prio = false;
m_tg_select_timeout_cnt = 1 + m_qsy_pending_timer.timeout() / 1000;
}
else
{
cout << name()
<< ": Server QSY request ignored due to no local activity" << endl;
os << "tg_qsy_ignored " << msg.tg();
m_use_prio = true;
m_tg_select_timeout_cnt = 0;
}
processEvent(os.str());
}
} /* ReflectorLogic::handleMsgRequestQsy */
@ -1505,6 +1537,16 @@ void ReflectorLogic::onLogicConInStreamStateChanged(bool is_active,
{
m_logic_con_in_valve->setOpen(true);
}
if (m_qsy_pending_timer.isEnabled())
{
std::ostringstream os;
os << "tg_qsy_on_sql " << m_last_qsy;
processEvent(os.str());
selectTg(m_last_qsy, "", true);
m_qsy_pending_timer.setEnable(false);
m_tg_local_activity = true;
m_use_prio = false;
}
}
else
{
@ -1515,6 +1557,7 @@ void ReflectorLogic::onLogicConInStreamStateChanged(bool is_active,
selectTg(m_default_tg, "tg_default_activation", !m_mute_first_tx_loc);
}
}
m_qsy_pending_timer.reset();
m_tg_local_activity = true;
m_use_prio = false;
m_tg_select_timeout_cnt = m_tg_select_timeout;
@ -1567,11 +1610,14 @@ void ReflectorLogic::selectTg(uint32_t tg, const std::string& event, bool unmute
{
cout << name() << ": Selecting TG #" << tg << endl;
ostringstream os;
os << event << " " << tg << " " << m_selected_tg;
m_tg_selection_event = os.str();
m_report_tg_timer.reset();
m_report_tg_timer.setEnable(true);
if (!event.empty())
{
ostringstream os;
os << event << " " << tg << " " << m_selected_tg;
m_tg_selection_event = os.str();
m_report_tg_timer.reset();
m_report_tg_timer.setEnable(true);
}
if (tg != m_selected_tg)
{
@ -1589,6 +1635,7 @@ void ReflectorLogic::selectTg(uint32_t tg, const std::string& event, bool unmute
else
{
m_tg_local_activity = !m_logic_con_in->isIdle();
m_qsy_pending_timer.setEnable(false);
}
m_event_handler->setVariable(name() + "::selected_tg", m_selected_tg);
m_event_handler->setVariable(name() + "::previous_tg", m_previous_tg);
@ -1653,6 +1700,19 @@ void ReflectorLogic::checkTmpMonitorTimeout(void)
} /* ReflectorLogic::checkTmpMonitorTimeout */
void ReflectorLogic::qsyPendingTimeout(void)
{
m_qsy_pending_timer.setEnable(false);
m_use_prio = true;
m_tg_select_timeout_cnt = 0;
cout << name()
<< ": Server QSY request ignored due to no local activity" << endl;
std::ostringstream os;
os << "tg_qsy_ignored " << m_last_qsy;
processEvent(os.str());
} /* ReflectorLogic::qsyPendingTimeout */
/*
* This file has not been truncated
*/

View File

@ -205,11 +205,11 @@ class ReflectorLogic : public LogicBase
typedef std::set<MonitorTgEntry> MonitorTgsSet;
static const unsigned DEFAULT_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 DEFAULT_TMP_MONITOR_TIMEOUT = 3600;
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 DEFAULT_TMP_MONITOR_TIMEOUT = 3600;
std::string m_reflector_host;
uint16_t m_reflector_port;
@ -255,6 +255,7 @@ class ReflectorLogic : public LogicBase
Async::Timer m_tmp_monitor_timer;
int m_tmp_monitor_timeout;
bool m_use_prio;
Async::Timer m_qsy_pending_timer;
ReflectorLogic(const ReflectorLogic&);
ReflectorLogic& operator=(const ReflectorLogic&);
@ -297,6 +298,7 @@ class ReflectorLogic : public LogicBase
void processEvent(const std::string& event);
void processTgSelectionEvent(void);
void checkTmpMonitorTimeout(void);
void qsyPendingTimeout(void);
}; /* class ReflectorLogic */

View File

@ -27,6 +27,10 @@ variable prev_announce_tg 0
# Change through ANNOUNCE_REMOTE_MIN_INTERVAL config variable.
variable announce_remote_min_interval 0
# This variable will be set to 1 if the QSY pending feature ("QSY on squelch
# activity") is active. See configuration variable QSY_PENDING_TIMEOUT.
variable qsy_pending_active 0
#
# Checking to see if this is the correct logic core
#
@ -195,6 +199,17 @@ proc tg_qsy {new_tg old_tg} {
}
#
# Executed when a QSY is followed due to squelch open (see QSY_PENDING_TIMEOUT)
#
# tg -- The talk group that has been activated
#
proc tg_qsy_on_sql {tg} {
playSilence 100
playMsg "Core" "qsy"
}
#
# Executed when a TG QSY request fails
#
@ -210,17 +225,37 @@ proc tg_qsy_failed {} {
}
#
# Executed when a TG QSY request is pending
#
# tg -- The talk group requested in the QSY
#
proc tg_qsy_pending {tg} {
playSilence 100
playMsg "Core" "qsy"
spellNumber $tg
playMsg "Core" "pending"
}
#
# Executed when a TG QSY request is ignored
#
# tg -- The talk group requested in the QSY
#
proc tg_qsy_ignored {tg} {
#puts "### tg_qsy_ignored"
variable qsy_pending_active
playSilence 100
playMsg "Core" "qsy"
spellNumber $tg
if {!$qsy_pending_active} {
playMsg "Core" "qsy"
spellNumber $tg
}
playMsg "Core" "ignored"
playSilence 500
playTone 880 200 50
playTone 659 200 50
playTone 440 200 50
playSilence 100
}
@ -299,6 +334,12 @@ if [info exists ::Logic::CFG_ANNOUNCE_REMOTE_MIN_INTERVAL] {
set announce_remote_min_interval $::Logic::CFG_ANNOUNCE_REMOTE_MIN_INTERVAL
}
if [info exists ::Logic::CFG_QSY_PENDING_TIMEOUT] {
if {$::Logic::CFG_QSY_PENDING_TIMEOUT > 0} {
set qsy_pending_active 1
}
}
# end of namespace
}

View File

@ -101,6 +101,7 @@ EVENT_HANDLER=@SVX_SHARE_INSTALL_DIR@/events.tcl
#MUTE_FIRST_TX_REM=1
#TMP_MONITOR_TIMEOUT=3600
#UDP_HEARTBEAT_INTERVAL=15
QSY_PENDING_TIMEOUT=10
[LinkToR4]
CONNECT_LOGICS=RepeaterLogic:94:SK3AB,SimplexLogic:92:SK3CD

View File

@ -11,7 +11,7 @@ LIBECHOLIB=1.3.3
LIBASYNC=1.6.99.12
# SvxLink versions
SVXLINK=1.7.99.31
SVXLINK=1.7.99.32
MODULE_HELP=1.0.0
MODULE_PARROT=1.1.1
MODULE_ECHO_LINK=1.5.99.0