From cfb58bc237c1b0fdf0d9ec842902962cb91df0e2 Mon Sep 17 00:00:00 2001 From: Doug McLain Date: Sat, 7 Jan 2023 17:56:36 -0500 Subject: [PATCH] Add integrated USRP reflector. Currently a single client (like an AllStar node) is defined in Main.h --- reflector/DVFramePacket.cpp | 26 ++- reflector/DVFramePacket.h | 2 + reflector/DVHeaderPacket.cpp | 15 ++ reflector/DVHeaderPacket.h | 1 + reflector/Main.h | 16 +- reflector/Makefile | 2 +- reflector/P25Protocol.cpp | 6 +- reflector/Packet.cpp | 6 +- reflector/Packet.h | 2 +- reflector/Protocols.cpp | 5 + reflector/TCPacketDef.h | 3 +- reflector/USRPClient.cpp | 47 +++++ reflector/USRPClient.h | 41 ++++ reflector/USRPProtocol.cpp | 358 +++++++++++++++++++++++++++++++++++ reflector/USRPProtocol.h | 75 ++++++++ reflector/YSFProtocol.cpp | 1 - 16 files changed, 595 insertions(+), 11 deletions(-) create mode 100644 reflector/USRPClient.cpp create mode 100644 reflector/USRPClient.h create mode 100644 reflector/USRPProtocol.cpp create mode 100644 reflector/USRPProtocol.h diff --git a/reflector/DVFramePacket.cpp b/reflector/DVFramePacket.cpp index eb58f6c..0f51d1b 100644 --- a/reflector/DVFramePacket.cpp +++ b/reflector/DVFramePacket.cpp @@ -29,6 +29,7 @@ CDvFramePacket::CDvFramePacket() memset(m_uiDvSync, 0, 7); memset(m_TCPack.m17, 0, 16); memset(m_TCPack.p25, 0, 11); + memset(m_TCPack.usrp, 0, 320); memset(m_Nonce, 0, 14); m_TCPack.codec_in = ECodecType::none; }; @@ -43,6 +44,7 @@ CDvFramePacket::CDvFramePacket(const SDStarFrame *dvframe, uint16_t sid, uint8_t memset(m_uiDvSync, 0, 7); memset(m_TCPack.m17, 0, 16); memset(m_TCPack.p25, 0, 11); + memset(m_TCPack.usrp, 0, 320); memset(m_Nonce, 0, 14); m_TCPack.codec_in = ECodecType::dstar; } @@ -57,6 +59,7 @@ CDvFramePacket::CDvFramePacket(const uint8_t *ambe, const uint8_t *sync, uint16_ memset(m_uiDvData, 0, 3); memset(m_TCPack.m17, 0, 16); memset(m_TCPack.p25, 0, 11); + memset(m_TCPack.usrp, 0, 320); memset(m_Nonce, 0, 14); m_TCPack.codec_in = ECodecType::dmr; } @@ -71,6 +74,7 @@ CDvFramePacket::CDvFramePacket(const uint8_t *ambe, uint16_t sid, uint8_t pid, u memset(m_uiDvData, 0, 3); memset(m_TCPack.m17, 0, 16); memset(m_TCPack.p25, 0, 11); + memset(m_TCPack.usrp, 0, 320); memset(m_Nonce, 0, 14); m_TCPack.codec_in = ECodecType::dmr; uint8_t c[12]; @@ -101,6 +105,7 @@ CDvFramePacket::CDvFramePacket(const CM17Packet &m17) : CPacket(m17) memcpy(m_TCPack.m17, m17.GetPayload(), 16); memcpy(m_Nonce, m17.GetNonce(), 14); memset(m_TCPack.p25, 0, 11); + memset(m_TCPack.usrp, 0, 320); switch (0x6U & m17.GetFrameType()) { case 0x4U: @@ -117,7 +122,7 @@ CDvFramePacket::CDvFramePacket(const CM17Packet &m17) : CPacket(m17) // p25 constructor CDvFramePacket::CDvFramePacket(const uint8_t *imbe, uint16_t streamid, bool islast) - : CPacket(streamid, islast) + : CPacket(streamid, false, islast) { memcpy(m_TCPack.p25, imbe, 11); memset(m_TCPack.dmr, 0, 9); @@ -125,10 +130,27 @@ CDvFramePacket::CDvFramePacket(const uint8_t *imbe, uint16_t streamid, bool isla memset(m_TCPack.dstar, 0, 9); memset(m_uiDvData, 0, 3); memset(m_TCPack.m17, 0, 16); + memset(m_TCPack.usrp, 0, 320); memset(m_Nonce, 0, 14); m_TCPack.codec_in = ECodecType::p25; } +// usrp constructor +CDvFramePacket::CDvFramePacket(const int16_t *usrp, uint16_t streamid, bool islast) + : CPacket(streamid, true, islast) +{ + for(int i = 0; i < 160; ++i){ + m_TCPack.usrp[i] = usrp[i]; + } + memset(m_TCPack.p25, 0, 11); + memset(m_TCPack.dmr, 0, 9); + memset(m_uiDvSync, 0, 7); + memset(m_TCPack.dstar, 0, 9); + memset(m_uiDvData, 0, 3); + memset(m_TCPack.m17, 0, 16); + memset(m_Nonce, 0, 14); + m_TCPack.codec_in = ECodecType::usrp; +} // Network unsigned int CDvFramePacket::GetNetworkSize() @@ -200,6 +222,8 @@ const uint8_t *CDvFramePacket::GetCodecData(ECodecType type) const return m_TCPack.m17; case ECodecType::p25: return m_TCPack.p25; + case ECodecType::usrp: + return (uint8_t*)m_TCPack.usrp; default: return nullptr; } diff --git a/reflector/DVFramePacket.h b/reflector/DVFramePacket.h index 26d7a1c..1a3fb56 100644 --- a/reflector/DVFramePacket.h +++ b/reflector/DVFramePacket.h @@ -53,6 +53,8 @@ public: CDvFramePacket(const CM17Packet &m17); // P25 Frame CDvFramePacket(const uint8_t *imbe, uint16_t streamid, bool islast); + // USRP Frame + CDvFramePacket(const int16_t *usrp, uint16_t streamid, bool islast); // URF Network CDvFramePacket(const CBuffer &buf); static unsigned int GetNetworkSize(); diff --git a/reflector/DVHeaderPacket.cpp b/reflector/DVHeaderPacket.cpp index d9fd865..ab47c3b 100644 --- a/reflector/DVHeaderPacket.cpp +++ b/reflector/DVHeaderPacket.cpp @@ -138,6 +138,21 @@ CDvHeaderPacket::CDvHeaderPacket(const CCallsign &my, const CCallsign &ur, const m_csMY = my; } +// P25 / USRP constructor + +CDvHeaderPacket::CDvHeaderPacket(const CCallsign &my, const CCallsign &ur, const CCallsign &rpt1, const CCallsign &rpt2, uint16_t sid, bool usrp) + : CPacket(sid, usrp, false) +{ + m_uiFlag1 = 0; + m_uiFlag2 = 0; + m_uiFlag3 = 0; + m_uiCrc = 0; + m_csUR = ur; + m_csRPT1 = rpt1; + m_csRPT2 = rpt2; + m_csMY = my; +} + // M17 CDvHeaderPacket::CDvHeaderPacket(const CM17Packet &m17) : CPacket(m17) diff --git a/reflector/DVHeaderPacket.h b/reflector/DVHeaderPacket.h index 75b70ee..2a6a8cd 100644 --- a/reflector/DVHeaderPacket.h +++ b/reflector/DVHeaderPacket.h @@ -57,6 +57,7 @@ public: CDvHeaderPacket(const struct dstar_header *, uint16_t, uint8_t); CDvHeaderPacket(uint32_t, const CCallsign &, const CCallsign &, const CCallsign &, uint16_t, uint8_t, uint8_t); CDvHeaderPacket(const CCallsign &, const CCallsign &, const CCallsign &, const CCallsign &, uint16_t, uint8_t); + CDvHeaderPacket(const CCallsign &, const CCallsign &, const CCallsign &, const CCallsign &, uint16_t, bool); CDvHeaderPacket(const CM17Packet &); // network diff --git a/reflector/Main.h b/reflector/Main.h index 78f4c87..ef9a373 100644 --- a/reflector/Main.h +++ b/reflector/Main.h @@ -51,6 +51,7 @@ #define XLX_IPV4 true #define M17_IPV4 true #define P25_IPV4 true +#define USRP_IPV4 true #define URF_IPV4 true #define DSTAR_IPV6 false @@ -59,6 +60,7 @@ #define XLX_IPV6 false #define M17_IPV6 true #define P25_IPV6 false +#define USRP_IPV6 false #define URF_IPV6 true // version ----------------------------------------------------- @@ -79,9 +81,9 @@ // protocols --------------------------------------------------- #ifndef NO_G3 -enum class EProtocol { any, none, dextra, dplus, dcs, bm, urf, dmrplus, dmrmmdvm, ysf, m17, g3, p25 }; +enum class EProtocol { any, none, dextra, dplus, dcs, bm, urf, dmrplus, dmrmmdvm, ysf, m17, g3, p25, usrp }; #else -enum class EProtocol { any, none, dextra, dplus, dcs, bm, urf, dmrplus, dmrmmdvm, ysf, m17, p25 }; +enum class EProtocol { any, none, dextra, dplus, dcs, bm, urf, dmrplus, dmrmmdvm, ysf, m17, p25, usrp }; #endif // DExtra @@ -154,6 +156,16 @@ enum class EProtocol { any, none, dextra, dplus, dcs, bm, urf, dmrplus, dmrmmdvm #define P25_AUTOLINK_ENABLE 1 // 1 = enable, 0 = disable auto-link #define P25_AUTOLINK_MODULE 'A' // module for client to auto-link to +// USRP +#define USRP_NODE_ADDRESS "192.168.1.5" +#define USRP_RXPORT 34003 // UDP port +#define USRP_TXPORT 32003 // UDP port +#define USRP_KEEPALIVE_PERIOD 1 // in seconds +#define USRP_KEEPALIVE_TIMEOUT (USRP_KEEPALIVE_PERIOD*10) // in seconds +#define USRP_AUTOLINK_ENABLE 1 // 1 = enable, 0 = disable auto-link +#define USRP_AUTOLINK_MODULE 'A' // module for client to auto-link to +#define USRP_DEFAULT_CALLSIGN "ALLSTAR" + #ifndef NO_G3 // G3 Terminal #define G3_PRESENCE_PORT 12346 // UDP port diff --git a/reflector/Makefile b/reflector/Makefile index 26b9c46..79e04a9 100644 --- a/reflector/Makefile +++ b/reflector/Makefile @@ -35,7 +35,7 @@ endif LDFLAGS=-pthread -URFSRCS = Buffer.cpp Callsign.cpp CallsignList.cpp CallsignListItem.cpp Client.cpp Clients.cpp DCSClient.cpp DCSProtocol.cpp DExtraClient.cpp DExtraPeer.cpp DExtraProtocol.cpp DPlusClient.cpp DPlusProtocol.cpp DVFramePacket.cpp DVHeaderPacket.cpp GateKeeper.cpp IP.cpp Notification.cpp Packet.cpp PacketStream.cpp PeerCallsignList.cpp Peer.cpp Peers.cpp Protocol.cpp Protocols.cpp Reflector.cpp SEProtocol.cpp UDPSocket.cpp User.cpp Users.cpp Version.cpp Main.cpp BMClient.cpp BMPeer.cpp BMProtocol.cpp BPTC19696.cpp CRC.cpp DMRIdDir.cpp DMRIdDirFile.cpp DMRIdDirHttp.cpp DMRMMDVMClient.cpp DMRMMDVMProtocol.cpp DMRPlusClient.cpp DMRPlusProtocol.cpp Golay2087.cpp Golay24128.cpp Hamming.cpp M17Client.cpp M17CRC.cpp M17Packet.cpp M17Client.cpp M17Protocol.cpp P25Client.cpp P25Protocol.cpp QR1676.cpp RS129.cpp Semaphore.cpp Utils.cpp WiresXCmd.cpp WiresXCmdHandler.cpp WiresXInfo.cpp URFClient.cpp URFProtocol.cpp URFPeer.cpp YSFClient.cpp YSFConvolution.cpp YSFFich.cpp YSFNode.cpp YSFNodeDir.cpp YSFNodeDirFile.cpp YSFNodeDirHttp.cpp YSFPayload.cpp YSFProtocol.cpp YSFUtils.cpp +URFSRCS = Buffer.cpp Callsign.cpp CallsignList.cpp CallsignListItem.cpp Client.cpp Clients.cpp DCSClient.cpp DCSProtocol.cpp DExtraClient.cpp DExtraPeer.cpp DExtraProtocol.cpp DPlusClient.cpp DPlusProtocol.cpp DVFramePacket.cpp DVHeaderPacket.cpp GateKeeper.cpp IP.cpp Notification.cpp Packet.cpp PacketStream.cpp PeerCallsignList.cpp Peer.cpp Peers.cpp Protocol.cpp Protocols.cpp Reflector.cpp SEProtocol.cpp UDPSocket.cpp User.cpp Users.cpp Version.cpp Main.cpp BMClient.cpp BMPeer.cpp BMProtocol.cpp BPTC19696.cpp CRC.cpp DMRIdDir.cpp DMRIdDirFile.cpp DMRIdDirHttp.cpp DMRMMDVMClient.cpp DMRMMDVMProtocol.cpp DMRPlusClient.cpp DMRPlusProtocol.cpp Golay2087.cpp Golay24128.cpp Hamming.cpp M17Client.cpp M17CRC.cpp M17Packet.cpp M17Client.cpp M17Protocol.cpp P25Client.cpp P25Protocol.cpp QR1676.cpp RS129.cpp Semaphore.cpp USRPClient.cpp USRPProtocol.cpp Utils.cpp WiresXCmd.cpp WiresXCmdHandler.cpp WiresXInfo.cpp URFClient.cpp URFProtocol.cpp URFPeer.cpp YSFClient.cpp YSFConvolution.cpp YSFFich.cpp YSFNode.cpp YSFNodeDir.cpp YSFNodeDirFile.cpp YSFNodeDirHttp.cpp YSFPayload.cpp YSFProtocol.cpp YSFUtils.cpp G3SRCS = G3Client.cpp G3Protocol.cpp RawSocket.cpp UDPMsgSocket.cpp diff --git a/reflector/P25Protocol.cpp b/reflector/P25Protocol.cpp index e154f92..1f75e5a 100644 --- a/reflector/P25Protocol.cpp +++ b/reflector/P25Protocol.cpp @@ -377,7 +377,7 @@ bool CP25Protocol::IsValidDvHeaderPacket(const CIp &Ip, const CBuffer &Buffer, s CCallsign rpt2 = m_ReflectorCallsign; rpt1.SetCSModule(P25_MODULE_ID); rpt2.SetCSModule(' '); - header = std::unique_ptr(new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, m_uiStreamId, 0)); + header = std::unique_ptr(new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, m_uiStreamId, false)); } return true; } @@ -389,6 +389,10 @@ void CP25Protocol::EncodeP25Packet(const CDvHeaderPacket &Header, const CDvFrame uint32_t uiSrcId = Header.GetMyCallsign().GetDmrid(); uint32_t uiRptrId = Header.GetRpt1Callsign().GetDmrid(); + if(uiSrcId == 0){ + uiSrcId = DMRMMDVM_DEFAULTID; + } + if(islast) { Buffer.resize(17); diff --git a/reflector/Packet.cpp b/reflector/Packet.cpp index 2ac6d42..03d5c73 100644 --- a/reflector/Packet.cpp +++ b/reflector/Packet.cpp @@ -138,8 +138,8 @@ CPacket::CPacket(uint16_t sid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysffri m_bLastPacket = lastpacket; } -// p25 constructor -CPacket::CPacket(uint16_t sid, bool lastpacket) +// p25 / usrp constructor +CPacket::CPacket(uint16_t sid, bool isusrp, bool lastpacket) { m_uiStreamId = sid; m_uiDstarPacketId = 0xFF; @@ -151,7 +151,7 @@ CPacket::CPacket(uint16_t sid, bool lastpacket) m_uiM17FrameNumber = 0xFFFFFFFFU; m_cModule = ' '; m_eOrigin = EOrigin::local; - m_eCodecIn = ECodecType::p25; + isusrp ? m_eCodecIn = ECodecType::usrp : ECodecType::p25; m_bLastPacket = lastpacket; }; diff --git a/reflector/Packet.h b/reflector/Packet.h index f48370f..a8bb06f 100644 --- a/reflector/Packet.h +++ b/reflector/Packet.h @@ -34,7 +34,7 @@ public: CPacket(const CBuffer &Buffer); CPacket(uint16_t sid, uint8_t dstarpid); CPacket(uint16_t sid, uint8_t dmrpid, uint8_t dmrsubpid, bool lastpacket); - CPacket(uint16_t sid, bool lastpacket); + CPacket(uint16_t sid, bool isusrp, bool lastpacket); CPacket(uint16_t sid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysfsubpidmax, bool lastpacket); CPacket(uint16_t sid, uint8_t dstarpid, uint8_t dmrpid, uint8_t dmrsubpid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysfsubpidmax, ECodecType, bool lastpacket); CPacket(const CM17Packet &); diff --git a/reflector/Protocols.cpp b/reflector/Protocols.cpp index facda65..9168303 100644 --- a/reflector/Protocols.cpp +++ b/reflector/Protocols.cpp @@ -27,6 +27,7 @@ #include "M17Protocol.h" #include "BMProtocol.h" #include "P25Protocol.h" +#include "USRPProtocol.h" #ifndef NO_G3 #include "G3Protocol.h" #endif @@ -82,6 +83,10 @@ bool CProtocols::Init(void) m_Protocols.emplace_back(std::unique_ptr(new CP25Protocol)); if (! m_Protocols.back()->Initialize("P25", EProtocol::p25, P25_PORT, P25_IPV4, P25_IPV6)) return false; + + m_Protocols.emplace_back(std::unique_ptr(new CUSRPProtocol)); + if (! m_Protocols.back()->Initialize("USRP", EProtocol::usrp, USRP_RXPORT, USRP_IPV4, USRP_IPV6)) + return false; m_Protocols.emplace_back(std::unique_ptr(new CURFProtocol)); if (! m_Protocols.back()->Initialize("URF", EProtocol::urf, URF_PORT, URF_IPV4, URF_IPV6)) diff --git a/reflector/TCPacketDef.h b/reflector/TCPacketDef.h index 1585842..43abf5c 100644 --- a/reflector/TCPacketDef.h +++ b/reflector/TCPacketDef.h @@ -23,7 +23,7 @@ #define TC2REF "TC2URFMod" #define REF2TC "URF2TC" -enum class ECodecType : std::uint8_t { none = 0, dstar = 1, dmr = 2, c2_1600 = 3, c2_3200 = 4, p25 = 5 }; +enum class ECodecType : std::uint8_t { none = 0, dstar = 1, dmr = 2, c2_1600 = 3, c2_3200 = 4, p25 = 5, usrp = 6 }; using STCPacket = struct tcpacket_tag { CTimer rt_timer; @@ -36,4 +36,5 @@ using STCPacket = struct tcpacket_tag { uint8_t dmr[9]; uint8_t m17[16]; uint8_t p25[11]; + int16_t usrp[160]; }; diff --git a/reflector/USRPClient.cpp b/reflector/USRPClient.cpp new file mode 100644 index 0000000..f75c866 --- /dev/null +++ b/reflector/USRPClient.cpp @@ -0,0 +1,47 @@ +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. + +// urfd -- The universal reflector +// Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2021 Doug McLain AD8DP +// +// 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 3 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, see . + +#include "Main.h" +#include "USRPClient.h" + + +//////////////////////////////////////////////////////////////////////////////////////// +// constructors + +CUSRPClient::CUSRPClient() +{ +} + +CUSRPClient::CUSRPClient(const CCallsign &callsign, const CIp &ip, char reflectorModule) + : CClient(callsign, ip, reflectorModule) +{ +} + +CUSRPClient::CUSRPClient(const CUSRPClient &client) + : CClient(client) +{ +} + +//////////////////////////////////////////////////////////////////////////////////////// +// status + +bool CUSRPClient::IsAlive(void) const +{ + return (m_LastKeepaliveTime.time() < USRP_KEEPALIVE_TIMEOUT); +} diff --git a/reflector/USRPClient.h b/reflector/USRPClient.h new file mode 100644 index 0000000..2157d2b --- /dev/null +++ b/reflector/USRPClient.h @@ -0,0 +1,41 @@ +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. + +// urfd -- The universal reflector +// Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2021 Doug McLain AD8DP +// +// 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 3 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, see . + +#pragma once + +#include "Client.h" +class CUSRPClient : public CClient +{ +public: + // constructors + CUSRPClient(); + CUSRPClient(const CCallsign &, const CIp &, char = ' '); + CUSRPClient(const CUSRPClient &); + + // destructor + virtual ~CUSRPClient() {}; + + // identity + EProtocol GetProtocol(void) const { return EProtocol::usrp; } + const char *GetProtocolName(void) const { return "USRP"; } + bool IsNode(void) const { return true; } + + // status + bool IsAlive(void) const; +}; diff --git a/reflector/USRPProtocol.cpp b/reflector/USRPProtocol.cpp new file mode 100644 index 0000000..dde6bb2 --- /dev/null +++ b/reflector/USRPProtocol.cpp @@ -0,0 +1,358 @@ +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. + +// urfd -- The universal reflector +// Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2021 Doug McLain AD8DP +// +// 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 3 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, see . + +#include "Main.h" +#include +#include "USRPClient.h" +#include "USRPProtocol.h" + +#include "Reflector.h" +#include "GateKeeper.h" + +const uint8_t USRP_TYPE_VOICE = 0; +const uint8_t USRP_TYPE_TEXT = 2; + +const uint8_t USRP_KEYUP_FALSE = 0; +const uint8_t USRP_KEYUP_TRUE = 1; + +const uint8_t TLV_TAG_SET_INFO = 8; + +//////////////////////////////////////////////////////////////////////////////////////// +// operation + +bool CUSRPProtocol::Initialize(const char *type, const EProtocol ptype, const uint16_t port, const bool has_ipv4, const bool has_ipv6) +{ + m_uiStreamId = 0; + // base class + if (! CProtocol::Initialize(type, ptype, port, has_ipv4, has_ipv6)) + return false; + + CIp Ip(AF_INET, USRP_TXPORT, USRP_NODE_ADDRESS); + CCallsign cs(USRP_DEFAULT_CALLSIGN); + CClients *clients = g_Reflector.GetClients(); + auto newclient = std::make_shared(cs, Ip); +#if USRP_AUTOLINK_ENABLE + newclient->SetReflectorModule(USRP_AUTOLINK_MODULE); +#endif + clients->AddClient(newclient); + g_Reflector.ReleaseClients(); + // update time + m_LastKeepaliveTime.start(); + + // done + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////////////// +// task + +void CUSRPProtocol::Task(void) +{ + CBuffer Buffer; + CIp Ip; + CCallsign Callsign; + char ToLinkModule; + std::unique_ptr Header; + std::unique_ptr Frame; + + // handle incoming packets +#if USRP_IPV6==true +#if USRP_IPV4==true + if ( ReceiveDS(Buffer, Ip, 20) ) +#else + if ( Receive6(Buffer, Ip, 20) ) +#endif +#else + if ( Receive4(Buffer, Ip, 20) ) +#endif + { + // crack the packet + if ( IsValidDvPacket(Ip, Buffer, Header, Frame) ) + { + // push the packet + OnDvFramePacketIn(Frame, &Ip); + } + else if( IsValidDvHeaderPacket(Ip, Buffer, Header) ) + { + // callsign muted? + if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::usrp) ) + { + OnDvHeaderPacketIn(Header, Ip); + } + } + else if ( IsValidDvLastPacket(Buffer) ) + { + // do nothing + std::cout << "USRP last frame" << std::endl; + } + else + { + // invalid packet + std::string title("Unknown USRP packet from "); + title += Ip.GetAddress(); + Buffer.Dump(title); + } + } + + // handle end of streaming timeout + CheckStreamsTimeout(); + + // handle queue from reflector + HandleQueue(); + + // keep client alive + if ( m_LastKeepaliveTime.time() > USRP_KEEPALIVE_PERIOD ) + { + // + HandleKeepalives(); + + // update time + m_LastKeepaliveTime.start(); + } +} + +//////////////////////////////////////////////////////////////////////////////////////// +// streams helpers + +void CUSRPProtocol::OnDvHeaderPacketIn(std::unique_ptr &Header, const CIp &Ip) +{ + // find the stream + auto stream = GetStream(Header->GetStreamId(), &Ip); + if ( stream ) + { + // stream already open + // skip packet, but tickle the stream + stream->Tickle(); + } + else + { + // no stream open yet, open a new one + CCallsign my(Header->GetMyCallsign()); + CCallsign rpt1(Header->GetRpt1Callsign()); + CCallsign rpt2(Header->GetRpt2Callsign()); + + // find this client + std::shared_ptrclient = g_Reflector.GetClients()->FindClient(Ip, EProtocol::usrp); + if ( client ) + { + // get client callsign + rpt1 = client->GetCallsign(); + auto m = client->GetReflectorModule(); + Header->SetRpt2Module(m); + rpt2.SetCSModule(m); + // and try to open the stream + if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr ) + { + // keep the handle + m_Streams[stream->GetStreamId()] = stream; + } + } + // release + g_Reflector.ReleaseClients(); + + // update last heard + g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); + g_Reflector.ReleaseUsers(); + } +} + +//////////////////////////////////////////////////////////////////////////////////////// +// queue helper + +void CUSRPProtocol::HandleQueue(void) +{ + m_Queue.Lock(); + while ( !m_Queue.empty() ) + { + // get the packet + auto packet = m_Queue.pop(); + + // get our sender's id + const auto module = packet->GetPacketModule(); + CBuffer buffer; + + // check if it's header and update cache + if ( packet->IsDvHeader() ) + { + // this relies on queue feeder setting valid module id + // m_StreamsCache[module] will be created if it doesn't exist + m_StreamsCache[module].m_dvHeader = CDvHeaderPacket((const CDvHeaderPacket &)*packet.get()); + m_StreamsCache[module].m_iSeqCounter = 0; + EncodeUSRPHeaderPacket(m_StreamsCache[module].m_dvHeader, m_StreamsCache[module].m_iSeqCounter++, buffer); + } + else if ( packet->IsDvFrame() ) + { + EncodeUSRPPacket(m_StreamsCache[module].m_dvHeader, (const CDvFramePacket &)*packet.get(), m_StreamsCache[module].m_iSeqCounter++, buffer, packet->IsLastPacket()); + } + + // send it + if ( buffer.size() > 0 ) + { + // and push it to all our clients linked to the module and who are not streaming in + CClients *clients = g_Reflector.GetClients(); + auto it = clients->begin(); + std::shared_ptrclient = nullptr; + while ( (client = clients->FindNextClient(EProtocol::usrp, it)) != nullptr ) + { + // is this client busy ? + if ( !client->IsAMaster() && (client->GetReflectorModule() == module) ) + { + // no, send the packet + Send(buffer, client->GetIp()); + } + } + g_Reflector.ReleaseClients(); + } + } + m_Queue.Unlock(); +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// packet decoding helpers + +bool CUSRPProtocol::IsValidDvPacket(const CIp &Ip, const CBuffer &Buffer, std::unique_ptr &header, std::unique_ptr &frame) +{ + if(!memcmp(Buffer.data(), "USRP", 4) && (Buffer.size() == 352) && (Buffer.data()[20] == USRP_TYPE_VOICE) && (Buffer.data()[15] == USRP_KEYUP_TRUE) ) + { + auto stream = GetStream(m_uiStreamId, &Ip); + if ( !stream ) + { + m_uiStreamId = static_cast(::rand()); + CCallsign csMY = CCallsign(USRP_DEFAULT_CALLSIGN); + CCallsign rpt1 = CCallsign(USRP_DEFAULT_CALLSIGN); + CCallsign rpt2 = m_ReflectorCallsign; + rpt1.SetCSModule(USRP_MODULE_ID); + rpt2.SetCSModule(' '); + header = std::unique_ptr(new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, m_uiStreamId, true)); + OnDvHeaderPacketIn(header, Ip); + } + + int16_t pcm[160]; + for(int i = 0; i < 160; ++i){ + pcm[i] = (Buffer.data()[32+(i*2)+1] << 8) | Buffer.data()[32+(i*2)]; + } + + frame = std::unique_ptr(new CDvFramePacket(pcm, m_uiStreamId, false)); + return true; + } + return false; +} + +bool CUSRPProtocol::IsValidDvHeaderPacket(const CIp &Ip, const CBuffer &Buffer, std::unique_ptr &header) +{ + if(!memcmp(Buffer.data(), "USRP", 4) && (Buffer.size() == 352) && (Buffer.data()[20] == USRP_TYPE_TEXT) && (Buffer.data()[32] == TLV_TAG_SET_INFO) ){ + auto stream = GetStream(m_uiStreamId, &Ip); + if ( !stream ) + { + uint32_t uiSrcId = ((Buffer.data()[1] << 16) | ((Buffer.data()[2] << 8) & 0xff00) | (Buffer.data()[3] & 0xff)); + m_uiStreamId = static_cast(::rand()); + CCallsign csMY = CCallsign("", uiSrcId); + CCallsign rpt1 = CCallsign("", uiSrcId); + CCallsign rpt2 = m_ReflectorCallsign; + rpt1.SetCSModule(USRP_MODULE_ID); + rpt2.SetCSModule(' '); + header = std::unique_ptr(new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, m_uiStreamId, true)); + } + return true; + } + return false; +} + +bool CUSRPProtocol::IsValidDvLastPacket(const CBuffer &Buffer) +{ + if(!memcmp(Buffer.data(), "USRP", 4) && (Buffer.size() == 32) && (Buffer.data()[15] == USRP_KEYUP_FALSE) ) + { + m_uiStreamId = 0; + return true; + } + return false; +} + +void CUSRPProtocol::EncodeUSRPHeaderPacket(const CDvHeaderPacket &Header, uint32_t iSeq, CBuffer &Buffer) const +{ + std::string cs = Header.GetMyCallsign().GetCS(); + const uint32_t cnt = htonl(iSeq); + Buffer.resize(352); + memset(Buffer.data(), 0, 352); + memcpy(Buffer.data(), "USRP", 4); + memcpy(Buffer.data() + 4, &cnt, 4); + Buffer.data()[15] = USRP_KEYUP_FALSE; + Buffer.data()[20] = USRP_TYPE_TEXT; + Buffer.data()[32] = TLV_TAG_SET_INFO; + Buffer.data()[33] = 13 + cs.size(); + memcpy(Buffer.data()+46, cs.c_str(), cs.size()); +} + +void CUSRPProtocol::EncodeUSRPPacket(const CDvHeaderPacket &Header, const CDvFramePacket &DvFrame, uint32_t iSeq, CBuffer &Buffer, bool islast) const +{ + if(islast) + { + const uint32_t cnt = htonl(iSeq); + Buffer.resize(32); + memset(Buffer.data(), 0, 32); + memcpy(Buffer.data(), "USRP", 4); + memcpy(Buffer.data() + 4, &cnt, 4); + Buffer.data()[15] = USRP_KEYUP_FALSE; + + } + else + { + std::string cs = Header.GetMyCallsign().GetCS(); + const uint32_t cnt = htonl(iSeq); + Buffer.resize(352); + memset(Buffer.data(), 0, 352); + memcpy(Buffer.data(), "USRP", 4); + memcpy(Buffer.data() + 4, &cnt, 4); + Buffer.data()[15] = USRP_KEYUP_TRUE; + memcpy(Buffer.data() + 32, DvFrame.GetCodecData(ECodecType::usrp), 320); + } +} + +//////////////////////////////////////////////////////////////////////////////////////// +// keepalive helpers + +void CUSRPProtocol::HandleKeepalives(void) +{ + // iterate on clients + CClients *clients = g_Reflector.GetClients(); + auto it = clients->begin(); + std::shared_ptrclient = nullptr; + while ( (client = clients->FindNextClient(EProtocol::usrp, it)) != nullptr ) + { + // is this client busy ? + //if ( client->IsAMaster() ) + //{ + // yes, just tickle it + client->Alive(); + //} + // check it's still with us + //else if ( !client->IsAlive() ) + //{ + // no, remove it + //std::cout << "USRP client " << client->GetCallsign() << " keepalive timeout" << std::endl; + //clients->RemoveClient(client); + //} + + } + g_Reflector.ReleaseClients(); +} + diff --git a/reflector/USRPProtocol.h b/reflector/USRPProtocol.h new file mode 100644 index 0000000..b4b2877 --- /dev/null +++ b/reflector/USRPProtocol.h @@ -0,0 +1,75 @@ +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. + +// urfd -- The universal reflector +// Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2021 Doug McLain AD8DP +// +// 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 3 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, see . + +#pragma once + +#include "Timer.h" +#include "Protocol.h" +#include "DVHeaderPacket.h" +#include "DVFramePacket.h" + +//////////////////////////////////////////////////////////////////////////////////////// +// define + +#define USRP_MODULE_ID 'B' +//////////////////////////////////////////////////////////////////////////////////////// +// class + +class CUSRPStreamCacheItem +{ +public: + CUSRPStreamCacheItem() : m_iSeqCounter(0) {} + + CDvHeaderPacket m_dvHeader; + uint32_t m_iSeqCounter; +}; + +class CUSRPProtocol : public CProtocol +{ +public: + // initialization + bool Initialize(const char *type, const EProtocol ptype, const uint16_t port, const bool has_ipv4, const bool has_ipv6); + + // task + void Task(void); + +protected: + // queue helper + void HandleQueue(void); + void HandleKeepalives(void); + + // stream helpers + void OnDvHeaderPacketIn(std::unique_ptr &, const CIp &); + + // packet decoding helpers + bool IsValidDvPacket(const CIp &, const CBuffer &, std::unique_ptr &, std::unique_ptr &); + bool IsValidDvHeaderPacket(const CIp &, const CBuffer &, std::unique_ptr &); + bool IsValidDvLastPacket(const CBuffer &); + + // packet encoding helpers + void EncodeUSRPHeaderPacket(const CDvHeaderPacket &, uint32_t, CBuffer &) const; + void EncodeUSRPPacket(const CDvHeaderPacket &, const CDvFramePacket &, uint32_t, CBuffer &Buffer, bool) const; + + // for keep alive + CTimer m_LastKeepaliveTime; + + // for queue header caches + std::unordered_map m_StreamsCache; + uint32_t m_uiStreamId; +}; diff --git a/reflector/YSFProtocol.cpp b/reflector/YSFProtocol.cpp index 558fb57..eec9bc6 100644 --- a/reflector/YSFProtocol.cpp +++ b/reflector/YSFProtocol.cpp @@ -280,7 +280,6 @@ void CYsfProtocol::OnDvHeaderPacketIn(std::unique_ptr &Header, void CYsfProtocol::HandleQueue(void) { - m_Queue.Lock(); while ( !m_Queue.empty() ) {