Add integrated USRP reflector. Currently a single client (like an AllStar node) is defined in Main.h

pull/8/head
Doug McLain 3 years ago
parent 8110a3c64c
commit cfb58bc237

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

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

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

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

Loading…
Cancel
Save

Powered by TurnKey Linux.