Compare commits

..

8 Commits

85 changed files with 738 additions and 5909 deletions

54
README.adoc Normal file
View File

@ -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
View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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));

View File

@ -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&);

View File

@ -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();

View File

@ -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:

View File

@ -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 */

View File

@ -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:

View File

@ -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
*/

View File

@ -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
*/

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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
*/

View File

@ -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}

View File

@ -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

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;
}
};

View File

@ -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})

View File

@ -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; }
}

View File

@ -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;
}
};

View File

@ -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 */

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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
----------------------

View File

@ -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
{

View File

@ -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.

View File

@ -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, " "));

View File

@ -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();

View File

@ -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;

View File

@ -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)
{

View File

@ -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,

View File

@ -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 */

View File

@ -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 "

View File

@ -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 "

View File

@ -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 "

View File

@ -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)

View File

@ -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
*/

View File

@ -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 */

View File

@ -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
*/

View File

@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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")

View File

@ -1 +0,0 @@
README.html

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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
#

View File

@ -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)

View File

@ -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

View File

@ -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
*/

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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());

View File

@ -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;

View File

@ -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 */

View File

@ -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 */
/****************************************************************************
*

View File

@ -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

View File

@ -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";
}

View File

@ -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);

View File

@ -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, " "));

View File

@ -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

View File

@ -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

View File

@ -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