mirror of
https://github.com/LX3JL/xlxd.git
synced 2025-12-06 07:42:01 +01:00
Merge pull request #202 from LX3JL/IMRS
implementation of Yaesu's IRMS protocol
This commit is contained in:
commit
a64b20bc07
|
|
@ -29,7 +29,7 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// constructor
|
// constructor
|
||||||
|
|
||||||
CBuffer::CBuffer(uint8 *buffer, int len)
|
CBuffer::CBuffer(const uint8 *buffer, int len)
|
||||||
{
|
{
|
||||||
resize(len);
|
resize(len);
|
||||||
::memcpy(data(), buffer, len);
|
::memcpy(data(), buffer, len);
|
||||||
|
|
@ -38,7 +38,7 @@ CBuffer::CBuffer(uint8 *buffer, int len)
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// set
|
// set
|
||||||
|
|
||||||
void CBuffer::Set(uint8 *buffer, int len)
|
void CBuffer::Set(const uint8 *buffer, int len)
|
||||||
{
|
{
|
||||||
resize(len);
|
resize(len);
|
||||||
::memcpy(data(), buffer, len);
|
::memcpy(data(), buffer, len);
|
||||||
|
|
@ -50,7 +50,21 @@ void CBuffer::Set(const char *sz)
|
||||||
::strcpy((char *)data(), 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();
|
int n = (int)size();
|
||||||
resize(n+len);
|
resize(n+len);
|
||||||
|
|
@ -91,6 +105,17 @@ void CBuffer::Append(const char *sz)
|
||||||
Append((uint8)0x00);
|
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)
|
void CBuffer::ReplaceAt(int i, uint8 ui)
|
||||||
{
|
{
|
||||||
if ( size() < (i+sizeof(uint8)) )
|
if ( size() < (i+sizeof(uint8)) )
|
||||||
|
|
@ -130,7 +155,7 @@ void CBuffer::ReplaceAt(int i, const uint8 *ptr, int len)
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// operation
|
// operation
|
||||||
|
|
||||||
int CBuffer::Compare(uint8 *buffer, int len) const
|
int CBuffer::Compare(const uint8 *buffer, int len) const
|
||||||
{
|
{
|
||||||
int result = -1;
|
int result = -1;
|
||||||
if ( size() >= len )
|
if ( size() >= len )
|
||||||
|
|
@ -140,7 +165,7 @@ int CBuffer::Compare(uint8 *buffer, int len) const
|
||||||
return result;
|
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;
|
int result = -1;
|
||||||
if ( size() >= (off+len) )
|
if ( size() >= (off+len) )
|
||||||
|
|
|
||||||
|
|
@ -32,28 +32,30 @@ class CBuffer : public std::vector<uint8>
|
||||||
public:
|
public:
|
||||||
// constructor
|
// constructor
|
||||||
CBuffer() {};
|
CBuffer() {};
|
||||||
CBuffer(uint8 *, int);
|
CBuffer(const uint8 *, int);
|
||||||
|
|
||||||
// destructor
|
// destructor
|
||||||
virtual ~CBuffer() {};
|
virtual ~CBuffer() {};
|
||||||
|
|
||||||
// set
|
// set
|
||||||
void Set(uint8 *, int);
|
void Set(const uint8 *, int);
|
||||||
void Set(const char *);
|
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, int);
|
||||||
void Append(uint8);
|
void Append(uint8);
|
||||||
void Append(uint16);
|
void Append(uint16);
|
||||||
void Append(uint32);
|
void Append(uint32);
|
||||||
void Append(const char *);
|
void Append(const char *);
|
||||||
|
void AppendAsAsciiHex(uint8 *, int);
|
||||||
void ReplaceAt(int, uint8);
|
void ReplaceAt(int, uint8);
|
||||||
void ReplaceAt(int, uint16);
|
void ReplaceAt(int, uint16);
|
||||||
void ReplaceAt(int, uint32);
|
void ReplaceAt(int, uint32);
|
||||||
void ReplaceAt(int, const uint8 *, int);
|
void ReplaceAt(int, const uint8 *, int);
|
||||||
|
|
||||||
// operation
|
// operation
|
||||||
int Compare(uint8 *, int) const;
|
int Compare(const uint8 *, int) const;
|
||||||
int Compare(uint8 *, int, int) const;
|
int Compare(const uint8 *, int, int) const;
|
||||||
|
|
||||||
// operator
|
// operator
|
||||||
bool operator ==(const CBuffer &) const;
|
bool operator ==(const CBuffer &) const;
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include "cdmriddirfile.h"
|
#include "cdmriddirfile.h"
|
||||||
#include "cdmriddirhttp.h"
|
#include "cdmriddirhttp.h"
|
||||||
|
#include "ysfdefines.h"
|
||||||
#include "ccallsign.h"
|
#include "ccallsign.h"
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -195,6 +196,39 @@ 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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// and update dmrid
|
||||||
|
g_DmridDir.Lock();
|
||||||
|
{
|
||||||
|
m_uiDmrid = g_DmridDir.FindDmrid(*this);
|
||||||
|
}
|
||||||
|
g_DmridDir.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
void CCallsign::SetDmrid(uint32 dmrid, bool UpdateCallsign)
|
void CCallsign::SetDmrid(uint32 dmrid, bool UpdateCallsign)
|
||||||
{
|
{
|
||||||
m_uiDmrid = dmrid;
|
m_uiDmrid = dmrid;
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ public:
|
||||||
// set
|
// set
|
||||||
void SetCallsign(const char *, bool = true);
|
void SetCallsign(const char *, bool = true);
|
||||||
void SetCallsign(const uint8 *, int, bool = true);
|
void SetCallsign(const uint8 *, int, bool = true);
|
||||||
|
void SetYsfCallsign(const char *);
|
||||||
void SetDmrid(uint32, bool = true);
|
void SetDmrid(uint32, bool = true);
|
||||||
void SetDmrid(const uint8 *, bool = true);
|
void SetDmrid(const uint8 *, bool = true);
|
||||||
void SetModule(char);
|
void SetModule(char);
|
||||||
|
|
|
||||||
|
|
@ -72,13 +72,24 @@ CDvFramePacket::CDvFramePacket(const uint8 *ambe, uint16 sid, uint8 pid, uint8 s
|
||||||
::memset(m_uiDvData, 0, sizeof(m_uiDvData));
|
::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
|
// xlx constructor
|
||||||
|
|
||||||
CDvFramePacket::CDvFramePacket
|
CDvFramePacket::CDvFramePacket
|
||||||
(uint16 sid,
|
(uint16 sid,
|
||||||
uint8 dstarpid, const uint8 *dstarambe, const uint8 *dstardvdata,
|
uint8 dstarpid, const uint8 *dstarambe, const uint8 *dstardvdata,
|
||||||
uint8 dmrpid, uint8 dprspid, const uint8 *dmrambe, const uint8 *dmrsync)
|
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_uiAmbe, dstarambe, sizeof(m_uiAmbe));
|
||||||
::memcpy(m_uiDvData, dstardvdata, sizeof(m_uiDvData));
|
::memcpy(m_uiDvData, dstardvdata, sizeof(m_uiDvData));
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ public:
|
||||||
CDvFramePacket(const struct dstar_dvframe *, uint16, uint8);
|
CDvFramePacket(const struct dstar_dvframe *, uint16, uint8);
|
||||||
CDvFramePacket(const uint8 *, const uint8 *, uint16, uint8, uint8);
|
CDvFramePacket(const uint8 *, const uint8 *, uint16, uint8, uint8);
|
||||||
CDvFramePacket(const uint8 *, uint16, uint8, 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(uint16, uint8, const uint8 *, const uint8 *, uint8, uint8, const uint8 *, const uint8 *);
|
||||||
CDvFramePacket(const CDvFramePacket &);
|
CDvFramePacket(const CDvFramePacket &);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,10 +70,10 @@ CDvHeaderPacket::CDvHeaderPacket(uint32 my, const CCallsign &ur, const CCallsign
|
||||||
m_csMY = CCallsign("", my);
|
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)
|
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_uiFlag1 = 0;
|
||||||
m_uiFlag2 = 0;
|
m_uiFlag2 = 0;
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ public:
|
||||||
CDvHeaderPacket(const struct dstar_header *, uint16, uint8);
|
CDvHeaderPacket(const struct dstar_header *, uint16, uint8);
|
||||||
CDvHeaderPacket(uint32, const CCallsign &, const CCallsign &, const CCallsign &, uint16, uint8, 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 CCallsign &, const CCallsign &, const CCallsign &, const CCallsign &, uint16, uint8);
|
||||||
CDvHeaderPacket(const CDvHeaderPacket &);
|
CDvHeaderPacket(const CDvHeaderPacket &);
|
||||||
|
|
||||||
// destructor
|
// destructor
|
||||||
virtual ~CDvHeaderPacket(){};
|
virtual ~CDvHeaderPacket(){};
|
||||||
|
|
|
||||||
|
|
@ -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
|
// copy constructor
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ public:
|
||||||
CDvLastFramePacket(const struct dstar_dvframe *, uint16, uint8);
|
CDvLastFramePacket(const struct dstar_dvframe *, uint16, uint8);
|
||||||
CDvLastFramePacket(const uint8 *, const uint8 *, uint16, uint8, uint8);
|
CDvLastFramePacket(const uint8 *, const uint8 *, uint16, uint8, uint8);
|
||||||
CDvLastFramePacket(const uint8 *, uint16, uint8, 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(uint16, uint8, const uint8 *, const uint8 *, uint8, uint8, const uint8 *, const uint8 *);
|
||||||
CDvLastFramePacket(const CDvLastFramePacket &);
|
CDvLastFramePacket(const CDvLastFramePacket &);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ bool CGateKeeper::MayLink(const CCallsign &callsign, const CIp &ip, int protocol
|
||||||
case PROTOCOL_DMRMMDVM:
|
case PROTOCOL_DMRMMDVM:
|
||||||
case PROTOCOL_YSF:
|
case PROTOCOL_YSF:
|
||||||
case PROTOCOL_G3:
|
case PROTOCOL_G3:
|
||||||
|
case PROTOCOL_IMRS:
|
||||||
// first check is IP & callsigned listed OK
|
// first check is IP & callsigned listed OK
|
||||||
ok &= IsNodeListedOk(callsign, ip);
|
ok &= IsNodeListedOk(callsign, ip);
|
||||||
// todo: then apply any protocol specific authorisation for the operation
|
// 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_DMRMMDVM:
|
||||||
case PROTOCOL_YSF:
|
case PROTOCOL_YSF:
|
||||||
case PROTOCOL_G3:
|
case PROTOCOL_G3:
|
||||||
|
case PROTOCOL_IMRS:
|
||||||
// first check is IP & callsigned listed OK
|
// first check is IP & callsigned listed OK
|
||||||
ok &= IsNodeListedOk(callsign, ip, module);
|
ok &= IsNodeListedOk(callsign, ip, module);
|
||||||
// todo: then apply any protocol specific authorisation for the operation
|
// todo: then apply any protocol specific authorisation for the operation
|
||||||
|
|
|
||||||
52
src/cimrsclient.cpp
Normal file
52
src/cimrsclient.cpp
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
59
src/cimrsclient.h
Normal file
59
src/cimrsclient.h
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#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 */
|
||||||
925
src/cimrsprotocol.cpp
Normal file
925
src/cimrsprotocol.cpp
Normal file
|
|
@ -0,0 +1,925 @@
|
||||||
|
//
|
||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
#include <string.h>
|
||||||
|
#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 dgids32 = 0x00000004;
|
||||||
|
uint32 mask32 = 0x00000400;
|
||||||
|
// modules 10->31
|
||||||
|
for ( int i = 0; i < (int)(MIN(NB_OF_MODULES,22)); i++ )
|
||||||
|
{
|
||||||
|
dgids32 |= mask32;
|
||||||
|
mask32 = mask32 << 1;
|
||||||
|
}
|
||||||
|
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 = 22; 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
117
src/cimrsprotocol.h
Normal file
117
src/cimrsprotocol.h
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#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<CImrsStreamCacheItem, NB_OF_MODULES> m_StreamsCache;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif /* cimrsprotocol__h */
|
||||||
|
|
@ -46,10 +46,13 @@ public:
|
||||||
void SetSockAddr(struct sockaddr_in *);
|
void SetSockAddr(struct sockaddr_in *);
|
||||||
struct sockaddr_in *GetSockAddr(void) { return &m_Addr; }
|
struct sockaddr_in *GetSockAddr(void) { return &m_Addr; }
|
||||||
|
|
||||||
// convertor
|
// get
|
||||||
uint32 GetAddr(void) const { return m_Addr.sin_addr.s_addr; }
|
uint32 GetAddr(void) const { return m_Addr.sin_addr.s_addr; }
|
||||||
uint16 GetPort(void) const { return m_Addr.sin_port; }
|
uint16 GetPort(void) const { return m_Addr.sin_port; }
|
||||||
|
|
||||||
|
// set
|
||||||
|
void SetPort(uint16 port) { m_Addr.sin_port = port; }
|
||||||
|
|
||||||
// operator
|
// operator
|
||||||
bool operator ==(const CIp &) const;
|
bool operator ==(const CIp &) const;
|
||||||
operator const char *() const;
|
operator const char *() const;
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,9 @@ CPacket::CPacket()
|
||||||
m_uiYsfPacketId = 0;
|
m_uiYsfPacketId = 0;
|
||||||
m_uiYsfPacketSubId = 0;
|
m_uiYsfPacketSubId = 0;
|
||||||
m_uiYsfPacketFrameId = 0;
|
m_uiYsfPacketFrameId = 0;
|
||||||
|
m_uiImrsPacketId = 0;
|
||||||
|
m_uiImrsPacketSubId = 0;
|
||||||
|
m_uiImrsPacketFrameId = 0;
|
||||||
m_uiModuleId = ' ';
|
m_uiModuleId = ' ';
|
||||||
m_uiOriginId = ORIGIN_LOCAL;
|
m_uiOriginId = ORIGIN_LOCAL;
|
||||||
};
|
};
|
||||||
|
|
@ -54,6 +57,9 @@ CPacket::CPacket(uint16 sid, uint8 dstarpid)
|
||||||
m_uiYsfPacketId = 0xFF;
|
m_uiYsfPacketId = 0xFF;
|
||||||
m_uiYsfPacketSubId = 0xFF;
|
m_uiYsfPacketSubId = 0xFF;
|
||||||
m_uiYsfPacketFrameId = 0xFF;
|
m_uiYsfPacketFrameId = 0xFF;
|
||||||
|
m_uiImrsPacketId = 0xFF;
|
||||||
|
m_uiImrsPacketSubId = 0xFF;
|
||||||
|
m_uiImrsPacketFrameId = 0xFFFF;
|
||||||
m_uiModuleId = ' ';
|
m_uiModuleId = ' ';
|
||||||
m_uiOriginId = ORIGIN_LOCAL;
|
m_uiOriginId = ORIGIN_LOCAL;
|
||||||
};
|
};
|
||||||
|
|
@ -69,6 +75,9 @@ CPacket::CPacket(uint16 sid, uint8 dmrpid, uint8 dmrspid)
|
||||||
m_uiYsfPacketId = 0xFF;
|
m_uiYsfPacketId = 0xFF;
|
||||||
m_uiYsfPacketSubId = 0xFF;
|
m_uiYsfPacketSubId = 0xFF;
|
||||||
m_uiYsfPacketFrameId = 0xFF;
|
m_uiYsfPacketFrameId = 0xFF;
|
||||||
|
m_uiImrsPacketId = 0xFF;
|
||||||
|
m_uiImrsPacketSubId = 0xFF;
|
||||||
|
m_uiImrsPacketFrameId = 0xFFFF;
|
||||||
m_uiModuleId = ' ';
|
m_uiModuleId = ' ';
|
||||||
m_uiOriginId = ORIGIN_LOCAL;
|
m_uiOriginId = ORIGIN_LOCAL;
|
||||||
};
|
};
|
||||||
|
|
@ -84,13 +93,34 @@ CPacket::CPacket(uint16 sid, uint8 ysfpid, uint8 ysfsubpid, uint8 ysffrid)
|
||||||
m_uiDstarPacketId = 0xFF;
|
m_uiDstarPacketId = 0xFF;
|
||||||
m_uiDmrPacketId = 0xFF;
|
m_uiDmrPacketId = 0xFF;
|
||||||
m_uiDmrPacketSubid = 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_uiModuleId = ' ';
|
||||||
m_uiOriginId = ORIGIN_LOCAL;
|
m_uiOriginId = ORIGIN_LOCAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// xlx constructor
|
// 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_uiStreamId = sid;
|
||||||
m_uiDstarPacketId = dstarpid;
|
m_uiDstarPacketId = dstarpid;
|
||||||
|
|
@ -99,6 +129,9 @@ CPacket::CPacket(uint16 sid, uint8 dstarpid, uint8 dmrpid, uint8 dmrsubpid, uint
|
||||||
m_uiYsfPacketId = ysfpid;
|
m_uiYsfPacketId = ysfpid;
|
||||||
m_uiYsfPacketSubId = ysfsubpid;
|
m_uiYsfPacketSubId = ysfsubpid;
|
||||||
m_uiYsfPacketFrameId = ysffrid;
|
m_uiYsfPacketFrameId = ysffrid;
|
||||||
|
m_uiImrsPacketId = imrspid;
|
||||||
|
m_uiImrsPacketSubId = imrssubid;
|
||||||
|
m_uiImrsPacketFrameId = imrsfrid;
|
||||||
m_uiModuleId = ' ';
|
m_uiModuleId = ' ';
|
||||||
m_uiOriginId = ORIGIN_LOCAL;
|
m_uiOriginId = ORIGIN_LOCAL;
|
||||||
}
|
}
|
||||||
|
|
@ -133,11 +166,24 @@ void CPacket::UpdatePids(uint32 pid)
|
||||||
m_uiDmrPacketId = ((pid / 3) % 6);
|
m_uiDmrPacketId = ((pid / 3) % 6);
|
||||||
m_uiDmrPacketSubid = ((pid % 3) + 1);
|
m_uiDmrPacketSubid = ((pid % 3) + 1);
|
||||||
}
|
}
|
||||||
// ysf pids need update ?
|
// ysf need update ?
|
||||||
if ( m_uiYsfPacketId == 0xFF )
|
if ( m_uiYsfPacketId == 0xFF )
|
||||||
{
|
{
|
||||||
m_uiYsfPacketId = ((pid / 5) % 8);
|
m_uiYsfPacketId = ((pid / 5) % 8);
|
||||||
m_uiYsfPacketSubId = pid % 5;
|
m_uiYsfPacketSubId = pid % 5;
|
||||||
|
}
|
||||||
|
if ( m_uiYsfPacketFrameId == 0xFF )
|
||||||
|
{
|
||||||
m_uiYsfPacketFrameId = ((pid / 5) & 0x7FU) << 1;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,9 @@ public:
|
||||||
CPacket();
|
CPacket();
|
||||||
CPacket(uint16 sid, uint8 dstarpid);
|
CPacket(uint16 sid, uint8 dstarpid);
|
||||||
CPacket(uint16 sid, uint8 dmrpid, uint8 dmrsubpid);
|
CPacket(uint16 sid, uint8 dmrpid, uint8 dmrsubpid);
|
||||||
CPacket(uint16 sid, uint8 ysfpid, uint8 ysfsubpid, uint8 ysfsubpidmax);
|
CPacket(uint16 sid, uint8 ysfpid, uint8 ysfsubpid, uint8 ysffrid);
|
||||||
CPacket(uint16 sid, uint8 dstarpid, uint8 dmrpid, uint8 dmrsubpid, uint8 ysfpid, uint8 ysfsubpid, uint8 ysfsubpidmax);
|
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
|
// destructor
|
||||||
virtual ~CPacket() {};
|
virtual ~CPacket() {};
|
||||||
|
|
@ -67,6 +68,9 @@ public:
|
||||||
uint8 GetYsfPacketId(void) const { return m_uiYsfPacketId; }
|
uint8 GetYsfPacketId(void) const { return m_uiYsfPacketId; }
|
||||||
uint8 GetYsfPacketSubId(void) const { return m_uiYsfPacketSubId; }
|
uint8 GetYsfPacketSubId(void) const { return m_uiYsfPacketSubId; }
|
||||||
uint8 GetYsfPacketFrameId(void) const { return m_uiYsfPacketFrameId; }
|
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; }
|
uint8 GetModuleId(void) const { return m_uiModuleId; }
|
||||||
bool IsLocalOrigin(void) const { return (m_uiOriginId == ORIGIN_LOCAL); }
|
bool IsLocalOrigin(void) const { return (m_uiOriginId == ORIGIN_LOCAL); }
|
||||||
|
|
||||||
|
|
@ -77,16 +81,23 @@ public:
|
||||||
void SetRemotePeerOrigin(void) { m_uiOriginId = ORIGIN_PEER; }
|
void SetRemotePeerOrigin(void) { m_uiOriginId = ORIGIN_PEER; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// data
|
// common
|
||||||
uint16 m_uiStreamId;
|
uint16 m_uiStreamId;
|
||||||
|
uint8 m_uiModuleId;
|
||||||
|
uint8 m_uiOriginId;
|
||||||
|
// dstar
|
||||||
uint8 m_uiDstarPacketId;
|
uint8 m_uiDstarPacketId;
|
||||||
|
// dmr
|
||||||
uint8 m_uiDmrPacketId;
|
uint8 m_uiDmrPacketId;
|
||||||
uint8 m_uiDmrPacketSubid;
|
uint8 m_uiDmrPacketSubid;
|
||||||
|
// ysf
|
||||||
uint8 m_uiYsfPacketId;
|
uint8 m_uiYsfPacketId;
|
||||||
uint8 m_uiYsfPacketSubId;
|
uint8 m_uiYsfPacketSubId;
|
||||||
uint8 m_uiYsfPacketFrameId;
|
uint8 m_uiYsfPacketFrameId;
|
||||||
uint8 m_uiModuleId;
|
// imrs
|
||||||
uint8 m_uiOriginId;
|
uint8 m_uiImrsPacketId;
|
||||||
|
uint16 m_uiImrsPacketFrameId;
|
||||||
|
uint8 m_uiImrsPacketSubId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include "cdmrmmdvmprotocol.h"
|
#include "cdmrmmdvmprotocol.h"
|
||||||
#include "cysfprotocol.h"
|
#include "cysfprotocol.h"
|
||||||
#include "cg3protocol.h"
|
#include "cg3protocol.h"
|
||||||
|
#include "cimrsprotocol.h"
|
||||||
#include "cprotocols.h"
|
#include "cprotocols.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -109,6 +110,10 @@ bool CProtocols::Init(void)
|
||||||
m_Protocols[7] = new CG3Protocol;
|
m_Protocols[7] = new CG3Protocol;
|
||||||
ok &= m_Protocols[7]->Init();
|
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();
|
m_Mutex.unlock();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,9 @@ CReflector::CReflector()
|
||||||
{
|
{
|
||||||
m_RouterThreads[i] = NULL;
|
m_RouterThreads[i] = NULL;
|
||||||
}
|
}
|
||||||
|
::memset(m_Mac, 0, sizeof(m_Mac));
|
||||||
#ifdef DEBUG_DUMPFILE
|
#ifdef DEBUG_DUMPFILE
|
||||||
m_DebugFile.open("/Users/jeanluc/Desktop/xlxdebug.txt");
|
m_DebugFile.open("/Users/jean-luc/Desktop/xlxdebug.txt");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,6 +63,7 @@ CReflector::CReflector(const CCallsign &callsign)
|
||||||
m_RouterThreads[i] = NULL;
|
m_RouterThreads[i] = NULL;
|
||||||
}
|
}
|
||||||
m_Callsign = callsign;
|
m_Callsign = callsign;
|
||||||
|
::memset(m_Mac, 0, sizeof(m_Mac));
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -100,7 +102,7 @@ bool CReflector::Start(void)
|
||||||
|
|
||||||
// reset stop flag
|
// reset stop flag
|
||||||
m_bStopThreads = false;
|
m_bStopThreads = false;
|
||||||
|
|
||||||
// init gate keeper
|
// init gate keeper
|
||||||
ok &= g_GateKeeper.Init();
|
ok &= g_GateKeeper.Init();
|
||||||
|
|
||||||
|
|
@ -768,3 +770,152 @@ void CReflector::SendJsonOffairObject(CUdpSocket &Socket, CIp &Ip, const CCallsi
|
||||||
//std::cout << Buffer << std::endl;
|
//std::cout << Buffer << std::endl;
|
||||||
Socket.Send(Buffer, Ip);
|
Socket.Send(Buffer, Ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// MAC address helpers
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <netpacket/packet.h>
|
||||||
|
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 <net/if_dl.h>
|
||||||
|
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
|
||||||
|
|
|
||||||
|
|
@ -57,9 +57,10 @@ public:
|
||||||
// settings
|
// settings
|
||||||
void SetCallsign(const CCallsign &callsign) { m_Callsign = callsign; }
|
void SetCallsign(const CCallsign &callsign) { m_Callsign = callsign; }
|
||||||
const CCallsign &GetCallsign(void) const { return m_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; }
|
void SetTranscoderIp(const CIp &ip) { m_AmbedIp = ip; }
|
||||||
const CIp &GetListenIp(void) const { return m_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; }
|
const CIp &GetTranscoderIp(void) const { return m_AmbedIp; }
|
||||||
|
|
||||||
// operation
|
// operation
|
||||||
|
|
@ -116,10 +117,14 @@ protected:
|
||||||
void SendJsonOnairObject(CUdpSocket &, CIp &, const CCallsign &);
|
void SendJsonOnairObject(CUdpSocket &, CIp &, const CCallsign &);
|
||||||
void SendJsonOffairObject(CUdpSocket &, CIp &, const CCallsign &);
|
void SendJsonOffairObject(CUdpSocket &, CIp &, const CCallsign &);
|
||||||
|
|
||||||
|
// MAC address helpers
|
||||||
|
bool UpdateListenMac(void);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// identity
|
// identity
|
||||||
CCallsign m_Callsign;
|
CCallsign m_Callsign;
|
||||||
CIp m_Ip;
|
CIp m_Ip;
|
||||||
|
uint8 m_Mac[6];
|
||||||
CIp m_AmbedIp;
|
CIp m_AmbedIp;
|
||||||
|
|
||||||
// objects
|
// objects
|
||||||
|
|
|
||||||
|
|
@ -306,3 +306,9 @@ void CYSFFICH::load(const unsigned char* fich)
|
||||||
::memcpy(m_fich, fich, 4U);
|
::memcpy(m_fich, fich, 4U);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CYSFFICH::data(unsigned char* fich)
|
||||||
|
{
|
||||||
|
assert(fich != NULL);
|
||||||
|
|
||||||
|
::memcpy(fich, m_fich, 4U);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ public:
|
||||||
void setSQ(unsigned char sq);
|
void setSQ(unsigned char sq);
|
||||||
|
|
||||||
void load(const unsigned char* fich);
|
void load(const unsigned char* fich);
|
||||||
|
void data(unsigned char* fich);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned char* m_fich;
|
unsigned char* m_fich;
|
||||||
|
|
|
||||||
|
|
@ -469,17 +469,21 @@ bool CYsfProtocol::IsValidDvHeaderPacket(const CIp &Ip, const CYSFFICH &Fich, co
|
||||||
char sz[YSF_CALLSIGN_LENGTH+1];
|
char sz[YSF_CALLSIGN_LENGTH+1];
|
||||||
::memcpy(sz, &(Buffer.data()[14]), YSF_CALLSIGN_LENGTH);
|
::memcpy(sz, &(Buffer.data()[14]), YSF_CALLSIGN_LENGTH);
|
||||||
sz[YSF_CALLSIGN_LENGTH] = 0;
|
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);
|
::memcpy(sz, &(Buffer.data()[4]), YSF_CALLSIGN_LENGTH);
|
||||||
sz[YSF_CALLSIGN_LENGTH] = 0;
|
sz[YSF_CALLSIGN_LENGTH] = 0;
|
||||||
CCallsign rpt1 = CCallsign((const char *)sz);
|
CCallsign rpt1 = CCallsign((const char *)sz);
|
||||||
rpt1.SetModule(YSF_MODULE_ID);
|
rpt1.SetModule(YSF_MODULE_ID);
|
||||||
CCallsign rpt2 = m_ReflectorCallsign;
|
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
|
// set module based on DG-ID value
|
||||||
rpt2.SetModule( 'A' + (char)(Fich.getSQ() - 10) );
|
rpt2.SetModule( 'A' + (char)(Fich.getSQ() - 10) );
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// as YSF protocol does not provide a module-tranlatable
|
// as YSF protocol does not provide a module-tranlatable
|
||||||
// destid, set module to none and rely on OnDvHeaderPacketIn()
|
// destid, set module to none and rely on OnDvHeaderPacketIn()
|
||||||
// to later fill it with proper value
|
// 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];
|
uint8 uiAmbe[AMBE_SIZE];
|
||||||
::memset(uiAmbe, 0x00, sizeof(uiAmbe));
|
::memset(uiAmbe, 0x00, sizeof(uiAmbe));
|
||||||
frames[0] = new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 0, 0);
|
frames[0] = new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 0, (uint8)0);
|
||||||
frames[1] = new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 1, 0);
|
frames[1] = new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 1, (uint8)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check validity of packets
|
// check validity of packets
|
||||||
|
|
@ -597,8 +601,8 @@ bool CYsfProtocol::IsValidDvLastFramePacket(const CIp &Ip, const CYSFFICH &Fich,
|
||||||
{
|
{
|
||||||
uint8 uiAmbe[AMBE_SIZE];
|
uint8 uiAmbe[AMBE_SIZE];
|
||||||
::memset(uiAmbe, 0x00, sizeof(uiAmbe));
|
::memset(uiAmbe, 0x00, sizeof(uiAmbe));
|
||||||
frames[0] = new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 0, 0);
|
frames[0] = new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 0, (uint8)0);
|
||||||
frames[1] = new CDvLastFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 1, 0);
|
frames[1] = new CDvLastFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 1, (uint8)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check validity of packets
|
// check validity of packets
|
||||||
|
|
|
||||||
|
|
@ -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])
|
#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
// decode
|
||||||
|
|
||||||
void CYsfUtils::DecodeVD2Vchs(uint8 *data, uint8 **ambe)
|
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)
|
void CYsfUtils::EncodeVD2Vch(uint8 *ambe, uint8 *data)
|
||||||
{
|
{
|
||||||
// convert from ambe2plus
|
// convert from ambe2plus
|
||||||
|
|
|
||||||
|
|
@ -40,10 +40,10 @@ public:
|
||||||
// destructor
|
// destructor
|
||||||
virtual ~CYsfUtils() {};
|
virtual ~CYsfUtils() {};
|
||||||
|
|
||||||
// operation
|
// code / decode
|
||||||
static void DecodeVD2Vchs(uint8 *, uint8 **);
|
static void DecodeVD2Vchs(uint8 *, uint8 **);
|
||||||
|
static void DecodeVD2Vch(uint8 *, uint8 *);
|
||||||
static void EncodeVD2Vch(uint8 *, uint8 *);
|
static void EncodeVD2Vch(uint8 *, uint8 *);
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// data
|
// data
|
||||||
|
|
|
||||||
13
src/main.h
13
src/main.h
|
|
@ -41,6 +41,7 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// defines
|
// defines
|
||||||
|
|
@ -48,8 +49,8 @@
|
||||||
// version -----------------------------------------------------
|
// version -----------------------------------------------------
|
||||||
|
|
||||||
#define VERSION_MAJOR 2
|
#define VERSION_MAJOR 2
|
||||||
#define VERSION_MINOR 4
|
#define VERSION_MINOR 5
|
||||||
#define VERSION_REVISION 2
|
#define VERSION_REVISION 0
|
||||||
|
|
||||||
// global ------------------------------------------------------
|
// global ------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -69,7 +70,7 @@
|
||||||
|
|
||||||
// protocols ---------------------------------------------------
|
// protocols ---------------------------------------------------
|
||||||
|
|
||||||
#define NB_OF_PROTOCOLS 8
|
#define NB_OF_PROTOCOLS 9
|
||||||
|
|
||||||
#define PROTOCOL_ANY -1
|
#define PROTOCOL_ANY -1
|
||||||
#define PROTOCOL_NONE 0
|
#define PROTOCOL_NONE 0
|
||||||
|
|
@ -81,6 +82,7 @@
|
||||||
#define PROTOCOL_DMRMMDVM 6
|
#define PROTOCOL_DMRMMDVM 6
|
||||||
#define PROTOCOL_YSF 7
|
#define PROTOCOL_YSF 7
|
||||||
#define PROTOCOL_G3 8
|
#define PROTOCOL_G3 8
|
||||||
|
#define PROTOCOL_IMRS 9
|
||||||
|
|
||||||
// DExtra
|
// DExtra
|
||||||
#define DEXTRA_PORT 30001 // UDP port
|
#define DEXTRA_PORT 30001 // UDP port
|
||||||
|
|
@ -133,6 +135,11 @@
|
||||||
#define G3_KEEPALIVE_PERIOD 10 // in seconds
|
#define G3_KEEPALIVE_PERIOD 10 // in seconds
|
||||||
#define G3_KEEPALIVE_TIMEOUT 3600 // in seconds, 1 hour
|
#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 --------------------------------------------
|
// Transcoder server --------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue