mirror of
https://github.com/nostar/urfd.git
synced 2026-11-08 04:19:39 +00:00
Add integrated USRP reflector. Currently a single client (like an AllStar node) is defined in Main.h
This commit is contained in:
1 parent
8110a3c64c
commit
cfb58bc237
16 files changed
+595
-11
No files matched your search
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
+14
-2
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
|
||||
@@ -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<CDvHeaderPacket>(new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, m_uiStreamId, 0));
|
||||
header = std::unique_ptr<CDvHeaderPacket>(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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -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 &);
|
||||
|
||||
@@ -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<CP25Protocol>(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<CUSRPProtocol>(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<CURFProtocol>(new CURFProtocol));
|
||||
if (! m_Protocols.back()->Initialize("URF", EProtocol::urf, URF_PORT, URF_IPV4, URF_IPV6))
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#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);
|
||||
}
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#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;
|
||||
};
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#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<CUSRPClient>(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<CDvHeaderPacket> Header;
|
||||
std::unique_ptr<CDvFramePacket> 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<CDvHeaderPacket> &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_ptr<CClient>client = 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_ptr<CClient>client = 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<CDvHeaderPacket> &header, std::unique_ptr<CDvFramePacket> &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<uint32_t>(::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<CDvHeaderPacket>(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<CDvFramePacket>(new CDvFramePacket(pcm, m_uiStreamId, false));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CUSRPProtocol::IsValidDvHeaderPacket(const CIp &Ip, const CBuffer &Buffer, std::unique_ptr<CDvHeaderPacket> &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<uint32_t>(::rand());
|
||||
CCallsign csMY = CCallsign("", uiSrcId);
|
||||
CCallsign rpt1 = CCallsign("", uiSrcId);
|
||||
CCallsign rpt2 = m_ReflectorCallsign;
|
||||
rpt1.SetCSModule(USRP_MODULE_ID);
|
||||
rpt2.SetCSModule(' ');
|
||||
header = std::unique_ptr<CDvHeaderPacket>(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_ptr<CClient>client = 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();
|
||||
}
|
||||
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#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<CDvHeaderPacket> &, const CIp &);
|
||||
|
||||
// packet decoding helpers
|
||||
bool IsValidDvPacket(const CIp &, const CBuffer &, std::unique_ptr<CDvHeaderPacket> &, std::unique_ptr<CDvFramePacket> &);
|
||||
bool IsValidDvHeaderPacket(const CIp &, const CBuffer &, std::unique_ptr<CDvHeaderPacket> &);
|
||||
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<char, CUSRPStreamCacheItem> m_StreamsCache;
|
||||
uint32_t m_uiStreamId;
|
||||
};
|
||||
@@ -280,7 +280,6 @@ void CYsfProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
|
||||
|
||||
void CYsfProtocol::HandleQueue(void)
|
||||
{
|
||||
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user