M17 Protocol introduction

unstable
Tom Early 4 years ago
parent d013a3d532
commit 47abcf0fdc

@ -25,7 +25,7 @@
CBuffer::CBuffer(uint8_t *buffer, int len) CBuffer::CBuffer(uint8_t *buffer, int len)
{ {
m_data.resize(len); m_data.resize(len);
::memcpy(m_data.data(), buffer, len); memcpy(m_data.data(), buffer, len);
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -34,7 +34,7 @@ CBuffer::CBuffer(uint8_t *buffer, int len)
void CBuffer::Set(uint8_t *buffer, int len) void CBuffer::Set(uint8_t *buffer, int len)
{ {
m_data.resize(len); m_data.resize(len);
::memcpy(m_data.data(), buffer, len); memcpy(m_data.data(), buffer, len);
} }
void CBuffer::Set(const char *sz) void CBuffer::Set(const char *sz)
@ -47,35 +47,35 @@ void CBuffer::Append(const uint8_t *buffer, int len)
{ {
int n = (int)m_data.size(); int n = (int)m_data.size();
m_data.resize(n+len); m_data.resize(n+len);
::memcpy(&(m_data.data()[n]), buffer, len); memcpy(&(m_data.data()[n]), buffer, len);
} }
void CBuffer::Append(uint8_t ui, int len) void CBuffer::Append(uint8_t ui, int len)
{ {
int n = (int)m_data.size(); int n = (int)m_data.size();
m_data.resize(n+len); m_data.resize(n+len);
::memset(&(m_data.data()[n]), ui, len); memset(&(m_data.data()[n]), ui, len);
} }
void CBuffer::Append(uint8_t ui) void CBuffer::Append(uint8_t ui)
{ {
int n = (int)m_data.size(); int n = (int)m_data.size();
m_data.resize(n+sizeof(uint8_t)); m_data.resize(n+sizeof(uint8_t));
::memcpy(&(m_data.data()[n]), &ui, sizeof(uint8_t)); memcpy(&(m_data.data()[n]), &ui, sizeof(uint8_t));
} }
void CBuffer::Append(uint16_t ui) void CBuffer::Append(uint16_t ui)
{ {
int n = (int)m_data.size(); int n = (int)m_data.size();
m_data.resize(n+sizeof(uint16_t)); m_data.resize(n+sizeof(uint16_t));
::memcpy(&(m_data.data()[n]), &ui, sizeof(uint16_t)); memcpy(&(m_data.data()[n]), &ui, sizeof(uint16_t));
} }
void CBuffer::Append(uint32_t ui) void CBuffer::Append(uint32_t ui)
{ {
int n = (int)m_data.size(); int n = (int)m_data.size();
m_data.resize(n+sizeof(uint32_t)); m_data.resize(n+sizeof(uint32_t));
::memcpy(&(m_data.data()[n]), &ui, sizeof(uint32_t)); memcpy(&(m_data.data()[n]), &ui, sizeof(uint32_t));
} }
void CBuffer::Append(const char *sz) void CBuffer::Append(const char *sz)
@ -117,7 +117,7 @@ void CBuffer::ReplaceAt(int i, const uint8_t *ptr, int len)
{ {
m_data.resize(i+len); m_data.resize(i+len);
} }
::memcpy(&(m_data.data()[i]), ptr, len); memcpy(&(m_data.data()[i]), ptr, len);
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -128,7 +128,7 @@ int CBuffer::Compare(uint8_t *buffer, int len) const
int result = -1; int result = -1;
if ( m_data.size() >= unsigned(len) ) if ( m_data.size() >= unsigned(len) )
{ {
result = ::memcmp(m_data.data(), buffer, len); result = memcmp(m_data.data(), buffer, len);
} }
return result; return result;
} }
@ -138,7 +138,7 @@ int CBuffer::Compare(uint8_t *buffer, int off, int len) const
int result = -1; int result = -1;
if ( m_data.size() >= unsigned(off+len) ) if ( m_data.size() >= unsigned(off+len) )
{ {
result = ::memcmp(&(m_data.data()[off]), buffer, len); result = memcmp(&(m_data.data()[off]), buffer, len);
} }
return result; return result;
} }
@ -151,7 +151,7 @@ bool CBuffer::operator ==(const CBuffer &Buffer) const
{ {
if ( m_data.size() == Buffer.m_data.size() ) if ( m_data.size() == Buffer.m_data.size() )
{ {
return (::memcmp((const char *)m_data.data(), (const char *)Buffer.m_data.data(), m_data.size()) == 0); return (memcmp((const char *)m_data.data(), (const char *)Buffer.m_data.data(), m_data.size()) == 0);
} }
return false; return false;
} }
@ -160,7 +160,7 @@ bool CBuffer::operator ==(const char *sz) const
{ {
if ( m_data.size() == ::strlen(sz) ) if ( m_data.size() == ::strlen(sz) )
{ {
return (::memcmp((const char *)m_data.data(), sz, m_data.size()) == 0); return (memcmp((const char *)m_data.data(), sz, m_data.size()) == 0);
} }
return false; return false;
} }

@ -23,34 +23,41 @@
#include "DMRIdDirHttp.h" #include "DMRIdDirHttp.h"
#include "Callsign.h" #include "Callsign.h"
// if a client is using special characters ',', '-' or '/', he's out of luck!
//#define M17CHARACTERS " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/."
#define M17CHARACTERS " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// constructors // constructors
CCallsign::CCallsign() CCallsign::CCallsign()
{ {
// blank all // blank all
::memset(m_Callsign, ' ', sizeof(m_Callsign)); memset(m_Callsign, ' ', CALLSIGN_LEN);
::memset(m_Suffix, ' ', sizeof(m_Suffix)); memset(m_Suffix, ' ', CALLSUFFIX_LEN);
m_Module = ' '; m_Module = ' ';
m_uiDmrid = 0; m_uiDmrid = 0;
m_coded = 0;
} }
CCallsign::CCallsign(const char *sz, uint32_t dmrid) CCallsign::CCallsign(const char *sz, uint32_t dmrid)
{ {
// blank all // blank all
::memset(m_Callsign, ' ', sizeof(m_Callsign)); memset(m_Callsign, ' ', CALLSIGN_LEN);
::memset(m_Suffix, ' ', sizeof(m_Suffix)); memset(m_Suffix, ' ', CALLSUFFIX_LEN);
m_Module = ' '; m_Module = ' ';
m_uiDmrid = dmrid; m_uiDmrid = dmrid;
// and populate // and populate
if ( ::strlen(sz) > 0 ) if ( ::strlen(sz) > 0 )
{ {
// Calculate the M17 coded callsign
CSIn();
// callsign valid // callsign valid
::memcpy(m_Callsign, sz, MIN(strlen(sz), sizeof(m_Callsign)-1)); memcpy(m_Callsign, sz, MIN(strlen(sz), CALLSIGN_LEN-1));
if ( strlen(sz) >= sizeof(m_Callsign) ) if ( strlen(sz) >= CALLSIGN_LEN )
{ {
m_Module = sz[sizeof(m_Callsign)-1]; m_Module = sz[CALLSIGN_LEN-1];
} }
// dmrid ok ? // dmrid ok ?
if ( m_uiDmrid == 0 ) if ( m_uiDmrid == 0 )
@ -69,7 +76,7 @@ CCallsign::CCallsign(const char *sz, uint32_t dmrid)
const CCallsign *callsign = g_DmridDir.FindCallsign(m_uiDmrid); const CCallsign *callsign = g_DmridDir.FindCallsign(m_uiDmrid);
if ( callsign != nullptr ) if ( callsign != nullptr )
{ {
::memcpy(m_Callsign, callsign->m_Callsign, sizeof(m_Callsign)); memcpy(m_Callsign, callsign->m_Callsign, CALLSIGN_LEN);
} }
} }
g_DmridDir.Unlock(); g_DmridDir.Unlock();
@ -136,13 +143,15 @@ bool CCallsign::HasSuffix(void) const
void CCallsign::SetCallsign(const char *sz, bool UpdateDmrid) void CCallsign::SetCallsign(const char *sz, bool UpdateDmrid)
{ {
// set callsign // set callsign
::memset(m_Callsign, ' ', sizeof(m_Callsign)); memset(m_Callsign, ' ', CALLSIGN_LEN);
m_Module = ' '; m_Module = ' ';
::memcpy(m_Callsign, sz, MIN(strlen(sz), sizeof(m_Callsign)-1)); memcpy(m_Callsign, sz, MIN(strlen(sz), CALLSIGN_LEN-1));
if ( strlen(sz) >= sizeof(m_Callsign) ) if ( strlen(sz) >= CALLSIGN_LEN )
{ {
m_Module = sz[sizeof(m_Callsign)-1]; m_Module = sz[CALLSIGN_LEN-1];
} }
// update M17 coded callsign
CSIn();
// and update dmrid // and update dmrid
if ( UpdateDmrid ) if ( UpdateDmrid )
{ {
@ -157,20 +166,21 @@ void CCallsign::SetCallsign(const char *sz, bool UpdateDmrid)
void CCallsign::SetCallsign(const uint8_t *buffer, int len, bool UpdateDmrid) void CCallsign::SetCallsign(const uint8_t *buffer, int len, bool UpdateDmrid)
{ {
// set callsign // set callsign
::memset(m_Callsign, ' ', sizeof(m_Callsign)); memset(m_Callsign, ' ', CALLSIGN_LEN);
m_Module = ' '; m_Module = ' ';
::memcpy(m_Callsign, buffer, MIN(len, (int)sizeof(m_Callsign)-1)); memcpy(m_Callsign, buffer, MIN(len, (int)CALLSIGN_LEN-1));
for ( unsigned i = 0; i < sizeof(m_Callsign); i++ ) for ( unsigned i = 0; i < CALLSIGN_LEN; i++ )
{ {
if ( m_Callsign[i] == 0 ) if ( m_Callsign[i] == 0 )
{ {
m_Callsign[i] = ' '; m_Callsign[i] = ' ';
} }
} }
if ( (len >= (int)sizeof(m_Callsign)) && ((char)buffer[sizeof(m_Callsign)-1] != 0) ) if ( (len >= (int)CALLSIGN_LEN) && ((char)buffer[CALLSIGN_LEN-1] != 0) )
{ {
m_Module = (char)buffer[sizeof(m_Callsign)-1]; m_Module = (char)buffer[CALLSIGN_LEN-1];
} }
CSIn();
if ( UpdateDmrid ) if ( UpdateDmrid )
{ {
g_DmridDir.Lock(); g_DmridDir.Lock();
@ -191,7 +201,7 @@ void CCallsign::SetDmrid(uint32_t dmrid, bool UpdateCallsign)
const CCallsign *callsign = g_DmridDir.FindCallsign(dmrid); const CCallsign *callsign = g_DmridDir.FindCallsign(dmrid);
if ( callsign != nullptr ) if ( callsign != nullptr )
{ {
::memcpy(m_Callsign, callsign->m_Callsign, sizeof(m_Callsign)); memcpy(m_Callsign, callsign->m_Callsign, CALLSIGN_LEN);
} }
} }
g_DmridDir.Unlock(); g_DmridDir.Unlock();
@ -201,7 +211,7 @@ void CCallsign::SetDmrid(uint32_t dmrid, bool UpdateCallsign)
void CCallsign::SetDmrid(const uint8_t *buffer, bool UpdateCallsign) void CCallsign::SetDmrid(const uint8_t *buffer, bool UpdateCallsign)
{ {
char sz[9]; char sz[9];
::memcpy(sz, buffer, 8); memcpy(sz, buffer, 8);
sz[8] = 0; sz[8] = 0;
SetDmrid((uint32_t)::strtol(sz, nullptr, 16), UpdateCallsign); SetDmrid((uint32_t)::strtol(sz, nullptr, 16), UpdateCallsign);
} }
@ -209,20 +219,21 @@ void CCallsign::SetDmrid(const uint8_t *buffer, bool UpdateCallsign)
void CCallsign::SetModule(char c) void CCallsign::SetModule(char c)
{ {
m_Module = c; m_Module = c;
CSIn();
} }
void CCallsign::SetSuffix(const char *sz) void CCallsign::SetSuffix(const char *sz)
{ {
::memset(m_Suffix, ' ', sizeof(m_Suffix)); memset(m_Suffix, ' ', CALLSUFFIX_LEN);
::memcpy(m_Suffix, sz, MIN(strlen(sz), sizeof(m_Suffix))); memcpy(m_Suffix, sz, MIN(strlen(sz), CALLSUFFIX_LEN));
} }
void CCallsign::SetSuffix(const uint8_t *buffer, int len) void CCallsign::SetSuffix(const uint8_t *buffer, int len)
{ {
len = MIN(len, (int)sizeof(m_Suffix)); len = MIN(len, (int)CALLSUFFIX_LEN);
::memset(m_Suffix, ' ', sizeof(m_Suffix)); memset(m_Suffix, ' ', CALLSUFFIX_LEN);
::memcpy(m_Suffix, buffer, len); memcpy(m_Suffix, buffer, len);
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -232,8 +243,9 @@ void CCallsign::PatchCallsign(int off, const uint8_t *patch, int len)
{ {
if ( off < CALLSIGN_LEN ) if ( off < CALLSIGN_LEN )
{ {
::memcpy(m_Callsign, patch, MIN(len, (int)sizeof(m_Callsign) - off)); memcpy(m_Callsign, patch, MIN(len, (int)CALLSIGN_LEN - off));
} }
CSIn();
} }
@ -242,26 +254,36 @@ void CCallsign::PatchCallsign(int off, const uint8_t *patch, int len)
void CCallsign::GetCallsign(uint8_t *buffer) const void CCallsign::GetCallsign(uint8_t *buffer) const
{ {
::memcpy(buffer, m_Callsign, sizeof(m_Callsign)); memcpy(buffer, m_Callsign, CALLSIGN_LEN);
if ( HasModule() ) if ( HasModule() )
{ {
buffer[sizeof(m_Callsign)-1] = m_Module; buffer[CALLSIGN_LEN-1] = m_Module;
} }
} }
void CCallsign::GetCallsignString(char *sz) const void CCallsign::GetCallsignString(char *sz) const
{ {
unsigned i; unsigned i;
for ( i = 0; (i < sizeof(m_Callsign)) && (m_Callsign[i] != ' '); i++ ) for ( i = 0; (i < CALLSIGN_LEN) && (m_Callsign[i] != ' '); i++ )
{ {
sz[i] = m_Callsign[i]; sz[i] = m_Callsign[i];
} }
sz[i] = 0; sz[i] = 0;
} }
const std::string CCallsign::GetCS(unsigned len) const
{
if (len > 8)
len = 8;
std::string rval(m_Callsign);
if (len)
rval.resize(len, ' ');
return rval;
}
void CCallsign::GetSuffix(uint8_t *buffer) const void CCallsign::GetSuffix(uint8_t *buffer) const
{ {
::memcpy(buffer, m_Suffix, sizeof(m_Suffix)); memcpy(buffer, m_Suffix, CALLSUFFIX_LEN);
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -269,7 +291,7 @@ void CCallsign::GetSuffix(uint8_t *buffer) const
bool CCallsign::HasSameCallsign(const CCallsign &Callsign) const bool CCallsign::HasSameCallsign(const CCallsign &Callsign) const
{ {
return (::memcmp(m_Callsign, Callsign.m_Callsign, sizeof(m_Callsign)) == 0); return (memcmp(m_Callsign, Callsign.m_Callsign, CALLSIGN_LEN) == 0);
} }
bool CCallsign::HasSameCallsignWithWildcard(const CCallsign &callsign) const bool CCallsign::HasSameCallsignWithWildcard(const CCallsign &callsign) const
@ -277,7 +299,7 @@ bool CCallsign::HasSameCallsignWithWildcard(const CCallsign &callsign) const
bool same = true; bool same = true;
bool done = false; bool done = false;
for ( unsigned i = 0; (i < sizeof(m_Callsign)) && same && !done; i++ ) for ( unsigned i = 0; (i < CALLSIGN_LEN) && same && !done; i++ )
{ {
if ( !(done = ((m_Callsign[i] == '*') || (callsign[i] == '*'))) ) if ( !(done = ((m_Callsign[i] == '*') || (callsign[i] == '*'))) )
{ {
@ -289,7 +311,7 @@ bool CCallsign::HasSameCallsignWithWildcard(const CCallsign &callsign) const
bool CCallsign::HasLowerCallsign(const CCallsign &Callsign) const bool CCallsign::HasLowerCallsign(const CCallsign &Callsign) const
{ {
return (::memcmp(m_Callsign, Callsign.m_Callsign, sizeof(m_Callsign)) < 0); return (memcmp(m_Callsign, Callsign.m_Callsign, CALLSIGN_LEN) < 0);
} }
bool CCallsign::HasSameModule(const CCallsign &Callsign) const bool CCallsign::HasSameModule(const CCallsign &Callsign) const
@ -303,8 +325,8 @@ bool CCallsign::HasSameModule(const CCallsign &Callsign) const
bool CCallsign::operator ==(const CCallsign &callsign) const bool CCallsign::operator ==(const CCallsign &callsign) const
{ {
return ((::memcmp(callsign.m_Callsign, m_Callsign, sizeof(m_Callsign)) == 0) && (m_Module == callsign.m_Module) return ((memcmp(callsign.m_Callsign, m_Callsign, CALLSIGN_LEN) == 0) && (m_Module == callsign.m_Module)
&& (::memcmp(callsign.m_Suffix, m_Suffix, sizeof(m_Suffix)) == 0) && (memcmp(callsign.m_Suffix, m_Suffix, CALLSUFFIX_LEN) == 0)
&& (m_uiDmrid == callsign.m_uiDmrid) && (m_uiDmrid == callsign.m_uiDmrid)
); );
} }
@ -312,19 +334,19 @@ bool CCallsign::operator ==(const CCallsign &callsign) const
CCallsign::operator const char *() const CCallsign::operator const char *() const
{ {
// empty // empty
::memset(m_sz, 0, sizeof(m_sz)); memset(m_sz, 0, sizeof(m_sz));
// callsign // callsign
::memcpy(m_sz, m_Callsign, sizeof(m_Callsign)); memcpy(m_sz, m_Callsign, CALLSIGN_LEN);
// module // module
if ( HasModule() ) if ( HasModule() )
{ {
m_sz[sizeof(m_Callsign)] = m_Module; m_sz[CALLSIGN_LEN] = m_Module;
} }
// suffix // suffix
if ( HasSuffix() ) if ( HasSuffix() )
{ {
::strcat(m_sz, " / "); ::strcat(m_sz, " / ");
::strncat(m_sz, m_Suffix, sizeof(m_Suffix)); ::strncat(m_sz, m_Suffix, CALLSUFFIX_LEN);
} }
// done // done
@ -348,3 +370,53 @@ bool CCallsign::IsSpace(char c) const
{ {
return (c == ' '); return (c == ' ');
} }
void CCallsign::CodeIn(const uint8_t *in)
{
char cs[10];
const std::string m17_alphabet(M17CHARACTERS);
memset(cs, 0, 10);
m_coded = in[0];
for (int i=1; i<6; i++)
m_coded = (m_coded << 8) | in[i];
if (m_coded > 0xee6b27ffffffu) {
std::cerr << "Callsign code is too large, 0x" << std::hex << m_coded << std::dec << std::endl;
return;
}
auto c = m_coded;
int i = 0;
while (c) {
cs[i++] = m17_alphabet[c % 40];
c /= 40;
}
SetCallsign(cs);
}
void CCallsign::CodeOut(uint8_t *out) const
{
memset(out, 0, 6);
auto c = m_coded;
auto pout = out+5;
while (c)
{
*pout-- = c % 0x100u;
c /= 0x100u;
}
}
// called to calculate the m17 encoded cs
void CCallsign::CSIn()
{
const std::string m17_alphabet(M17CHARACTERS);
auto pos = m17_alphabet.find(m_Module);
m_coded = pos;
m_coded *= 40;
for( int i=CALLSIGN_LEN-2; i>=0; i-- ) {
pos = m17_alphabet.find(m_Callsign[i]);
if (pos == std::string::npos) {
pos = 0;
}
m_coded *= 40;
m_coded += pos;
}
}

@ -55,6 +55,7 @@ public:
// get // get
void GetCallsign(uint8_t *) const; void GetCallsign(uint8_t *) const;
void GetCallsignString(char *) const; void GetCallsignString(char *) const;
const std::string GetCS(unsigned len = 9) const;
uint32_t GetDmrid(void) const { return m_uiDmrid; } uint32_t GetDmrid(void) const { return m_uiDmrid; }
void GetSuffix(uint8_t *) const; void GetSuffix(uint8_t *) const;
char GetModule(void) const { return m_Module; } char GetModule(void) const { return m_Module; }
@ -69,7 +70,13 @@ public:
bool operator ==(const CCallsign &) const; bool operator ==(const CCallsign &) const;
operator const char *() const; operator const char *() const;
// M17
void CodeIn(const uint8_t *code);
void CodeOut(uint8_t *out) const;
protected: protected:
// M17
void CSIn();
// helper // helper
bool IsNumber(char) const; bool IsNumber(char) const;
bool IsLetter(char) const; bool IsLetter(char) const;
@ -82,4 +89,5 @@ protected:
char m_Module; char m_Module;
mutable char m_sz[CALLSIGN_LEN+CALLSUFFIX_LEN+5]; mutable char m_sz[CALLSIGN_LEN+CALLSUFFIX_LEN+5];
uint32_t m_uiDmrid; uint32_t m_uiDmrid;
uint64_t m_coded; // M17 encoded callsign
}; };

@ -28,7 +28,7 @@
CCallsignList::CCallsignList() CCallsignList::CCallsignList()
{ {
m_Filename = nullptr; m_Filename = nullptr;
::memset(&m_LastModTime, 0, sizeof(time_t)); memset(&m_LastModTime, 0, sizeof(time_t));
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////

@ -25,21 +25,21 @@
CCallsignListItem::CCallsignListItem() CCallsignListItem::CCallsignListItem()
{ {
::memset(m_Modules, 0, sizeof(m_Modules)); memset(m_Modules, 0, sizeof(m_Modules));
::memset(m_szUrl, 0, sizeof(m_szUrl)); memset(m_szUrl, 0, sizeof(m_szUrl));
} }
CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const CIp &ip, const char *modules) CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const CIp &ip, const char *modules)
{ {
m_Callsign = callsign; m_Callsign = callsign;
::memset(m_szUrl, 0, sizeof(m_szUrl)); memset(m_szUrl, 0, sizeof(m_szUrl));
m_Ip = ip; m_Ip = ip;
if ( modules != nullptr ) if ( modules != nullptr )
{ {
::memset(m_Modules, 0, sizeof(m_Modules)); memset(m_Modules, 0, sizeof(m_Modules));
if ( modules[0] == '*' ) if ( modules[0] == '*' )
{ {
::memcpy(m_Modules, ACTIVE_MODULES, sizeof(ACTIVE_MODULES)); memcpy(m_Modules, ACTIVE_MODULES, sizeof(ACTIVE_MODULES));
} }
else else
{ {
@ -62,10 +62,10 @@ CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const char *url,
m_Ip = CIp(m_szUrl); m_Ip = CIp(m_szUrl);
if ( modules != nullptr ) if ( modules != nullptr )
{ {
::memset(m_Modules, 0, sizeof(m_Modules)); memset(m_Modules, 0, sizeof(m_Modules));
if ( modules[0] == '*' ) if ( modules[0] == '*' )
{ {
::memcpy(m_Modules, ACTIVE_MODULES, sizeof(ACTIVE_MODULES)); memcpy(m_Modules, ACTIVE_MODULES, sizeof(ACTIVE_MODULES));
} }
else else
{ {
@ -84,9 +84,9 @@ CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const char *url,
CCallsignListItem::CCallsignListItem(const CCallsignListItem &item) CCallsignListItem::CCallsignListItem(const CCallsignListItem &item)
{ {
m_Callsign = item.m_Callsign; m_Callsign = item.m_Callsign;
::memcpy(m_szUrl, item.m_szUrl, sizeof(m_szUrl)); memcpy(m_szUrl, item.m_szUrl, sizeof(m_szUrl));
m_Ip = item.m_Ip; m_Ip = item.m_Ip;
::memcpy(m_Modules, item.m_Modules, sizeof(m_Modules)); memcpy(m_Modules, item.m_Modules, sizeof(m_Modules));
} }

@ -144,7 +144,7 @@ void CCodecStream::Task(void)
{ {
CBuffer Buffer; CBuffer Buffer;
CIp Ip; CIp Ip;
uint8_t Ambe[AMBE_SIZE]; uint8_t Ambe[9];
uint8_t DStarSync[] = { 0x55,0x2D,0x16 }; uint8_t DStarSync[] = { 0x55,0x2D,0x16 };
// any packet from transcoder // any packet from transcoder
@ -235,7 +235,7 @@ bool CCodecStream::IsValidAmbePacket(const CBuffer &Buffer, uint8_t *Ambe)
if ( (Buffer.size() == 11) && (Buffer.data()[0] == m_uiCodecOut) ) if ( (Buffer.size() == 11) && (Buffer.data()[0] == m_uiCodecOut) )
{ {
::memcpy(Ambe, &(Buffer.data()[2]), 9); memcpy(Ambe, &(Buffer.data()[2]), 9);
valid = true; valid = true;
} }
return valid; return valid;

@ -26,8 +26,8 @@
// define // define
// frame sizes // frame sizes
#define AMBE_SIZE 9 #define 9 9
#define AMBEPLUS_SIZE 9 #define 9 9
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////

@ -490,8 +490,8 @@ void CDcsProtocol::EncodeDvPacket(const CDvHeaderPacket &Header, const CDvFrameP
Buffer->Append((uint8_t *)&DstarHeader, sizeof(struct dstar_header) - sizeof(uint16_t)); Buffer->Append((uint8_t *)&DstarHeader, sizeof(struct dstar_header) - sizeof(uint16_t));
Buffer->Append(DvFrame.GetStreamId()); Buffer->Append(DvFrame.GetStreamId());
Buffer->Append((uint8_t)(DvFrame.GetPacketId() % 21)); Buffer->Append((uint8_t)(DvFrame.GetPacketId() % 21));
Buffer->Append((uint8_t *)DvFrame.GetAmbe(), AMBE_SIZE); Buffer->Append((uint8_t *)DvFrame.GetCodecData(ECodecType::dstar), 9);
Buffer->Append((uint8_t *)DvFrame.GetDvData(), DVDATA_SIZE); Buffer->Append((uint8_t *)DvFrame.GetDvData(), 3);
Buffer->Append((uint8_t)((iSeq >> 0) & 0xFF)); Buffer->Append((uint8_t)((iSeq >> 0) & 0xFF));
Buffer->Append((uint8_t)((iSeq >> 8) & 0xFF)); Buffer->Append((uint8_t)((iSeq >> 8) & 0xFF));
Buffer->Append((uint8_t)((iSeq >> 16) & 0xFF)); Buffer->Append((uint8_t)((iSeq >> 16) & 0xFF));

@ -612,8 +612,8 @@ bool CDextraProtocol::EncodeDvFramePacket(const CDvFramePacket &Packet, CBuffer
Buffer->Set(tag, sizeof(tag)); Buffer->Set(tag, sizeof(tag));
Buffer->Append(Packet.GetStreamId()); Buffer->Append(Packet.GetStreamId());
Buffer->Append((uint8_t)(Packet.GetPacketId() % 21)); Buffer->Append((uint8_t)(Packet.GetPacketId() % 21));
Buffer->Append((uint8_t *)Packet.GetAmbe(), AMBE_SIZE); Buffer->Append((uint8_t *)Packet.GetCodecData(ECodecType::dstar), 9);
Buffer->Append((uint8_t *)Packet.GetDvData(), DVDATA_SIZE); Buffer->Append((uint8_t *)Packet.GetDvData(), 3);
return true; return true;

@ -32,7 +32,7 @@ CDmridDirFile g_DmridDir;
CDmridDirFile::CDmridDirFile() CDmridDirFile::CDmridDirFile()
{ {
::memset(&m_LastModTime, 0, sizeof(time_t)); memset(&m_LastModTime, 0, sizeof(time_t));
} }

@ -102,11 +102,11 @@ bool CDmridDirHttp::HttpGet(const char *hostname, const char *filename, int port
// get hostname address // get hostname address
struct sockaddr_in servaddr; struct sockaddr_in servaddr;
struct hostent *hp; struct hostent *hp;
::memset(&servaddr,0,sizeof(servaddr)); memset(&servaddr,0,sizeof(servaddr));
if( (hp = gethostbyname(hostname)) != nullptr ) if( (hp = gethostbyname(hostname)) != nullptr )
{ {
// dns resolved // dns resolved
::memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length); memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length);
servaddr.sin_port = htons(port); servaddr.sin_port = htons(port);
servaddr.sin_family = AF_INET; servaddr.sin_family = AF_INET;

@ -608,11 +608,11 @@ bool CDmrmmdvmProtocol::IsValidDvHeaderPacket(const CBuffer &Buffer, std::unique
// extract sync // extract sync
uint8_t dmrsync[7]; uint8_t dmrsync[7];
dmrsync[0] = Buffer.data()[33] & 0x0F; dmrsync[0] = Buffer.data()[33] & 0x0F;
::memcpy(&dmrsync[1], &Buffer.data()[34], 5); memcpy(&dmrsync[1], &Buffer.data()[34], 5);
dmrsync[6] = Buffer.data()[39] & 0xF0; dmrsync[6] = Buffer.data()[39] & 0xF0;
// and check // and check
if ( (::memcmp(dmrsync, g_DmrSyncMSData, sizeof(dmrsync)) == 0) || if ( (memcmp(dmrsync, g_DmrSyncMSData, sizeof(dmrsync)) == 0) ||
(::memcmp(dmrsync, g_DmrSyncBSData, sizeof(dmrsync)) == 0)) (memcmp(dmrsync, g_DmrSyncBSData, sizeof(dmrsync)) == 0))
{ {
// get payload // get payload
//CBPTC19696 bptc; //CBPTC19696 bptc;
@ -696,7 +696,7 @@ bool CDmrmmdvmProtocol::IsValidDvFramePacket(const CBuffer &Buffer, std::array<s
memcpy(&dmr3ambe[14], &dmrframe[20], 13); memcpy(&dmr3ambe[14], &dmrframe[20], 13);
// extract sync // extract sync
dmrsync[0] = dmrframe[13] & 0x0F; dmrsync[0] = dmrframe[13] & 0x0F;
::memcpy(&dmrsync[1], &dmrframe[14], 5); memcpy(&dmrsync[1], &dmrframe[14], 5);
dmrsync[6] = dmrframe[19] & 0xF0; dmrsync[6] = dmrframe[19] & 0xF0;
// debug // debug
@ -744,11 +744,11 @@ bool CDmrmmdvmProtocol::IsValidDvLastFramePacket(const CBuffer &Buffer, std::uni
// extract sync // extract sync
uint8_t dmrsync[7]; uint8_t dmrsync[7];
dmrsync[0] = Buffer.data()[33] & 0x0F; dmrsync[0] = Buffer.data()[33] & 0x0F;
::memcpy(&dmrsync[1], &Buffer.data()[34], 5); memcpy(&dmrsync[1], &Buffer.data()[34], 5);
dmrsync[6] = Buffer.data()[39] & 0xF0; dmrsync[6] = Buffer.data()[39] & 0xF0;
// and check // and check
if ( (::memcmp(dmrsync, g_DmrSyncMSData, sizeof(dmrsync)) == 0) || if ( (memcmp(dmrsync, g_DmrSyncMSData, sizeof(dmrsync)) == 0) ||
(::memcmp(dmrsync, g_DmrSyncBSData, sizeof(dmrsync)) == 0)) (memcmp(dmrsync, g_DmrSyncBSData, sizeof(dmrsync)) == 0))
{ {
// get payload // get payload
//CBPTC19696 bptc; //CBPTC19696 bptc;
@ -765,7 +765,7 @@ bool CDmrmmdvmProtocol::IsValidDvLastFramePacket(const CBuffer &Buffer, std::uni
// dummy ambe // dummy ambe
uint8_t ambe[9]; uint8_t ambe[9];
::memset(ambe, 0, sizeof(ambe)); memset(ambe, 0, sizeof(ambe));
// and packet // and packet
@ -901,15 +901,15 @@ void CDmrmmdvmProtocol::EncodeDvPacket(
// Payload // Payload
// frame0 // frame0
Buffer->ReplaceAt(20, DvFrame0.GetAmbePlus(), 9); Buffer->ReplaceAt(20, DvFrame0.GetCodecData(ECodecType::dmr), 9);
// 1/2 frame1 // 1/2 frame1
Buffer->ReplaceAt(29, DvFrame1.GetAmbePlus(), 5); Buffer->ReplaceAt(29, DvFrame1.GetCodecData(ECodecType::dmr), 5);
Buffer->ReplaceAt(33, (uint8_t)(Buffer->at(33) & 0xF0)); Buffer->ReplaceAt(33, (uint8_t)(Buffer->at(33) & 0xF0));
// 1/2 frame1 // 1/2 frame1
Buffer->ReplaceAt(39, DvFrame1.GetAmbePlus()+4, 5); Buffer->ReplaceAt(39, DvFrame1.GetCodecData(ECodecType::dmr)+4, 5);
Buffer->ReplaceAt(39, (uint8_t)(Buffer->at(39) & 0x0F)); Buffer->ReplaceAt(39, (uint8_t)(Buffer->at(39) & 0x0F));
// frame2 // frame2
Buffer->ReplaceAt(44, DvFrame2.GetAmbePlus(), 9); Buffer->ReplaceAt(44, DvFrame2.GetCodecData(ECodecType::dmr), 9);
// sync or embedded signaling // sync or embedded signaling
ReplaceEMBInBuffer(Buffer, DvFrame0.GetDmrPacketId()); ReplaceEMBInBuffer(Buffer, DvFrame0.GetDmrPacketId());
@ -997,11 +997,11 @@ void CDmrmmdvmProtocol::AppendVoiceLCToBuffer(CBuffer *buffer, uint32_t uiSrcId)
// fill payload // fill payload
CBPTC19696 bptc; CBPTC19696 bptc;
::memset(payload, 0, sizeof(payload)); memset(payload, 0, sizeof(payload));
// LC data // LC data
uint8_t lc[12]; uint8_t lc[12];
{ {
::memset(lc, 0, sizeof(lc)); memset(lc, 0, sizeof(lc));
// uiDstId = TG9 // uiDstId = TG9
lc[5] = 9; lc[5] = 9;
// uiSrcId // uiSrcId
@ -1016,12 +1016,12 @@ void CDmrmmdvmProtocol::AppendVoiceLCToBuffer(CBuffer *buffer, uint32_t uiSrcId)
lc[11] = parity[0] ^ DMR_VOICE_LC_HEADER_CRC_MASK; lc[11] = parity[0] ^ DMR_VOICE_LC_HEADER_CRC_MASK;
} }
// sync // sync
::memcpy(payload+13, g_DmrSyncBSData, sizeof(g_DmrSyncBSData)); memcpy(payload+13, g_DmrSyncBSData, sizeof(g_DmrSyncBSData));
// slot type // slot type
{ {
// slot type // slot type
uint8_t slottype[3]; uint8_t slottype[3];
::memset(slottype, 0, sizeof(slottype)); memset(slottype, 0, sizeof(slottype));
slottype[0] = (DMRMMDVM_REFLECTOR_COLOUR << 4) & 0xF0; slottype[0] = (DMRMMDVM_REFLECTOR_COLOUR << 4) & 0xF0;
slottype[0] |= (DMR_DT_VOICE_LC_HEADER << 0) & 0x0FU; slottype[0] |= (DMR_DT_VOICE_LC_HEADER << 0) & 0x0FU;
CGolay2087::encode(slottype); CGolay2087::encode(slottype);
@ -1044,11 +1044,11 @@ void CDmrmmdvmProtocol::AppendTerminatorLCToBuffer(CBuffer *buffer, uint32_t uiS
// fill payload // fill payload
CBPTC19696 bptc; CBPTC19696 bptc;
::memset(payload, 0, sizeof(payload)); memset(payload, 0, sizeof(payload));
// LC data // LC data
uint8_t lc[12]; uint8_t lc[12];
{ {
::memset(lc, 0, sizeof(lc)); memset(lc, 0, sizeof(lc));
// uiDstId = TG9 // uiDstId = TG9
lc[5] = 9; lc[5] = 9;
// uiSrcId // uiSrcId
@ -1063,12 +1063,12 @@ void CDmrmmdvmProtocol::AppendTerminatorLCToBuffer(CBuffer *buffer, uint32_t uiS
lc[11] = parity[0] ^ DMR_TERMINATOR_WITH_LC_CRC_MASK; lc[11] = parity[0] ^ DMR_TERMINATOR_WITH_LC_CRC_MASK;
} }
// sync // sync
::memcpy(payload+13, g_DmrSyncBSData, sizeof(g_DmrSyncBSData)); memcpy(payload+13, g_DmrSyncBSData, sizeof(g_DmrSyncBSData));
// slot type // slot type
{ {
// slot type // slot type
uint8_t slottype[3]; uint8_t slottype[3];
::memset(slottype, 0, sizeof(slottype)); memset(slottype, 0, sizeof(slottype));
slottype[0] = (DMRMMDVM_REFLECTOR_COLOUR << 4) & 0xF0; slottype[0] = (DMRMMDVM_REFLECTOR_COLOUR << 4) & 0xF0;
slottype[0] |= (DMR_DT_TERMINATOR_WITH_LC << 0) & 0x0FU; slottype[0] |= (DMR_DT_TERMINATOR_WITH_LC << 0) & 0x0FU;
CGolay2087::encode(slottype); CGolay2087::encode(slottype);

@ -367,12 +367,12 @@ bool CDmrplusProtocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign *ca
if ( Buffer.size() == 31 ) if ( Buffer.size() == 31 )
{ {
char sz[9]; char sz[9];
::memcpy(sz, Buffer.data(), 8); memcpy(sz, Buffer.data(), 8);
sz[8] = 0; sz[8] = 0;
uint32_t dmrid = atoi(sz); uint32_t dmrid = atoi(sz);
callsign->SetDmrid(dmrid, true); callsign->SetDmrid(dmrid, true);
callsign->SetModule(DMRPLUS_MODULE_ID); callsign->SetModule(DMRPLUS_MODULE_ID);
::memcpy(sz, &Buffer.data()[8], 4); memcpy(sz, &Buffer.data()[8], 4);
sz[4] = 0; sz[4] = 0;
*reflectormodule = DmrDstIdToModule(atoi(sz)); *reflectormodule = DmrDstIdToModule(atoi(sz));
valid = (callsign->IsValid() && (std::isupper(*reflectormodule) || (*reflectormodule == ' ')) ); valid = (callsign->IsValid() && (std::isupper(*reflectormodule) || (*reflectormodule == ' ')) );
@ -390,7 +390,7 @@ bool CDmrplusProtocol::IsValidDisconnectPacket(const CBuffer &Buffer, CCallsign
if ( Buffer.size() == 32 ) if ( Buffer.size() == 32 )
{ {
char sz[9]; char sz[9];
::memcpy(sz, Buffer.data(), 8); memcpy(sz, Buffer.data(), 8);
sz[8] = 0; sz[8] = 0;
uint32_t dmrid = atoi(sz); uint32_t dmrid = atoi(sz);
callsign->SetDmrid(dmrid, true); callsign->SetDmrid(dmrid, true);
@ -468,7 +468,7 @@ bool CDmrplusProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffer
memcpy(&dmr3ambe[14], &dmrframe[20], 13); memcpy(&dmr3ambe[14], &dmrframe[20], 13);
// extract sync // extract sync
dmrsync[0] = dmrframe[13] & 0x0F; dmrsync[0] = dmrframe[13] & 0x0F;
::memcpy(&dmrsync[1], &dmrframe[14], 5); memcpy(&dmrsync[1], &dmrframe[14], 5);
dmrsync[6] = dmrframe[19] & 0xF0; dmrsync[6] = dmrframe[19] & 0xF0;
// and create 3 dv frames // and create 3 dv frames
@ -597,15 +597,15 @@ void CDmrplusProtocol::EncodeDvPacket
uint32_t uiSrcId = Header.GetMyCallsign().GetDmrid() & 0x00FFFFFF; uint32_t uiSrcId = Header.GetMyCallsign().GetDmrid() & 0x00FFFFFF;
uint32_t uiDstId = ModuleToDmrDestId(Header.GetRpt2Module()) & 0x00FFFFFF; uint32_t uiDstId = ModuleToDmrDestId(Header.GetRpt2Module()) & 0x00FFFFFF;
// frame0 // frame0
Buffer->ReplaceAt(26, DvFrame0.GetAmbePlus(), 9); Buffer->ReplaceAt(26, DvFrame0.GetCodecData(ECodecType::dmr), 9);
// 1/2 frame1 // 1/2 frame1
Buffer->ReplaceAt(35, DvFrame1.GetAmbePlus(), 5); Buffer->ReplaceAt(35, DvFrame1.GetCodecData(ECodecType::dmr), 5);
Buffer->ReplaceAt(39, (uint8_t)(Buffer->at(39) & 0xF0)); Buffer->ReplaceAt(39, (uint8_t)(Buffer->at(39) & 0xF0));
// 1/2 frame1 // 1/2 frame1
Buffer->ReplaceAt(45, DvFrame1.GetAmbePlus()+4, 5); Buffer->ReplaceAt(45, DvFrame1.GetCodecData(ECodecType::dmr)+4, 5);
Buffer->ReplaceAt(45, (uint8_t)(Buffer->at(45) & 0x0F)); Buffer->ReplaceAt(45, (uint8_t)(Buffer->at(45) & 0x0F));
// frame2 // frame2
Buffer->ReplaceAt(50, DvFrame2.GetAmbePlus(), 9); Buffer->ReplaceAt(50, DvFrame2.GetCodecData(ECodecType::dmr), 9);
// sync or embedded signaling // sync or embedded signaling
ReplaceEMBInBuffer(Buffer, DvFrame0.GetDmrPacketId()); ReplaceEMBInBuffer(Buffer, DvFrame0.GetDmrPacketId());
@ -675,11 +675,11 @@ void CDmrplusProtocol::AppendVoiceLCToBuffer(CBuffer *buffer, uint32_t uiSrcId)
// fill payload // fill payload
CBPTC19696 bptc; CBPTC19696 bptc;
::memset(payload, 0, sizeof(payload)); memset(payload, 0, sizeof(payload));
// LC data // LC data
uint8_t lc[12]; uint8_t lc[12];
{ {
::memset(lc, 0, sizeof(lc)); memset(lc, 0, sizeof(lc));
// uiDstId = TG9 // uiDstId = TG9
lc[5] = 9; lc[5] = 9;
// uiSrcId // uiSrcId
@ -694,12 +694,12 @@ void CDmrplusProtocol::AppendVoiceLCToBuffer(CBuffer *buffer, uint32_t uiSrcId)
lc[11] = parity[0] ^ DMR_VOICE_LC_HEADER_CRC_MASK; lc[11] = parity[0] ^ DMR_VOICE_LC_HEADER_CRC_MASK;
} }
// sync // sync
::memcpy(payload+13, g_DmrSyncBSData, sizeof(g_DmrSyncBSData)); memcpy(payload+13, g_DmrSyncBSData, sizeof(g_DmrSyncBSData));
// slot type // slot type
{ {
// slot type // slot type
uint8_t slottype[3]; uint8_t slottype[3];
::memset(slottype, 0, sizeof(slottype)); memset(slottype, 0, sizeof(slottype));
slottype[0] = (DMRPLUS_REFLECTOR_COLOUR << 4) & 0xF0; slottype[0] = (DMRPLUS_REFLECTOR_COLOUR << 4) & 0xF0;
slottype[0] |= (DMR_DT_VOICE_LC_HEADER << 0) & 0x0FU; slottype[0] |= (DMR_DT_VOICE_LC_HEADER << 0) & 0x0FU;
CGolay2087::encode(slottype); CGolay2087::encode(slottype);

@ -393,7 +393,7 @@ bool CDplusProtocol::IsValidLoginPacket(const CBuffer &Buffer, CCallsign *Callsi
uint8_t Tag[] = { 0x1C,0xC0,0x04,0x00 }; uint8_t Tag[] = { 0x1C,0xC0,0x04,0x00 };
bool valid = false; bool valid = false;
if ( (Buffer.size() == 28) &&(::memcmp(Buffer.data(), Tag, sizeof(Tag)) == 0) ) if ( (Buffer.size() == 28) &&(memcmp(Buffer.data(), Tag, sizeof(Tag)) == 0) )
{ {
Callsign->SetCallsign(&(Buffer.data()[4]), 8); Callsign->SetCallsign(&(Buffer.data()[4]), 8);
valid = Callsign->IsValid(); valid = Callsign->IsValid();
@ -503,8 +503,8 @@ bool CDplusProtocol::EncodeDvFramePacket(const CDvFramePacket &Packet, CBuffer *
Buffer->Set(tag, sizeof(tag)); Buffer->Set(tag, sizeof(tag));
Buffer->Append(Packet.GetStreamId()); Buffer->Append(Packet.GetStreamId());
Buffer->Append((uint8_t)(Packet.GetPacketId() % 21)); Buffer->Append((uint8_t)(Packet.GetPacketId() % 21));
Buffer->Append((uint8_t *)Packet.GetAmbe(), AMBE_SIZE); Buffer->Append((uint8_t *)Packet.GetCodecData(ECodecType::dstar), 9);
Buffer->Append((uint8_t *)Packet.GetDvData(), DVDATA_SIZE); Buffer->Append((uint8_t *)Packet.GetDvData(), 3);
return true; return true;

@ -1,5 +1,5 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. // Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ulxd -- The universal reflector // ulxd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE // Copyright © 2021 Thomas A. Early N7TAE
// //
@ -16,20 +16,21 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include "Main.h" #include "Main.h"
#include <string.h>
#include "DVFramePacket.h" #include "DVFramePacket.h"
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// constructor // constructor
CDvFramePacket::CDvFramePacket() CDvFramePacket::CDvFramePacket()
{ {
::memset(m_uiAmbe, 0, sizeof(m_uiAmbe)); memset(m_uiAmbe, 0, AMBE_SIZE);
::memset(m_uiDvData, 0, sizeof(m_uiDvData)); memset(m_uiDvData, 0, DVDATA_SIZE);
::memset(m_uiAmbePlus, 0, sizeof(m_uiAmbePlus)); memset(m_uiAmbePlus, 0, AMBEPLUS_SIZE);
::memset(m_uiDvSync, 0, sizeof(m_uiDvSync)); memset(m_uiDvSync, 0, DVSYNC_SIZE);
memset(m_uiCodec2, 0, 16);
memset(m_Nonce, 0, 14);
}; };
// dstar constructor // dstar constructor
@ -37,10 +38,12 @@ CDvFramePacket::CDvFramePacket()
CDvFramePacket::CDvFramePacket(const struct dstar_dvframe *dvframe, uint16_t sid, uint8_t pid) CDvFramePacket::CDvFramePacket(const struct dstar_dvframe *dvframe, uint16_t sid, uint8_t pid)
: CPacket(sid, pid) : CPacket(sid, pid)
{ {
::memcpy(m_uiAmbe, dvframe->AMBE, sizeof(m_uiAmbe)); memcpy(m_uiAmbe, dvframe->AMBE, AMBE_SIZE);
::memcpy(m_uiDvData, dvframe->DVDATA, sizeof(m_uiDvData)); memcpy(m_uiDvData, dvframe->DVDATA, DVDATA_SIZE);
::memset(m_uiAmbePlus, 0, sizeof(m_uiAmbePlus)); memset(m_uiAmbePlus, 0, AMBEPLUS_SIZE);
::memset(m_uiDvSync, 0, sizeof(m_uiDvSync)); memset(m_uiDvSync, 0, DVSYNC_SIZE);
memset(m_uiCodec2, 0, 16);
memset(m_Nonce, 0, 14);
} }
// dmr constructor // dmr constructor
@ -48,10 +51,12 @@ CDvFramePacket::CDvFramePacket(const struct dstar_dvframe *dvframe, uint16_t sid
CDvFramePacket::CDvFramePacket(const uint8_t *ambe, const uint8_t *sync, uint16_t sid, uint8_t pid, uint8_t spid) CDvFramePacket::CDvFramePacket(const uint8_t *ambe, const uint8_t *sync, uint16_t sid, uint8_t pid, uint8_t spid)
: CPacket(sid, pid, spid) : CPacket(sid, pid, spid)
{ {
::memcpy(m_uiAmbePlus, ambe, sizeof(m_uiAmbePlus)); memcpy(m_uiAmbePlus, ambe, AMBEPLUS_SIZE);
::memcpy(m_uiDvSync, sync, sizeof(m_uiDvSync)); memcpy(m_uiDvSync, sync, DVSYNC_SIZE);
::memset(m_uiAmbe, 0, sizeof(m_uiAmbe)); memset(m_uiAmbe, 0, AMBE_SIZE);
::memset(m_uiDvData, 0, sizeof(m_uiDvData)); memset(m_uiDvData, 0, DVDATA_SIZE);
memset(m_uiCodec2, 0, 16);
memset(m_Nonce, 0, 14);
} }
// ysf constructor // ysf constructor
@ -59,10 +64,12 @@ CDvFramePacket::CDvFramePacket(const uint8_t *ambe, const uint8_t *sync, uint16_
CDvFramePacket::CDvFramePacket(const uint8_t *ambe, uint16_t sid, uint8_t pid, uint8_t spid, uint8_t fid) CDvFramePacket::CDvFramePacket(const uint8_t *ambe, uint16_t sid, uint8_t pid, uint8_t spid, uint8_t fid)
: CPacket(sid, pid, spid, fid) : CPacket(sid, pid, spid, fid)
{ {
::memcpy(m_uiAmbePlus, ambe, sizeof(m_uiAmbePlus)); memcpy(m_uiAmbePlus, ambe, AMBEPLUS_SIZE);
::memset(m_uiDvSync, 0, sizeof(m_uiDvSync)); memset(m_uiDvSync, 0, DVSYNC_SIZE);
::memset(m_uiAmbe, 0, sizeof(m_uiAmbe)); memset(m_uiAmbe, 0, AMBE_SIZE);
::memset(m_uiDvData, 0, sizeof(m_uiDvData)); memset(m_uiDvData, 0, DVDATA_SIZE);
memset(m_uiCodec2, 0, 16);
memset(m_Nonce, 0, 14);
} }
// xlx constructor // xlx constructor
@ -70,13 +77,25 @@ CDvFramePacket::CDvFramePacket(const uint8_t *ambe, uint16_t sid, uint8_t pid, u
CDvFramePacket::CDvFramePacket CDvFramePacket::CDvFramePacket
(uint16_t sid, (uint16_t sid,
uint8_t dstarpid, const uint8_t *dstarambe, const uint8_t *dstardvdata, uint8_t dstarpid, const uint8_t *dstarambe, const uint8_t *dstardvdata,
uint8_t dmrpid, uint8_t dprspid, const uint8_t *dmrambe, const uint8_t *dmrsync) uint8_t dmrpid, uint8_t dprspid, const uint8_t *dmrambe, const uint8_t *dmrsync, ECodecType codecInType, const uint8_t *codec2, const uint8_t * nonce)
: CPacket(sid, dstarpid, dmrpid, dprspid, 0xFF, 0xFF, 0xFF) : CPacket(sid, dstarpid, dmrpid, dprspid, 0xFF, 0xFF, 0xFF, codecInType)
{ {
::memcpy(m_uiAmbe, dstarambe, sizeof(m_uiAmbe)); memcpy(m_uiAmbe, dstarambe, AMBE_SIZE);
::memcpy(m_uiDvData, dstardvdata, sizeof(m_uiDvData)); memcpy(m_uiDvData, dstardvdata, DVDATA_SIZE);
::memcpy(m_uiAmbePlus, dmrambe, sizeof(m_uiAmbePlus)); memcpy(m_uiAmbePlus, dmrambe, AMBEPLUS_SIZE);
::memcpy(m_uiDvSync, dmrsync, sizeof(m_uiDvSync)); memcpy(m_uiDvSync, dmrsync, DVSYNC_SIZE);
memcpy(m_uiCodec2, codec2, 16);
memcpy(m_Nonce, nonce, 14);
}
CDvFramePacket::CDvFramePacket(const CM17Packet &m17) : CPacket(m17)
{
memset(m_uiAmbe, 0, AMBE_SIZE);
memset(m_uiDvData, 0, DVDATA_SIZE);
memset(m_uiAmbePlus, 0, AMBEPLUS_SIZE);
memset(m_uiDvSync, 0, DVSYNC_SIZE);
memcpy(m_uiCodec2, m17.GetPayload(), 16);
memcpy(m_Nonce, m17.GetNonce(), 14);
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -90,14 +109,17 @@ std::unique_ptr<CPacket> CDvFramePacket::Duplicate(void) const
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// get // get
const uint8_t *CDvFramePacket::GetAmbe(uint8_t uiCodec) const const uint8_t *CDvFramePacket::GetCodecData(ECodecType type) const
{ {
switch (uiCodec) switch (type)
{ {
case CODEC_AMBEPLUS: case ECodecType::dstar:
return m_uiAmbe; return m_uiAmbe;
case CODEC_AMBE2PLUS: case ECodecType::dmr:
return m_uiAmbePlus; return m_uiAmbePlus;
case ECodecType::c2_1600:
case ECodecType::c2_3200:
return m_uiCodec2;
default: default:
return nullptr; return nullptr;
} }
@ -108,18 +130,24 @@ const uint8_t *CDvFramePacket::GetAmbe(uint8_t uiCodec) const
void CDvFramePacket::SetDvData(uint8_t *DvData) void CDvFramePacket::SetDvData(uint8_t *DvData)
{ {
::memcpy(m_uiDvData, DvData, sizeof(m_uiDvData)); memcpy(m_uiDvData, DvData, DVDATA_SIZE);
} }
void CDvFramePacket::SetAmbe(uint8_t uiCodec, uint8_t *Ambe) void CDvFramePacket::SetCodecData(ECodecType type, uint8_t *data)
{ {
switch (uiCodec) switch (type)
{ {
case CODEC_AMBEPLUS: case ECodecType::dstar:
::memcpy(m_uiAmbe, Ambe, sizeof(m_uiAmbe)); memcpy(m_uiAmbe, data, AMBE_SIZE);
break;
case ECodecType::dmr:
memcpy(m_uiAmbePlus, data, DVDATA_SIZE);
break;
case ECodecType::c2_1600:
memcpy(m_uiCodec2, data, 8);
break; break;
case CODEC_AMBE2PLUS: case ECodecType::c2_3200:
::memcpy(m_uiAmbePlus, Ambe, sizeof(m_uiAmbe)); memcpy(m_uiCodec2, data, 16);
break; break;
} }
} }
@ -130,9 +158,11 @@ void CDvFramePacket::SetAmbe(uint8_t uiCodec, uint8_t *Ambe)
bool CDvFramePacket::operator ==(const CDvFramePacket &DvFrame) const bool CDvFramePacket::operator ==(const CDvFramePacket &DvFrame) const
{ {
return ( (::memcmp(m_uiAmbe, DvFrame.m_uiAmbe, sizeof(m_uiAmbe)) == 0) return ( (memcmp(m_uiAmbe, DvFrame.m_uiAmbe, AMBE_SIZE) == 0)
&& (::memcmp(m_uiDvData, DvFrame.m_uiDvData, sizeof(m_uiDvData)) == 0) && (memcmp(m_uiDvData, DvFrame.m_uiDvData, DVDATA_SIZE) == 0)
&& (::memcmp(m_uiAmbePlus, DvFrame.m_uiAmbePlus, sizeof(m_uiAmbePlus)) == 0) #ifndef NO_XLX
&& (::memcmp(m_uiDvSync, DvFrame.m_uiDvSync, sizeof(m_uiDvSync)) == 0) && (memcmp(m_uiAmbePlus, DvFrame.m_uiAmbePlus, AMBEPLUS_SIZE) == 0)
&& (memcmp(m_uiDvSync, DvFrame.m_uiDvSync, DVSYNC_SIZE) == 0)
#endif
); );
} }

@ -1,5 +1,7 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. #pragma once
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ulxd -- The universal reflector // ulxd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE // Copyright © 2021 Thomas A. Early N7TAE
// //
@ -16,8 +18,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "Packet.h" #include "Packet.h"
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -49,7 +49,8 @@ public:
CDvFramePacket(const struct dstar_dvframe *, uint16_t, uint8_t); CDvFramePacket(const struct dstar_dvframe *, uint16_t, uint8_t);
CDvFramePacket(const uint8_t *, const uint8_t *, uint16_t, uint8_t, uint8_t); CDvFramePacket(const uint8_t *, const uint8_t *, uint16_t, uint8_t, uint8_t);
CDvFramePacket(const uint8_t *, uint16_t, uint8_t, uint8_t, uint8_t); CDvFramePacket(const uint8_t *, uint16_t, uint8_t, uint8_t, uint8_t);
CDvFramePacket(uint16_t, uint8_t, const uint8_t *, const uint8_t *, uint8_t, uint8_t, const uint8_t *, const uint8_t *); CDvFramePacket(uint16_t, uint8_t, const uint8_t *, const uint8_t *, uint8_t, uint8_t, const uint8_t *, const uint8_t *, ECodecType, const uint8_t *, const uint8_t *);
CDvFramePacket(const CM17Packet &m17);
// virtual duplication // virtual duplication
std::unique_ptr<CPacket> Duplicate(void) const; std::unique_ptr<CPacket> Duplicate(void) const;
@ -59,24 +60,18 @@ public:
bool HasTranscodableAmbe(void) const { return true; } bool HasTranscodableAmbe(void) const { return true; }
// get // get
const uint8_t *GetAmbe(uint8_t) const; const uint8_t *GetCodecData(ECodecType) const;
const uint8_t *GetAmbe(void) const { return m_uiAmbe; }
const uint8_t *GetAmbePlus(void) const { return m_uiAmbePlus; }
const uint8_t *GetDvSync(void) const { return m_uiDvSync; } const uint8_t *GetDvSync(void) const { return m_uiDvSync; }
const uint8_t *GetDvData(void) const { return m_uiDvData; } const uint8_t *GetDvData(void) const { return m_uiDvData; }
const uint8_t *GetNonce(void) const { return m_Nonce; }
// set // set
void SetDvData(uint8_t *); void SetDvData(uint8_t *);
void SetAmbe(uint8_t, uint8_t *); void SetCodecData(ECodecType, uint8_t *);
// operators // operators
bool operator ==(const CDvFramePacket &) const; bool operator ==(const CDvFramePacket &) const;
protected:
// get
uint8_t *GetAmbeData(void) { return m_uiAmbe; }
uint8_t *GetAmbePlusData(void) { return m_uiAmbePlus; }
protected: protected:
// data (dstar) // data (dstar)
uint8_t m_uiAmbe[AMBE_SIZE]; uint8_t m_uiAmbe[AMBE_SIZE];
@ -84,4 +79,7 @@ protected:
// data (dmr) // data (dmr)
uint8_t m_uiAmbePlus[AMBEPLUS_SIZE]; uint8_t m_uiAmbePlus[AMBEPLUS_SIZE];
uint8_t m_uiDvSync[DVSYNC_SIZE]; uint8_t m_uiDvSync[DVSYNC_SIZE];
uint8_t m_uiCodec2[16];
uint8_t m_Nonce[14];
}; };

@ -1,5 +1,5 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. // Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ulxd -- The universal reflector // ulxd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE // Copyright © 2021 Thomas A. Early N7TAE
// //
@ -79,6 +79,17 @@ CDvHeaderPacket::CDvHeaderPacket(const CCallsign &my, const CCallsign &ur, const
m_csMY = my; m_csMY = my;
} }
// M17
CDvHeaderPacket::CDvHeaderPacket(const CM17Packet &m17) : CPacket(m17)
{
m_uiFlag1 = m_uiFlag2 = m_uiFlag3 = 0;
m_uiCrc = 0;
m_csUR = CCallsign("CQCQCQ");
m_csMY = m_csRPT1 = m_csRPT2 = m17.GetSourceCallsign();
m_csRPT1.SetModule('G');
}
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// virtual duplication // virtual duplication
@ -92,7 +103,7 @@ std::unique_ptr<CPacket> CDvHeaderPacket::Duplicate(void) const
void CDvHeaderPacket::ConvertToDstarStruct(struct dstar_header *buffer) const void CDvHeaderPacket::ConvertToDstarStruct(struct dstar_header *buffer) const
{ {
::memset(buffer, 0, sizeof(struct dstar_header)); memset(buffer, 0, sizeof(struct dstar_header));
buffer->Flag1 = m_uiFlag1; buffer->Flag1 = m_uiFlag1;
buffer->Flag2 = m_uiFlag2; buffer->Flag2 = m_uiFlag2;
buffer->Flag3 = m_uiFlag3; buffer->Flag3 = m_uiFlag3;

@ -1,5 +1,7 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. #pragma once
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ulxd -- The universal reflector // ulxd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE // Copyright © 2021 Thomas A. Early N7TAE
// //
@ -16,8 +18,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "Callsign.h" #include "Callsign.h"
#include "Packet.h" #include "Packet.h"
@ -57,6 +57,7 @@ public:
CDvHeaderPacket(const struct dstar_header *, uint16_t, uint8_t); CDvHeaderPacket(const struct dstar_header *, uint16_t, uint8_t);
CDvHeaderPacket(uint32_t, const CCallsign &, const CCallsign &, const CCallsign &, uint16_t, uint8_t, uint8_t); CDvHeaderPacket(uint32_t, const CCallsign &, const CCallsign &, const CCallsign &, uint16_t, uint8_t, uint8_t);
CDvHeaderPacket(const CCallsign &, const CCallsign &, const CCallsign &, const CCallsign &, uint16_t, uint8_t); CDvHeaderPacket(const CCallsign &, const CCallsign &, const CCallsign &, const CCallsign &, uint16_t, uint8_t);
CDvHeaderPacket(const CM17Packet &);
// virtual duplication // virtual duplication
std::unique_ptr<CPacket> Duplicate(void) const; std::unique_ptr<CPacket> Duplicate(void) const;

@ -1,5 +1,5 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. // Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ulxd -- The universal reflector // ulxd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE // Copyright © 2021 Thomas A. Early N7TAE
// //
@ -41,22 +41,27 @@ CDvLastFramePacket::CDvLastFramePacket(const uint8_t *ambe, const uint8_t *sync,
{ {
} }
// dstar + dmr constructor // ysf constructor
CDvLastFramePacket::CDvLastFramePacket(const uint8_t *ambe, uint16_t sid, uint8_t pid, uint8_t spid, uint8_t fid)
: CDvFramePacket(ambe, sid, pid, spid, fid)
{
}
// urf constructor
CDvLastFramePacket::CDvLastFramePacket CDvLastFramePacket::CDvLastFramePacket
(uint16_t sid, (uint16_t sid,
uint8_t dstarpid, const uint8_t *dstarambe, const uint8_t *dstardvdata, uint8_t dstarpid, const uint8_t *dstarambe, const uint8_t *dstardvdata,
uint8_t dmrpid, uint8_t dprspid, const uint8_t *dmrambe, const uint8_t *dmrsync) uint8_t dmrpid, uint8_t dprspid, const uint8_t *dmrambe, const uint8_t *dmrsync, ECodecType type, const uint8_t *codec2)
: CDvFramePacket(sid, dstarpid, dstarambe, dstardvdata, dmrpid, dprspid, dmrambe, dmrsync) : CDvFramePacket(sid, dstarpid, dstarambe, dstardvdata, dmrpid, dprspid, dmrambe, dmrsync, type, codec2)
{ {
} }
// ysf constructor CDvLastFramePacket::CDvLastFramePacket(const CM17Packet &m17) : CDvFramePacket(m17)
CDvLastFramePacket::CDvLastFramePacket(const uint8_t *ambe, uint16_t sid, uint8_t pid, uint8_t spid, uint8_t fid)
: CDvFramePacket(ambe, sid, pid, spid, fid)
{ {
} }
// copy constructor // copy constructor
CDvLastFramePacket::CDvLastFramePacket(const CDvLastFramePacket &DvFrame) CDvLastFramePacket::CDvLastFramePacket(const CDvLastFramePacket &DvFrame)

@ -1,5 +1,7 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. #pragma once
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ulxd -- The universal reflector // ulxd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE // Copyright © 2021 Thomas A. Early N7TAE
// //
@ -16,10 +18,15 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "DVFramePacket.h" #include "DVFramePacket.h"
////////////////////////////////////////////////////////////////////////////////////////
// defines
////////////////////////////////////////////////////////////////////////////////////////
// class
class CDvLastFramePacket : public CDvFramePacket class CDvLastFramePacket : public CDvFramePacket
{ {
public: public:
@ -28,7 +35,8 @@ public:
CDvLastFramePacket(const struct dstar_dvframe *, uint16_t, uint8_t); CDvLastFramePacket(const struct dstar_dvframe *, uint16_t, uint8_t);
CDvLastFramePacket(const uint8_t *, const uint8_t *, uint16_t, uint8_t, uint8_t); CDvLastFramePacket(const uint8_t *, const uint8_t *, uint16_t, uint8_t, uint8_t);
CDvLastFramePacket(const uint8_t *, uint16_t, uint8_t, uint8_t, uint8_t); CDvLastFramePacket(const uint8_t *, uint16_t, uint8_t, uint8_t, uint8_t);
CDvLastFramePacket(uint16_t, uint8_t, const uint8_t *, const uint8_t *, uint8_t, uint8_t, const uint8_t *, const uint8_t *); CDvLastFramePacket(uint16_t, uint8_t, const uint8_t *, const uint8_t *, uint8_t, uint8_t, const uint8_t *, const uint8_t *, ECodecType, const uint8_t *);
CDvLastFramePacket(const CM17Packet &);
CDvLastFramePacket(const CDvLastFramePacket &); CDvLastFramePacket(const CDvLastFramePacket &);
// virtual duplication // virtual duplication

@ -652,8 +652,8 @@ bool CG3Protocol::EncodeDvFramePacket(const CDvFramePacket &Packet, CBuffer *Buf
Buffer->Set(tag, sizeof(tag)); Buffer->Set(tag, sizeof(tag));
Buffer->Append(Packet.GetStreamId()); Buffer->Append(Packet.GetStreamId());
Buffer->Append((uint8_t)(Packet.GetPacketId() % 21)); Buffer->Append((uint8_t)(Packet.GetPacketId() % 21));
Buffer->Append((uint8_t *)Packet.GetAmbe(), AMBE_SIZE); Buffer->Append((uint8_t *)Packet.GetCodecData(ECodecType::dstar), 9);
Buffer->Append((uint8_t *)Packet.GetDvData(), DVDATA_SIZE); Buffer->Append((uint8_t *)Packet.GetDvData(), 3);
return true; return true;

@ -88,6 +88,7 @@ bool CGateKeeper::MayLink(const CCallsign &callsign, const CIp &ip, EProtocol pr
case EProtocol::dmrplus: case EProtocol::dmrplus:
case EProtocol::dmrmmdvm: case EProtocol::dmrmmdvm:
case EProtocol::ysf: case EProtocol::ysf:
case EProtocol::m17:
#ifndef NO_G3 #ifndef NO_G3
case EProtocol::g3: case EProtocol::g3:
#endif #endif
@ -132,6 +133,7 @@ bool CGateKeeper::MayTransmit(const CCallsign &callsign, const CIp &ip, const EP
case EProtocol::dmrplus: case EProtocol::dmrplus:
case EProtocol::dmrmmdvm: case EProtocol::dmrmmdvm:
case EProtocol::ysf: case EProtocol::ysf:
case EProtocol::m17:
#ifndef NO_G3 #ifndef NO_G3
case EProtocol::g3: case EProtocol::g3:
#endif #endif

@ -0,0 +1,76 @@
/*
* Library: libcrc
* Git: https://github.com/lammertb/libcrc
* Author: Lammert Bies
*
* This file is licensed under the MIT License as stated below
*
* Copyright (c) 1999-2016 Lammert Bies
* Copyright (c) 2020 Thomas A. Early, N7TAE
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Description
* -----------
* The source file contains routines which calculate the CCITT CRC
* values for an incomming byte string.
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "M17CRC.h"
#define CRC_POLY_16 0x5935u
#define CRC_START_16 0xFFFFu
CM17CRC::CM17CRC()
{
for (uint16_t i=0; i<256; i++)
{
uint16_t crc = 0;
uint16_t c = i << 8;
for (uint16_t j=0; j<8; j++)
{
if ( (crc ^ c) & 0x8000 )
crc = ( crc << 1 ) ^ CRC_POLY_16;
else
crc = crc << 1;
c = c << 1;
}
crc_tab16[i] = crc;
}
}
uint16_t CM17CRC::CalcCRC( const uint8_t *input_str, size_t num_bytes ) const
{
uint16_t crc = CRC_START_16;
if ( input_str )
for (size_t a=0; a<num_bytes; a++)
{
crc = (crc << 8) ^ crc_tab16[ ((crc >> 8) ^ uint16_t(input_str[a])) & 0x00FF ];
}
return crc;
}

@ -0,0 +1,48 @@
/*
* Library: libcrc
* Git: https://github.com/lammertb/libcrc
* Author: Lammert Bies
*
* This file is licensed under the MIT License as stated below
*
* Copyright (c) 1999-2016 Lammert Bies
* Copyright (c) 2020 Thomas A. Early, N7TAE
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Description
* -----------
* The source file contains routines which calculate the CCITT CRC
* values for an incomming byte string.
*/
#pragma once
#include <cstdint>
#include <cstddef>
class CM17CRC
{
public:
CM17CRC();
uint16_t CalcCRC(const uint8_t *buf, size_t len) const;
private:
uint16_t crc_tab16[256];
};

@ -0,0 +1,44 @@
// ulxd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "M17Client.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructors
CM17Client::CM17Client()
{
}
CM17Client::CM17Client(const CCallsign &callsign, const CIp &ip, char reflectorModule)
: CClient(callsign, ip, reflectorModule)
{
}
CM17Client::CM17Client(const CM17Client &client)
: CClient(client)
{
}
////////////////////////////////////////////////////////////////////////////////////////
// status
bool CM17Client::IsAlive(void) const
{
return (m_LastKeepaliveTime.time() < M17_KEEPALIVE_TIMEOUT);
}

@ -0,0 +1,47 @@
#pragma once
// ulxd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Client.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
////////////////////////////////////////////////////////////////////////////////////////
// class
class CM17Client : public CClient
{
public:
// constructors
CM17Client();
CM17Client(const CCallsign &, const CIp &, char);
CM17Client(const CM17Client &);
// destructor
virtual ~CM17Client() {};
// identity
const char *GetProtocolName(void) const { return "M17"; }
bool IsNode(void) const { return true; }
// status
bool IsAlive(void) const;
};
////////////////////////////////////////////////////////////////////////////////////////

@ -0,0 +1,95 @@
//
// Copyright © 2020 Thomas A. Early, N7TAE
//
// ----------------------------------------------------------------------------
//
// m17ref 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.
//
// m17ref 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
// with this software. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#include <arpa/inet.h>
#include "M17Packet.h"
CM17Packet::CM17Packet(const uint8_t *buf)
{
memcpy(m17.magic, buf, sizeof(SM17Frame));
destination.CodeIn(m17.lich.addr_dst);
source.CodeIn(m17.lich.addr_src);
}
const CCallsign &CM17Packet::GetDestCallsign() const
{
return destination;
}
const CCallsign &CM17Packet::GetSourceCallsign() const
{
return source;
}
char CM17Packet::GetDestModule() const
{
return destination.GetModule();
}
uint16_t CM17Packet::GetFrameNumber() const
{
return ntohs(m17.framenumber);
}
uint16_t CM17Packet::GetFrameType() const
{
return ntohs(m17.lich.frametype);
}
const uint8_t *CM17Packet::GetPayload() const
{
return m17.payload;
}
const uint8_t *CM17Packet::GetNonce() const
{
return m17.lich.nonce;
}
void CM17Packet::SetPayload(const uint8_t *newpayload)
{
memcpy(m17.payload, newpayload, 16);
}
uint16_t CM17Packet::GetStreamId() const
{
return ntohs(m17.streamid);
}
uint16_t CM17Packet::GetCRC() const
{
return ntohs(m17.crc);
}
void CM17Packet::SetCRC(uint16_t crc)
{
m17.crc = htons(crc);
}
std::unique_ptr<CM17Packet> CM17Packet::Duplicate(void) const
{
return std::unique_ptr<CM17Packet>(new CM17Packet(*this));
}
bool CM17Packet::IsLastPacket() const
{
return ((0x8000u & ntohs(m17.framenumber)) == 0x8000u);
}

@ -0,0 +1,78 @@
//
// Copyright © 2020 Thomas A. Early, N7TAE
//
// ----------------------------------------------------------------------------
//
// m17ref 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.
//
// m17ref 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
// with this software. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#pragma once
#include <cstdint>
#include <string.h>
#include <memory>
#include "Callsign.h"
////////////////////////////////////////////////////////////////////////////////////////
// aliases
// M17 Packets
//all structures must be big endian on the wire, so you'll want htonl (man byteorder 3) and such.
using SM17Lich = struct __attribute__((__packed__)) lich_tag {
uint8_t addr_dst[6];
uint8_t addr_src[6];
uint16_t frametype; //frametype flag field per the M17 spec
uint8_t nonce[14]; //bytes for the nonce
}; // 6 + 6 + 2 + 14 = 28 bytes
//without SYNC or other parts
using SM17Frame = struct __attribute__((__packed__)) m17_tag {
uint8_t magic[4];
uint16_t streamid;
SM17Lich lich;
uint16_t framenumber;
uint8_t payload[16];
uint16_t crc; //16 bit CRC
}; // 4 + 2 + 28 + 2 + 16 + 2 = 54 bytes
using SLinkPacket = struct __attribute__((__packed__)) link_tag {
uint8_t magic[4];
uint8_t fromcs[6];
uint8_t mod;
}; // 37 bytes
class CM17Packet
{
public:
CM17Packet() {}
CM17Packet(const uint8_t *buf);
const CCallsign &GetDestCallsign() const;
const CCallsign &GetSourceCallsign() const;
char GetDestModule() const;
uint16_t GetFrameNumber() const;
uint16_t GetFrameType() const;
const uint8_t *GetPayload() const;
const uint8_t *GetNonce() const;
void SetPayload(const uint8_t *newpayload);
uint16_t GetStreamId() const;
uint16_t GetCRC() const;
void SetCRC(uint16_t crc);
std::unique_ptr<CM17Packet> Duplicate(void) const;
bool IsLastPacket() const;
private:
CCallsign destination, source;
SM17Frame m17;
};

@ -0,0 +1,434 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// ulxd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "M17Client.h"
#include "M17Protocol.h"
#include "M17Packet.h"
#include "Reflector.h"
#include "GateKeeper.h"
////////////////////////////////////////////////////////////////////////////////////////
// operation
bool CM17Protocol::Initialize(const char *type, const EProtocol ptype, const uint16_t port, const bool has_ipv4, const bool has_ipv6)
{
// base class
if (! CProtocol::Initialize(type, ptype, port, has_ipv4, has_ipv6))
return false;
// update time
m_LastKeepaliveTime.start();
// done
return true;
}
////////////////////////////////////////////////////////////////////////////////////////
// task
void CM17Protocol::Task(void)
{
CBuffer Buffer;
CIp Ip;
CCallsign Callsign;
char ToLinkModule;
std::unique_ptr<CDvHeaderPacket> Header;
std::unique_ptr<CDvFramePacket> Frame;
// handle incoming packets
#if DSTAR_IPV6==true
#if DSTAR_IPV4==true
if ( ReceiveDS(Buffer, Ip, 20) )
#else
if ( Receive6(Buffer, Ip, 20) )
#endif
#else
if ( Receive4(Buffer, Ip, 20) )
#endif
{
// crack the packet
if ( IsValidDvPacket(Buffer, Header, Frame) )
{
// callsign muted?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::m17, Header->GetRpt2Module()) )
{
OnDvHeaderPacketIn(Header, Ip);
if ( !Frame->IsLastPacket() )
{
//std::cout << "M17 DV frame" << std::endl;
OnDvFramePacketIn(Frame, &Ip);
}
else
{
//std::cout << "M17 DV last frame" << std::endl;
OnDvLastFramePacketIn((std::unique_ptr<CDvLastFramePacket> &)Frame, &Ip);
}
}
}
else if ( IsValidConnectPacket(Buffer, Callsign, ToLinkModule) )
{
std::cout << "M17 connect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl;
// callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::m17) && g_Reflector.IsValidModule(ToLinkModule) )
{
// valid module ?
if ( g_Reflector.IsValidModule(ToLinkModule) )
{
// acknowledge the request
Buffer.Set("ACKN");
Send(Buffer, Ip);
// create the client and append
g_Reflector.GetClients()->AddClient(std::make_shared<CM17Client>(Callsign, Ip, ToLinkModule));
g_Reflector.ReleaseClients();
}
else
{
std::cout << "M17 node " << Callsign << " connect attempt on non-existing module" << std::endl;
// deny the request
Buffer.Set("NACK");
Send(Buffer, Ip);
}
}
else
{
// deny the request
Buffer.Set("NACK");
Send(Buffer, Ip);
}
}
else if ( IsValidDisconnectPacket(Buffer, Callsign) )
{
std::cout << "M17 disconnect packet from " << Callsign << " at " << Ip << std::endl;
// find client
CClients *clients = g_Reflector.GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::m17);
if ( client != nullptr )
{
// remove it
clients->RemoveClient(client);
// and acknowledge the disconnect
Buffer.Set("DISC");
Send(Buffer, Ip);
}
g_Reflector.ReleaseClients();
}
else if ( IsValidKeepAlivePacket(Buffer, Callsign) )
{
//std::cout << "M17 keepalive packet from " << Callsign << " at " << Ip << std::endl;
// find all clients with that callsign & ip and keep them alive
CClients *clients = g_Reflector.GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(Callsign, Ip, EProtocol::m17, it)) != nullptr )
{
client->Alive();
}
g_Reflector.ReleaseClients();
}
else
{
// invalid packet
std::string title("Unknown M17 packet from ");
title += Ip.GetAddress();
Buffer.Dump(title);
}
}
// handle end of streaming timeout
CheckStreamsTimeout();
// handle queue from reflector
HandleQueue();
// keep client alive
if ( m_LastKeepaliveTime.time() > M17_KEEPALIVE_PERIOD )
{
//
HandleKeepalives();
// update time
m_LastKeepaliveTime.start();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// streams helpers
void CM17Protocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header, const CIp &Ip)
{
// find the stream
auto stream = GetStream(Header->GetStreamId());
if ( stream )
{
// stream already open
// skip packet, but tickle the stream
stream->Tickle();
}
else
{
// no stream open yet, open a new one
CCallsign my(Header->GetMyCallsign());
CCallsign rpt1(Header->GetRpt1Callsign());
CCallsign rpt2(Header->GetRpt2Callsign());
// find this client
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, EProtocol::m17);
if ( client )
{
// get client callsign
rpt1 = client->GetCallsign();
// and try to open the stream
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
{
// keep the handle
m_Streams.push_back(stream);
}
}
// release
g_Reflector.ReleaseClients();
// update last heard
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// queue helper
void CM17Protocol::HandleQueue(void)
{
m_Queue.Lock();
while ( !m_Queue.empty() )
{
// get the packet
auto packet = m_Queue.pop();
// get our sender's id
const auto module = packet->GetModule();
// check if it's header and update cache
if ( packet->IsDvHeader() )
{
// this relies on queue feeder setting valid module id
// m_StreamsCache[module] will be created if it doesn't exist
m_StreamsCache[module].m_dvHeader = CDvHeaderPacket((const CDvHeaderPacket &)*packet.get());
m_StreamsCache[module].m_iSeqCounter = 0;
}
else
{
// encode it
SM17Frame frame;
memcpy(frame.magic, "M17 ", 4);
if ( packet->IsLastPacket() )
{
EncodeDvLastPacket(frame, m_StreamsCache[module].m_dvHeader, (const CDvFramePacket &)*packet.get(), m_StreamsCache[module].m_iSeqCounter++);
}
else if ( packet->IsDvFrame() )
{
EncodeDvPacket(frame, m_StreamsCache[module].m_dvHeader, (const CDvFramePacket &)*packet.get(), m_StreamsCache[module].m_iSeqCounter++);
}
// push it to all our clients linked to the module and who are not streaming in
CClients *clients = g_Reflector.GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::m17, it)) != nullptr )
{
// is this client busy ?
if ( !client->IsAMaster() && (client->GetReflectorModule() == module) )
{
CBuffer Buffer(frame.magic, sizeof(SM17Frame));
// no, send the packet
Send(Buffer, client->GetIp());
}
}
g_Reflector.ReleaseClients();
}
}
m_Queue.Unlock();
}
////////////////////////////////////////////////////////////////////////////////////////
// keepalive helpers
void CM17Protocol::HandleKeepalives(void)
{
// M17 protocol sends and monitors keepalives packets
// event if the client is currently streaming
// so, send keepalives to all
CBuffer keepalive;
EncodeKeepAlivePacket(keepalive);
// iterate on clients
CClients *clients = g_Reflector.GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::m17, it)) != nullptr )
{
// send keepalive
Send(keepalive, client->GetIp());
// is this client busy ?
if ( client->IsAMaster() )
{
// yes, just tickle it
client->Alive();
}
// check it's still with us
else if ( !client->IsAlive() )
{
// no, disconnect
CBuffer disconnect;
disconnect.Set("DISC");
Send(disconnect, client->GetIp());
// remove it
std::cout << "M17 client " << client->GetCallsign() << " keepalive timeout" << std::endl;
clients->RemoveClient(client);
}
}
g_Reflector.ReleaseClients();
}
////////////////////////////////////////////////////////////////////////////////////////
// packet decoding helpers
bool CM17Protocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign &callsign, char &mod)
{
uint8_t tag[] = { 'C', 'O', 'N', 'N' };
bool valid = false;
if (11 == Buffer.size() && 0 == Buffer.Compare(tag, 4))
{
callsign.CodeIn(Buffer.data() + 4);
mod = Buffer.data()[10];
valid = (callsign.IsValid() && IsLetter(mod));
}
return valid;
}
bool CM17Protocol::IsValidDisconnectPacket(const CBuffer &Buffer, CCallsign &callsign)
{
uint8_t tag[] = { 'D', 'I', 'S', 'C' };
bool valid = false;
if ((Buffer.size() == 10) && (0 == Buffer.Compare(tag, 4)))
{
callsign.CodeIn(Buffer.data() + 4);
valid = callsign.IsValid();
}
return valid;
}
bool CM17Protocol::IsValidKeepAlivePacket(const CBuffer &Buffer, CCallsign &callsign)
{
uint8_t tag[] = { 'P', 'O', 'N', 'G' };
bool valid = false;
if ( (Buffer.size() == 10) || (0 == Buffer.Compare(tag, 4)) )
{
callsign.CodeIn(Buffer.data() + 4);
valid = callsign.IsValid();
}
return valid;
}
bool CM17Protocol::IsValidDvPacket(const CBuffer &Buffer, std::unique_ptr<CDvHeaderPacket> &header, std::unique_ptr<CDvFramePacket> &frame)
{
uint8_t tag[] = { 'M', '1', '7', ' ' };
if ( (Buffer.size() == sizeof(SM17Frame)) && (0 == Buffer.Compare(tag, sizeof(tag))) && (0x4U == (0x1CU & Buffer[13])) )
// Buffer[13] is the lsb byte of the frametype. 0x4 means payload contains Codec2 voice data and there is no encryption.
// the 0x1CU mask just lets us see the encryptions bytes (must be zero) and the msb of the payload type (must be set)
{
// Make the M17 header
CM17Packet m17(Buffer.data());
// get the header
header = std::unique_ptr<CDvHeaderPacket>(new CDvHeaderPacket(m17));
// get the frame
if (m17.IsLastPacket())
{
// it's the last frame
frame = std::unique_ptr<CDvLastFramePacket>(new CDvLastFramePacket(m17));
}
else
{
// it's a regular DV frame
frame = std::unique_ptr<CDvFramePacket>(new CDvFramePacket(m17));
}
// check validity of packets
if ( header && header->IsValid() && frame && frame->IsValid() )
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////
// packet encoding helpers
void CM17Protocol::EncodeKeepAlivePacket(CBuffer &Buffer)
{
Buffer.resize(10);
memcpy(Buffer.data(), "PING", 4);
g_Reflector.GetCallsign().CodeOut(Buffer.data() + 4);
}
void CM17Protocol::EncodeDvPacket(SM17Frame &frame, const CDvHeaderPacket &Header, const CDvFramePacket &DvFrame, uint32_t iSeq) const
{
ECodecType codec_in = Header.GetCodecIn(); // We'll need this
// do the lich structure first
// first, the dest and src callsigns
Header.GetRpt2Callsign().CodeOut(frame.lich.addr_dst);
CCallsign from = g_Reflector.GetCallsign();
from.SetModule(Header.GetModule());
from.CodeOut(frame.lich.addr_src);
// then the frame type, if the incoming frame is NOT an M17 1600, then it will be Voice only
frame.lich.frametype = htons((ECodecType::c2_1600==codec_in) ? 0x7U : 0x5U);
memcpy(frame.lich.nonce, DvFrame.GetNonce(), 14);
// now the main part of the packet
memcpy(frame.magic, "M17 ", 4);
// the frame number comes from the stream sequence counter
frame.framenumber = htons(iSeq % 0x8000U);
memcpy(frame.payload, DvFrame.GetCodecData(codec_in), 16);
frame.streamid = Header.GetStreamId(); // no host<--->network byte swapping since we never do any math on this value
// finally, calcualte the m17 CRC value and load it
frame.crc = htons(m17crc.CalcCRC(frame.magic, sizeof(SM17Frame)-2));
}
void CM17Protocol::EncodeDvLastPacket(SM17Frame &frame, const CDvHeaderPacket &Header, const CDvFramePacket &DvFrame, uint32_t iSeq) const
{
EncodeDvPacket(frame, Header, DvFrame, iSeq);
frame.framenumber |= 0x8000U;
}

@ -0,0 +1,82 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// ulxd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "Timer.h"
#include "Protocol.h"
#include "DVHeaderPacket.h"
#include "DVFramePacket.h"
#include "DVLastFramePacket.h"
#include "M17CRC.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
////////////////////////////////////////////////////////////////////////////////////////
// class
class CM17StreamCacheItem
{
public:
CM17StreamCacheItem() : m_iSeqCounter(0) {}
CDvHeaderPacket m_dvHeader;
uint32_t m_iSeqCounter;
};
class CM17Protocol : public CProtocol
{
public:
// initialization
bool Initialize(const char *type, const EProtocol ptype, const uint16_t port, const bool has_ipv4, const bool has_ipv6);
// task
void Task(void);
protected:
// queue helper
void HandleQueue(void);
// keepalive helpers
void HandleKeepalives(void);
// stream helpers
void OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &, const CIp &);
// packet decoding helpers
bool IsValidConnectPacket(const CBuffer &, CCallsign &, char &);
bool IsValidDisconnectPacket(const CBuffer &, CCallsign &);
bool IsValidKeepAlivePacket(const CBuffer &, CCallsign &);
bool IsValidDvPacket(const CBuffer &, std::unique_ptr<CDvHeaderPacket> &, std::unique_ptr<CDvFramePacket> &);
// packet encoding helpers
void EncodeKeepAlivePacket(CBuffer &);
void EncodeDvPacket(SM17Frame &, const CDvHeaderPacket &, const CDvFramePacket &, uint32_t) const;
void EncodeDvLastPacket(SM17Frame &, const CDvHeaderPacket &, const CDvFramePacket &, uint32_t) const;
protected:
// for keep alive
CTimer m_LastKeepaliveTime;
// for queue header caches
std::unordered_map<char, CM17StreamCacheItem> m_StreamsCache;
private:
CM17CRC m17crc;
};

@ -73,9 +73,9 @@
// protocols --------------------------------------------------- // protocols ---------------------------------------------------
#ifndef NO_G3 #ifndef NO_G3
enum class EProtocol { any, none, dextra, dplus, dcs, ulx, dmrplus, dmrmmdvm, ysf, g3 }; enum class EProtocol { any, none, dextra, dplus, dcs, ulx, dmrplus, dmrmmdvm, ysf, m17, g3 };
#else #else
enum class EProtocol { any, none, dextra, dplus, dcs, xlx, dmrplus, dmrmmdvm, ysf }; enum class EProtocol { any, none, dextra, dplus, dcs, xlx, dmrplus, dmrmmdvm, ysf, m17 };
#endif #endif
// DExtra // DExtra
@ -124,6 +124,12 @@ enum class EProtocol { any, none, dextra, dplus, dcs, xlx, dmrplus, dmrmmdvm, ys
// #define YSF_AUTOLINK_ENABLE 0 // 1 = enable, 0 = disable auto-link // #define YSF_AUTOLINK_ENABLE 0 // 1 = enable, 0 = disable auto-link
// #define YSF_AUTOLINK_MODULE 'B' // module for client to auto-link to // #define YSF_AUTOLINK_MODULE 'B' // module for client to auto-link to
// M17
#define M17_PORT 17000
#define M17_KEEPALIVE_PERIOD 3
#define M17_KEEPALIVE_TIMEOUT (M17_KEEPALIVE_PERIOD*10)
#define M17_RECONNECT_PERIOD 5
#ifndef NO_G3 #ifndef NO_G3
// G3 Terminal // G3 Terminal
#define G3_PRESENCE_PORT 12346 // UDP port #define G3_PRESENCE_PORT 12346 // UDP port
@ -133,21 +139,14 @@ enum class EProtocol { any, none, dextra, dplus, dcs, xlx, dmrplus, dmrmmdvm, ys
#define G3_KEEPALIVE_TIMEOUT 3600 // in seconds, 1 hour #define G3_KEEPALIVE_TIMEOUT 3600 // in seconds, 1 hour
#endif #endif
#ifdef TRANSCODER_IP
// Transcoder server -------------------------------------------- // Transcoder server --------------------------------------------
#ifdef TRANSCODER_IP
#define TRANSCODER_PORT 10100 // UDP port #define TRANSCODER_PORT 10100 // UDP port
#endif
#define TRANSCODER_KEEPALIVE_PERIOD 5 // in seconds #define TRANSCODER_KEEPALIVE_PERIOD 5 // in seconds
#define TRANSCODER_KEEPALIVE_TIMEOUT 30 // in seconds #define TRANSCODER_KEEPALIVE_TIMEOUT 30 // in seconds
#define TRANSCODER_AMBEPACKET_TIMEOUT 400 // in ms #define TRANSCODER_AMBEPACKET_TIMEOUT 400 // in ms
#endif
// codec --------------------------------------------------------
#define CODEC_NONE 0
#define CODEC_AMBEPLUS 1 // DStar
#define CODEC_AMBE2PLUS 2 // DMR
// DMRid database ----------------------------------------------- // DMRid database -----------------------------------------------

@ -47,8 +47,8 @@ ifeq ($(ysf_db), true)
LDFLAGS += `mysql_config --libs` LDFLAGS += `mysql_config --libs`
endif endif
ifdef tc_ip ifdef need_tc
SRCS += Transcoder.cpp CodecStream.cpp SRCS += CodecStream.cpp
endif endif
ifeq ($(use_g3), true) ifeq ($(use_g3), true)

@ -19,6 +19,11 @@
#include "Main.h" #include "Main.h"
#include "Packet.h" #include "Packet.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CPacket::CPacket() CPacket::CPacket()
{ {
m_uiStreamId = 0; m_uiStreamId = 0;
@ -28,8 +33,10 @@ CPacket::CPacket()
m_uiYsfPacketId = 0; m_uiYsfPacketId = 0;
m_uiYsfPacketSubId = 0; m_uiYsfPacketSubId = 0;
m_uiYsfPacketFrameId = 0; m_uiYsfPacketFrameId = 0;
m_uiM17FrameNumber = 0;
m_cModule = ' '; m_cModule = ' ';
m_uiOriginId = ORIGIN_LOCAL; m_uiOriginId = ORIGIN_LOCAL;
m_eCodecIn = ECodecType::none;
}; };
// dstar contrsuctor // dstar contrsuctor
@ -43,8 +50,10 @@ CPacket::CPacket(uint16_t sid, uint8_t dstarpid)
m_uiYsfPacketId = 0xFF; m_uiYsfPacketId = 0xFF;
m_uiYsfPacketSubId = 0xFF; m_uiYsfPacketSubId = 0xFF;
m_uiYsfPacketFrameId = 0xFF; m_uiYsfPacketFrameId = 0xFF;
m_uiM17FrameNumber = 0x8000U;
m_cModule = ' '; m_cModule = ' ';
m_uiOriginId = ORIGIN_LOCAL; m_uiOriginId = ORIGIN_LOCAL;
m_eCodecIn = ECodecType::dstar;
}; };
// dmr constructor // dmr constructor
@ -58,8 +67,10 @@ CPacket::CPacket(uint16_t sid, uint8_t dmrpid, uint8_t dmrspid)
m_uiYsfPacketId = 0xFF; m_uiYsfPacketId = 0xFF;
m_uiYsfPacketSubId = 0xFF; m_uiYsfPacketSubId = 0xFF;
m_uiYsfPacketFrameId = 0xFF; m_uiYsfPacketFrameId = 0xFF;
m_uiM17FrameNumber = 0x8000U;
m_cModule = ' '; m_cModule = ' ';
m_uiOriginId = ORIGIN_LOCAL; m_uiOriginId = ORIGIN_LOCAL;
m_eCodecIn = ECodecType::dmr;
}; };
// ysf constructor // ysf constructor
@ -73,13 +84,15 @@ CPacket::CPacket(uint16_t sid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysffri
m_uiDstarPacketId = 0xFF; m_uiDstarPacketId = 0xFF;
m_uiDmrPacketId = 0xFF; m_uiDmrPacketId = 0xFF;
m_uiDmrPacketSubid = 0xFF; m_uiDmrPacketSubid = 0xFF;
m_uiM17FrameNumber = 0x8000U;
m_cModule = ' '; m_cModule = ' ';
m_uiOriginId = ORIGIN_LOCAL; m_uiOriginId = ORIGIN_LOCAL;
m_eCodecIn = ECodecType::dmr;
} }
// xlx constructor // xlx constructor
CPacket::CPacket(uint16_t sid, uint8_t dstarpid, uint8_t dmrpid, uint8_t dmrsubpid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysffrid) CPacket::CPacket(uint16_t sid, uint8_t dstarpid, uint8_t dmrpid, uint8_t dmrsubpid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysffrid, ECodecType codecIn)
{ {
m_uiStreamId = sid; m_uiStreamId = sid;
m_uiDstarPacketId = dstarpid; m_uiDstarPacketId = dstarpid;
@ -88,8 +101,25 @@ CPacket::CPacket(uint16_t sid, uint8_t dstarpid, uint8_t dmrpid, uint8_t dmrsubp
m_uiYsfPacketId = ysfpid; m_uiYsfPacketId = ysfpid;
m_uiYsfPacketSubId = ysfsubpid; m_uiYsfPacketSubId = ysfsubpid;
m_uiYsfPacketFrameId = ysffrid; m_uiYsfPacketFrameId = ysffrid;
m_uiM17FrameNumber = 0x8000U;
m_cModule = ' '; m_cModule = ' ';
m_uiOriginId = ORIGIN_LOCAL; m_uiOriginId = ORIGIN_LOCAL;
m_eCodecIn = codecIn;
}
// m17 constructor
CPacket::CPacket(const CM17Packet &m17) : CPacket()
{
m_uiStreamId = m17.GetStreamId();
m_uiDstarPacketId = 0xFF;
m_uiDmrPacketId = 0xFF;
m_uiDmrPacketSubid = 0xFF;
m_uiYsfPacketId = 0xFF;
m_uiYsfPacketSubId = 0xFF;
m_uiYsfPacketFrameId = 0xFF;
m_eCodecIn = (0x6U == (0x6U & m17.GetFrameType())) ? ECodecType::c2_1600 : ECodecType::c2_3200;
m_uiM17FrameNumber = 0x7FFFU & m17.GetFrameNumber();
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -97,9 +127,9 @@ CPacket::CPacket(uint16_t sid, uint8_t dstarpid, uint8_t dmrpid, uint8_t dmrsubp
void CPacket::UpdatePids(uint32_t pid) void CPacket::UpdatePids(uint32_t pid)
{ {
// called while phusing this packet in a stream queue // called while pushing this packet in a stream queue
// so now packet sequence number is known and undefined pids can be updated // so now packet sequence number is known and undefined pids can be updated
// this is needed as dtsar & dmt pids are different and cannot be // this is needed as dtsar & dmr pids are different and cannot be
// derived from each other // derived from each other
// dstar pid needs update ? // dstar pid needs update ?
@ -120,4 +150,9 @@ void CPacket::UpdatePids(uint32_t pid)
m_uiYsfPacketSubId = pid % 5; m_uiYsfPacketSubId = pid % 5;
m_uiYsfPacketFrameId = ((pid / 5) & 0x7FU) << 1; m_uiYsfPacketFrameId = ((pid / 5) & 0x7FU) << 1;
} }
// m17 needs update?
if (m_uiM17FrameNumber == 0x8000U)
{
m_uiM17FrameNumber = pid % 0x7FFFU;
}
} }

@ -1,5 +1,7 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. #pragma once
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ulxd -- The universal reflector // ulxd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE // Copyright © 2021 Thomas A. Early N7TAE
// //
@ -16,17 +18,14 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
////////////////////////////////////////////////////////////////////////////////////////
// Origin Id // Origin Id
enum class ECodecType { none, dstar, dmr, c2_1600, c2_3200 };
#define ORIGIN_LOCAL 0 #define ORIGIN_LOCAL 0
#define ORIGIN_PEER 1 #define ORIGIN_PEER 1
//////////////////////////////////////////////////////////////////////////////////////// #include "M17Packet.h"
// class
class CPacket class CPacket
{ {
@ -36,7 +35,8 @@ public:
CPacket(uint16_t sid, uint8_t dstarpid); CPacket(uint16_t sid, uint8_t dstarpid);
CPacket(uint16_t sid, uint8_t dmrpid, uint8_t dmrsubpid); CPacket(uint16_t sid, uint8_t dmrpid, uint8_t dmrsubpid);
CPacket(uint16_t sid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysfsubpidmax); CPacket(uint16_t sid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysfsubpidmax);
CPacket(uint16_t sid, uint8_t dstarpid, uint8_t dmrpid, uint8_t dmrsubpid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysfsubpidmax); CPacket(uint16_t sid, uint8_t dstarpid, uint8_t dmrpid, uint8_t dmrsubpid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysfsubpidmax, ECodecType);
CPacket(const CM17Packet &);
// destructor // destructor
virtual ~CPacket() {} virtual ~CPacket() {}
@ -53,6 +53,7 @@ public:
// get // get
virtual bool IsValid(void) const { return true; } virtual bool IsValid(void) const { return true; }
uint16_t GetStreamId(void) const { return m_uiStreamId; } uint16_t GetStreamId(void) const { return m_uiStreamId; }
uint16_t M17FrameNumber(void) const { return m_uiM17FrameNumber; }
uint8_t GetPacketId(void) const { return m_uiDstarPacketId; } uint8_t GetPacketId(void) const { return m_uiDstarPacketId; }
uint8_t GetDstarPacketId(void) const { return m_uiDstarPacketId; } uint8_t GetDstarPacketId(void) const { return m_uiDstarPacketId; }
uint8_t GetDmrPacketId(void) const { return m_uiDmrPacketId; } uint8_t GetDmrPacketId(void) const { return m_uiDmrPacketId; }
@ -62,16 +63,18 @@ public:
uint8_t GetYsfPacketFrameId(void) const { return m_uiYsfPacketFrameId; } uint8_t GetYsfPacketFrameId(void) const { return m_uiYsfPacketFrameId; }
char GetModule(void) const { return m_cModule; } char GetModule(void) const { return m_cModule; }
bool IsLocalOrigin(void) const { return (m_uiOriginId == ORIGIN_LOCAL); } bool IsLocalOrigin(void) const { return (m_uiOriginId == ORIGIN_LOCAL); }
ECodecType GetCodecIn(void) const { return m_eCodecIn; }
// set // set
void UpdatePids(uint32_t); void UpdatePids(uint32_t);
void SetModule(char c) { m_cModule = c; } void SetModule(char cMod) { m_cModule = cMod; }
void SetLocalOrigin(void) { m_uiOriginId = ORIGIN_LOCAL; } void SetLocalOrigin(void) { m_uiOriginId = ORIGIN_LOCAL; }
void SetRemotePeerOrigin(void) { m_uiOriginId = ORIGIN_PEER; } void SetRemotePeerOrigin(void) { m_uiOriginId = ORIGIN_PEER; }
protected: protected:
// data // data
uint16_t m_uiStreamId; uint16_t m_uiStreamId;
uint16_t m_uiM17FrameNumber;
uint8_t m_uiDstarPacketId; uint8_t m_uiDstarPacketId;
uint8_t m_uiDmrPacketId; uint8_t m_uiDmrPacketId;
uint8_t m_uiDmrPacketSubid; uint8_t m_uiDmrPacketSubid;
@ -80,4 +83,5 @@ protected:
uint8_t m_uiYsfPacketFrameId; uint8_t m_uiYsfPacketFrameId;
char m_cModule; char m_cModule;
uint8_t m_uiOriginId; uint8_t m_uiOriginId;
ECodecType m_eCodecIn;
}; };

@ -28,7 +28,7 @@
CPeer::CPeer() CPeer::CPeer()
{ {
::memset(m_ReflectorModules, 0, sizeof(m_ReflectorModules)); memset(m_ReflectorModules, 0, sizeof(m_ReflectorModules));
m_ConnectTime = std::time(nullptr); m_ConnectTime = std::time(nullptr);
m_LastHeardTime = std::time(nullptr); m_LastHeardTime = std::time(nullptr);
} }
@ -37,7 +37,7 @@ CPeer::CPeer(const CCallsign &callsign, const CIp &ip, const char *modules, cons
{ {
m_Callsign = callsign; m_Callsign = callsign;
m_Ip = ip; m_Ip = ip;
::memset(m_ReflectorModules, 0, sizeof(m_ReflectorModules)); memset(m_ReflectorModules, 0, sizeof(m_ReflectorModules));
::strncpy(m_ReflectorModules, modules, sizeof(m_ReflectorModules)-1); ::strncpy(m_ReflectorModules, modules, sizeof(m_ReflectorModules)-1);
m_Version = version; m_Version = version;
m_LastKeepaliveTime.start(); m_LastKeepaliveTime.start();

@ -638,13 +638,13 @@ bool CURFProtocol::EncodeDvFramePacket(const CDvFramePacket &Packet, CBuffer *Bu
Buffer->Set(tag, sizeof(tag)); Buffer->Set(tag, sizeof(tag));
Buffer->Append(Packet.GetStreamId()); Buffer->Append(Packet.GetStreamId());
Buffer->Append((uint8_t)(Packet.GetDstarPacketId() % 21)); Buffer->Append((uint8_t)(Packet.GetDstarPacketId() % 21));
Buffer->Append((uint8_t *)Packet.GetAmbe(), AMBE_SIZE); Buffer->Append((uint8_t *)Packet.GetAmbe(), 9);
Buffer->Append((uint8_t *)Packet.GetDvData(), DVDATA_SIZE); Buffer->Append((uint8_t *)Packet.GetDvData(), 3);
Buffer->Append((uint8_t)Packet.GetDmrPacketId()); Buffer->Append((uint8_t)Packet.GetDmrPacketId());
Buffer->Append((uint8_t)Packet.GetDmrPacketSubid()); Buffer->Append((uint8_t)Packet.GetDmrPacketSubid());
Buffer->Append((uint8_t *)Packet.GetAmbePlus(), AMBEPLUS_SIZE); Buffer->Append((uint8_t *)Packet.GetAmbePlus(), 9);
Buffer->Append((uint8_t *)Packet.GetDvSync(), DVSYNC_SIZE); Buffer->Append((uint8_t *)Packet.GetDvSync(), 7);
return true; return true;
@ -665,8 +665,8 @@ bool CURFProtocol::EncodeDvLastFramePacket(const CDvLastFramePacket &Packet, CBu
Buffer->Append((uint8_t)Packet.GetDmrPacketId()); Buffer->Append((uint8_t)Packet.GetDmrPacketId());
Buffer->Append((uint8_t)Packet.GetDmrPacketSubid()); Buffer->Append((uint8_t)Packet.GetDmrPacketSubid());
Buffer->Append((uint8_t *)Packet.GetAmbePlus(), AMBEPLUS_SIZE); Buffer->Append((uint8_t *)Packet.GetAmbePlus(), 9);
Buffer->Append((uint8_t *)Packet.GetDvSync(), DVSYNC_SIZE); Buffer->Append((uint8_t *)Packet.GetDvSync(), 7);
return true; return true;
} }

@ -0,0 +1,207 @@
/*
* Copyright (C) 2020 by Thomas Early N7TAE
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <unistd.h>
#include <sys/un.h>
#include <sys/socket.h>
#include "UnixPacketSock.h"
CUnixPacket::CUnixPacket() : m_fd(-1), m_host(NULL) {}
ssize_t CUnixPacket::Read(void *buffer, const ssize_t size)
{
if (0 > m_fd)
return -1;
ssize_t len = read(m_fd, buffer, size);
if (len < 1)
{
if (-1 == len)
{
std::cerr << "Read error on '" << m_name << "': " << strerror(errno) << std::endl;
}
else if (0 == len)
{
std::cerr << "Read error on '" << m_name << "': EOF" << std::endl;
}
if (Restart())
return -1;
else
return 0;
}
return len;
}
bool CUnixPacket::Write(const void *buffer, const ssize_t size)
{
if (0 > m_fd)
return true;
ssize_t written = write(m_fd, buffer, size);
if (written != size)
{
if (-1 == written)
{
std::cerr << "Write error on '" << m_name << "': " << strerror(errno) << std::endl;
}
else
{
std::cout << "Write error on '" << m_name << "': Only wrote " << written << " of " << size << " bytes" << std::endl;
}
return Restart();
}
return false;
}
bool CUnixPacket::Restart()
{
if (! m_host->IsRunning())
return true;
std::cout << "Restarting '" << m_name << "'... " << std::endl;
Close();
std::string name(m_name);
return Open(name.c_str(), m_host);
}
int CUnixPacket::GetFD()
{
return m_fd;
}
CUnixPacketServer::CUnixPacketServer() : m_server(-1) {}
CUnixPacketServer::~CUnixPacketServer()
{
Close();
}
bool CUnixPacketServer::Open(const char *name, CKRBase *host)
{
m_server = socket(AF_UNIX, SOCK_SEQPACKET, 0);
m_host = host;
if (m_server < 0)
{
std::cerr << "Cannot open '" << name << "' socket: " << strerror(errno) << std::endl;
return true;
}
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
memcpy(addr.sun_path+1, name, strlen(name));
if (-1 == bind(m_server, (struct sockaddr *)&addr, sizeof(addr)))
{
std::cerr << "Cannot bind '" << name << "' socket: " << strerror(errno) << std::endl;
Close();
return true;
}
if (-1 == listen(m_server, 1))
{
std::cerr << "Cannot listen on '" << name << "' socket: " << strerror(errno) << std::endl;
Close();
return true;
}
m_fd = accept(m_server, nullptr, 0);
if (m_fd < 0)
{
std::cerr << "Cannot accept on '" << name << "' socket: " << strerror(errno) << std::endl;
Close();
return true;
}
strncpy(m_name, name, 108);
return false;
}
void CUnixPacketServer::Close()
{
if (m_server >= 0)
{
close(m_server);
m_server = -1;
}
if (m_fd >= 0)
{
close(m_fd);
m_fd = -1;
}
}
CUnixPacketClient::~CUnixPacketClient()
{
Close();
}
bool CUnixPacketClient::Open(const char *name, CKRBase *host)
{
m_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (m_fd < 0)
{
std::cerr << "Cannot open unix client socket " << name << std::endl;
return true;
}
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
memcpy(addr.sun_path+1, name, strlen(name));
int rval = -1;
int tries = 0;
while (rval < 0)
{
rval = connect(m_fd, (struct sockaddr *)&addr, sizeof(addr));
if (rval < 0)
{
if (ECONNREFUSED == errno)
{
if (0 == tries++ % 20)
std::cout << "Waiting for " << name << " server to start..." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
else
{
std::cerr << "Cannot connect '" << name << "' socket: " << strerror(errno) << std::endl;
Close();
return true;
}
}
if (! m_host->IsRunning())
{
Close();
return true;
}
}
m_host = host;
strncpy(m_name, name, 108);
return false;
}
void CUnixPacketClient::Close()
{
if (m_fd >= 0)
{
close(m_fd);
m_fd = -1;
}
}

@ -0,0 +1,58 @@
#pragma once
/*
* Copyright (C) 2020 by Thomas Early N7TAE
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <sys/types.h>
#include "KRBase.h"
class CUnixPacket
{
public:
CUnixPacket();
virtual bool Open(const char *name, CKRBase *host) = 0;
virtual void Close() = 0;
bool Write(const void *buffer, const ssize_t size);
ssize_t Read(void *buffer, const ssize_t size);
int GetFD();
protected:
bool Restart();
int m_fd;
CKRBase *m_host;
char m_name[108];
};
class CUnixPacketServer : public CUnixPacket
{
public:
CUnixPacketServer();
~CUnixPacketServer();
bool Open(const char *name, CKRBase *host);
void Close();
protected:
int m_server;
};
class CUnixPacketClient : public CUnixPacket
{
public:
~CUnixPacketClient();
bool Open(const char *name, CKRBase *host);
void Close();
};

@ -238,16 +238,16 @@ bool CWiresxCmdHandler::ReplyToWiresxDxReqPacket(const CIp &Ip, const CWiresxInf
RoomId = (uint8_t)(Module - 'A'); RoomId = (uint8_t)(Module - 'A');
// fill data buffer // fill data buffer
::memset(data, 0x00U, 150U); memset(data, 0x00U, 150U);
::memset(data, ' ', 128U); memset(data, ' ', 128U);
// seq no // seq no
data[0U] = m_seqNo; data[0U] = m_seqNo;
// command // command
::memcpy(data + 1U, DX_RESP, 4U); memcpy(data + 1U, DX_RESP, 4U);
// node info // node info
::memcpy(data + 5U, WiresxInfo.GetId(), 5U); memcpy(data + 5U, WiresxInfo.GetId(), 5U);
::memcpy(data + 10U, WiresxInfo.GetNode(), 10U); memcpy(data + 10U, WiresxInfo.GetNode(), 10U);
::memcpy(data + 20U, WiresxInfo.GetName(), 14U); memcpy(data + 20U, WiresxInfo.GetName(), 14U);
// linked room // linked room
if (!IsLinked) if (!IsLinked)
{ {
@ -266,19 +266,19 @@ bool CWiresxCmdHandler::ReplyToWiresxDxReqPacket(const CIp &Ip, const CWiresxInf
char item[16U]; char item[16U];
// refl->m_id // refl->m_id
::sprintf(item, "%05d", 4001U + RoomId); ::sprintf(item, "%05d", 4001U + RoomId);
::memcpy(data + 36U, item, 5U); memcpy(data + 36U, item, 5U);
// refl->name // refl->name
::memset(item, ' ', 16U); memset(item, ' ', 16U);
::memcpy(item, "MODULE", 6U); // K2IE fix for U/C only radios memcpy(item, "MODULE", 6U); // K2IE fix for U/C only radios
item[7] = 'A' + RoomId; item[7] = 'A' + RoomId;
::memcpy(data + 41U, item, 16U); memcpy(data + 41U, item, 16U);
// refl->count // refl->count
::sprintf(item, "%03d", RoomId + 1); ::sprintf(item, "%03d", RoomId + 1);
::memcpy(data + 57U, item, 3U); memcpy(data + 57U, item, 3U);
// other // other
::memset(data + 60U, ' ', 10U); memset(data + 60U, ' ', 10U);
// refl->m_desc // refl->m_desc
::memcpy(data + 70U, "Description ", 14U); memcpy(data + 70U, "Description ", 14U);
} }
// frequencies // frequencies
@ -301,7 +301,7 @@ bool CWiresxCmdHandler::ReplyToWiresxDxReqPacket(const CIp &Ip, const CWiresxInf
char freq[30U]; char freq[30U];
::sprintf(freq, "%05u.%06u%c%03u.%06u", WiresxInfo.GetTxFrequency() / 1000000U, freqHz, sign, offset / 1000000U, offset % 1000000U); ::sprintf(freq, "%05u.%06u%c%03u.%06u", WiresxInfo.GetTxFrequency() / 1000000U, freqHz, sign, offset / 1000000U, offset % 1000000U);
::memcpy(data + 84U, freq, 23U); memcpy(data + 84U, freq, 23U);
} }
// EOD & CRC // EOD & CRC
@ -325,16 +325,16 @@ bool CWiresxCmdHandler::ReplyToWiresxAllReqPacket(const CIp &Ip, const CWiresxIn
uint8_t data[1100U]; uint8_t data[1100U];
// fill data buffer // fill data buffer
::memset(data, 0x00U, 1100U); memset(data, 0x00U, 1100U);
// seq no // seq no
data[0U] = m_seqNo; data[0U] = m_seqNo;
// command // command
::memcpy(data + 1U, ALL_RESP, 4U); memcpy(data + 1U, ALL_RESP, 4U);
data[5U] = '2'; data[5U] = '2';
data[6U] = '1'; data[6U] = '1';
// node info // node info
::memcpy(data + 7U, WiresxInfo.GetId(), 5U); memcpy(data + 7U, WiresxInfo.GetId(), 5U);
::memcpy(data + 12U, WiresxInfo.GetNode(), 10U); memcpy(data + 12U, WiresxInfo.GetNode(), 10U);
// number of entries // number of entries
const char *modules = ACTIVE_MODULES; const char *modules = ACTIVE_MODULES;
@ -356,24 +356,24 @@ bool CWiresxCmdHandler::ReplyToWiresxAllReqPacket(const CIp &Ip, const CWiresxIn
int RoomId = RoomMod - 'A'; int RoomId = RoomMod - 'A';
// prepare // prepare
::memset(data + offset, ' ', 50U); memset(data + offset, ' ', 50U);
data[offset + 0U] = '5'; data[offset + 0U] = '5';
// refl->m_id // refl->m_id
::sprintf(item, "%05d", 4001U + RoomId); ::sprintf(item, "%05d", 4001U + RoomId);
::memcpy(data + offset + 1U, item, 5U); memcpy(data + offset + 1U, item, 5U);
// refl->name // refl->name
::memset(item, ' ', 16U); memset(item, ' ', 16U);
::memcpy(item, "MODULE", 6U); // K2IE fix for U/C only radios memcpy(item, "MODULE", 6U); // K2IE fix for U/C only radios
item[7] = RoomMod; item[7] = RoomMod;
::memcpy(data + offset + 6U, item, 16U); memcpy(data + offset + 6U, item, 16U);
// refl->count // refl->count
::sprintf(item, "%03d", RoomId + 1); ::sprintf(item, "%03d", RoomId + 1);
::memcpy(data + offset + 22U, item, 3U); memcpy(data + offset + 22U, item, 3U);
// other // other
::memset(data + offset + 25U, ' ', 10U); memset(data + offset + 25U, ' ', 10U);
// refl->m_desc // refl->m_desc
::memcpy(data + offset + 35U, "Description ", 14U); memcpy(data + offset + 35U, "Description ", 14U);
data[offset + 49U] = 0x0DU; data[offset + 49U] = 0x0DU;
// next // next
offset += 50U; offset += 50U;
@ -388,7 +388,7 @@ bool CWiresxCmdHandler::ReplyToWiresxAllReqPacket(const CIp &Ip, const CWiresxIn
uint offset2 = offset; uint offset2 = offset;
// patch the remaining // patch the remaining
uint k = 1029U - offset2; uint k = 1029U - offset2;
::memset(data+offset2, ' ', k); memset(data+offset2, ' ', k);
offset2 += k; offset2 += k;
// EOD + CRC // EOD + CRC
@ -412,7 +412,7 @@ bool CWiresxCmdHandler::ReplyToWiresxAllReqPacket(const CIp &Ip, const CWiresxIn
// patch the remaining // patch the remaining
//uint k = 1031U - offset; //uint k = 1031U - offset;
//::memset(data+offset, ' ', k); //memset(data+offset, ' ', k);
//offset += k; //offset += k;
// and encode the reply // and encode the reply
@ -439,17 +439,17 @@ bool CWiresxCmdHandler::ReplyToWiresxConnReqPacket(const CIp &Ip, const CWiresxI
RoomId = (uint8_t)(Module - 'A'); RoomId = (uint8_t)(Module - 'A');
// prepare buffer // prepare buffer
::memset(data, 0x00U, 110U); memset(data, 0x00U, 110U);
::memset(data, ' ', 90U); memset(data, ' ', 90U);
// seq no // seq no
data[0U] = m_seqNo; data[0U] = m_seqNo;
// command // command
::memcpy(data + 1U, CONN_RESP, 4U); memcpy(data + 1U, CONN_RESP, 4U);
// node info // node info
::memcpy(data + 5U, WiresxInfo.GetId(), 5U); memcpy(data + 5U, WiresxInfo.GetId(), 5U);
::memcpy(data + 10U, WiresxInfo.GetNode(), 10U); memcpy(data + 10U, WiresxInfo.GetNode(), 10U);
::memcpy(data + 20U, WiresxInfo.GetName(), 14U); memcpy(data + 20U, WiresxInfo.GetName(), 14U);
data[34U] = '1'; data[34U] = '1';
data[35U] = '5'; data[35U] = '5';
// entry info // entry info
@ -458,17 +458,17 @@ bool CWiresxCmdHandler::ReplyToWiresxConnReqPacket(const CIp &Ip, const CWiresxI
// refl->m_id // refl->m_id
::sprintf(item, "%05d", 4001U + RoomId); ::sprintf(item, "%05d", 4001U + RoomId);
::memcpy(data + 36U, item, 5U); memcpy(data + 36U, item, 5U);
// refl->name // refl->name
::memset(item, ' ', 16U); memset(item, ' ', 16U);
::memcpy(item, "MODULE", 6U); // K2IE fix for U/C only radios memcpy(item, "MODULE", 6U); // K2IE fix for U/C only radios
item[7] = 'A' + RoomId; item[7] = 'A' + RoomId;
::memcpy(data + 41U, item, 16U); memcpy(data + 41U, item, 16U);
// refl->count // refl->count
::sprintf(item, "%03d", RoomId + 1); ::sprintf(item, "%03d", RoomId + 1);
::memcpy(data + 57U, item, 3U); memcpy(data + 57U, item, 3U);
// refl->m_desc // refl->m_desc
::memcpy(data + 70U, "Description ", 14U); memcpy(data + 70U, "Description ", 14U);
} }
data[84U] = '0'; data[84U] = '0';
data[85U] = '0'; data[85U] = '0';
@ -497,17 +497,17 @@ bool CWiresxCmdHandler::ReplyToWiresxDiscReqPacket(const CIp &Ip, const CWiresxI
uint8_t data[110U]; uint8_t data[110U];
// prepare buffer // prepare buffer
::memset(data, 0x00U, 110U); memset(data, 0x00U, 110U);
::memset(data, ' ', 90U); memset(data, ' ', 90U);
// seq no // seq no
data[0U] = m_seqNo; data[0U] = m_seqNo;
// command // command
::memcpy(data + 1U, DISC_RESP, 4U); memcpy(data + 1U, DISC_RESP, 4U);
// node info // node info
::memcpy(data + 5U, WiresxInfo.GetId(), 5U); memcpy(data + 5U, WiresxInfo.GetId(), 5U);
::memcpy(data + 10U, WiresxInfo.GetNode(), 10U); memcpy(data + 10U, WiresxInfo.GetNode(), 10U);
::memcpy(data + 20U, WiresxInfo.GetName(), 14U); memcpy(data + 20U, WiresxInfo.GetName(), 14U);
// data // data
data[34U] = '1'; data[34U] = '1';
data[35U] = '2'; data[35U] = '2';
@ -580,11 +580,11 @@ bool CWiresxCmdHandler::EncodeAndSendWiresxPacket(const CIp &Ip, const CBuffer &
// Write the header // Write the header
{ {
//header //header
::memcpy(buffer, NET_HEADER, 34U); memcpy(buffer, NET_HEADER, 34U);
::memcpy(buffer + 4U, WiresxInfo.GetCallsign(), 10U); memcpy(buffer + 4U, WiresxInfo.GetCallsign(), 10U);
::memcpy(buffer + 14U, WiresxInfo.GetNode(), 10U); memcpy(buffer + 14U, WiresxInfo.GetNode(), 10U);
// sync // sync
::memcpy(buffer + 35U, YSF_SYNC_BYTES, YSF_SYNC_LENGTH_BYTES); memcpy(buffer + 35U, YSF_SYNC_BYTES, YSF_SYNC_LENGTH_BYTES);
// Fich // Fich
fich.load(DEFAULT_FICH); fich.load(DEFAULT_FICH);
fich.setFI(YSF_FI_HEADER); fich.setFI(YSF_FI_HEADER);
@ -637,7 +637,7 @@ bool CWiresxCmdHandler::EncodeAndSendWiresxPacket(const CIp &Ip, const CBuffer &
{ {
uint8_t temp[20U]; uint8_t temp[20U];
temp[0U] = 0x00U; temp[0U] = 0x00U;
::memcpy(temp + 1U, Data.data() + offset, 19U); memcpy(temp + 1U, Data.data() + offset, 19U);
payload.writeDataFRModeData2(temp, buffer + 35U); payload.writeDataFRModeData2(temp, buffer + 35U);
offset += 19U; offset += 19U;
} }
@ -734,7 +734,7 @@ bool CWiresxCmdHandler::DebugTestDecodePacket(const CBuffer &Buffer)
{ {
case YSF_FI_HEADER: case YSF_FI_HEADER:
len = 0; len = 0;
::memset(command, 0x00, sizeof(command)); memset(command, 0x00, sizeof(command));
std::cout << "Header" << std::endl; std::cout << "Header" << std::endl;
break; break;
case YSF_FI_TERMINATOR: case YSF_FI_TERMINATOR:

@ -27,16 +27,16 @@
CWiresxInfo::CWiresxInfo() CWiresxInfo::CWiresxInfo()
{ {
::memset(m_callsign, ' ', YSF_CALLSIGN_LENGTH); memset(m_callsign, ' ', YSF_CALLSIGN_LENGTH);
::memset(m_node, ' ', YSF_CALLSIGN_LENGTH); memset(m_node, ' ', YSF_CALLSIGN_LENGTH);
::memset(m_name, ' ', 14); memset(m_name, ' ', 14);
::memset(m_id, ' ', 6); memset(m_id, ' ', 6);
m_txFrequency = 0U; m_txFrequency = 0U;
m_rxFrequency = 0U; m_rxFrequency = 0U;
::memset(m_csd1, '*', 20U); memset(m_csd1, '*', 20U);
::memset(m_csd2, ' ', 20U); memset(m_csd2, ' ', 20U);
::memset(m_csd3, ' ', 20U); memset(m_csd3, ' ', 20U);
} }
@ -45,22 +45,22 @@ CWiresxInfo::CWiresxInfo()
void CWiresxInfo::SetCallsign(const CCallsign &callsign) void CWiresxInfo::SetCallsign(const CCallsign &callsign)
{ {
::memset(m_callsign, ' ', YSF_CALLSIGN_LENGTH); memset(m_callsign, ' ', YSF_CALLSIGN_LENGTH);
callsign.GetCallsign(m_callsign); callsign.GetCallsign(m_callsign);
UpdateCsds(); UpdateCsds();
} }
void CWiresxInfo::SetNode(const char *node) void CWiresxInfo::SetNode(const char *node)
{ {
::memset(m_node, ' ', YSF_CALLSIGN_LENGTH); memset(m_node, ' ', YSF_CALLSIGN_LENGTH);
::memcpy(m_node, node, MIN(::strlen(node), YSF_CALLSIGN_LENGTH)); memcpy(m_node, node, MIN(::strlen(node), YSF_CALLSIGN_LENGTH));
UpdateCsds(); UpdateCsds();
} }
void CWiresxInfo::SetName(const char *name) void CWiresxInfo::SetName(const char *name)
{ {
::memset(m_name, ' ', 14); memset(m_name, ' ', 14);
::memcpy(m_name, name, MIN(::strlen(name), 14)); memcpy(m_name, name, MIN(::strlen(name), 14));
UpdateId(); UpdateId();
} }
@ -75,13 +75,13 @@ void CWiresxInfo::SetFrequencies(uint txFreq, uint rxFreq)
void CWiresxInfo::UpdateCsds(void) void CWiresxInfo::UpdateCsds(void)
{ {
::memset(m_csd1, '*', 20U); memset(m_csd1, '*', 20U);
::memset(m_csd2, ' ', 20U); memset(m_csd2, ' ', 20U);
::memset(m_csd3, ' ', 20U); memset(m_csd3, ' ', 20U);
::memcpy(m_csd1 + 10U, m_node, 10U); memcpy(m_csd1 + 10U, m_node, 10U);
::memcpy(m_csd2 + 0U, m_callsign, 10U); memcpy(m_csd2 + 0U, m_callsign, 10U);
::memcpy(m_csd3 + 0U, m_id, 5U); memcpy(m_csd3 + 0U, m_id, 5U);
::memcpy(m_csd3 + 15U, m_id, 5U); memcpy(m_csd3 + 15U, m_id, 5U);
} }
void CWiresxInfo::UpdateId(void) void CWiresxInfo::UpdateId(void)

@ -59,7 +59,7 @@ const unsigned int INTERLEAVE_TABLE[] =
CYSFFICH::CYSFFICH() CYSFFICH::CYSFFICH()
{ {
::memset(m_fich, 0U, 6U); memset(m_fich, 0U, 6U);
} }
bool CYSFFICH::decode(const unsigned char* bytes) bool CYSFFICH::decode(const unsigned char* bytes)
@ -300,5 +300,5 @@ void CYSFFICH::load(const unsigned char* fich)
{ {
assert(fich != nullptr); assert(fich != nullptr);
::memcpy(m_fich, fich, 4U); memcpy(m_fich, fich, 4U);
} }

@ -32,7 +32,7 @@ CYsfNodeDirFile g_YsfNodeDir;
CYsfNodeDirFile::CYsfNodeDirFile() CYsfNodeDirFile::CYsfNodeDirFile()
{ {
::memset(&m_LastModTime, 0, sizeof(time_t)); memset(&m_LastModTime, 0, sizeof(time_t));
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////

@ -105,11 +105,11 @@ bool CYsfNodeDirHttp::HttpGet(const char *hostname, const char *filename, int po
// get hostname address // get hostname address
struct sockaddr_in servaddr; struct sockaddr_in servaddr;
struct hostent *hp; struct hostent *hp;
::memset(&servaddr,0,sizeof(servaddr)); memset(&servaddr,0,sizeof(servaddr));
if( (hp = gethostbyname(hostname)) != nullptr ) if( (hp = gethostbyname(hostname)) != nullptr )
{ {
// dns resolved // dns resolved
::memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length); memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length);
servaddr.sin_port = htons(port); servaddr.sin_port = htons(port);
servaddr.sin_family = AF_INET; servaddr.sin_family = AF_INET;

@ -94,7 +94,7 @@ bool CYSFPayload::processHeaderData(unsigned char* data)
unsigned char* p2 = dch; unsigned char* p2 = dch;
for (unsigned int i = 0U; i < 5U; i++) for (unsigned int i = 0U; i < 5U; i++)
{ {
::memcpy(p2, p1, 9U); memcpy(p2, p1, 9U);
p1 += 18U; p1 += 18U;
p2 += 9U; p2 += 9U;
} }
@ -125,13 +125,13 @@ bool CYSFPayload::processHeaderData(unsigned char* data)
if (m_dest == nullptr) if (m_dest == nullptr)
{ {
m_dest = std::unique_ptr<unsigned char[]>(new unsigned char[YSF_CALLSIGN_LENGTH]); m_dest = std::unique_ptr<unsigned char[]>(new unsigned char[YSF_CALLSIGN_LENGTH]);
::memcpy(m_dest.get(), output, YSF_CALLSIGN_LENGTH); memcpy(m_dest.get(), output, YSF_CALLSIGN_LENGTH);
} }
if (m_source == nullptr) if (m_source == nullptr)
{ {
m_source = std::unique_ptr<unsigned char[]>(new unsigned char[YSF_CALLSIGN_LENGTH]); m_source = std::unique_ptr<unsigned char[]>(new unsigned char[YSF_CALLSIGN_LENGTH]);
::memcpy(m_source.get(), output + YSF_CALLSIGN_LENGTH, YSF_CALLSIGN_LENGTH); memcpy(m_source.get(), output + YSF_CALLSIGN_LENGTH, YSF_CALLSIGN_LENGTH);
} }
for (unsigned int i = 0U; i < 20U; i++) for (unsigned int i = 0U; i < 20U; i++)
@ -165,7 +165,7 @@ bool CYSFPayload::processHeaderData(unsigned char* data)
p2 = bytes; p2 = bytes;
for (unsigned int i = 0U; i < 5U; i++) for (unsigned int i = 0U; i < 5U; i++)
{ {
::memcpy(p1, p2, 9U); memcpy(p1, p2, 9U);
p1 += 18U; p1 += 18U;
p2 += 9U; p2 += 9U;
} }
@ -175,7 +175,7 @@ bool CYSFPayload::processHeaderData(unsigned char* data)
p2 = dch; p2 = dch;
for (unsigned int i = 0U; i < 5U; i++) for (unsigned int i = 0U; i < 5U; i++)
{ {
::memcpy(p2, p1, 9U); memcpy(p2, p1, 9U);
p1 += 18U; p1 += 18U;
p2 += 9U; p2 += 9U;
} }
@ -202,10 +202,10 @@ bool CYSFPayload::processHeaderData(unsigned char* data)
output[i] ^= WHITENING_DATA[i]; output[i] ^= WHITENING_DATA[i];
if (m_downlink) if (m_downlink)
::memcpy(output + 0U, m_downlink.get(), YSF_CALLSIGN_LENGTH); memcpy(output + 0U, m_downlink.get(), YSF_CALLSIGN_LENGTH);
if (m_uplink) if (m_uplink)
::memcpy(output + YSF_CALLSIGN_LENGTH, m_uplink.get(), YSF_CALLSIGN_LENGTH); memcpy(output + YSF_CALLSIGN_LENGTH, m_uplink.get(), YSF_CALLSIGN_LENGTH);
for (unsigned int i = 0U; i < 20U; i++) for (unsigned int i = 0U; i < 20U; i++)
output[i] ^= WHITENING_DATA[i]; output[i] ^= WHITENING_DATA[i];
@ -238,7 +238,7 @@ bool CYSFPayload::processHeaderData(unsigned char* data)
p2 = bytes; p2 = bytes;
for (unsigned int i = 0U; i < 5U; i++) for (unsigned int i = 0U; i < 5U; i++)
{ {
::memcpy(p1, p2, 9U); memcpy(p1, p2, 9U);
p1 += 18U; p1 += 18U;
p2 += 9U; p2 += 9U;
} }
@ -252,7 +252,7 @@ bool CYSFPayload::readDataFRModeData1(const unsigned char* data, unsigned char*
assert(data != nullptr); assert(data != nullptr);
assert(dt != nullptr); assert(dt != nullptr);
::memset(dt, ' ', 20U); memset(dt, ' ', 20U);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES; data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -262,7 +262,7 @@ bool CYSFPayload::readDataFRModeData1(const unsigned char* data, unsigned char*
unsigned char* p2 = dch; unsigned char* p2 = dch;
for (unsigned int i = 0U; i < 5U; i++) for (unsigned int i = 0U; i < 5U; i++)
{ {
::memcpy(p2, p1, 9U); memcpy(p2, p1, 9U);
p1 += 18U; p1 += 18U;
p2 += 9U; p2 += 9U;
} }
@ -292,7 +292,7 @@ bool CYSFPayload::readDataFRModeData1(const unsigned char* data, unsigned char*
// CUtils::dump(1U, "FR Mode Data 1", output, 20U); // CUtils::dump(1U, "FR Mode Data 1", output, 20U);
::memcpy(dt, output, 20U); memcpy(dt, output, 20U);
} }
return ret; return ret;
@ -303,7 +303,7 @@ bool CYSFPayload::readDataFRModeData2(const unsigned char* data, unsigned char*
assert(data != nullptr); assert(data != nullptr);
assert(dt != nullptr); assert(dt != nullptr);
::memset(dt, ' ', 20U); memset(dt, ' ', 20U);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES; data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -313,7 +313,7 @@ bool CYSFPayload::readDataFRModeData2(const unsigned char* data, unsigned char*
unsigned char* p2 = dch; unsigned char* p2 = dch;
for (unsigned int i = 0U; i < 5U; i++) for (unsigned int i = 0U; i < 5U; i++)
{ {
::memcpy(p2, p1, 9U); memcpy(p2, p1, 9U);
p1 += 18U; p1 += 18U;
p2 += 9U; p2 += 9U;
} }
@ -343,7 +343,7 @@ bool CYSFPayload::readDataFRModeData2(const unsigned char* data, unsigned char*
// CUtils::dump(1U, "FR Mode Data 2", output, 20U); // CUtils::dump(1U, "FR Mode Data 2", output, 20U);
::memcpy(dt, output, 20U); memcpy(dt, output, 20U);
} }
return ret; return ret;
@ -354,7 +354,7 @@ void CYSFPayload::writeVDMode2Data(unsigned char* data, const unsigned char* dt)
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES; data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
unsigned char dt_tmp[13]; unsigned char dt_tmp[13];
::memcpy(dt_tmp, dt, YSF_CALLSIGN_LENGTH); memcpy(dt_tmp, dt, YSF_CALLSIGN_LENGTH);
for (unsigned int i = 0U; i < 10U; i++) for (unsigned int i = 0U; i < 10U; i++)
dt_tmp[i] ^= WHITENING_DATA[i]; dt_tmp[i] ^= WHITENING_DATA[i];
@ -389,7 +389,7 @@ void CYSFPayload::writeVDMode2Data(unsigned char* data, const unsigned char* dt)
unsigned char* p2 = bytes; unsigned char* p2 = bytes;
for (unsigned int i = 0U; i < 5U; i++) for (unsigned int i = 0U; i < 5U; i++)
{ {
::memcpy(p1, p2, 5U); memcpy(p1, p2, 5U);
p1 += 18U; p1 += 18U;
p2 += 5U; p2 += 5U;
} }
@ -409,7 +409,7 @@ bool CYSFPayload::readVDMode1Data(const unsigned char* data, unsigned char* dt)
unsigned char* p2 = dch; unsigned char* p2 = dch;
for (unsigned int i = 0U; i < 5U; i++) for (unsigned int i = 0U; i < 5U; i++)
{ {
::memcpy(p2, p1, 9U); memcpy(p2, p1, 9U);
p1 += 18U; p1 += 18U;
p2 += 9U; p2 += 9U;
} }
@ -439,7 +439,7 @@ bool CYSFPayload::readVDMode1Data(const unsigned char* data, unsigned char* dt)
// CUtils::dump(1U, "V/D Mode 1 Data", output, 20U); // CUtils::dump(1U, "V/D Mode 1 Data", output, 20U);
::memcpy(dt, output, 20U); memcpy(dt, output, 20U);
} }
return ret; return ret;
@ -459,7 +459,7 @@ bool CYSFPayload::readVDMode2Data(const unsigned char* data, unsigned char* dt)
unsigned char* p2 = dch; unsigned char* p2 = dch;
for (unsigned int i = 0U; i < 5U; i++) for (unsigned int i = 0U; i < 5U; i++)
{ {
::memcpy(p2, p1, 5U); memcpy(p2, p1, 5U);
p1 += 18U; p1 += 18U;
p2 += 5U; p2 += 5U;
} }
@ -489,7 +489,7 @@ bool CYSFPayload::readVDMode2Data(const unsigned char* data, unsigned char* dt)
// CUtils::dump(1U, "V/D Mode 2 Data", output, YSF_CALLSIGN_LENGTH); // CUtils::dump(1U, "V/D Mode 2 Data", output, YSF_CALLSIGN_LENGTH);
::memcpy(dt, output, YSF_CALLSIGN_LENGTH); memcpy(dt, output, YSF_CALLSIGN_LENGTH);
} }
return ret; return ret;
@ -547,7 +547,7 @@ void CYSFPayload::writeDataFRModeData1(const unsigned char* dt, unsigned char* d
unsigned char* p2 = bytes; unsigned char* p2 = bytes;
for (unsigned int i = 0U; i < 5U; i++) for (unsigned int i = 0U; i < 5U; i++)
{ {
::memcpy(p1, p2, 9U); memcpy(p1, p2, 9U);
p1 += 18U; p1 += 18U;
p2 += 9U; p2 += 9U;
} }
@ -594,7 +594,7 @@ void CYSFPayload::writeDataFRModeData2(const unsigned char* dt, unsigned char* d
unsigned char* p2 = bytes; unsigned char* p2 = bytes;
for (unsigned int i = 0U; i < 5U; i++) for (unsigned int i = 0U; i < 5U; i++)
{ {
::memcpy(p1, p2, 9U); memcpy(p1, p2, 9U);
p1 += 18U; p1 += 18U;
p2 += 9U; p2 += 9U;
} }

@ -186,11 +186,11 @@ void CYsfProtocol::Task(void)
EncodeServerStatusPacket(&Buffer); EncodeServerStatusPacket(&Buffer);
Send(Buffer, Ip); Send(Buffer, Ip);
} }
else if ( Buffer.size() == 80 && 0 == ::memcmp(Buffer.data(), "YSFI", 4) ) else if ( Buffer.size() == 80 && 0 == memcmp(Buffer.data(), "YSFI", 4) )
{ {
// do nothing, it's unneeded information from BlueDV // do nothing, it's unneeded information from BlueDV
} }
else if ( Buffer.size() == 50 && 0 == ::memcmp(Buffer.data(), "YSFO", 4) ) else if ( Buffer.size() == 50 && 0 == memcmp(Buffer.data(), "YSFO", 4) )
{ {
// do nothing, it's unneeded options from BlueDV // do nothing, it's unneeded options from BlueDV
} }
@ -425,10 +425,10 @@ bool CYsfProtocol::IsValidDvHeaderPacket(const CIp &Ip, const CYSFFICH &Fich, co
{ {
// build DVHeader // build DVHeader
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((const char *)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);
@ -443,8 +443,8 @@ bool CYsfProtocol::IsValidDvHeaderPacket(const CIp &Ip, const CYSFFICH &Fich, co
} }
// and 2 DV Frames // and 2 DV Frames
{ {
uint8_t uiAmbe[AMBE_SIZE]; uint8_t uiAmbe[9];
::memset(uiAmbe, 0x00, sizeof(uiAmbe)); memset(uiAmbe, 0x00, sizeof(uiAmbe));
frames[0] = std::unique_ptr<CDvFramePacket>(new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 0, 0)); frames[0] = std::unique_ptr<CDvFramePacket>(new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 0, 0));
frames[1] = std::unique_ptr<CDvFramePacket>(new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 1, 0)); frames[1] = std::unique_ptr<CDvFramePacket>(new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 1, 0));
} }
@ -466,11 +466,11 @@ bool CYsfProtocol::IsValidDvFramePacket(const CIp &Ip, const CYSFFICH &Fich, con
uint32_t uiStreamId = IpToStreamId(Ip); uint32_t uiStreamId = IpToStreamId(Ip);
// get DV frames // get DV frames
uint8_t ambe0[AMBEPLUS_SIZE]; uint8_t ambe0[9];
uint8_t ambe1[AMBEPLUS_SIZE]; uint8_t ambe1[9];
uint8_t ambe2[AMBEPLUS_SIZE]; uint8_t ambe2[9];
uint8_t ambe3[AMBEPLUS_SIZE]; uint8_t ambe3[9];
uint8_t ambe4[AMBEPLUS_SIZE]; uint8_t ambe4[9];
uint8_t *ambes[5] = { ambe0, ambe1, ambe2, ambe3, ambe4 }; uint8_t *ambes[5] = { ambe0, ambe1, ambe2, ambe3, ambe4 };
CYsfUtils::DecodeVD2Vchs((unsigned char *)&(Buffer.data()[35]), ambes); CYsfUtils::DecodeVD2Vchs((unsigned char *)&(Buffer.data()[35]), ambes);
@ -499,8 +499,8 @@ bool CYsfProtocol::IsValidDvLastFramePacket(const CIp &Ip, const CYSFFICH &Fich,
// get DV frames // get DV frames
{ {
uint8_t uiAmbe[AMBE_SIZE]; uint8_t uiAmbe[9];
::memset(uiAmbe, 0x00, sizeof(uiAmbe)); memset(uiAmbe, 0x00, sizeof(uiAmbe));
oneframe = std::unique_ptr<CDvFramePacket>(new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 0, 0)); oneframe = std::unique_ptr<CDvFramePacket>(new CDvFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 0, 0));
lastframe = std::unique_ptr<CDvLastFramePacket>(new CDvLastFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 1, 0)); lastframe = std::unique_ptr<CDvLastFramePacket>(new CDvLastFramePacket(uiAmbe, uiStreamId, Fich.getFN(), 1, 0));
} }
@ -532,12 +532,12 @@ bool CYsfProtocol::EncodeDvHeaderPacket(const CDvHeaderPacket &Header, CBuffer *
// tag // tag
Buffer->Set(tag, sizeof(tag)); Buffer->Set(tag, sizeof(tag));
// rpt1 // rpt1
::memset(sz, ' ', sizeof(sz)); memset(sz, ' ', sizeof(sz));
Header.GetRpt1Callsign().GetCallsignString(sz); Header.GetRpt1Callsign().GetCallsignString(sz);
sz[::strlen(sz)] = ' '; sz[::strlen(sz)] = ' ';
Buffer->Append((uint8_t *)sz, YSF_CALLSIGN_LENGTH); Buffer->Append((uint8_t *)sz, YSF_CALLSIGN_LENGTH);
// my // my
::memset(sz, ' ', sizeof(sz)); memset(sz, ' ', sizeof(sz));
Header.GetMyCallsign().GetCallsignString(sz); Header.GetMyCallsign().GetCallsignString(sz);
sz[::strlen(sz)] = ' '; sz[::strlen(sz)] = ' ';
Buffer->Append((uint8_t *)sz, YSF_CALLSIGN_LENGTH); Buffer->Append((uint8_t *)sz, YSF_CALLSIGN_LENGTH);
@ -563,11 +563,11 @@ bool CYsfProtocol::EncodeDvHeaderPacket(const CDvHeaderPacket &Header, CBuffer *
Buffer->Append(fichd, YSF_FICH_LENGTH_BYTES); Buffer->Append(fichd, YSF_FICH_LENGTH_BYTES);
// payload // payload
unsigned char csd1[20U], csd2[20U]; unsigned char csd1[20U], csd2[20U];
::memset(csd1, '*', YSF_CALLSIGN_LENGTH); memset(csd1, '*', YSF_CALLSIGN_LENGTH);
::memset(csd1 + YSF_CALLSIGN_LENGTH, ' ', YSF_CALLSIGN_LENGTH); memset(csd1 + YSF_CALLSIGN_LENGTH, ' ', YSF_CALLSIGN_LENGTH);
Header.GetMyCallsign().GetCallsignString(sz); Header.GetMyCallsign().GetCallsignString(sz);
::memcpy(csd1 + YSF_CALLSIGN_LENGTH, sz, ::strlen(sz)); memcpy(csd1 + YSF_CALLSIGN_LENGTH, sz, ::strlen(sz));
::memset(csd2, ' ', YSF_CALLSIGN_LENGTH + YSF_CALLSIGN_LENGTH); memset(csd2, ' ', YSF_CALLSIGN_LENGTH + YSF_CALLSIGN_LENGTH);
CYSFPayload payload; CYSFPayload payload;
uint8_t temp[120]; uint8_t temp[120];
payload.writeHeader(temp, csd1, csd2); payload.writeHeader(temp, csd1, csd2);
@ -588,12 +588,12 @@ bool CYsfProtocol::EncodeDvPacket(const CDvHeaderPacket &Header, const CDvFrameP
// tag // tag
Buffer->Set(tag, sizeof(tag)); Buffer->Set(tag, sizeof(tag));
// rpt1 // rpt1
::memset(sz, ' ', sizeof(sz)); memset(sz, ' ', sizeof(sz));
Header.GetRpt1Callsign().GetCallsignString(sz); Header.GetRpt1Callsign().GetCallsignString(sz);
sz[::strlen(sz)] = ' '; sz[::strlen(sz)] = ' ';
Buffer->Append((uint8_t *)sz, YSF_CALLSIGN_LENGTH); Buffer->Append((uint8_t *)sz, YSF_CALLSIGN_LENGTH);
// my // my
::memset(sz, ' ', sizeof(sz)); memset(sz, ' ', sizeof(sz));
Header.GetMyCallsign().GetCallsignString(sz); Header.GetMyCallsign().GetCallsignString(sz);
sz[::strlen(sz)] = ' '; sz[::strlen(sz)] = ' ';
Buffer->Append((uint8_t *)sz, YSF_CALLSIGN_LENGTH); Buffer->Append((uint8_t *)sz, YSF_CALLSIGN_LENGTH);
@ -619,11 +619,11 @@ bool CYsfProtocol::EncodeDvPacket(const CDvHeaderPacket &Header, const CDvFrameP
// payload // payload
CYSFPayload payload; CYSFPayload payload;
uint8_t temp[120]; uint8_t temp[120];
::memset(temp, 0x00, sizeof(temp)); memset(temp, 0x00, sizeof(temp));
// DV // DV
for ( int i = 0; i < 5; i++ ) for ( int i = 0; i < 5; i++ )
{ {
CYsfUtils::EncodeVD2Vch((unsigned char *)DvFrames[i].GetAmbePlus(), temp+35+(18*i)); CYsfUtils::EncodeVD2Vch((unsigned char *)DvFrames[i].GetCodecData(ECodecType::dmr), temp+35+(18*i));
} }
// data // data
switch (DvFrames[0].GetYsfPacketId()) switch (DvFrames[0].GetYsfPacketId())
@ -634,14 +634,14 @@ bool CYsfProtocol::EncodeDvPacket(const CDvHeaderPacket &Header, const CDvFrameP
break; break;
case 1: case 1:
// Src // Src
::memset(sz, ' ', sizeof(sz)); memset(sz, ' ', sizeof(sz));
Header.GetMyCallsign().GetCallsignString(sz); Header.GetMyCallsign().GetCallsignString(sz);
sz[::strlen(sz)] = ' '; sz[::strlen(sz)] = ' ';
payload.writeVDMode2Data(temp, (const unsigned char*)sz); payload.writeVDMode2Data(temp, (const unsigned char*)sz);
break; break;
case 2: case 2:
// Down // Down
::memset(sz, ' ', sizeof(sz)); memset(sz, ' ', sizeof(sz));
Header.GetRpt1Callsign().GetCallsignString(sz); Header.GetRpt1Callsign().GetCallsignString(sz);
sz[::strlen(sz)] = ' '; sz[::strlen(sz)] = ' ';
payload.writeVDMode2Data(temp, (const unsigned char*)sz); payload.writeVDMode2Data(temp, (const unsigned char*)sz);
@ -679,12 +679,12 @@ bool CYsfProtocol::EncodeDvLastPacket(const CDvHeaderPacket &Header, CBuffer *Bu
// tag // tag
Buffer->Set(tag, sizeof(tag)); Buffer->Set(tag, sizeof(tag));
// rpt1 // rpt1
::memset(sz, ' ', sizeof(sz)); memset(sz, ' ', sizeof(sz));
Header.GetRpt1Callsign().GetCallsignString(sz); Header.GetRpt1Callsign().GetCallsignString(sz);
sz[::strlen(sz)] = ' '; sz[::strlen(sz)] = ' ';
Buffer->Append((uint8_t *)sz, YSF_CALLSIGN_LENGTH); Buffer->Append((uint8_t *)sz, YSF_CALLSIGN_LENGTH);
// my // my
::memset(sz, ' ', sizeof(sz)); memset(sz, ' ', sizeof(sz));
Header.GetMyCallsign().GetCallsignString(sz); Header.GetMyCallsign().GetCallsignString(sz);
sz[::strlen(sz)] = ' '; sz[::strlen(sz)] = ' ';
Buffer->Append((uint8_t *)sz, YSF_CALLSIGN_LENGTH); Buffer->Append((uint8_t *)sz, YSF_CALLSIGN_LENGTH);
@ -710,11 +710,11 @@ bool CYsfProtocol::EncodeDvLastPacket(const CDvHeaderPacket &Header, CBuffer *Bu
Buffer->Append(fichd, YSF_FICH_LENGTH_BYTES); Buffer->Append(fichd, YSF_FICH_LENGTH_BYTES);
// payload // payload
unsigned char csd1[20U], csd2[20U]; unsigned char csd1[20U], csd2[20U];
::memset(csd1, '*', YSF_CALLSIGN_LENGTH); memset(csd1, '*', YSF_CALLSIGN_LENGTH);
::memset(csd1 + YSF_CALLSIGN_LENGTH, ' ', YSF_CALLSIGN_LENGTH); memset(csd1 + YSF_CALLSIGN_LENGTH, ' ', YSF_CALLSIGN_LENGTH);
Header.GetMyCallsign().GetCallsignString(sz); Header.GetMyCallsign().GetCallsignString(sz);
::memcpy(csd1 + YSF_CALLSIGN_LENGTH, sz, ::strlen(sz)); memcpy(csd1 + YSF_CALLSIGN_LENGTH, sz, ::strlen(sz));
::memset(csd2, ' ', YSF_CALLSIGN_LENGTH + YSF_CALLSIGN_LENGTH); memset(csd2, ' ', YSF_CALLSIGN_LENGTH + YSF_CALLSIGN_LENGTH);
CYSFPayload payload; CYSFPayload payload;
uint8_t temp[120]; uint8_t temp[120];
payload.writeHeader(temp, csd1, csd2); payload.writeHeader(temp, csd1, csd2);
@ -793,35 +793,35 @@ bool CYsfProtocol::IsValidwirexPacket(const CBuffer &Buffer, CYSFFICH *Fich, CCa
{ {
// get argument // get argument
char buffer[4U]; char buffer[4U];
::memcpy(buffer, command + 5U + 2U, 3U); memcpy(buffer, command + 5U + 2U, 3U);
buffer[3U] = 0x00U; buffer[3U] = 0x00U;
*Arg = ::atoi(buffer); *Arg = ::atoi(buffer);
// and decode command // and decode command
if (::memcmp(command + 1U, DX_REQ, 3U) == 0) if (memcmp(command + 1U, DX_REQ, 3U) == 0)
{ {
*Cmd = WIRESX_CMD_DX_REQ; *Cmd = WIRESX_CMD_DX_REQ;
*Arg = 0; *Arg = 0;
} }
else if (::memcmp(command + 1U, ALL_REQ, 3U) == 0) else if (memcmp(command + 1U, ALL_REQ, 3U) == 0)
{ {
// argument is start index of list // argument is start index of list
if ( *Arg > 0 ) if ( *Arg > 0 )
(*Arg)--; (*Arg)--;
// check if all or search // check if all or search
if ( ::memcmp(command + 5U, "01", 2) == 0 ) if ( memcmp(command + 5U, "01", 2) == 0 )
{ {
*Cmd = WIRESX_CMD_ALL_REQ; *Cmd = WIRESX_CMD_ALL_REQ;
} }
else if ( ::memcmp(command + 5U, "11", 2) == 0 ) else if ( memcmp(command + 5U, "11", 2) == 0 )
{ {
*Cmd = WIRESX_CMD_SEARCH_REQ; *Cmd = WIRESX_CMD_SEARCH_REQ;
} }
} }
else if (::memcmp(command + 1U, CONN_REQ, 3U) == 0) else if (memcmp(command + 1U, CONN_REQ, 3U) == 0)
{ {
*Cmd = WIRESX_CMD_CONN_REQ; *Cmd = WIRESX_CMD_CONN_REQ;
} }
else if (::memcmp(command + 1U, DISC_REQ, 3U) == 0) else if (memcmp(command + 1U, DISC_REQ, 3U) == 0)
{ {
*Cmd = WIRESX_CMD_DISC_REQ; *Cmd = WIRESX_CMD_DISC_REQ;
*Arg = 0; *Arg = 0;
@ -860,7 +860,7 @@ bool CYsfProtocol::EncodeServerStatusPacket(CBuffer *Buffer) const
// tag // tag
Buffer->Set(tag, sizeof(tag)); Buffer->Set(tag, sizeof(tag));
// hash // hash
::memset(callsign, ' ', sizeof(callsign)); memset(callsign, ' ', sizeof(callsign));
g_Reflector.GetCallsign().GetCallsign(callsign); g_Reflector.GetCallsign().GetCallsign(callsign);
char sz[16]; char sz[16];
::sprintf(sz, "%05u", CalcHash(callsign, 16) % 100000U); ::sprintf(sz, "%05u", CalcHash(callsign, 16) % 100000U);
@ -938,7 +938,7 @@ bool CYsfProtocol::DebugTestDecodePacket(const CBuffer &Buffer)
{ {
case YSF_FI_HEADER: case YSF_FI_HEADER:
len = 0; len = 0;
::memset(command, 0x00, sizeof(command)); memset(command, 0x00, sizeof(command));
std::cout << "Header" << std::endl; std::cout << "Header" << std::endl;
break; break;
case YSF_FI_TERMINATOR: case YSF_FI_TERMINATOR:

@ -562,7 +562,7 @@ void CYsfUtils::DecodeVD2Vchs(uint8_t *data, uint8_t **ambe)
WRITE_BIT(v_dmr, cPos, dat_c & MASK); WRITE_BIT(v_dmr, cPos, dat_c & MASK);
} }
::memcpy(ambe[frame++], v_dmr, 9); memcpy(ambe[frame++], v_dmr, 9);
} }
} }
@ -602,8 +602,8 @@ void CYsfUtils::EncodeVD2Vch(uint8_t *ambe, uint8_t *data)
// and to vch // and to vch
unsigned char vch[13U]; unsigned char vch[13U];
unsigned char ysfFrame[13U]; unsigned char ysfFrame[13U];
::memset(vch, 0U, 13U); memset(vch, 0U, 13U);
::memset(ysfFrame, 0, 13U); memset(ysfFrame, 0, 13U);
unsigned int dat_a = a >> 12; unsigned int dat_a = a >> 12;
@ -656,5 +656,5 @@ void CYsfUtils::EncodeVD2Vch(uint8_t *ambe, uint8_t *data)
WRITE_BIT(ysfFrame, n, s); WRITE_BIT(ysfFrame, n, s);
} }
::memcpy(data, ysfFrame, 13U); memcpy(data, ysfFrame, 13U);
} }

Loading…
Cancel
Save

Powered by TurnKey Linux.