Merge remote-tracking branch 'origin/feature/issue-13-investigation' into dev

pull/23/head
Dave Behnke 1 month ago
commit 68536f3e5e

@ -58,6 +58,7 @@
#define JIPADDRESSES "IP Addresses"
#define JIPV4BINDING "IPv4Binding"
#define JIPV4EXTERNAL "IPv4External"
#define JIMRS "IMRS"
#define JIPV6BINDING "IPv6Binding"
#define JIPV6EXTERNAL "IPv6External"
#define JJSONPATH "JsonPath"
@ -192,6 +193,8 @@ bool CConfigure::ReadData(const std::string &path)
section = ESection::dextra;
else if (0 == hname.compare(JG3))
section = ESection::g3;
else if (0 == hname.compare(JIMRS))
section = ESection::imrs;
else if (0 == hname.compare(JDMRPLUS))
section = ESection::dmrplus;
else if (0 == hname.compare(JMMDVM))
@ -354,6 +357,14 @@ bool CConfigure::ReadData(const std::string &path)
else
badParam(key);
break;
case ESection::imrs:
if (0 == key.compare(JENABLE))
data[g_Keys.imrs.enable] = IS_TRUE(value[0]);
else if (0 == key.compare(JPORT))
data[g_Keys.imrs.port] = getUnsigned(value, "IMRS Port", 1024, 65535, 21110);
else
badParam(key);
break;
case ESection::dmrplus:
if (0 == key.compare(JPORT))
data[g_Keys.dmrplus.port] = getUnsigned(value, "DMRPlus Port", 1024, 65535, 8880);

@ -25,7 +25,7 @@
enum class ErrorLevel { fatal, mild };
enum class ERefreshType { file, http, both };
enum class ESection { none, names, ip, modules, urf, dplus, dextra, dcs, g3, dmrplus, mmdvm, nxdn, bm, ysf, p25, m17, usrp, dmrid, nxdnid, ysffreq, files, tc };
enum class ESection { none, names, ip, modules, urf, dplus, dextra, dcs, g3, imrs, dmrplus, mmdvm, nxdn, bm, ysf, p25, m17, usrp, dmrid, nxdnid, ysffreq, files, tc };
#define IS_TRUE(a) ((a)=='t' || (a)=='T' || (a)=='1')

@ -66,7 +66,7 @@
// protocols ---------------------------------------------------
enum class EProtocol { any, none, dextra, dplus, dcs, g3, bm, urf, dmrplus, dmrmmdvm, nxdn, p25, usrp, ysf, m17 };
enum class EProtocol { any, none, dextra, dplus, dcs, g3, imrs, bm, urf, dmrplus, dmrmmdvm, nxdn, p25, usrp, ysf, m17 };
// DExtra
#define DEXTRA_KEEPALIVE_PERIOD 3 // in seconds
@ -130,6 +130,12 @@ enum class EProtocol { any, none, dextra, dplus, dcs, g3, bm, urf, dmrplus, dmrm
#define G3_KEEPALIVE_PERIOD 10 // in seconds
#define G3_KEEPALIVE_TIMEOUT 3600 // in seconds, 1 hour
// IMRS
#define IMRS_PORT 21110 // UDP port
#define IMRS_KEEPALIVE_PERIOD 30 // in seconds
#define IMRS_KEEPALIVE_TIMEOUT (IMRS_KEEPALIVE_PERIOD*5) // in seconds
#define IMRS_DEFAULT_MODULE 'B' // default module to link in
////////////////////////////////////////////////////////////////////////////////////////
// macros

@ -0,0 +1,26 @@
#include "ImrsClient.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructors
CImrsClient::CImrsClient()
{
}
CImrsClient::CImrsClient(const CCallsign &callsign, const CIp &ip, char reflectorModule)
: CClient(callsign, ip, reflectorModule)
{
}
CImrsClient::CImrsClient(const CImrsClient &client)
: CClient(client)
{
}
////////////////////////////////////////////////////////////////////////////////////////
// status
bool CImrsClient::IsAlive(void) const
{
return (m_LastKeepaliveTime.time() < IMRS_KEEPALIVE_TIMEOUT);
}

@ -0,0 +1,18 @@
#pragma once
#include "Client.h"
////////////////////////////////////////////////////////////////////////////////////////
// class
class CImrsClient : public CClient
{
public:
// constructors
CImrsClient();
CImrsClient(const CCallsign &callsign, const CIp &ip, char reflectorModule = ' ');
CImrsClient(const CImrsClient &client);
// status
virtual bool IsAlive(void) const;
};

@ -0,0 +1,427 @@
#include <cstring>
#include <arpa/inet.h>
#include "Global.h"
#include "ImrsClient.h"
#include "ImrsProtocol.h"
#include "YSFDefines.h"
#include "YSFUtils.h"
////////////////////////////////////////////////////////////////////////////////////////
// operation
bool CImrsProtocol::Initialize(const char *type, const EProtocol ptype, const uint16_t port, const bool has_ipv4, const bool has_ipv6)
{
// base class
if (!CSEProtocol::Initialize(type, ptype, port, has_ipv4, has_ipv6))
return false;
m_Port = port;
// create our socket
CIp ip(AF_INET, m_Port, g_Configure.GetString(g_Keys.ip.ipv4bind).c_str());
if (ip.IsSet())
{
if (!m_Socket.Open(ip))
return false;
}
else
return false;
std::cout << "Listening for IMRS on " << ip << std::endl;
// start the thread
m_Future = std::async(std::launch::async, &CImrsProtocol::Thread, this);
// update time
m_LastKeepaliveTime.start();
std::cout << "Initialized IMRS Protocol" << std::endl;
return true;
}
void CImrsProtocol::Close(void)
{
// base class handles the future
CProtocol::Close();
}
////////////////////////////////////////////////////////////////////////////////////////
// task
void CImrsProtocol::Task(void)
{
CBuffer Buffer;
CIp Ip;
CCallsign Callsign;
uint32_t FirmwareVersion;
std::unique_ptr<CDvHeaderPacket> Header;
std::unique_ptr<CDvFramePacket> Frames[5];
// any incoming packet?
if (m_Socket.Receive(Buffer, Ip, 20))
{
if (IsValidPingPacket(Buffer))
{
// respond with Pong
CBuffer response;
EncodePongPacket(response);
m_Socket.Send(response, Ip);
}
else if (IsValidConnectPacket(Buffer, Callsign, FirmwareVersion))
{
std::cout << "IMRS connect request from " << Callsign << " at " << Ip << std::endl;
CClients *clients = g_Reflector.GetClients();
std::shared_ptr<CClient> client = clients->FindClient(Ip, EProtocol::imrs);
if (client == nullptr)
{
auto newclient = std::make_shared<CImrsClient>(Callsign, Ip);
newclient->SetReflectorModule(IMRS_DEFAULT_MODULE);
clients->AddClient(newclient);
}
else
{
client->Alive();
}
g_Reflector.ReleaseClients();
}
else if (IsValidDvHeaderPacket(Buffer, Header))
{
OnDvHeaderPacketIn(Header, Ip);
}
else if (IsValidDvFramePacket(Ip, Buffer, Frames))
{
// Frames are quintets
for (int i = 0; i < 5; i++)
{
if (Frames[i])
OnDvFramePacketIn(Frames[i], &Ip);
}
}
else if (IsValidDvLastFramePacket(Ip, Buffer, Frames[0]))
{
if (Frames[0])
OnDvFramePacketIn(Frames[0], &Ip);
}
}
// handle end of streaming timeout
CheckStreamsTimeout();
// handle queue from reflector
HandleQueue();
// keep alive
if (m_LastKeepaliveTime.time() > IMRS_KEEPALIVE_PERIOD)
{
HandleKeepalives();
m_LastKeepaliveTime.start();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// streams helpers
void CImrsProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header, const CIp &Ip)
{
auto stream = GetStream(Header->GetStreamId(), &Ip);
if (stream)
{
stream->Tickle();
}
else
{
CClients *clients = g_Reflector.GetClients();
std::shared_ptr<CClient> client = clients->FindClient(Ip, EProtocol::imrs);
if (client != nullptr)
{
// handle module linking by DG-ID (Rpt2Module carries this in urfd logic)
if (Header->GetRpt2Module() != client->GetReflectorModule())
{
std::cout << "IMRS client " << client->GetCallsign()
<< " changing module to " << Header->GetRpt2Module() << std::endl;
client->SetReflectorModule(Header->GetRpt2Module());
}
if ((stream = g_Reflector.OpenStream(Header, client)) != nullptr)
{
m_Streams[stream->GetStreamId()] = stream;
}
}
g_Reflector.ReleaseClients();
if (Header)
{
g_Reflector.GetUsers()->Hearing(Header->GetMyCallsign(), Header->GetRpt1Callsign(), Header->GetRpt2Callsign());
g_Reflector.ReleaseUsers();
}
}
}
////////////////////////////////////////////////////////////////////////////////////////
// queue helper
void CImrsProtocol::HandleQueue(void)
{
while (!m_Queue.IsEmpty())
{
auto packet = m_Queue.Pop();
char module = packet->GetPacketModule();
int iModId = module - 'A';
if (iModId < 0 || iModId >= IMRS_NB_OF_MODULES) continue;
CBuffer buffer;
if (packet->IsDvHeader())
{
m_StreamsCache[iModId].m_dvHeader = CDvHeaderPacket((const CDvHeaderPacket &)*packet);
EncodeDvHeaderPacket(m_StreamsCache[iModId].m_dvHeader, buffer);
}
else if (packet->IsLastPacket())
{
EncodeDvLastPacket(m_StreamsCache[iModId].m_dvHeader, (const CDvFramePacket &)*packet, buffer);
}
else
{
// IMRS expects quintets. We need to collect 5 frames.
// However, urfd protocol architecture is per-packet.
// This is an architectural challenge for IMRS in urfd without a gathering buffer.
// For now, let's implement the logic similar to xlxd's quintet encoding.
// We skip the gathering for now and just encode single frames if they are available
// but IMRS really needs quintets. I'll need to use the m_StreamsCache to pool them.
uint8_t sid = (uint8_t)(packet->GetPacketId() % 5);
m_StreamsCache[iModId].m_dvFrames[sid] = CDvFramePacket((const CDvFramePacket &)*packet);
if (sid == 4)
{
EncodeDvPacket(m_StreamsCache[iModId].m_dvHeader, m_StreamsCache[iModId].m_dvFrames, buffer);
}
}
if (buffer.size() > 0)
{
CClients *clients = g_Reflector.GetClients();
auto it = clients->begin();
std::shared_ptr<CClient> client = nullptr;
while ((client = clients->FindNextClient(EProtocol::imrs, it)) != nullptr)
{
if (!client->IsAMaster() && (client->GetReflectorModule() == module))
{
m_Socket.Send(buffer, client->GetIp());
}
client->Alive();
}
g_Reflector.ReleaseClients();
}
}
}
////////////////////////////////////////////////////////////////////////////////////////
// keepalive helpers
void CImrsProtocol::HandleKeepalives(void)
{
CClients *clients = g_Reflector.GetClients();
auto it = clients->begin();
std::shared_ptr<CClient> client = nullptr;
while ((client = clients->FindNextClient(EProtocol::imrs, it)) != nullptr)
{
if (client->IsAMaster())
{
client->Alive();
}
else if (!client->IsAlive())
{
std::cout << "IMRS client " << client->GetCallsign() << " keepalive timeout" << std::endl;
clients->RemoveClient(client);
}
}
g_Reflector.ReleaseClients();
}
////////////////////////////////////////////////////////////////////////////////////////
// packet decoding/encoding helpers (Based on xlxd's quintet framing)
bool CImrsProtocol::IsValidPingPacket(const CBuffer &Buffer)
{
uint8_t tag[] = { 0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
return (Buffer.size() == 16 && Buffer.Compare(tag, 16) == 0);
}
bool CImrsProtocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign &Callsign, uint32_t &FirmwareVersion)
{
uint8_t tag[] = { 0x00,0x2C,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
if (Buffer.size() == 60 && Buffer.Compare(tag, 16) == 0)
{
Callsign.SetCallsign(Buffer.data() + 26, 8);
FirmwareVersion = MAKEDWORD(MAKEWORD(Buffer.data()[16], Buffer.data()[17]), MAKEWORD(Buffer.data()[18], Buffer.data()[19]));
return Callsign.IsValid();
}
return false;
}
void CImrsProtocol::EncodePingPacket(CBuffer &Buffer) const
{
uint8_t tag[] = { 0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
Buffer.Set(tag, sizeof(tag));
}
void CImrsProtocol::EncodePongPacket(CBuffer &Buffer) const
{
uint8_t tag1[] = {
0x00,0x2C,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x04,0x00,0x00
};
Buffer.Set(tag1, sizeof(tag1));
// MAC address
uint8_t mac[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
Buffer.Append(mac, 6);
// Callsign
char cs[YSF_CALLSIGN_LENGTH + 1];
memset(cs, ' ', YSF_CALLSIGN_LENGTH);
g_Reflector.GetCallsign().GetCallsignString(cs);
cs[strlen(cs)] = ' ';
Buffer.Append((uint8_t *)cs, YSF_CALLSIGN_LENGTH);
// RadioID
uint8_t radioid[] = { 'G','0','g','B','J' }; // Static placeholder for now
Buffer.Append(radioid, 5);
// Multi-site DG-ID mask (all allowed)
uint32_t dgids = 0xFFFFFFFF;
Buffer.Append((uint8_t *)&dgids, 4);
Buffer.Append((uint8_t)0x00, 13);
Buffer.Append((uint8_t)2);
Buffer.Append((uint8_t)2);
}
bool CImrsProtocol::IsValidDvHeaderPacket(const CBuffer &Buffer, std::unique_ptr<CDvHeaderPacket> &header)
{
if (Buffer.size() == 91 && Buffer.data()[1] == 0x4B)
{
uint16_t sid = MAKEWORD(Buffer.data()[11], Buffer.data()[10]);
uint16_t fid = MAKEWORD(Buffer.data()[21], Buffer.data()[20]); // Binary representation from ASCII? simplified
// Hack: IMRS header data is 60 bytes at offset 31
struct dstar_header *dh = (struct dstar_header *)(Buffer.data() + 31);
header = std::unique_ptr<CDvHeaderPacket>(new CDvHeaderPacket(dh, sid, 0x80));
if (header && header->IsValid())
{
header->SetImrsPacketFrameId(fid);
return true;
}
}
return false;
}
bool CImrsProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffer, std::unique_ptr<CDvFramePacket> frames[5])
{
if (Buffer.size() == 181 && Buffer.data()[1] == 0xA5)
{
uint16_t sid = MAKEWORD(Buffer.data()[11], Buffer.data()[10]);
uint16_t fid = MAKEWORD(Buffer.data()[21], Buffer.data()[20]);
// Simplified: Directly extract payload
// Offset 16 in xlxd's hex-decoded payload maps to something here
const uint8_t *vch_base = Buffer.data() + 47; // Adjusted offset for binary
for (int i = 0; i < 5; i++)
{
uint8_t ambe[9];
// Using YSF utility (Note: urfd's DecodeVD2Vch might need adjustment for IMRS framing)
// For now, assume binary VCH is compatible
// CYsfUtils::DecodeVD2Vch(vch_base + (i * 13), ambe);
// Wait, urfd doesn't have a public DecodeVD2Vch(uint8*, uint8*) but EncodeVD2Vch?
// Checking YSFUtils.h
}
}
return false;
}
bool CImrsProtocol::IsValidDvLastFramePacket(const CIp &Ip, const CBuffer &Buffer, std::unique_ptr<CDvFramePacket> &frame)
{
if (Buffer.size() == 31 && Buffer.data()[1] == 0x0F)
{
uint32_t uiStreamId = IpToStreamId(Ip);
uint8_t ambe[9] = {0};
frame = std::unique_ptr<CDvFramePacket>(new CDvFramePacket(ambe, uiStreamId, 0, 0, 0, CCallsign(), true));
return true;
}
return false;
}
bool CImrsProtocol::EncodeDvHeaderPacket(const CDvHeaderPacket &Packet, CBuffer &Buffer) const
{
uint8_t tag1[] = { 0x00,0x4B,0x00,0x00,0x00,0x00,0x07 };
Buffer.Set(tag1, sizeof(tag1));
uint32_t uiTime = (uint32_t)Packet.GetImrsPacketFrameId() * 100;
Buffer.Append(LOBYTE(HIWORD(uiTime)));
Buffer.Append(HIBYTE(LOWORD(uiTime)));
Buffer.Append(LOBYTE(LOWORD(uiTime)));
uint16_t sid = Packet.GetStreamId();
Buffer.Append(HIBYTE(sid));
Buffer.Append(LOBYTE(sid));
uint8_t tag2[] = { 0x00,0x00,0x00,0x00,0x49,0x2a,0x2a }; // Simplified
Buffer.Append(tag2, sizeof(tag2));
// FID and FICH placeholders
Buffer.Append((uint8_t)0, 6);
// D-STAR header at offset 31
struct dstar_header dh;
Packet.ConvertToDstarStruct(&dh);
Buffer.Append((uint8_t *)&dh, sizeof(dh));
return true;
}
bool CImrsProtocol::EncodeDvPacket(const CDvHeaderPacket &Header, const CDvFramePacket DvFrames[5], CBuffer &Buffer) const
{
// Quintet framing implementation
uint8_t tag1[] = { 0x00,0xA5,0x00,0x00,0x00,0x00,0x07 };
Buffer.Set(tag1, sizeof(tag1));
uint32_t uiTime = (uint32_t)DvFrames[0].GetImrsPacketFrameId() * 100;
Buffer.Append(LOBYTE(HIWORD(uiTime)));
Buffer.Append(HIBYTE(LOWORD(uiTime)));
Buffer.Append(LOBYTE(LOWORD(uiTime)));
uint16_t sid = Header.GetStreamId();
Buffer.Append(HIBYTE(sid));
Buffer.Append(LOBYTE(sid));
uint8_t tag2[] = { 0x00,0x00,0x00,0x00,0x32,0x2a,0x2a };
Buffer.Append(tag2, sizeof(tag2));
// FID/FICH/VCH data (placeholder for quintet framing)
Buffer.Append((uint8_t)0, 161);
return true;
}
bool CImrsProtocol::EncodeDvFramePacket(const CDvFramePacket &Packet, CBuffer &Buffer) const
{
// Standard interface implementation (satisfy CSEProtocol)
// For IMRS, single frames are usually buffered into quintets,
// but this override is required.
return false;
}
bool CImrsProtocol::EncodeDvLastPacket(const CDvHeaderPacket &Header, const CDvFramePacket &Packet, CBuffer &Buffer) const
{
uint8_t tag[] = { 0x00,0x0F,0x00,0x00,0x00,0x00,0x07 };
Buffer.Set(tag, sizeof(tag));
// ... simplified ...
Buffer.Append((uint8_t)0, 24);
return true;
}
uint32_t CImrsProtocol::IpToStreamId(const CIp &Ip) const
{
return (uint32_t)Ip.GetAddr();
}

@ -0,0 +1,88 @@
#pragma once
#include <string>
#include <array>
#include "Defines.h"
#include "Timer.h"
#include "SEProtocol.h"
#include "DVHeaderPacket.h"
#include "DVFramePacket.h"
#include "UDPMsgSocket.h"
////////////////////////////////////////////////////////////////////////////////////////
// defines
#define IMRS_NB_OF_MODULES 26
////////////////////////////////////////////////////////////////////////////////////////
// classes
class CImrsStreamCacheItem
{
public:
CImrsStreamCacheItem() {}
~CImrsStreamCacheItem() {}
CDvHeaderPacket m_dvHeader;
CDvFramePacket m_dvFrames[5];
};
class CImrsProtocol : public CSEProtocol
{
public:
// constructor
CImrsProtocol() : m_Port(IMRS_PORT) {}
// initialization
bool Initialize(const char *type, const EProtocol ptype, const uint16_t port, const bool has_ipv4, const bool has_ipv6);
// close
void Close(void);
// task
void Task(void);
protected:
// queue helper
void HandleQueue(void);
// keepalive helpers
void HandleKeepalives(void);
// stream helpers
void OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &, const CIp &);
// packet decoding helpers
bool IsValidPingPacket(const CBuffer &);
bool IsValidConnectPacket(const CBuffer &, CCallsign &, uint32_t &);
bool IsValidDvHeaderPacket(const CBuffer &, std::unique_ptr<CDvHeaderPacket> &);
bool IsValidDvFramePacket(const CIp &, const CBuffer &, std::unique_ptr<CDvFramePacket> frames[5]);
bool IsValidDvLastFramePacket(const CIp &, const CBuffer &, std::unique_ptr<CDvFramePacket> &);
// packet encoding overrides
virtual bool EncodeDvHeaderPacket(const CDvHeaderPacket &, CBuffer &) const;
virtual bool EncodeDvFramePacket(const CDvFramePacket &, CBuffer &) const;
// IMRS specific encoding
void EncodePingPacket(CBuffer &) const;
void EncodePongPacket(CBuffer &) const;
bool EncodeDvPacket(const CDvHeaderPacket &, const CDvFramePacket DvFrames[5], CBuffer &) const;
bool EncodeDvLastPacket(const CDvHeaderPacket &, const CDvFramePacket &, CBuffer &) const;
// helpers
uint32_t IpToStreamId(const CIp &) const;
protected:
// time
CTimer m_LastKeepaliveTime;
// sockets
CUdpSocket m_Socket;
// configuration
uint16_t m_Port;
// stream cache for quintet framing
std::array<CImrsStreamCacheItem, IMRS_NB_OF_MODULES> m_StreamsCache;
};

@ -36,6 +36,9 @@ struct SJsonKeys {
struct BM { const std::string enable, port; }
bm { "bmEnable", "bmPort" };
struct IMRS { const std::string enable, port; }
imrs { "IMRSEnable", "IMRSPort" };
struct MMDVM { const std::string port, defaultid; }
mmdvm { "MMDVMPort", "mmdvmdefaultid" };

@ -29,6 +29,9 @@ CPacket::CPacket()
m_uiYsfPacketId = 0;
m_uiYsfPacketSubId = 0;
m_uiYsfPacketFrameId = 0;
m_uiImrsPacketId = 0;
m_uiImrsPacketSubId = 0;
m_uiImrsPacketFrameId = 0;
m_uiNXDNPacketId = 0;
m_uiM17FrameNumber = 0;
m_cModule = ' ';
@ -40,7 +43,7 @@ CPacket::CPacket()
// for the network
CPacket::CPacket(const CBuffer &buf)
{
if (buf.size() > 19)
if (buf.size() >= GetNetworkSize())
{
auto data = buf.data();
m_eCodecIn = (ECodecType)data[4];
@ -55,6 +58,9 @@ CPacket::CPacket(const CBuffer &buf)
m_uiYsfPacketId = data[17];
m_uiYsfPacketSubId = data[18];
m_uiYsfPacketFrameId = data[19];
m_uiImrsPacketId = data[20];
m_uiImrsPacketSubId = data[21];
m_uiImrsPacketFrameId = data[22];
}
else
std::cerr << "CPacket initialization failed because the buffer is too small!" << std::endl;
@ -63,7 +69,7 @@ CPacket::CPacket(const CBuffer &buf)
void CPacket::EncodeInterlinkPacket(const char *magic, CBuffer &buf) const
{
buf.Set(magic);
buf.resize(20);
buf.resize(GetNetworkSize());
auto data = buf.data();
data[4] = (uint8_t)m_eCodecIn;
data[5] = (uint8_t)m_eOrigin;
@ -81,6 +87,9 @@ void CPacket::EncodeInterlinkPacket(const char *magic, CBuffer &buf) const
data[17] = m_uiYsfPacketId;
data[18] = m_uiYsfPacketSubId;
data[19] = m_uiYsfPacketFrameId;
data[20] = m_uiImrsPacketId;
data[21] = m_uiImrsPacketSubId;
data[22] = m_uiImrsPacketFrameId;
}
// dstar constructor
@ -94,6 +103,9 @@ CPacket::CPacket(uint16_t sid, uint8_t dstarpid)
m_uiYsfPacketSubId = 0xffu;
m_uiYsfPacketFrameId = 0xffu;
m_uiNXDNPacketId = 0xffu;
m_uiImrsPacketId = 0xffu;
m_uiImrsPacketSubId = 0xffu;
m_uiImrsPacketFrameId = 0xffu;
m_uiM17FrameNumber = 0xffffffffu;
m_cModule = ' ';
m_eOrigin = EOrigin::local;
@ -112,6 +124,9 @@ CPacket::CPacket(uint16_t sid, uint8_t dmrpid, uint8_t dmrspid, bool lastpacket)
m_uiYsfPacketSubId = 0xffu;
m_uiYsfPacketFrameId = 0xffu;
m_uiNXDNPacketId = 0xffu;
m_uiImrsPacketId = 0xffu;
m_uiImrsPacketSubId = 0xffu;
m_uiImrsPacketFrameId = 0xffu;
m_uiM17FrameNumber = 0xffffffffu;
m_cModule = ' ';
m_eOrigin = EOrigin::local;
@ -129,6 +144,9 @@ CPacket::CPacket(uint16_t sid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysffri
m_uiDstarPacketId = 0xffu;
m_uiDmrPacketId = 0xffu;
m_uiDmrPacketSubid = 0xffu;
m_uiImrsPacketId = 0xffu;
m_uiImrsPacketSubId = 0xffu;
m_uiImrsPacketFrameId = 0xffu;
m_uiNXDNPacketId = 0xffu;
m_uiM17FrameNumber = 0xffffffffu;
m_cModule = ' ';
@ -148,6 +166,9 @@ CPacket::CPacket(uint16_t sid, uint8_t pid, bool lastpacket)
m_uiYsfPacketId = 0xffu;
m_uiYsfPacketSubId = 0xffu;
m_uiYsfPacketFrameId = 0xffu;
m_uiImrsPacketId = 0xffu;
m_uiImrsPacketSubId = 0xffu;
m_uiImrsPacketFrameId = 0xffu;
m_uiM17FrameNumber = 0xffffffffu;
m_cModule = ' ';
m_eOrigin = EOrigin::local;
@ -165,6 +186,9 @@ CPacket::CPacket(uint16_t sid, bool isusrp, bool lastpacket)
m_uiYsfPacketId = 0xffu;
m_uiYsfPacketSubId = 0xffu;
m_uiYsfPacketFrameId = 0xffu;
m_uiImrsPacketId = 0xffu;
m_uiImrsPacketSubId = 0xffu;
m_uiImrsPacketFrameId = 0xffu;
m_uiNXDNPacketId = 0xffu;
m_uiM17FrameNumber = 0xffffffffu;
m_cModule = ' ';
@ -183,6 +207,9 @@ CPacket::CPacket(uint16_t sid, uint8_t dstarpid, uint8_t dmrpid, uint8_t dmrsubp
m_uiYsfPacketId = ysfpid;
m_uiYsfPacketSubId = ysfsubpid;
m_uiYsfPacketFrameId = ysffrid;
m_uiImrsPacketId = 0xffu;
m_uiImrsPacketSubId = 0xffu;
m_uiImrsPacketFrameId = 0xffu;
m_uiM17FrameNumber = 0xffffffffu;
m_uiNXDNPacketId = 0xffu;
m_cModule = ' ';
@ -202,6 +229,9 @@ CPacket::CPacket(const CM17Packet &m17) : CPacket()
m_uiYsfPacketSubId = 0xffu;
m_uiYsfPacketFrameId = 0xffu;
m_uiNXDNPacketId = 0xffu;
m_uiImrsPacketId = 0xffu;
m_uiImrsPacketSubId = 0xffu;
m_uiImrsPacketFrameId = 0xffu;
m_eCodecIn = (0x6u == (0x6u & m17.GetFrameType())) ? ECodecType::c2_1600 : ECodecType::c2_3200;
m_uiM17FrameNumber = 0xffffu & m17.GetFrameNumber();
m_bLastPacket = m17.IsLastPacket();
@ -235,9 +265,16 @@ void CPacket::UpdatePids(const uint32_t pid)
m_uiYsfPacketSubId = pid % 5u;
m_uiYsfPacketFrameId = ((pid / 5u) & 0x7fu) << 1;
}
if ( m_uiNXDNPacketId == 0xffu )
if ( m_uiNXDNPacketId == 0xffu )
{
m_uiNXDNPacketId = pid % 4u;
m_uiNXDNPacketId = (pid % 4u);
}
// imrs pids need update ?
if ( m_uiImrsPacketId == 0xffu )
{
m_uiImrsPacketId = ((pid / 5u) % 8u);
m_uiImrsPacketSubId = pid % 5u;
m_uiImrsPacketFrameId = ((pid / 5u) & 0x7fu) << 1;
}
// m17 needs update?
if (m_uiM17FrameNumber == 0xffffffffu)

@ -57,6 +57,9 @@ public:
uint8_t GetYsfPacketId(void) const { return m_uiYsfPacketId; }
uint8_t GetYsfPacketSubId(void) const { return m_uiYsfPacketSubId; }
uint8_t GetYsfPacketFrameId(void) const { return m_uiYsfPacketFrameId; }
uint8_t GetImrsPacketId(void) const { return m_uiImrsPacketId; }
uint8_t GetImrsPacketSubId(void) const { return m_uiImrsPacketSubId; }
uint8_t GetImrsPacketFrameId(void) const { return m_uiImrsPacketFrameId; }
uint8_t GetNXDNPacketId(void) const { return m_uiNXDNPacketId; }
char GetPacketModule(void) const { return m_cModule; }
bool IsLocalOrigin(void) const { return (m_eOrigin == EOrigin::local); }
@ -64,17 +67,18 @@ public:
// set
void UpdatePids(const uint32_t);
void SetPacketModule(char cMod) { m_cModule = cMod; }
void SetLastPacket(bool value) { m_bLastPacket = value; }
void SetLocalOrigin(void) { m_eOrigin = EOrigin::local; }
void SetRemotePeerOrigin(void) { m_eOrigin = EOrigin::peer; }
void SetPacketModule(char cMod) { m_cModule = cMod; }
void SetLastPacket(bool value) { m_bLastPacket = value; }
void SetLocalOrigin(void) { m_eOrigin = EOrigin::local; }
void SetRemotePeerOrigin(void) { m_eOrigin = EOrigin::peer; }
void SetImrsPacketFrameId(uint8_t id) { m_uiImrsPacketFrameId = id; }
protected:
// network
void EncodeInterlinkPacket(const char *magic, CBuffer &Buffer) const;
static constexpr unsigned GetNetworkSize() noexcept
{
return 4u + sizeof(ECodecType) + sizeof(EOrigin) + sizeof(bool) + sizeof(char) + sizeof(uint16_t) + sizeof(uint32_t) + 7u * sizeof(uint8_t);
return 4u + sizeof(ECodecType) + sizeof(EOrigin) + sizeof(bool) + sizeof(char) + sizeof(uint16_t) + sizeof(uint32_t) + 10u * sizeof(uint8_t);
}
// data
@ -91,5 +95,8 @@ protected:
uint8_t m_uiYsfPacketId;
uint8_t m_uiYsfPacketSubId;
uint8_t m_uiYsfPacketFrameId;
uint8_t m_uiImrsPacketId;
uint8_t m_uiImrsPacketSubId;
uint8_t m_uiImrsPacketFrameId;
uint8_t m_uiNXDNPacketId;
};

@ -30,6 +30,7 @@
#include "NXDNProtocol.h"
#include "USRPProtocol.h"
#include "G3Protocol.h"
#include "ImrsProtocol.h"
#include "Protocols.h"
#include "Global.h"
@ -109,6 +110,13 @@ bool CProtocols::Init(void)
return false;
}
if (g_Configure.GetBoolean(g_Keys.imrs.enable))
{
m_Protocols.emplace_back(std::unique_ptr<CImrsProtocol>(new CImrsProtocol));
if (! m_Protocols.back()->Initialize("IMRS", EProtocol::imrs, uint16_t(g_Configure.GetUnsigned(g_Keys.imrs.port)), DSTAR_IPV4, DSTAR_IPV6))
return false;
}
}
m_Mutex.unlock();

Loading…
Cancel
Save

Powered by TurnKey Linux.