Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 29 additions & 29 deletions src/doc/man/svxlink.conf.5
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH SVXLINK.CONF 5 "OCTOBER 2025" Linux "File Formats"
.TH SVXLINK.CONF 5 "FEBRUARY 2026" Linux "File Formats"
.
.SH NAME
.
Expand Down Expand Up @@ -437,6 +437,34 @@ If the squelch close before the delay time has expired, no talkgroup will be
reported. Default: 0.

Example: CTCSS_TO_TG_DELAY=1000
.TP
.B COMMAND_PTY
Using this configuration variable it is possible to specify a path to a UNIX 98
PTY that can be used to send commands to a SvxLink logic core. SvxLink will
create a softlink to the actual slave PTY. For that reason, SvxLink must have
write permissions in the directory where the softlink should be created.
Sending commands to the PTY is as simple as doing a
.B "echo 'THE COMMAND TO EXECUTE' > /path/to/pty"
after starting SvxLink.

Valid commands:
.RS
.IP \(bu 4
.BR "CFG <section> <tag> <value>" " --"
Set a configuration variable. Only a few configuration variables support being
set at runtime. Example: CFG RepeaterLogic ONLINE 0.
.IP \(bu 4
.BR "EVENT <event name> [<arg> ...]" " --"
Call an event handler (TCL function). It is important to specify the correct
TCL namespace for the function to be found. If no namespace is given, the
namespace of the current logic core will be added, e.g. "manual_identification"
is the same as "RepeaterLogic::manual_identification" if the logic core
namnespace is "RepeaterLogic". To call a function in the root namespace, the
function name must be prepended with "::".
Example: EVENT ::playNumber -42.5.
.RE

Example: COMMAND_PTY=/dev/shm/repeater_logic_ctrl
.
.SS Simplex Logic Section
.
Expand Down Expand Up @@ -470,34 +498,6 @@ is open.
.B RGR_SOUND_ALWAYS
Set to 1 to always send roger sound after squelch close, even when no module is
active.
.TP
.B COMMAND_PTY
Using this configuration variable it is possible to specify a path to a UNIX 98
PTY that can be used to send commands to a SvxLink logic core. SvxLink will
create a softlink to the actual slave PTY. For that reason, SvxLink must have
write permissions in the directory where the softlink should be created.
Sending commands to the PTY is as simple as doing a
.B "echo 'THE COMMAND TO EXECUTE' > /path/to/pty"
after starting SvxLink.

Valid commands:
.RS
.IP \(bu 4
.BR "CFG <section> <tag> <value>" " --"
Set a configuration variable. Only a few configuration variables support being
set at runtime. Example: CFG RepeaterLogic ONLINE 0.
.IP \(bu 4
.BR "EVENT <event name> [<arg> ...]" " --"
Call an event handler (TCL function). It is important to specify the correct
TCL namespace for the function to be found. If no namespace is given, the
namespace of the current logic core will be added, e.g. "manual_identification"
is the same as "RepeaterLogic::manual_identification" if the logic core
namnespace is "RepeaterLogic". To call a function in the root namespace, the
function name must be prepended with "::".
Example: EVENT ::playNumber -42.5.
.RE

Example: COMMAND_PTY=/dev/shm/repeater_logic_ctrl
.
.SS Repeater Logic Section
.
Expand Down
146 changes: 93 additions & 53 deletions src/svxlink/trx/PttHidraw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

\verbatim
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
Copyright (C) 2003-2014 Tobias Blomberg / SM0SVX
Copyright (C) 2003-2026 Tobias Blomberg / SM0SVX

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -45,6 +45,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
****************************************************************************/

#include <common.h>


/****************************************************************************
Expand All @@ -64,7 +65,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
****************************************************************************/

using namespace std;
using namespace Async;



Expand Down Expand Up @@ -115,52 +115,90 @@ using namespace Async;
****************************************************************************/

PttHidraw::PttHidraw(void)
: active_low(false), fd(-1), pin(0)
{
} /* PttHidraw::PttHidraw */


PttHidraw::~PttHidraw(void)
{
if (fd >= 0)
{
close(fd);
fd = -1;
}
closeDevice();
} /* PttHidraw::~PttHidraw */


bool PttHidraw::initialize(Async::Config &cfg, const std::string name)
bool PttHidraw::initialize(Async::Config& cfg, const std::string name)
{
m_cfg = &cfg;
m_tx_name = name;

return openDevice();
} /* PttHidraw::initialize */



/****************************************************************************
*
* Protected member functions
*
****************************************************************************/



map<string, char> pin_mask;
pin_mask["GPIO1"] = 0x01;
pin_mask["GPIO2"] = 0x02;
pin_mask["GPIO3"] = 0x04;
pin_mask["GPIO4"] = 0x08;
/****************************************************************************
*
* Private member functions
*
****************************************************************************/

bool PttHidraw::openDevice(void)
{
static const std::map<string, char> pin_mask{
{"GPIO1", 0x01},
{"GPIO2", 0x02},
{"GPIO3", 0x04},
{"GPIO4", 0x08}
};

std::string hidraw_dev;
if (!m_cfg->getValue(m_tx_name, "HID_DEVICE", hidraw_dev) ||
hidraw_dev.empty())
{
std::cerr << "*** ERROR: Config variable " << m_tx_name
<< "/HID_DEVICE not set"
<< std::endl;
return false;
}

string hidraw_pin;
if (!cfg.getValue(name, "HID_PTT_PIN", hidraw_pin) || hidraw_pin.empty())
std::string hidraw_pin;
if (!m_cfg->getValue(m_tx_name, "HID_PTT_PIN", hidraw_pin) ||
hidraw_pin.empty())
{
cerr << "*** ERROR: Config variable " << name << "/HID_PTT_PIN not set\n";
std::cerr << "*** ERROR: Config variable " << m_tx_name
<< "/HID_PTT_PIN not set"
<< std::endl;
return false;
}

string hidraw_dev;
if (!cfg.getValue(name, "HID_DEVICE", hidraw_dev) || hidraw_dev.empty())
auto it = pin_mask.find(hidraw_pin);
if (it == pin_mask.end())
{
cerr << "*** ERROR: Config variable " << name << "/HID_DEVICE not set\n";
std::cerr << "*** ERROR: Wrong value for " << m_tx_name << "/HID_PTT_PIN="
<< hidraw_pin << ", valid values are GPIO1, GPIO2, GPIO3, GPIO4"
<< std::endl;
return false;
}
m_pin = (*it).second;

if ((fd = open(hidraw_dev.c_str(), O_WRONLY, 0)) < 0)
if ((m_fd = ::open(hidraw_dev.c_str(), O_WRONLY, 0)) < 0)
{
cerr << "*** ERROR: Can't open port " << hidraw_dev << endl;
std::cerr << "*** ERROR: Can't open HIDRAW device '" << hidraw_dev
<< "': " << SvxLink::strError(errno)
<< std::endl;
closeDevice();
return false;
}

struct hidraw_devinfo hiddevinfo;
if ((ioctl(fd, HIDIOCGRAWINFO, &hiddevinfo) != -1) &&
if ((::ioctl(m_fd, HIDIOCGRAWINFO, &hiddevinfo) != -1) &&
(hiddevinfo.vendor == 0x0d8c))
{
cout << "--- Hidraw sound chip is ";
Expand Down Expand Up @@ -197,61 +235,63 @@ bool PttHidraw::initialize(Async::Config &cfg, const std::string name)
else
{
cerr << "*** ERROR: unknown/unsupported sound chip detected...\n";
closeDevice();
return false;
}

if (hidraw_pin[0] == '!')
{
active_low = true;
m_active_low = true;
hidraw_pin.erase(0, 1);
}

map<string, char>::iterator it = pin_mask.find(hidraw_pin);
if (it == pin_mask.end())
return true;
} /* PttHidraw::openDevice */


void PttHidraw::closeDevice(void)
{
m_active_low = false;
m_pin = 0;

if (m_fd >= 0)
{
cerr << "*** ERROR: Wrong value for " << name << "/HID_PIN=" << hidraw_pin
<< ", valid are GPIO1, GPIO2, GPIO3, GPIO4" << endl;
return false;
::close(m_fd);
m_fd = -1;
}
pin = (*it).second;

return true;
} /* PttHidraw::initialize */
} /* PttHidraw::closeDevice */


bool PttHidraw::setTxOn(bool tx_on)
{
//cerr << "### PttHidraw::setTxOn(" << (tx_on ? "true" : "false") << ")\n";

char a[5] = {'\000', '\000',
(tx_on ^ active_low ? pin : '\000'), pin, '\000'};
const char a[5] = {
'\000',
'\000',
(tx_on ^ m_active_low ? m_pin : '\000'),
m_pin,
'\000'
};

if (write(fd, a, sizeof(a)) == -1)
if ((m_fd < 0) && !openDevice())
{
return false;
}

if (::write(m_fd, a, sizeof(a)) == -1)
{
std::cerr << "*** ERROR: Failed to write to HIDRAW device: "
<< SvxLink::strError(errno)
<< std::endl;
closeDevice();
return false;
}

return true;
} /* PttHidraw::setTxOn */



/****************************************************************************
*
* Protected member functions
*
****************************************************************************/



/****************************************************************************
*
* Private member functions
*
****************************************************************************/



/*
* This file has not been truncated
*/
Expand Down
20 changes: 12 additions & 8 deletions src/svxlink/trx/PttHidraw.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

\verbatim
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
Copyright (C) 2003-2014 Tobias Blomberg / SM0SVX
Copyright (C) 2003-2026 Tobias Blomberg / SM0SVX

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -121,33 +121,37 @@ class PttHidraw : public Ptt
/**
* @brief Destructor
*/
~PttHidraw(void);
virtual ~PttHidraw(void);

/**
* @brief Initialize the PTT hardware
* @param cfg An initialized config object
* @param name The name of the config section to read config from
* @returns Returns \em true on success or else \em false
*/
virtual bool initialize(Async::Config &cfg, const std::string name);
virtual bool initialize(Async::Config& cfg,
const std::string name) override;

/**
* @brief Set the state of the PTT, TX on or off
* @param tx_on Set to \em true to turn the transmitter on
* @returns Returns \em true on success or else \em false
*/
virtual bool setTxOn(bool tx_on);
virtual bool setTxOn(bool tx_on) override;

protected:

private:
bool active_low;

int fd;
char pin;
bool m_active_low {false};
int m_fd {-1};
char m_pin {0};
Async::Config* m_cfg {nullptr};
std::string m_tx_name;

PttHidraw(const PttHidraw&);
PttHidraw& operator=(const PttHidraw&);
bool openDevice(void);
void closeDevice(void);

}; /* class PttHidraw */

Expand Down
Loading
Loading