From a45cdff2d23d0747fb23f4325d8939dc011d35ab Mon Sep 17 00:00:00 2001 From: LX3JL Date: Tue, 26 Oct 2021 20:36:29 +0200 Subject: [PATCH 1/4] implementation of Yaesu's IRMS protocol --- src/cbuffer.cpp | 35 +- src/cbuffer.h | 12 +- src/ccallsign.cpp | 28 ++ src/ccallsign.h | 1 + src/cdvframepacket.cpp | 13 +- src/cdvframepacket.h | 1 + src/cdvheaderpacket.cpp | 4 +- src/cdvheaderpacket.h | 2 +- src/cdvlastframepacket.cpp | 8 + src/cdvlastframepacket.h | 1 + src/cgatekeeper.cpp | 2 + src/cimrsclient.cpp | 52 +++ src/cimrsclient.h | 59 +++ src/cimrsprotocol.cpp | 915 +++++++++++++++++++++++++++++++++++++ src/cimrsprotocol.h | 117 +++++ src/cip.h | 5 +- src/cpacket.cpp | 50 +- src/cpacket.h | 21 +- src/cprotocols.cpp | 5 + src/creflector.cpp | 155 ++++++- src/creflector.h | 7 +- src/cysffich.cpp | 6 + src/cysffich.h | 1 + src/cysfprotocol.cpp | 18 +- src/cysfutils.cpp | 76 ++- src/cysfutils.h | 4 +- src/main.h | 13 +- 27 files changed, 1573 insertions(+), 38 deletions(-) create mode 100644 src/cimrsclient.cpp create mode 100644 src/cimrsclient.h create mode 100644 src/cimrsprotocol.cpp create mode 100644 src/cimrsprotocol.h diff --git a/src/cbuffer.cpp b/src/cbuffer.cpp index 479abee..ef68bca 100644 --- a/src/cbuffer.cpp +++ b/src/cbuffer.cpp @@ -29,7 +29,7 @@ //////////////////////////////////////////////////////////////////////////////////////// // constructor -CBuffer::CBuffer(uint8 *buffer, int len) +CBuffer::CBuffer(const uint8 *buffer, int len) { resize(len); ::memcpy(data(), buffer, len); @@ -38,7 +38,7 @@ CBuffer::CBuffer(uint8 *buffer, int len) //////////////////////////////////////////////////////////////////////////////////////// // set -void CBuffer::Set(uint8 *buffer, int len) +void CBuffer::Set(const uint8 *buffer, int len) { resize(len); ::memcpy(data(), buffer, len); @@ -50,7 +50,21 @@ void CBuffer::Set(const char *sz) ::strcpy((char *)data(), sz); } -void CBuffer::Append(uint8 *buffer, int len) +void CBuffer::SetFromAsciiHex(const char *sz, int len) +{ + char ascii[3]; + + resize(len/2); + ascii[2] = 0x00; + for ( int i = 0; i < len/2; i++ ) + { + ::memcpy(ascii, sz+(i*2), 2); + data()[i] = ::strtol(ascii, NULL, 16); + } +} + + +void CBuffer::Append(const uint8 *buffer, int len) { int n = (int)size(); resize(n+len); @@ -91,6 +105,17 @@ void CBuffer::Append(const char *sz) Append((uint8)0x00); } +void CBuffer::AppendAsAsciiHex(uint8 *buffer, int len) +{ + char sz[3]; + for ( int i = 0; i < len; i++ ) + { + ::sprintf(sz, "%02X", buffer[i]); + Append((uint8 *)sz, 2); + } +} + + void CBuffer::ReplaceAt(int i, uint8 ui) { if ( size() < (i+sizeof(uint8)) ) @@ -130,7 +155,7 @@ void CBuffer::ReplaceAt(int i, const uint8 *ptr, int len) //////////////////////////////////////////////////////////////////////////////////////// // operation -int CBuffer::Compare(uint8 *buffer, int len) const +int CBuffer::Compare(const uint8 *buffer, int len) const { int result = -1; if ( size() >= len ) @@ -140,7 +165,7 @@ int CBuffer::Compare(uint8 *buffer, int len) const return result; } -int CBuffer::Compare(uint8 *buffer, int off, int len) const +int CBuffer::Compare(const uint8 *buffer, int off, int len) const { int result = -1; if ( size() >= (off+len) ) diff --git a/src/cbuffer.h b/src/cbuffer.h index ba4b967..809850c 100644 --- a/src/cbuffer.h +++ b/src/cbuffer.h @@ -32,28 +32,30 @@ class CBuffer : public std::vector public: // constructor CBuffer() {}; - CBuffer(uint8 *, int); + CBuffer(const uint8 *, int); // destructor virtual ~CBuffer() {}; // set - void Set(uint8 *, int); + void Set(const uint8 *, int); void Set(const char *); - void Append(uint8 *, int); + void SetFromAsciiHex(const char *, int); + void Append(const uint8 *, int); void Append(uint8, int); void Append(uint8); void Append(uint16); void Append(uint32); void Append(const char *); + void AppendAsAsciiHex(uint8 *, int); void ReplaceAt(int, uint8); void ReplaceAt(int, uint16); void ReplaceAt(int, uint32); void ReplaceAt(int, const uint8 *, int); // operation - int Compare(uint8 *, int) const; - int Compare(uint8 *, int, int) const; + int Compare(const uint8 *, int) const; + int Compare(const uint8 *, int, int) const; // operator bool operator ==(const CBuffer &) const; diff --git a/src/ccallsign.cpp b/src/ccallsign.cpp index 23cdb3e..03966c7 100644 --- a/src/ccallsign.cpp +++ b/src/ccallsign.cpp @@ -27,6 +27,7 @@ #include #include "cdmriddirfile.h" #include "cdmriddirhttp.h" +#include "ysfdefines.h" #include "ccallsign.h" //////////////////////////////////////////////////////////////////////////////////////// @@ -195,6 +196,33 @@ void CCallsign::SetCallsign(const uint8 *buffer, int len, bool UpdateDmrid) } } +void CCallsign::SetYsfCallsign(const char *sz) +{ + int i; + + // reset object + ::memset(m_Callsign, ' ', sizeof(m_Callsign)); + ::memset(m_Suffix, ' ', sizeof(m_Suffix)); + m_Module = ' '; + m_uiDmrid = 0; + + // set callsign + for ( i = 0; (i < sizeof(m_Callsign)) && (sz[i] != '/') && (sz[i] != '-'); i++ ) + { + m_Callsign[i] = sz[i]; + } + // suffix + if ( (sz[i] == '/') || (sz[i] == '-') ) + { + i++; + int j = 0; + for ( ; (i < YSF_CALLSIGN_LENGTH) && (j < sizeof(m_Suffix)); i++ ) + { + m_Suffix[j++] = sz[i]; + } + } +} + void CCallsign::SetDmrid(uint32 dmrid, bool UpdateCallsign) { m_uiDmrid = dmrid; diff --git a/src/ccallsign.h b/src/ccallsign.h index bd5f118..b3b1829 100644 --- a/src/ccallsign.h +++ b/src/ccallsign.h @@ -54,6 +54,7 @@ public: // set void SetCallsign(const char *, bool = true); void SetCallsign(const uint8 *, int, bool = true); + void SetYsfCallsign(const char *); void SetDmrid(uint32, bool = true); void SetDmrid(const uint8 *, bool = true); void SetModule(char); diff --git a/src/cdvframepacket.cpp b/src/cdvframepacket.cpp index 8c2e02b..e93c9b9 100644 --- a/src/cdvframepacket.cpp +++ b/src/cdvframepacket.cpp @@ -72,13 +72,24 @@ CDvFramePacket::CDvFramePacket(const uint8 *ambe, uint16 sid, uint8 pid, uint8 s ::memset(m_uiDvData, 0, sizeof(m_uiDvData)); } +// imrs constructor + +CDvFramePacket::CDvFramePacket(const uint8 *ambe, uint16 sid, uint8 pid, uint8 spid, uint16 fid) +: CPacket(sid, pid, spid, fid) +{ + ::memcpy(m_uiAmbePlus, ambe, sizeof(m_uiAmbePlus)); + ::memset(m_uiDvSync, 0, sizeof(m_uiDvSync)); + ::memset(m_uiAmbe, 0, sizeof(m_uiAmbe)); + ::memset(m_uiDvData, 0, sizeof(m_uiDvData)); +} + // xlx constructor CDvFramePacket::CDvFramePacket (uint16 sid, uint8 dstarpid, const uint8 *dstarambe, const uint8 *dstardvdata, uint8 dmrpid, uint8 dprspid, const uint8 *dmrambe, const uint8 *dmrsync) -: CPacket(sid, dstarpid, dmrpid, dprspid, 0xFF, 0xFF, 0xFF) +: CPacket(sid, dstarpid, dmrpid, dprspid, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFFFF) { ::memcpy(m_uiAmbe, dstarambe, sizeof(m_uiAmbe)); ::memcpy(m_uiDvData, dstardvdata, sizeof(m_uiDvData)); diff --git a/src/cdvframepacket.h b/src/cdvframepacket.h index cddad5d..d471a74 100644 --- a/src/cdvframepacket.h +++ b/src/cdvframepacket.h @@ -56,6 +56,7 @@ public: CDvFramePacket(const struct dstar_dvframe *, uint16, uint8); CDvFramePacket(const uint8 *, const uint8 *, uint16, uint8, uint8); CDvFramePacket(const uint8 *, uint16, uint8, uint8, uint8); + CDvFramePacket(const uint8 *, uint16, uint8, uint8, uint16); CDvFramePacket(uint16, uint8, const uint8 *, const uint8 *, uint8, uint8, const uint8 *, const uint8 *); CDvFramePacket(const CDvFramePacket &); diff --git a/src/cdvheaderpacket.cpp b/src/cdvheaderpacket.cpp index 3a281b2..1044b9b 100644 --- a/src/cdvheaderpacket.cpp +++ b/src/cdvheaderpacket.cpp @@ -70,10 +70,10 @@ CDvHeaderPacket::CDvHeaderPacket(uint32 my, const CCallsign &ur, const CCallsign m_csMY = CCallsign("", my); } -// YSF constructor +// YSF + IMRS constructor CDvHeaderPacket::CDvHeaderPacket(const CCallsign &my, const CCallsign &ur, const CCallsign &rpt1, const CCallsign &rpt2, uint16 sid, uint8 pid) -: CPacket(sid, pid, 0, 0) +: CPacket(sid, pid, 0, (uint8)0) { m_uiFlag1 = 0; m_uiFlag2 = 0; diff --git a/src/cdvheaderpacket.h b/src/cdvheaderpacket.h index df9eb79..a5ae9ee 100644 --- a/src/cdvheaderpacket.h +++ b/src/cdvheaderpacket.h @@ -64,7 +64,7 @@ public: CDvHeaderPacket(const struct dstar_header *, uint16, uint8); CDvHeaderPacket(uint32, const CCallsign &, const CCallsign &, const CCallsign &, uint16, uint8, uint8); CDvHeaderPacket(const CCallsign &, const CCallsign &, const CCallsign &, const CCallsign &, uint16, uint8); - CDvHeaderPacket(const CDvHeaderPacket &); + CDvHeaderPacket(const CDvHeaderPacket &); // destructor virtual ~CDvHeaderPacket(){}; diff --git a/src/cdvlastframepacket.cpp b/src/cdvlastframepacket.cpp index eb44f4d..4150455 100644 --- a/src/cdvlastframepacket.cpp +++ b/src/cdvlastframepacket.cpp @@ -64,6 +64,14 @@ CDvLastFramePacket::CDvLastFramePacket(const uint8 *ambe, uint16 sid, uint8 pid, { } +// imrs constructor + +CDvLastFramePacket::CDvLastFramePacket(const uint8 *ambe, uint16 sid, uint8 pid, uint8 spid, uint16 fid) + : CDvFramePacket(ambe, sid, pid, spid, fid) +{ +} + + // copy constructor diff --git a/src/cdvlastframepacket.h b/src/cdvlastframepacket.h index 8dc339d..1cc23c4 100644 --- a/src/cdvlastframepacket.h +++ b/src/cdvlastframepacket.h @@ -43,6 +43,7 @@ public: CDvLastFramePacket(const struct dstar_dvframe *, uint16, uint8); CDvLastFramePacket(const uint8 *, const uint8 *, uint16, uint8, uint8); CDvLastFramePacket(const uint8 *, uint16, uint8, uint8, uint8); + CDvLastFramePacket(const uint8 *, uint16, uint8, uint8, uint16); CDvLastFramePacket(uint16, uint8, const uint8 *, const uint8 *, uint8, uint8, const uint8 *, const uint8 *); CDvLastFramePacket(const CDvLastFramePacket &); diff --git a/src/cgatekeeper.cpp b/src/cgatekeeper.cpp index 50c079f..6bbacca 100644 --- a/src/cgatekeeper.cpp +++ b/src/cgatekeeper.cpp @@ -103,6 +103,7 @@ bool CGateKeeper::MayLink(const CCallsign &callsign, const CIp &ip, int protocol case PROTOCOL_DMRMMDVM: case PROTOCOL_YSF: case PROTOCOL_G3: + case PROTOCOL_IMRS: // first check is IP & callsigned listed OK ok &= IsNodeListedOk(callsign, ip); // todo: then apply any protocol specific authorisation for the operation @@ -145,6 +146,7 @@ bool CGateKeeper::MayTransmit(const CCallsign &callsign, const CIp &ip, int prot case PROTOCOL_DMRMMDVM: case PROTOCOL_YSF: case PROTOCOL_G3: + case PROTOCOL_IMRS: // first check is IP & callsigned listed OK ok &= IsNodeListedOk(callsign, ip, module); // todo: then apply any protocol specific authorisation for the operation diff --git a/src/cimrsclient.cpp b/src/cimrsclient.cpp new file mode 100644 index 0000000..5609e7a --- /dev/null +++ b/src/cimrsclient.cpp @@ -0,0 +1,52 @@ +// +// cimrsclient.cpp +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 29/10/2019. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd 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. +// +// xlxd 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 Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#include "main.h" +#include "cimrsclient.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.DurationSinceNow() < IMRS_KEEPALIVE_TIMEOUT); +} diff --git a/src/cimrsclient.h b/src/cimrsclient.h new file mode 100644 index 0000000..cecaa36 --- /dev/null +++ b/src/cimrsclient.h @@ -0,0 +1,59 @@ +// +// cimrsclient.h +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 29/10/2019. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd 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. +// +// xlxd 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 Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#ifndef cimrsclient_h +#define cimrsclient_h + +#include "cclient.h" + +//////////////////////////////////////////////////////////////////////////////////////// +// define + + +//////////////////////////////////////////////////////////////////////////////////////// +// class + +class CImrsClient : public CClient +{ +public: + // constructors + CImrsClient(); + CImrsClient(const CCallsign &, const CIp &, char = ' '); + CImrsClient(const CImrsClient &); + + // destructor + virtual ~CImrsClient() {}; + + // identity + int GetProtocol(void) const { return PROTOCOL_IMRS; } + const char *GetProtocolName(void) const { return "IMRS"; } + int GetCodec(void) const { return CODEC_AMBE2PLUS; } + bool IsNode(void) const { return true; } + + // status + bool IsAlive(void) const; +}; + +//////////////////////////////////////////////////////////////////////////////////////// +#endif /* cimrsclient_h */ diff --git a/src/cimrsprotocol.cpp b/src/cimrsprotocol.cpp new file mode 100644 index 0000000..9f31a18 --- /dev/null +++ b/src/cimrsprotocol.cpp @@ -0,0 +1,915 @@ +// +// cimrsprotocol.cpp +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 29/10/2019. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd 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. +// +// xlxd 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 Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#include "main.h" +#include +#include "ysfdefines.h" +#include "cysfutils.h" +#include "cysffich.h" +#include "cimrsclient.h" +#include "cimrsprotocol.h" +#include "creflector.h" +#include "cgatekeeper.h" + +//////////////////////////////////////////////////////////////////////////////////////// +// operation + +bool CImrsProtocol::Init(void) +{ + bool ok; + + // base class + ok = CProtocol::Init(); + + // update the reflector callsign + m_ReflectorCallsign.PatchCallsign(0, (const uint8 *)"IMR", 3); + + // create our socket + ok &= m_Socket.Open(IMRS_PORT); + if ( !ok ) + { + std::cout << "Error opening socket on port UDP" << IMRS_PORT << " on ip " << g_Reflector.GetListenIp() << std::endl; + } + + // update time + m_LastKeepaliveTime.Now(); + + // done + return ok; +} + +void CImrsProtocol::Close(void) +{ + // base class + CProtocol::Close(); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// task + +void CImrsProtocol::Task(void) +{ + CBuffer Buffer; + CIp Ip; + CCallsign Callsign; + //CYSFFICH Fich; + CDvHeaderPacket *Header; + CDvFramePacket *Frames[5]; + + // handle incoming packets + if ( m_Socket.Receive(&Buffer, &Ip, 20) != -1 ) + { + // force port + Ip.SetPort(IMRS_PORT); + // crack the packet + if ( IsValidDvFramePacket(Ip, Buffer, Frames) ) + { + //std::cout << "IMRS DV frame" << std::endl; + + // handle it + OnDvFramePacketIn(Frames[0], &Ip); + OnDvFramePacketIn(Frames[1], &Ip); + OnDvFramePacketIn(Frames[2], &Ip); + OnDvFramePacketIn(Frames[3], &Ip); + OnDvFramePacketIn(Frames[4], &Ip); + + } + else if ( IsValidDvHeaderPacket(Ip, Buffer, &Header) ) + { + //std::cout << "IMRS DV header:" << std::endl << *Header << std::endl; + //std::cout << "IMRS DV header:" << std::endl; + + // node linked and callsign muted? + if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, PROTOCOL_IMRS, Header->GetRpt2Module()) ) + { + // handle it + OnDvHeaderPacketIn(Header, Ip); + } + else + { + delete Header; + } + } + else if ( IsValidDvLastFramePacket(Ip, Buffer, Frames) ) + { + //std::cout << "IMRS last DV frame" << std::endl; + + // handle it + OnDvLastFramePacketIn((CDvLastFramePacket *)Frames[0], &Ip); + } + else if ( IsValidPingPacket(Buffer) ) + { + //std::cout << "IMRS ping packet from " << Ip << std::endl; + + // acknowledge request + EncodePongPacket(&Buffer); + m_Socket.Send(Buffer, Ip, IMRS_PORT); + + // and our turn + EncodePingPacket(&Buffer); + m_Socket.Send(Buffer, Ip, IMRS_PORT); + + } + else if ( IsValidConnectPacket(Buffer, &Callsign) ) + { + //std::cout << "IMRS keepalive/connect packet from " << Callsign << " at " << Ip << std::endl; + + // callsign authorized? + if ( g_GateKeeper.MayLink(Callsign, Ip, PROTOCOL_IMRS) ) + { + // add client if needed + CClients *clients = g_Reflector.GetClients(); + CClient *client = clients->FindClient(Callsign, Ip, PROTOCOL_IMRS); + // client already connected ? + if ( client == NULL ) + { + std::cout << "IMRS connect packet from " << Callsign << " at " << Ip << std::endl; + + // create the client + CImrsClient *newclient = new CImrsClient(Callsign, Ip); + // connect to default module + newclient->SetReflectorModule(IMRS_DEFAULT_MODULE); + + // and append + clients->AddClient(newclient); + } + else + { + client->Alive(); + } + // and done + g_Reflector.ReleaseClients(); + } + } + else + { + // invalid packet + //std::cout << "IMRS packet (" << Buffer.size() << ") from " << Callsign << " at " << Ip << std::endl; + //Buffer.DebugDump(g_Reflector.m_DebugFile); + } + } + + // handle end of streaming timeout + CheckStreamsTimeout(); + + // handle queue from reflector + HandleQueue(); + + // keep client alive + if ( m_LastKeepaliveTime.DurationSinceNow() > IMRS_KEEPALIVE_PERIOD ) + { + // + HandleKeepalives(); + + // update time + m_LastKeepaliveTime.Now(); + } +} + +//////////////////////////////////////////////////////////////////////////////////////// +// streams helpers + +bool CImrsProtocol::OnDvHeaderPacketIn(CDvHeaderPacket *Header, const CIp &Ip) +{ + bool newstream = false; + + // find the stream + CPacketStream *stream = GetStream(Header->GetStreamId()); + if ( stream == NULL ) + { + // no stream open yet, open a new one + CCallsign via(Header->GetRpt1Callsign()); + + // find this client + CClient *client = g_Reflector.GetClients()->FindClient(Ip, PROTOCOL_IMRS); + if ( client != NULL ) + { + // get client callsign + via = client->GetCallsign(); + + // handle changing module client is linked to + // via dgid of packet + if ( Header->GetRpt2Module() != client->GetReflectorModule() ) + { + std::cout << "IMRS client " << client->GetCallsign() + << " linking by DG-ID to module " << Header->GetRpt2Module() << std::endl; + client->SetReflectorModule(Header->GetRpt2Module()); + } + + // get module it's linked to + //Header->SetRpt2Module(client->GetReflectorModule()); + + // and try to open the stream + if ( (stream = g_Reflector.OpenStream(Header, client)) != NULL ) + { + // keep the handle + m_Streams.push_back(stream); + newstream = true; + } + } + // release + g_Reflector.ReleaseClients(); + + // update last heard + if ( g_Reflector.IsValidModule(Header->GetRpt2Module()) ) + { + g_Reflector.GetUsers()->Hearing(Header->GetMyCallsign(), via, Header->GetRpt2Callsign()); + g_Reflector.ReleaseUsers(); + } + + // delete header if needed + if ( !newstream ) + { + delete Header; + } + } + else + { + // stream already open + // skip packet, but tickle the stream + stream->Tickle(); + // and delete packet + delete Header; + } + + // done + return newstream; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// queue helper + +void CImrsProtocol::HandleQueue(void) +{ + m_Queue.Lock(); + while ( !m_Queue.empty() ) + { + // get the packet + CPacket *packet = m_Queue.front(); + m_Queue.pop(); + + // get our sender's id + int iModId = g_Reflector.GetModuleIndex(packet->GetModuleId()); + + // encode + CBuffer buffer; + + // check if it's header + if ( packet->IsDvHeader() ) + { + // update local stream cache + // this relies on queue feeder setting valid module id + m_StreamsCache[iModId].m_dvHeader = CDvHeaderPacket((const CDvHeaderPacket &)*packet); + for ( int i = 0; i < 5; i++ ) + { + m_StreamsCache[iModId].m_dvFrames[i] = CDvFramePacket(); + } + + // encode it + EncodeDvHeaderPacket((const CDvHeaderPacket &)*packet, &buffer); + } + // check if it's a last frame + else if ( packet->IsLastPacket() ) + { + // encode it + EncodeDvLastPacket(m_StreamsCache[iModId].m_dvHeader, (const CDvLastFramePacket &)*packet, &buffer); + } + // otherwise, just a regular DV frame + else + { + // update local stream cache or send quintet when needed + uint8 sid = packet->GetImrsPacketSubId(); + if ( (sid >= 0) && (sid <= 4) ) + { + //std::cout << (int)sid; + 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); + } + } + } + + // 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(); + int index = -1; + CClient *client = NULL; + while ( (client = clients->FindNextClient(PROTOCOL_IMRS, &index)) != NULL ) + { + // is this client busy ? + if ( !client->IsAMaster() && (client->GetReflectorModule() == packet->GetModuleId()) ) + { + // no, send the packet + m_Socket.Send(buffer, client->GetIp(), IMRS_PORT); + //std::cout << "sending " << buffer.size() << " bytes to " << client->GetIp() << std::endl; + } + } + g_Reflector.ReleaseClients(); + } + + // done + delete packet; + } + m_Queue.Unlock(); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// keepalive helpers + +void CImrsProtocol::HandleKeepalives(void) +{ + // IMRS protocol keepalive request is client tasks + // here, just check that all clients are still alive + // and disconnect them if not + + // iterate on clients + CClients *clients = g_Reflector.GetClients(); + int index = -1; + CClient *client = NULL; + while ( (client = clients->FindNextClient(PROTOCOL_IMRS, &index)) != NULL ) + { + // 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 << "IMRS client " << client->GetCallsign() << " keepalive timeout" << std::endl; + clients->RemoveClient(client); + } + + } + g_Reflector.ReleaseClients(); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// DV packet decoding helpers + +bool CImrsProtocol::IsValidPingPacket(const CBuffer &Buffer) +{ + uint8 tag[] = { 0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, }; + + return ( (Buffer.size() == 16) && (Buffer.Compare(tag, sizeof(tag)) == 0) ); +} + +bool CImrsProtocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign *Callsign) +{ + uint8 tag[] = { 0x00,0x2C,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x04,0x00,0x00 }; + + bool valid = false; + if ( (Buffer.size() == 60) && (Buffer.Compare(tag, sizeof(tag)) == 0) ) + { + Callsign->SetCallsign(Buffer.data()+26, 8); + Callsign->SetModule(IMRS_MODULE_ID); + valid = (Callsign->IsValid()); + //std::cout << "DG-IDs " << (int)Buffer.at(58) << "," << (int)Buffer.at(59) << std::endl; + } + return valid; + +} + +bool CImrsProtocol::IsValidDvHeaderPacket(const CIp &Ip, const CBuffer &Buffer, CDvHeaderPacket **header) +{ + bool valid = false; + *header = NULL; + + if ( (Buffer.size() == 91) && (Buffer.at(1) == 0x4B) ) + { + // get stream id + uint32 uiStreamId = IpToStreamId(Ip); + + // and payload + CBuffer payload; + payload.SetFromAsciiHex((const char *)(Buffer.data()+19), 12); + + // fich + CYSFFICH Fich; + Fich.load((uint8 *)(payload.data()+2)); + /*std::cout << "H:" + << (int)Fich.getDT() << "," + << (int)Fich.getFI() << "," + << (int)Fich.getCS() << "," + << (int)Fich.getCM() << "," + << (int)Fich.getMR() << "," + << (int)Fich.getDev() << "," + << (int)Fich.getSQL() << "," + << (int)Fich.getSQ() << "," + << (int)Fich.getBN() << "," + << (int)Fich.getBT() << "," + << (int)Fich.getFN() << "," + << (int)Fich.getFT() << std::endl;*/ + + if ( (Fich.getDT() == YSF_DT_VD_MODE2) && (Fich.getFI() == YSF_FI_HEADER) ) + { + // build DVHeader + char sz[YSF_CALLSIGN_LENGTH+1]; + ::memcpy(sz, &(Buffer.data()[41]), YSF_CALLSIGN_LENGTH); + sz[YSF_CALLSIGN_LENGTH] = 0; + CCallsign csMY = CCallsign(); + csMY.SetYsfCallsign(sz); + ::memcpy(sz, &(Buffer.data()[61]), YSF_CALLSIGN_LENGTH); + sz[YSF_CALLSIGN_LENGTH] = 0; + CCallsign rpt1 = CCallsign((const char *)sz); + rpt1.SetModule(IMRS_MODULE_ID); + CCallsign rpt2 = m_ReflectorCallsign; + // translate dg-id to module + rpt2.SetModule(DgidToModule(Fich.getSQ())); + + // and packet + *header = new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, uiStreamId, 0); + + // debug + #ifdef DEBUG_DUMPFILE + CBuffer debug; + debug.Set((uint8 *)(Buffer.data()+0), 91); + debug.DebugDump(g_Reflector.m_DebugFile); + #endif + } + + // check validity of packets + if ( ((*header) == NULL) || !(*header)->IsValid() ) + + { + delete *header; + *header = NULL; + } + else + { + valid = true; + } + } + + // done + return valid; +} + +bool CImrsProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffer, CDvFramePacket **frames) +{ + bool valid = false; + frames[0] = NULL; + frames[1] = NULL; + frames[2] = NULL; + frames[3] = NULL; + frames[4] = NULL; + + if ( (Buffer.size() == 181) && (Buffer.at(1) == 0xA5) ) + { + // get stream id + uint32 uiStreamId = IpToStreamId(Ip); + + // and payload + CBuffer payload; + payload.SetFromAsciiHex((const char *)(Buffer.data()+19), 162); + + // fid + uint16 fid = MAKEWORD(payload.at(1), payload.at(0)); + + // fich + CYSFFICH Fich; + Fich.load((uint8 *)(payload.data()+2)); + /*std::cout << "F:" + << (int)Fich.getDT() << "," + << (int)Fich.getFI() << "," + << (int)Fich.getBN() << "," + << (int)Fich.getBT() << "," + << (int)Fich.getFN() << "," + << (int)Fich.getFT() << std::endl;*/ + + if ( (Fich.getDT() == YSF_DT_VD_MODE2) && (Fich.getFI() == YSF_FI_COMMUNICATIONS) ) + { + // dch + //CBuffer dch; + //dch.Set((uint8 *)(payload.data()+6), 10); + + // ambes + uint8 ambe0[AMBEPLUS_SIZE]; + uint8 ambe1[AMBEPLUS_SIZE]; + uint8 ambe2[AMBEPLUS_SIZE]; + uint8 ambe3[AMBEPLUS_SIZE]; + uint8 ambe4[AMBEPLUS_SIZE]; + CYsfUtils::DecodeVD2Vch((uint8 *)(payload.data()+16+0), ambe0); + CYsfUtils::DecodeVD2Vch((uint8 *)(payload.data()+16+13), ambe1); + CYsfUtils::DecodeVD2Vch((uint8 *)(payload.data()+16+26), ambe2); + CYsfUtils::DecodeVD2Vch((uint8 *)(payload.data()+16+39), ambe3); + CYsfUtils::DecodeVD2Vch((uint8 *)(payload.data()+16+52), ambe4); + + // and create frames + frames[0] = new CDvFramePacket(ambe0, uiStreamId, Fich.getFN(), 0, fid); + frames[1] = new CDvFramePacket(ambe1, uiStreamId, Fich.getFN(), 1, fid); + frames[2] = new CDvFramePacket(ambe2, uiStreamId, Fich.getFN(), 2, fid); + frames[3] = new CDvFramePacket(ambe3, uiStreamId, Fich.getFN(), 3, fid); + frames[4] = new CDvFramePacket(ambe4, uiStreamId, Fich.getFN(), 4, fid); + + // debug + //std::cout << "F:" << uiStreamId << "," << fid << "," << (int)Fich.getFN() << std::endl; + #ifdef DEBUG_DUMPFILE + CBuffer debug; + debug.Set((uint8 *)(Buffer.data()+0), 181); + debug.DebugDump(g_Reflector.m_DebugFile); + #endif + + } + + // check validity of packets + if ( (frames[0] == NULL) || !(frames[0]->IsValid()) || + (frames[1] == NULL) || !(frames[1]->IsValid()) || + (frames[2] == NULL) || !(frames[2]->IsValid()) || + (frames[3] == NULL) || !(frames[3]->IsValid()) || + (frames[4] == NULL) || !(frames[4]->IsValid()) ) + { + delete frames[0]; + delete frames[1]; + delete frames[2]; + delete frames[3]; + delete frames[4]; + frames[0] = NULL; + frames[1] = NULL; + frames[2] = NULL; + frames[3] = NULL; + frames[4] = NULL; + } + else + { + valid = true; + } + } + + // done + return valid; +} + +bool CImrsProtocol::IsValidDvLastFramePacket(const CIp &Ip, const CBuffer &Buffer, CDvFramePacket **frame) +{ + bool valid = false; + uint8 ambe[AMBEPLUS_SIZE]; + + *frame = NULL; + + if ( (Buffer.size() == 31) && (Buffer.at(1) == 0x0F) ) + { + // get stream id + uint32 uiStreamId = IpToStreamId(Ip); + + // and payload + CBuffer payload; + payload.SetFromAsciiHex((const char *)(Buffer.data()+19), 12); + + // fid + uint16 fid = MAKEWORD(payload.at(1), payload.at(0)); + + // fich + CYSFFICH Fich; + Fich.load((uint8 *)(payload.data()+2)); + + if ( (Fich.getDT() == YSF_DT_VD_MODE2) && (Fich.getFI() == YSF_FI_TERMINATOR) ) + { + // build frame + ::memset(ambe, 0x00, sizeof(ambe)); + *frame = new CDvLastFramePacket(ambe, uiStreamId, Fich.getFN(), 0, fid); + /*std::cout << "L:" + << (int)Fich.getDT() << "," + << (int)Fich.getFI() << "," + << (int)Fich.getBN() << "," + << (int)Fich.getBT() << "," + << (int)Fich.getFN() << "," + << (int)Fich.getFT() << std::endl;*/ + + // debug + #ifdef DEBUG_DUMPFILE + CBuffer debug; + debug.Set((uint8 *)(Buffer.data()+0), 31); + debug.DebugDump(g_Reflector.m_DebugFile); + #endif + } + + // check validity of packets + if ( (*frame == NULL) || !((*frame)->IsValid()) ) + + { + delete *frame; + *frame = NULL; + } + else + { + valid = true; + } + } + + // done + return valid; +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// DV packet encoding helpers + +void CImrsProtocol::EncodePingPacket(CBuffer *Buffer) const +{ + uint8 tag[] = { 0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, }; + + // tag + Buffer->Set(tag, sizeof(tag)); +} + +void CImrsProtocol::EncodePongPacket(CBuffer *Buffer) const +{ + uint8 tag1[] = { 0x00,0x2C,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x04,0x00,0x00 }; + uint8 radioid[] = { 'G','0','g','B','J' }; + char sz[YSF_CALLSIGN_LENGTH]; + + // tag + Buffer->Set(tag1, sizeof(tag1)); + // mac address + Buffer->Append(g_Reflector.GetListenMac(), 6); + // callsign + ::memset(sz, ' ', sizeof(sz)); + g_Reflector.GetCallsign().GetCallsignString(sz); + sz[::strlen(sz)] = ' '; + Buffer->Append((uint8 *)sz, YSF_CALLSIGN_LENGTH); + // radioid + Buffer->Append(radioid, sizeof(radioid)); + // list of authorised dg-id + // enable dg-id 2 & 10 -> 10+NBmodules + uint32 dgids = 0x00000004; + uint32 mask = 0x00000400; + for ( int i = 0; i < NB_OF_MODULES; i++ ) + { + dgids |= mask; + mask = mask << 1; + } + Buffer->Append(LOBYTE(LOWORD(dgids))); + Buffer->Append(HIBYTE(LOWORD(dgids))); + Buffer->Append(LOBYTE(HIWORD(dgids))); + Buffer->Append(HIBYTE(HIWORD(dgids))); + Buffer->Append((uint8)0x00, 13); + // and dg-id + Buffer->Append((uint8)2); + Buffer->Append((uint8)2); +} + +bool CImrsProtocol::EncodeDvHeaderPacket(const CDvHeaderPacket &Header, CBuffer *Buffer) const +{ + uint8 tag1[] = { 0x00,0x4B,0x00,0x00,0x00,0x00,0x07 }; + uint8 tag2[] = { 0x00,0x00,0x00,0x00,0x49,0x2a,0x2a }; + + // tag1 + Buffer->Set(tag1, sizeof(tag1)); + + // time + uint32 uiTime = (uint32)Header.GetImrsPacketFrameId() * 100; + Buffer->Append(LOBYTE(HIWORD(uiTime))); + Buffer->Append(HIBYTE(LOWORD(uiTime))); + Buffer->Append(LOBYTE(LOWORD(uiTime))); + + // steamid + uint16 uiSid = Header.GetStreamId(); + Buffer->Append(HIBYTE(uiSid)); + Buffer->Append(LOBYTE(uiSid)); + + // tag2 + Buffer->Append(tag2, sizeof(tag2)); + + // fid + uint8 fid[2]; + fid[0] = HIBYTE(Header.GetImrsPacketFrameId()); + fid[1] = LOBYTE(Header.GetImrsPacketFrameId()); + Buffer->AppendAsAsciiHex(fid, sizeof(fid)); + + // fich + CYSFFICH Fich; + Fich.setFI(YSF_FI_HEADER); + Fich.setCS(2U); + Fich.setBN(0U); + Fich.setBT(0U); + Fich.setFN(0U); + Fich.setFT(6U); + Fich.setDev(0U); + Fich.setMR(0U); + Fich.setDT(YSF_DT_VD_MODE2); + Fich.setSQL(0U); + Fich.setSQ(ModuleToDgid(Header.GetModuleId())); + Fich.setCM(1U); + uint8 fich[4]; + Fich.data(fich); + Buffer->AppendAsAsciiHex(fich, 4); + + // debug + //std::cout << "H:" << uiSid << "," << Header.GetImrsPacketFrameId() << "," << uiTime << std::endl; + + // header + Buffer->Append((uint8)' ', 60); + + // destination radioid + Buffer->ReplaceAt(31+0, (uint8 *)"*****", 5); + + // source radioid + Buffer->ReplaceAt(31+5, (uint8 *)"G0gBJ", 5); + + // source callsign = csMY + uint8 cs[YSF_CALLSIGN_LENGTH]; + ::memset(cs, ' ', sizeof(cs)); + Header.GetMyCallsign().GetCallsign(cs); + Buffer->ReplaceAt(31+10, cs, YSF_CALLSIGN_LENGTH); + + // downlink callsign is blank + + // uplink callsign = csRPT1 + ::memset(cs, ' ', sizeof(cs)); + Header.GetRpt1Callsign().GetCallsign(cs); + Buffer->ReplaceAt(31+30, cs, YSF_CALLSIGN_LENGTH); + + // downlink radioid + // uplink radioid + // voip station id (relay system ID on the internet) + + // transmission source radio id + Buffer->ReplaceAt(31+55, (uint8 *)"G0gBJ", 5); + + // done + return true; +} + + +bool CImrsProtocol::EncodeDvPacket(const CDvHeaderPacket &Header, const CDvFramePacket *DvFrames, CBuffer *Buffer) const +{ + uint8 tag1[] = { 0x00,0xA5,0x00,0x00,0x00,0x00,0x07 }; + uint8 tag2[] = { 0x00,0x00,0x00,0x00,0x32,0x2a,0x2a }; + + // tag1 + Buffer->Set(tag1, sizeof(tag1)); + + // time + uint32 uiTime = (uint32)DvFrames[0].GetImrsPacketFrameId() * 100; + Buffer->Append(LOBYTE(HIWORD(uiTime))); + Buffer->Append(HIBYTE(LOWORD(uiTime))); + Buffer->Append(LOBYTE(LOWORD(uiTime))); + + // steamid + uint16 uiSid = Header.GetStreamId(); + Buffer->Append(HIBYTE(uiSid)); + Buffer->Append(LOBYTE(uiSid)); + + // tag2 + Buffer->Append(tag2, sizeof(tag2)); + + // fid + uint8 fid[2]; + fid[0] = HIBYTE(DvFrames[0].GetImrsPacketFrameId()); + fid[1] = LOBYTE(DvFrames[0].GetImrsPacketFrameId()); + Buffer->AppendAsAsciiHex(fid, sizeof(fid)); + + // sub frame id + // todo: normally FN should be rolling from 0 to 6, but for some + // reasons, if done so, the DR-2X interrupt shortly the transmission + // after 1 second approx ???? + //uint8 uiFN = (uint8)DvFrames[0].GetImrsPacketId(); + uint8 uiFN = 0; + + // fich + CYSFFICH Fich; + Fich.setFI(YSF_FI_COMMUNICATIONS); + Fich.setCS(2U); + Fich.setBN(0U); + Fich.setBT(0U); + Fich.setFN(uiFN); + Fich.setFT(6U); + Fich.setDev(0U); + Fich.setMR(0U); + Fich.setDT(YSF_DT_VD_MODE2); + Fich.setSQL(0U); + Fich.setSQ(ModuleToDgid(Header.GetModuleId())); + uint8 fich[4]; + Fich.data(fich); + Buffer->AppendAsAsciiHex(fich, 4); + + // debug + //std::cout << "F:" << uiSid << "," << DvFrames[0].GetImrsPacketFrameId() << "," << (int)DvFrames[0].GetImrsPacketId() << "," << uiTime << std::endl; + + // todo: fill with proper content if needed + // dch + Buffer->Append((uint8*)"2A2A2A2A2A4835215245", 20); + + // ambe frames + for ( int i = 0; i < 5; i++ ) + { + uint8 ambe[13]; + CYsfUtils::EncodeVD2Vch((unsigned char *)DvFrames[i].GetAmbePlus(), ambe); + Buffer->AppendAsAsciiHex(ambe, 13); + } + + // done + return true; +} + +bool CImrsProtocol::EncodeDvLastPacket(const CDvHeaderPacket &Header, const CDvLastFramePacket &LastFrame, CBuffer *Buffer) const +{ + uint8 tag1[] = { 0x00,0x0F,0x00,0x00,0x00,0x00,0x00 }; + uint8 tag2[] = { 0x00,0x00,0x00,0x00,0x54,0x2a,0x2a }; + + // tag1 + Buffer->Set(tag1, sizeof(tag1)); + + // time + Buffer->Append((uint8)0x3e); + Buffer->Append((uint8)0x70); + Buffer->Append((uint8)0xf0); + + // steamid + uint16 uiSid = Header.GetStreamId(); + Buffer->Append(HIBYTE(uiSid)); + Buffer->Append(LOBYTE(uiSid)); + + // tag2 + Buffer->Append(tag2, sizeof(tag2)); + + // fid + uint8 fid[2]; + fid[0] = HIBYTE(LastFrame.GetImrsPacketFrameId()); + fid[1] = LOBYTE(LastFrame.GetImrsPacketFrameId()); + Buffer->AppendAsAsciiHex(fid, sizeof(fid)); + + // fich + CYSFFICH Fich; + Fich.setFI(YSF_FI_TERMINATOR); + Fich.setCS(2U); + Fich.setBN(0U); + Fich.setBT(0U); + Fich.setFN(1U); + Fich.setFT(6U); + Fich.setDev(0U); + Fich.setMR(0U); + Fich.setDT(YSF_DT_VD_MODE2); + Fich.setSQL(0U); + Fich.setSQ(ModuleToDgid(Header.GetModuleId())); + uint8 fich[4]; + Fich.data(fich); + Buffer->AppendAsAsciiHex(fich, 4); + + // debug + //std::cout << "L:" << uiSid << "," << LastFrame.GetImrsPacketFrameId() << std::endl; + + // done + return true; +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// uiStreamId helpers + +uint32 CImrsProtocol::IpToStreamId(const CIp &ip) const +{ + return ip.GetAddr() ^ (uint32)(MAKEDWORD(ip.GetPort(), ip.GetPort())); +} + +//////////////////////////////////////////////////////////////////////////////////////// +///// DG-ID helper + +char CImrsProtocol::DgidToModule(uint8 uiDgid) const +{ + char cModule = ' '; + + if ( (uiDgid >= 10) && (uiDgid < (10+NB_OF_MODULES)) ) + { + cModule = 'A' + (uiDgid-10); + } + return cModule; + +} +uint8 CImrsProtocol::ModuleToDgid(char cModule) const +{ + uint8 uiDgid = 0x00; + + if ( (cModule >+ 'A') && (cModule < ('A'+NB_OF_MODULES)) ) + { + uiDgid = 10 + (cModule - 'A'); + } + return uiDgid; +} diff --git a/src/cimrsprotocol.h b/src/cimrsprotocol.h new file mode 100644 index 0000000..62e024d --- /dev/null +++ b/src/cimrsprotocol.h @@ -0,0 +1,117 @@ +// +// cimrsprotocol..h +// xlxd +// +// Created by Jean-Luc Deltombe (LX3JL) on 29/10/2019. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd 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. +// +// xlxd 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 Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#ifndef cimrsprotocol__h +#define cimrsprotocol__h +#include "ctimepoint.h" +#include "cprotocol.h" +#include "cdvheaderpacket.h" +#include "cdvframepacket.h" +#include "cdvlastframepacket.h" +//#include "ysfdefines.h" +//#include "cysffich.h" +//#include "cwiresxinfo.h" +//#include "cwiresxcmdhandler.h" + +//////////////////////////////////////////////////////////////////////////////////////// +// define + + + +// IMRS Module ID +#define IMRS_MODULE_ID 'B' + +//////////////////////////////////////////////////////////////////////////////////////// +// class + +class CImrsStreamCacheItem +{ +public: + CImrsStreamCacheItem() {} + ~CImrsStreamCacheItem() {} + + CDvHeaderPacket m_dvHeader; + CDvFramePacket m_dvFrames[5]; + + //uint8 m_uiSeqId; +}; + +class CImrsProtocol : public CProtocol +{ +public: + // constructor + CImrsProtocol() {}; + + // destructor + virtual ~CImrsProtocol() {}; + + // initialization + bool Init(void); + void Close(void); + + // task + void Task(void); + +protected: + // queue helper + void HandleQueue(void); + + // keepalive helpers + void HandleKeepalives(void); + + // stream helpers + bool OnDvHeaderPacketIn(CDvHeaderPacket *, const CIp &); + + // DV packet decoding helpers + bool IsValidPingPacket(const CBuffer &); + bool IsValidConnectPacket(const CBuffer &, CCallsign *); + bool IsValidDvHeaderPacket(const CIp &, const CBuffer &, CDvHeaderPacket **); + bool IsValidDvLastFramePacket(const CIp &, const CBuffer &, CDvFramePacket **); + bool IsValidDvFramePacket(const CIp &, const CBuffer &, CDvFramePacket **); + //bool IsValidDvLastFramePacket(const CIp &, const CYSFFICH &, const CBuffer &, CDvFramePacket **); + + // DV packet encoding helpers + void EncodePingPacket(CBuffer *) const; + void EncodePongPacket(CBuffer *) const; + bool EncodeDvHeaderPacket(const CDvHeaderPacket &, CBuffer *) const; + bool EncodeDvPacket(const CDvHeaderPacket &, const CDvFramePacket *, CBuffer *) const; + bool EncodeDvLastPacket(const CDvHeaderPacket &, const CDvLastFramePacket &, CBuffer *) const; + + // uiStreamId helpers + uint32 IpToStreamId(const CIp &) const; + + // DG-ID helper + char DgidToModule(uint8 uiDgid) const; + uint8 ModuleToDgid(char cModule) const; + +protected: + // for keep alive + CTimePoint m_LastKeepaliveTime; + + // for queue header caches + std::array m_StreamsCache; +}; + +//////////////////////////////////////////////////////////////////////////////////////// +#endif /* cimrsprotocol__h */ diff --git a/src/cip.h b/src/cip.h index 6c43288..8d52cde 100644 --- a/src/cip.h +++ b/src/cip.h @@ -46,10 +46,13 @@ public: void SetSockAddr(struct sockaddr_in *); struct sockaddr_in *GetSockAddr(void) { return &m_Addr; } - // convertor + // get uint32 GetAddr(void) const { return m_Addr.sin_addr.s_addr; } uint16 GetPort(void) const { return m_Addr.sin_port; } + // set + void SetPort(uint16 port) { m_Addr.sin_port = port; } + // operator bool operator ==(const CIp &) const; operator const char *() const; diff --git a/src/cpacket.cpp b/src/cpacket.cpp index 94bf645..3fe3bd5 100644 --- a/src/cpacket.cpp +++ b/src/cpacket.cpp @@ -39,6 +39,9 @@ CPacket::CPacket() m_uiYsfPacketId = 0; m_uiYsfPacketSubId = 0; m_uiYsfPacketFrameId = 0; + m_uiImrsPacketId = 0; + m_uiImrsPacketSubId = 0; + m_uiImrsPacketFrameId = 0; m_uiModuleId = ' '; m_uiOriginId = ORIGIN_LOCAL; }; @@ -54,6 +57,9 @@ CPacket::CPacket(uint16 sid, uint8 dstarpid) m_uiYsfPacketId = 0xFF; m_uiYsfPacketSubId = 0xFF; m_uiYsfPacketFrameId = 0xFF; + m_uiImrsPacketId = 0xFF; + m_uiImrsPacketSubId = 0xFF; + m_uiImrsPacketFrameId = 0xFFFF; m_uiModuleId = ' '; m_uiOriginId = ORIGIN_LOCAL; }; @@ -69,6 +75,9 @@ CPacket::CPacket(uint16 sid, uint8 dmrpid, uint8 dmrspid) m_uiYsfPacketId = 0xFF; m_uiYsfPacketSubId = 0xFF; m_uiYsfPacketFrameId = 0xFF; + m_uiImrsPacketId = 0xFF; + m_uiImrsPacketSubId = 0xFF; + m_uiImrsPacketFrameId = 0xFFFF; m_uiModuleId = ' '; m_uiOriginId = ORIGIN_LOCAL; }; @@ -84,13 +93,34 @@ CPacket::CPacket(uint16 sid, uint8 ysfpid, uint8 ysfsubpid, uint8 ysffrid) m_uiDstarPacketId = 0xFF; m_uiDmrPacketId = 0xFF; m_uiDmrPacketSubid = 0xFF; + m_uiImrsPacketId = 0xFF; + m_uiImrsPacketSubId = 0xFF; + m_uiImrsPacketFrameId = 0xFFFF; + m_uiModuleId = ' '; + m_uiOriginId = ORIGIN_LOCAL; +} + +// imrs constructor + +CPacket::CPacket(uint16 sid, uint8 imrspid, uint8 imrssubid, uint16 imrsfrid) +{ + m_uiStreamId = sid; + m_uiImrsPacketId = imrspid; + m_uiImrsPacketFrameId = imrsfrid; + m_uiImrsPacketSubId = imrssubid; + m_uiYsfPacketId = 0xFF; + m_uiYsfPacketSubId = 0xFF; + m_uiYsfPacketFrameId = 0xFF; + m_uiDstarPacketId = 0xFF; + m_uiDmrPacketId = 0xFF; + m_uiDmrPacketSubid = 0xFF; m_uiModuleId = ' '; m_uiOriginId = ORIGIN_LOCAL; } // xlx constructor -CPacket::CPacket(uint16 sid, uint8 dstarpid, uint8 dmrpid, uint8 dmrsubpid, uint8 ysfpid, uint8 ysfsubpid, uint8 ysffrid) +CPacket::CPacket(uint16 sid, uint8 dstarpid, uint8 dmrpid, uint8 dmrsubpid, uint8 ysfpid, uint8 ysfsubpid, uint8 ysffrid, uint8 imrspid, uint8 imrssubid, uint16 imrsfrid) { m_uiStreamId = sid; m_uiDstarPacketId = dstarpid; @@ -99,6 +129,9 @@ CPacket::CPacket(uint16 sid, uint8 dstarpid, uint8 dmrpid, uint8 dmrsubpid, uint m_uiYsfPacketId = ysfpid; m_uiYsfPacketSubId = ysfsubpid; m_uiYsfPacketFrameId = ysffrid; + m_uiImrsPacketId = imrspid; + m_uiImrsPacketSubId = imrssubid; + m_uiImrsPacketFrameId = imrsfrid; m_uiModuleId = ' '; m_uiOriginId = ORIGIN_LOCAL; } @@ -133,11 +166,24 @@ void CPacket::UpdatePids(uint32 pid) m_uiDmrPacketId = ((pid / 3) % 6); m_uiDmrPacketSubid = ((pid % 3) + 1); } - // ysf pids need update ? + // ysf need update ? if ( m_uiYsfPacketId == 0xFF ) { m_uiYsfPacketId = ((pid / 5) % 8); m_uiYsfPacketSubId = pid % 5; + } + if ( m_uiYsfPacketFrameId == 0xFF ) + { m_uiYsfPacketFrameId = ((pid / 5) & 0x7FU) << 1; } + // imrs pid needs update ? + if ( m_uiImrsPacketId == 0xFF ) + { + m_uiImrsPacketId = ((pid / 5) % 7); + m_uiImrsPacketSubId = (pid % 5); + } + if ( m_uiImrsPacketFrameId == 0xFFFF ) + { + m_uiImrsPacketFrameId = LOWORD(pid / 5); + } } diff --git a/src/cpacket.h b/src/cpacket.h index eddcd39..b9aea64 100644 --- a/src/cpacket.h +++ b/src/cpacket.h @@ -42,8 +42,9 @@ public: CPacket(); CPacket(uint16 sid, uint8 dstarpid); CPacket(uint16 sid, uint8 dmrpid, uint8 dmrsubpid); - CPacket(uint16 sid, uint8 ysfpid, uint8 ysfsubpid, uint8 ysfsubpidmax); - CPacket(uint16 sid, uint8 dstarpid, uint8 dmrpid, uint8 dmrsubpid, uint8 ysfpid, uint8 ysfsubpid, uint8 ysfsubpidmax); + CPacket(uint16 sid, uint8 ysfpid, uint8 ysfsubpid, uint8 ysffrid); + CPacket(uint16 sid, uint8 imrspid, uint8 imrssubid, uint16 imrsfrid); + CPacket(uint16 sid, uint8 dstarpid, uint8 dmrpid, uint8 dmrsubpid, uint8 ysfpid, uint8 ysfsubpid, uint8 ysffrid, uint8 imrspid, uint8 imrssubid, uint16 imrsfrid); // destructor virtual ~CPacket() {}; @@ -67,6 +68,9 @@ public: uint8 GetYsfPacketId(void) const { return m_uiYsfPacketId; } uint8 GetYsfPacketSubId(void) const { return m_uiYsfPacketSubId; } uint8 GetYsfPacketFrameId(void) const { return m_uiYsfPacketFrameId; } + uint8 GetImrsPacketId(void) const { return m_uiImrsPacketId; } + uint16 GetImrsPacketFrameId(void) const { return m_uiImrsPacketFrameId; } + uint8 GetImrsPacketSubId(void) const { return m_uiImrsPacketSubId; } uint8 GetModuleId(void) const { return m_uiModuleId; } bool IsLocalOrigin(void) const { return (m_uiOriginId == ORIGIN_LOCAL); } @@ -77,16 +81,23 @@ public: void SetRemotePeerOrigin(void) { m_uiOriginId = ORIGIN_PEER; } protected: - // data + // common uint16 m_uiStreamId; + uint8 m_uiModuleId; + uint8 m_uiOriginId; + // dstar uint8 m_uiDstarPacketId; + // dmr uint8 m_uiDmrPacketId; uint8 m_uiDmrPacketSubid; + // ysf uint8 m_uiYsfPacketId; uint8 m_uiYsfPacketSubId; uint8 m_uiYsfPacketFrameId; - uint8 m_uiModuleId; - uint8 m_uiOriginId; + // imrs + uint8 m_uiImrsPacketId; + uint16 m_uiImrsPacketFrameId; + uint8 m_uiImrsPacketSubId; }; diff --git a/src/cprotocols.cpp b/src/cprotocols.cpp index bc6c4d4..bed9744 100644 --- a/src/cprotocols.cpp +++ b/src/cprotocols.cpp @@ -31,6 +31,7 @@ #include "cdmrmmdvmprotocol.h" #include "cysfprotocol.h" #include "cg3protocol.h" +#include "cimrsprotocol.h" #include "cprotocols.h" @@ -109,6 +110,10 @@ bool CProtocols::Init(void) m_Protocols[7] = new CG3Protocol; ok &= m_Protocols[7]->Init(); + // create and initialize IMRS + delete m_Protocols[8]; + m_Protocols[8] = new CImrsProtocol; + ok &= m_Protocols[8]->Init(); } m_Mutex.unlock(); diff --git a/src/creflector.cpp b/src/creflector.cpp index 2eeea8b..1f5e65b 100644 --- a/src/creflector.cpp +++ b/src/creflector.cpp @@ -44,8 +44,9 @@ CReflector::CReflector() { m_RouterThreads[i] = NULL; } + ::memset(m_Mac, 0, sizeof(m_Mac)); #ifdef DEBUG_DUMPFILE - m_DebugFile.open("/Users/jeanluc/Desktop/xlxdebug.txt"); + m_DebugFile.open("/Users/jean-luc/Desktop/xlxdebug.txt"); #endif } @@ -62,6 +63,7 @@ CReflector::CReflector(const CCallsign &callsign) m_RouterThreads[i] = NULL; } m_Callsign = callsign; + ::memset(m_Mac, 0, sizeof(m_Mac)); } //////////////////////////////////////////////////////////////////////////////////////// @@ -100,7 +102,7 @@ bool CReflector::Start(void) // reset stop flag m_bStopThreads = false; - + // init gate keeper ok &= g_GateKeeper.Init(); @@ -768,3 +770,152 @@ void CReflector::SendJsonOffairObject(CUdpSocket &Socket, CIp &Ip, const CCallsi //std::cout << Buffer << std::endl; Socket.Send(Buffer, Ip); } + +//////////////////////////////////////////////////////////////////////////////////////// +// MAC address helpers + +#ifdef __linux__ +#include +bool CReflector::UpdateListenMac(void) +{ + struct ifaddrs *ifap, *ifaptr; + char host[NI_MAXHOST]; + char *ifname = NULL; + bool found = false; + + // iterate through all our AF_INET interface to find the one + // of our listening ip + if ( getifaddrs(&ifap) == 0 ) + { + for ( ifaptr = ifap; (ifaptr != NULL) && !found; ifaptr = (ifaptr)->ifa_next ) + { + // is it an AF_INET? + if ( ifaptr->ifa_addr->sa_family == AF_INET ) + { + if (ifaptr->ifa_addr == NULL) + continue; + + // get the IP + if ( getnameinfo(ifaptr->ifa_addr, + sizeof(struct sockaddr_in), + host, NI_MAXHOST, + NULL, 0, NI_NUMERICHOST) == 0 ) + { + if ( CIp(host) == m_Ip ) + { + // yes, found it + found = true; + ifname = new char[strlen(ifaptr->ifa_name)+1]; + strcpy(ifname, ifaptr->ifa_name); + } + } + } + + } + freeifaddrs(ifap); + } + + // if listening interface name found, iterate again + // to find the corresponding AF_PACKET interface + if ( found ) + { + found = false; + if ( getifaddrs(&ifap) == 0 ) + { + for ( ifaptr = ifap; (ifaptr != NULL) && !found; ifaptr = (ifaptr)->ifa_next ) + { + if ( !strcmp((ifaptr)->ifa_name, ifname) && (ifaptr->ifa_addr->sa_family == AF_PACKET) ) + { + found = true; + struct sockaddr_ll *s = (struct sockaddr_ll *)(ifaptr->ifa_addr); + for ( int i = 0; i < 6; i++ ) + { + m_Mac[i] = s->sll_addr[i]; + } + } + } + } + freeifaddrs(ifap); + } + + // done + return found; +} +#endif + +#if defined(__APPLE__) && defined(__MACH__) +#include +bool CReflector::UpdateListenMac(void) +{ + struct ifaddrs *ifaddr; + int s; + char host[NI_MAXHOST]; + char *ifname = NULL; + bool found = false; + bool ok = false; + + if ( getifaddrs(&ifaddr) != -1) + { + // Walk through linked list, maintaining head pointer so we can free list later. + // until finding our listening AF_INET interface + for (struct ifaddrs *ifa = ifaddr; (ifa != NULL) && !found; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr == NULL) + continue; + + // is it an AF_INET? + if (ifa->ifa_addr->sa_family == AF_INET) + { + // get IP + s = getnameinfo(ifa->ifa_addr, + sizeof(struct sockaddr_in), + host, NI_MAXHOST, + NULL, 0, NI_NUMERICHOST); + if (s != 0) + { + return false; + } + // is it our listening ip ? + if ( CIp(host) == m_Ip ) + { + // yes, found it + found = true; + ifname = new char[strlen(ifa->ifa_name)+1]; + strcpy(ifname, ifa->ifa_name); + } + } + } + freeifaddrs(ifaddr); + + // found our interface ? + if ( found ) + { + // yes + //std::cout << ifname << " : " << host << std::endl; + + // Walk again through linked list + // until finding our listening AF_LINK interface + if ( getifaddrs(&ifaddr) != -1 ) + { + found = false; + for (struct ifaddrs *ifa = ifaddr; (ifa != NULL) && !found; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr == NULL) + continue; + + if ( !strcmp(ifa->ifa_name, ifname) && (ifa->ifa_addr->sa_family == AF_LINK)) + { + ::memcpy((void *)m_Mac, (void *)LLADDR((struct sockaddr_dl *)(ifa)->ifa_addr), sizeof(m_Mac)); + ok = true; + found = true; + } + } + freeifaddrs(ifaddr); + } + } + + delete [] ifname; + } + return ok; +} +#endif diff --git a/src/creflector.h b/src/creflector.h index 1424453..ece983e 100644 --- a/src/creflector.h +++ b/src/creflector.h @@ -57,9 +57,10 @@ public: // settings void SetCallsign(const CCallsign &callsign) { m_Callsign = callsign; } const CCallsign &GetCallsign(void) const { return m_Callsign; } - void SetListenIp(const CIp &ip) { m_Ip = ip; } + void SetListenIp(const CIp &ip) { m_Ip = ip; UpdateListenMac(); } void SetTranscoderIp(const CIp &ip) { m_AmbedIp = ip; } const CIp &GetListenIp(void) const { return m_Ip; } + const uint8 *GetListenMac(void) const { return (const uint8 *)m_Mac; } const CIp &GetTranscoderIp(void) const { return m_AmbedIp; } // operation @@ -116,10 +117,14 @@ protected: void SendJsonOnairObject(CUdpSocket &, CIp &, const CCallsign &); void SendJsonOffairObject(CUdpSocket &, CIp &, const CCallsign &); + // MAC address helpers + bool UpdateListenMac(void); + protected: // identity CCallsign m_Callsign; CIp m_Ip; + uint8 m_Mac[6]; CIp m_AmbedIp; // objects diff --git a/src/cysffich.cpp b/src/cysffich.cpp index 36a093b..46a331b 100644 --- a/src/cysffich.cpp +++ b/src/cysffich.cpp @@ -306,3 +306,9 @@ void CYSFFICH::load(const unsigned char* fich) ::memcpy(m_fich, fich, 4U); } +void CYSFFICH::data(unsigned char* fich) +{ + assert(fich != NULL); + + ::memcpy(fich, m_fich, 4U); +} diff --git a/src/cysffich.h b/src/cysffich.h index 7adcad8..1e21990 100644 --- a/src/cysffich.h +++ b/src/cysffich.h @@ -57,6 +57,7 @@ public: void setSQ(unsigned char sq); void load(const unsigned char* fich); + void data(unsigned char* fich); private: unsigned char* m_fich; diff --git a/src/cysfprotocol.cpp b/src/cysfprotocol.cpp index 61d8357..572464f 100644 --- a/src/cysfprotocol.cpp +++ b/src/cysfprotocol.cpp @@ -469,17 +469,21 @@ bool CYsfProtocol::IsValidDvHeaderPacket(const CIp &Ip, const CYSFFICH &Fich, co char sz[YSF_CALLSIGN_LENGTH+1]; ::memcpy(sz, &(Buffer.data()[14]), YSF_CALLSIGN_LENGTH); sz[YSF_CALLSIGN_LENGTH] = 0; - CCallsign csMY = CCallsign((const char *)sz); + CCallsign csMY = CCallsign(); + csMY.SetYsfCallsign(sz); ::memcpy(sz, &(Buffer.data()[4]), YSF_CALLSIGN_LENGTH); sz[YSF_CALLSIGN_LENGTH] = 0; CCallsign rpt1 = CCallsign((const char *)sz); rpt1.SetModule(YSF_MODULE_ID); CCallsign rpt2 = m_ReflectorCallsign; - if ( (Fich.getSQ() >= 10) && (Fich.getSQ() < 10+NB_OF_MODULES) ) { + if ( (Fich.getSQ() >= 10) && (Fich.getSQ() < 10+NB_OF_MODULES) ) + { // set module based on DG-ID value rpt2.SetModule( 'A' + (char)(Fich.getSQ() - 10) ); - } else { + } + else + { // as YSF protocol does not provide a module-tranlatable // destid, set module to none and rely on OnDvHeaderPacketIn() // to later fill it with proper value @@ -493,8 +497,8 @@ bool CYsfProtocol::IsValidDvHeaderPacket(const CIp &Ip, const CYSFFICH &Fich, co { uint8 uiAmbe[AMBE_SIZE]; ::memset(uiAmbe, 0x00, sizeof(uiAmbe)); - frames[0] = new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 0, 0); - frames[1] = new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 1, 0); + frames[0] = new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 0, (uint8)0); + frames[1] = new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 1, (uint8)0); } // check validity of packets @@ -597,8 +601,8 @@ bool CYsfProtocol::IsValidDvLastFramePacket(const CIp &Ip, const CYSFFICH &Fich, { uint8 uiAmbe[AMBE_SIZE]; ::memset(uiAmbe, 0x00, sizeof(uiAmbe)); - frames[0] = new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 0, 0); - frames[1] = new CDvLastFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 1, 0); + frames[0] = new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 0, (uint8)0); + frames[1] = new CDvLastFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 1, (uint8)0); } // check validity of packets diff --git a/src/cysfutils.cpp b/src/cysfutils.cpp index 914f684..6a5475b 100644 --- a/src/cysfutils.cpp +++ b/src/cysfutils.cpp @@ -472,7 +472,7 @@ const unsigned char WHITENING_DATA[] = {0x93U, 0xD7U, 0x51U, 0x21U, 0x9CU, 0x2FU #define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) //////////////////////////////////////////////////////////////////////////////////////// -// +// decode void CYsfUtils::DecodeVD2Vchs(uint8 *data, uint8 **ambe) { @@ -555,6 +555,80 @@ void CYsfUtils::DecodeVD2Vchs(uint8 *data, uint8 **ambe) } } +void CYsfUtils::DecodeVD2Vch(uint8 *data, uint8 *ambe) +{ + unsigned char vch[13U]; + unsigned int dat_a = 0U; + unsigned int dat_b = 0U; + unsigned int dat_c = 0U; + + // Deinterleave + for (unsigned int i = 0U; i < 104U; i++) { + unsigned int n = INTERLEAVE_TABLE_26_4[i]; + bool s = READ_BIT(data, n); + WRITE_BIT(vch, i, s); + } + + // "Un-whiten" (descramble) + for (unsigned int i = 0U; i < 13U; i++) + vch[i] ^= WHITENING_DATA[i]; + + for (unsigned int i = 0U; i < 12U; i++) { + dat_a <<= 1U; + if (READ_BIT(vch, 3U*i + 1U)) + dat_a |= 0x01U;; + } + + for (unsigned int i = 0U; i < 12U; i++) { + dat_b <<= 1U; + if (READ_BIT(vch, 3U*(i + 12U) + 1U)) + dat_b |= 0x01U;; + } + + for (unsigned int i = 0U; i < 3U; i++) { + dat_c <<= 1U; + if (READ_BIT(vch, 3U*(i + 24U) + 1U)) + dat_c |= 0x01U;; + } + + for (unsigned int i = 0U; i < 22U; i++) { + dat_c <<= 1U; + if (READ_BIT(vch, i + 81U)) + dat_c |= 0x01U;; + } + + // convert to ambe2plus + unsigned char v_dmr[9U]; + + unsigned int a = CGolay24128::encode24128(dat_a); + unsigned int p = PRNG_TABLE[dat_a] >> 1; + unsigned int b = CGolay24128::encode23127(dat_b) >> 1; + b ^= p; + + unsigned int MASK = 0x800000U; + for (unsigned int i = 0U; i < 24U; i++, MASK >>= 1) { + unsigned int aPos = DMR_A_TABLE[i]; + WRITE_BIT(v_dmr, aPos, a & MASK); + } + + MASK = 0x400000U; + for (unsigned int i = 0U; i < 23U; i++, MASK >>= 1) { + unsigned int bPos = DMR_B_TABLE[i]; + WRITE_BIT(v_dmr, bPos, b & MASK); + } + + MASK = 0x1000000U; + for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) { + unsigned int cPos = DMR_C_TABLE[i]; + WRITE_BIT(v_dmr, cPos, dat_c & MASK); + } + + ::memcpy(ambe, v_dmr, 9); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// encode + void CYsfUtils::EncodeVD2Vch(uint8 *ambe, uint8 *data) { // convert from ambe2plus diff --git a/src/cysfutils.h b/src/cysfutils.h index 90a9a01..508e560 100644 --- a/src/cysfutils.h +++ b/src/cysfutils.h @@ -40,10 +40,10 @@ public: // destructor virtual ~CYsfUtils() {}; - // operation + // code / decode static void DecodeVD2Vchs(uint8 *, uint8 **); + static void DecodeVD2Vch(uint8 *, uint8 *); static void EncodeVD2Vch(uint8 *, uint8 *); - protected: // data diff --git a/src/main.h b/src/main.h index 4212a3e..ae10c8c 100644 --- a/src/main.h +++ b/src/main.h @@ -41,6 +41,7 @@ #include #include #include +#include //////////////////////////////////////////////////////////////////////////////////////// // defines @@ -48,8 +49,8 @@ // version ----------------------------------------------------- #define VERSION_MAJOR 2 -#define VERSION_MINOR 4 -#define VERSION_REVISION 2 +#define VERSION_MINOR 5 +#define VERSION_REVISION 0 // global ------------------------------------------------------ @@ -69,7 +70,7 @@ // protocols --------------------------------------------------- -#define NB_OF_PROTOCOLS 8 +#define NB_OF_PROTOCOLS 9 #define PROTOCOL_ANY -1 #define PROTOCOL_NONE 0 @@ -81,6 +82,7 @@ #define PROTOCOL_DMRMMDVM 6 #define PROTOCOL_YSF 7 #define PROTOCOL_G3 8 +#define PROTOCOL_IMRS 9 // DExtra #define DEXTRA_PORT 30001 // UDP port @@ -133,6 +135,11 @@ #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 // Transcoder server -------------------------------------------- From 43c1a10832b45782baf6cca6828959ba5462e4d6 Mon Sep 17 00:00:00 2001 From: narspt Date: Thu, 28 Oct 2021 23:07:52 +0100 Subject: [PATCH 2/4] fix SetYsfCallsign() missing dmrid update this caused YSF transmissions to show-up on DMR listeners with dmrid 0 --- src/ccallsign.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ccallsign.cpp b/src/ccallsign.cpp index 03966c7..6206f65 100644 --- a/src/ccallsign.cpp +++ b/src/ccallsign.cpp @@ -221,6 +221,12 @@ void CCallsign::SetYsfCallsign(const char *sz) m_Suffix[j++] = sz[i]; } } + // and update dmrid + g_DmridDir.Lock(); + { + m_uiDmrid = g_DmridDir.FindDmrid(*this); + } + g_DmridDir.Unlock(); } void CCallsign::SetDmrid(uint32 dmrid, bool UpdateCallsign) From b411eb8b8a4f698e5c3dc683e8d3ff4630c2a908 Mon Sep 17 00:00:00 2001 From: LX3JL Date: Sat, 30 Oct 2021 18:21:05 +0200 Subject: [PATCH 3/4] corrected bug preventing relaying streams on module 'A' of IMRS clients corrected bug xlxd not advertising module W,X,Y & Z to IMRS clients --- src/cimrsprotocol.cpp | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/cimrsprotocol.cpp b/src/cimrsprotocol.cpp index 9f31a18..d64d1ee 100644 --- a/src/cimrsprotocol.cpp +++ b/src/cimrsprotocol.cpp @@ -658,18 +658,29 @@ void CImrsProtocol::EncodePongPacket(CBuffer *Buffer) const Buffer->Append(radioid, sizeof(radioid)); // list of authorised dg-id // enable dg-id 2 & 10 -> 10+NBmodules - uint32 dgids = 0x00000004; - uint32 mask = 0x00000400; - for ( int i = 0; i < NB_OF_MODULES; i++ ) + uint32 dgids32 = 0x00000004; + uint32 mask32 = 0x00000400; + // modules 10->31 + for ( int i = 0; i < MIN(NB_OF_MODULES,22); i++ ) { - dgids |= mask; - mask = mask << 1; + dgids32 |= mask32; + mask32 = mask32 << 1; } - Buffer->Append(LOBYTE(LOWORD(dgids))); - Buffer->Append(HIBYTE(LOWORD(dgids))); - Buffer->Append(LOBYTE(HIWORD(dgids))); - Buffer->Append(HIBYTE(HIWORD(dgids))); - Buffer->Append((uint8)0x00, 13); + Buffer->Append(LOBYTE(LOWORD(dgids32))); + Buffer->Append(HIBYTE(LOWORD(dgids32))); + Buffer->Append(LOBYTE(HIWORD(dgids32))); + Buffer->Append(HIBYTE(HIWORD(dgids32))); + // module 32->35 + uint8 dgids8 = 0x00; + uint8 mask8 = 0x01; + for ( int i = 23; i < NB_OF_MODULES; i++ ) + { + dgids8 |= mask8; + mask8 = mask8 << 1; + + } + Buffer->Append(dgids8); + Buffer->Append((uint8)0x00, 12); // and dg-id Buffer->Append((uint8)2); Buffer->Append((uint8)2); @@ -907,7 +918,7 @@ uint8 CImrsProtocol::ModuleToDgid(char cModule) const { uint8 uiDgid = 0x00; - if ( (cModule >+ 'A') && (cModule < ('A'+NB_OF_MODULES)) ) + if ( (cModule >= 'A') && (cModule < ('A'+NB_OF_MODULES)) ) { uiDgid = 10 + (cModule - 'A'); } From c3de5fa8936e28fe93933406dd537982d12c1549 Mon Sep 17 00:00:00 2001 From: LX3JL Date: Sat, 30 Oct 2021 23:09:48 +0200 Subject: [PATCH 4/4] corrected deadloop in CImrsProtocol::EncodePongPacket() --- src/cimrsprotocol.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/cimrsprotocol.cpp b/src/cimrsprotocol.cpp index d64d1ee..4ad5fe3 100644 --- a/src/cimrsprotocol.cpp +++ b/src/cimrsprotocol.cpp @@ -660,8 +660,8 @@ void CImrsProtocol::EncodePongPacket(CBuffer *Buffer) const // enable dg-id 2 & 10 -> 10+NBmodules uint32 dgids32 = 0x00000004; uint32 mask32 = 0x00000400; - // modules 10->31 - for ( int i = 0; i < MIN(NB_OF_MODULES,22); i++ ) + // modules 10->31 + for ( int i = 0; i < (int)(MIN(NB_OF_MODULES,22)); i++ ) { dgids32 |= mask32; mask32 = mask32 << 1; @@ -673,11 +673,10 @@ void CImrsProtocol::EncodePongPacket(CBuffer *Buffer) const // module 32->35 uint8 dgids8 = 0x00; uint8 mask8 = 0x01; - for ( int i = 23; i < NB_OF_MODULES; i++ ) + for ( int i = 22; i < NB_OF_MODULES; i++ ) { dgids8 |= mask8; mask8 = mask8 << 1; - } Buffer->Append(dgids8); Buffer->Append((uint8)0x00, 12);