Compare commits

...

54 Commits

Author SHA1 Message Date
Adi Bier / DL1HRC 5f75990cb0 Bugfix in jsonToString method. 2023-01-24 22:52:30 +01:00
Adi Bier / DL1HRC 8b549d6024 Merged 2023-01-20 15:21:10 +01:00
Adi Bier / DL1HRC e56a8f116a Documentation changed to README.adoc 2022-11-06 11:08:21 +01:00
Adi/DL1HRC 443976ea81 Added debug output for USRP_RX_PORT, USRP_TX_PORT and USRP_HOST. Hint from Waldek/SP2ONG 2022-10-24 11:55:26 +02:00
Adi Bier/DL1HRC 03b2931719 Readme updated 2022-10-20 10:18:35 +02:00
Adi/DL1HRC d78d881bfa Small typo, tnx to Waldek/SP2ONG 2022-10-19 12:04:56 +02:00
Adi/DL1HRC cafb011c83 Moved usrp files to the new contrib structure 2022-10-18 15:27:52 +02:00
Adi/DL1HRC 5689486629 Adapted usrp to the new logic structure to make implementations easier. 2022-10-18 11:08:20 +02:00
Adi Bier ffa09e46a4
Merge pull request #3 from dl1bz/svxlink-usrp
filter improvement by DL1BZ (mni tnx)
2022-10-07 13:31:29 +02:00
dl1bz 255a05a240 filter improvement 2022-10-07 13:07:53 +02:00
Adi Bier / DL1HRC da2731a81d Parameters of the audio filters changed to improve the quality of DV-audio. Tnx to Heiko/DL1BZ for investigations. 2022-09-30 09:14:16 +02:00
Adi Bier 148c2f9a4c
Merge branch 'sm0svx:master' into svxlink-usrp 2022-08-20 15:47:55 +02:00
Adi Bier abb72ab14f
Merge branch 'sm0svx:master' into svxlink-usrp 2022-08-04 10:04:00 +02:00
Adi Bier 04b43dce3c
Merge branch 'sm0svx:master' into svxlink-usrp 2022-05-22 17:07:36 +02:00
Adi Bier / DL1HRC 202525860a Merged with master 2022-04-15 18:07:47 +02:00
Adi Bier a4f59aacaa
Merge branch 'sm0svx:master' into svxlink-usrp 2022-04-04 07:25:01 +02:00
Adi Bier / DL1HRC 98bd2ef35a Removed unnecessary spaces 2022-04-02 08:31:26 +02:00
Adi Bier / DL1HRC 609896587a MErged 2022-04-02 08:11:45 +02:00
Adi Bier / DL1HRC eda0dd6dae Merge branch 'svxlink-usrp' of https://github.com/dl1hrc/svxlink into svxlink-usrp 2022-04-02 08:09:33 +02:00
Adi Bier / DL1HRC a3d92d68fb Added AudioClipper and AudioCompressor 2022-04-02 08:09:29 +02:00
Adi Bier / DL1HRC 083bb87e4b Merged with upstream/master 2022-03-18 19:43:30 +01:00
Adi Bier / DL1HRC 02d609e590 Merge remote-tracking branch 'sm0svx/master' into svxlink-usrp 2022-01-28 19:39:08 +01:00
Adi Bier / DL1HRC 46140a033a Fixed and merged 2022-01-23 20:03:29 +01:00
Adi Bier / DL1HRC ca06c9b554 Merged with upstream 2022-01-10 14:51:12 +01:00
Adi Bier / DL1HRC 4ba0fce47f Merge remote-tracking branch 'sm0svx/master' into svxlink-usrp 2022-01-10 14:45:35 +01:00
Adi Bier / DL1HRC 93a7a154a2 Added missing config-params EVENT_HANDLER and JITTER_BUFFER_DELAY in svxlink.conf template 2022-01-05 09:10:07 +01:00
Adi Bier / DL1HRC 97702098d7 Update Usrp protocol documentation. Tnx to Waldek/SP2ONG 2022-01-04 17:45:10 +01:00
Adi Bier / DL1HRC 4f494974bd Bugfix: wrong path in svxlink.conf.in 2021-12-18 11:07:05 +01:00
Adi Bier / DL1HRC b50982b56f More data exchange between SvxLink node and SvxRflector, like Tetra extension 2021-12-08 19:36:34 +01:00
Adi Bier / DL1HRC 40d1e412a1 Documentation updated, added info regarding required libraries 2021-11-16 20:28:33 +01:00
Adi Bier / DL1HRC 2b1d538e21 Fixed another small error in doc (INSTALL.adoc), mni tnx to Waldek/SP2ONG 2021-10-16 18:51:49 +02:00
Adi Bier / DL1HRC b151754e71 Wrong git link in INSTALL.adoc, tnx to Waldek/SP2ONG 2021-10-14 13:01:36 +02:00
Adi Bier / DL1HRC c8f3808ce9 Documentation added, take a look into CONFIG.adoc for a short information how it fits together. 2021-08-24 23:00:13 +02:00
Adi Bier / DL1HRC 9470642e6a merged with master 2021-08-16 16:33:48 +02:00
Adi Bier / DL1HRC 2191a9cd04 Fixed: Handling of (Tlv) meta data, mni tnx to Waldek/SP2ONG for support. 2021-07-14 14:42:33 +02:00
Adi Bier / DL1HRC 98e8b6206d Changed handling of meta data. Changed USRP_HOST default entry. 2021-05-31 13:00:05 +02:00
Adi Bier / DL1HRC 9714a208e9 Intermediate commit for the evaluation of the metadata. Documentation renewed. Tcl methods expanded. 2021-05-12 20:36:16 +02:00
Adi Bier / DL1HRC ea067b6da5 Doc changed, changed TG that is given out 2021-05-10 21:02:47 +02:00
Adi Bier / DL1HRC 660e320ea0 Small change in UsrpLogic.tcl, usrp protocol description added 2021-05-10 11:32:43 +02:00
Adi Bier / DL1HRC c54e349949 Bugfix: Dmrid was not issued, if 0 then the output is suppressed now 2021-05-08 09:12:10 +02:00
Adi Bier / DL1HRC 503818acb5 Added filters for incoming/outgoing audio 2021-05-07 12:11:58 +02:00
Adi Bier / DL1HRC 58d450e367 Merge remote-tracking branch 'sm0svx/master' into svxlink-usrp 2021-05-06 20:54:26 +02:00
Adi Bier / DL1HRC 1b06a7c5a4 Removed unused variables 2021-05-06 20:53:10 +02:00
Adi Bier / DL1HRC c13884713d Removed some default parameter that not used yet 2021-05-06 15:26:46 +02:00
Adi Bier / DL1HRC 5d5a6faa66 Tcl-event support added, rebuilt UsrpLogic.tcl, Usrp documentation from Waldek/SP2ONG added, removed unused methods 2021-05-06 12:40:29 +02:00
Adi Bier / DL1HRC d493e2d5b4 Documentation added. Setting option for outgoing/incoming audio. Unused variabledeclarations removed. 2021-05-06 07:57:48 +02:00
Adi Bier / DL1HRC 21b25fa9e7 Some adjustments regarding host / network byte order, tnx to Waldek / SP2ONG for hints 2021-05-05 13:35:49 +02:00
Adi Bier / DL1HRC d09f71b3cf Fixed: Metamessage buf. Handling incoming stream to create (audio-,meta,-)messages.. Add some checks for pack/unpack in AsyncMsg.h 2021-05-04 23:13:30 +02:00
Adi Bier / DL1HRC bb72918ba5 Added Decimator/Interpolator, changed byteorder for network transmission. Remaining Bug: unpack USRP_TYPE_TEXT message 2021-05-04 20:52:46 +02:00
Adi Bier / DL1HRC bf25eed183 Added meta Usrp-message (USRP_TYPE_TEXT) 2021-05-03 20:20:08 +02:00
Adi Bier / DL1HRC 033e0c2296 Added new class for USRP stopmessage, Bugfix with audiostream data (buf/char - int16_t/sizeof Etc) 2021-05-02 14:56:02 +02:00
Adi Bier / DL1HRC a697dc3c1a Added std::array to message packing framework (in AsyncMsg.h) with much help from porst17, mni tnx 2021-04-30 13:06:19 +02:00
Adi Bier / DL1HRC 55b3adeff4 Reasonably running version with errors, currently not usable in a meaningful way 2021-04-29 19:23:39 +02:00
Adi Bier / DL1HRC 127208e547 1st version 2021-04-22 11:08:55 +02:00
24 changed files with 6245 additions and 16 deletions

211
CONFIG.adoc Normal file
View File

@ -0,0 +1,211 @@
Configuration svxlink-usrp with SvxReflector, Analoge_Bridge and MMDVM_Bridge
=============================================================================
1.) Basic structure
|.-................. SvxLink ......................| |........... MMDVM stuff ..........| |.. freeDMR ..>
|----------| |---------------| |--------------| |-----------| |---------------| |--------------| |-------------|
| Radio | | SimplexLogic | | LogicLinking | | UsrpLogic | | Analog_Bridge | | MMDVM_Bridge | | DMR-Network |
| 2m/70cm |<->| RepeaterLogic |<->| |<->| |<->| |<->| |<->| |
|----------| |---------------| |--------------| |-----------| |---------------| |--------------| |-------------|
| |
| |
|----------| |---------------| |--------------| |---------------|
| Analogue | | SvxReflector- | | Reflector- | | md380- |
| Network |<->| Server |<->| Logic | | emulator |
|----------| |---------------| |--------------| |---------------|
2.) Configuration
2.1.) svxLink.conf
Usually located in /etc/svxlink/svxlink.conf
Below is an example configuration for the svxlink.conf file. Only the most important parameters and
configuration sections are given
---
[GLOBAL]
LOGICS=RepeaterLogic,ReflectorLogic,UsrpLogic
LINKS=UsrpLink
[RepeaterLogic]
TYPE=Repeater
RX=Rx1
TX=Tx1
MODULES=ModuleParrot,ModuleTclVoiceMail,ModulePropagationMonitor,ModuleMetarInfo
CALLSIGN=DB0ABC
SHORT_IDENT_INTERVAL=30
LONG_IDENT_INTERVAL=60
EVENT_HANDLER=/usr/share/svxlink/events.tcl
DEFAULT_LANG=de_DE
RGR_SOUND_DELAY=200
TX_CTCSS=SQL_OPEN,ANNOUNCEMENT
FX_GAIN_NORMAL=0
FX_GAIN_LOW=-12
#NO_REPEAT=1
IDLE_TIMEOUT=6
OPEN_ON_DTMF=*
OPEN_ON_SQL=1000
OPEN_SQL_FLANK=OPEN
[UsrpLogic]
TYPE=Usrp
USRP_HOST=127.0.0.1
USRP_TX_PORT=44442 <-------------------------------------------------
USRP_RX_PORT=44441 <---------------------------------------------- |
CALL=DB0ABC | |
DMRID=262123 | |
RPTID= | |
DEFAULT_CC=1 | |
DEFAULT_TG=2629 | |
DEFAULT_TS=2 | |
#PREAMP=3 | |
#FILTER_FROM_USRP=HsBq2/0.01/-18/4000 | |
FILTER_TO_USRP=BpBu1/650-3800 | |
#NET_PREAMP=3 | |
JITTER_BUFFER_DELAY=100 | |
EVENT_HANDLER=/usr/share/svxlink/events.tcl | |
| |
[ReflectorLogic] | |
TYPE=Reflector | |
HOST=10.8.0.1 ---------> to Analogue network, usually a | |
PORT=5302 --------------> SvxReflector server | |
AUTH_KEY="secret" | |
CALLSIGN="DB0ABC | |
#JITTER_BUFFER_DELAY=0 | |
DEFAULT_TG=9 | |
MONITOR_TGS=9 | |
ANNOUNCE_REMOTE_MIN_INTERVAL=300 | |
EVENT_HANDLER=/usr/share/svxlink/events.tcl | |
NODE_INFO_FILE=/etc/svxlink/node_info.json | |
MUTE_FIRST_TX_LOC=0 | |
MUTE_FIRST_TX_REM=0 | |
| |
[UsrpLink] | |
NAME=Usrp | |
CONNECT_LOGICS=RepeaterLogic,UsrpLogic,ReflectorLogic | |
DEFAULT_ACTIVE=1 | |
---EOF | |
| |
| |
2.2.) Analog_Bridge | |
Here we have an example for the Analog_Bridge.ini, | |
usually located in /opt/Analog_Bridge/Analog_Bridge.ini | |
For details regarding the configuration paramaters | |
refer to Analog_Bridge manual page. | |
| |
--- | |
include = dvsm.macro | |
| |
[GENERAL] | |
logLevel = 2 | |
exportMetadata = true | |
transferRootDir = /tmp | |
subscriberFile = /var/lib/dvswitch/subscriber_ids.csv | |
decoderFallBack = true | |
useEmulator = false | |
emulatorAddress = 127.0.0.1:2460 | |
pcmPort = 2222 | |
| |
[USRP] | |
address = 127.0.0.1 | |
txPort = 44441 <-------------------------------------------------- |
rxPort = 44442 <-----------------------------------------------------
usrpAudio = AUDIO_UNITY
usrpGain = 1.10
usrpAGC = -20,10,100
tlvAudio = AUDIO_UNITY
tlvGain = 0.35
[AMBE_AUDIO]
address = 127.0.0.1
txPort = 31103 <-----------------------------------------------------
rxPort = 31100 <-------------------------------------------------- |
ambeMode = DMR | |
minTxTimeMS = 2500 | |
gatewayDmrId = 262123 | |
repeaterID = 26200123 | |
txTg = 2629 | |
txTs = 2 | |
colorCode = 1 | |
| |
[MACROS] | |
| |
[DV3000] | |
;address = 127.0.0.1 -------------------> To | |
;rxPort = 2460 -------------------------> AMBEServer | |
| |
address = /dev/ttyUSB4 -----------------> To | |
baud = 460800 --------------------------> DV3k-stick | |
serial = true | |
---EOF | |
| |
| |
2.3.) MMDVM_Bridge | |
Usually located in /opt/MMDVM_Bridge/MMDVM_Bridge.ini | |
Here is an example for the MMDVM_Bridge.ini | |
Only the most important parameters and configuration | |
sections are given | |
| |
--- | |
[General] | |
Callsign=DB0ABC | |
Id=262123 | |
Timeout=180 | |
Duplex=1 | |
| |
[Info] | |
RXFrequency=431025000 | |
TXFrequency=438625000 | |
Power=15 | |
Latitude=51.000 | |
Longitude=12.000 | |
Height=123 | |
Location=somewhere | |
Description=FreeDMR_Germany | |
URL=https://svxreflector.org | |
| |
[Log] | |
DisplayLevel=1 | |
FileLevel=2 | |
FilePath=/var/log/mmdvm | |
FileRoot=MMDVM_Bridge | |
| |
[DMR Id Lookup] | |
File=/var/lib/mmdvm/DMRIds.dat | |
Time=24 | |
| |
[DMR] | |
Enable=1 | |
ColorCode=1 | |
EmbeddedLCOnly=1 | |
DumpTAData=0 | |
| |
[DMR Network] | |
Enable=1 | |
Address=svxreflector.org ---------------> To DMR master server | |
Port=62031 -----------------------------> e.g. freeDMR | |
Jitter=360 | |
Local=62032 | |
Password=passw0rd | |
Slot1=0 | |
Slot2=1 | |
Debug=1 | |
---EOF | |
| |
| |
2.4.) DV-Switch | |
Uually located in /opt/MMDVM_Bridge/DVSwitch.ini | |
Example of DVSwitch.ini | |
| |
--- | |
[DMR] | |
address = 127.0.0.1 | |
txPort = 31100 <-------------------------------------------------- |
rxPort = 31103 <-----------------------------------------------------
slot = 2
exportTG = 2629
hangTimerInFrames = 0
talkerAlias = %callsign %location %description
---EOF

View File

@ -26,9 +26,11 @@ or "-devel".
* *libgcrypt*: Cryptographic functions (Required)
* *libasound*: Alsa sound system support (Recommended)
* *libgsm*: GSM audio codec (Required)
* *libjsoncpp*: For json file support (Required)
* *libspeex*: The Speex audio codec (Optional)
* *librtlsdr*: Support for RTL2832U DVB-T/SDR USB dongles (Optional)
* *libqt*: Version 4. Framework for graphical applications (Optional)
* *libgpiod*: For gpio support at RaspberryPis (Optional)
There also are some runtime dependencies which normally is needed to run a
SvxLink system.
@ -46,11 +48,14 @@ A common command that exist on many distributions is 'useradd'. The 'daemon'
group usually exist but if not, look for the 'groupadd' command.
== Build and install ==
== Build and install SvxLink with Usrp extension ==
SvxLink use the CMake build system. The basic pattern for building using CMake
looks like this:
cd path/to/svxlink/src
git clone https://github.com/dl1hrc/svxlink.git
cd svxlink
git checkout svxlink-usrp
cd src
mkdir build
cd build
cmake ..

View File

@ -443,6 +443,72 @@ class MsgPacker<std::string>
}
};
// MsgPacker for std::array
template <typename T, size_t N>
class MsgPacker<std::array<T, N> >
{
public:
static bool pack(std::ostream &os, const std::array<T, N> &vec) {
for (typename std::array<T, N>::const_iterator it = vec.begin();
it != vec.end(); ++it) {
if (!MsgPacker<T>::pack(os, *it))
{
return false;
}
}
return true;
}
static size_t packedSize(const std::array<T, N> &vec) {
size_t size = 0;
for (typename std::array<T, N>::const_iterator it = vec.begin();
it != vec.end(); ++it) {
size += MsgPacker<T>::packedSize(*it);
}
return size;
}
static bool unpack(std::istream &is, std::array<T, N> &vec) {
for (size_t i = 0; i < N; ++i) {
if (!MsgPacker<T>::unpack(is, vec[i]))
{
return false;
}
}
return true;
}
};
// MsgPacker for static arrays
template <typename T, std::size_t N> class MsgPacker<T[N]> {
public:
static bool pack(std::ostream &os, const T (&vec)[N]) {
for (const T *it = std::begin(vec); it != std::end(vec); ++it) {
if (!MsgPacker<T>::pack(os, *it))
{
return false;
}
}
return true;
}
static size_t packedSize(const T (&vec)[N]) {
size_t size = 0;
for (const T *it = std::begin(vec); it != std::end(vec); ++it) {
size += MsgPacker<T>::packedSize(*it);
}
return size;
}
static bool unpack(std::istream &is, T (&vec)[N]) {
for (T *it = std::begin(vec); it != std::end(vec); ++it) {
if (!MsgPacker<T>::unpack(is, *it))
{
return false;
}
}
return true;
}
};
template <typename I>
class MsgPacker<std::vector<I> >
{
@ -459,7 +525,10 @@ class MsgPacker<std::vector<I> >
it != vec.end();
++it)
{
MsgPacker<I>::pack(os, *it);
if (!MsgPacker<I>::pack(os, *it))
{
return false;
}
}
return true;
}
@ -487,7 +556,10 @@ class MsgPacker<std::vector<I> >
for (int i=0; i<vec_size; ++i)
{
I val;
MsgPacker<I>::unpack(is, val);
if (!MsgPacker<I>::unpack(is, val))
{
return false;
}
vec.push_back(val);
}
return true;
@ -505,12 +577,18 @@ class MsgPacker<std::set<I> >
{
return false;
}
MsgPacker<uint16_t>::pack(os, s.size());
if (!MsgPacker<uint16_t>::pack(os, s.size()))
{
return false;
}
for (typename std::set<I>::const_iterator it = s.begin();
it != s.end();
++it)
{
MsgPacker<I>::pack(os, *it);
if (!MsgPacker<I>::pack(os, *it))
{
return false;
}
}
return true;
}
@ -527,7 +605,10 @@ class MsgPacker<std::set<I> >
static bool unpack(std::istream& is, std::set<I>& s)
{
uint16_t set_size;
MsgPacker<uint16_t>::unpack(is, set_size);
if (!MsgPacker<uint16_t>::unpack(is, set_size))
{
return false;
}
if (set_size > std::numeric_limits<uint16_t>::max())
{
return false;
@ -537,7 +618,10 @@ class MsgPacker<std::set<I> >
for (int i=0; i<set_size; ++i)
{
I val;
MsgPacker<I>::unpack(is, val);
if (!MsgPacker<I>::unpack(is, val))
{
return false;
}
s.insert(val);
}
return true;
@ -846,6 +930,111 @@ class Msg
unpack(is, v7) && unpack(is, v8) && unpack(is, v9) &&
unpack(is, v10);
}
// need by Usrp protocol (16 params)
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9, typename T10,
typename T11, typename T12, typename T13, typename T14, typename T15,
typename T16>
bool pack(std::ostream& os, const T1& v1, const T2& v2, const T3& v3,
const T4& v4, const T5& v5, const T6& v6, const T7& v7,
const T8& v8, const T9& v9, const T10& v10,
const T11& v11, const T12& v12, const T13& v13,
const T14& v14, const T15& v15, const T16& v16) const
{
return pack(os, v1) && pack(os, v2) && pack(os, v3) && pack(os, v4) &&
pack(os, v5) && pack(os, v6) && pack(os, v7) && pack(os, v8) &&
pack(os, v9) && pack(os, v10) && pack(os, v11) && pack(os, v12) &&
pack(os, v13) && pack(os, v14) && pack(os, v15) && pack(os, v16);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9, typename T10,
typename T11, typename T12, typename T13, typename T14, typename T15,
typename T16>
size_t packedSize(const T1& v1, const T2& v2, const T3& v3,
const T4& v4, const T5& v5, const T6& v6,
const T7& v7, const T8& v8, const T9& v9,
const T10& v10, const T11& v11, const T12& v12,
const T13& v13, const T14& v14, const T15& v15,
const T16& v16) const
{
return packedSize(v1) + packedSize(v2) + packedSize(v3) + packedSize(v4) +
packedSize(v5) + packedSize(v6) + packedSize(v7) + packedSize(v8) +
packedSize(v9) + packedSize(v10) + packedSize(v11) + packedSize(v12) +
packedSize(v13) + packedSize(v14) + packedSize(v15) + packedSize(v16);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9, typename T10,
typename T11, typename T12, typename T13, typename T14, typename T15,
typename T16>
bool unpack(std::istream& is, T1& v1, T2& v2, T3& v3, T4& v4, T5& v5,
T6& v6, T7& v7, T8& v8, T9& v9, T10& v10, T11& v11, T12& v12,
T13& v13, T14& v14, T15& v15, T16& v16)
{
return unpack(is, v1) && unpack(is, v2) && unpack(is, v3) &&
unpack(is, v4) && unpack(is, v5) && unpack(is, v6) &&
unpack(is, v7) && unpack(is, v8) && unpack(is, v9) &&
unpack(is, v10) && unpack(is, v11) && unpack(is, v12) &&
unpack(is, v13) && unpack(is, v14) && unpack(is, v15) &&
unpack(is, v16);
}
// need by Usrp protocol (17 params)
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9, typename T10,
typename T11, typename T12, typename T13, typename T14, typename T15,
typename T16, typename T17>
bool pack(std::ostream& os, const T1& v1, const T2& v2, const T3& v3,
const T4& v4, const T5& v5, const T6& v6, const T7& v7,
const T8& v8, const T9& v9, const T10& v10,
const T11& v11, const T12& v12, const T13& v13,
const T14& v14, const T15& v15, const T16& v16,
const T17& v17) const
{
return pack(os, v1) && pack(os, v2) && pack(os, v3) && pack(os, v4) &&
pack(os, v5) && pack(os, v6) && pack(os, v7) && pack(os, v8) &&
pack(os, v9) && pack(os, v10) && pack(os, v11) && pack(os, v12) &&
pack(os, v13) && pack(os, v14) && pack(os, v15) && pack(os, v16) &&
pack(os, v17);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9, typename T10,
typename T11, typename T12, typename T13, typename T14, typename T15,
typename T16, typename T17>
size_t packedSize(const T1& v1, const T2& v2, const T3& v3,
const T4& v4, const T5& v5, const T6& v6,
const T7& v7, const T8& v8, const T9& v9,
const T10& v10, const T11& v11, const T12& v12,
const T13& v13, const T14& v14, const T15& v15,
const T16& v16, const T17& v17) const
{
return packedSize(v1) + packedSize(v2) + packedSize(v3) + packedSize(v4) +
packedSize(v5) + packedSize(v6) + packedSize(v7) + packedSize(v8) +
packedSize(v9) + packedSize(v10) + packedSize(v11) + packedSize(v12) +
packedSize(v13) + packedSize(v14) + packedSize(v15) + packedSize(v16) +
packedSize(v17);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9, typename T10,
typename T11, typename T12, typename T13, typename T14, typename T15,
typename T16, typename T17>
bool unpack(std::istream& is, T1& v1, T2& v2, T3& v3, T4& v4, T5& v5,
T6& v6, T7& v7, T8& v8, T9& v9, T10& v10, T11& v11, T12& v12,
T13& v13, T14& v14, T15& v15, T16& v16, T17& v17)
{
return unpack(is, v1) && unpack(is, v2) && unpack(is, v3) &&
unpack(is, v4) && unpack(is, v5) && unpack(is, v6) &&
unpack(is, v7) && unpack(is, v8) && unpack(is, v9) &&
unpack(is, v10) && unpack(is, v11) && unpack(is, v12) &&
unpack(is, v13) && unpack(is, v14) && unpack(is, v15) &&
unpack(is, v16) && unpack(is, v17);
}
}; /* class Msg */

View File

@ -760,6 +760,66 @@ variables as documented for networked receivers and transmitters. For example,
to lighten the encoder CPU load for the Opus encoder, set OPUS_ENC_COMPLEXITY
to something lower than 9.
.
.SS UsrpLogic
.
The UsprLogic is used to connect SvxLink with a digital Hamradio network. The
communication is based on Udp transmission. Some Hamradio applications
are able to accept the protocol (Asterisk, MMDVM).
.TP
.B TYPE
The type for a Usrp Logic is always "Usrp"
.TP
.B CALL
Specify the callsign used at this logic.
.TP
.B USRP_HOST
The hostname of the Usrp server.
.TP
.B USRP_TX_PORT
The Udp port used to send Udp messages to Usrp server
.TP
.B USRP_RX_PORT
The Udp port used to receive Udp messages from the Usrp server.
.TP
.B DMRID
The DMR-ID ssigned to the callsign.
.TP
.B RPTID
The repeater ID. It's not used in most cases.
.TP
.B DEFAULT_TG
The talk group. Default is 0
.TP
.B DEFAULT_CC
The color code. It's not used in most cases, default is 1
.TP
.B DEFAULT_TS
The time slot. It's not used in most cases, default is 1
.TP
.B PREAMP
The signal (internal audio from connected logic) will be amplified/reduced
by the specified number of dB. This processed audio is sent to the usrp server.
.TP
.B NET_PREAMP
The signal received from Usrp network will be amplified/reduced by the
number of dB. This processed audio is sent to connected logics.
.TP
.B NET_LIMITER_THRESH
Set the threshold, in dBFS, for the audio limiter from the net site. 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 to not overmodulate
the local connected logics.A good value
to start with for this parameter is then -6 but try to lower it further (like
-9 to -12) if it does not affect audio quality negatively.
.TP
.B LOCAL_LIMITER_THRESH
Set the threshold, in dBFS, for the audio limiter from the local site to Usrp
network. 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 to
not overmodulate the remote connected usrp nodes. A good value
to start with for this parameter is then -6 but try to lower it further (like
-9 to -12) if it does not affect audio quality negatively.
.
.SS QSO Recorder Section
.
The QSO recorder is used to record all received audio to files on disk. All

View File

@ -32,6 +32,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <cassert>
#include <json/json.h>
#include <fstream>
#include <algorithm>
/****************************************************************************
@ -123,7 +125,8 @@ namespace {
Reflector::Reflector(void)
: m_srv(0), m_udp_sock(0), m_tg_for_v1_clients(1), m_random_qsy_lo(0),
m_random_qsy_hi(0), m_random_qsy_tg(0), m_http_server(0)
m_random_qsy_hi(0), m_random_qsy_tg(0), m_http_server(0),
cfg_filename("/tmp/userinfo.json"), debug(false)
{
TGHandler::instance()->talkerUpdated.connect(
mem_fun(*this, &Reflector::onTalkerUpdated));
@ -226,10 +229,87 @@ bool Reflector::initialize(Async::Config &cfg)
sigc::mem_fun(*this, &Reflector::httpClientDisconnected));
}
m_cfg->getValue("GLOBAL", "DEBUG", debug);
if (!m_cfg->getValue("GLOBAL", "USERFILE", cfg_filename))
{
cfg_filename = "/tmp/svxreflector_userdata-";
cfg_filename += to_string(udp_listen_port);
cfg_filename += ".json";
}
// reads the user data from json file
if (!getUserData())
{
cout << "*** Can not read user data from json file: " << cfg_filename << endl;
}
return true;
} /* Reflector::initialize */
void Reflector::updateUserdata(Json::Value user_arr)
{
User m_user;
for (Json::Value::ArrayIndex i = 0; i != user_arr.size(); i++)
{
Json::Value& t_userdata = user_arr[i];
m_user.id = t_userdata.get("id", "").asString();
m_user.name = t_userdata.get("name","").asString();
m_user.mode = t_userdata.get("mode","").asString();
m_user.call = t_userdata.get("call","").asString();
m_user.location = t_userdata.get("location","").asString();
m_user.aprs_sym = static_cast<char>(t_userdata.get("sym","").asInt());
m_user.aprs_tab = static_cast<char>(t_userdata.get("tab","").asInt());
m_user.comment = t_userdata.get("comment","").asString();
if (t_userdata.get("last_activity","").asUInt() > 0)
{
m_user.last_activity = (time_t) t_userdata.get("last_activity","").asUInt();
}
std::map<std::string, User>::iterator iu;
iu = userdata.find(m_user.id);
if (iu != userdata.end())
{
iu->second.name= m_user.name;
iu->second.mode= m_user.mode;
iu->second.aprs_sym = m_user.aprs_sym;
iu->second.aprs_tab = m_user.aprs_tab;
iu->second.comment = m_user.comment;
iu->second.location = m_user.location;
if (m_user.last_activity)
{
iu->second.last_activity = m_user.last_activity;
}
if (debug)
{
cout << "UPDATE: call=" << m_user.call << ", id=" << m_user.id
<< ", name=" << m_user.name << ", location=" << m_user.location
<< " (" << m_user.comment << ")" << endl;
}
}
else
{
userdata.insert(std::pair<std::string, User>(m_user.id, m_user));
if (debug)
{
cout << "New user: call=" << m_user.call << ", id=" << m_user.id
<< ", name=" << m_user.name << ", location=" << m_user.location
<< " (" << m_user.comment << ")" << endl;
}
}
}
writeUserData(userdata);
} /* Reflector::updateUserdata */
void Reflector::updateQsostate(Json::Value eventmessage)
{
cout << jsonToString(eventmessage) << endl;
} /* Reflector::updateQsostate */
void Reflector::nodeList(std::vector<std::string>& nodes) const
{
nodes.clear();
@ -783,6 +863,98 @@ uint32_t Reflector::nextRandomQsyTg(void)
} /* Reflector::nextRandomQsyTg */
bool Reflector::getUserData(void)
{
// loading user info
Json::Value cfg_root;
std::ifstream cfgfile(cfg_filename);
if (!cfgfile.is_open())
{
if (debug)
{
cout << "+++ WARNING: Can not open " << cfg_filename << endl;
}
return false;
}
cfgfile >> cfg_root;
cfgfile.close();
if (cfg_root.size() < 1)
{
if (debug)
{
cout << "+++ WARNING: File (" << cfg_filename << ") contains no userdata"
<< endl;
}
return false;
}
for (Json::Value::ArrayIndex i = 0; i != cfg_root.size(); i++)
{
User m_user;
Json::Value& t_userdata = cfg_root[i];
m_user.id = t_userdata.get("id", "").asString();
m_user.mode = t_userdata.get("mode","").asString();
m_user.name = t_userdata.get("name","").asString();
m_user.call = t_userdata.get("call","").asString();
m_user.location = t_userdata.get("location","").asString();
m_user.aprs_sym = static_cast<char>(t_userdata.get("sym","").asInt());
m_user.aprs_tab = static_cast<char>(t_userdata.get("tab","").asInt());
m_user.comment = t_userdata.get("comment","").asString();
m_user.last_activity = (time_t) t_userdata.get("last_activity","").asUInt();
userdata[m_user.id] = m_user;
}
cout << "+++ " << cfg_root.size() << " users loaded from '"
<< cfg_filename << "'" << endl;
return true;
} /* Reflector::getUserData */
void Reflector::writeUserData(std::map<std::string, User> userdata)
{
Json::Value event(Json::arrayValue);
std::map<std::string, User>::iterator iu;
for (iu = userdata.begin(); iu!=userdata.end(); iu++)
{
Json::Value t_userinfo(Json::objectValue);
t_userinfo["id"] = iu->second.id;
t_userinfo["call"] = iu->second.call;
t_userinfo["mode"] = iu->second.mode;
t_userinfo["name"] = iu->second.name;
t_userinfo["location"] = iu->second.location;
t_userinfo["sym"] = iu->second.aprs_sym;
t_userinfo["tab"] = iu->second.aprs_tab;
t_userinfo["comment"] = iu->second.comment;
t_userinfo["last_activity"] = static_cast<uint32_t>(iu->second.last_activity);
event.append(t_userinfo);
}
// sending own Dv user information to the svxreflector network
Json::StreamWriterBuilder builder;
builder["commentStyle"] = "None";
builder["indentation"] = ""; //The JSON document is written on a single line
Json::StreamWriter* writer = builder.newStreamWriter();
std::ofstream outputFileStream(cfg_filename);
std::stringstream os;
writer->write(event, &os);
writer->write(event, &outputFileStream);
delete writer;
// send user info to client nodes
broadcastMsg(MsgStateEvent("Reflector","DvUsers:info",
os.str()), v1_client_filter);
cout << jsonToString(event) << endl;
} /* Reflector::writeUserData */
string Reflector::jsonToString(Json::Value eventmessage)
{
Json::StreamWriterBuilder builder;
builder["indentation"] = "";
std::string message = Json::writeString(builder, eventmessage);
return message;
} /* Reflector::jsonToString */
/*
* This file has not been truncated
*/

View File

@ -38,6 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <sys/time.h>
#include <vector>
#include <string>
#include <json/json.h>
/****************************************************************************
@ -181,6 +182,18 @@ class Reflector : public sigc::trackable
*/
void requestQsy(ReflectorClient *client, uint32_t tg);
/**
* @brief Updates the user information
* @param user array with all data of the useres
*/
void updateUserdata(Json::Value eventmessage);
/**
* @brief Update Qso information
* @param ToDo
*/
void updateQsostate(Json::Value eventmessage);
private:
typedef std::map<Async::FramedTcpConnection*,
ReflectorClient*> ReflectorClientConMap;
@ -195,7 +208,29 @@ class Reflector : public sigc::trackable
uint32_t m_random_qsy_hi;
uint32_t m_random_qsy_tg;
Async::TcpServer<Async::HttpServerConnection>* m_http_server;
std::string cfg_filename;
bool debug;
// contain user data
struct User {
std::string id;
std::string call;
std::string mode;
std::string name;
std::string location;
std::string comment;
float lat;
float lon;
std::string state;
short reasonforsending;
char aprs_sym;
char aprs_tab;
time_t last_activity;
time_t sent_last_sds;
};
std::map<std::string, User> userdata;
Reflector(const Reflector&);
Reflector& operator=(const Reflector&);
void clientConnected(Async::FramedTcpConnection *con);
@ -212,7 +247,10 @@ class Reflector : public sigc::trackable
Async::HttpServerConnection::DisconnectReason reason);
void onRequestAutoQsy(uint32_t from_tg);
uint32_t nextRandomQsyTg(void);
bool getUserData(void);
void writeUserData(std::map<std::string, User> userdata);
std::string jsonToString(Json::Value eventmessage);
}; /* class Reflector */

View File

@ -36,6 +36,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <algorithm>
#include <cerrno>
#include <iterator>
#include <fstream>
#include <iostream>
/****************************************************************************
@ -687,11 +689,33 @@ void ReflectorClient::handleStateEvent(std::istream& is)
sendError("Illegal MsgStateEvent protocol message received");
return;
}
cout << "### ReflectorClient::handleStateEvent:"
<< " src=" << msg.src()
<< " name=" << msg.name()
<< " msg=" << msg.msg()
<< std::endl;
//cout << "### ReflectorClient::handleStateEvent:"
// << " src=" << msg.src()
// << " name=" << msg.name()
// << " msg=" << msg.msg()
// << std::endl;
Json::Value eventmessage;
Json::CharReaderBuilder rbuilder;
std::unique_ptr<Json::CharReader> const reader(rbuilder.newCharReader());
std::string jsonReaderError;
if (!reader->parse(msg.msg().c_str(), msg.msg().c_str() + msg.msg().size(),
&eventmessage, &jsonReaderError))
{
cout << "*** Error: parsing StateEvent message ("
<< jsonReaderError << ")" << endl;
return;
}
if (msg.name() == "DvUsers:info")
{
m_reflector->updateUserdata(eventmessage);
}
else if (msg.name() == "QsoInfo:state")
{
m_reflector->updateQsostate(eventmessage);
}
} /* ReflectorClient::handleStateEvent */

View File

@ -101,6 +101,8 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gpio.conf.in
${CMAKE_CURRENT_BINARY_DIR}/gpio.conf
@ONLY
)
install_if_not_exists(node_info.json ${SVX_SYSCONF_INSTALL_DIR})
install_if_not_exists(dv_users.json ${SVX_SYSCONF_INSTALL_DIR})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/svxlink_gpio_up.in
${RUNTIME_OUTPUT_DIRECTORY}/svxlink_gpio_up
@ONLY)

View File

@ -719,6 +719,24 @@ void ReflectorLogic::remoteReceivedPublishStateEvent(
}
sendMsg(msg);
}
else if (event_name == "QsoInfo:state")
{
std::istringstream is(data);
Json::Value user_info;
is >> user_info;
user_info["TG"] = m_selected_tg;
string ud =jsonToString(user_info);
// cout << "sende: " << event_name << "," << ud << endl;
MsgStateEvent msg(logic->name(), event_name, ud);
sendMsg(msg);
}
else if (event_name == "Sds:info" || event_name == "DvUsers:info")
{
// cout << "sende: " << event_name << "," << data << endl;
MsgStateEvent msg(logic->name(), event_name, data);
sendMsg(msg);
}
} /* ReflectorLogic::remoteReceivedPublishStateEvent */
@ -1847,6 +1865,18 @@ void ReflectorLogic::handlePlayDtmf(const std::string& digit, int amp,
} /* ReflectorLogic::handlePlayDtmf */
string ReflectorLogic::jsonToString(Json::Value eventmessage)
{
Json::StreamWriterBuilder builder;
std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
std::ostringstream ostream;
writer->write(eventmessage, &ostream);
std::string message = ostream.str();
message.erase(std::remove_if(message.begin(), message.end(),
[](unsigned char x){return std::iscntrl(x);}));
return message;
} /* ReflectorLogic::jsonToString */
/*
* This file has not been truncated
*/

View File

@ -305,7 +305,7 @@ class ReflectorLogic : public LogicBase
void handlePlaySilence(int duration);
void handlePlayTone(int fq, int amp, int duration);
void handlePlayDtmf(const std::string& digit, int amp, int duration);
std::string jsonToString(Json::Value eventmessage);
}; /* class ReflectorLogic */

View File

@ -12,5 +12,7 @@ macro(add_contrib name subdir comment)
endif(${WITH_CONTRIB_${name}})
endmacro(add_contrib)
add_contrib(USRP_LOGIC UsrpLogic
"Set to ON to build and install contributed logic core UsrpLogic")
add_contrib(SIP_LOGIC SipLogic
"Set to ON to build and install contributed logic core SipLogic")

View File

@ -0,0 +1,27 @@
message(
"-- The installing EXPERIMENTAL UsrpLogic extension"
)
add_manual_pages(UsrpLogic.conf.5)
# Build the plugin
add_library(UsrpLogic MODULE UsrpLogic.cpp)
set_target_properties(UsrpLogic PROPERTIES PREFIX "")
set_property(TARGET UsrpLogic PROPERTY NO_SONAME 1)
target_link_libraries(UsrpLogic ${LIBS})
# Install plugin, TCL event handler and config file
install(TARGETS UsrpLogic DESTINATION ${SVX_LOGIC_CORE_INSTALL_DIR})
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/UsrpLogic.tcl
DESTINATION ${SVX_SHARE_INSTALL_DIR}/events.d
)
install_if_not_exists(${CMAKE_CURRENT_SOURCE_DIR}/dv_users.json
${SVX_SYSCONF_INSTALL_DIR}
)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/UsrpLogic.conf.in
${CMAKE_CURRENT_BINARY_DIR}/UsrpLogic.conf
@ONLY
)
install_if_not_exists(${CMAKE_CURRENT_BINARY_DIR}/UsrpLogic.conf
${SVX_SYSCONF_INSTALL_DIR}/svxlink.d
)

View File

@ -0,0 +1,71 @@
Contrib: UsrpLogic
==================
----
#
# UsrpLogic (beta)
# Adi Bier / DL1HRC (dl1hrc [at] gmx.de)
#
----
== UsrpLogic ==
Provides a Logic to connect to MMDVM services with USRP protocol.
This branch only works if you have the following things:
- DV3000 USB-stick (hardware transcoder) or
- md380-emu service
Here are quick-and-dirty installation/update documentation, keep in
mind: No configuration will be done!
The configuration of the Usrp part has been moved to this new file,
normally found in /etc/svxlink/svxlink.d
== First time installation ==
including German(!) voice announcements.
You may use my semi-automatic installation-script from here
```
http://svxlink.ham-radio-op.net/svxlink/svxlink-usrp-contrib.sh
```
Start installation as root:
```
wget -O - http://svxlink.ham-radio-op.net/svxlink/svxlink-usrp-contrib.sh | bash
```
== Installation of SvxLink with UsrpLogic extension ==
```
git clone https://github.com/dl1hrc/svxlink.git
cd svxlink/src
git checkout svxlink-usrp
mkdir build
cd build
cmake -DUSE_QT=OFF -DCMAKE_INSTALL_PREFIX=/usr -DSYSCONF_INSTALL_DIR=/etc -DLOCAL_STATE_DIR=/var -DCMAKE_BUILD_TYPE=Release -DWITH_CONTRIB_USRP_LOGIC=ON ..
make
make install
```
Please not that the cmake-parameter "-DWITH_CONTRIB_USRP_LOGIC=ON" enables the
UsrpLogic extension. Without this it will not work.
== Update an existing usrp-contrib ==
```
systemctl stop svxlink
cd /home/svxlink/svxlink/src/build/
make clean
git pull
sudo make install
sudo systemctl restart svxlink
```
The new configuration file UsrpLogic.conf contains the [UsrpLogic]-section
from svxlink.conf. This file is now located in /etc/svxlink/svxlink.d directory.
Remove the [UsrpLogic]-section from svxlink.conf but let the LOGICS- and LINKS
definitions with "Usrp" untouched.
== Documentation ==
- manpage svxlink.conf.5
- German pdf is available here: https://github.com/dl1hrc/documentation

View File

@ -0,0 +1,17 @@
[UsrpLogic]
TYPE=Usrp
USRP_HOST=127.0.0.1
USRP_TX_PORT=41234
USRP_RX_PORT=41233
CALL=N0CALL
#DMRID=1234567
#PREAMP=1
#NET_PREAMP=0
#FILTER_TO_USRP=BpBu1/600-3500
#FILTER_FROM_USRP=HsBq2/0.01/-18/4000
DV_USER_INFOFILE=/etc/svxlink/dv_users.json
#DEBUG=1
EVENT_HANDLER=@SVX_SHARE_INSTALL_DIR@/events.tcl
JITTER_BUFFER_DELAY=400
NET_LIMITER_THRESH=-1.0
LOCAL_LIMITER_THRESH=-1.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,268 @@
/**
@file UsrpLogic.h
@brief A logic core that connect to the SvxUsrp
@author Tobias Blomberg / SM0SVX & Adi Bier / DL1HRC
@date 2021-04-24
\verbatim
SvxLink - A Multi Purpose Voice Services System for Ham Radio Use
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
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 USRP_LOGIC_INCLUDED
#define USRP_LOGIC_INCLUDED
/****************************************************************************
*
* System Includes
*
****************************************************************************/
#include <sys/time.h>
#include <iostream>
#include <string>
/****************************************************************************
*
* Project Includes
*
****************************************************************************/
#include <AsyncAudioDecoder.h>
#include <AsyncAudioEncoder.h>
#include <AsyncTimer.h>
#include <AsyncAudioFifo.h>
#include <AsyncAudioStreamStateDetector.h>
/****************************************************************************
*
* Local Includes
*
****************************************************************************/
#include "LogicBase.h"
#include "UsrpMsg.h"
/****************************************************************************
*
* Forward declarations
*
****************************************************************************/
namespace Async
{
class UdpSocket;
class AudioValve;
};
class EventHandler;
/****************************************************************************
*
* Forward declarations of classes inside of the declared namespace
*
****************************************************************************/
/****************************************************************************
*
* Defines & typedefs
*
****************************************************************************/
/****************************************************************************
*
* Exported Global Variables
*
****************************************************************************/
/****************************************************************************
*
* Class definitions
*
****************************************************************************/
/**
@brief A logic core that connect to the SvxUsrp
@author Tobias Blomberg / SM0SVX
@date 2021-04-24
*/
class UsrpLogic : public LogicBase
{
public:
/**
* @brief Constructor
* @param cfg A previously initialized configuration object
* @param name The name of the logic core
*/
UsrpLogic(void);
/**
* @brief Initialize 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::AudioSource *logicConOut(void) { return m_logic_con_out; }
protected:
/**
* @brief Destructor
*/
virtual ~UsrpLogic(void) override {};
private:
struct MonitorTgEntry
{
uint32_t tg;
uint8_t prio;
mutable int timeout;
MonitorTgEntry(uint32_t tg=0) : tg(tg), prio(0), timeout(0) {}
bool operator<(const MonitorTgEntry& mte) const { return tg < mte.tg; }
bool operator==(const MonitorTgEntry& mte) const { return tg == mte.tg; }
operator uint32_t(void) const { return tg; }
};
typedef std::set<MonitorTgEntry> MonitorTgsSet;
// contain user data
struct User {
std::string id;
std::string mode;
std::string call;
std::string name;
std::string comment;
std::string location;
float lat;
float lon;
std::string state;
short reasonforsending;
char aprs_sym;
char aprs_tab;
time_t last_activity = 0;
time_t sent_last_sds = 0;
};
std::map<std::string, User> userdata;
std::string m_usrp_host;
uint16_t m_usrp_port;
uint16_t m_usrp_rx_port;
Async::UdpSocket* m_udp_rxsock;
Async::AudioStreamStateDetector* m_logic_con_in;
Async::AudioStreamStateDetector* m_logic_con_out;
Async::AudioDecoder* m_dec;
Async::Timer m_flush_timeout_timer;
struct timeval m_last_talker_timestamp;
Async::AudioEncoder* m_enc;
unsigned m_tg_select_timeout;
uint32_t m_selected_tg;
Async::Timer m_report_tg_timer;
MonitorTgsSet m_monitor_tgs;
Async::AudioSource* m_enc_endpoint;
// Async::Timer m_tmp_monitor_timer;
int udp_seq;
// Async::Timer m_qsy_pending_timer;
int stored_samples;
int16_t *r_buf;
std::string m_callsign;
bool ident;
uint32_t m_dmrid;
uint32_t m_rptid;
uint8_t m_selected_cc;
uint8_t m_selected_ts;
float preamp_gain;
float net_preamp_gain;
EventHandler* m_event_handler;
uint32_t m_last_tg;
std::string m_last_call;
uint32_t m_last_dmrid;
short debug;
Json::Value m_user_info;
bool share_userinfo;
Async::Timer m_delay_timer;
uint8_t m_last_ts;
uint8_t m_last_cc;
std::string m_last_mode;
UsrpLogic(const UsrpLogic&);
UsrpLogic& operator=(const UsrpLogic&);
void handleMsgError(std::istream& is);
void sendEncodedAudio(const void *buf, int count);
void flushEncodedAudio(void);
void udpDatagramReceived(const Async::IpAddress& addr, uint16_t port,
void *buf, int count);
void handleStreamStop(void);
void handleVoiceStream(UsrpAudioMsg usrp);
void sendAudioMsg(UsrpAudioMsg& usrp);
void sendStopMsg(void);
void sendMetaMsg(void);
void sendUdpMessage(std::ostringstream& ss);
void sendHeartbeat(void);
void sendInfoJson(void);
void allEncodedSamplesFlushed(void);
void flushTimeout(Async::Timer *t=0);
void onDelayTimeout(Async::Timer *t);
void handleTimerTick(Async::Timer *t);
bool setAudioCodec(void);
void onLogicConInStreamStateChanged(bool is_active, bool is_idle);
void onLogicConOutStreamStateChanged(bool is_active, bool is_idle);
void checkIdle(void);
bool isIdle(void);
void handleMetaData(std::string metadata);
void switchMode(uint8_t mode);
void processEvent(const std::string& event);
void handleSettingsMsg(std::string infomsg);
void handlePlayFile(const std::string& path);
void handlePlaySilence(int duration);
void handlePlayTone(int fq, int amp, int duration);
void handlePlayDtmf(const std::string& digit, int amp,
int duration);
void onPublishStateEvent(const std::string &event_name, const std::string &msg);
void sendUserInfo(void);
void publishInfo(std::string type, Json::Value event);
}; /* class UsrpLogic */
#endif /* USRP_LOGIC_INCLUDED */
/*
* This file has not been truncated
*/

View File

@ -0,0 +1,110 @@
###############################################################################
#
# UsrpLogic event handlers
#
###############################################################################
#
# This is the namespace in which all functions below will exist. The name
# must match the corresponding section "[UsrpLogic]" in the configuration
# file. The name may be changed but it must be changed in both places.
#
namespace eval UsrpLogic {
#
# Checking to see if this is the correct logic core
#
if {$logic_name != [namespace tail [namespace current]]} {
return;
}
#
# Executed when an unknown command is received
# cmd - The command string
#
proc unknown_command {cmd} {
Logic::unknown_command $cmd;
}
#
# Executed when a received command fails
#
proc command_failed {cmd} {
Logic::command_failed $cmd;
}
#
# Executed each time a Usrp Meta frame is received
# and contains station data
#
proc usrp_stationdata_received {call tgid dmrid} {
set dmr "";
set tg "";
if {$dmrid > 0} {
set dmr "Dmr-ID $dmrid";
}
if {$tgid > 0} {
set tg "TG# $tgid";
}
puts "Talker $call $dmr $tg";
}
#
# Executed when the own transmission starts
#
proc transmission_start {tg} {
puts "Transmission starts (TG# $tg)";
}
#
# Executed when the own transmission stops
#
proc transmission_stop {tg} {
puts "Transmission stops (TG# $tg)";
}
#
# Executed when the remote transmision has stopped
#
proc talker_stop {tg {call "unknown"}} {
puts "Talker stop: $call TG# $tg";
}
#
# Executed when a switch between different modes has initiated
#
proc switch_to_mode {mode} {
puts "Send request for $mode";
}
#
# Executed when the analog_bridge confirm to switch the mode
#
proc setting_mode {mode} {
puts "New mode: $mode";
}
#
# Executed when json data has received, e.g.:
# {"call":"SP2ONG","name":"Waldek"}
#
proc usrp_jsondata_received {jsondata} {
puts "JSON: $jsondata";
}
# end of namespace
}
#
# This file has not been truncated
#

View File

@ -0,0 +1,501 @@
/**
@file UsrpMsg.h
@brief Usrp protocol message definitions
@author Tobias Blomberg / SM0SVX & Adi Bier / DL1HRC
@date 2021-04-26
\verbatim
SvxReflector - An audio reflector for connecting SvxLink Servers
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
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 USRP_MSG_INCLUDED
#define USRP_MSG_INCLUDED
/****************************************************************************
*
* System Includes
*
****************************************************************************/
#include <AsyncMsg.h>
/****************************************************************************
*
* Project Includes
*
****************************************************************************/
/****************************************************************************
*
* Local Includes
*
****************************************************************************/
/****************************************************************************
*
* Forward declarations
*
****************************************************************************/
/****************************************************************************
*
* Forward declarations of classes inside of the declared namespace
*
****************************************************************************/
/****************************************************************************
*
* Defines & typedefs
*
****************************************************************************/
#define MODE_NONE 0
#define MODE_DMR 1
#define MODE_P25 2
#define MODE_NXDN 3
/****************************************************************************
*
* Exported Global Variables
*
****************************************************************************/
static const unsigned DEFAULT_UDP_HEARTBEAT_TX_CNT_RESET = 15;
static const unsigned UDP_HEARTBEAT_RX_CNT_RESET = 60;
static const unsigned DEFAULT_TG_SELECT_TIMEOUT = 30;
static const int DEFAULT_TMP_MONITOR_TIMEOUT = 3600;
static const int USRP_AUDIO_FRAME_LEN = 160;
static const int USRP_HEADER_LEN = 32;
enum { USRP_TYPE_VOICE=0, USRP_TYPE_DTMF=1, USRP_TYPE_TEXT=2,
USRP_TYPE_PING=3, USRP_TYPE_TLV=4, USRP_TYPE_VOICE_ADPCM = 5,
USRP_TYPE_VOICE_ULAW = 6 };
enum { TLV_TAG_BEGIN_TX = 0, TLV_TAG_AMBE = 1, TLV_TAG_END_TX = 2,
TLV_TAG_TG_TUNE = 3, TLV_TAG_PLAY_AMBE= 4, TLV_TAG_REMOTE_CMD= 5,
TLV_TAG_AMBE_49 = 6, TLV_TAG_AMBE_72 = 7, TLV_TAG_SET_INFO = 8,
TLV_TAG_IMBE = 9, TLV_TAG_DSAMBE = 10, TLV_TAG_FILE_XFER= 11
};
//std::map<uint8_t, std::string> selected_mode;
const std::string selected_mode[] = { "*NONE", "*DMR", "*P25", "*NXDN" };
/****************************************************************************
*
* Class definitions
*
****************************************************************************/
/**
* @brief Class for Usrp audio network messages
* @author Tobias Blomberg / SM0SVX & Adi Bier / DL1HRC
* @date 2021-04-28
*/
class UsrpAudioMsg : public Async::Msg
{
public:
UsrpAudioMsg(uint32_t seq=0, uint32_t memory=0, uint32_t keyup=0,
uint32_t talkgroup=0, uint32_t type=0, uint32_t mpxid=0,
uint32_t reserved=0, const std::array<int16_t, 160> audio_data={0})
: m_seq(htole32(seq)), m_memory(htonl(memory)), m_keyup(keyup),
m_talkgroup(htonl(talkgroup)), m_type(htonl(type)),
m_mpxid(htonl(mpxid)), m_reserved(htonl(reserved)),
m_audio_data(audio_data)
{
eye = {'U','S','R','P'};
}
/**
* @brief Destructor
*/
virtual ~UsrpAudioMsg(void) {}
uint32_t type(void) const { return ntohl(m_type); }
uint32_t seq(void) const { return ntohl(m_seq); }
uint32_t memory(void) const { return ntohl(m_memory); }
uint32_t keyup(void) const { return m_keyup; }
uint32_t mpxid(void) const { return ntohl(m_mpxid); }
uint32_t reserved(void) const { return ntohl(m_reserved); }
uint32_t talkgroup(void) const { return ntohl(m_talkgroup); }
void setTg(uint32_t tg) { m_talkgroup = htole32(tg);}
void setType(uint32_t type) { m_type = htole32(type);}
void setSeq(uint32_t seq) { m_seq = htole32(seq); }
void setKeyup(bool keyup) { (keyup ? m_keyup=1 : m_keyup=0); }
void setAudioData(int16_t in[USRP_AUDIO_FRAME_LEN*2])
{
for (size_t x=0; x<USRP_AUDIO_FRAME_LEN; x++)
{
m_audio_data[x] = htons(in[x]);
}
}
std::array<int16_t, USRP_AUDIO_FRAME_LEN>& audioData(void)
{ return m_audio_data; }
const std::array<int16_t, USRP_AUDIO_FRAME_LEN>& audioData(void)
const { return m_audio_data; }
ASYNC_MSG_MEMBERS(eye, m_seq, m_memory, m_keyup, m_talkgroup, m_type,
m_mpxid, m_reserved, m_audio_data)
private:
std::array<char, 4> eye;
uint32_t m_seq;
uint32_t m_memory;
uint32_t m_keyup;
uint32_t m_talkgroup;
uint32_t m_type;
uint32_t m_mpxid;
uint32_t m_reserved;
std::array<int16_t, USRP_AUDIO_FRAME_LEN> m_audio_data;
};
/**
* @brief Class for Usrp network header message
* @author Tobias Blomberg / SM0SVX & Adi Bier / DL1HRC
* @date 2021-04-28
*/
class UsrpHeaderMsg : public Async::Msg
{
public:
UsrpHeaderMsg(uint32_t seq=0, uint32_t keyup=0, uint32_t talkgroup=0,
uint32_t type=0)
: m_seq(htole32(seq)), m_keyup(keyup),
m_talkgroup(htole32(talkgroup)), m_type(htole32(type))
{
eye = {'U','S','R','P'};
m_memory = 0;
m_keyup = 0;
m_type = 0;
m_mpxid = 0;
m_reserved = 0;
}
/**
* @brief Destructor
*/
virtual ~UsrpHeaderMsg(void) {}
uint32_t type(void) const { return ntohl(m_type); }
uint32_t seq(void) const { return ntohl(m_seq); }
uint32_t memory(void) const { return ntohl(m_memory); }
bool keyup(void) const { return (m_keyup & 1 ? true : false); }
uint32_t mpxid(void) const { return ntohl(m_mpxid); }
uint32_t reserved(void) const { return ntohl(m_reserved); }
uint32_t talkgroup(void) const { return ntohl(m_talkgroup); }
void setTg(uint32_t tg) { m_talkgroup = htole32(tg); }
void setSeq(uint32_t seq) { m_seq = htole32(seq); }
ASYNC_MSG_MEMBERS(eye, m_seq, m_memory, m_keyup, m_talkgroup,
m_type, m_mpxid, m_reserved)
private:
std::array<char, 4> eye;
uint32_t m_seq;
uint32_t m_memory;
uint32_t m_keyup;
uint32_t m_talkgroup;
uint32_t m_type;
uint32_t m_mpxid;
uint32_t m_reserved;
};
/*
template <typename P>
class UsrpMsg {
UsrpMsg(UsrpHeaderMsg header, P payload) : header(header), payload(p) {}
private:
UsrpHeaderMsg header;
P payload;
};
UrspHeaderMsg h = ....
if(condition(h)) {
std::vector<uint8_t> payload =...
UsrpMsg<std::vector> msg(h, payload);
}
*/
/**
* @brief Class for UsrpMetaTextMsg message
* @author Tobias Blomberg / SM0SVX & Adi Bier / DL1HRC
* @date 2021-07-02
*/
class UsrpMetaTextMsg : public Async::Msg
{
public:
UsrpMetaTextMsg(uint32_t seq=0, uint32_t keyup=0,
uint32_t talkgroup=0, uint32_t type=0)
: m_seq(htole32(seq)), m_keyup(keyup),
m_talkgroup(htole32(talkgroup)), m_type(htole32(type))
{
eye = {'U','S','R','P'};
m_memory = 0;
m_keyup = 0;
m_talkgroup = 0;
m_type = htobe32(USRP_TYPE_TEXT);
m_mpxid = 0;
m_reserved = 0;
}
/**
* @brief Destructor
*/
virtual ~UsrpMetaTextMsg(void) {}
/**
* public methods
*/
uint32_t type(void) const { return ntohl(m_type); }
uint32_t seq(void) const { return m_seq; }
uint32_t tg(void) const { return ntohl(m_talkgroup); }
uint32_t keyup(void) const { return ntohl(m_keyup); }
uint32_t mpx(void) const { return ntohl(m_mpxid); }
uint32_t res(void) const { return ntohl(m_reserved); }
// return true if the message is TLV (first character == 0x08)
bool isTlv(void)
{
return (m_meta == 0x08 ? true : false);
}
ASYNC_MSG_MEMBERS(eye, m_seq, m_memory, m_keyup, m_talkgroup,
m_type, m_mpxid, m_reserved, m_meta)
private:
std::array<char, 4> eye;
uint32_t m_seq;
uint32_t m_memory;
uint32_t m_keyup;
uint32_t m_talkgroup;
uint32_t m_type;
uint32_t m_mpxid;
uint32_t m_reserved;
uint8_t m_meta;
}; /* class UsrpMetaTextMsg */
/**
* @brief Class for Usrp network Metadata message (TLV)
* @author Tobias Blomberg / SM0SVX & Adi Bier / DL1HRC
* @date 2021-04-28
*/
class UsrpTlvMetaMsg : public Async::Msg
{
public:
UsrpTlvMetaMsg(uint32_t seq=0) : m_seq(htole32(seq))
{
eye = {'U','S','R','P'};
m_memory = 0;
m_keyup = 0;
m_talkgroup = 0;
m_type = htobe32(USRP_TYPE_TEXT);
m_mpxid = 0;
m_reserved = 0;
m_tlv = TLV_TAG_SET_INFO;
m_tlvlen = 0x13;
m_dmrid = {0,0,0};
m_rptid = 0;
m_tg = {0,0,0};
m_ts = 0;
m_cc = 1;
m_meta.fill(0);
}
/**
* @brief Destructor
*/
virtual ~UsrpTlvMetaMsg(void) {}
// set the own talk group
void setTg(uint32_t tg)
{
std::array<uint8_t, 3> t;
t[0] = (tg >> 16) & 0xff;
t[1] = (tg >> 8) & 0xff;
t[2] = (tg >> 0) & 0xff;
m_tg = t;
}
// set USRP_TYPE
void setType(uint32_t type)
{
m_type = htobe32(type);
}
// set the squence
void setSeq(uint32_t seq) { m_seq = htole32(seq); }
// set the own callsign
void setCallsign(std::string call)
{
for (size_t i=0; i<call.length(); i++)
{
m_meta[i] = call.c_str()[i];
}
m_tlvlen = static_cast<int>(call.length() + 13) & 0xff;
}
// set Metadata
void setMetaData(std::string metadata)
{
}
// set DMR-ID
void setDmrId(uint32_t dmrid)
{
std::array<uint8_t, 3> t;
t[0] = (dmrid >> 16) & 0xff;
t[1] = (dmrid >> 8) & 0xff;
t[2] = (dmrid >> 0) & 0xff;
m_dmrid = t;
}
// set the own repeater ID
void setRptId(uint32_t rptid) { m_rptid = htole32(rptid); }
// set the color code
void setCC(uint8_t cc) { m_cc = cc; }
// set Time slot
void setTS(uint8_t ts)
{
(ts > 4 ? m_ts = 4 : m_ts = ts);
}
void setTlv(uint8_t tlv)
{
m_tlv = tlv;
}
void setTlvLen(uint8_t tlvlen)
{
m_tlvlen = tlvlen;
}
// returns the callsing of the talker
std::string getCallsign(void)
{
uint8_t i = 0;
uint8_t call[9];
if (m_tlv == TLV_TAG_SET_INFO && m_tlvlen < 0x16)
{
for(i=0;i<(m_tlvlen-13);i++)
{
call[i] = m_meta[i];
if (m_meta[i] == 0x00) break;
}
}
return std::string(call, call+i);
}
// returns MetaData info
std::string getMetaInfo(void)
{
uint8_t metainfo[306];
uint8_t z;
if (m_tlv == TLV_TAG_SET_INFO)
{
for (z=0;z<306;z++)
{
metainfo[z] = m_meta[z];
if (m_meta[z] == 0x00) break;
}
return std::string(metainfo, metainfo+z);
}
return "";
}
// returns the TYPE of message
uint32_t type(void) const { return ntohl(m_type); }
// returns the current talkgroup of the talker
uint32_t getTg(void)
{
return ((m_tg[0] << 16) + (m_tg[1] << 8) + (m_tg[2] & 0xff));
}
// returns the DMR ID of the talker
uint32_t getDmrId(void)
{
return (m_dmrid[2] & 0xff) + (m_dmrid[1] << 8) + (m_dmrid[0] << 16);
}
// getTlv
uint8_t getTlv(void) { return m_tlv; }
// getTS
uint8_t getTS(void) { return (m_ts > 4 ? 4 : m_ts); }
// getTlvLen
uint8_t getTlvLen(void) { return m_tlvlen; }
ASYNC_MSG_MEMBERS(eye, m_seq, m_memory, m_keyup, m_talkgroup, m_type,
m_mpxid, m_reserved, m_tlv, m_tlvlen, m_dmrid, m_rptid,
m_tg, m_ts, m_cc, m_meta)
private:
std::array<char, 4> eye; // is always "USRP"
uint32_t m_seq; // sequence number
uint32_t m_memory; // set to 0 - not used
uint32_t m_keyup; // Tx on/off (1/0)
uint32_t m_talkgroup; // current talkgroup
uint32_t m_type; // type of frame
uint32_t m_mpxid; // set to 0 - not used
uint32_t m_reserved; // set to 0 - not used
uint8_t m_tlv; // see TLV_TAGS
uint8_t m_tlvlen; // TLV-length of MetaData
std::array<uint8_t, 3> m_dmrid; // DMR-ID length 3 bytes
uint32_t m_rptid; // Repeater-ID length 4 bytes
std::array<uint8_t, 3> m_tg; // Talkgroup length 3 bytes
uint8_t m_ts; // Timeslot length 1 byte
uint8_t m_cc; // color code length 1 byte
std::array<uint8_t, 306> m_meta; // padding the rest with 0x00
};
#endif /* USRP_MSG_INCLUDED */
/*
* This file has not been truncated
*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
{
"ab":{"version":"1.6.2","date":"Wed.Mar.31.13:52:10.EDT.2021"},
"dv3000":{"ip":"127.0.0.1","port":"2460","use_serial":"false"},
"use_fallback":"true",
"use_emulator":"true",
"mute":"OFF",
"usrp":{"ip":"127.0.0.1","rx_port":"14321","tx_port":"14321","ping":"10",
"to_pcm":{"shape":"AUDIO_USE_AGC","gain":"4.00"},
"to_ambe":{"shape":"AUDIO_USE_GAIN","gain":"0.35"}
},
"tlv":{"ip":"127.0.0.1","tx_port":"0","rx_port":"0","ambe_size":"72","ambe_mode":"NXDN"},
"digital":{"gw":"1234567","rpt":"123456789","tg":"7","ts":"2","cc":"1","call":"N0CALL"},
"last_tune":"7"
}

View File

@ -0,0 +1,309 @@
USRP protocol used to send via UDP analog audio (2021.07.14)
The USRP was implemented in Allstar (in 2010, KA1RBI) and used by various hamradio applications like
MMDVMHost, USRP2M17, Analog_Bridge, Analog_Reflector, etc
UDP USRP FRAME:
===============
USRP Header (32 bytes) + DATA
Typical sequence for send audio:
USRP_HEADER (Type_Frame=2, PTT=0) + DATA (The DATA in first byte contain TLV_TAGS: 0x08 (TLV_TAG_SET_INFO)
and contain MetaDATA (see below))
USRP_HEADER (Type_Frame=0, PTT=1) + DATA (Audio 320 bytes)
....
USRP_HEADER (Type_Frame=0, PTT=0) + DATA (last Audio or empty buffer 320 bytes)
The first frame type = 2 (USRP_TYPE_TEXT) with MetaData is not obligatory and can be omitted, but it can be useful when,
for example, we want to send information about the callsign source from the analog to
for example M17 or callsign and its DMR ID to DMR.
At current in USRP header are used only the following information:
USRP string in 0-3 bytes
Sequence number (4-7 bytes)
PTT status (15 byte) 1 = ON , 0 = OFF
Type of Frame (20 byte) 0 Audio data, 1 DTMF, 2 MetaData
The rest of the information in USRP header should be set to 0
USRP Header:
==============================
Bytes Value Notes
0-3 USRP string char: USRP
4-7 Sequence number
8-11 Memory? Set to 0 (not used)
12-15 PTT PTT value is stored in 15 byte. 1 for PTT ON start transmission, 0 for PTT OFF stop transmission
16-19 Talkgroup? Set to 0 (not used)
20-23 Type_Frame Type frame is stored in 20 byte. 0 for Audio (USRP_TYPE_VOICE), 2 for MetaData (USRP_TYPE_TEXT)
24-27 Mpxid? Set to 0 (not used)
28-31 Reserved? Set to 0 (not used)
Minimum use USRP protocol is:
Received side
-------------
Two types of frames are we received
- USRP_TYPE_TEXT with set TVL_TAG_SET_INFO (0x08) bit where we get information about source callsign and DmrID
and Talk Group
- USRP_TYPE_VOICE is used to receive stream audio wherein USRP Header is information about KEYUP status (PTT)
which allow track start an audio and stop audio stream received
Transmitting side
-----------------
Two types of frames are we received
- USRP_TYPE_TEXT with set TVL_TAG_SET_INFO (0x08) bit where we send information about source callsign and DmrID
and Talk Group. DmrID and Talk Group make sense when we have a link to DMR DV
- USRP_TYPE_VOICE used to send audio stream where in USRP Header in information about KEYUP status (PTT)
which allow track start an audio and stop audio stream received
Below short description type of UDP USRP frames
-----------------------------------------------
DATA contain Audio stream (see example 1)
===========================================
In byte 20 of the USRP HEADER, frame type 0 (USRP_TYPE_VOICE)
In byte 15 of the USRP HEADER, status PTT: 1 ON, 0 OFF (last frame)
The DATA contains an AUDIO stream.
Audio signed 16-bit little-endian PCM audio at 8000 samples/sec, 160 samples per packet.
The PTT status in the USRP of the header can be used to control PTT or
SQL, or information about start and end transmission in an application that is receiving data via USRP.
1. DATA = MetaData with Callsign, DmrId, Talk Group (see example 2)
===================================================================
In byte 20 of the USRP HEADER, frame type 1 (USRP_TYPE_TEXT)
The DATA in the first byte contains TLV_TAGS: 0x08 (TLV_TAG_SET_INFO)
The next bytes contain MetaData:
TLVLenght,dmrID, repeaterID, tg, ts, cc, callsign, 0
TLV Tags Set 0x08 (see TLV_TAGS)
TLV Length Value of lenght of MetaData where TLVLenght = 3 + 4 + 3 + 1 + 1 + len(call) + 1
DMR Id Lenght 3 bytes. Set 0 or ((dmr_id >> 16) & 0xff),((dmr_id >> 8) & 0xff),(dmr_id & 0xff)
RPT Id Lenght 4 bytes. Set 0 or ((rpt_id >> 32) & 0xff),((rpt_id >> 16) & 0xff),((rpt_id >> 8) & 0xff),(rpt_id & 0xff)
TalkGroup Lenght 3 bytes. Set 0 or ((tg >> 16) & 0xff),((tg >> 8) & 0xff),(tg & 0xff)
TimeSlot# Length 1 byte. Set 0 or Time Slot number
ColorCode Length 1 byte. Set 0 or value of ColorCode
Callsing Put the callisgn
End of MetData Set 0
Note:
For most applications with USRP protocol, it is enough to send in MetaData
only callsign and in the case of DMR and P25 network,
additionally DMR ID for the given callsign
The Analog Bridge v1.6.2 set in field CALLSIGN information like:
{"call":"N3ABC","name":"Club station"}
if our application is connected with Analog Refelctor via BRIDGE mode.
2. DATA = MetaData tune Talk Group on Analog Bridge (see example 3)
==========================================================
In byte 20 of the USRP HEADER, frame type 1 (USRP_TYPE_DTMF)
The DATA contains a string where is Talk Group number.
For example, we want to set the TG # 26021 string in DATA in
bytes is: 3236 3032 3100
2 is 32, 6 is 36, etc
3. DATA = MetaData switch DV mode on Analog Bridge (see example 4)
==========================================================
In byte 20 of the USRP HEADER, frame type 1 (USRP_TYPE_DTMF)
The DATA contains a string where the first character
is * (star) followed by the Digital Voice mode name.
For example, we want to set mode DMR string in DATA: *DMR
Available DV Mode Names: DMR, YSF, P25, NXDN, DSTAR
4. DATA = MetaData send request INFO to Analog Bridge (see example 5)
=================================================================
In byte 20 of the USRP HEADER, frame type 2 (USRP_TYPE_TEXT)
The DATA contains a string INFO
5. DATA = MetaData received from Analog Bridge with INFO in JSON format (see example 6)
==============================================================================
In byte 20 of the USRP HEADER, frame type 2 (USRP_TYPE_TEXT)
The DATA contains a string INFO:
and next status Analog Bridge in JSON format
The length frame is bigger than 320 bytes
Example 1
-------------------------------------------
Dump with USRP Audio data PTT ON = 1
0x0000: 4500 017c 524b 4000 4011 e923 7f00 0001 E..|RK@.@..#....
0x0010: 7f00 0001 d432 d431 0168 ff7b 5553 5250 .....2.1.h.{USRP
0x0020: 0000 000b 0000 0000 0000 0001 0000 0000 ................
0x0030: 0000 0000 0000 0000 0000 0000 eaff efff ................
0x0040: d5ff c3ff c4ff c6ff c9ff caff e1ff eeff ................
The last USRP frame PTT OFF = 0
0x0000: 4500 017c 9b6d 4000 4011 a001 7f00 0001 E..|.m@.@.......
0x0010: 7f00 0001 d432 d431 0168 ff7b 5553 5250 .....2.1.h.{USRP
0x0020: 0000 0050 0000 0000 0000 0000 0000 0000 ...P............
0x0030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
Example 2
--------------------------------------------
MetaData: Callsign N0CALL DmrID 1234567
0x0000: 0000 0000 0000 0000 0000 0000 0800 4500 ..............E.
0x0010: 017c cbb9 4000 4011 6fb5 7f00 0001 7f00 .|..@.@.o.......
0x0020: 0001 8613 8614 0168 ff7b 5553 5250 0000 .......h.{USRP..
0x0030: 00da 0000 0000 0000 0000 0000 0000 0200 ................
0x0040: 0000 0000 0000 0000 0000 0813 12d6 8700 ...............
0x0050: 0000 0000 0000 0000 4e30 4341 4c4c 0000 ........N0CALL..
0x0060: 0000 0000 0000 0000 0000 0000 0000 0000 ................
Example 3
--------------------------------------------
Tune Talk Group 4000
0x0000: 4500 017c 9f5b 4000 4011 9c13 7f00 0001 E..|.[@.@.......
0x0010: 7f00 0001 d432 d431 0168 ff7b 5553 5250 .....2.1.h.{USRP
0x0020: 0000 0002 0000 0000 0000 0000 0000 0000 ................
0x0030: 0100 0000 0000 0000 0000 0000 3430 3030 ............4000
0x0040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
Tune Talk Group 7
0x0000: 4500 017c d985 4000 4011 61e9 7f00 0001 E..|..@.@.a.....
0x0010: 7f00 0001 d432 d431 0168 ff7b 5553 5250 .....2.1.h.{USRP
0x0020: 0000 0003 0000 0000 0000 0000 0000 0000 ................
0x0030: 0100 0000 0000 0000 0000 0000 3700 0000 ............7...
0x0040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
Example 4
--------------------------------------------
Switch mode to YSF
0x0000: 4500 017c 32ac 4000 4011 08c3 7f00 0001 E..|2.@.@.......
0x0010: 7f00 0001 d432 d431 0168 ff7b 5553 5250 .....2.1.h.{USRP
0x0020: 0000 0002 0000 0000 0000 0000 0000 0000 ................
0x0030: 0100 0000 0000 0000 0000 0000 2a59 5346 ............*YSF
0x0040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
Analog Bridge send to client INFO about confirm setting mode YSF
The byte 20 is type frame 2 USRP_TYPE_TEXT. From byte 33 is
string INFO: and next bytes contain a message
0x0000: 4500 017c 332f 4000 4011 0840 7f00 0001 E..|3/@.@..@....
0x0010: 7f00 0001 d431 d432 0168 ff7b 5553 5250 .....1.2.h.{USRP
0x0020: 0000 0ac3 0000 0000 0000 0000 0000 0000 ................
0x0030: 0200 0000 0000 0000 0000 0000 494e 464f ............INFO
0x0040: 3a4d 5347 3a53 6574 7469 6e67 206d 6f64 :MSG:Setting.mod
0x0050: 6520 746f 2059 5346 0000 0000 0000 0000 e.to.YSF........
0x0060: 0000 0000 0000 0000 0000 0000 0000 0000 ................
Example 5
-----------------------------------------------
0x0000: 4500 017c 32eb 4000 4011 0884 7f00 0001 E..|2.@.@.......
0x0010: 7f00 0001 d432 d431 0168 ff7b 5553 5250 .....2.1.h.{USRP
0x0020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0030: 0200 0000 0000 0000 0000 0000 494e 464f ............INFO
0x0040: 3a00 0000 0000 0000 0000 0000 0000 0000 :...............
Example 6
-----------------------------------------------
0x0000: 4500 0269 12d4 4000 4011 27ae 7f00 0001 E..i..@.@.'.....
0x0010: 7f00 0001 d431 d432 0255 0069 5553 5250 .....1.2.U.iUSRP
0x0020: 0000 1495 0000 0000 0000 0000 0000 0000 ................
0x0030: 0200 0000 0000 0000 0000 0000 494e 464f ............INFO
0x0040: 3a7b 2261 6222 3a7b 2276 6572 7369 6f6e :{"ab":{"version
0x0050: 223a 2231 2e36 2e32 222c 2264 6174 6522 ":"1.6.2","date"
0x0060: 3a22 5765 6420 4d61 7220 3331 2031 333a :"Wed.Mar.31.13:
0x0070: 3532 3a31 3020 4544 5420 3230 3231 227d 52:10.EDT.2021"}
0x0080: 2c22 6476 3330 3030 223a 7b22 6970 223a ,"dv3000":{"ip":
0x0090: 2231 3237 2e30 2e30 2e31 222c 2270 6f72 "127.0.0.1","por
0x00a0: 7422 3a22 3234 3630 222c 2275 7365 5f73 t":"2460","use_s
0x00b0: 6572 6961 6c22 3a22 6661 6c73 6522 7d2c erial":"false"},
0x00c0: 2275 7365 5f66 616c 6c62 6163 6b22 3a22 "use_fallback":"
0x00d0: 7472 7565 222c 2275 7365 5f65 6d75 6c61 true","use_emula
0x00e0: 746f 7222 3a22 7472 7565 222c 226d 7574 tor":"true","mut
0x00f0: 6522 3a22 4f46 4622 2c22 7573 7270 223a e":"OFF","usrp":
0x0100: 7b22 6970 223a 2231 3237 2e30 2e30 2e31 {"ip":"127.0.0.1
0x0110: 222c 2272 785f 706f 7274 223a 2231 3433 ","rx_port":"143
0x0120: 3231 222c 2274 785f 706f 7274 223a 2231 21","tx_port":"1
0x0130: 3433 3231 222c 2270 696e 6722 3a22 3130 4321","ping":"10
0x0140: 222c 2274 6f5f 7063 6d22 3a7b 2273 6861 ","to_pcm":{"sha
0x0150: 7065 223a 2241 5544 494f 5f55 5345 5f41 pe":"AUDIO_USE_A
0x0160: 4743 222c 2267 6169 6e22 3a22 342e 3030 GC","gain":"4.00
0x0170: 227d 2c22 746f 5f61 6d62 6522 3a7b 2273 "},"to_ambe":{"s
0x0180: 6861 7065 223a 2241 5544 494f 5f55 5345 hape":"AUDIO_USE
0x0190: 5f47 4149 4e22 2c22 6761 696e 223a 2230 _GAIN","gain":"0
0x01a0: 2e33 3522 7d7d 2c22 746c 7622 3a7b 2269 .35"}},"tlv":{"i
0x01b0: 7022 3a22 3132 372e 302e 302e 3122 2c22 p":"127.0.0.1","
0x01c0: 7478 5f70 6f72 7422 3a22 3022 2c22 7278 tx_port":"0","rx
0x01d0: 5f70 6f72 7422 3a22 3022 2c22 616d 6265 _port":"0","ambe
0x01e0: 5f73 697a 6522 3a22 3732 222c 2261 6d62 _size":"72","amb
0x01f0: 655f 6d6f 6465 223a 224e 5844 4e22 7d2c e_mode":"NXDN"},
0x0200: 2264 6967 6974 616c 223a 7b22 6777 223a "digital":{"gw":
0x0210: 2231 3233 3435 3637 222c 2272 7074 223a "1234567","rpt":
0x0220: 2231 3233 3435 3637 3839 222c 2274 6722 "123456789","tg"
0x0230: 3a22 3722 2c22 7473 223a 2232 222c 2263 :"7","ts":"2","c
0x0240: 6322 3a22 3122 2c22 6361 6c6c 223a 224E c":"1","call":"N
0x0250: 3043 414C 4C22 7d2c 226c 6173 745f 7475 0CALL"},"last_tu
0x0260: 6e65 223a 2237 227d 00 ne":"7"}.
Other information
-----------------
TYPE of USRP frames
#######################
USRP_TYPE_VOICE = 0 (Audio data)
USRP_TYPE_DTMF = 1
USRP_TYPE_TEXT = 2 (Meta data)
USRP_TYPE_PING = 3
USRP_TYPE_TLV = 4
USRP_TYPE_VOICE_ADPCM = 5
USRP_TYPE_VOICE_ULAW = 6
TLV tags
#######################
TLV_TAG_BEGIN_TX = 0
TLV_TAG_AMBE = 1
TLV_TAG_END_TX = 2
TLV_TAG_TG_TUNE = 3
TLV_TAG_PLAY_AMBE = 4
TLV_TAG_REMOTE_CMD = 5
TLV_TAG_AMBE_49 = 6
TLV_TAG_AMBE_72 = 7
TLV_TAG_SET_INFO = 8
TLV_TAG_IMBE = 9
TLV_TAG_DSAMBE = 10
TLV_TAG_FILE_XFER = 11
Information base on:
The above information about the USRP protocol is based on an analysis of the dump
frames from applications that use USRP as well and from links
https://github.com/AllStarLink/ASL-Asterisk/blob/develop/asterisk/channels/chan_usrp.h
https://github.com/AllStarLink/ASL-Asterisk/blob/develop/asterisk/channels/chan_usrp.c
https://github.com/DVSwitch/MMDVM_Bridge/blob/master/dvswitch.sh
https://github.com/DVSwitch/USRP_Client/blob/master/pyUC.py

View File

@ -0,0 +1,6 @@
[
{ "id" : "2620055", "mode" : "DMR", "name" : "Adi", "call" : "DL1HRC-1", "location" : "Leuna", "symbol" : "\\r", "comment" : "DMR ID" },
{ "id" : "9031", "mode" : "NXDN", "name" : "Adi", "call" : "DL1HRC-2", "location" : "Leuna", "symbol" : "\\r", "comment" : "SvxLink Sysop" },
{ "id" : "09011638300023403", "mode" : "TETRA", "name" : "Adi", "call" : "DL1HRC-3", "location" : "Leuna", "symbol" : "\\E", "comment" : "SvxLink Sysop" },
{ "id" : "123456", "mode" : "SPECIAL", "name" : "Adi", "call" : "DL1HRC-4", "location" : "Leuna", "symbol" : "\\r", "comment" : "SvxLink Sysop" }
]

View File

@ -109,6 +109,24 @@ EVENT_HANDLER=@SVX_SHARE_INSTALL_DIR@/events.tcl
QSY_PENDING_TIMEOUT=15
#VERBOSE=1
[UsrpLogic]
TYPE=Usrp
USRP_HOST=127.0.0.1
USRP_TX_PORT=41234
USRP_RX_PORT=41233
CALL=N0CALL
#DMRID=1234567
#PREAMP=1
#NET_PREAMP=0
#FILTER_TO_USRP=BpBu1/600-3500
#FILTER_FROM_USRP=HsBq2/0.01/-18/4000
DV_USER_INFOFILE=/etc/svxlink/dv_users.json
#DEBUG=1
EVENT_HANDLER=@SVX_SHARE_INSTALL_DIR@/events.tcl
JITTER_BUFFER_DELAY=400
NET_LIMITER_THRESH=-1.0
LOCAL_LIMITER_THRESH=-1.0
[LinkToR4]
CONNECT_LOGICS=RepeaterLogic:94:SK3AB,SimplexLogic:92:SK3CD
#DEFAULT_ACTIVE=1

View File

@ -38,3 +38,6 @@ SVXSERVER=0.0.6
# Version for SvxReflector
SVXREFLECTOR=1.99.16
# Version for Usrp support
USRPSUPPORT=0.0.1.2