diff --git a/.gitignore b/.gitignore index d900137..ac9e54f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,24 +7,8 @@ *.o *.obj -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib +# Files +tcd.* # Visual Studio .vscode diff --git a/Configure.cpp b/Configure.cpp index 78d00d8..e585b02 100644 --- a/Configure.cpp +++ b/Configure.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "Configure.h" // ini file keywords @@ -30,7 +31,9 @@ #define DMRGAINOUT "DmrYsfGainOut" #define DSTARGAININ "DStarGainIn" #define DSTARGAINOUT "DStarGainOut" -#define TRANSCODED "Transcoded" +#define MODULES "Modules" +#define ADDRESS "Address" +#define PORT "Port" static inline void split(const std::string &s, char delim, std::vector &v) { @@ -63,7 +66,10 @@ static inline void trim(std::string &s) { bool CConfigure::ReadData(const std::string &path) // returns true on failure { - std::string modstmp; + std::regex IPv4RegEx = std::regex("^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3,3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]){1,1}$", std::regex::extended); + std::regex IPv6RegEx = std::regex("^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}){1,1}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|([0-9a-fA-F]{1,4}:){1,1}(:[0-9a-fA-F]{1,4}){1,6}|:((:[0-9a-fA-F]{1,4}){1,7}|:))$", std::regex::extended); + + std::string modstmp, porttmp; std::ifstream cfgfile(path.c_str(), std::ifstream::in); if (! cfgfile.is_open()) { @@ -104,7 +110,11 @@ bool CConfigure::ReadData(const std::string &path) std::cout << "WARNING: missing key or value: '" << line << "'" << std::endl; continue; } - if (0 == key.compare(TRANSCODED)) + if (0 == key.compare(ADDRESS)) + address.assign(value); + else if (0 == key.compare(PORT)) + porttmp.assign(value); + else if (0 == key.compare(MODULES)) modstmp.assign(value); else if (0 == key.compare(DSTARGAININ)) dstar_in = getSigned(key, value); @@ -139,7 +149,22 @@ bool CConfigure::ReadData(const std::string &path) return true; } - std::cout << TRANSCODED << " = " << tcmods << std::endl; + if (! std::regex_match(address, IPv4RegEx) && ! std::regex_match(address, IPv6RegEx)) + { + std::cerr << "ERROR: '" << address << "' is malformed, Halt." << std::endl; + return true; + } + + port = std::strtoul(porttmp.c_str(), nullptr, 10); + if (port < 1025 || port > 49000) + { + std::cerr << "ERROR: Port '" << porttmp << "' must be between >1024 and <49000. Halt." << std::endl; + return true; + } + + std::cout << MODULES << " = " << tcmods << std::endl; + std::cout << ADDRESS << " = " << address << std::endl; + std::cout << PORT << " = " << port << std::endl; std::cout << DSTARGAININ << " = " << dstar_in << std::endl; std::cout << DSTARGAINOUT << " = " << dstar_out << std::endl; std::cout << DMRGAININ << " = " << dmr_in << std::endl; diff --git a/Configure.h b/Configure.h index e553f38..f5313df 100644 --- a/Configure.h +++ b/Configure.h @@ -32,10 +32,13 @@ public: bool ReadData(const std::string &path); int GetGain(EGainType gt) const; std::string GetTCMods(void) const { return tcmods; } + std::string GetAddress(void) const { return address; } + unsigned GetPort(void) const { return port; } private: // CFGDATA data; - std::string tcmods; + std::string tcmods, address; + uint16_t port; int dstar_in, dstar_out, dmr_in, dmr_out, usrp_tx, usrp_rx; int getSigned(const std::string &key, const std::string &value) const; diff --git a/Controller.cpp b/Controller.cpp index ad8cf95..1865ee9 100644 --- a/Controller.cpp +++ b/Controller.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef USE_SW_AMBE2 #include #endif @@ -46,7 +47,7 @@ bool CController::Start() usrp_rx_num = calcNumerator(g_Conf.GetGain(EGainType::usrprx)); usrp_tx_num = calcNumerator(g_Conf.GetGain(EGainType::usrptx)); - if (InitVocoders() || reader.Open(REF2TC)) + if (InitVocoders() || tcClient.Initialize(g_Conf.GetAddress(), g_Conf.GetTCMods(), g_Conf.GetPort())) { keep_running = false; return true; @@ -70,7 +71,7 @@ void CController::Stop() if (c2Future.valid()) c2Future.get(); - reader.Close(); + tcClient.Close(); dstar_device->CloseDevice(); dmrsf_device->CloseDevice(); dstar_device.reset(); @@ -249,39 +250,42 @@ void CController::ReadReflectorThread() { while (keep_running) { - STCPacket tcpack; + std::queue> queue; // wait up to 100 ms to read something on the unix port - if (reader.Receive(&tcpack, 100)) + if (tcClient.Receive(queue, 100)) { - // create a shared pointer to a new packet - // there is only one CTranscoderPacket created for each new STCPacket received from the reflector - auto packet = std::make_shared(tcpack); - - switch (packet->GetCodecIn()) + while (! queue.empty()) { - case ECodecType::dstar: - dstar_device->AddPacket(packet); - break; - case ECodecType::dmr: -#ifdef USE_SW_AMBE2 - swambe2_queue.push(packet); -#else - dmrsf_device->AddPacket(packet); -#endif - break; - case ECodecType::p25: - imbe_queue.push(packet); - break; - case ECodecType::usrp: - usrp_queue.push(packet); - break; - case ECodecType::c2_1600: - case ECodecType::c2_3200: - codec2_queue.push(packet); - break; - default: - Dump(packet, "ERROR: Received a reflector packet with unknown Codec:"); - break; + // create a shared pointer to a new packet + // there is only one CTranscoderPacket created for each new STCPacket received from the reflector + auto packet = std::make_shared(*queue.front()); + queue.pop(); + switch (packet->GetCodecIn()) + { + case ECodecType::dstar: + dstar_device->AddPacket(packet); + break; + case ECodecType::dmr: + #ifdef USE_SW_AMBE2 + swambe2_queue.push(packet); + #else + dmrsf_device->AddPacket(packet); + #endif + break; + case ECodecType::p25: + imbe_queue.push(packet); + break; + case ECodecType::usrp: + usrp_queue.push(packet); + break; + case ECodecType::c2_1600: + case ECodecType::c2_3200: + codec2_queue.push(packet); + break; + default: + Dump(packet, "ERROR: Received a reflector packet with unknown Codec:"); + break; + } } } } @@ -595,14 +599,8 @@ void CController::ProcessUSRPThread() void CController::SendToReflector(std::shared_ptr packet) { - // open a socket to the reflector channel - CUnixDgramWriter socket; - std::string name(TC2REF); - name.append(1, packet->GetModule()); - socket.SetUp(name.c_str()); // send the packet over the socket - socket.Send(packet->GetTCPacket()); - // the socket will automatically close after sending + tcClient.Send(packet->GetTCPacket()); packet->Sent(); } diff --git a/Controller.h b/Controller.h index 0b65473..10555b8 100644 --- a/Controller.h +++ b/Controller.h @@ -29,7 +29,7 @@ #include "codec2.h" #include "DV3000.h" #include "DV3003.h" -#include "UnixDgramSocket.h" +#include "TCSocket.h" class CController { @@ -48,8 +48,7 @@ protected: std::future reflectorFuture, c2Future, imbeFuture, usrpFuture; std::unordered_map audio_store; std::unordered_map data_store; - CUnixDgramReader reader; - CUnixDgramWriter writer; + CTCClient tcClient; std::unordered_map> c2_16, c2_32; std::unique_ptr dstar_device, dmrsf_device; diff --git a/IP.cpp b/IP.cpp new file mode 120000 index 0000000..0d0f0e2 --- /dev/null +++ b/IP.cpp @@ -0,0 +1 @@ +../urfd/reflector/IP.cpp \ No newline at end of file diff --git a/IP.h b/IP.h new file mode 120000 index 0000000..d6ec9ce --- /dev/null +++ b/IP.h @@ -0,0 +1 @@ +../urfd/reflector/IP.h \ No newline at end of file diff --git a/Makefile b/Makefile index b67209f..541c745 100644 --- a/Makefile +++ b/Makefile @@ -5,9 +5,9 @@ include tcd.mk GCC = g++ ifeq ($(debug), true) -CFLAGS = -ggdb3 -W -Werror -Icodec2 -MMD -MD -std=c++11 +CFLAGS = -ggdb3 -W -Werror -Icodec2 -MMD -MD -std=c++17 else -CFLAGS = -W -Werror -Icodec2 -MMD -MD -std=c++11 +CFLAGS = -W -Werror -Icodec2 -MMD -MD -std=c++17 endif ifeq ($(swambe2), true) diff --git a/README.md b/README.md index d8a34ba..21ca73a 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Currently, this program must be run locally with its paired URF reflector. Remot Only systemd-based operating systems are supported. Debian or Ubuntu is recommended. If you want to install this on a non-systemd based OS, you are on your own. Also, by default, *tcd* is built without gdb support. -The P25 IMBE software vocoder library is available [here](https://github.com/nostar/imbe_vocoder). See its README.md file for instructions for compiling and installating this library. +The P25 IMBE software vocoder library is available [here](https://github.com/nostar/imbe_vocoder). See its README.md file for instructions for compiling and installing this library. If you are running tcd on an ARM-base processor, you can opt to use a software-based vocoder library available [here](https://github.com/nostar/md380_vocoder) for DMR/YSF vocoding. This library is used for the AMBE+2 (DMR/YSF/NXDN) codec. If you are going to use this library, *tcd* must run on an ARM platform like a RPi. Using this software solution means that you only need one DVSI device to handle D-Star vocoding. diff --git a/TCSocket.cpp b/TCSocket.cpp new file mode 120000 index 0000000..7b6bde0 --- /dev/null +++ b/TCSocket.cpp @@ -0,0 +1 @@ +../urfd/reflector/TCSocket.cpp \ No newline at end of file diff --git a/TCSocket.h b/TCSocket.h new file mode 120000 index 0000000..55b7cbb --- /dev/null +++ b/TCSocket.h @@ -0,0 +1 @@ +../urfd/reflector/TCSocket.h \ No newline at end of file diff --git a/UnixDgramSocket.cpp b/UnixDgramSocket.cpp deleted file mode 120000 index ac38194..0000000 --- a/UnixDgramSocket.cpp +++ /dev/null @@ -1 +0,0 @@ -../urfd/reflector/UnixDgramSocket.cpp \ No newline at end of file diff --git a/UnixDgramSocket.h b/UnixDgramSocket.h deleted file mode 120000 index e0b3691..0000000 --- a/UnixDgramSocket.h +++ /dev/null @@ -1 +0,0 @@ -../urfd/reflector/UnixDgramSocket.h \ No newline at end of file diff --git a/config/tcd.ini b/config/tcd.ini index 15f68a4..cee1602 100644 --- a/config/tcd.ini +++ b/config/tcd.ini @@ -2,10 +2,13 @@ # # this is a comment -# VERY IMPORTANT: This need to be idential to the same line in the urfd ini file! +Port = 10100 +ServerAddress = 127.0.0.1 +# VERY IMPORTANT: This need to be idential to the same line in [Transcder] section of the urfd ini file! # This will either be a single module (for DVSI-3000), or # up to three modules (for DVSI-3003). -Transcoded = A +Modules = A + # All gain values are in dB. # Gain values are limited to -24 to +24. Typical values will usually be less.