Skip to content

Added control of remote RXes via Voter using a PTY (VOTER_PTY). #186

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
Closed
79 changes: 77 additions & 2 deletions src/svxlink/modules/echolink/ModuleEchoLink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <cstdlib>
#include <vector>

#include <string.h>

/****************************************************************************
*
Expand All @@ -58,6 +59,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <common.h>


#include <AsyncPty.h>
#include <AsyncPtyStreamBuf.h>

/****************************************************************************
*
* Local Includes
Expand Down Expand Up @@ -158,7 +162,7 @@ ModuleEchoLink::ModuleEchoLink(void *dl_handle, Logic *logic,
listen_only_valve(0), selector(0), num_con_max(0), num_con_ttl(5*60),
num_con_block_time(120*60), num_con_update_timer(0), reject_conf(false),
autocon_echolink_id(0), autocon_time(DEFAULT_AUTOCON_TIME),
autocon_timer(0), proxy(0)
autocon_timer(0), proxy(0), pty(0)
{
cout << "\tModule EchoLink v" MODULE_ECHOLINK_VERSION " starting...\n";

Expand Down Expand Up @@ -461,6 +465,20 @@ bool ModuleEchoLink::initialize(void)
mem_fun(*this, &ModuleEchoLink::checkAutoCon));
}

string pty_path;
if(cfg().getValue(cfgName(), "ECHOLINK_PTY", pty_path))
{
pty = new Pty(pty_path);
if (!pty->open()) {
cerr << "*** ERROR: Could not open echolink PTY "
<<pty_path << " as specified in configuration variable "
<< name() << "/" << "ECHOLINK_PTY" << endl;
return false;
}
pty->dataReceived.connect(sigc::mem_fun(*this, &ModuleEchoLink::commandHandler));
}


return true;

} /* ModuleEchoLink::initialize */
Expand Down Expand Up @@ -500,6 +518,35 @@ void ModuleEchoLink::logicIdleStateChanged(bool is_idle)
* Private member functions
*
****************************************************************************/
void ModuleEchoLink::commandHandler(const void *buf, size_t count) {
char* buffer = (char *) buf;
char* command;
buffer[count] = '\0'; // received string is not null terminated
cout << "echolink commandHandler received: " << buffer << " (" << count << ")" << endl;
command = strtok(buffer, "\n\r ");
while (command != NULL && count >= 3) {
if (strstr(command, "KILL")) {
if (talker == 0) {
cout << "echolink: trying to KILL, but no active talkers" << endl;
} else {
cout << "echolink: KILLing talker: " << talker->remoteCallsign() << endl;
talker->disconnect();
}
} else if (strstr(command, ":D")) {
// disconnect client by callsign
vector<QsoImpl *>::iterator it;
for (it = qsos.begin(); it != qsos.end(); ++it) {
if (strstr(command, (*it)->remoteCallsign().c_str())) {
cout << "echolink: disconnecting user " << (*it)->remoteCallsign() << endl;
(*it)->disconnect();
}
}
}
command = strtok(NULL, "\n\r ");
count -= sizeof(command);
}
// printSquelchState();
}


void ModuleEchoLink::moduleCleanup(void)
Expand Down Expand Up @@ -898,6 +945,32 @@ void ModuleEchoLink::onError(const string& msg)
} /* onError */


/*
*----------------------------------------------------------------------------
* Method: clientList
* Purpose: Called on connect or disconnect of a remote client to send an
* event to list the connected stations.
* Input: None
* Output: None
* Author: Wim Fournier / PH7WIM
* Created: 2016-01-11
* Remarks:
* Bugs:
*----------------------------------------------------------------------------
*/
void ModuleEchoLink::clientList(void) {
stringstream ss;
ss << "clients [list";
vector<QsoImpl *>::iterator it;
for (it = qsos.begin(); it != qsos.end(); ++it) {
if ((*it)->currentState() != Qso::STATE_DISCONNECTED) {
ss << " " << (*it)->remoteCallsign();
}
}
ss << "]";
processEvent(ss.str());
// cout << ss.str();
} /* clientList */

/*
*----------------------------------------------------------------------------
Expand Down Expand Up @@ -1029,6 +1102,7 @@ void ModuleEchoLink::onIncomingConnection(const IpAddress& ip,
qso->accept();
broadcastTalkerStatus();
updateDescription();
clientList();

if (LocationInfo::has_instance())
{
Expand Down Expand Up @@ -1088,6 +1162,7 @@ void ModuleEchoLink::onStateChange(QsoImpl *qso, Qso::State qso_state)

broadcastTalkerStatus();
updateDescription();
clientList();
break;
}

Expand Down Expand Up @@ -1162,7 +1237,7 @@ void ModuleEchoLink::onIsReceiving(bool is_receiving, QsoImpl *qso)
// << (is_receiving ? "TRUE" : "FALSE") << endl;

stringstream ss;
ss << "is_receiving " << (is_receiving ? "1" : "0");
ss << "is_receiving " << (is_receiving ? "1" : "0") << " " << qso->remoteCallsign();
processEvent(ss.str());

if ((talker == 0) && is_receiving)
Expand Down
9 changes: 7 additions & 2 deletions src/svxlink/modules/echolink/ModuleEchoLink.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ namespace Async
class AudioSplitter;
class AudioValve;
class AudioSelector;
class Pty;
};
namespace EchoLink
{
Expand Down Expand Up @@ -103,7 +104,7 @@ namespace EchoLink
class MsgHandler;
class QsoImpl;
class LocationInfo;


/****************************************************************************
*
Expand Down Expand Up @@ -140,7 +141,7 @@ class ModuleEchoLink : public Module
bool initialize(void);
const char *compiledForVersion(void) const { return SVXLINK_VERSION; }


protected:
/**
* @brief Notify the module that the logic core idle state has changed
Expand Down Expand Up @@ -220,10 +221,14 @@ class ModuleEchoLink : public Module
void squelchOpen(bool is_open);
int audioFromRx(float *samples, int count);
void allMsgsWritten(void);
void commandHandler(const void *buf, size_t count); // WIM
Async::Pty *pty;


void onStatusChanged(EchoLink::StationData::Status status);
void onStationListUpdated(void);
void onError(const std::string& msg);
void clientList(void);
void onIncomingConnection(const Async::IpAddress& ip,
const std::string& callsign, const std::string& name,
const std::string& priv);
Expand Down
5 changes: 3 additions & 2 deletions src/svxlink/svxlink/Logic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ Logic::Logic(Config &cfg, const string& name)
qso_recorder(0), tx_ctcss(TX_CTCSS_ALWAYS),
tx_ctcss_mask(0),
currently_set_tx_ctrl_mode(Tx::TX_OFF), is_online(true),
dtmf_digit_handler(0), state_pty(0)
dtmf_digit_handler(0), state_pty(0),
{
rgr_sound_timer.expired.connect(sigc::hide(
mem_fun(*this, &Logic::sendRgrSound)));
Expand Down Expand Up @@ -262,13 +262,14 @@ bool Logic::initialize(void)
if (!state_pty->open())
{
cerr << "*** ERROR: Could not open state PTY "
<< state_pty_path << " as spcified in configuration variable "
<< state_pty_path << " as specified in configuration variable "
<< name() << "/" << "STATE_PTY" << endl;
cleanup();
return false;
}
}


string value;
if (cfg().getValue(name(), "ACTIVATE_MODULE_ON_LONG_CMD", value))
{
Expand Down
1 change: 1 addition & 0 deletions src/svxlink/svxlink/svxlink.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ BUFFER_LENGTH=0
#HYSTERESIS=50
#SQL_CLOSE_REVOTE_DELAY=500
#RX_SWITCH_DELAY=500
#VOTER_PTY=/var/run/svxlink/voter

[MultiTx]
TYPE=Multi
Expand Down
38 changes: 33 additions & 5 deletions src/svxlink/trx/Rx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#include <iostream>
#include <cstdlib>
#include <time.h>



Expand Down Expand Up @@ -199,6 +200,23 @@ map<string, RxFactory*> RxFactory::rx_factories;
*
****************************************************************************/

void Rx::setEnabled(bool enabled)
{
m_enabled = enabled;
if (! enabled) {
// close squelch, but set m_sql_open_hidden to what it WAS
int was_open = m_sql_open;
setSquelchState(false);
m_sql_open_hidden = was_open;

} else {
cout << "Rx:setEnabled: re-enable, set SQ to " << m_sql_open_hidden << endl;
// Set squelch to the correct, current status
setSquelchState(m_sql_open_hidden);
}

}

std::string Rx::muteStateToString(MuteState mute_state)
{
switch (mute_state)
Expand All @@ -215,7 +233,7 @@ std::string Rx::muteStateToString(MuteState mute_state)


Rx::Rx(Config &cfg, const string& name)
: m_name(name), m_verbose(true), m_sql_open(false), m_cfg(cfg),
: m_name(name), m_verbose(true), m_enabled(true), m_sql_open(false), m_sql_open_hidden(false), m_cfg(cfg),
m_sql_tmo_timer(0)
{
} /* Rx::Rx */
Expand Down Expand Up @@ -315,19 +333,29 @@ Rx *RxFactory::createNamedRx(Config& cfg, const string& name)

void Rx::setSquelchState(bool is_open)
{
// cout << "Rx::setSquelchState: " << m_name << ": requested: " << is_open << endl;
// set m_sql_open_hidden to the sql state as well, so we can set the correct state on re-enable
m_sql_open_hidden = is_open;

if (is_open == m_sql_open)
{
return;
}

if (m_verbose)
{
cout << m_name << ": The squelch is " << (is_open ? "OPEN" : "CLOSED")
<< " (" << signalStrength() << ")" << endl;
}
m_sql_open = is_open;
squelchOpen(is_open);

if (!m_enabled && is_open) {

// cout << "Rx::setSquelchState: " << m_name << ": Tried to open squelch on disabled receiver, ignoring" << endl;
} else {
// cout << "Rx::setSquelchState: " << m_name << ": setting to: " << (is_open?"OPEN":"CLOSED") << endl;
m_sql_open = is_open;
squelchOpen(is_open);
}

if (m_sql_tmo_timer != 0)
{
m_sql_tmo_timer->setEnable(is_open);
Expand Down
10 changes: 9 additions & 1 deletion src/svxlink/trx/Rx.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ class Rx : public sigc::trackable, public Async::AudioSource
*/
virtual void setVerbose(bool verbose) { m_verbose = verbose; }

/**
* @brief Set the enabled state of the receiver
* @param eneabled Set to \em false to disable receiver
*/
virtual void setEnabled(bool);

/**
* @brief Set the mute state for this receiver
* @param mute_state The mute state to set for this receiver
Expand Down Expand Up @@ -278,10 +284,12 @@ class Rx : public sigc::trackable, public Async::AudioSource
private:
std::string m_name;
bool m_verbose;
bool m_enabled;
bool m_sql_open;
bool m_sql_open_hidden;
Async::Config m_cfg;
Async::Timer *m_sql_tmo_timer;

void sqlTimeout(Async::Timer *t);

}; /* class Rx */
Expand Down
Loading