Compare commits
8 Commits
master
...
audiofilte
| Author | SHA1 | Date |
|---|---|---|
|
|
c0ea72e466 | |
|
|
861d4dc2fb | |
|
|
fe72601b61 | |
|
|
f119b77aed | |
|
|
0fc7462b8b | |
|
|
c363f0fde8 | |
|
|
3e29d82fa3 | |
|
|
7d4e3969d2 |
|
|
@ -0,0 +1,54 @@
|
|||
SvxLink
|
||||
=======
|
||||
|
||||
image:https://travis-ci.org/sm0svx/svxlink.svg?branch=master["Build Status", link="https://travis-ci.org/sm0svx/svxlink"]
|
||||
image:https://badges.gitter.im/Join%20Chat.svg[link="https://gitter.im/sm0svx/svxlink?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
|
||||
|
||||
SvxLink is a project that develops software targeting the ham radio community.
|
||||
It started out as an EchoLink application for Linux back in 2003 but has now
|
||||
evolved to be something much more advanced.
|
||||
|
||||
== SvxLink Server ==
|
||||
The SvxLink Server is a general purpose voice services system, which when
|
||||
connected to a transceiver, can act as both an advanced repeater system and can
|
||||
also operate on a simplex channel. One could call it a radio operating system.
|
||||
|
||||
SvxLink is very extensible and modular. Voice services are implemented as
|
||||
modules which are isolated from each other. Modules can be implemented in
|
||||
either C++ or TCL. Examples of modules are:
|
||||
|
||||
* *Help* -- A help system
|
||||
* *Parrot* -- Play back everything that is received
|
||||
* *EchoLink* -- Connect to other EchoLink stations
|
||||
* *DtmfRepeater* -- Repeater received DTMF digits
|
||||
* *TclVoiceMail* -- Send voice mail to other local users
|
||||
* *PropagationMonitor* -- Announce propagation warnings from dxmaps.com
|
||||
* *SelCall* -- Send selective calling sequences by entering DTMF codes
|
||||
* *MetarInformation* -- Play airport weather information
|
||||
* *Frn* -- Connect to Free Radio Network (FRN) servers
|
||||
|
||||
== Qtel ==
|
||||
Qtel, the Qt EchoLink client, is a graphical application used to access the
|
||||
EchoLink network.
|
||||
|
||||
== Resources ==
|
||||
These are some of the resources connected to SvxLink:
|
||||
|
||||
:gh_pages: http://svxlink.org/
|
||||
:gh_wiki: https://github.com/sm0svx/svxlink/wiki
|
||||
:gh_issues: https://github.com/sm0svx/svxlink/issues
|
||||
:gh_releases: https://github.com/sm0svx/svxlink/releases
|
||||
:gh_sndclips: https://github.com/sm0svx/svxlink-sounds-en_US-heather/releases
|
||||
:sf_lists: http://sourceforge.net/p/svxlink/mailman
|
||||
:gh_main: https://github.com/sm0svx/svxlink
|
||||
:sf_summary: https://sourceforge.net/projects/svxlink
|
||||
|
||||
* {gh_pages}[Project Home Page] -- The main project page
|
||||
* {gh_wiki}[Wiki Pages] -- Main documentation
|
||||
* {gh_issues}[Issue Tracker] -- Report bugs and feature requests
|
||||
* {gh_releases}[Download Releases] -- Download source code releases here
|
||||
* {gh_sndclips}[Download Sound Clips] -- Download English sound clip files for
|
||||
SvxLink Server from here
|
||||
* {sf_lists}[Mailing Lists] -- Communicate with other SvxLink users
|
||||
* {gh_main}[GitHub Main Page] -- The project site on GitHub
|
||||
* {sf_summary}[The SvxLink SourcForge Site] -- Old project site
|
||||
141
README.md
141
README.md
|
|
@ -1,141 +0,0 @@
|
|||
# Установка (svxlink-usrp)
|
||||
|
||||
```
|
||||
cd ~
|
||||
sudo apt update
|
||||
sudo apt upgrade -y
|
||||
sudo apt install g++ cmake make libsigc++-2.0-dev libgsm1-dev libpopt-dev tcl-dev libgcrypt20-dev
|
||||
sudo apt install libspeex-dev libasound2-dev libopus-dev librtlsdr-dev doxygen groff alsa-utils
|
||||
sudo apt install vorbis-tools curl libcurl4-openssl-dev git rtl-sdr libcurl4-openssl-dev libjsoncpp-dev
|
||||
|
||||
```
|
||||
Создаём пользователя svxlink с нужными свойствами
|
||||
```
|
||||
sudo useradd -rG audio,plugdev,gpio,dialout svxlink
|
||||
sudo gpasswd -a svxlink gpio
|
||||
|
||||
```
|
||||
Далее
|
||||
```
|
||||
git clone https://github.com/dl1hrc/svxlink.git
|
||||
cd svxlink
|
||||
git checkout svxlink-usrp
|
||||
cd src
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
```
|
||||
|
||||
Компилируем и устанавливаем (внимательно смотрим на ошибки). Время компиляции зависит от типа платы и длится примерно 10-30 минут
|
||||
```
|
||||
cmake -DUSE_QT=OFF -DCMAKE_INSTALL_PREFIX=/usr -DSYSCONF_INSTALL_DIR=/etc -DLOCAL_STATE_DIR=/var -DWITH_SYSTEMD=ON ..
|
||||
make -j4
|
||||
make doc
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
```
|
||||
|
||||
Устанавливаем русскоязычные звуковые файлы (спасибо ua6hjq):
|
||||
```
|
||||
wget http://ua6hjq.qrz.ru/files/rus-16k.tgz
|
||||
sudo tar xvf rus-16k.tgz -C /
|
||||
sudo chown -R svxlink:svxlink /usr/share/svxlink/sounds
|
||||
|
||||
```
|
||||
# Настройка
|
||||
Итак. У нас есть собранный из свежих исходников svxlink, который нужно предварительно настроить, как описано в статьях, в конце этой странички. Для этого (в первую очередь) редактируем эти файлы конфигурации
|
||||
```
|
||||
sudo nano /etc/svxlink/svxlink.conf
|
||||
sudo nano /etc/svxlink/gpio.conf
|
||||
|
||||
```
|
||||
# Запуск
|
||||
Правильно будет запустить svxlink в режиме демона и включить автозапуск, чтобы он стартовал самостоятельно, при перезагрузки системы. Делается это так:
|
||||
|
||||
```
|
||||
sudo systemctl enable --now svxlink
|
||||
|
||||
```
|
||||
Запуск, остановка и перезапуск в режиме демона. Если вы изменили любой конфигурационный файл, нужно обязательно перезапустить svxlink
|
||||
```
|
||||
sudo systemctl start svxlink
|
||||
sudo systemctl stop svxlink
|
||||
sudo systemctl restart svxlink
|
||||
```
|
||||
Увидеть что делает svxlink, в реальном времени, посмотреть ошибки, можно приведённой ниже командой , для выхода нажмите Ctrl+C
|
||||
```
|
||||
tail -f /var/log/svxlink
|
||||
|
||||
```
|
||||
|
||||
# Обновление
|
||||
Чтобы иметь всегда свежую версию svxlink, обновите исходный код, делаем это так:
|
||||
```
|
||||
sudo systemctl stop svxlink
|
||||
cd ~
|
||||
cd svxlink
|
||||
git pull
|
||||
cd src/build
|
||||
make clean
|
||||
......
|
||||
```
|
||||
и повторяем компиляцию (как описано выше) начиная от строки cmake .... ваша рабочая конфигурация в /etc/svxlink/ останется не тронутой, сразу после обновления, вы можете запускать svxlink и работать как раньше.
|
||||
|
||||
|
||||
|
||||
|
||||
SvxLink
|
||||
=======
|
||||
|
||||
image:https://travis-ci.org/sm0svx/svxlink.svg?branch=master["Build Status", link="https://travis-ci.org/sm0svx/svxlink"]
|
||||
image:https://badges.gitter.im/Join%20Chat.svg[link="https://gitter.im/sm0svx/svxlink?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
|
||||
|
||||
SvxLink is a project that develops software targeting the ham radio community.
|
||||
It started out as an EchoLink application for Linux back in 2003 but has now
|
||||
evolved to be something much more advanced.
|
||||
|
||||
== SvxLink Server ==
|
||||
The SvxLink Server is a general purpose voice services system, which when
|
||||
connected to a transceiver, can act as both an advanced repeater system and can
|
||||
also operate on a simplex channel. One could call it a radio operating system.
|
||||
|
||||
SvxLink is very extensible and modular. Voice services are implemented as
|
||||
modules which are isolated from each other. Modules can be implemented in
|
||||
either C++ or TCL. Examples of modules are:
|
||||
|
||||
* *Help* -- A help system
|
||||
* *Parrot* -- Play back everything that is received
|
||||
* *EchoLink* -- Connect to other EchoLink stations
|
||||
* *DtmfRepeater* -- Repeater received DTMF digits
|
||||
* *TclVoiceMail* -- Send voice mail to other local users
|
||||
* *PropagationMonitor* -- Announce propagation warnings from dxmaps.com
|
||||
* *SelCall* -- Send selective calling sequences by entering DTMF codes
|
||||
* *MetarInformation* -- Play airport weather information
|
||||
* *Frn* -- Connect to Free Radio Network (FRN) servers
|
||||
|
||||
== Qtel ==
|
||||
Qtel, the Qt EchoLink client, is a graphical application used to access the
|
||||
EchoLink network.
|
||||
|
||||
== Resources ==
|
||||
These are some of the resources connected to SvxLink:
|
||||
|
||||
:gh_pages: http://svxlink.org/
|
||||
:gh_wiki: https://github.com/sm0svx/svxlink/wiki
|
||||
:gh_issues: https://github.com/sm0svx/svxlink/issues
|
||||
:gh_releases: https://github.com/sm0svx/svxlink/releases
|
||||
:gh_sndclips: https://github.com/sm0svx/svxlink-sounds-en_US-heather/releases
|
||||
:sf_lists: http://sourceforge.net/p/svxlink/mailman
|
||||
:gh_main: https://github.com/sm0svx/svxlink
|
||||
:sf_summary: https://sourceforge.net/projects/svxlink
|
||||
|
||||
* {gh_pages}[Project Home Page] -- The main project page
|
||||
* {gh_wiki}[Wiki Pages] -- Main documentation
|
||||
* {gh_issues}[Issue Tracker] -- Report bugs and feature requests
|
||||
* {gh_releases}[Download Releases] -- Download source code releases here
|
||||
* {gh_sndclips}[Download Sound Clips] -- Download English sound clip files for
|
||||
SvxLink Server from here
|
||||
* {sf_lists}[Mailing Lists] -- Communicate with other SvxLink users
|
||||
* {gh_main}[GitHub Main Page] -- The project site on GitHub
|
||||
* {sf_summary}[The SvxLink SourcForge Site] -- Old project site
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
##############################################################################
|
||||
# SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
# Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX
|
||||
# Copyright (C) 2003-2013 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
|
||||
|
|
@ -30,11 +30,6 @@ set(PROJECT_INCLUDE_DIR ${PROJECT_BINARY_DIR}/include)
|
|||
# Where to put library files
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
|
||||
|
||||
# We need to force buildtime RPATH so that dlopen will find plugins in the
|
||||
# library output directory when running applications within the build tree
|
||||
# (uninstalled)
|
||||
set(CMAKE_BUILD_RPATH "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
|
||||
|
||||
# Where to put executable files
|
||||
set(RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
|
|
@ -176,11 +171,6 @@ if(NOT DEFINED SVX_MODULE_INSTALL_DIR)
|
|||
set(SVX_MODULE_INSTALL_DIR ${LIB_INSTALL_DIR}/svxlink)
|
||||
endif(NOT DEFINED SVX_MODULE_INSTALL_DIR)
|
||||
|
||||
# Where to install SvxLink logic cores
|
||||
if(NOT DEFINED SVX_LOGIC_CORE_INSTALL_DIR)
|
||||
set(SVX_LOGIC_CORE_INSTALL_DIR ${LIB_INSTALL_DIR}/svxlink)
|
||||
endif(NOT DEFINED SVX_LOGIC_CORE_INSTALL_DIR)
|
||||
|
||||
# Clear global variables implemented using internal cache
|
||||
set(CONFIG_FILES "" CACHE INTERNAL "CONFIG_FILES")
|
||||
set(FILE_OWNER "" CACHE INTERNAL "FILE_OWNER")
|
||||
|
|
@ -304,7 +294,6 @@ message(STATUS "SvxLink user = ${SVXLINK_USER}")
|
|||
message(STATUS "SvxLink group = ${SVXLINK_GROUP}")
|
||||
|
||||
# Add directories to build
|
||||
add_subdirectory(doc)
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(async)
|
||||
add_subdirectory(misc)
|
||||
|
|
@ -314,6 +303,7 @@ add_subdirectory(svxlink)
|
|||
if(USE_QT)
|
||||
add_subdirectory(qtel)
|
||||
endif(USE_QT)
|
||||
add_subdirectory(doc)
|
||||
|
||||
# Experimental CPack package building
|
||||
set(CPACK_SET_DESTDIR "ON")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
1.7.0 -- ?? ??? ????
|
||||
1.7.0 -- ?? ??? 2022
|
||||
----------------------
|
||||
|
||||
* ASYNC_AUDIO_ALSA_ZEROFILL is now enabled by default.
|
||||
|
|
@ -52,18 +52,13 @@
|
|||
VARNAME=88.5:-1,136.5:1. It is also possible to use other key/value
|
||||
separators.
|
||||
|
||||
* New class Async::StateMachine used to build Hierarchical Finite State
|
||||
* New class Async::StateMachine used to build Hierarchial Finate State
|
||||
Machines.
|
||||
|
||||
* New class Async::TcpPrioClient for handling pools of servers to connect to.
|
||||
The pool members can be specified using DNS SRV records or locally using the
|
||||
HOSTS configuration variable.
|
||||
|
||||
* Slightly changed semantics of the TcpClient::connect functions. It's now
|
||||
not allowed to call the connect function if already connected.
|
||||
|
||||
* Async::Plugin: A new class for loading code as plugins.
|
||||
|
||||
|
||||
|
||||
1.6.0 -- 01 Sep 2019
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ using namespace Async;
|
|||
****************************************************************************/
|
||||
|
||||
AtTimer::AtTimer(void)
|
||||
: m_expire_offset(0)
|
||||
{
|
||||
timerclear(&m_expire_at);
|
||||
m_timer.expired.connect(mem_fun(*this, &AtTimer::onTimerExpired));
|
||||
|
|
@ -124,6 +125,7 @@ AtTimer::AtTimer(void)
|
|||
|
||||
|
||||
AtTimer::AtTimer(struct tm &tm, bool do_start)
|
||||
: m_expire_offset(0)
|
||||
{
|
||||
timerclear(&m_expire_at);
|
||||
m_timer.expired.connect(mem_fun(*this, &AtTimer::onTimerExpired));
|
||||
|
|
|
|||
|
|
@ -137,8 +137,6 @@ class AtTimer : public sigc::trackable
|
|||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*
|
||||
* After default construction the timer will be disabled.
|
||||
*/
|
||||
AtTimer(void);
|
||||
|
||||
|
|
@ -148,7 +146,7 @@ class AtTimer : public sigc::trackable
|
|||
* @param do_start Set to \em true (default) if the timer should start
|
||||
* upon creation
|
||||
*/
|
||||
explicit AtTimer(struct tm &tm, bool do_start=true);
|
||||
AtTimer(struct tm &tm, bool do_start=true);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
|
|
@ -204,9 +202,9 @@ class AtTimer : public sigc::trackable
|
|||
protected:
|
||||
|
||||
private:
|
||||
Timer m_timer {-1};
|
||||
Timer m_timer;
|
||||
struct timeval m_expire_at;
|
||||
int m_expire_offset {0};
|
||||
int m_expire_offset;
|
||||
|
||||
AtTimer(const AtTimer&);
|
||||
AtTimer& operator=(const AtTimer&);
|
||||
|
|
|
|||
|
|
@ -127,8 +127,6 @@ FramedTcpConnection::FramedTcpConnection(
|
|||
: TcpConnection(sock, remote_addr, remote_port, recv_buf_len),
|
||||
m_max_frame_size(DEFAULT_MAX_FRAME_SIZE), m_size_received(false)
|
||||
{
|
||||
TcpConnection::sendBufferFull.connect(
|
||||
sigc::mem_fun(*this, &FramedTcpConnection::onSendBufferFull));
|
||||
} /* FramedTcpConnection::FramedTcpConnection */
|
||||
|
||||
|
||||
|
|
@ -223,6 +221,7 @@ int FramedTcpConnection::write(const void *buf, int count)
|
|||
|
||||
void FramedTcpConnection::closeConnection(void)
|
||||
{
|
||||
//cout << "### FramedTcpConnection::closeConnection\n";
|
||||
disconnectCleanup();
|
||||
TcpConnection::closeConnection();
|
||||
} /* FramedTcpConnection::closeConnection */
|
||||
|
|
@ -230,8 +229,11 @@ void FramedTcpConnection::closeConnection(void)
|
|||
|
||||
void FramedTcpConnection::onDisconnected(DisconnectReason reason)
|
||||
{
|
||||
//cout << "### FramedTcpConnection::onDisconnected: "
|
||||
// << TcpConnection::disconnectReasonStr(reason) << "\n";
|
||||
disconnectCleanup();
|
||||
TcpConnection::onDisconnected(reason);
|
||||
disconnected(this, reason);
|
||||
} /* FramedTcpConnection::onDisconnected */
|
||||
|
||||
|
||||
|
|
@ -255,7 +257,7 @@ int FramedTcpConnection::onDataReceived(void *buf, int count)
|
|||
if (m_frame_size > m_max_frame_size)
|
||||
{
|
||||
closeConnection();
|
||||
onDisconnected(DR_PROTOCOL_ERROR);
|
||||
disconnected(this, DR_PROTOCOL_ERROR);
|
||||
return orig_count - count;
|
||||
}
|
||||
m_frame.clear();
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ class FramedTcpConnection : public TcpConnection
|
|||
std::vector<uint8_t>&> frameReceived;
|
||||
|
||||
protected:
|
||||
sigc::signal<int, TcpConnection*, void*, int> dataReceived;
|
||||
sigc::signal<int, FramedTcpConnection *, void *, int> dataReceived;
|
||||
sigc::signal<void, bool> sendBufferFull;
|
||||
|
||||
/**
|
||||
|
|
@ -242,14 +242,10 @@ class FramedTcpConnection : public TcpConnection
|
|||
*/
|
||||
virtual int onDataReceived(void *buf, int count) override;
|
||||
|
||||
/**
|
||||
* @brief Emit the disconnected signal
|
||||
* @param reason The reason for the disconnection
|
||||
*/
|
||||
virtual void emitDisconnected(DisconnectReason reason) override
|
||||
{
|
||||
disconnected(this, reason);
|
||||
TcpConnection::emitDisconnected(reason);
|
||||
disconnected(this, reason);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -127,8 +127,6 @@ HttpServerConnection::HttpServerConnection(
|
|||
: TcpConnection(sock, remote_addr, remote_port, recv_buf_len),
|
||||
m_state(STATE_EXPECT_START_LINE), m_chunked(false)
|
||||
{
|
||||
TcpConnection::sendBufferFull.connect(
|
||||
sigc::mem_fun(*this, &HttpServerConnection::onSendBufferFull));
|
||||
} /* HttpServerConnection::HttpServerConnection */
|
||||
|
||||
|
||||
|
|
@ -205,9 +203,10 @@ bool HttpServerConnection::write(const Response& res)
|
|||
{
|
||||
std::ostringstream os;
|
||||
os << "HTTP/1.1 " << res.code() << " " << codeToString(res.code()) << "\r\n";
|
||||
for (const auto& header : res.headers())
|
||||
for (std::map<std::string, std::string>::const_iterator it=res.headers().begin();
|
||||
it!=res.headers().end(); ++it)
|
||||
{
|
||||
os << header.first << ": " << header.second << "\r\n";
|
||||
os << (*it).first << ": " << (*it).second << "\r\n";
|
||||
}
|
||||
if (m_chunked)
|
||||
{
|
||||
|
|
@ -257,6 +256,7 @@ bool HttpServerConnection::write(const char* buf, int len)
|
|||
|
||||
void HttpServerConnection::closeConnection(void)
|
||||
{
|
||||
//std::cout << "### HttpServerConnection::closeConnection" << std::endl;
|
||||
disconnectCleanup();
|
||||
TcpConnection::closeConnection();
|
||||
} /* HttpServerConnection::closeConnection */
|
||||
|
|
@ -264,8 +264,10 @@ void HttpServerConnection::closeConnection(void)
|
|||
|
||||
void HttpServerConnection::onDisconnected(DisconnectReason reason)
|
||||
{
|
||||
//cout << "### HttpServerConnection::onDisconnected: "
|
||||
// << TcpConnection::disconnectReasonStr(reason) << "\n";
|
||||
disconnectCleanup();
|
||||
TcpConnection::onDisconnected(reason);
|
||||
disconnected(this, reason);
|
||||
} /* HttpServerConnection::onDisconnected */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -323,14 +323,10 @@ class HttpServerConnection : public TcpConnection
|
|||
*/
|
||||
virtual int onDataReceived(void *buf, int count) override;
|
||||
|
||||
/**
|
||||
* @brief Emit the disconnected signal
|
||||
* @param reason The reason for the disconnection
|
||||
*/
|
||||
virtual void emitDisconnected(DisconnectReason reason) override
|
||||
{
|
||||
disconnected(this, reason);
|
||||
TcpConnection::emitDisconnected(reason);
|
||||
disconnected(this, reason);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -1,196 +0,0 @@
|
|||
/**
|
||||
@file AsyncPlugin.cpp
|
||||
@brief A base class for making a class into a dynamic loadable plugin
|
||||
@author Tobias Blomberg / SM0SVX
|
||||
@date 2022-08-23
|
||||
|
||||
\verbatim
|
||||
Async - A library for programming event driven applications
|
||||
Copyright (C) 2003-2022 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
\endverbatim
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* System Includes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <link.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Project Includes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Local Includes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "AsyncPlugin.h"
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Namespaces to use
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
using namespace Async;
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Defines & typedefs
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Static class variables
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Local class definitions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Local functions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
}; /* End of anonymous namespace */
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Public member functions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
Plugin* Plugin::load(const std::string& path)
|
||||
{
|
||||
//std::cout << "### Loading plugin \"" << path << "\"" << std::endl;
|
||||
|
||||
void *handle = nullptr;
|
||||
handle = dlopen(path.c_str(), RTLD_NOW);
|
||||
if (handle == nullptr)
|
||||
{
|
||||
std::cerr << "*** ERROR: Failed to load plugin "
|
||||
<< path << ": " << dlerror() << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct link_map *link_map;
|
||||
if (dlinfo(handle, RTLD_DI_LINKMAP, &link_map) == -1)
|
||||
{
|
||||
std::cerr << "*** ERROR: Could not read information for plugin "
|
||||
<< path << ": " << dlerror() << std::endl;
|
||||
dlclose(handle);
|
||||
return nullptr;
|
||||
}
|
||||
//std::cout << "### Found plugin " << link_map->l_name << std::endl;
|
||||
|
||||
ConstructFunc construct = (ConstructFunc)dlsym(handle, "construct");
|
||||
if (construct == nullptr)
|
||||
{
|
||||
std::cerr << "*** ERROR: Could not find construct function for plugin "
|
||||
<< path << ": " << dlerror() << std::endl;
|
||||
dlclose(handle);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Plugin *plugin = construct();
|
||||
if (plugin == nullptr)
|
||||
{
|
||||
std::cerr << "*** ERROR: Construction failed for plugin "
|
||||
<< path << std::endl;
|
||||
dlclose(handle);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
plugin->setHandle(handle);
|
||||
plugin->m_plugin_path = link_map->l_name;
|
||||
|
||||
return plugin;
|
||||
} /* Plugin::load */
|
||||
|
||||
|
||||
void Plugin::unload(Plugin* p)
|
||||
{
|
||||
if (p != nullptr)
|
||||
{
|
||||
void* handle = p->pluginHandle();
|
||||
delete p;
|
||||
dlclose(handle);
|
||||
}
|
||||
} /* Plugin::unload */
|
||||
|
||||
|
||||
Plugin::Plugin(void)
|
||||
{
|
||||
//std::cout << "### Plugin::Plugin" << std::endl;
|
||||
} /* Plugin::Plugin */
|
||||
|
||||
|
||||
Plugin::~Plugin(void)
|
||||
{
|
||||
//std::cout << "### Plugin::~Plugin" << std::endl;
|
||||
m_handle = nullptr;
|
||||
} /* Plugin::~Plugin */
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Protected member functions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Private member functions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This file has not been truncated
|
||||
*/
|
||||
|
|
@ -1,211 +0,0 @@
|
|||
/**
|
||||
@file AsyncPlugin.h
|
||||
@brief A base class for making a class into a dynamic loadable plugin
|
||||
@author Tobias Blomberg / SM0SVX
|
||||
@date 2022-08-23
|
||||
|
||||
\verbatim
|
||||
Async - A library for programming event driven applications
|
||||
Copyright (C) 2003-2022 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
\endverbatim
|
||||
*/
|
||||
|
||||
/** @example AsyncPlugin_demo.cpp
|
||||
An example of how to use the Async::Plugin class
|
||||
*/
|
||||
|
||||
#ifndef ASYNC_PLUGIN_INCLUDED
|
||||
#define ASYNC_PLUGIN_INCLUDED
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* System Includes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Project Includes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Local Includes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Forward declarations
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Namespace
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
namespace Async
|
||||
{
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Forward declarations of classes inside of the declared namespace
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Defines & typedefs
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Exported Global Variables
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Class definitions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
class PluginBase
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
@brief A base class for making a class into a dynamic loadable plugin
|
||||
@author Tobias Blomberg / SM0SVX
|
||||
@date 2022-08-23
|
||||
|
||||
A_detailed_class_description
|
||||
|
||||
\include AsyncPlugin_demo.cpp
|
||||
*/
|
||||
class Plugin : public PluginBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Load the plugin from the specified path
|
||||
* @param path The file path
|
||||
*/
|
||||
static Plugin* load(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief Load the plugin from the specified path returning correct type
|
||||
* @param path The file path
|
||||
*
|
||||
* The plugin may use this function to load the plugin, check that it is of
|
||||
* the correct type and then return a pointer to that type.
|
||||
*/
|
||||
template <class T>
|
||||
static T* load(const std::string& path)
|
||||
{
|
||||
Plugin* p = Plugin::load(path);
|
||||
if (p == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
T* demop = dynamic_cast<T*>(p);
|
||||
if (demop == nullptr)
|
||||
{
|
||||
std::cerr << "*** ERROR: Could not load plugin \"" << path
|
||||
<< "\": Not a \"" << T::typeName() << "\" plugin"
|
||||
<< std::endl;
|
||||
delete p;
|
||||
}
|
||||
return demop;
|
||||
}
|
||||
|
||||
static void unload(Plugin* p);
|
||||
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
Plugin(void);
|
||||
|
||||
/**
|
||||
* @brief Disallow copy construction
|
||||
*/
|
||||
Plugin(const Plugin&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Disallow copy assignment
|
||||
*/
|
||||
Plugin& operator=(const Plugin&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Retrieve the handle returned from the dlopen function
|
||||
* @return Returns a handle from dlopen (@see man 3 dlopen)
|
||||
*/
|
||||
void* pluginHandle(void) const { return m_handle; }
|
||||
|
||||
/**
|
||||
* @brief Retrieve the path used to find the plugin
|
||||
* @return Returns the path to the plugin
|
||||
*
|
||||
* This function can be called to find out which path was used to load the
|
||||
* plugin.
|
||||
*/
|
||||
const std::string& pluginPath(void) const { return m_plugin_path; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~Plugin(void);
|
||||
|
||||
private:
|
||||
typedef Plugin* (*ConstructFunc)(void);
|
||||
|
||||
void* m_handle = nullptr;
|
||||
std::string m_plugin_path;
|
||||
|
||||
void setHandle(void* handle) { m_handle = handle; }
|
||||
|
||||
}; /* class Plugin */
|
||||
|
||||
|
||||
} /* namespace Async */
|
||||
|
||||
#endif /* ASYNC_PLUGIN_INCLUDED */
|
||||
|
||||
/*
|
||||
* This file has not been truncated
|
||||
*/
|
||||
|
|
@ -49,7 +49,6 @@ An example of how to use the StateMachine class
|
|||
****************************************************************************/
|
||||
|
||||
#include <AsyncTimer.h>
|
||||
#include <AsyncAtTimer.h>
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -171,15 +170,8 @@ class StateMachine
|
|||
[&](Timer*)
|
||||
{
|
||||
assert(m_state != nullptr);
|
||||
clearTimeout();
|
||||
static_cast<StateTopBaseT*>(m_state)->timeoutEvent();
|
||||
});
|
||||
m_at_timer.expired.connect(
|
||||
[&](AtTimer*)
|
||||
{
|
||||
assert(m_state != nullptr);
|
||||
clearTimeoutAt();
|
||||
static_cast<StateTopBaseT*>(m_state)->timeoutAtEvent();
|
||||
clearTimeout();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -295,34 +287,15 @@ class StateMachine
|
|||
*
|
||||
* Use this function to set a timeout to occur after the specified number
|
||||
* of milliseconds. The timeoutEvent will be issued after the time has
|
||||
* expired.
|
||||
* expired. The timeout will be automatically cleared when an exit from a
|
||||
* state occur.
|
||||
*/
|
||||
void setTimeout(int timeout_ms)
|
||||
{
|
||||
#ifdef ASYNC_STATE_MACHINE_DEBUG
|
||||
std::cout << "### StateMachine: setTimeout(" << timeout_ms << ")"
|
||||
<< std::endl;
|
||||
#endif
|
||||
m_timer.setTimeout(timeout_ms);
|
||||
m_timer.setEnable(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a timeout after which the timeoutAtEvent is issued
|
||||
* @param tm The absolute time when the timeout should occur
|
||||
* @param expire_offset A millisecond offset for the timer expiration
|
||||
*
|
||||
* Use this function to set a timeout to occur at the specified absolute
|
||||
* time, plus or minus the offset value. The time is specified in local
|
||||
* time. The timeoutAtEvent will be issued after the time has expired.
|
||||
*/
|
||||
void setTimeoutAt(struct tm& tm, int expire_offset=0)
|
||||
{
|
||||
m_at_timer.setTimeout(tm);
|
||||
m_at_timer.setExpireOffset(expire_offset);
|
||||
m_at_timer.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear a pending timeout
|
||||
*
|
||||
|
|
@ -331,28 +304,13 @@ class StateMachine
|
|||
*/
|
||||
void clearTimeout(void)
|
||||
{
|
||||
#ifdef ASYNC_STATE_MACHINE_DEBUG
|
||||
std::cout << "### StateMachine: clearTimeout()" << std::endl;
|
||||
#endif
|
||||
m_timer.setEnable(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear a pending absolute time timeout
|
||||
*
|
||||
* Use this function to immediately cancel a running absolute time timeout
|
||||
* timer. See \ref setTimeoutAt for more information.
|
||||
*/
|
||||
void clearTimeoutAt(void)
|
||||
{
|
||||
m_at_timer.stop();
|
||||
}
|
||||
|
||||
private:
|
||||
StateTopT* m_state = nullptr;
|
||||
ContextT* m_ctx = nullptr;
|
||||
Timer m_timer = -1;
|
||||
AtTimer m_at_timer;
|
||||
StateTopT* m_state = nullptr;
|
||||
ContextT* m_ctx = nullptr;
|
||||
Timer m_timer = -1;
|
||||
}; /* StateMachine */
|
||||
|
||||
|
||||
|
|
@ -422,6 +380,7 @@ class StateBase : public ParentT
|
|||
{
|
||||
if (dynamic_cast<T*>(to) == nullptr)
|
||||
{
|
||||
ParentT::clearTimeout();
|
||||
dynamic_cast<T*>(this)->exit();
|
||||
ParentT::exitHandler(to);
|
||||
}
|
||||
|
|
@ -481,11 +440,6 @@ class StateBase : public ParentT
|
|||
assert(!"Async::StateBase: Unhandled timeoutEvent");
|
||||
}
|
||||
|
||||
virtual void timeoutAtEvent(void) override
|
||||
{
|
||||
assert(!"Async::StateBase: Unhandled timeoutAtEvent");
|
||||
}
|
||||
|
||||
}; /* StateBase */
|
||||
|
||||
|
||||
|
|
@ -554,24 +508,11 @@ class StateTopBase
|
|||
*
|
||||
* Use this function to set a timeout to occur after the specified number
|
||||
* of milliseconds. The timeoutEvent will be issued after the time has
|
||||
* expired.
|
||||
* expired. The timeout will be automatically cleared when an exit from a
|
||||
* state occur.
|
||||
*/
|
||||
void setTimeout(int timeout_ms) { m_sm->setTimeout(timeout_ms); }
|
||||
|
||||
/**
|
||||
* @brief Set a timeout after which the timeoutAtEvent is issued
|
||||
* @param tm The absolute time when the timeout should occur
|
||||
* @param expire_offset A millisecond offset for the timer expiration
|
||||
*
|
||||
* Use this function to set a timeout to occur at the specified absolute
|
||||
* time, plus or minus the offset value. The time is specified in local
|
||||
* time. The timeoutAtEvent will be issued after the time has expired.
|
||||
*/
|
||||
void setTimeoutAt(struct tm& tm, int expire_offset=0)
|
||||
{
|
||||
m_sm->setTimeoutAt(tm, expire_offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear a pending timeout
|
||||
*
|
||||
|
|
@ -580,14 +521,6 @@ class StateTopBase
|
|||
*/
|
||||
void clearTimeout(void) { m_sm->clearTimeout(); }
|
||||
|
||||
/**
|
||||
* @brief Clear a pending absolute time timeout
|
||||
*
|
||||
* Use this function to immediately cancel a running absolute time timeout
|
||||
* timer. See \ref setTimeoutAt for more information.
|
||||
*/
|
||||
void clearTimeoutAt(void) { m_sm->clearTimeoutAt(); }
|
||||
|
||||
/**
|
||||
* @brief Get the typeid for this state
|
||||
*/
|
||||
|
|
@ -623,19 +556,6 @@ class StateTopBase
|
|||
*/
|
||||
virtual void timeoutEvent(void) = 0;
|
||||
|
||||
/**
|
||||
* @brief Event function called when an absolute time timeout occurs
|
||||
*
|
||||
* This event function will be called when an absolute time timeout,
|
||||
* previously set up using the setTimeoutAt function, has occurred.
|
||||
*
|
||||
* As all event functions this is a virtual function which work like any
|
||||
* other virtual function in C++. The state which is furtherest down in the
|
||||
* hierarchy, which have the timeoutAtEvent function implemented, will have
|
||||
* the function called.
|
||||
*/
|
||||
virtual void timeoutAtEvent(void) = 0;
|
||||
|
||||
private:
|
||||
StateMachineT* m_sm;
|
||||
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ class TcpClient : public ConT, public TcpClientBase
|
|||
* disconnected, nothing will be done. The disconnected signal is not
|
||||
* emitted when this function is called
|
||||
*/
|
||||
virtual void disconnect(void) override { closeConnection(); }
|
||||
virtual void disconnect(void) { closeConnection(); }
|
||||
|
||||
/**
|
||||
* @brief Check if the connection is idle
|
||||
|
|
@ -210,7 +210,7 @@ class TcpClient : public ConT, public TcpClientBase
|
|||
* This function is used internally to close the connection to the remote
|
||||
* peer.
|
||||
*/
|
||||
virtual void closeConnection(void) override
|
||||
virtual void closeConnection(void)
|
||||
{
|
||||
ConT::closeConnection();
|
||||
TcpClientBase::closeConnection();
|
||||
|
|
|
|||
|
|
@ -135,16 +135,13 @@ TcpClientBase::TcpClientBase(TcpConnection *con)
|
|||
|
||||
TcpClientBase::TcpClientBase(TcpConnection *con, const string& remote_host,
|
||||
uint16_t remote_port)
|
||||
: con(con), sock(-1)
|
||||
: con(con), remote_host(remote_host), sock(-1)
|
||||
{
|
||||
IpAddress ip_addr(remote_host);
|
||||
if (!ip_addr.isEmpty())
|
||||
{
|
||||
con->setRemoteAddr(ip_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
dns.setLookupParams(remote_host);
|
||||
this->remote_host = ip_addr.toString();
|
||||
}
|
||||
con->setRemotePort(remote_port);
|
||||
wr_watch.activity.connect(mem_fun(*this, &TcpClientBase::connectHandler));
|
||||
|
|
@ -154,7 +151,7 @@ TcpClientBase::TcpClientBase(TcpConnection *con, const string& remote_host,
|
|||
|
||||
TcpClientBase::TcpClientBase(TcpConnection *con, const IpAddress& remote_ip,
|
||||
uint16_t remote_port)
|
||||
: con(con), sock(-1)
|
||||
: con(con), remote_host(remote_ip.toString()), sock(-1)
|
||||
{
|
||||
con->setRemoteAddr(remote_ip);
|
||||
con->setRemotePort(remote_port);
|
||||
|
|
@ -176,6 +173,9 @@ TcpClientBase& TcpClientBase::operator=(TcpClientBase&& other)
|
|||
|
||||
dns = std::move(other.dns);
|
||||
|
||||
remote_host = other.remote_host;
|
||||
other.remote_host.clear();
|
||||
|
||||
sock = other.sock;
|
||||
other.sock = -1;
|
||||
|
||||
|
|
@ -196,17 +196,12 @@ void TcpClientBase::setBindIp(const IpAddress& bind_ip)
|
|||
|
||||
void TcpClientBase::connect(const string &remote_host, uint16_t remote_port)
|
||||
{
|
||||
assert(isIdle() && con->isIdle());
|
||||
|
||||
this->remote_host = remote_host;
|
||||
IpAddress ip_addr(remote_host);
|
||||
if (!ip_addr.isEmpty())
|
||||
{
|
||||
con->setRemoteAddr(ip_addr);
|
||||
dns.setLookupParams("");
|
||||
}
|
||||
else
|
||||
{
|
||||
dns.setLookupParams(remote_host);
|
||||
this->remote_host = ip_addr.toString();
|
||||
}
|
||||
con->setRemotePort(remote_port);
|
||||
connect();
|
||||
|
|
@ -215,22 +210,33 @@ void TcpClientBase::connect(const string &remote_host, uint16_t remote_port)
|
|||
|
||||
void TcpClientBase::connect(const IpAddress& remote_ip, uint16_t remote_port)
|
||||
{
|
||||
assert(isIdle() && con->isIdle());
|
||||
|
||||
con->setRemoteAddr(remote_ip);
|
||||
remote_host = remote_ip.toString();
|
||||
con->setRemotePort(remote_port);
|
||||
dns.setLookupParams("");
|
||||
connect();
|
||||
} /* TcpClientBase::connect */
|
||||
|
||||
|
||||
void TcpClientBase::connect(void)
|
||||
{
|
||||
assert(isIdle() && con->isIdle());
|
||||
//std::cout << "### TcpClientBase::connect:"
|
||||
// << " dns.isPending()=" << dns.isPending()
|
||||
// << " sock=" << sock
|
||||
// << " con->socket()=" << con->socket()
|
||||
// << std::endl;
|
||||
|
||||
if (!dns.label().empty())
|
||||
// Do nothing if DNS lookup is pending, connection is pending or if the
|
||||
// connection is already established
|
||||
if (dns.isPending() || (sock != -1) || (con->socket() != -1))
|
||||
{
|
||||
dns.lookup();
|
||||
return;
|
||||
}
|
||||
|
||||
if (con->remoteHost().isEmpty() ||
|
||||
(remote_host != con->remoteHost().toString()))
|
||||
{
|
||||
assert(!remote_host.empty());
|
||||
dns.lookup(remote_host);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -239,13 +245,6 @@ void TcpClientBase::connect(void)
|
|||
} /* TcpClientBase::connect */
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Protected member functions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void TcpClientBase::closeConnection(void)
|
||||
{
|
||||
wr_watch.setEnabled(false);
|
||||
|
|
@ -261,6 +260,14 @@ void TcpClientBase::closeConnection(void)
|
|||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Protected member functions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Private member functions
|
||||
|
|
@ -269,27 +276,26 @@ void TcpClientBase::closeConnection(void)
|
|||
|
||||
void TcpClientBase::dnsResultsReady(DnsLookup& dns_lookup)
|
||||
{
|
||||
for (const auto& addr : dns.addresses())
|
||||
{
|
||||
if (!addr.isEmpty())
|
||||
{
|
||||
con->setRemoteAddr(addr);
|
||||
connectToRemote();
|
||||
return;
|
||||
}
|
||||
}
|
||||
//std::cout << "### TcpClientBase::dnsResultsReady" << std::endl;
|
||||
vector<IpAddress> result = dns.addresses();
|
||||
|
||||
closeConnection();
|
||||
con->onDisconnected(TcpConnection::DR_HOST_NOT_FOUND);
|
||||
if (result.empty() || result[0].isEmpty())
|
||||
{
|
||||
closeConnection();
|
||||
con->onDisconnected(TcpConnection::DR_HOST_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
con->setRemoteAddr(result[0]);
|
||||
|
||||
connectToRemote();
|
||||
} /* TcpClientBase::dnsResultsReady */
|
||||
|
||||
|
||||
void TcpClientBase::connectToRemote(void)
|
||||
{
|
||||
assert(sock == -1);
|
||||
assert(!con->remoteHost().isEmpty());
|
||||
assert(con->remotePort() > 0);
|
||||
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
|
|
|
|||
|
|
@ -176,17 +176,9 @@ class TcpClientBase : virtual public sigc::trackable
|
|||
* @return Returns the name of the remote host
|
||||
*
|
||||
* This function return the name of the remote host as it was given to the
|
||||
* connect call. If an IP address was used the text representation of that
|
||||
* will be returned.
|
||||
* connect call.
|
||||
*/
|
||||
std::string remoteHostName(void) const
|
||||
{
|
||||
if (!dns.label().empty())
|
||||
{
|
||||
return dns.label();
|
||||
}
|
||||
return con->remoteHost().toString();
|
||||
}
|
||||
const std::string& remoteHostName(void) const { return remote_host; }
|
||||
|
||||
/**
|
||||
* @brief Bind to the interface having the specified IP address
|
||||
|
|
@ -208,7 +200,7 @@ class TcpClientBase : virtual public sigc::trackable
|
|||
* This function will initiate a connection to the remote host. The
|
||||
* connection must not be written to before the connected signal
|
||||
* (see @ref TcpClient::connected) has been emitted. If the connection is
|
||||
* already established or pending, an assertion will be raised.
|
||||
* already established or pending, nothing will be done.
|
||||
*/
|
||||
void connect(const std::string &remote_host, uint16_t remote_port);
|
||||
|
||||
|
|
@ -220,7 +212,7 @@ class TcpClientBase : virtual public sigc::trackable
|
|||
* This function will initiate a connection to the remote host. The
|
||||
* connection must not be written to before the connected signal
|
||||
* (see @ref TcpClient::connected) has been emitted. If the connection is
|
||||
* already established or pending, an assertion will be raised.
|
||||
* already established or pending, nothing will be done.
|
||||
*/
|
||||
void connect(const Async::IpAddress& remote_ip, uint16_t remote_port);
|
||||
|
||||
|
|
@ -230,7 +222,7 @@ class TcpClientBase : virtual public sigc::trackable
|
|||
* This function will initiate a connection to the remote host. The
|
||||
* connection must not be written to before the connected signal
|
||||
* (see @ref TcpClient::connected) has been emitted. If the connection is
|
||||
* already established or pending, an assertion will be raised.
|
||||
* already established or pending, nothing will be done.
|
||||
*/
|
||||
void connect(void);
|
||||
|
||||
|
|
@ -249,12 +241,8 @@ class TcpClientBase : virtual public sigc::trackable
|
|||
*
|
||||
* A connection being idle means that it is not connected nor connecting.
|
||||
*/
|
||||
bool isIdle(void) const { return !dns.isPending() && (sock == -1); }
|
||||
bool isIdle(void) const { return (sock == -1); }
|
||||
|
||||
/**
|
||||
* @brief Return the connection object for this client connection
|
||||
* @return Returns the connection object
|
||||
*/
|
||||
TcpConnection* conObj(void) { return con; }
|
||||
|
||||
/**
|
||||
|
|
@ -291,6 +279,7 @@ class TcpClientBase : virtual public sigc::trackable
|
|||
private:
|
||||
TcpConnection * con;
|
||||
DnsLookup dns;
|
||||
std::string remote_host;
|
||||
int sock;
|
||||
FdWatch wr_watch;
|
||||
Async::IpAddress bind_ip;
|
||||
|
|
|
|||
|
|
@ -235,6 +235,7 @@ class TcpConnection : virtual public sigc::trackable
|
|||
* @return Returns \em true if the connection is idle
|
||||
*
|
||||
* A connection being idle means that it is not connected
|
||||
* NOTE: This function is overridden in Async::TcpClient.
|
||||
*/
|
||||
bool isIdle(void) const { return sock == -1; }
|
||||
|
||||
|
|
@ -320,7 +321,8 @@ class TcpConnection : virtual public sigc::trackable
|
|||
*/
|
||||
virtual void onDisconnected(DisconnectReason reason)
|
||||
{
|
||||
emitDisconnected(reason);
|
||||
//std::cout << "### TcpConnection::onDisconnected" << std::endl;
|
||||
disconnected(this, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -342,10 +344,6 @@ class TcpConnection : virtual public sigc::trackable
|
|||
return dataReceived(this, buf, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Emit the disconnected signal
|
||||
* @param reason The reason for the disconnection
|
||||
*/
|
||||
virtual void emitDisconnected(DisconnectReason reason)
|
||||
{
|
||||
disconnected(this, reason);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
|
|
@ -133,6 +132,23 @@ class TcpPrioClientBase::Machine
|
|||
ctx.connect_retry_wait.setRandomizePercent(p);
|
||||
}
|
||||
|
||||
void setBgConnectMinTime(unsigned t)
|
||||
{
|
||||
ctx.bg_connect_retry_wait.setMinTime(t);
|
||||
}
|
||||
void setBgConnectMaxTime(unsigned t)
|
||||
{
|
||||
ctx.bg_connect_retry_wait.setMaxTime(t);
|
||||
}
|
||||
void setBgConnectBackoffPercent(unsigned p)
|
||||
{
|
||||
ctx.bg_connect_retry_wait.setBackoffPercent(p);
|
||||
}
|
||||
void setBgConnectRandomizePercent(unsigned p)
|
||||
{
|
||||
ctx.bg_connect_retry_wait.setRandomizePercent(p);
|
||||
}
|
||||
|
||||
void setLookupParams(const std::string& label, DnsLookup::Type type)
|
||||
{
|
||||
ctx.dns.setLookupParams(label, DnsLookup::Type::SRV);
|
||||
|
|
@ -212,7 +228,7 @@ class TcpPrioClientBase::Machine
|
|||
operator Time() { return time(); }
|
||||
|
||||
private:
|
||||
Time m_min_time = 1000;
|
||||
Time m_min_time = 2000;
|
||||
Time m_max_time = 20000;
|
||||
Percent m_backoff = 50;
|
||||
Percent m_randomize = 10;
|
||||
|
|
@ -231,6 +247,7 @@ class TcpPrioClientBase::Machine
|
|||
DnsSRVList rrs;
|
||||
DnsSRVList::iterator next_rr = rrs.end();
|
||||
BackoffTime connect_retry_wait;
|
||||
BackoffTime bg_connect_retry_wait;
|
||||
|
||||
Context(TcpPrioClientBase *client)
|
||||
: client(client), bg_con(client->newTcpClient()) {}
|
||||
|
|
@ -252,8 +269,7 @@ class TcpPrioClientBase::Machine
|
|||
|
||||
void emitConnected(void)
|
||||
{
|
||||
//client->emitConnected();
|
||||
client->TcpClientBase::connectionEstablished();
|
||||
client->emitConnected();
|
||||
}
|
||||
|
||||
bool isIdle(void) const
|
||||
|
|
@ -261,7 +277,7 @@ class TcpPrioClientBase::Machine
|
|||
return client->isIdle();
|
||||
}
|
||||
|
||||
std::string remoteHostName(void) const
|
||||
const std::string& remoteHostName(void) const
|
||||
{
|
||||
return client->remoteHostName();
|
||||
}
|
||||
|
|
@ -426,11 +442,6 @@ class TcpPrioClientBase::Machine
|
|||
setTimeout(ctx().connect_retry_wait);
|
||||
}
|
||||
|
||||
void exit(void) noexcept
|
||||
{
|
||||
clearTimeout();
|
||||
}
|
||||
|
||||
virtual void timeoutEvent(void) noexcept override
|
||||
{
|
||||
DEBUG_EVENT;
|
||||
|
|
@ -481,7 +492,12 @@ class TcpPrioClientBase::Machine
|
|||
: Async::StateBase<StateConnected, StateConnectedLowerPrio>
|
||||
{
|
||||
static constexpr auto NAME = "ConnectedLowerPrio";
|
||||
}; /* StateConnectedLowerPrio */
|
||||
void entry(void) noexcept
|
||||
{
|
||||
DEBUG_EVENT;
|
||||
ctx().bg_connect_retry_wait.reset();
|
||||
}
|
||||
}; /* StateConnecting */
|
||||
|
||||
|
||||
struct StateConnectedLowerPrioIdle
|
||||
|
|
@ -491,23 +507,10 @@ class TcpPrioClientBase::Machine
|
|||
|
||||
void entry(void) noexcept
|
||||
{
|
||||
struct timeval tv;
|
||||
auto err = gettimeofday(&tv, NULL);
|
||||
assert(err == 0);
|
||||
struct tm tm;
|
||||
time_t timeout_at = tv.tv_sec + 60;
|
||||
auto tm_ret = localtime_r(&timeout_at, &tm);
|
||||
assert(tm_ret == &tm);
|
||||
tm.tm_sec = 0;
|
||||
setTimeoutAt(tm, std::rand() % 500);
|
||||
setTimeout(ctx().bg_connect_retry_wait.time());
|
||||
}
|
||||
|
||||
void exit(void) noexcept
|
||||
{
|
||||
clearTimeoutAt();
|
||||
}
|
||||
|
||||
virtual void timeoutAtEvent(void) noexcept override
|
||||
virtual void timeoutEvent(void) noexcept override
|
||||
{
|
||||
DEBUG_EVENT;
|
||||
setState<StateConnectedLowerPrioSRVLookup>();
|
||||
|
|
@ -679,6 +682,30 @@ void TcpPrioClientBase::setReconnectRandomizePercent(unsigned p)
|
|||
}
|
||||
|
||||
|
||||
void TcpPrioClientBase::setBgConnectMinTime(unsigned t)
|
||||
{
|
||||
m_machine->setBgConnectMinTime(t);
|
||||
}
|
||||
|
||||
|
||||
void TcpPrioClientBase::setBgConnectMaxTime(unsigned t)
|
||||
{
|
||||
m_machine->setBgConnectMaxTime(t);
|
||||
}
|
||||
|
||||
|
||||
void TcpPrioClientBase::setBgConnectBackoffPercent(unsigned p)
|
||||
{
|
||||
m_machine->setBgConnectBackoffPercent(p);
|
||||
}
|
||||
|
||||
|
||||
void TcpPrioClientBase::setBgConnectRandomizePercent(unsigned p)
|
||||
{
|
||||
m_machine->setBgConnectRandomizePercent(p);
|
||||
}
|
||||
|
||||
|
||||
void TcpPrioClientBase::setService(const std::string& srv_name,
|
||||
const std::string& srv_proto,
|
||||
const std::string& srv_domain)
|
||||
|
|
|
|||
|
|
@ -169,6 +169,30 @@ class TcpPrioClientBase : public TcpClientBase
|
|||
*/
|
||||
void setReconnectRandomizePercent(unsigned p);
|
||||
|
||||
/**
|
||||
* @brief Minimum time between background reconnects
|
||||
* @param t Time in milliseconds
|
||||
*/
|
||||
void setBgConnectMinTime(unsigned t);
|
||||
|
||||
/**
|
||||
* @brief Maximum time between background reconnects
|
||||
* @param t Time in milliseconds
|
||||
*/
|
||||
void setBgConnectMaxTime(unsigned t);
|
||||
|
||||
/**
|
||||
* @brief Percent to increase background reconnect time with each try
|
||||
* @param p Percent
|
||||
*/
|
||||
void setBgConnectBackoffPercent(unsigned p);
|
||||
|
||||
/**
|
||||
* @brief Percent to randomize background reconnect time
|
||||
* @param p Percent
|
||||
*/
|
||||
void setBgConnectRandomizePercent(unsigned p);
|
||||
|
||||
/**
|
||||
* @brief Use a DNS service resource record for connections
|
||||
* @param srv_name The name of the service
|
||||
|
|
@ -288,7 +312,7 @@ class TcpPrioClientBase : public TcpClientBase
|
|||
* when a connection has been established. The overriding function should
|
||||
* normally call this function.
|
||||
*/
|
||||
virtual void connectionEstablished(void) override;
|
||||
virtual void connectionEstablished(void);
|
||||
|
||||
/**
|
||||
* @brief Called when a connection has been terminated
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
\verbatim
|
||||
Async - A library for programming event driven applications
|
||||
Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2014 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
|
||||
|
|
@ -36,10 +36,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
|
|
@ -52,6 +50,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
||||
#include <AsyncFdWatch.h>
|
||||
#include <AsyncApplication.h>
|
||||
#include <AsyncFramedTcpConnection.h>
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -96,6 +95,9 @@ using namespace Async;
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
namespace {
|
||||
void delete_connection(TcpConnection *con);
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -106,6 +108,7 @@ using namespace Async;
|
|||
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Local Global Variables
|
||||
|
|
@ -302,7 +305,7 @@ void TcpServerBase::removeConnection(TcpConnection *con)
|
|||
it = find(tcpConnectionList.begin(), tcpConnectionList.end(), con);
|
||||
assert(it != tcpConnectionList.end());
|
||||
tcpConnectionList.erase(it);
|
||||
Application::app().runTask([=]{ delete con; });
|
||||
Application::app().runTask(sigc::bind(sigc::ptr_fun(&delete_connection), con));
|
||||
} /* TcpServerBase::onDisconnected */
|
||||
|
||||
|
||||
|
|
@ -378,6 +381,11 @@ void TcpServerBase::onConnection(FdWatch *watch)
|
|||
} /* TcpServerBase::onConnection */
|
||||
|
||||
|
||||
namespace {
|
||||
void delete_connection(TcpConnection *con) { delete con; }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This file has not been truncated
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@ set(EXPINC AsyncApplication.h AsyncFdWatch.h AsyncTimer.h AsyncIpAddress.h
|
|||
AsyncAtTimer.h AsyncExec.h AsyncPty.h AsyncPtyStreamBuf.h AsyncMsg.h
|
||||
AsyncFramedTcpConnection.h AsyncTcpClientBase.h AsyncTcpServerBase.h
|
||||
AsyncHttpServerConnection.h AsyncFactory.h AsyncDnsResourceRecord.h
|
||||
AsyncTcpPrioClientBase.h AsyncTcpPrioClient.h AsyncStateMachine.h
|
||||
AsyncPlugin.h)
|
||||
AsyncTcpPrioClientBase.h AsyncTcpPrioClient.h AsyncStateMachine.h)
|
||||
|
||||
set(LIBSRC AsyncApplication.cpp AsyncFdWatch.cpp AsyncTimer.cpp
|
||||
AsyncIpAddress.cpp AsyncDnsLookup.cpp AsyncTcpClientBase.cpp
|
||||
|
|
@ -16,7 +15,7 @@ set(LIBSRC AsyncApplication.cpp AsyncFdWatch.cpp AsyncTimer.cpp
|
|||
AsyncSerialDevice.cpp AsyncFileReader.cpp
|
||||
AsyncAtTimer.cpp AsyncExec.cpp AsyncPty.cpp AsyncPtyStreamBuf.cpp
|
||||
AsyncFramedTcpConnection.cpp AsyncHttpServerConnection.cpp
|
||||
AsyncTcpPrioClientBase.cpp AsyncPlugin.cpp)
|
||||
AsyncTcpPrioClientBase.cpp)
|
||||
|
||||
# Copy exported include files to the global include directory
|
||||
foreach(incfile ${EXPINC})
|
||||
|
|
@ -31,13 +30,6 @@ set(LIBS ${LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
|||
# FIXME: Do we need this?
|
||||
add_definitions(-D_REENTRANT)
|
||||
|
||||
# Find the dl library - only for Linux, not required for FreeBSD
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
find_package(DL REQUIRED)
|
||||
set(LIBS ${LIBS} ${DL_LIBRARIES})
|
||||
include_directories(${DL_INCLUDES})
|
||||
endif()
|
||||
|
||||
# Build a shared library and a static library if configured
|
||||
add_library(${LIBNAME} SHARED ${LIBSRC})
|
||||
set_target_properties(${LIBNAME} PROPERTIES VERSION ${VER_LIBASYNC}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ used by Async::CppApplication to execute DNS queries.
|
|||
|
||||
\verbatim
|
||||
Async - A library for programming event driven applications
|
||||
Copyright (C) 2003-2023 Tobias Blomberg
|
||||
Copyright (C) 2003-2022 Tobias Blomberg
|
||||
|
||||
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
|
||||
|
|
@ -172,20 +172,23 @@ bool CppDnsLookupWorker::doLookup(void)
|
|||
int fd[2];
|
||||
if (pipe(fd) != 0)
|
||||
{
|
||||
printErrno("ERROR: Could not create pipe");
|
||||
char errbuf[256];
|
||||
strerror_r(errno, errbuf, sizeof(errbuf));
|
||||
std::cerr << "*** ERROR: Could not create pipe: " << errbuf << std::endl;
|
||||
setLookupFailed();
|
||||
return false;
|
||||
}
|
||||
m_notifier_watch.setFd(fd[0], FdWatch::FD_WATCH_RD);
|
||||
m_notifier_watch.setEnabled(true);
|
||||
|
||||
m_ctx = std::unique_ptr<ThreadContext>(new ThreadContext);
|
||||
m_ctx->label = dns().label();
|
||||
m_ctx->type = dns().type();
|
||||
m_ctx->notifier_wr = fd[1];
|
||||
m_ctx->anslen = 0;
|
||||
m_ctx->thread_cerr.clear();
|
||||
m_result = std::async(std::launch::async, workerFunc, std::ref(*m_ctx));
|
||||
ThreadContext ctx;
|
||||
ctx.label = dns().label();
|
||||
ctx.type = dns().type();
|
||||
ctx.notifier_wr = fd[1];
|
||||
ctx.anslen = 0;
|
||||
ctx.thread_cerr.clear();
|
||||
m_result = std::move(std::async(std::launch::async, workerFunc,
|
||||
std::move(ctx)));
|
||||
|
||||
return true;
|
||||
|
||||
|
|
@ -196,7 +199,13 @@ void CppDnsLookupWorker::abortLookup(void)
|
|||
{
|
||||
if (m_result.valid())
|
||||
{
|
||||
m_result.get();
|
||||
const ThreadContext& ctx(m_result.get());
|
||||
|
||||
if (ctx.addrinfo != nullptr)
|
||||
{
|
||||
freeaddrinfo(ctx.addrinfo);
|
||||
}
|
||||
//m_result = std::move(std::future<ThreadContext>());
|
||||
}
|
||||
|
||||
int fd = m_notifier_watch.fd();
|
||||
|
|
@ -205,8 +214,6 @@ void CppDnsLookupWorker::abortLookup(void)
|
|||
m_notifier_watch.setFd(-1, FdWatch::FD_WATCH_RD);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
m_ctx.reset();
|
||||
} /* CppDnsLookupWorker::abortLookup */
|
||||
|
||||
|
||||
|
|
@ -232,7 +239,8 @@ void CppDnsLookupWorker::abortLookup(void)
|
|||
* Bugs:
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
void CppDnsLookupWorker::workerFunc(CppDnsLookupWorker::ThreadContext& ctx)
|
||||
CppDnsLookupWorker::ThreadContext CppDnsLookupWorker::workerFunc(
|
||||
CppDnsLookupWorker::ThreadContext ctx)
|
||||
{
|
||||
std::ostream& th_cerr = ctx.thread_cerr;
|
||||
|
||||
|
|
@ -312,7 +320,7 @@ void CppDnsLookupWorker::workerFunc(CppDnsLookupWorker::ThreadContext& ctx)
|
|||
state.options = RES_DEFAULT;
|
||||
const char *dname = ctx.label.c_str();
|
||||
ctx.anslen = res_nsearch(&state, dname, ns_c_in, qtype,
|
||||
ctx.answer, sizeof(ctx.answer));
|
||||
ctx.answer, NS_PACKETSZ);
|
||||
if (ctx.anslen == -1)
|
||||
{
|
||||
th_cerr << "*** ERROR: Name resolver failure -- res_nsearch: "
|
||||
|
|
@ -335,6 +343,8 @@ void CppDnsLookupWorker::workerFunc(CppDnsLookupWorker::ThreadContext& ctx)
|
|||
|
||||
close(ctx.notifier_wr);
|
||||
ctx.notifier_wr = -1;
|
||||
|
||||
return std::move(ctx);
|
||||
} /* CppDnsLookupWorker::workerFunc */
|
||||
|
||||
|
||||
|
|
@ -360,22 +370,22 @@ void CppDnsLookupWorker::notificationReceived(FdWatch *w)
|
|||
close(w->fd());
|
||||
w->setFd(-1, FdWatch::FD_WATCH_RD);
|
||||
|
||||
m_result.get();
|
||||
const ThreadContext& ctx(m_result.get());
|
||||
|
||||
const std::string& thread_errstr = m_ctx->thread_cerr.str();
|
||||
const std::string& thread_errstr = ctx.thread_cerr.str();
|
||||
if (!thread_errstr.empty())
|
||||
{
|
||||
std::cerr << thread_errstr;
|
||||
setLookupFailed();
|
||||
}
|
||||
|
||||
if (m_ctx->type == DnsResourceRecord::Type::A)
|
||||
if (ctx.type == DnsResourceRecord::Type::A)
|
||||
{
|
||||
if (m_ctx->addrinfo != nullptr)
|
||||
if (ctx.addrinfo != nullptr)
|
||||
{
|
||||
struct addrinfo *entry;
|
||||
std::vector<IpAddress> the_addresses;
|
||||
for (entry = m_ctx->addrinfo; entry != 0; entry = entry->ai_next)
|
||||
for (entry = ctx.addrinfo; entry != 0; entry = entry->ai_next)
|
||||
{
|
||||
IpAddress ip_addr(
|
||||
reinterpret_cast<struct sockaddr_in*>(entry->ai_addr)->sin_addr);
|
||||
|
|
@ -388,35 +398,35 @@ void CppDnsLookupWorker::notificationReceived(FdWatch *w)
|
|||
{
|
||||
the_addresses.push_back(ip_addr);
|
||||
addResourceRecord(
|
||||
new DnsResourceRecordA(m_ctx->label, 0, ip_addr));
|
||||
new DnsResourceRecordA(ctx.label, 0, ip_addr));
|
||||
}
|
||||
}
|
||||
m_ctx.reset();
|
||||
freeaddrinfo(ctx.addrinfo);
|
||||
}
|
||||
}
|
||||
else if (m_ctx->type == DnsResourceRecord::Type::PTR)
|
||||
else if (ctx.type == DnsResourceRecord::Type::PTR)
|
||||
{
|
||||
if (m_ctx->host[0] != '\0')
|
||||
if (ctx.host[0] != '\0')
|
||||
{
|
||||
addResourceRecord(
|
||||
new DnsResourceRecordPTR(m_ctx->label, 0, m_ctx->host));
|
||||
new DnsResourceRecordPTR(ctx.label, 0, ctx.host));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_ctx->anslen == -1)
|
||||
if (ctx.anslen == -1)
|
||||
{
|
||||
workerDone();
|
||||
return;
|
||||
}
|
||||
|
||||
char errbuf[256];
|
||||
ns_msg msg;
|
||||
int ret = ns_initparse(m_ctx->answer, m_ctx->anslen, &msg);
|
||||
int ret = ns_initparse(ctx.answer, ctx.anslen, &msg);
|
||||
if (ret == -1)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "WARNING: ns_initparse failed (anslen=" << m_ctx->anslen << ")";
|
||||
printErrno(ss.str());
|
||||
strerror_r(ret, errbuf, sizeof(errbuf));
|
||||
std::cerr << "*** WARNING: ns_initparse failed: " << errbuf << std::endl;
|
||||
setLookupFailed();
|
||||
workerDone();
|
||||
return;
|
||||
|
|
@ -433,7 +443,9 @@ void CppDnsLookupWorker::notificationReceived(FdWatch *w)
|
|||
ret = ns_parserr(&msg, ns_s_an, rrnum, &rr);
|
||||
if (ret == -1)
|
||||
{
|
||||
printErrno("WARNING: DNS lookup failure in ns_parserr");
|
||||
strerror_r(errno, errbuf, sizeof(errbuf));
|
||||
std::cerr << "*** WARNING: DNS lookup failure in ns_parserr: "
|
||||
<< errbuf << std::endl;
|
||||
setLookupFailed();
|
||||
continue;
|
||||
}
|
||||
|
|
@ -468,7 +480,9 @@ void CppDnsLookupWorker::notificationReceived(FdWatch *w)
|
|||
exp_dn, NS_MAXDNAME);
|
||||
if (ret == -1)
|
||||
{
|
||||
printErrno("WARNING: DNS lookup failure in ns_name_uncompress");
|
||||
strerror_r(errno, errbuf, sizeof(errbuf));
|
||||
std::cerr << "*** WARNING: DNS lookup failure in "
|
||||
"ns_name_uncompress: " << errbuf << std::endl;
|
||||
setLookupFailed();
|
||||
continue;
|
||||
}
|
||||
|
|
@ -486,7 +500,9 @@ void CppDnsLookupWorker::notificationReceived(FdWatch *w)
|
|||
exp_dn, NS_MAXDNAME);
|
||||
if (ret == -1)
|
||||
{
|
||||
printErrno("WARNING: DNS lookup failure in ns_name_uncompress");
|
||||
strerror_r(errno, errbuf, sizeof(errbuf));
|
||||
std::cerr << "*** WARNING: DNS lookup failure in "
|
||||
"ns_name_uncompress" << errbuf << std::endl;
|
||||
setLookupFailed();
|
||||
continue;
|
||||
}
|
||||
|
|
@ -510,7 +526,9 @@ void CppDnsLookupWorker::notificationReceived(FdWatch *w)
|
|||
exp_dn, NS_MAXDNAME);
|
||||
if (ret == -1)
|
||||
{
|
||||
printErrno("WARNING: DNS lookup failure in ns_name_uncompress");
|
||||
strerror_r(errno, errbuf, sizeof(errbuf));
|
||||
std::cerr << "*** WARNING: DNS lookup failure in "
|
||||
"ns_name_uncompress: " << errbuf << std::endl;
|
||||
setLookupFailed();
|
||||
continue;
|
||||
}
|
||||
|
|
@ -534,19 +552,6 @@ void CppDnsLookupWorker::notificationReceived(FdWatch *w)
|
|||
} /* CppDnsLookupWorker::notificationReceived */
|
||||
|
||||
|
||||
void CppDnsLookupWorker::printErrno(const std::string& msg)
|
||||
{
|
||||
char errbuf[1024];
|
||||
char* errmsg = errbuf;
|
||||
#if (_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE
|
||||
int ret = strerror_r(errno, errbuf, sizeof(errbuf));
|
||||
assert(ret == 0);
|
||||
#else
|
||||
errmsg = strerror_r(errno, errbuf, sizeof(errbuf));
|
||||
#endif
|
||||
std::cerr << "*** " << msg << ": " << errmsg << std::endl;
|
||||
} /* CppDnsLookupWorker::printErrno */
|
||||
|
||||
|
||||
/*
|
||||
* This file has not been truncated
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ used by Async::CppApplication to execute DNS queries.
|
|||
|
||||
\verbatim
|
||||
Async - A library for programming event driven applications
|
||||
Copyright (C) 2003-2023 Tobias Blomberg
|
||||
Copyright (C) 2003-2022 Tobias Blomberg
|
||||
|
||||
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
|
||||
|
|
@ -164,29 +164,18 @@ class CppDnsLookupWorker : public DnsLookupWorker, public sigc::trackable
|
|||
std::string label;
|
||||
DnsLookup::Type type = DnsLookup::Type::A;
|
||||
int notifier_wr = -1;
|
||||
unsigned char answer[NS_MAXMSG];
|
||||
unsigned char answer[NS_PACKETSZ];
|
||||
int anslen = 0;
|
||||
struct addrinfo* addrinfo = nullptr;
|
||||
char host[NI_MAXHOST] = {0};
|
||||
std::ostringstream thread_cerr;
|
||||
|
||||
~ThreadContext(void)
|
||||
{
|
||||
if (addrinfo != nullptr)
|
||||
{
|
||||
freeaddrinfo(addrinfo);
|
||||
addrinfo = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Async::FdWatch m_notifier_watch;
|
||||
std::future<void> m_result;
|
||||
std::unique_ptr<ThreadContext> m_ctx;
|
||||
Async::FdWatch m_notifier_watch;
|
||||
std::future<ThreadContext> m_result;
|
||||
|
||||
static void workerFunc(ThreadContext& ctx);
|
||||
static ThreadContext workerFunc(ThreadContext ctx);
|
||||
void notificationReceived(FdWatch *w);
|
||||
void printErrno(const std::string& msg);
|
||||
|
||||
}; /* class CppDnsLookupWorker */
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
#include <iostream>
|
||||
#include "DemoPluginBase.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
auto p = Async::Plugin::load<DemoPluginBase>("DemoPlugin.so");
|
||||
if (p == nullptr)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
std::cout << "Found plugin " << p->pluginPath() << std::endl;
|
||||
p->initialize("hello");
|
||||
Async::Plugin::unload(p);
|
||||
p = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
#include <AsyncCppApplication.h>
|
||||
#include <AsyncTcpClient.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace Async;
|
||||
|
||||
class MyClass : public sigc::trackable
|
||||
|
|
@ -9,41 +10,38 @@ class MyClass : public sigc::trackable
|
|||
public:
|
||||
MyClass(void)
|
||||
{
|
||||
con.connected.connect(mem_fun(*this, &MyClass::onConnected));
|
||||
con.disconnected.connect(mem_fun(*this, &MyClass::onDisconnected));
|
||||
con.dataReceived.connect(mem_fun(*this, &MyClass::onDataReceived));
|
||||
con.connect("www.svxlink.org", 80);
|
||||
con = new TcpClient<>("www.linux.org", 80);
|
||||
con->connected.connect(mem_fun(*this, &MyClass::onConnected));
|
||||
con->disconnected.connect(mem_fun(*this, &MyClass::onDisconnected));
|
||||
con->dataReceived.connect(mem_fun(*this, &MyClass::onDataReceived));
|
||||
con->connect();
|
||||
}
|
||||
|
||||
~MyClass(void)
|
||||
{
|
||||
delete con;
|
||||
}
|
||||
|
||||
private:
|
||||
TcpClient<> con;
|
||||
|
||||
TcpClient<>* con;
|
||||
|
||||
void onConnected(void)
|
||||
{
|
||||
std::cout << "--- Connection established to " << con.remoteHost()
|
||||
<< std::endl;
|
||||
std::string req(
|
||||
"GET / HTTP/1.0\r\n"
|
||||
"Host: " + con.remoteHostName() + "\r\n"
|
||||
"\r\n");
|
||||
std::cout << "--- Sending request:\n" << req << std::endl;
|
||||
con.write(req.data(), req.size());
|
||||
cout << "Connection established to " << con->remoteHost() << "...\n";
|
||||
con->write("GET /\n", 6);
|
||||
}
|
||||
|
||||
void onDisconnected(TcpConnection *, TcpClient<>::DisconnectReason reason)
|
||||
|
||||
void onDisconnected(TcpConnection *con, TcpClient<>::DisconnectReason reason)
|
||||
{
|
||||
std::cout << "--- Disconnected from " << con.remoteHost() << ": "
|
||||
<< TcpConnection::disconnectReasonStr(reason)
|
||||
<< std::endl;
|
||||
cout << "Disconnected from " << con->remoteHost() << "...\n";
|
||||
Application::app().quit();
|
||||
}
|
||||
|
||||
int onDataReceived(TcpConnection *, void *buf, int count)
|
||||
|
||||
int onDataReceived(TcpConnection *con, void *buf, int count)
|
||||
{
|
||||
std::cout << "--- Data received:" << std::endl;
|
||||
const char *str = static_cast<char *>(buf);
|
||||
std::string html(str, str+count);
|
||||
std::cout << html;
|
||||
char *str = static_cast<char *>(buf);
|
||||
string html(str, str+count);
|
||||
cout << html;
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,13 +6,12 @@ set(CPPPROGS AsyncAudioIO_demo AsyncDnsLookup_demo AsyncFdWatch_demo
|
|||
AsyncFramedTcpClient_demo AsyncAudioSelector_demo
|
||||
AsyncAudioFsf_demo AsyncHttpServer_demo AsyncFactory_demo
|
||||
AsyncAudioContainer_demo AsyncTcpPrioClient_demo
|
||||
AsyncStateMachine_demo AsyncPlugin_demo
|
||||
AsyncStateMachine_demo
|
||||
)
|
||||
|
||||
set(QTPROGS AsyncQtApplication_demo)
|
||||
|
||||
|
||||
# Build all demo applications
|
||||
foreach(prog ${CPPPROGS})
|
||||
add_executable(${prog} ${prog}.cpp)
|
||||
target_link_libraries(${prog} ${LIBS} asynccpp asyncaudio asynccore)
|
||||
|
|
@ -46,9 +45,3 @@ if(USE_QT)
|
|||
endforeach(prog)
|
||||
endif(USE_QT)
|
||||
|
||||
# Build the demo plugin used by the AsyncPlugin_demo application
|
||||
add_library(DemoPlugin MODULE DemoPlugin.cpp)
|
||||
set_target_properties(DemoPlugin PROPERTIES PREFIX "")
|
||||
set_property(TARGET DemoPlugin PROPERTY NO_SONAME 1)
|
||||
#target_link_libraries(DemoPlugin ${LIBS})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
#include <iostream>
|
||||
#include "DemoPluginBase.h"
|
||||
|
||||
class DemoPlugin : public DemoPluginBase
|
||||
{
|
||||
public:
|
||||
DemoPlugin(void)
|
||||
{
|
||||
std::cout << "### DemoPlugin::DemoPlugin" << std::endl;
|
||||
}
|
||||
virtual bool initialize(const std::string& str) override
|
||||
{
|
||||
std::cout << "### DemoPlugin::initialize: str=" << str << std::endl;
|
||||
return true;
|
||||
}
|
||||
protected:
|
||||
virtual ~DemoPlugin(void) override
|
||||
{
|
||||
std::cout << "### DemoPlugin::~DemoPlugin" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
DemoPluginBase* construct(void) { return new DemoPlugin; }
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
#include <iostream>
|
||||
#include <AsyncPlugin.h>
|
||||
|
||||
// Base class for all plugins of type DemoPlugin
|
||||
class DemoPluginBase : public Async::Plugin
|
||||
{
|
||||
public:
|
||||
// Return the name of this plugin type
|
||||
static std::string typeName(void) { return "DemoPlugin"; }
|
||||
|
||||
// Pluging base class constructor
|
||||
DemoPluginBase(void)
|
||||
{
|
||||
std::cout << "### DemoPluginBase::DemoPluginBase" << std::endl;
|
||||
}
|
||||
|
||||
// Any plugin type specific functions
|
||||
virtual bool initialize(const std::string& str) = 0;
|
||||
|
||||
protected:
|
||||
// Plugin base class destructor
|
||||
virtual ~DemoPluginBase(void) override
|
||||
{
|
||||
std::cout << "### DemoPluginBase::~DemoPluginBase" << std::endl;
|
||||
}
|
||||
};
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
#ifndef CONFIG_H_INCLUDED
|
||||
#define CONFIG_H_INCLUDED
|
||||
|
||||
#define SYSCONF_INSTALL_DIR "@SYSCONF_INSTALL_DIR@"
|
||||
#define SVX_SYSCONF_INSTALL_DIR "@SVX_SYSCONF_INSTALL_DIR@"
|
||||
#define SHARE_INSTALL_PREFIX "@SHARE_INSTALL_PREFIX@"
|
||||
#define SVX_SHARE_INSTALL_DIR "@SVX_SHARE_INSTALL_DIR@"
|
||||
#define SVX_MODULE_INSTALL_DIR "@SVX_MODULE_INSTALL_DIR@"
|
||||
#define SVX_LOGIC_CORE_INSTALL_DIR "@SVX_LOGIC_CORE_INSTALL_DIR@"
|
||||
#define SYSCONF_INSTALL_DIR "@SYSCONF_INSTALL_DIR@"
|
||||
#define SVX_SYSCONF_INSTALL_DIR "@SVX_SYSCONF_INSTALL_DIR@"
|
||||
#define SHARE_INSTALL_PREFIX "@SHARE_INSTALL_PREFIX@"
|
||||
#define SVX_SHARE_INSTALL_DIR "@SVX_SHARE_INSTALL_DIR@"
|
||||
#define SVX_MODULE_INSTALL_DIR "@SVX_MODULE_INSTALL_DIR@"
|
||||
|
||||
#endif /* CONFIG_H_INCLUDED */
|
||||
|
|
|
|||
|
|
@ -1,56 +1,48 @@
|
|||
# Add an empty man target and make the doc target depend on it. We'll add
|
||||
# dependencies later
|
||||
add_custom_target(man)
|
||||
add_dependencies(doc man)
|
||||
# Set up which man pages to build and install
|
||||
set(MAN_PAGES svxlink.1 svxlink.conf.5 remotetrx.1 remotetrx.conf.5
|
||||
siglevdetcal.1 devcal.1 svxreflector.1 svxreflector.conf.5 qtel.1
|
||||
ModuleHelp.conf.5 ModuleParrot.conf.5 ModuleEchoLink.conf.5
|
||||
ModuleTclVoiceMail.conf.5 ModuleDtmfRepeater.conf.5
|
||||
ModulePropagationMonitor.conf.5 ModuleSelCallEnc.conf.5
|
||||
ModuleFrn.conf.5 ModuleTrx.conf.5
|
||||
)
|
||||
|
||||
# Search for the gzip and groff programs
|
||||
include(FindGROFF)
|
||||
# Search for the gzip and groff programs. Error out if not found.
|
||||
include(FindGZIP)
|
||||
if(NOT GROFF_TOOL OR NOT GZIP_TOOL)
|
||||
include(FindGROFF)
|
||||
|
||||
# Set up a target for compressing each manual page. Also add an install
|
||||
# target for it.
|
||||
if(GROFF_TOOL AND GZIP_TOOL)
|
||||
set(TARGETS)
|
||||
foreach(man ${MAN_PAGES})
|
||||
add_custom_command(OUTPUT ${man}.gz
|
||||
DEPENDS ${man}
|
||||
COMMAND ${GZIP_TOOL} -c ${CMAKE_CURRENT_SOURCE_DIR}/${man} > ${man}.gz
|
||||
COMMENT "Compressing manual page ${man}.gz..."
|
||||
)
|
||||
add_custom_command(OUTPUT ${man}.html
|
||||
DEPENDS ${man}
|
||||
COMMAND ${GROFF_TOOL} -mandoc -Thtml < ${CMAKE_CURRENT_SOURCE_DIR}/${man} > ${man}.html
|
||||
COMMENT "Createing HTML manual page ${man}.html..."
|
||||
)
|
||||
string(REGEX REPLACE ^.*\([1-9]\)\$ \\1 sec ${man})
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${man}.gz
|
||||
DESTINATION ${MAN_INSTALL_DIR}/man${sec}
|
||||
OPTIONAL
|
||||
)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${man}.html
|
||||
DESTINATION ${DOC_INSTALL_DIR}/man${sec}
|
||||
OPTIONAL
|
||||
)
|
||||
set(TARGETS ${TARGETS} ${man}.gz ${man}.html)
|
||||
endforeach(man)
|
||||
|
||||
# Add a custom target to trigger the build of the man pages
|
||||
add_custom_target(man DEPENDS ${TARGETS})
|
||||
add_dependencies(doc man)
|
||||
else(GROFF_TOOL AND GZIP_TOOL)
|
||||
message("-- The groff and gzip tools are optional dependencies.")
|
||||
message("-- They are used to build the UNIX manual pages. SvxLink will")
|
||||
message("-- build without them but usage documentation will be missing.")
|
||||
endif(NOT GROFF_TOOL OR NOT GZIP_TOOL)
|
||||
|
||||
# Call this function to add manual pages to be built
|
||||
function(add_manual_pages man_pages)
|
||||
if(GROFF_TOOL AND GZIP_TOOL)
|
||||
foreach(man ${ARGV})
|
||||
add_custom_command(
|
||||
OUTPUT ${man}.gz
|
||||
DEPENDS ${man}
|
||||
COMMAND ${GZIP_TOOL} -c ${CMAKE_CURRENT_SOURCE_DIR}/${man} > ${man}.gz
|
||||
COMMENT "Compressing manual page ${man}.gz..."
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT ${man}.html
|
||||
DEPENDS ${man}
|
||||
COMMAND ${GROFF_TOOL} -mandoc -Thtml < ${CMAKE_CURRENT_SOURCE_DIR}/${man} > ${man}.html
|
||||
COMMENT "Createing HTML manual page ${man}.html..."
|
||||
)
|
||||
|
||||
string(REGEX REPLACE ^.*\([1-9]\)\$ \\1 sec ${man})
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${man}.gz
|
||||
DESTINATION ${MAN_INSTALL_DIR}/man${sec}
|
||||
OPTIONAL
|
||||
)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${man}.html
|
||||
DESTINATION ${DOC_INSTALL_DIR}/man${sec}
|
||||
OPTIONAL
|
||||
)
|
||||
|
||||
add_custom_target(man_${man} DEPENDS ${man}.gz ${man}.html)
|
||||
add_dependencies(man man_${man})
|
||||
endforeach(man)
|
||||
endif(GROFF_TOOL AND GZIP_TOOL)
|
||||
endfunction(add_manual_pages)
|
||||
|
||||
# Set up which man pages to build and install
|
||||
add_manual_pages(
|
||||
svxlink.1 svxlink.conf.5 remotetrx.1 remotetrx.conf.5 siglevdetcal.1 devcal.1
|
||||
svxreflector.1 svxreflector.conf.5 qtel.1 ModuleHelp.conf.5
|
||||
ModuleParrot.conf.5 ModuleEchoLink.conf.5 ModuleTclVoiceMail.conf.5
|
||||
ModuleDtmfRepeater.conf.5 ModulePropagationMonitor.conf.5
|
||||
ModuleSelCallEnc.conf.5 ModuleFrn.conf.5 ModuleTrx.conf.5
|
||||
)
|
||||
|
||||
endif(GROFF_TOOL AND GZIP_TOOL)
|
||||
|
|
|
|||
|
|
@ -54,10 +54,10 @@ neighbouring channels. The default value is 5000Hz.
|
|||
.BI "-H|--headroom=" "headroom in dB"
|
||||
The headroom is the margin to add above the maximum deviation level. Adding a
|
||||
headroom will allow SvxLink to handle levels above the maximum deviation level
|
||||
without causing immediate distortion. The default is 6dB which mean that
|
||||
without causing immediate distorsion. The default is 6dB which mean that
|
||||
SvxLink can handle twice the specified maximum deviation. If both maxdev and
|
||||
headroom are left at their default this will mean that SvxLink can handle 10kHz
|
||||
deviation without distortion.
|
||||
deviation without distorsion.
|
||||
|
||||
Changing the headroom cause a lot of different effects so don't do that unless
|
||||
you are prepared to deal with the problems. For example, increasing the
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.TH SVXLINK.CONF 5 "AUGUST 2022" Linux "File Formats"
|
||||
.TH SVXLINK.CONF 5 "MARS 2022" Linux "File Formats"
|
||||
.
|
||||
.SH NAME
|
||||
.
|
||||
|
|
@ -60,14 +60,6 @@ also fails a hard-coded default will be used. What that default is depend on the
|
|||
architecture but typically on a x86_64 system it is /usr/lib64/svxlink.
|
||||
Leaving this variable unset should work in most cases.
|
||||
.TP
|
||||
.B LOGIC_CORE_PATH
|
||||
Specify where the SvxLink logic core plugins can be found. If not set, a
|
||||
hard-coded default will be used. What that default is depend on the
|
||||
architecture but typically on an x86_64 system it is /usr/lib64/svxlink.
|
||||
Leaving this variable unset should work in most cases.
|
||||
If this variable is set to empty, the standard search paths for library files
|
||||
will be used (see man 3 dlopen).
|
||||
.TP
|
||||
.B LOGICS
|
||||
Specify a comma separated list of logic cores that should be created. The logic core is
|
||||
the thing that ties the transceiver and the voice services (modules) together. It contains
|
||||
|
|
@ -155,11 +147,7 @@ configuration information for linking logics together (see Logic Linking).
|
|||
.
|
||||
A logic core is what define how SvxLink should behave on the RF channel. The
|
||||
SvxLink server can handle more than one logic core and so can be connected to
|
||||
more than one transceiver. When configured, a logic core is loaded at runtime
|
||||
as a plugin. See the LOGIC_CORE_PATH configuration variable for more
|
||||
information on how SvxLink find the logic core plugins.
|
||||
.P
|
||||
The configuration variables below are common to all
|
||||
more than one transceiver. The configuration variables below are common to all
|
||||
logic types. Configuration variables that are specific to a certain logic core
|
||||
type are described below in a section of its own.
|
||||
.TP
|
||||
|
|
@ -1668,6 +1656,15 @@ The destination is specified as ip-address:port.
|
|||
|
||||
Example: RAW_AUDIO_UDP_DEST=127.0.0.1:10000
|
||||
.TP
|
||||
.B AUDIO_FILTER
|
||||
Define an audio filter here to improve the frequency response caused by
|
||||
unfavorable hardware in the audio path from discriminator to the soundcard
|
||||
input. A lot of audio filters are available (Butterworth, Chebyshev, Lowpass,
|
||||
Highpass, ...). Look into the src/async/audio/fidlib.c for more information.
|
||||
|
||||
Example: AUDIO_FILTER=HsBq1/0.01/-18/3500
|
||||
|
||||
|
||||
.B OB_AFSK_ENABLE
|
||||
Set to 1 to enable reception of metadata like signal level measurements, DTMF
|
||||
digits and tone detections via out-of-band (OB) AFSK. The out-of-band AFSK is
|
||||
|
|
@ -2393,6 +2390,14 @@ It is possible to specify the same PTY for multiple functions (e.g. squelch,
|
|||
ptt etc) in both TX and RX configurations. This may be good if there is one
|
||||
script handling all functions.
|
||||
.
|
||||
.TP
|
||||
.B AUDIO_FILTER
|
||||
Define an audio filter here to improve the frequency response caused by
|
||||
unfavorable hardware in the audio path from discriminator to the soundcard
|
||||
input. A lot of audio filters are available (Butterworth, Chebyshev, Lowpass,
|
||||
Highpass, ...). Look into the src/async/audio/fidlib.c for more information.
|
||||
|
||||
Example: AUDIO_FILTER=HsBq1/0.01/-18/3500
|
||||
.SS Networked Transmitter Section
|
||||
.
|
||||
A networked transmitter section is used to specify the configuration for a
|
||||
|
|
|
|||
|
|
@ -1,12 +1,3 @@
|
|||
1.3.4 -- ?? ??? ????
|
||||
----------------------
|
||||
|
||||
* Replace potentially dangerous function call 'localtime' with 'localtime_r'.
|
||||
|
||||
* Smaller adaptions to new networking code in Async.
|
||||
|
||||
|
||||
|
||||
1.3.3 -- 30 Dec 2017
|
||||
----------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ bool DirectoryCon::isIdle(void) const
|
|||
Proxy *proxy = Proxy::instance();
|
||||
if (proxy == 0)
|
||||
{
|
||||
return is_ready && client->isIdle();
|
||||
return is_ready && !client->isConnected();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -205,26 +205,6 @@
|
|||
HOST -> HOSTS, PORT -> HOST_PORT. New configuration variables:
|
||||
DNS_DOMAIN, HOST_PRIO, HOST_PRIO_INC, HOST_WEIGHT.
|
||||
|
||||
* Logic cores (SimplexLogic, RepeaterLogic etc) are now implemented as plugins
|
||||
which mean they are dynamically loaded at runtime if needed. There are
|
||||
multiple benefits with that:
|
||||
- Easier to accept contributed logic cores into the main source tree since
|
||||
no core code needs changing.
|
||||
- As long as the plugin is not loaded it can cause no harm if it contain a
|
||||
bug.
|
||||
- Third-party logic cores can be packaged separately. Package maintainers
|
||||
that build contributed code are urged to put such artifacts in its own
|
||||
package with a name like svxlink-contrib-examplelogic.
|
||||
See man svxlink.conf and the LOGIC_CORE_PATH configuration variable for info
|
||||
on how SvxLink find the plugins.
|
||||
|
||||
* Bugfix in SvxReflector: After 65536 client connections the warning "Incoming
|
||||
UDP datagram from XX.XX.XX.XX:YYYYY has invalid client id ZZZZZ" was logged
|
||||
for all new client connections.
|
||||
|
||||
* New contribution from DL1HRC: SipLogic. The build is enabled by using the
|
||||
-DWITH_CONTRIB_SIP_LOGIC=ON CMake command line option.
|
||||
|
||||
|
||||
|
||||
1.7.0 -- 01 Sep 2019
|
||||
|
|
@ -1497,7 +1477,7 @@
|
|||
the input volume. It is enabled by setting the PEAK_METER variable in
|
||||
the receiver configuration section. Start SvxLink and open the squelch on
|
||||
the receiver so that only noise is available on the input. Adjust the input
|
||||
volume until you see messages printed about distortion. Then lower the
|
||||
volume until you see messages printed about distorsion. Then lower the
|
||||
volume until there are no more messages.
|
||||
|
||||
* Now using libsigc++ version 1.2 instead of the old and outdated 1.0.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2022 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
|
||||
|
|
@ -83,7 +83,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
****************************************************************************/
|
||||
|
||||
using namespace std;
|
||||
using namespace std::placeholders;
|
||||
using namespace Async;
|
||||
|
||||
|
||||
|
|
@ -485,7 +484,7 @@ static const unsigned audio_ch = 0;
|
|||
int main(int argc, const char *argv[])
|
||||
{
|
||||
cout << PROGRAM_NAME " v" DEVCAL_VERSION
|
||||
" Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX\n\n";
|
||||
" Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX\n\n";
|
||||
cout << PROGRAM_NAME " comes with ABSOLUTELY NO WARRANTY. "
|
||||
"This is free software, and you\n";
|
||||
cout << "are welcome to redistribute it in accordance with the "
|
||||
|
|
@ -502,7 +501,7 @@ int main(int argc, const char *argv[])
|
|||
|
||||
vector<float> mod_idxs(mod_fqs.size());
|
||||
transform(mod_fqs.begin(), mod_fqs.end(), mod_idxs.begin(),
|
||||
std::bind(divides<float>(), caldev, _1));
|
||||
bind1st(divides<float>(), caldev));
|
||||
float mod_level = 100.0 * caldev / (maxdev * pow(10.0, headroom_db / 20.0));
|
||||
cout << "--- Modulation frequencies [Hz] : ";
|
||||
copy(mod_fqs.begin(), mod_fqs.end(), ostream_iterator<float>(cout, " "));
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
\verbatim
|
||||
SvxReflector - An audio reflector for connecting SvxLink Servers
|
||||
Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2021 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
|
||||
|
|
@ -140,8 +140,14 @@ Reflector::~Reflector(void)
|
|||
m_udp_sock = 0;
|
||||
delete m_srv;
|
||||
m_srv = 0;
|
||||
m_client_con_map.clear();
|
||||
ReflectorClient::cleanup();
|
||||
|
||||
for (ReflectorClientMap::iterator it = m_client_map.begin();
|
||||
it != m_client_map.end(); ++it)
|
||||
{
|
||||
delete (*it).second;
|
||||
}
|
||||
m_client_map.clear();
|
||||
|
||||
delete TGHandler::instance();
|
||||
} /* Reflector::~Reflector */
|
||||
|
||||
|
|
@ -233,9 +239,10 @@ bool Reflector::initialize(Async::Config &cfg)
|
|||
void Reflector::nodeList(std::vector<std::string>& nodes) const
|
||||
{
|
||||
nodes.clear();
|
||||
for (const auto& item : m_client_con_map)
|
||||
for (ReflectorClientMap::const_iterator it = m_client_map.begin();
|
||||
it != m_client_map.end(); ++it)
|
||||
{
|
||||
const std::string& callsign = item.second->callsign();
|
||||
const std::string& callsign = (*it).second->callsign();
|
||||
if (!callsign.empty())
|
||||
{
|
||||
nodes.push_back(callsign);
|
||||
|
|
@ -247,13 +254,14 @@ void Reflector::nodeList(std::vector<std::string>& nodes) const
|
|||
void Reflector::broadcastMsg(const ReflectorMsg& msg,
|
||||
const ReflectorClient::Filter& filter)
|
||||
{
|
||||
for (const auto& item : m_client_con_map)
|
||||
ReflectorClientMap::const_iterator it = m_client_map.begin();
|
||||
for (; it != m_client_map.end(); ++it)
|
||||
{
|
||||
ReflectorClient *client = item.second;
|
||||
ReflectorClient *client = (*it).second;
|
||||
if (filter(client) &&
|
||||
(client->conState() == ReflectorClient::STATE_CONNECTED))
|
||||
{
|
||||
client->sendMsg(msg);
|
||||
(*it).second->sendMsg(msg);
|
||||
}
|
||||
}
|
||||
} /* Reflector::broadcastMsg */
|
||||
|
|
@ -270,9 +278,10 @@ bool Reflector::sendUdpDatagram(ReflectorClient *client, const void *buf,
|
|||
void Reflector::broadcastUdpMsg(const ReflectorUdpMsg& msg,
|
||||
const ReflectorClient::Filter& filter)
|
||||
{
|
||||
for (const auto& item : m_client_con_map)
|
||||
for (ReflectorClientMap::iterator it = m_client_map.begin();
|
||||
it != m_client_map.end(); ++it)
|
||||
{
|
||||
ReflectorClient *client = item.second;
|
||||
ReflectorClient *client = (*it).second;
|
||||
if (filter(client) &&
|
||||
(client->conState() == ReflectorClient::STATE_CONNECTED))
|
||||
{
|
||||
|
|
@ -326,7 +335,9 @@ void Reflector::clientConnected(Async::FramedTcpConnection *con)
|
|||
{
|
||||
cout << "Client " << con->remoteHost() << ":" << con->remotePort()
|
||||
<< " connected" << endl;
|
||||
m_client_con_map[con] = new ReflectorClient(this, con, m_cfg);
|
||||
ReflectorClient *rc = new ReflectorClient(this, con, m_cfg);
|
||||
m_client_map[rc->clientId()] = rc;
|
||||
m_client_con_map[con] = rc;
|
||||
} /* Reflector::clientConnected */
|
||||
|
||||
|
||||
|
|
@ -350,6 +361,7 @@ void Reflector::clientDisconnected(Async::FramedTcpConnection *con,
|
|||
cout << "disconnected: " << TcpConnection::disconnectReasonStr(reason)
|
||||
<< endl;
|
||||
|
||||
m_client_map.erase(client->clientId());
|
||||
m_client_con_map.erase(it);
|
||||
|
||||
if (!client->callsign().empty())
|
||||
|
|
@ -375,13 +387,14 @@ void Reflector::udpDatagramReceived(const IpAddress& addr, uint16_t port,
|
|||
return;
|
||||
}
|
||||
|
||||
ReflectorClient *client = ReflectorClient::lookup(header.clientId());
|
||||
if (client == nullptr)
|
||||
ReflectorClientMap::iterator it = m_client_map.find(header.clientId());
|
||||
if (it == m_client_map.end())
|
||||
{
|
||||
cerr << "*** WARNING: Incoming UDP datagram from " << addr << ":" << port
|
||||
<< " has invalid client id " << header.clientId() << endl;
|
||||
return;
|
||||
}
|
||||
ReflectorClient *client = (*it).second;
|
||||
if (addr != client->remoteHost())
|
||||
{
|
||||
cerr << "*** WARNING[" << client->callsign()
|
||||
|
|
@ -629,9 +642,10 @@ void Reflector::httpRequestReceived(Async::HttpServerConnection *con,
|
|||
|
||||
Json::Value status;
|
||||
status["nodes"] = Json::Value(Json::objectValue);
|
||||
for (const auto& item : m_client_con_map)
|
||||
ReflectorClientMap::const_iterator client_it;
|
||||
for (client_it = m_client_map.begin(); client_it != m_client_map.end(); ++client_it)
|
||||
{
|
||||
ReflectorClient* client = item.second;
|
||||
ReflectorClient* client = client_it->second;
|
||||
Json::Value node(client->nodeInfo());
|
||||
//node["addr"] = client->remoteHost().toString();
|
||||
node["protoVer"]["majorVer"] = client->protoVer().majorVer();
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
\verbatim
|
||||
SvxReflector - An audio reflector for connecting SvxLink Servers
|
||||
Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2017 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
|
||||
|
|
@ -182,12 +182,14 @@ class Reflector : public sigc::trackable
|
|||
void requestQsy(ReflectorClient *client, uint32_t tg);
|
||||
|
||||
private:
|
||||
typedef std::map<uint32_t, ReflectorClient*> ReflectorClientMap;
|
||||
typedef std::map<Async::FramedTcpConnection*,
|
||||
ReflectorClient*> ReflectorClientConMap;
|
||||
typedef Async::TcpServer<Async::FramedTcpConnection> FramedTcpServer;
|
||||
|
||||
FramedTcpServer* m_srv;
|
||||
Async::UdpSocket* m_udp_sock;
|
||||
ReflectorClientMap m_client_map;
|
||||
ReflectorClientConMap m_client_con_map;
|
||||
Async::Config* m_cfg;
|
||||
uint32_t m_tg_for_v1_clients;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
\verbatim
|
||||
SvxReflector - An audio reflector for connecting SvxLink Servers
|
||||
Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2021 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
|
||||
|
|
@ -111,9 +111,7 @@ using namespace Async;
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
ReflectorClient::ClientMap ReflectorClient::client_map;
|
||||
std::mt19937 ReflectorClient::id_gen(std::random_device{}());
|
||||
ReflectorClient::ClientIdRandomDist ReflectorClient::id_dist(0, CLIENT_ID_MAX);
|
||||
uint32_t ReflectorClient::next_client_id = 0;
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -122,28 +120,6 @@ ReflectorClient::ClientIdRandomDist ReflectorClient::id_dist(0, CLIENT_ID_MAX);
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
ReflectorClient* ReflectorClient::lookup(ClientId id)
|
||||
{
|
||||
auto it = client_map.find(id);
|
||||
if (it == client_map.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return it->second;
|
||||
} /* ReflectorClient::lookup */
|
||||
|
||||
|
||||
void ReflectorClient::cleanup(void)
|
||||
{
|
||||
auto client_map_copy = client_map;
|
||||
for (const auto& item : client_map_copy)
|
||||
{
|
||||
delete item.second;
|
||||
}
|
||||
assert(client_map.size() == 0);
|
||||
} /* ReflectorClient::cleanup */
|
||||
|
||||
|
||||
bool ReflectorClient::TgFilter::operator()(ReflectorClient* client) const
|
||||
{
|
||||
//cout << "m_tg=" << m_tg << " client_tg="
|
||||
|
|
@ -156,7 +132,7 @@ ReflectorClient::ReflectorClient(Reflector *ref, Async::FramedTcpConnection *con
|
|||
Async::Config *cfg)
|
||||
: m_con(con), m_con_state(STATE_EXPECT_PROTO_VER),
|
||||
m_disc_timer(10000, Timer::TYPE_ONESHOT, false),
|
||||
m_client_id(newClient(this)), m_remote_udp_port(0), m_cfg(cfg),
|
||||
m_client_id(next_client_id++), m_remote_udp_port(0), m_cfg(cfg),
|
||||
m_next_udp_tx_seq(0), m_next_udp_rx_seq(0),
|
||||
m_heartbeat_timer(1000, Timer::TYPE_PERIODIC),
|
||||
m_heartbeat_tx_cnt(HEARTBEAT_TX_CNT_RESET),
|
||||
|
|
@ -207,9 +183,6 @@ ReflectorClient::ReflectorClient(Reflector *ref, Async::FramedTcpConnection *con
|
|||
|
||||
ReflectorClient::~ReflectorClient(void)
|
||||
{
|
||||
auto client_it = client_map.find(m_client_id);
|
||||
assert(client_it != client_map.end());
|
||||
client_map.erase(client_it);
|
||||
TGHandler::instance()->removeClient(this);
|
||||
} /* ReflectorClient::~ReflectorClient */
|
||||
|
||||
|
|
@ -287,19 +260,6 @@ void ReflectorClient::setBlock(unsigned blocktime)
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
ReflectorClient::ClientId ReflectorClient::newClient(ReflectorClient* client)
|
||||
{
|
||||
assert(!(client_map.size() > CLIENT_ID_MAX));
|
||||
ClientId id = id_dist(id_gen);
|
||||
while (client_map.count(id) > 0)
|
||||
{
|
||||
id = (id < CLIENT_ID_MAX) ? id+1 : 0;
|
||||
}
|
||||
client_map[id] = client;
|
||||
return id;
|
||||
} /* ReflectorClient::newClient */
|
||||
|
||||
|
||||
void ReflectorClient::onFrameReceived(FramedTcpConnection *con,
|
||||
std::vector<uint8_t>& data)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
\verbatim
|
||||
SvxReflector - An audio reflector for connecting SvxLink Servers
|
||||
Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2017 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
|
||||
|
|
@ -36,7 +36,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
||||
#include <string>
|
||||
#include <json/json.h>
|
||||
#include <random>
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -111,8 +110,6 @@ the client connection.
|
|||
class ReflectorClient
|
||||
{
|
||||
public:
|
||||
using ClientId = ReflectorUdpMsg::ClientId;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STATE_DISCONNECTED, STATE_EXPECT_PROTO_VER, STATE_EXPECT_AUTH_RESPONSE,
|
||||
|
|
@ -238,18 +235,6 @@ class ReflectorClient
|
|||
return OrFilter<F1, F2>(f1, f2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the client object associated with the given id
|
||||
* @param id The id of the client object to find
|
||||
* @return Return the client object associated with the given id
|
||||
*/
|
||||
static ReflectorClient* lookup(ClientId id);
|
||||
|
||||
/**
|
||||
* @brief Remove all client objects
|
||||
*/
|
||||
static void cleanup(void);
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param ref The associated Reflector object
|
||||
|
|
@ -272,7 +257,7 @@ class ReflectorClient
|
|||
* It is for example used to associate incoming audio with the correct
|
||||
* client.
|
||||
*/
|
||||
ClientId clientId(void) const { return m_client_id; }
|
||||
uint32_t clientId(void) const { return m_client_id; }
|
||||
|
||||
/**
|
||||
* @brief Return the remote IP address
|
||||
|
|
@ -427,29 +412,21 @@ class ReflectorClient
|
|||
const Json::Value& nodeInfo(void) const { return m_node_info; }
|
||||
|
||||
private:
|
||||
using ClientIdRandomDist = std::uniform_int_distribution<ClientId>;
|
||||
using ClientMap = std::map<ClientId, ReflectorClient*>;
|
||||
|
||||
static const uint16_t MIN_MAJOR_VER = 0;
|
||||
static const uint16_t MIN_MINOR_VER = 6;
|
||||
static uint32_t next_client_id;
|
||||
|
||||
static const unsigned HEARTBEAT_TX_CNT_RESET = 10;
|
||||
static const unsigned HEARTBEAT_RX_CNT_RESET = 15;
|
||||
static const unsigned UDP_HEARTBEAT_TX_CNT_RESET = 15;
|
||||
static const unsigned UDP_HEARTBEAT_RX_CNT_RESET = 120;
|
||||
|
||||
static const ClientId CLIENT_ID_MAX = std::numeric_limits<ClientId>::max();
|
||||
|
||||
static ClientMap client_map;
|
||||
static std::mt19937 id_gen;
|
||||
static ClientIdRandomDist id_dist;
|
||||
|
||||
Async::FramedTcpConnection* m_con;
|
||||
unsigned char m_auth_challenge[MsgAuthChallenge::CHALLENGE_LEN];
|
||||
ConState m_con_state;
|
||||
Async::Timer m_disc_timer;
|
||||
std::string m_callsign;
|
||||
ClientId m_client_id;
|
||||
uint32_t m_client_id;
|
||||
uint16_t m_remote_udp_port;
|
||||
Async::Config* m_cfg;
|
||||
uint16_t m_next_udp_tx_seq;
|
||||
|
|
@ -470,8 +447,6 @@ class ReflectorClient
|
|||
TxMap m_tx_map;
|
||||
Json::Value m_node_info;
|
||||
|
||||
static ClientId newClient(ReflectorClient* client);
|
||||
|
||||
ReflectorClient(const ReflectorClient&);
|
||||
ReflectorClient& operator=(const ReflectorClient&);
|
||||
void onFrameReceived(Async::FramedTcpConnection *con,
|
||||
|
|
|
|||
|
|
@ -162,14 +162,12 @@ the argument type for functions that take a UDP message as argument.
|
|||
class ReflectorUdpMsg : public Async::Msg
|
||||
{
|
||||
public:
|
||||
using ClientId = uint16_t;
|
||||
|
||||
/**
|
||||
* @brief Constuctor
|
||||
* @param type The message type
|
||||
* @param client_id The client ID
|
||||
*/
|
||||
ReflectorUdpMsg(uint16_t type=0, ClientId client_id=0, uint16_t seq=0)
|
||||
ReflectorUdpMsg(uint16_t type=0, uint16_t client_id=0, uint16_t seq=0)
|
||||
: m_type(type), m_client_id(client_id), m_seq(seq) {}
|
||||
|
||||
/**
|
||||
|
|
@ -187,7 +185,7 @@ class ReflectorUdpMsg : public Async::Msg
|
|||
* @brief Get the clientId
|
||||
* @return Returns the client ID
|
||||
*/
|
||||
ClientId clientId(void) const { return m_client_id; }
|
||||
uint16_t clientId(void) const { return m_client_id; }
|
||||
|
||||
/**
|
||||
* @brief Get the sequence number
|
||||
|
|
@ -198,9 +196,9 @@ class ReflectorUdpMsg : public Async::Msg
|
|||
ASYNC_MSG_MEMBERS(m_type, m_client_id, m_seq)
|
||||
|
||||
private:
|
||||
uint16_t m_type;
|
||||
ClientId m_client_id;
|
||||
uint16_t m_seq;
|
||||
uint16_t m_type;
|
||||
uint16_t m_client_id;
|
||||
uint16_t m_seq;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -477,20 +475,17 @@ connection properties.
|
|||
class MsgServerInfo : public ReflectorMsgBase<100>
|
||||
{
|
||||
public:
|
||||
using ClientId = ReflectorUdpMsg::ClientId;
|
||||
|
||||
MsgServerInfo(ClientId client_id=0,
|
||||
MsgServerInfo(uint32_t client_id=0,
|
||||
std::vector<std::string> codecs=std::vector<std::string>())
|
||||
: m_client_id(client_id), m_codecs(codecs) {}
|
||||
ClientId clientId(void) const { return m_client_id; }
|
||||
uint32_t clientId(void) const { return m_client_id; }
|
||||
std::vector<std::string>& nodes(void) { return m_nodes; }
|
||||
std::vector<std::string>& codecs(void) { return m_codecs; }
|
||||
|
||||
ASYNC_MSG_MEMBERS(m_reserved, m_client_id, m_nodes, m_codecs)
|
||||
ASYNC_MSG_MEMBERS(m_client_id, m_nodes, m_codecs)
|
||||
|
||||
private:
|
||||
uint16_t m_reserved = 0;
|
||||
ClientId m_client_id;
|
||||
uint32_t m_client_id;
|
||||
std::vector<std::string> m_nodes;
|
||||
std::vector<std::string> m_codecs;
|
||||
}; /* MsgServerInfo */
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ nodes together.
|
|||
|
||||
\verbatim
|
||||
SvxReflector - An audio reflector for connecting SvxLink Servers
|
||||
Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2022 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
|
||||
|
|
@ -412,7 +412,7 @@ int main(int argc, const char *argv[])
|
|||
cfg.getValue("GLOBAL", "TIMESTAMP_FORMAT", tstamp_format);
|
||||
|
||||
cout << PROGRAM_NAME " v" SVXREFLECTOR_VERSION
|
||||
" Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX\n\n";
|
||||
" Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX\n\n";
|
||||
cout << PROGRAM_NAME " comes with ABSOLUTELY NO WARRANTY. "
|
||||
"This is free software, and you are\n";
|
||||
cout << "welcome to redistribute it in accordance with the "
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ server core (e.g. via a TCP/IP network).
|
|||
|
||||
\verbatim
|
||||
RemoteTrx - A remote receiver for the SvxLink server
|
||||
Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2022 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
|
||||
|
|
@ -474,7 +474,7 @@ int main(int argc, char **argv)
|
|||
cfg.getValue("GLOBAL", "TIMESTAMP_FORMAT", tstamp_format);
|
||||
|
||||
cout << PROGRAM_NAME " v" REMOTE_TRX_VERSION
|
||||
" Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX\n\n";
|
||||
" Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX\n\n";
|
||||
cout << PROGRAM_NAME " comes with ABSOLUTELY NO WARRANTY. "
|
||||
"This is free software, and you are\n";
|
||||
cout << "welcome to redistribute it in accordance with the "
|
||||
|
|
|
|||
|
|
@ -1,46 +1,7 @@
|
|||
/**
|
||||
@file siglevdetcal.cpp
|
||||
@brief Signal level detector calibration utility
|
||||
@author Tobias Blomberg / SM0SVX
|
||||
@date 2008-03-30
|
||||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2003-2023 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
\endverbatim
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* System Includes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Project Includes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <AsyncCppApplication.h>
|
||||
#include <AsyncConfig.h>
|
||||
#include <AsyncFdWatch.h>
|
||||
|
|
@ -49,33 +10,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
||||
#include <LocalRxBase.h>
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Local Includes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "version/SIGLEV_DET_CAL.h"
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Namespaces to use
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
using namespace std;
|
||||
using namespace sigc;
|
||||
using namespace Async;
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Defines & typedefs
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#define PROGRAM_NAME "SigLevDetCal"
|
||||
|
||||
struct CtcssMeasurement
|
||||
|
|
@ -84,13 +24,6 @@ struct CtcssMeasurement
|
|||
size_t count = 0;
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Local Global Variables
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static const int INTERVAL = 100;
|
||||
static const int ITERATIONS = 150;
|
||||
|
||||
|
|
@ -105,12 +38,6 @@ static std::map<float, float> ctcss_open_snr;
|
|||
static std::map<float, float> ctcss_close_snr;
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Local Functions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if 0
|
||||
void squelchOpen(bool is_open)
|
||||
{
|
||||
|
|
@ -303,18 +230,12 @@ void ctcss_snr_updated(float snr, float fq)
|
|||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* MAIN
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CppApplication app;
|
||||
|
||||
cout << PROGRAM_NAME " v" SIGLEV_DET_CAL_VERSION
|
||||
" Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX\n\n";
|
||||
" Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX\n\n";
|
||||
cout << PROGRAM_NAME " comes with ABSOLUTELY NO WARRANTY. "
|
||||
"This is free software, and you\n";
|
||||
cout << "are welcome to redistribute it in accordance with the "
|
||||
|
|
|
|||
|
|
@ -1,20 +1,3 @@
|
|||
# C++ source files needed to build SvxLink
|
||||
set(SVXLINK_SRCS
|
||||
svxlink.cpp MsgHandler.cpp Module.cpp Logic.cpp EventHandler.cpp
|
||||
LinkManager.cpp CmdParser.cpp QsoRecorder.cpp DtmfDigitHandler.cpp
|
||||
)
|
||||
|
||||
# TCL event handler files to install in the events.d subdirectory
|
||||
set(SVXLINK_TCL_EVENT_FILES
|
||||
RepeaterLogic.tcl SimplexLogic.tcl ReflectorLogic.tcl Module.tcl Logic.tcl
|
||||
CW.tcl SelCall.tcl locale.tcl
|
||||
)
|
||||
|
||||
# Logic core plugins to build
|
||||
set(SVXLINK_LOGIC_CORES
|
||||
Dummy Simplex Repeater Reflector
|
||||
)
|
||||
|
||||
# Find the popt library
|
||||
find_package(Popt REQUIRED)
|
||||
set(LIBS ${LIBS} ${POPT_LIBRARIES})
|
||||
|
|
@ -78,20 +61,17 @@ set(LIBS ${LIBS} ${JSONCPP_LIBRARIES})
|
|||
set(LIBS trx locationinfo asynccpp asyncaudio asynccore svxmisc ${LIBS})
|
||||
|
||||
# Build the executable
|
||||
add_executable(svxlink ${SVXLINK_SRCS} ${VERSION_DEPENDS})
|
||||
add_executable(svxlink
|
||||
MsgHandler.cpp Module.cpp Logic.cpp SimplexLogic.cpp RepeaterLogic.cpp
|
||||
EventHandler.cpp LinkManager.cpp CmdParser.cpp QsoRecorder.cpp svxlink.cpp
|
||||
DtmfDigitHandler.cpp ReflectorLogic.cpp
|
||||
${VERSION_DEPENDS}
|
||||
)
|
||||
target_link_libraries(svxlink ${LIBS})
|
||||
set_target_properties(svxlink PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY ${RUNTIME_OUTPUT_DIRECTORY}
|
||||
)
|
||||
|
||||
# Build logic plugins
|
||||
foreach(logic_name ${SVXLINK_LOGIC_CORES})
|
||||
add_library(${logic_name}Logic MODULE ${logic_name}Logic.cpp)
|
||||
set_target_properties(${logic_name}Logic PROPERTIES PREFIX "")
|
||||
set_property(TARGET ${logic_name}Logic PROPERTY NO_SONAME 1)
|
||||
#target_link_libraries(${logic_name}Logic ${LIBS})
|
||||
endforeach()
|
||||
|
||||
# Generate config file with correct paths
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/svxlink.conf.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/svxlink.conf
|
||||
|
|
@ -120,7 +100,8 @@ install_if_not_exists(${CMAKE_CURRENT_BINARY_DIR}/gpio.conf
|
|||
)
|
||||
install_if_not_exists(node_info.json ${SVX_SYSCONF_INSTALL_DIR})
|
||||
install(FILES events.tcl DESTINATION ${SVX_SHARE_INSTALL_DIR})
|
||||
install(FILES ${SVXLINK_TCL_EVENT_FILES}
|
||||
install(FILES RepeaterLogic.tcl SimplexLogic.tcl ReflectorLogic.tcl Module.tcl
|
||||
Logic.tcl CW.tcl SelCall.tcl locale.tcl
|
||||
DESTINATION ${SVX_SHARE_INSTALL_DIR}/events.d
|
||||
)
|
||||
install(PROGRAMS ${RUNTIME_OUTPUT_DIRECTORY}/svxlink_gpio_up
|
||||
|
|
@ -129,9 +110,3 @@ install(PROGRAMS ${RUNTIME_OUTPUT_DIRECTORY}/svxlink_gpio_up
|
|||
install(PROGRAMS ${RUNTIME_OUTPUT_DIRECTORY}/svxlink_gpio_down
|
||||
DESTINATION ${SBIN_INSTALL_DIR}
|
||||
)
|
||||
foreach(logic_name ${SVXLINK_LOGIC_CORES})
|
||||
install(TARGETS ${logic_name}Logic DESTINATION ${SVX_LOGIC_CORE_INSTALL_DIR})
|
||||
endforeach()
|
||||
|
||||
# Include contributed parts
|
||||
add_subdirectory(contrib)
|
||||
|
|
|
|||
|
|
@ -1,152 +0,0 @@
|
|||
/**
|
||||
@file DummyLogic.h
|
||||
@brief A simple dummy logic core that does not do anything
|
||||
@author Tobias Blomberg / SM0SVX
|
||||
@date 2017-02-10
|
||||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2003-2022 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
\endverbatim
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* System Includes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Project Includes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <AsyncAudioDebugger.h>
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Local Includes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "DummyLogic.h"
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Namespaces to use
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
//using namespace MyNamespace;
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Defines & typedefs
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Static class variables
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Exported Global functions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
extern "C" {
|
||||
LogicBase* construct(void) { return new DummyLogic; }
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Local class definitions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Local functions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
}; /* End of anonymous namespace */
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Public member functions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
DummyLogic::DummyLogic(void)
|
||||
{
|
||||
m_logic_con_in = new Async::AudioDebugger;
|
||||
m_logic_con_in->setName("DummyLogicIn");
|
||||
m_logic_con_out = new Async::AudioDebugger;
|
||||
m_logic_con_out->setName("DummyLogicOut");
|
||||
} /* DummyLogic::DummyLogic */
|
||||
|
||||
|
||||
bool DummyLogic::initialize(Async::Config& cfgobj, const std::string& logic_name)
|
||||
{
|
||||
return LogicBase::initialize(cfgobj, logic_name);
|
||||
} /* DummyLogic::initialize */
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Protected member functions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
DummyLogic::~DummyLogic(void)
|
||||
{
|
||||
delete m_logic_con_in;
|
||||
delete m_logic_con_out;
|
||||
} /* DummyLogic::~DummyLogic */
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Private member functions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This file has not been truncated
|
||||
*/
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
/**
|
||||
@file DummyLogic.h
|
||||
@file DummyLogic.h
|
||||
@brief A simple dummy logic core that does not do anything
|
||||
@author Tobias Blomberg / SM0SVX
|
||||
@date 2017-02-10
|
||||
@date 2017-02-10
|
||||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2017 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
|
||||
|
|
@ -42,6 +42,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <AsyncAudioDebugger.h>
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -102,59 +103,58 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
****************************************************************************/
|
||||
|
||||
/**
|
||||
@brief A simple dummy logic core that does not do anything
|
||||
@brief A simple dummy logic core that does not do anything
|
||||
@author Tobias Blomberg / SM0SVX
|
||||
@date 2017-02-10
|
||||
|
||||
The dummy logic core is just an example of the simplest possible logic core. It
|
||||
does not do anything but printing debug info when receiving audio from another
|
||||
logic core. It's primary purpose is to serve as a start for writing new logic
|
||||
cores.
|
||||
logic core.
|
||||
*/
|
||||
class DummyLogic : public LogicBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @brief Constructor
|
||||
* @param cfg A previously initialized configuration object
|
||||
* @param name The name of the logic core
|
||||
*/
|
||||
DummyLogic(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize this logic
|
||||
* @param cfgobj A previously initialized config object
|
||||
* @param logic_name The name of the logic core
|
||||
* @return Returns \em true on success or \em false on failure
|
||||
*/
|
||||
virtual bool initialize(Async::Config& cfgobj,
|
||||
const std::string& logic_name) override;
|
||||
|
||||
/**
|
||||
* @brief Get the audio pipe sink used for writing audio into this logic
|
||||
* @return Returns an audio pipe sink object
|
||||
*/
|
||||
virtual Async::AudioSink *logicConIn(void) override
|
||||
DummyLogic(Async::Config& cfg, const std::string& name)
|
||||
: LogicBase(cfg, name)
|
||||
{
|
||||
return m_logic_con_in;
|
||||
m_logic_con_in = new Async::AudioDebugger;
|
||||
m_logic_con_out = new Async::AudioDebugger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the audio pipe source used for reading audio from this logic
|
||||
* @return Returns an audio pipe source object
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual Async::AudioSource *logicConOut(void) override
|
||||
~DummyLogic(void)
|
||||
{
|
||||
return m_logic_con_out;
|
||||
delete m_logic_con_in;
|
||||
delete m_logic_con_out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the audio pipe sink used for writing audio into this logic
|
||||
* @return Returns an audio pipe sink object
|
||||
*/
|
||||
virtual Async::AudioSink *logicConIn(void) { return m_logic_con_in; }
|
||||
|
||||
/**
|
||||
* @brief Get the audio pipe source used for reading audio from this logic
|
||||
* @return Returns an audio pipe source object
|
||||
*/
|
||||
virtual Async::AudioSource *logicConOut(void) { return m_logic_con_out; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~DummyLogic(void) override;
|
||||
|
||||
private:
|
||||
Async::AudioDebugger *m_logic_con_in = nullptr;
|
||||
Async::AudioDebugger *m_logic_con_out = nullptr;
|
||||
Async::AudioDebugger *m_logic_con_in;
|
||||
Async::AudioDebugger *m_logic_con_out;
|
||||
|
||||
DummyLogic(const DummyLogic&);
|
||||
DummyLogic& operator=(const DummyLogic&);
|
||||
|
||||
}; /* class DummyLogic */
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2019 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
|
||||
|
|
@ -190,16 +190,6 @@ bool EventHandler::initialize(void)
|
|||
} /* EventHandler::initialize */
|
||||
|
||||
|
||||
void EventHandler::addCommand(const std::string& name, CommandHandler f)
|
||||
{
|
||||
Tcl_CreateCommand(interp, name.c_str(), genericCommandHandler,
|
||||
new CommandHandler(f),
|
||||
[](ClientData cdata) {
|
||||
delete static_cast<CommandHandler*>(cdata);
|
||||
});
|
||||
} /* EventHandler::addCommand */
|
||||
|
||||
|
||||
void EventHandler::setVariable(const string& name, const string& value)
|
||||
{
|
||||
if (interp == 0)
|
||||
|
|
@ -474,23 +464,6 @@ int EventHandler::setConfigValueHandler(ClientData cdata, Tcl_Interp *irp,
|
|||
} /* EventHandler::setConfigValueHandler */
|
||||
|
||||
|
||||
int EventHandler::genericCommandHandler(ClientData cdata, Tcl_Interp *irp,
|
||||
int argc, const char *argv[])
|
||||
{
|
||||
const auto& func = *static_cast<CommandHandler*>(cdata);
|
||||
std::string msg = func(argc, argv);
|
||||
if (!msg.empty())
|
||||
{
|
||||
auto msg_alloc_len = msg.size()+1;
|
||||
char* msg_copy = Tcl_Alloc(msg_alloc_len);
|
||||
memcpy(msg_copy, msg.c_str(), msg_alloc_len);
|
||||
Tcl_SetResult(irp, msg_copy, TCL_DYNAMIC);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
} /* EventHandler::genericCommandHandler */
|
||||
|
||||
|
||||
/*
|
||||
* This file has not been truncated
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2019 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
|
||||
|
|
@ -113,8 +113,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
class EventHandler : public sigc::trackable
|
||||
{
|
||||
public:
|
||||
using CommandHandler = std::function<std::string(int argc, const char *argv[])>;
|
||||
|
||||
/**
|
||||
* @brief Constuctor
|
||||
*/
|
||||
|
|
@ -130,34 +128,7 @@ class EventHandler : public sigc::trackable
|
|||
* @return Returns \em true on success or else \em false
|
||||
*/
|
||||
bool initialize(void);
|
||||
|
||||
/**
|
||||
* @brief Add a custom command to the event handler
|
||||
* @param name The name of the command
|
||||
* @param f The handler function
|
||||
* @return Return empty string on success or else an error string
|
||||
*
|
||||
* This is an example of how to add a TCL event handler command that take
|
||||
* one argument. The example use a lambda function but other methods
|
||||
* compatible with std::function may be used as well.
|
||||
*
|
||||
* event_handler->addCommand("demoCommand",
|
||||
* [&](int argc, const char* argv[])
|
||||
* {
|
||||
* if (argc != 2)
|
||||
* {
|
||||
* return std::string("Usage: demoCommand: <arg1>");
|
||||
* }
|
||||
* std::cout << "### demoCommand(" << argv[1] << ")" << std::endl;
|
||||
* return std::string();
|
||||
* });
|
||||
*
|
||||
* It would be executed in TCL like this:
|
||||
*
|
||||
* demoCommand "hello"
|
||||
*/
|
||||
void addCommand(const std::string& name, CommandHandler f);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set a TCL variable
|
||||
* @param name The name of the variable to set
|
||||
|
|
@ -290,8 +261,7 @@ class EventHandler : public sigc::trackable
|
|||
int argc, const char *argv[]);
|
||||
static int setConfigValueHandler(ClientData cdata, Tcl_Interp *irp,
|
||||
int argc, const char *argv[]);
|
||||
static int genericCommandHandler(ClientData cdata, Tcl_Interp *irp,
|
||||
int argc, const char *argv[]);
|
||||
|
||||
}; /* class EventHandler */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
#include "LogicCmds.h"
|
||||
#include "Logic.h"
|
||||
#include "QsoRecorder.h"
|
||||
//#include "LinkManager.h"
|
||||
#include "LinkManager.h"
|
||||
#include "DtmfDigitHandler.h"
|
||||
|
||||
|
||||
|
|
@ -152,8 +152,9 @@ using namespace SvxLink;
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
Logic::Logic(void)
|
||||
: m_rx(0), m_tx(0),
|
||||
Logic::Logic(Config &cfg, const string& name)
|
||||
: LogicBase(cfg, name),
|
||||
m_rx(0), m_tx(0),
|
||||
msg_handler(0), active_module(0),
|
||||
exec_cmd_on_sql_close_timer(-1), rgr_sound_timer(-1),
|
||||
report_ctcss(0.0f), event_handler(0),
|
||||
|
|
@ -178,9 +179,18 @@ Logic::Logic(void)
|
|||
} /* Logic::Logic */
|
||||
|
||||
|
||||
bool Logic::initialize(Async::Config& cfgobj, const std::string& logic_name)
|
||||
Logic::~Logic(void)
|
||||
{
|
||||
if (!LogicBase::initialize(cfgobj, logic_name))
|
||||
cleanup();
|
||||
delete logic_con_out;
|
||||
delete logic_con_in;
|
||||
delete dtmf_digit_handler;
|
||||
} /* Logic::~Logic */
|
||||
|
||||
|
||||
bool Logic::initialize(void)
|
||||
{
|
||||
if (!LogicBase::initialize())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -394,7 +404,7 @@ bool Logic::initialize(Async::Config& cfgobj, const std::string& logic_name)
|
|||
AudioSource *prev_rx_src = 0;
|
||||
|
||||
// Create the RX object
|
||||
cout << name() << ": Loading RX \"" << rx_name << "\"" << endl;
|
||||
cout << "Loading RX: " << rx_name << endl;
|
||||
m_rx = RxFactory::createNamedRx(cfg(), rx_name);
|
||||
if ((m_rx == 0) || !rx().initialize())
|
||||
{
|
||||
|
|
@ -555,7 +565,7 @@ bool Logic::initialize(Async::Config& cfgobj, const std::string& logic_name)
|
|||
prev_tx_src = tx_audio_mixer;
|
||||
|
||||
// Create the TX object
|
||||
std::cout << name() << ": Loading TX \"" << tx_name << "\"" << endl;
|
||||
cout << "Loading TX: " << tx_name << endl;
|
||||
m_tx = TxFactory::createNamedTx(cfg(), tx_name);
|
||||
if ((m_tx == 0) || !tx().initialize())
|
||||
{
|
||||
|
|
@ -1006,15 +1016,6 @@ void Logic::remoteReceivedTgUpdated(LogicBase *src_logic, uint32_t tg)
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
Logic::~Logic(void)
|
||||
{
|
||||
cleanup();
|
||||
delete logic_con_out;
|
||||
delete logic_con_in;
|
||||
delete dtmf_digit_handler;
|
||||
} /* Logic::~Logic */
|
||||
|
||||
|
||||
void Logic::squelchOpen(bool is_open)
|
||||
{
|
||||
if (active_module != 0)
|
||||
|
|
@ -1273,8 +1274,8 @@ void Logic::loadModules(void)
|
|||
|
||||
void Logic::loadModule(const string& module_cfg_name)
|
||||
{
|
||||
std::cout << name() << ": Loading module \"" << module_cfg_name << "\""
|
||||
<< std::endl;
|
||||
cout << "Loading module \"" << module_cfg_name << "\" into logic \""
|
||||
<< name() << "\"\n";
|
||||
|
||||
string module_path;
|
||||
cfg().getValue("GLOBAL", "MODULE_PATH", module_path);
|
||||
|
|
@ -1690,10 +1691,10 @@ void Logic::cleanup(void)
|
|||
rgr_sound_timer.setEnable(false);
|
||||
every_minute_timer.stop();
|
||||
|
||||
//if (LinkManager::hasInstance())
|
||||
//{
|
||||
// LinkManager::instance()->deleteLogic(this);
|
||||
//}
|
||||
if (LinkManager::hasInstance())
|
||||
{
|
||||
LinkManager::instance()->deleteLogic(this);
|
||||
}
|
||||
|
||||
delete event_handler; event_handler = 0;
|
||||
delete m_tx; m_tx = 0;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ specific logic core classes (e.g. SimplexLogic and RepeaterLogic).
|
|||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2004-2022 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2004-2018 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
|
||||
|
|
@ -141,31 +141,31 @@ class DtmfDigitHandler;
|
|||
****************************************************************************/
|
||||
|
||||
/**
|
||||
@brief This class implements the functions in common for RF logic cores
|
||||
@brief This class implements the core logic of SvxLink
|
||||
@author Tobias Blomberg
|
||||
@date 2004-03-23
|
||||
|
||||
This class is used as the base class for all logic cores that implement "RF"
|
||||
behaviour. That is, logic cores which are primarily intended to operate a radio
|
||||
channel, e.g. RepeaterLogic and SimplexLogic.
|
||||
*/
|
||||
class Logic : public LogicBase
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @brief Default constuctor
|
||||
*/
|
||||
Logic(void);
|
||||
Logic(Async::Config& cfg, const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief Initialize the logic core
|
||||
* @param cfgobj A previously initialized configuration object
|
||||
* @param plugin_name The name of the logic core
|
||||
* @return Returns \em true on success or \em false on failure
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual bool initialize(Async::Config& cfgobj,
|
||||
const std::string& plugin_name) override;
|
||||
virtual ~Logic(void);
|
||||
|
||||
/**
|
||||
* @brief A_brief_member_function_description
|
||||
* @param param1 Description_of_param1
|
||||
* @return Return_value_of_this_member_function
|
||||
*/
|
||||
|
||||
virtual bool initialize(void);
|
||||
|
||||
virtual void processEvent(const std::string& event, const Module *module=0);
|
||||
void setEventVariable(const std::string& name, const std::string& value);
|
||||
|
|
@ -212,11 +212,6 @@ class Logic : public LogicBase
|
|||
CmdParser *cmdParser(void) { return &cmd_parser; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~Logic(void) override;
|
||||
|
||||
virtual void squelchOpen(bool is_open);
|
||||
virtual void allMsgsWritten(void);
|
||||
virtual void dtmfDigitDetected(char digit, int duration);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2004-2022 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2004-2019 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
|
||||
|
|
@ -46,7 +46,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <AsyncPlugin.h>
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -127,29 +126,29 @@ LogicBase is a pure virtual class so it cannot be instatiated on its own.
|
|||
|
||||
@example DummyLogic.h
|
||||
*/
|
||||
class LogicBase : public Async::Plugin, public sigc::trackable
|
||||
class LogicBase : public sigc::trackable
|
||||
{
|
||||
public:
|
||||
// Return the name of this plugin type
|
||||
static std::string typeName(void) { return "Logic"; }
|
||||
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @brief Constuctor
|
||||
* @param cfg A previously initialized configuration object
|
||||
* @param name The name of the logic core
|
||||
*/
|
||||
LogicBase(void) {}
|
||||
LogicBase(Async::Config& cfg, const std::string& name)
|
||||
: m_cfg(cfg), m_name(name), m_is_idle(true), m_received_tg(0) {}
|
||||
|
||||
/**
|
||||
* @brief Initialize the logic core
|
||||
* @param cfgobj A previously initialized configuration object
|
||||
* @param plugin_name The name of the logic core
|
||||
* @return Returns \em true on success or \em false on failure
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual bool initialize(Async::Config& cfgobj,
|
||||
const std::string& logic_name)
|
||||
virtual ~LogicBase(void) {}
|
||||
|
||||
/**
|
||||
* @brief Initialize the logic core
|
||||
* @return Returns \em true on success or \em false on failure
|
||||
*/
|
||||
virtual bool initialize(void)
|
||||
{
|
||||
m_cfg = &cfgobj;
|
||||
m_name = logic_name;
|
||||
|
||||
if (LinkManager::hasInstance())
|
||||
{
|
||||
// Register this logic in the link manager
|
||||
|
|
@ -165,7 +164,7 @@ class LogicBase : public Async::Plugin, public sigc::trackable
|
|||
* @brief Get the configuration object associated with this logic core
|
||||
* @return Returns the configuration object associated with this logic core
|
||||
*/
|
||||
Async::Config &cfg(void) const { return *m_cfg; }
|
||||
Async::Config &cfg(void) const { return m_cfg; }
|
||||
|
||||
/**
|
||||
* @brief Get the idle state of this logic core
|
||||
|
|
@ -296,18 +295,6 @@ class LogicBase : public Async::Plugin, public sigc::trackable
|
|||
const std::string&> publishStateEvent;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~LogicBase(void) override
|
||||
{
|
||||
if (LinkManager::hasInstance())
|
||||
{
|
||||
// Unregister this logic from the link manager
|
||||
LinkManager::instance()->deleteLogic(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Used by derived classes to set the idle state of the logic core
|
||||
* @param set_idle \em True to set to idle or \em false to set to active
|
||||
|
|
@ -338,10 +325,10 @@ class LogicBase : public Async::Plugin, public sigc::trackable
|
|||
}
|
||||
|
||||
private:
|
||||
Async::Config* m_cfg = nullptr;
|
||||
Async::Config &m_cfg;
|
||||
std::string m_name;
|
||||
bool m_is_idle = true;
|
||||
uint32_t m_received_tg = 0;
|
||||
bool m_is_idle;
|
||||
uint32_t m_received_tg;
|
||||
|
||||
}; /* class LogicBase */
|
||||
|
||||
|
|
|
|||
|
|
@ -105,17 +105,6 @@ using namespace Async;
|
|||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Exported Global functions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
extern "C" {
|
||||
LogicBase* construct(void) { return new ReflectorLogic; }
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Local Global Variables
|
||||
|
|
@ -130,8 +119,8 @@ extern "C" {
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
ReflectorLogic::ReflectorLogic(void)
|
||||
: m_msg_type(0), m_udp_sock(0),
|
||||
ReflectorLogic::ReflectorLogic(Async::Config& cfg, const std::string& name)
|
||||
: LogicBase(cfg, name), m_msg_type(0), m_udp_sock(0),
|
||||
m_logic_con_in(0), m_logic_con_out(0),
|
||||
m_reconnect_timer(60000, Timer::TYPE_ONESHOT, false),
|
||||
m_next_udp_tx_seq(0), m_next_udp_rx_seq(0),
|
||||
|
|
@ -179,21 +168,26 @@ ReflectorLogic::ReflectorLogic(void)
|
|||
} /* ReflectorLogic::ReflectorLogic */
|
||||
|
||||
|
||||
bool ReflectorLogic::initialize(Async::Config& cfgobj, const std::string& logic_name)
|
||||
ReflectorLogic::~ReflectorLogic(void)
|
||||
{
|
||||
// Must create logic connection objects before calling LogicBase::initialize
|
||||
m_logic_con_in = new Async::AudioStreamStateDetector;
|
||||
m_logic_con_in->sigStreamStateChanged.connect(
|
||||
sigc::mem_fun(*this, &ReflectorLogic::onLogicConInStreamStateChanged));
|
||||
m_logic_con_out = new Async::AudioStreamStateDetector;
|
||||
m_logic_con_out->sigStreamStateChanged.connect(
|
||||
sigc::mem_fun(*this, &ReflectorLogic::onLogicConOutStreamStateChanged));
|
||||
disconnect();
|
||||
delete m_event_handler;
|
||||
m_event_handler = 0;
|
||||
delete m_udp_sock;
|
||||
m_udp_sock = 0;
|
||||
delete m_logic_con_in;
|
||||
m_logic_con_in = 0;
|
||||
delete m_enc;
|
||||
m_enc = 0;
|
||||
delete m_dec;
|
||||
m_dec = 0;
|
||||
delete m_logic_con_in_valve;
|
||||
m_logic_con_in_valve = 0;
|
||||
} /* ReflectorLogic::~ReflectorLogic */
|
||||
|
||||
if (!LogicBase::initialize(cfgobj, logic_name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReflectorLogic::initialize(void)
|
||||
{
|
||||
cfg().getValue(name(), "VERBOSE", m_verbose);
|
||||
|
||||
std::vector<std::string> hosts;
|
||||
|
|
@ -316,6 +310,10 @@ bool ReflectorLogic::initialize(Async::Config& cfgobj, const std::string& logic_
|
|||
cfg().getValue(name(), "AUDIO_CODEC", audio_codec);
|
||||
#endif
|
||||
|
||||
// Create logic connection incoming audio passthrough
|
||||
m_logic_con_in = new Async::AudioStreamStateDetector;
|
||||
m_logic_con_in->sigStreamStateChanged.connect(
|
||||
sigc::mem_fun(*this, &ReflectorLogic::onLogicConInStreamStateChanged));
|
||||
AudioSource *prev_src = m_logic_con_in;
|
||||
|
||||
cfg().getValue(name(), "MUTE_FIRST_TX_LOC", m_mute_first_tx_loc);
|
||||
|
|
@ -346,6 +344,9 @@ bool ReflectorLogic::initialize(Async::Config& cfgobj, const std::string& logic_
|
|||
fifo->setPrebufSamples(jitter_buffer_delay * INTERNAL_SAMPLE_RATE / 1000);
|
||||
}
|
||||
|
||||
m_logic_con_out = new Async::AudioStreamStateDetector;
|
||||
m_logic_con_out->sigStreamStateChanged.connect(
|
||||
sigc::mem_fun(*this, &ReflectorLogic::onLogicConOutStreamStateChanged));
|
||||
prev_src->registerSink(m_logic_con_out, true);
|
||||
prev_src = 0;
|
||||
|
||||
|
|
@ -440,6 +441,11 @@ bool ReflectorLogic::initialize(Async::Config& cfgobj, const std::string& logic_
|
|||
cfg().getValue(name(), "UDP_HEARTBEAT_INTERVAL",
|
||||
m_udp_heartbeat_tx_cnt_reset);
|
||||
|
||||
if (!LogicBase::initialize())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
connect();
|
||||
|
||||
return true;
|
||||
|
|
@ -728,24 +734,6 @@ void ReflectorLogic::remoteReceivedPublishStateEvent(
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
ReflectorLogic::~ReflectorLogic(void)
|
||||
{
|
||||
disconnect();
|
||||
delete m_event_handler;
|
||||
m_event_handler = 0;
|
||||
delete m_udp_sock;
|
||||
m_udp_sock = 0;
|
||||
delete m_logic_con_in;
|
||||
m_logic_con_in = 0;
|
||||
delete m_enc;
|
||||
m_enc = 0;
|
||||
delete m_dec;
|
||||
m_dec = 0;
|
||||
delete m_logic_con_in_valve;
|
||||
m_logic_con_in_valve = 0;
|
||||
} /* ReflectorLogic::~ReflectorLogic */
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -771,7 +759,6 @@ void ReflectorLogic::onConnected(void)
|
|||
timerclear(&m_last_talker_timestamp);
|
||||
m_con_state = STATE_EXPECT_AUTH_CHALLENGE;
|
||||
m_con.setMaxFrameSize(ReflectorMsg::MAX_PREAUTH_FRAME_SIZE);
|
||||
processEvent("reflector_connection_status_update 1");
|
||||
} /* ReflectorLogic::onConnected */
|
||||
|
||||
|
||||
|
|
@ -799,7 +786,6 @@ void ReflectorLogic::onDisconnected(TcpConnection *con,
|
|||
timerclear(&m_last_talker_timestamp);
|
||||
}
|
||||
m_con_state = STATE_DISCONNECTED;
|
||||
processEvent("reflector_connection_status_update 0");
|
||||
} /* ReflectorLogic::onDisconnected */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2017 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
|
||||
|
|
@ -119,18 +119,22 @@ class ReflectorLogic : public LogicBase
|
|||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @brief Constructor
|
||||
* @param cfg A previously initialized configuration object
|
||||
* @param name The name of the logic core
|
||||
*/
|
||||
ReflectorLogic(void);
|
||||
ReflectorLogic(Async::Config& cfg, const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief Initialize the logic core
|
||||
* @param cfgobj A previously initialized configuration object
|
||||
* @param plugin_name The name of the logic core
|
||||
* @return Returns \em true on success or \em false on failure
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual bool initialize(Async::Config& cfgobj,
|
||||
const std::string& logic_name) override;
|
||||
~ReflectorLogic(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize the logic core
|
||||
* @return Returns \em true on success or \em false on failure
|
||||
*/
|
||||
virtual bool initialize(void);
|
||||
|
||||
/**
|
||||
* @brief Get the audio pipe sink used for writing audio into this logic
|
||||
|
|
@ -178,10 +182,6 @@ class ReflectorLogic : public LogicBase
|
|||
const std::string& data);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~ReflectorLogic(void) override;
|
||||
|
||||
private:
|
||||
struct MonitorTgEntry
|
||||
|
|
|
|||
|
|
@ -31,10 +31,6 @@ variable announce_remote_min_interval 0
|
|||
# activity") is active. See configuration variable QSY_PENDING_TIMEOUT.
|
||||
variable qsy_pending_active 0
|
||||
|
||||
# This variable will be set to 1 if the connection to the reflector is
|
||||
# established and to 0 if disconnected.
|
||||
variable reflector_connection_established 0
|
||||
|
||||
#
|
||||
# Checking to see if this is the correct logic core
|
||||
#
|
||||
|
|
@ -43,22 +39,6 @@ if {$logic_name != [namespace tail [namespace current]]} {
|
|||
}
|
||||
|
||||
|
||||
#
|
||||
# A helper function for announcing a talkgroup.
|
||||
# If there is an audio clip matching the name talk_group-<tg> it will be played
|
||||
# instead of spelling the digits. Look at the documentation for playMsg for
|
||||
# more information on where to put the audio clip.
|
||||
#
|
||||
# tg - The talkgroup to announce
|
||||
#
|
||||
proc say_talkgroup {tg} {
|
||||
if [playMsg "Core" "talk_group-$tg" 0] {
|
||||
} else {
|
||||
spellNumber $tg
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when an unknown command is received
|
||||
# cmd - The command string
|
||||
|
|
@ -76,25 +56,6 @@ proc command_failed {cmd} {
|
|||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when the reflector connection status is updated
|
||||
#
|
||||
# is_established - 0=disconnected, 1=established
|
||||
#
|
||||
proc reflector_connection_status_update {is_established} {
|
||||
variable reflector_connection_established
|
||||
if {$is_established != $reflector_connection_established} {
|
||||
set reflector_connection_established $is_established
|
||||
#playMsg "Core" "reflector"
|
||||
#if {$is_established} {
|
||||
# playMsg "Core" "connected"
|
||||
#} else {
|
||||
# playMsg "Core" "disconnected"
|
||||
#}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when manual TG announcement is triggered
|
||||
#
|
||||
|
|
@ -103,24 +64,16 @@ proc report_tg_status {} {
|
|||
variable previous_tg
|
||||
variable prev_announce_time
|
||||
variable prev_announce_tg
|
||||
variable reflector_connection_established
|
||||
playSilence 100
|
||||
playMsg "Core" "reflector"
|
||||
if {$reflector_connection_established} {
|
||||
playMsg "Core" "connected"
|
||||
} else {
|
||||
playMsg "Core" "disconnected"
|
||||
}
|
||||
playSilence 200
|
||||
if {$selected_tg > 0} {
|
||||
set prev_announce_time [clock seconds]
|
||||
set prev_announce_tg $selected_tg
|
||||
playMsg "Core" "talk_group"
|
||||
say_talkgroup $selected_tg
|
||||
spellNumber $selected_tg
|
||||
} else {
|
||||
playMsg "Core" "previous"
|
||||
playMsg "Core" "talk_group"
|
||||
say_talkgroup $previous_tg
|
||||
spellNumber $previous_tg
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -156,20 +109,14 @@ proc tg_local_activation {new_tg old_tg} {
|
|||
variable prev_announce_time
|
||||
variable prev_announce_tg
|
||||
variable selected_tg
|
||||
variable reflector_connection_established
|
||||
|
||||
#puts "### tg_local_activation"
|
||||
if {$new_tg != $old_tg} {
|
||||
set prev_announce_time [clock seconds]
|
||||
set prev_announce_tg $new_tg
|
||||
playSilence 100
|
||||
if {!$reflector_connection_established} {
|
||||
playMsg "Core" "reflector"
|
||||
playMsg "Core" "disconnected"
|
||||
playSilence 200
|
||||
}
|
||||
playMsg "Core" "talk_group"
|
||||
say_talkgroup $new_tg
|
||||
spellNumber $new_tg
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -196,7 +143,7 @@ proc tg_remote_activation {new_tg old_tg} {
|
|||
set prev_announce_tg $new_tg
|
||||
playSilence 100
|
||||
playMsg "Core" "talk_group"
|
||||
say_talkgroup $new_tg
|
||||
spellNumber $new_tg
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -222,19 +169,13 @@ proc tg_remote_prio_activation {new_tg old_tg} {
|
|||
proc tg_command_activation {new_tg old_tg} {
|
||||
variable prev_announce_time
|
||||
variable prev_announce_tg
|
||||
variable reflector_connection_established
|
||||
|
||||
#puts "### tg_command_activation"
|
||||
set prev_announce_time [clock seconds]
|
||||
set prev_announce_tg $new_tg
|
||||
playSilence 100
|
||||
if {!$reflector_connection_established} {
|
||||
playMsg "Core" "reflector"
|
||||
playMsg "Core" "disconnected"
|
||||
playSilence 200
|
||||
}
|
||||
playMsg "Core" "talk_group"
|
||||
say_talkgroup $new_tg
|
||||
spellNumber $new_tg
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -248,19 +189,13 @@ proc tg_default_activation {new_tg old_tg} {
|
|||
#variable prev_announce_time
|
||||
#variable prev_announce_tg
|
||||
#variable selected_tg
|
||||
#variable reflector_connection_established
|
||||
#puts "### tg_default_activation"
|
||||
#if {$new_tg != $old_tg} {
|
||||
# set prev_announce_time [clock seconds]
|
||||
# set prev_announce_tg $new_tg
|
||||
# playSilence 100
|
||||
# if {!$reflector_connection_established} {
|
||||
# playMsg "Core" "reflector"
|
||||
# playMsg "Core" "disconnected"
|
||||
# playSilence 200
|
||||
# }
|
||||
# playMsg "Core" "talk_group"
|
||||
# say_talkgroup $new_tg
|
||||
# spellNumber $new_tg
|
||||
#}
|
||||
}
|
||||
|
||||
|
|
@ -281,7 +216,7 @@ proc tg_qsy {new_tg old_tg} {
|
|||
playSilence 100
|
||||
playMsg "Core" "qsy"
|
||||
#playMsg "Core" "talk_group"
|
||||
say_talkgroup $new_tg
|
||||
spellNumber $new_tg
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -319,7 +254,7 @@ proc tg_qsy_failed {} {
|
|||
proc tg_qsy_pending {tg} {
|
||||
playSilence 100
|
||||
playMsg "Core" "qsy"
|
||||
say_talkgroup $tg
|
||||
spellNumber $tg
|
||||
playMsg "Core" "pending"
|
||||
}
|
||||
|
||||
|
|
@ -334,7 +269,7 @@ proc tg_qsy_ignored {tg} {
|
|||
playSilence 100
|
||||
if {!$qsy_pending_active} {
|
||||
playMsg "Core" "qsy"
|
||||
say_talkgroup $tg
|
||||
spellNumber $tg
|
||||
}
|
||||
playMsg "Core" "ignored"
|
||||
playSilence 500
|
||||
|
|
@ -402,7 +337,7 @@ proc tmp_monitor_add {tg} {
|
|||
#puts "### tmp_monitor_add: $tg"
|
||||
playSilence 100
|
||||
playMsg "Core" "monitor"
|
||||
say_talkgroup $tg
|
||||
spellNumber $tg
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -109,16 +109,6 @@ using namespace Async;
|
|||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Exported Global functions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
extern "C" {
|
||||
LogicBase* construct(void) { return new RepeaterLogic; }
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
|
|
@ -135,8 +125,8 @@ extern "C" {
|
|||
****************************************************************************/
|
||||
|
||||
|
||||
RepeaterLogic::RepeaterLogic(void)
|
||||
: repeater_is_up(false),
|
||||
RepeaterLogic::RepeaterLogic(Async::Config& cfg, const std::string& name)
|
||||
: Logic(cfg, name), repeater_is_up(false),
|
||||
up_timer(30000, Timer::TYPE_ONESHOT, false),
|
||||
idle_sound_timer(-1, Timer::TYPE_PERIODIC),
|
||||
open_on_sql_after_rpt_close(0), open_on_dtmf('?'),
|
||||
|
|
@ -157,9 +147,14 @@ RepeaterLogic::RepeaterLogic(void)
|
|||
} /* RepeaterLogic::RepeaterLogic */
|
||||
|
||||
|
||||
bool RepeaterLogic::initialize(Async::Config& cfgobj, const std::string& logic_name)
|
||||
RepeaterLogic::~RepeaterLogic(void)
|
||||
{
|
||||
if (!Logic::initialize(cfgobj, logic_name))
|
||||
} /* RepeaterLogic::~RepeaterLogic */
|
||||
|
||||
|
||||
bool RepeaterLogic::initialize(void)
|
||||
{
|
||||
if (!Logic::initialize())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2004-2022 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2004-2015 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
|
||||
|
|
@ -121,19 +121,23 @@ class RepeaterLogic : public Logic
|
|||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @brief Constuctor
|
||||
* @param cfg A previously initialized config object
|
||||
* @param name The name of this logic
|
||||
*/
|
||||
RepeaterLogic(void);
|
||||
|
||||
RepeaterLogic(Async::Config& cfg, const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~RepeaterLogic(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize this logic
|
||||
* @param cfgobj A previously initialized config object
|
||||
* @param plugin_name The name of this logic
|
||||
* @return Returns \em true on success or \em false on failure
|
||||
*/
|
||||
virtual bool initialize(Async::Config& cfgobj,
|
||||
const std::string& logic_name) override;
|
||||
|
||||
bool initialize(void);
|
||||
|
||||
/**
|
||||
* @brief Process an event
|
||||
* @param event Event string
|
||||
|
|
@ -169,11 +173,6 @@ class RepeaterLogic : public Logic
|
|||
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~RepeaterLogic(void) override {};
|
||||
|
||||
virtual void allMsgsWritten(void);
|
||||
virtual void audioStreamStateChange(bool is_active, bool is_idle);
|
||||
virtual void dtmfCtrlPtyCmdReceived(const void *buf, size_t count);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2018 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
|
||||
|
|
@ -100,16 +100,6 @@ using namespace Async;
|
|||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Exported Global functions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
extern "C" {
|
||||
LogicBase* construct(void) { return new SimplexLogic; }
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
|
|
@ -126,16 +116,21 @@ extern "C" {
|
|||
****************************************************************************/
|
||||
|
||||
|
||||
SimplexLogic::SimplexLogic(void)
|
||||
: mute_rx_on_tx(true), mute_tx_on_rx(true),
|
||||
SimplexLogic::SimplexLogic(Async::Config& cfg, const string& name)
|
||||
: Logic(cfg, name), mute_rx_on_tx(true), mute_tx_on_rx(true),
|
||||
rgr_sound_always(false)
|
||||
{
|
||||
} /* SimplexLogic::SimplexLogic */
|
||||
|
||||
|
||||
bool SimplexLogic::initialize(Async::Config& cfgobj, const string& logic_name)
|
||||
SimplexLogic::~SimplexLogic(void)
|
||||
{
|
||||
if (!Logic::initialize(cfgobj, logic_name))
|
||||
} /* SimplexLogic::~SimplexLogic */
|
||||
|
||||
|
||||
bool SimplexLogic::initialize(void)
|
||||
{
|
||||
if (!Logic::initialize())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2018 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
|
||||
|
|
@ -112,26 +112,25 @@ class SimplexLogic : public Logic
|
|||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @brief Constuctor
|
||||
* @param cfg A previously opened configuration
|
||||
* @param name The configuration section name of this logic
|
||||
*/
|
||||
SimplexLogic(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize the simplex logic core
|
||||
* @param cfgobj A previously opened configuration
|
||||
* @param plugin_name The configuration section name of this logic
|
||||
* @return Returns \em true if the initialization was successful or else
|
||||
* \em false is returned.
|
||||
*/
|
||||
virtual bool initialize(Async::Config &cfgobj,
|
||||
const std::string &logic_name) override;
|
||||
|
||||
protected:
|
||||
SimplexLogic(Async::Config &cfg, const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~SimplexLogic(void) override {};
|
||||
~SimplexLogic(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize the simplex logic core
|
||||
* @return Returns \em true if the initialization was successful or else
|
||||
* \em false is returned.
|
||||
*/
|
||||
bool initialize(void);
|
||||
|
||||
protected:
|
||||
virtual void squelchOpen(bool is_open);
|
||||
virtual void transmitterStateChange(bool is_transmitting);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
# Add a subdirectory containing contributed code
|
||||
#
|
||||
# name - The upper case name of the contrib
|
||||
# subdir - The subdirectory where the code is found
|
||||
# comment - Comment text for the CMake option
|
||||
#
|
||||
macro(add_contrib name subdir comment)
|
||||
option(WITH_CONTRIB_${name} ${comment})
|
||||
if(${WITH_CONTRIB_${name}})
|
||||
message(STATUS "Building experimental contributed code ${subdir}")
|
||||
add_subdirectory(${subdir})
|
||||
endif(${WITH_CONTRIB_${name}})
|
||||
endmacro(add_contrib)
|
||||
|
||||
add_contrib(SIP_LOGIC SipLogic
|
||||
"Set to ON to build and install contributed logic core SipLogic")
|
||||
|
|
@ -1 +0,0 @@
|
|||
README.html
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
# Find the pjproject libraries and include files
|
||||
pkg_check_modules(PJSIP "libpjproject")
|
||||
message(
|
||||
"-- The pjproject libraries are used for the EXPERIMENTAL logic core\n"
|
||||
"-- SipLogic."
|
||||
)
|
||||
if(PJSIP_FOUND)
|
||||
# Set up the build environment for the plugin
|
||||
add_definitions(${PJSIP_CFLAGS})
|
||||
set(LIBS ${PJSIP_STATIC_LIBRARIES})
|
||||
include_directories(${PJSIP_INCLUDE_DIRS})
|
||||
add_definitions("-DPJSIP_MAJOR=${PJSIP_VERSION_MAJOR}")
|
||||
add_manual_pages(SipLogic.conf.5)
|
||||
|
||||
# Build the plugin
|
||||
add_library(SipLogic MODULE SipLogic.cpp)
|
||||
set_target_properties(SipLogic PROPERTIES PREFIX "")
|
||||
set_property(TARGET SipLogic PROPERTY NO_SONAME 1)
|
||||
target_link_libraries(SipLogic ${LIBS})
|
||||
|
||||
# Install plugin, TCL event handler and config file
|
||||
install(TARGETS SipLogic DESTINATION ${SVX_LOGIC_CORE_INSTALL_DIR})
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/SipLogic.tcl
|
||||
DESTINATION ${SVX_SHARE_INSTALL_DIR}/events.d
|
||||
)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/SipLogic.conf.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/SipLogic.conf
|
||||
@ONLY
|
||||
)
|
||||
install_if_not_exists(${CMAKE_CURRENT_BINARY_DIR}/SipLogic.conf
|
||||
${SVX_SYSCONF_INSTALL_DIR}/svxlink.d
|
||||
)
|
||||
else (PJSIP_FOUND)
|
||||
message(FATAL_ERROR
|
||||
"Building of the contributed logic core SipLogic has been enabled "
|
||||
"but dependencies are missing. Aborting build."
|
||||
)
|
||||
endif(PJSIP_FOUND)
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
include (FindPkgConfig)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PJSIP REQUIRED libpjproject)
|
||||
endif()
|
||||
|
||||
include_directories(${PJSIP_INCLUDE_DIRS})
|
||||
link_directories(${PJSIP_LIBRARY_DIRS})
|
||||
|
||||
mark_as_advanced(pjsip_LIBRARY_DIRS pjsip_LIBRARIES)
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
Contrib: SipLogic
|
||||
=================
|
||||
|
||||
----
|
||||
#
|
||||
# SipLogic (beta)
|
||||
# Adi Bier / DL1HRC (dl1hrc [at] gmx.de)
|
||||
# Version 15112022
|
||||
#
|
||||
----
|
||||
SipLogic.conf is a sample configuration for a SipLogic connected to a Fritzbox
|
||||
by AVM. Remember that a Fritzbox requires a sip login and password with
|
||||
at least 8 characters that must be different eachother. The configuration of the
|
||||
Sip part has been moved to this new file, normally found in /etc/svxlink/svxlink.d
|
||||
----
|
||||
SIP_REGISTRAR=fritz.box
|
||||
or
|
||||
SIP_REGISTRAR=ip-address of your Fritzbox
|
||||
----
|
||||
is mandatory.
|
||||
|
||||
== pjSipLogic ==
|
||||
Provides a Sip client to connect to a Sip server like Asterisk, Allstar or a simple dsl router with Sip functionality.
|
||||
|
||||
Requirements:
|
||||
pjsip in version 2.10 or newer from https://www.pjsip.org/
|
||||
install pjsip first before continue with SvxLink:
|
||||
```
|
||||
wget https://github.com/pjsip/pjproject/archive/2.10.tar.gz
|
||||
tar -xzvf 2.10.tar.gz
|
||||
cd project-2.10
|
||||
./configure --disable-libwebrtc --disable-video
|
||||
|
||||
On amd64/x86_64 systems you should use
|
||||
./configure --disable-libwebrtc --disable-video CPPFLAGS=-fPIC CXXFLAGS=-fPIC CFLAGS=-fPIC
|
||||
otherwise linking errors may occur.
|
||||
|
||||
make dep;make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
== Installation of SvxLink with SipLogic extension ==
|
||||
```
|
||||
git clone https://github.com/dl1hrc/svxlink.git
|
||||
cd svxlink/src/
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DUSE_QT=OFF -DCMAKE_INSTALL_PREFIX=/usr -DSYSCONF_INSTALL_DIR=/etc -DLOCAL_STATE_DIR=/var -DMAKE_BUILD_TYPE=Release -DWITH_CONTRIB_SIP_LOGIC=ON ..
|
||||
make
|
||||
make install
|
||||
```
|
||||
== Documentation ==
|
||||
- manpage svxlink.conf.5
|
||||
- German pdf is available here: https://github.com/dl1hrc/documentation
|
||||
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
###############################################################################
|
||||
#
|
||||
# Generic Logic event handlers
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
#
|
||||
# This is the namespace in which all functions and variables below will exist.
|
||||
#
|
||||
namespace eval SimplexLogic {
|
||||
|
||||
variable stored_digits "";
|
||||
|
||||
#
|
||||
# Executed when a DTMF digit has been received
|
||||
# digit - The detected DTMF digit
|
||||
# duration - The duration, in milliseconds, of the digit
|
||||
#
|
||||
# Return 1 to hide the digit from further processing in SvxLink or
|
||||
# return 0 to make SvxLink continue processing as normal.
|
||||
#
|
||||
proc dtmf_digit_received {digit duration} {
|
||||
variable port;
|
||||
variable stored_digits;
|
||||
puts "DTMF digit \"$digit\" detected with duration $duration ms";
|
||||
|
||||
set len [string length $stored_digits];
|
||||
if {$len > 20} {
|
||||
set stored_digits "";
|
||||
}
|
||||
|
||||
if {$digit == "#"} {
|
||||
if {$len > 5 || $stored_digits == "CA"} {
|
||||
set port [open "/tmp/sip_ctrl" w+];
|
||||
puts $port $stored_digits;
|
||||
close $port;
|
||||
}
|
||||
set stored_digits "";
|
||||
} else {
|
||||
set stored_digits "$stored_digits$digit";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
# end of namespace
|
||||
}
|
||||
|
||||
#
|
||||
# This file has not been truncated
|
||||
#
|
||||
|
|
@ -1,180 +0,0 @@
|
|||
.TH SIPLOGIC.CONF 5 "November 2022" Linux "File Formats"
|
||||
.
|
||||
.SH NAME
|
||||
.
|
||||
SipLogic.conf \- SipLogic configuration file for the SvxLink server
|
||||
.
|
||||
.SH DESCRIPTION
|
||||
.
|
||||
.B svxlink
|
||||
is a general purpose voice service system for ham radio use. This man-page
|
||||
describe the SvxLink server configuration file format for the SipLogic logic
|
||||
core.
|
||||
.
|
||||
.SH CONFIGURATION VARIABLES
|
||||
.
|
||||
Here is the description of all configuration variables that the SipLogic
|
||||
SvxLink logic core understands. The configuration variables are described
|
||||
section for section.
|
||||
.
|
||||
.SS SipLogic
|
||||
.
|
||||
The SipLogic is used to connect to a Sip-based communication server like
|
||||
Astrisk.
|
||||
.TP
|
||||
.B TYPE
|
||||
The type for a sip logic core is always
|
||||
.BR Sip .
|
||||
.TP
|
||||
.B SIPSERVER
|
||||
The ip address or the hostname of the Sip communication server.
|
||||
.TP
|
||||
.B SIPPORT
|
||||
The udp port that is used for communication (normally 5060).
|
||||
.TP
|
||||
.B CALLERNAME
|
||||
The name of the station that is displayed instead of the number.
|
||||
.TP
|
||||
.B USERNAME
|
||||
The username that is used to connect to the Sip communication server.
|
||||
.TP
|
||||
.B PASSWORD
|
||||
The password for the USERNAME to connect to the Sip communication server.
|
||||
.TP
|
||||
.B SIPREGISTRAR
|
||||
The sip registrar or better kown as proxy (e.g. "fritz.box" for AVM Fritzboxes)
|
||||
.TP
|
||||
.B SIPSCHEMA
|
||||
The authentication scheme (e.g. "digest")
|
||||
.TP
|
||||
.B SIPEXTENSION
|
||||
The extension to used when connecting to a Sip communication server.
|
||||
.TP
|
||||
.B AUTOANSWER
|
||||
If set the call will be pickuped immediately when received.
|
||||
AUTOANSWER=(0|1)
|
||||
.TP
|
||||
.B AUTOCONNECT
|
||||
Define a party that will being connected after upon startup of SvxLink.
|
||||
AUTOCONNECT=user123@sipaccount.com
|
||||
.TP
|
||||
.B REJECT_INCOMING
|
||||
Reject all incoming phone calls where the remote number match this regular
|
||||
expression. For more information on the syntax, seek for
|
||||
.B REGULAR EXPRESSIONS
|
||||
.TP
|
||||
.B ACCEPT_INCOMING
|
||||
Only accept incoming phone calls where the remote number match this regular
|
||||
expression.
|
||||
For more information on the syntax, seek for
|
||||
.B REGULAR EXPRESSIONS
|
||||
.TP
|
||||
.B REJECT_OUTGOING
|
||||
Reject all outgoing phone calls where the remote number match this regular
|
||||
expression. For more information on the syntax, seek for
|
||||
.B REGULAR EXPRESSIONS
|
||||
.TP
|
||||
.B ACCEPT_OUTGOING
|
||||
Only accept outgoing phone calls where the remote number match this regular
|
||||
expression.
|
||||
For more information on the syntax, seek for
|
||||
.B REGULAR EXPRESSIONS
|
||||
.TP
|
||||
.B SEMI_DUPLEX (ToDo)
|
||||
If enabled no VOX squelch is used for Sip clients. That means that the audio
|
||||
stream from the SipLogic is sent continuously to the connected SvxLink nodes.
|
||||
That is only meaningful if all connected nodes are repeaters.
|
||||
SEMI_DUPLEX=(0|1)
|
||||
.TP
|
||||
.B VOX_FILTER_DEPTH
|
||||
see "Local Receiver Section"
|
||||
.TP
|
||||
.B VOX_THRESH
|
||||
see "Local Receiver Section"
|
||||
.TP
|
||||
.B SQL_START_DELAY
|
||||
see "Local Receiver Section"
|
||||
.TP
|
||||
.B SQL_DELAY
|
||||
see "Local Receiver Section"
|
||||
.TP
|
||||
.B SQL_HANGTIME
|
||||
see "Local Receiver Section"
|
||||
.TP
|
||||
.B SIP_LOGLEVEL
|
||||
The debug output of the pjsip library (0..6)
|
||||
.TP
|
||||
.B JITTER_BUFFER_DELAY
|
||||
A jitter buffer is used to prevent gaps in the audio when the network
|
||||
connection do not provide a steady flow of data. Set this configuration
|
||||
variable to the number of milliseconds to buffer before starting to process the
|
||||
audio. Default: 0.
|
||||
.TP
|
||||
.B REG_TIMEOUT
|
||||
Time in seconds to renewal the registration at the sip server.
|
||||
.TP
|
||||
.B CALL_TIMEOUT
|
||||
Time in seconds after an outgoing call will be terminate when the party will not
|
||||
pickup the call.
|
||||
.TP
|
||||
.B SIP_CTRL_PTY
|
||||
Using this configuration variable it is possible to specify a path to a UNIX 98
|
||||
PTY that allows a dtmf control of each single SvxLink logic. 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 'C1#' > /path/to/pty"
|
||||
after starting SvxLink. The device works bidirectional, received dtmf characters
|
||||
(from local application) are output via this interface.
|
||||
Example: SIP_CTRL_PTY=/dev/shm/dtmf_ctrl
|
||||
.TP
|
||||
.B SIP_PREAMP
|
||||
The incoming signal from the Sip network will be amplified by the specified
|
||||
number of dB. This can be used as a last measure if the input audio level
|
||||
can't be set high enough on the analogue side. A value of 6dB will double
|
||||
the signal level. Note that this is a digital amplification. Hence it will
|
||||
reduce the dynamic range of the signal so usage should be avoided if possible.
|
||||
It's always better to correct the audio level before sampling it.
|
||||
.TP
|
||||
.B SIP_LIMITER_THRESH
|
||||
Set the threshold, in dBFS, for the audio limiter. The audio limiter really is
|
||||
a compressor with a very steep compression ratio like 10:1. The limiter is
|
||||
used to help keeping down the audio level from Sip network for overmodulating
|
||||
stations. Try values from -6 to -12 if the incoming Sip audio is to high. Set
|
||||
to 0 to deactivate it.
|
||||
.TP
|
||||
.B PHONENUMBER_TO_TG
|
||||
Comma-separated list of assignments of phonenumber(full||substring):Talkgroup.
|
||||
When a phone call is received, the call is assigned to the defined TG according
|
||||
to the recognized number. This can be used to prevent the transfer of an SIP
|
||||
call to a network or to carry out a country-specific assignment. The number
|
||||
format transmitted must match the configuration (+49 != 0049). Whole SIP
|
||||
numbers as well as parts of phone numbers can be configured, with the
|
||||
evaluation taking place on the left-hand side.
|
||||
Example: PHONENUMBER_TO_TG=0049:262,0034:214,0043:232,0049123454543:991
|
||||
.TP
|
||||
.B USE_TCP
|
||||
If set, TCP is used as transport layer instead of UDP (default).
|
||||
.
|
||||
.SH FILES
|
||||
.
|
||||
.TP
|
||||
.IR /etc/svxlink/svxlink.d/SipLogic.conf
|
||||
The SipLogic specific configuration file.
|
||||
.TP
|
||||
.IR /etc/svxlink/svxlink.conf
|
||||
The system wide configuration file.
|
||||
.TP
|
||||
.IR ~/.svxlink/svxlink.conf
|
||||
Per user configuration file.
|
||||
.TP
|
||||
.I /etc/svxlink/svxlink.d/*
|
||||
Additional configuration files. Typically one configuration file per module.
|
||||
.
|
||||
.SH AUTHOR
|
||||
.
|
||||
Adi Bier (DL1HRC)
|
||||
.
|
||||
.SH "SEE ALSO"
|
||||
.
|
||||
.BR svxlink.conf (5)
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
[SipLogic]
|
||||
TYPE=Sip
|
||||
DEFAULT_LANG=en_US
|
||||
SIPSERVER=reflector.example.com
|
||||
#SIPREGISTRAR=proxy.mysipnetwork.com
|
||||
SIPPORT=5060
|
||||
CALLERNAME="svxlink user <12345>"
|
||||
USERNAME=user
|
||||
PASSWORD=secret
|
||||
SIPSCHEMA=Digest
|
||||
SIPEXTENSION=default
|
||||
AUTOANSWER=0
|
||||
#AUTOCONNECT=621
|
||||
SIP_LOGLEVEL=1
|
||||
CALL_TIMEOUT=45
|
||||
SEMI_DUPLEX=0
|
||||
#REJECT_INCOMING=^()$
|
||||
#ACCEPT_INCOMING=^(.*)$
|
||||
#REJECT_OUTGOING=^()$
|
||||
#ACCEPT_OUTGOING=^(.*)$
|
||||
#REG_TIMEOUT=300
|
||||
VOX_FILTER_DEPTH=20
|
||||
VOX_THRESH=1000
|
||||
SIP_CTRL_PTY=/tmp/sip_pty
|
||||
#JITTER_BUFFER_DELAY=0
|
||||
EVENT_HANDLER=@SVX_SHARE_INSTALL_DIR@/events.tcl
|
||||
SIP_PREAMP=3
|
||||
SIP_LIMITER_THRESH=-1.0
|
||||
PHONENUMBER_TO_TG=0049:262,0034:232,0041:222,017612345678:9999
|
||||
#USE_TCP=1
|
||||
|
||||
# ToDo, section still not active
|
||||
[Phonenumber_to_Tg]
|
||||
0049=262
|
||||
0034=232
|
||||
262=262
|
||||
0176212121212=9
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,250 +0,0 @@
|
|||
/**
|
||||
@file SipLogic.h
|
||||
@brief A logic core that connect to a Sip Server e.g. Asterisk
|
||||
@author Tobias Blomberg / SM0SVX & Christian Stussak & Adi Bier / DL1HRC
|
||||
@date 2018-02-12
|
||||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2003-2022 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
\endverbatim
|
||||
*/
|
||||
|
||||
#ifndef SIP_LOGIC_INCLUDED
|
||||
#define SIP_LOGIC_INCLUDED
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* System Includes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sigc++/sigc++.h>
|
||||
#include <regex.h>
|
||||
|
||||
#include <pjmedia.h>
|
||||
#include <pjsua-lib/pjsua.h>
|
||||
#include <pjsua2.hpp>
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Project Includes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <AsyncTimer.h>
|
||||
#include <AsyncAudioFifo.h>
|
||||
#include <AsyncAudioPassthrough.h>
|
||||
#include <AsyncAudioValve.h>
|
||||
#include <AsyncAudioReader.h>
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Local Includes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "LogicBase.h"
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Forward declarations
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Forward declarations of classes inside of the declared namespace
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
namespace sip
|
||||
{
|
||||
class _Account;
|
||||
class _Call;
|
||||
class _AudioMedia;
|
||||
};
|
||||
namespace Async
|
||||
{
|
||||
class Pty;
|
||||
};
|
||||
class Squelch;
|
||||
class MsgHandler;
|
||||
class EventHandler;
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Defines & typedefs
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Exported Global Variables
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Class definitions
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
@brief A logic core that connect to a Sip Server e.g. Asterisk
|
||||
@author Tobias Blomberg / SM0SVX & Adi Bier / DL1HRC
|
||||
@date 2018-02-12
|
||||
*/
|
||||
class SipLogic : public LogicBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
SipLogic(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize the logic core
|
||||
* @param cfgobj A previously initialized configuration object
|
||||
* @param logic_name The name of the logic core
|
||||
* @return Returns \em true on success or \em false on failure
|
||||
*/
|
||||
virtual bool initialize(Async::Config& cfgobj,
|
||||
const std::string& logic_name) override;
|
||||
|
||||
/**
|
||||
* @brief Get the audio pipe sink used for writing audio into this logic
|
||||
* @return Returns an audio pipe sink object
|
||||
*/
|
||||
virtual Async::AudioSink *logicConIn(void) { return m_logic_con_in; }
|
||||
|
||||
/**
|
||||
* @brief Get the audio pipe source used for reading audio from this logic
|
||||
* @return Returns an audio pipe source object
|
||||
*/
|
||||
virtual Async::AudioSelector *logicConOut(void) { return m_logic_con_out; }
|
||||
|
||||
pj_status_t mediaPortGetFrame(pjmedia_port *med_port, pjmedia_frame *put_frame);
|
||||
pj_status_t mediaPortPutFrame(pjmedia_port *med_port, pjmedia_frame *put_frame);
|
||||
|
||||
void setReportEventsAsIdle(bool idle) { report_events_as_idle = idle; }
|
||||
|
||||
void processLogicEvent(const std::string& event);
|
||||
void processSipEvent(const std::string& event);
|
||||
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~SipLogic(void) override;
|
||||
|
||||
virtual void allMsgsWritten(void);
|
||||
std::string initCallHandler(int argc, const char* argv[]);
|
||||
void checkIdle(void);
|
||||
|
||||
private:
|
||||
std::string m_sipserver;
|
||||
Async::AudioPassthrough* m_logic_con_in;
|
||||
Async::AudioSelector* m_logic_con_out;
|
||||
Async::AudioPassthrough* m_out_src;
|
||||
Async::AudioValve* m_outto_sip;
|
||||
Async::AudioValve* m_infrom_sip;
|
||||
Async::AudioReader* m_ar;
|
||||
bool m_autoanswer;
|
||||
uint16_t m_sip_port;
|
||||
sip::_Account *acc;
|
||||
std::vector<sip::_Call *> calls;
|
||||
Async::Pty *dtmf_ctrl_pty;
|
||||
pj::AudioMedia *sip_buf;
|
||||
Async::Timer m_call_timeout_timer;
|
||||
sip::_AudioMedia *media;
|
||||
Squelch *squelch_det;
|
||||
pj::Endpoint ep;
|
||||
regex_t *accept_incoming_regex;
|
||||
regex_t *reject_incoming_regex;
|
||||
regex_t *accept_outgoing_regex;
|
||||
regex_t *reject_outgoing_regex;
|
||||
MsgHandler *logic_msg_handler;
|
||||
EventHandler *logic_event_handler;
|
||||
bool report_events_as_idle;
|
||||
bool startup_finished;
|
||||
Async::AudioSelector *logicselector;
|
||||
bool semi_duplex;
|
||||
float sip_preamp_gain;
|
||||
std::string m_autoconnect;
|
||||
EventHandler *sip_event_handler;
|
||||
MsgHandler *sip_msg_handler;
|
||||
Async::AudioSelector *sipselector;
|
||||
std::map<std::string, uint32_t> phoneNrTgVec;
|
||||
uint16_t m_siploglevel;
|
||||
|
||||
SipLogic(const SipLogic&);
|
||||
SipLogic& operator=(const SipLogic&);
|
||||
void makeCall(sip::_Account *acc, std::string dest_uri);
|
||||
void onIncomingCall(sip::_Account *acc, pj::OnIncomingCallParam &iprm);
|
||||
void onRegState(sip::_Account *acc, pj::OnRegStateParam &prm);
|
||||
bool setAudioCodec(const std::string& codec_name);
|
||||
void onDtmfDigit(sip::_Call *call, pj::OnDtmfDigitParam &prm);
|
||||
void onCallState(sip::_Call *call, pj::OnCallStateParam &prm);
|
||||
void onMessageInfo(sip::_Call *call, pj::OnInstantMessageParam &prm);
|
||||
void onMessage(sip::_Account *acc, pj::OnInstantMessageParam &imprm);
|
||||
void hangupCalls(std::vector<sip::_Call *> calls);
|
||||
void hangupCall(sip::_Call *call);
|
||||
void dtmfCtrlPtyCmdReceived(const void *buf, size_t count);
|
||||
void onMediaState(sip::_Call *call, pj::OnCallMediaStateParam &prm);
|
||||
void allSamplesFlushed(void);
|
||||
void registerCall(sip::_Call *call);
|
||||
std::string getCallerNumber(std::string uri);
|
||||
void flushAudio(void);
|
||||
void callTimeout(Async::Timer *t=0);
|
||||
void flushTimeout(Async::Timer *t=0);
|
||||
void onSquelchOpen(bool is_open);
|
||||
void unregisterCall(sip::_Call *call);
|
||||
void hangupAllCalls(void);
|
||||
|
||||
void playLogicFile(const std::string& path);
|
||||
void playLogicSilence(int length);
|
||||
void playLogicTone(int fq, int amp, int len);
|
||||
void playLogicDtmf(const std::string& digits, int amp, int len);
|
||||
void playSipFile(const std::string& path);
|
||||
void playSipSilence(int length);
|
||||
void playSipTone(int fq, int amp, int len);
|
||||
void playSipDtmf(const std::string& digits, int amp, int len);
|
||||
|
||||
}; /* class SipLogic */
|
||||
|
||||
|
||||
#endif /* SIP_LOGIC_INCLUDED */
|
||||
|
||||
|
||||
/*
|
||||
* This file has not been truncated
|
||||
*/
|
||||
|
|
@ -1,358 +0,0 @@
|
|||
###############################################################################
|
||||
#
|
||||
# SipLogic event handlers
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
#
|
||||
# This is the namespace in which all functions below will exist. The name
|
||||
# must match the corresponding section "[SipLogic]" in the configuration
|
||||
# file. The name may be changed but it must be changed in both places.
|
||||
#
|
||||
namespace eval SipLogic {
|
||||
|
||||
#
|
||||
# Checking to see if this is the correct logic core
|
||||
#
|
||||
if {$logic_name != [namespace tail [namespace current]]} {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when the SvxLink software is started
|
||||
#
|
||||
proc startup {} {
|
||||
global logic_name;
|
||||
puts "starting $logic_name";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when an unknown DTMF command is entered
|
||||
#
|
||||
proc unknown_command {cmd} {
|
||||
playMsg "Core" "unknown_command";
|
||||
playNumber $cmd;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when an outgoing call is not permitted (dropped)
|
||||
#
|
||||
proc drop_outgoing_call {caller} {
|
||||
puts "Dropping outgoing call to $caller due to configuration.";
|
||||
playMsg "SipLogic" "call_not_allowed";
|
||||
playSilence 200;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when an incoming call is rejected
|
||||
#
|
||||
proc reject_incoming_call {caller} {
|
||||
puts "Rejecting incoming call from $caller due to configuration.";
|
||||
playMsg "SipLogic" "reject_incoming_call";
|
||||
playSilence 200;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when an entered DTMF command failed
|
||||
#
|
||||
proc command_failed {cmd} {
|
||||
playMsg "Core" "command_failed";
|
||||
playNumber "Core" $cmd;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a link to another logic core is activated.
|
||||
# name - The name of the link
|
||||
#
|
||||
proc activating_link {name} {
|
||||
playMsg "Core" "activating_link";
|
||||
playMsg "Core" $name;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a link to another logic core is deactivated.
|
||||
# name - The name of the link
|
||||
#
|
||||
proc deactivating_link {name} {
|
||||
playMsg "Core" "deactivating_link";
|
||||
playMsg "Core" $name;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when trying to deactivate a link to another logic core but the
|
||||
# link is not currently active.
|
||||
# name - The name of the link
|
||||
#
|
||||
proc link_not_active {name} {
|
||||
# Logic::link_not_active $name;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when trying to activate a link to another logic core but the
|
||||
# link is already active.
|
||||
# name - The name of the link
|
||||
#
|
||||
proc link_already_active {name} {
|
||||
# Logic::link_already_active $name;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed once every whole minute
|
||||
#
|
||||
proc every_minute {} {
|
||||
Logic::every_minute;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed once every second
|
||||
#
|
||||
proc every_second {} {
|
||||
Logic::every_second;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed once every whole minute to check if it's time to identify
|
||||
#
|
||||
proc checkPeriodicIdentify {} {
|
||||
# Logic::checkPeriodicIdentify;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed if an call is established
|
||||
#
|
||||
proc call_connected {caller} {
|
||||
puts "call to/from: $caller established";
|
||||
playSilence 500;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed if an outgoing call is pending
|
||||
#
|
||||
proc calling {caller} {
|
||||
playSilence 500;
|
||||
playMsg "SipLogic" "outgoing_phonecall";
|
||||
playSilence 100;
|
||||
spellNumber [getCallerNumber $caller];
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed if an outgoing call is pending
|
||||
#
|
||||
proc outgoing_call {caller} {
|
||||
puts "outgoing_call $caller";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed if somebody is ringing
|
||||
#
|
||||
proc ringing {caller} {
|
||||
puts "$caller ringing";
|
||||
playMsg "SipLogic" "ringtone";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed if an incoming call is established
|
||||
#
|
||||
proc incoming_call {caller} {
|
||||
playSilence 500;
|
||||
playMsg "SipLogic" "incoming_phonecall";
|
||||
playSilence 100;
|
||||
playNumber [getCallerNumber $caller];
|
||||
playSilence 200;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a DTMF digit has been received
|
||||
# digit - The detected DTMF digit
|
||||
# code - The duration, in milliseconds, of the digit
|
||||
#
|
||||
# Return 1 to hide the digit from further processing in SvxLink or
|
||||
# return 0 to make SvxLink continue processing as normal.
|
||||
#
|
||||
proc dtmf_digit_received {digit caller} {
|
||||
puts "Dtmf digit received $digit from $caller";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a DTMF command has been received
|
||||
# cmd - The command
|
||||
#
|
||||
# Return 1 to hide the command from further processing is SvxLink or
|
||||
# return 0 to make SvxLink continue processing as normal.
|
||||
#
|
||||
proc dtmf_cmd_received {cmd} {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when the node is being brought online after being offline
|
||||
#
|
||||
proc logic_online {online} {
|
||||
puts "$online";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when the party isn't at home
|
||||
#
|
||||
proc call_timeout {} {
|
||||
puts "Called party is not at home";
|
||||
playMsg "SipLogic" "person_not_available";
|
||||
playSilence 200;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a call has hangup
|
||||
#
|
||||
proc hangup_call {uri duration} {
|
||||
puts "Hangup call $uri ($duration seconds)";
|
||||
playMsg "SipLogic" "call_terminated";
|
||||
playSilence 200;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Registration state (code)
|
||||
#
|
||||
proc registration_state {server state code} {
|
||||
variable status;
|
||||
if {$state} {
|
||||
set status "registered";
|
||||
} else {
|
||||
set status "unregistered";
|
||||
}
|
||||
puts "Registration on $server, code $code ($status)";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Returns the phone number of the remote station
|
||||
# URI: <sip:12345678@sipserver.com:5060>
|
||||
# -> 12345678
|
||||
#
|
||||
proc getCallerNumber {uri} {
|
||||
set r [split $uri @];
|
||||
set number [split [lindex $r 0] :];
|
||||
set nr [lindex $number 1];
|
||||
if {$nr ne ""} {
|
||||
return $nr;
|
||||
} else {
|
||||
return $uri;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# ToDo: Sends a reject-message to the caller via Sip
|
||||
#
|
||||
proc remote_reject_call {} {
|
||||
playMsg "call_rejected";
|
||||
playSilence 2500;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# ToDo: Sends a greeting message to the caller via Sip
|
||||
#
|
||||
proc remote_greeting {} {
|
||||
playMsg "SipLogic" "welcome";
|
||||
playSilence 200;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when an incoming call has ben picked
|
||||
#
|
||||
proc incoming_call_answered {caller} {
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a call(s) has been hangup by a rf user
|
||||
# by dtmf
|
||||
#
|
||||
proc call_hangup_by_user {} {
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
proc call_state_confirmed {caller} {
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed at unknown callstate
|
||||
#
|
||||
proc unknown_callstate {caller} {
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed if a PJSIP_INV_STATE_EARLY event occurred
|
||||
#
|
||||
proc pjsip_state_early {caller} {
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed if a PJSIP_INV_STATE_NULL event occurred
|
||||
#
|
||||
proc pjsip_state_null {caller} {
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed on incoming sip message from a connected party
|
||||
#
|
||||
proc text_message_received {uri message} {
|
||||
puts "Message from $uri received:";
|
||||
puts "$message";
|
||||
}
|
||||
|
||||
|
||||
# Executed on imcoming sip message from a not connected party over
|
||||
# the registered account
|
||||
#
|
||||
proc account_text_message_received {uri message} {
|
||||
puts "Message from $uri received:";
|
||||
puts "$message";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed if a call is registered
|
||||
#
|
||||
#
|
||||
proc call_registered {caller} {
|
||||
}
|
||||
|
||||
# end of namespace
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# This file has not been truncated
|
||||
#
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,160 +0,0 @@
|
|||
###############################################################################
|
||||
# #
|
||||
# Configuration file for the SvxLink server #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
[GLOBAL]
|
||||
MODULE_PATH=/usr/lib/svxlink
|
||||
LOGICS=RepeaterLogic,SipLogic
|
||||
CFG_DIR=svxlink.d
|
||||
TIMESTAMP_FORMAT="%d.%m.%Y %H:%M:%S.%f"
|
||||
CARD_SAMPLE_RATE=48000
|
||||
CARD_CHANNELS=1
|
||||
LINKS=SipLink
|
||||
|
||||
[SipLink]
|
||||
NAME=Sip
|
||||
CONNECT_LOGICS=RepeaterLogic,ReflectorLogic
|
||||
DEFAULT_ACTIVE=1
|
||||
|
||||
[SipLogic]
|
||||
TYPE=Sip
|
||||
SIPSERVER=192.168.178.1
|
||||
SIPPORT=5060
|
||||
USERNAME=svxlink_test
|
||||
CALLERNAME=SvxLink @ Fritz
|
||||
PASSWORD=secret_with_8chars
|
||||
SIPSCHEMA=digest
|
||||
SIPEXTENSION=default
|
||||
SIPREGISTRAR=fritz.box
|
||||
AUTOANSWER=1
|
||||
VOX_THRESH=1000
|
||||
VOX_FILTER_DEPTH=20
|
||||
#AUTOCONNECT=621
|
||||
#REJECT_INCOMING=^()$
|
||||
#ACCEPT_INCOMING=^(.*)$
|
||||
#REJECT_OUTGOING=^()$
|
||||
#ACCEPT_OUTGOING=^(.*)$
|
||||
SIP_LOGLEVEL=0
|
||||
CALL_TIMEOUT=45
|
||||
SEMI_DUPLEX=0
|
||||
SQL_DELAY=0
|
||||
SQL_START_DELAY=0
|
||||
SQL_HANGTIME=1400
|
||||
#REG_TIMEOUT=300
|
||||
#JITTER_BUFFER_DELAY=0
|
||||
|
||||
[RepeaterLogic]
|
||||
TYPE=Repeater
|
||||
RX=Rx1
|
||||
TX=Tx1
|
||||
MODULES=ModuleHelp,ModuleMetarInfo
|
||||
CALLSIGN=DL1ABC
|
||||
SHORT_IDENT_INTERVAL=30
|
||||
LONG_IDENT_INTERVAL=60
|
||||
#IDENT_ONLY_AFTER_TX=4
|
||||
#EXEC_CMD_ON_SQL_CLOSE=500
|
||||
EVENT_HANDLER=/usr/share/svxlink/events.tcl
|
||||
DEFAULT_LANG=de_DE
|
||||
RGR_SOUND_DELAY=200
|
||||
#REPORT_CTCSS=136.5
|
||||
#TX_CTCSS=SQL_OPEN
|
||||
MACROS=Macros_R
|
||||
#SEL5_MACRO_RANGE=03400,03499
|
||||
FX_GAIN_NORMAL=0
|
||||
FX_GAIN_LOW=-12
|
||||
QSO_RECORDER=8:QsoRecorder
|
||||
NO_REPEAT=0
|
||||
IDLE_TIMEOUT=10
|
||||
#OPEN_ON_1750=1000
|
||||
#OPEN_ON_CTCSS=136:2000
|
||||
OPEN_ON_DTMF=*
|
||||
OPEN_ON_SQL=200
|
||||
#OPEN_ON_SEL5=01234
|
||||
OPEN_SQL_FLANK=OPEN
|
||||
#OPEN_ON_SQL_AFTER_RPT_CLOSE=10
|
||||
#IDLE_SOUND_INTERVAL=3000
|
||||
#SQL_FLAP_SUP_MIN_TIME=1000
|
||||
#SQL_FLAP_SUP_MAX_COUNT=10
|
||||
ACTIVATE_MODULE_ON_LONG_CMD=4:EchoLink
|
||||
#IDENT_NAG_TIMEOUT=15
|
||||
#IDENT_NAG_MIN_TIME=2000
|
||||
#ONLINE_CMD=998877
|
||||
DTMF_CTRL_PTY=/tmp/RepeaterLogic
|
||||
|
||||
[Rx1]
|
||||
TYPE=Local
|
||||
AUDIO_DEV=alsa:plughw:0
|
||||
AUDIO_CHANNEL=0
|
||||
SQL_DET=VOX
|
||||
SQL_START_DELAY=40
|
||||
SQL_DELAY=40
|
||||
SQL_HANGTIME=1400
|
||||
#SQL_EXTENDED_HANGTIME=1000
|
||||
#SQL_EXTENDED_HANGTIME_THRESH=15
|
||||
#SQL_TIMEOUT=600
|
||||
VOX_FILTER_DEPTH=20
|
||||
VOX_THRESH=1000
|
||||
#CTCSS_MODE=2
|
||||
#CTCSS_FQ=136.5
|
||||
#CTCSS_SNR_OFFSET=0
|
||||
#CTCSS_OPEN_THRESH=15
|
||||
#CTCSS_CLOSE_THRESH=9
|
||||
#CTCSS_BPF_LOW=60
|
||||
#CTCSS_BPF_HIGH=270
|
||||
#SERIAL_PORT=/dev/ttyUSB1
|
||||
SERIAL_PORT=/dev/ttyUSB_3
|
||||
SERIAL_PIN=CTS
|
||||
#SERIAL_SET_PINS=DTR!RTS
|
||||
#EVDEV_DEVNAME=/dev/input/by-id/usb-SYNIC_SYNIC_Wireless_Audio-event-if03
|
||||
#EVDEV_OPEN=1,163,1
|
||||
#EVDEV_CLOSE=1,163,0
|
||||
#GPIO_SQL_PIN=gpio30
|
||||
#PTY_PATH=/tmp/rx1_sql
|
||||
#HID_DEVICE=/dev/hidraw3
|
||||
#HID_SQL_PIN=VOL_UP
|
||||
#SIGLEV_DET=TONE
|
||||
SIGLEV_SLOPE=1
|
||||
SIGLEV_OFFSET=0
|
||||
#SIGLEV_BOGUS_THRESH=120
|
||||
#TONE_SIGLEV_MAP=100,84,60,50,37,32,28,23,19,8
|
||||
SIGLEV_OPEN_THRESH=30
|
||||
SIGLEV_CLOSE_THRESH=10
|
||||
DEEMPHASIS=1
|
||||
#SQL_TAIL_ELIM=0
|
||||
#PREAMP=6
|
||||
#PEAK_METER=1
|
||||
DTMF_DEC_TYPE=INTERNAL
|
||||
DTMF_MUTING=1
|
||||
DTMF_HANGTIME=100
|
||||
DTMF_SERIAL=/dev/ttyS0
|
||||
#DTMF_PTY=/tmp/rx1_dtmf
|
||||
DTMF_MAX_FWD_TWIST=18
|
||||
DTMF_MAX_REV_TWIST=12
|
||||
1750_MUTING=1
|
||||
SEL5_DEC_TYPE=INTERNAL
|
||||
SEL5_TYPE=ZVEI1
|
||||
#FQ=433475000
|
||||
#WBRX=WbRx1
|
||||
|
||||
[Tx1]
|
||||
TYPE=Local
|
||||
AUDIO_DEV=alsa:plughw:0
|
||||
AUDIO_CHANNEL=0
|
||||
PTT_TYPE=NONE
|
||||
PTT_PORT=/dev/ttyUSB_3
|
||||
PTT_PIN=DTRRTS
|
||||
#HID_DEVICE=/dev/hidraw3
|
||||
#HID_PTT_PIN=GPIO3
|
||||
#SERIAL_SET_PINS=DTR!RTS
|
||||
#PTT_HANGTIME=1000
|
||||
TIMEOUT=3600
|
||||
TX_DELAY=0
|
||||
#CTCSS_FQ=136.5
|
||||
#CTCSS_LEVEL=9
|
||||
PREEMPHASIS=0
|
||||
DTMF_TONE_LENGTH=100
|
||||
DTMF_TONE_SPACING=50
|
||||
DTMF_DIGIT_PWR=-15
|
||||
#MASTER_GAIN=0.0
|
||||
|
|
@ -18,43 +18,17 @@
|
|||
# EchoLink, Help, Parrot etc. If a sound is not found in the specified context,
|
||||
# a search in the "Default" context is done.
|
||||
#
|
||||
# It's also possible to have local overrides by putting files under a "local"
|
||||
# directory either directly under the "sounds" directory or under the language
|
||||
# pack directory. For example if context is "Core" and the language is set to
|
||||
# "en_US" the following paths will be searched:
|
||||
#
|
||||
# .../sounds/en_US/local/Core/
|
||||
# .../sounds/local/Core/
|
||||
# .../sounds/en_US/Core/
|
||||
# .../sounds/en_US/local/Default/
|
||||
# .../sounds/local/Default/
|
||||
# .../sounds/en_US/Default/
|
||||
#
|
||||
# context - The context to look for the sound files in (e.g Default,
|
||||
# Parrot etc).
|
||||
# msg - The basename of the file to play
|
||||
# warn - Set to 0 to not print a warning if no sound clip was found
|
||||
#
|
||||
proc playMsg {context msg {warn 1}} {
|
||||
proc playMsg {context msg} {
|
||||
global basedir
|
||||
global langdir
|
||||
|
||||
set candidates [glob -nocomplain \
|
||||
"$langdir/local/$context/$msg.{wav,raw,gsm}" \
|
||||
"$basedir/sounds/local/$context/$msg.{wav,raw,gsm}" \
|
||||
"$langdir/$context/$msg.{wav,raw,gsm}" \
|
||||
"$langdir/local/Default/$msg.{wav,raw,gsm}" \
|
||||
"$basedir/sounds/local/Default/$msg.{wav,raw,gsm}" \
|
||||
"$langdir/Default/$msg.{wav,raw,gsm}"];
|
||||
if {[llength $candidates] > 0} {
|
||||
set candidates [glob -nocomplain "$langdir/$context/$msg.{wav,raw,gsm}" \
|
||||
"$langdir/Default/$msg.{wav,raw,gsm}"];
|
||||
if { [llength $candidates] > 0 } {
|
||||
playFile [lindex $candidates 0];
|
||||
} else {
|
||||
if {$warn} {
|
||||
puts "*** WARNING: Could not find audio clip \"$msg\" in context \"$context\"";
|
||||
}
|
||||
return 0
|
||||
puts "*** WARNING: Could not find audio clip \"$msg\" in context \"$context\"";
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
[GLOBAL]
|
||||
#MODULE_PATH=@SVX_MODULE_INSTALL_DIR@
|
||||
LOGIC_CORE_PATH=@SVX_LOGIC_CORE_INSTALL_DIR@
|
||||
LOGICS=SimplexLogic
|
||||
CFG_DIR=svxlink.d
|
||||
TIMESTAMP_FORMAT="%c"
|
||||
|
|
@ -282,7 +281,7 @@ PTT_PIN=DTRRTS
|
|||
#PTT_GPIOD_CHIP=gpiochip0
|
||||
#PTT_GPIOD_LINE=17
|
||||
#PTT_HANGTIME=1000
|
||||
#TIMEOUT=300
|
||||
TIMEOUT=300
|
||||
TX_DELAY=500
|
||||
#CTCSS_FQ=136.5
|
||||
#CTCSS_LEVEL=9
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2022 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
|
||||
|
|
@ -81,7 +81,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
||||
#include "version/SVXLINK.h"
|
||||
#include "MsgHandler.h"
|
||||
#include "Logic.h"
|
||||
#include "DummyLogic.h"
|
||||
#include "SimplexLogic.h"
|
||||
#include "RepeaterLogic.h"
|
||||
#include "ReflectorLogic.h"
|
||||
#include "LinkManager.h"
|
||||
|
||||
|
||||
|
|
@ -432,7 +435,7 @@ int main(int argc, char **argv)
|
|||
cfg.getValue("GLOBAL", "TIMESTAMP_FORMAT", tstamp_format);
|
||||
|
||||
cout << PROGRAM_NAME " v" SVXLINK_VERSION
|
||||
" Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX\n\n";
|
||||
" Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX\n\n";
|
||||
cout << PROGRAM_NAME " comes with ABSOLUTELY NO WARRANTY. "
|
||||
"This is free software, and you are\n";
|
||||
cout << "welcome to redistribute it in accordance with the terms "
|
||||
|
|
@ -547,7 +550,7 @@ int main(int argc, char **argv)
|
|||
vector<LogicBase*>::iterator lit;
|
||||
for (lit=logic_vec.begin(); lit!=logic_vec.end(); lit++)
|
||||
{
|
||||
Async::Plugin::unload(*lit);
|
||||
delete *lit;
|
||||
}
|
||||
logic_vec.clear();
|
||||
|
||||
|
|
@ -714,9 +717,6 @@ static void initialize_logics(Config &cfg)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
std::string logic_core_path(SVX_LOGIC_CORE_INSTALL_DIR);
|
||||
cfg.getValue("GLOBAL", "LOGIC_CORE_PATH", logic_core_path);
|
||||
|
||||
string::iterator comma;
|
||||
string::iterator begin = logics.begin();
|
||||
do
|
||||
|
|
@ -742,29 +742,37 @@ static void initialize_logics(Config &cfg)
|
|||
<< logic_name << "\". Skipping...\n";
|
||||
continue;
|
||||
}
|
||||
std::string logic_plugin_filename =
|
||||
logic_core_path.empty()
|
||||
? logic_type + "Logic.so"
|
||||
: logic_core_path + "/" + logic_type + "Logic.so";
|
||||
//std::cout << "### logic_plugin_filename=" << logic_plugin_filename
|
||||
// << std::endl;
|
||||
LogicBase *logic = Async::Plugin::load<LogicBase>(logic_plugin_filename);
|
||||
if (logic != nullptr)
|
||||
LogicBase *logic = 0;
|
||||
if (logic_type == "Simplex")
|
||||
{
|
||||
std::cout << "\tFound plugin: " << logic->pluginPath() << std::endl;
|
||||
if (!logic->initialize(cfg, logic_name))
|
||||
{
|
||||
Async::Plugin::unload(logic);
|
||||
logic = nullptr;
|
||||
}
|
||||
logic = new SimplexLogic(cfg, logic_name);
|
||||
}
|
||||
if (logic == nullptr)
|
||||
else if (logic_type == "Repeater")
|
||||
{
|
||||
cerr << "*** ERROR: Could not load or initialize Logic object \""
|
||||
<< logic_name << "\". Skipping...\n";
|
||||
logic = new RepeaterLogic(cfg, logic_name);
|
||||
}
|
||||
else if (logic_type == "Reflector")
|
||||
{
|
||||
logic = new ReflectorLogic(cfg, logic_name);
|
||||
}
|
||||
else if (logic_type == "Dummy")
|
||||
{
|
||||
logic = new DummyLogic(cfg, logic_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "*** ERROR: Unknown logic type \"" << logic_type
|
||||
<< "\" specified for logic " << logic_name << ".\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((logic == 0) || !logic->initialize())
|
||||
{
|
||||
cerr << "*** ERROR: Could not initialize Logic object \""
|
||||
<< logic_name << "\". Skipping...\n";
|
||||
delete logic;
|
||||
continue;
|
||||
}
|
||||
|
||||
logic_vec.push_back(logic);
|
||||
} while (comma != logics.end());
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ class PeakMeter : public AudioPassthrough
|
|||
if (i < ret)
|
||||
{
|
||||
cout << name
|
||||
<< ": Distortion detected! Please lower the input volume!\n";
|
||||
<< ": Distorsion detected! Please lower the input volume!\n";
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -529,6 +529,15 @@ bool LocalRxBase::initialize(void)
|
|||
prev_src->registerSink(voiceband_filter, true);
|
||||
prev_src = voiceband_filter;
|
||||
|
||||
string filterdesc;
|
||||
if (cfg().getValue(name(), "AUDIO_FILTER", filterdesc))
|
||||
{
|
||||
cout << "+++ Init Audiofilter=" << filterdesc << endl;
|
||||
AudioFilter *additional_audiofilter = new AudioFilter(filterdesc);
|
||||
prev_src->registerSink(additional_audiofilter, true);
|
||||
prev_src = additional_audiofilter;
|
||||
}
|
||||
|
||||
// Create an audio splitter to distribute the voiceband audio to all
|
||||
// other consumers
|
||||
AudioSplitter *voiceband_splitter = new AudioSplitter;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ This file contains a class that implements a local transmitter.
|
|||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2019 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
|
||||
|
|
@ -472,7 +472,27 @@ bool LocalTx::initialize(void)
|
|||
prev_src->registerSink(preemph, true);
|
||||
prev_src = preemph;
|
||||
}
|
||||
|
||||
|
||||
string filterdesc;
|
||||
if (cfg.getValue(name(), "AUDIO_FILTER", filterdesc))
|
||||
{
|
||||
cout << "+++ Init Audiofilter=" << filterdesc << endl;
|
||||
AudioFilter *additional_audiofilter = new AudioFilter(filterdesc);
|
||||
prev_src->registerSink(additional_audiofilter, true);
|
||||
prev_src = additional_audiofilter;
|
||||
}
|
||||
|
||||
/*
|
||||
AudioCompressor *limit = new AudioCompressor;
|
||||
limit->setThreshold(-1);
|
||||
limit->setRatio(0.1);
|
||||
limit->setAttack(2);
|
||||
limit->setDecay(20);
|
||||
limit->setOutputGain(1);
|
||||
prev_src->registerSink(limit, true);
|
||||
prev_src = limit;
|
||||
*/
|
||||
|
||||
// Add a limiter to smoothly limit the audio before hard clipping it
|
||||
double limiter_thresh = DEFAULT_LIMITER_THRESH;
|
||||
cfg.getValue(name(), "LIMITER_THRESH", limiter_thresh);
|
||||
|
|
@ -718,14 +738,6 @@ bool LocalTx::initialize(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (!audio_io->open(AudioIO::MODE_WR))
|
||||
{
|
||||
cerr << "*** ERROR: Could not open audio device for transmitter \""
|
||||
<< name() << "\"\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
audio_io->close();
|
||||
return true;
|
||||
|
||||
} /* LocalTx::initialize */
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
\verbatim
|
||||
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
|
||||
Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2008 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
|
||||
|
|
@ -196,14 +196,6 @@ void NetTrxTcpClient::sendMsg(Msg *msg)
|
|||
} /* NetTrxTcpClient::sendMsg */
|
||||
|
||||
|
||||
void NetTrxTcpClient::connect(void)
|
||||
{
|
||||
if (isIdle())
|
||||
{
|
||||
TcpClient<>::connect();
|
||||
}
|
||||
} /* NetTrxTcpClient::connect */
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
|
|
|
|||
|
|
@ -157,17 +157,7 @@ class NetTrxTcpClient : public Async::TcpClient<>
|
|||
* @brief Get the reason for the last disconnect
|
||||
*/
|
||||
DiscReason disconnectReason(void) const { return disc_reason; }
|
||||
|
||||
/**
|
||||
* @brief Connect to the remote host
|
||||
*
|
||||
* This function will initiate a connection to the remote host. The
|
||||
* connection must not be written to before the connected signal
|
||||
* (see @ref TcpClient::connected) has been emitted. If the connection is
|
||||
* already established or pending, nothing will happen.
|
||||
*/
|
||||
void connect(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief A signal that is emitted when the connection to the remote side
|
||||
* is ready for operation
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ void RtlSdr::handleIq(const complex<uint8_t> *samples, int samp_count)
|
|||
{
|
||||
if (dist_print_cnt == static_cast<int>(samp_rate))
|
||||
{
|
||||
cout << "*** WARNING: Distortion detected on Rtl tuner "
|
||||
cout << "*** WARNING: Distorsion detected on Rtl tuner "
|
||||
<< displayName() << ". Lower the RF gain\n";
|
||||
}
|
||||
dist_print_cnt -= samp_count;
|
||||
|
|
@ -423,7 +423,7 @@ int RtlSdr::dataReceived(Async::TcpConnection *con, void *buf, int count)
|
|||
{
|
||||
if (dist_print_cnt == static_cast<int>(samp_rate))
|
||||
{
|
||||
cout << "*** WARNING: Distortion detected on RtlSdr tuner "
|
||||
cout << "*** WARNING: Distorsion detected on RtlSdr tuner "
|
||||
<< con->remoteHost() << ":" << con->remotePort() << ". "
|
||||
<< "Lower the RF gain\n";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ class RtlSdr : public sigc::trackable
|
|||
virtual ~RtlSdr(void);
|
||||
|
||||
/**
|
||||
* @brief Enable printing of distortion warnings
|
||||
* @brief Enable printing of distorsion warnings
|
||||
* @param enable Set to \em true to enable printing
|
||||
*/
|
||||
void enableDistPrint(bool enable);
|
||||
|
|
|
|||
|
|
@ -71,7 +71,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
****************************************************************************/
|
||||
|
||||
using namespace std;
|
||||
using namespace std::placeholders;
|
||||
|
||||
|
||||
|
||||
|
|
@ -388,7 +387,7 @@ void WbRxRtlSdr::rtlReadyStateChanged(void)
|
|||
vector<float> tuner_gains;
|
||||
tuner_gains.assign(int_tuner_gains.begin(), int_tuner_gains.end());
|
||||
transform(tuner_gains.begin(), tuner_gains.end(),
|
||||
tuner_gains.begin(), std::bind(divides<float>(), _1, 10.0));
|
||||
tuner_gains.begin(), bind2nd(divides<float>(),10.0));
|
||||
cout << "\tValid tuner gains : ";
|
||||
copy(tuner_gains.begin(), tuner_gains.end(),
|
||||
ostream_iterator<float>(cout, " "));
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
@file MyNamespaceTemplate.cpp
|
||||
@brief A_brief_description_for_this_file
|
||||
@author Tobias Blomberg / SM0SVX
|
||||
@date 2023-
|
||||
@date 2022-
|
||||
|
||||
A_detailed_description_for_this_file
|
||||
|
||||
\verbatim
|
||||
<A brief description of the program or library this file belongs to>
|
||||
Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2022 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
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
@file MyNamespaceTemplate.h
|
||||
@brief A_brief_description_for_this_file
|
||||
@author Tobias Blomberg / SM0SVX
|
||||
@date 2023-
|
||||
@date 2022-
|
||||
|
||||
A_detailed_description_for_this_file
|
||||
|
||||
\verbatim
|
||||
<A brief description of the program or library this file belongs to>
|
||||
Copyright (C) 2003-2023 Tobias Blomberg / SM0SVX
|
||||
Copyright (C) 2003-2022 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
|
||||
|
|
@ -109,7 +109,7 @@ namespace MyNamespace
|
|||
/**
|
||||
@brief A_brief_class_description
|
||||
@author Tobias Blomberg / SM0SVX
|
||||
@date 2023-
|
||||
@date 2022-
|
||||
|
||||
A_detailed_class_description
|
||||
|
||||
|
|
|
|||
16
src/versions
16
src/versions
|
|
@ -5,16 +5,16 @@ PROJECT=master
|
|||
QTEL=1.2.4.99.5
|
||||
|
||||
# Version for the EchoLib library
|
||||
LIBECHOLIB=1.3.3.99.2
|
||||
LIBECHOLIB=1.3.3.99.1
|
||||
|
||||
# Version for the Async library
|
||||
LIBASYNC=1.6.99.25
|
||||
LIBASYNC=1.6.99.19
|
||||
|
||||
# SvxLink versions
|
||||
SVXLINK=1.7.99.75
|
||||
SVXLINK=1.7.99.64
|
||||
MODULE_HELP=1.0.0
|
||||
MODULE_PARROT=1.1.1
|
||||
MODULE_ECHO_LINK=1.5.99.3
|
||||
MODULE_ECHO_LINK=1.5.99.2
|
||||
MODULE_TCL=1.0.1
|
||||
MODULE_PROPAGATION_MONITOR=1.0.1
|
||||
MODULE_TCL_VOICE_MAIL=1.0.2
|
||||
|
|
@ -25,16 +25,16 @@ MODULE_FRN=1.1.0
|
|||
MODULE_TRX=1.0.0
|
||||
|
||||
# Version for the RemoteTrx application
|
||||
REMOTE_TRX=1.3.99.12
|
||||
REMOTE_TRX=1.3.99.8
|
||||
|
||||
# Version for the signal level calibration utility
|
||||
SIGLEV_DET_CAL=1.0.7.99.8
|
||||
SIGLEV_DET_CAL=1.0.7.99.5
|
||||
|
||||
# Version for the deviation calibration utility
|
||||
DEVCAL=1.0.2.99.9
|
||||
DEVCAL=1.0.2.99.6
|
||||
|
||||
# Version for svxserver
|
||||
SVXSERVER=0.0.6
|
||||
|
||||
# Version for SvxReflector
|
||||
SVXREFLECTOR=1.99.16
|
||||
SVXREFLECTOR=1.99.14
|
||||
|
|
|
|||
Loading…
Reference in New Issue