Browse Source

new CCallsign class

master
Tom Early 1 year ago
parent
commit
9b9ddc624e
  1. 346
      callsign.cpp
  2. 122
      callsign.h
  3. 2
      ip.h
  4. 14
      m17protocol.cpp
  5. 2
      main.cpp
  6. 6
      packet.cpp
  7. 1
      packet.h

346
callsign.cpp

@ -1,253 +1,111 @@
//
// ccallsign.cpp
// m17ref
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// Copyright © 2020 Thomas A. Early N7TAE
//
// ----------------------------------------------------------------------------
// This file is part of m17ref.
//
// 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 <string.h>
#include <cctype>
/*
* Copyright (c) 2020 by 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 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 "callsign.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructors
#define M17CHARACTERS " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/."
CCallsign::CCallsign()
{
// blank all
::memset(m_Callsign, ' ', sizeof(m_Callsign));
::memset(m_Suffix, ' ', sizeof(m_Suffix));
m_Module = ' ';
memset(cs, 0, sizeof(cs));
memset(code, 0, sizeof(code));
}
CCallsign::CCallsign(const char *sz)
CCallsign::CCallsign(const std::string &callsign)
{
// blank all
::memset(m_Callsign, ' ', sizeof(m_Callsign));
::memset(m_Suffix, ' ', sizeof(m_Suffix));
m_Module = ' ';
// and populate
if ( ::strlen(sz) > 0 )
{
// callsign valid
::memcpy(m_Callsign, sz, MIN(strlen(sz), sizeof(m_Callsign)));
if ( strlen(sz) >= sizeof(m_Callsign) )
{
m_Module = sz[sizeof(m_Callsign)];
}
}
CSIn(callsign);
}
////////////////////////////////////////////////////////////////////////////////////////
// status
bool CCallsign::IsValid(void) const
CCallsign::CCallsign(const uint8_t *in)
{
bool valid = true;
int i;
// callsign
// first 3 chars are letter or number but cannot be all number
int iNum = 0;
for ( i = 0; i < 3; i++ )
{
valid &= IsLetter(m_Callsign[i]) || IsNumber(m_Callsign[i]);
if ( IsNumber(m_Callsign[i]) )
{
iNum++;
}
}
valid &= (iNum < 3);
// all remaining char are letter, number or space
for ( ; i < CALLSIGN_LEN; i++)
{
valid &= IsLetter(m_Callsign[i]) || IsNumber(m_Callsign[i]) || IsSpace(m_Callsign[i]);
}
// prefix
// all chars are number, uppercase or space
for ( i = 0; i < CALLSUFFIX_LEN; i++ )
{
valid &= IsLetter(m_Suffix[i]) || IsNumber(m_Suffix[i]) || IsSpace(m_Suffix[i]);
}
// module
// is an letter or space
valid &= IsLetter(m_Module) || IsSpace(m_Module);
// dmrid is not tested, as it can be nullptr
// if station does is not dmr registered
// done
return valid;
CodeIn(in);
}
bool CCallsign::HasSuffix(void) const
void CCallsign::CSIn(const std::string &callsign)
{
bool has = false;
for ( int i = 0; (i < CALLSUFFIX_LEN) && ! has; i++ )
{
has = has && (m_Suffix[i] != ' ');
const std::string m17_alphabet(M17CHARACTERS);
memset(cs, 0, sizeof(cs));
memcpy(cs, callsign.c_str(), (callsign.size()<10) ? callsign.size() : 9);
uint64_t encoded = 0;
for( int i=int(callsign.size()-1); i>=0; i-- ) {
auto pos = m17_alphabet.find(cs[i]);
if (pos == std::string::npos) {
pos = 0;
}
encoded *= 40;
encoded += pos;
}
for (int i=0; i<6; i++) {
code[i] = (encoded >> (8*(5-i)) & 0xFFU);
}
return has;
}
////////////////////////////////////////////////////////////////////////////////////////
// set
void CCallsign::DecodeCallsign(const uint8_t *in)
void CCallsign::CodeIn(const uint8_t *in)
{
const char *m17_alphabet = M17CHARACTERS;
char cs[9] = { ' ' };
const std::string m17_alphabet(M17CHARACTERS);
memset(cs, 0, 10);
uint64_t coded = in[0];
for (int i=1; i<6; i++)
coded = (coded << 8) | in[i];
int index = 0;
if (coded > 0xee6b27ffffffu) {
std::cerr << "Callsign code is too large, 0x" << std::hex << coded << std::endl;
return;
}
memcpy(code, in, 6);
int i = 0;
while (coded) {
cs[index++] = m17_alphabet[coded % 40];
cs[i++] = m17_alphabet[coded % 40];
coded /= 40;
}
strncpy(m_Callsign, cs, 8);
m_Module = cs[8];
::memset(m_Suffix, ' ', sizeof(m_Suffix));
}
void CCallsign::SetCallsign(const char *sz)
{
// set callsign
::memset(m_Callsign, ' ', sizeof(m_Callsign));
m_Module = ' ';
::memcpy(m_Callsign, sz, MIN(strlen(sz), sizeof(m_Callsign)-1));
if ( strlen(sz) >= sizeof(m_Callsign) )
{
m_Module = sz[sizeof(m_Callsign)-1];
}
}
void CCallsign::SetCallsign(const uint8_t *buffer, int len)
{
// set callsign
::memset(m_Callsign, ' ', sizeof(m_Callsign));
m_Module = ' ';
::memcpy(m_Callsign, buffer, MIN(len, sizeof(m_Callsign)-1));
for ( unsigned i = 0; i < sizeof(m_Callsign); i++ )
{
if ( m_Callsign[i] == 0 )
{
m_Callsign[i] = ' ';
}
}
if ( (len >= (int)sizeof(m_Callsign)) && ((char)buffer[sizeof(m_Callsign)-1] != 0) )
{
m_Module = (char)buffer[sizeof(m_Callsign)-1];
}
}
void CCallsign::SetModule(char c)
{
m_Module = c;
}
void CCallsign::SetSuffix(const char *sz)
{
::memset(m_Suffix, ' ', sizeof(m_Suffix));
::memcpy(m_Suffix, sz, MIN(strlen(sz), sizeof(m_Suffix)));
}
void CCallsign::SetSuffix(const uint8_t *buffer, int len)
{
len = MIN(len, sizeof(m_Suffix));
::memset(m_Suffix, ' ', sizeof(m_Suffix));
::memcpy(m_Suffix, buffer, len);
}
////////////////////////////////////////////////////////////////////////////////////////
// modify
void CCallsign::PatchCallsign(int off, const uint8_t *patch, int len)
{
if ( off < CALLSIGN_LEN )
{
::memcpy(m_Callsign, patch, MIN(len, sizeof(m_Callsign) - off));
}
}
////////////////////////////////////////////////////////////////////////////////////////
// get
void CCallsign::GetCallsign(uint8_t *buffer) const
const std::string CCallsign::GetCS(unsigned len) const
{
::memcpy(buffer, m_Callsign, sizeof(m_Callsign));
if ( HasModule() )
{
buffer[sizeof(m_Callsign)-1] = m_Module;
}
if (len > 9)
len = 9;
std::string rval(cs);
rval.resize(len, ' ');
return rval;
}
void CCallsign::GetCallsignString(char *sz) const
char CCallsign::GetModule() const
{
unsigned i;
for ( i = 0; (i < sizeof(m_Callsign)) && (m_Callsign[i] != ' '); i++ )
{
sz[i] = m_Callsign[i];
}
sz[i] = 0;
if (cs[9])
return cs[9];
else
return ' ';
}
void CCallsign::GetSuffix(uint8_t *buffer) const
bool CCallsign::HasSameCallsign(const CCallsign &call) const
{
::memcpy(buffer, m_Suffix, sizeof(m_Suffix));
return (0 == memcmp(cs, call.cs, 8));
}
void CCallsign::EncodeCallsign(uint8_t *out) const
bool CCallsign::operator==(const CCallsign &rhs) const
{
const char *alphabet = M17CHARACTERS;
uint64_t encoded = 0;
for( int i=0; i<9; i++)
{
encoded *= 40u;
const char *pos;
if (i)
pos = strchr(alphabet, m_Callsign[8-i]);
else
pos = strchr(alphabet, m_Module);
if (nullptr != pos)
encoded += pos - alphabet;
}
for (int i=0; i<6; i++) {
out[i] = (encoded >> (8*(5-i)) & 0xFFU);
}
return (0 == memcmp(code, rhs.code, 6));
}
////////////////////////////////////////////////////////////////////////////////////////
// compare
bool CCallsign::HasSameCallsign(const CCallsign &Callsign) const
bool CCallsign::operator!=(const CCallsign &rhs) const
{
return (::memcmp(m_Callsign, Callsign.m_Callsign, sizeof(m_Callsign)) == 0);
return (0 != memcmp(code, rhs.code, 6));
}
bool CCallsign::HasSameCallsignWithWildcard(const CCallsign &callsign) const
@ -255,73 +113,31 @@ bool CCallsign::HasSameCallsignWithWildcard(const CCallsign &callsign) const
bool same = true;
bool done = false;
for ( unsigned i = 0; (i < sizeof(m_Callsign)) && same && !done; i++ )
for ( unsigned i = 0; (i < sizeof(cs)) && same && !done; i++ )
{
if ( !(done = ((m_Callsign[i] == '*') || (callsign[i] == '*'))) )
if ( !(done = ((cs[i] == '*') || (callsign.cs[i] == '*'))) )
{
same &= (m_Callsign[i] == callsign[i]);
same &= (cs[i] == callsign.cs[i]);
}
}
return same;
}
bool CCallsign::HasLowerCallsign(const CCallsign &Callsign) const
{
return (::memcmp(m_Callsign, Callsign.m_Callsign, sizeof(m_Callsign)) < 0);
}
bool CCallsign::HasSameModule(const CCallsign &Callsign) const
{
return (m_Module == Callsign.m_Module);
}
////////////////////////////////////////////////////////////////////////////////////////
// operators
bool CCallsign::operator ==(const CCallsign &callsign) const
{
return ((::memcmp(callsign.m_Callsign, m_Callsign, sizeof(m_Callsign)) == 0) && (m_Module == callsign.m_Module)
&& (::memcmp(callsign.m_Suffix, m_Suffix, sizeof(m_Suffix)) == 0)
);
}
CCallsign::operator const char *() const
{
// empty
::memset(m_sz, 0, sizeof(m_sz));
// callsign
::memcpy(m_sz, m_Callsign, sizeof(m_Callsign));
// module
if ( HasModule() )
{
m_sz[sizeof(m_Callsign)] = m_Module;
}
// suffix
if ( HasSuffix() )
{
::strcat(m_sz, " / ");
::strncat(m_sz, m_Suffix, sizeof(m_Suffix));
}
// done
return m_sz;
}
////////////////////////////////////////////////////////////////////////////////////////
// helper
bool CCallsign::IsNumber(char c) const
void CCallsign::SetModule(char m)
{
return ((c >= '0') && (c <= '9'));
std::string call(cs);
call.resize(8, ' ');
call.append(1, m);
CSIn(call);
}
bool CCallsign::IsLetter(char c) const
bool CCallsign::IsValid() const
{
return ((c >= 'A') && (c <= 'Z'));
return true;
}
bool CCallsign::IsSpace(char c) const
std::ostream &operator<<(std::ostream &stream, const CCallsign &call)
{
return (c == ' ');
stream << call.cs;
return stream;
}

122
callsign.h

@ -1,93 +1,47 @@
//
// ccallsign.h
// m17ref
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// Copyright © 2020 Thomas A. Early N7TAE
//
// ----------------------------------------------------------------------------
// This file is part of m17ref.
//
// 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/>.
// ----------------------------------------------------------------------------
/*
* Copyright (c) 2020 by 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 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.
*/
#pragma once
#include "main.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
#define CALLSIGN_LEN 8
#define CALLSUFFIX_LEN 4
#define M17CHARACTERS " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/."
////////////////////////////////////////////////////////////////////////////////////////
// class
#include <cstdint>
#include <string>
#include <cstring>
class CCallsign
{
public:
// contructors
CCallsign();
CCallsign(const char *);
// status
bool IsValid(void) const;
bool HasSuffix(void) const;
bool HasModule(void) const { return m_Module != ' '; }
// set
void SetCallsign(const char *);
void SetCallsign(const uint8_t *, int);
void SetModule(char);
void SetSuffix(const char *);
void SetSuffix(const uint8_t *, int);
// modify
void PatchCallsign(int, const uint8_t *, int);
// get
void GetCallsign(uint8_t *) const;
void GetCallsignString(char *) const;
void GetSuffix(uint8_t *) const;
char GetModule(void) const { return m_Module; }
void EncodeCallsign(uint8_t *) const; // M17
void DecodeCallsign(const uint8_t *); // M17
// compare
bool HasSameCallsign(const CCallsign &) const;
bool HasSameCallsignWithWildcard(const CCallsign &) const;
bool HasLowerCallsign(const CCallsign &) const;
bool HasSameModule(const CCallsign &) const;
// operators
bool operator ==(const CCallsign &) const;
operator const char *() const;
protected:
// helper
bool IsNumber(char) const;
bool IsLetter(char) const;
bool IsSpace(char) const;
protected:
// data
char m_Callsign[CALLSIGN_LEN];
char m_Suffix[CALLSUFFIX_LEN];
char m_Module;
mutable char m_sz[CALLSIGN_LEN+CALLSUFFIX_LEN+5];
CCallsign(const std::string &cs);
CCallsign(const uint8_t *code);
void CSIn(const std::string &cs);
void CodeIn(const uint8_t *code);
const std::string GetCS(unsigned len = 9) const;
void CodeOut(uint8_t *out) const { memcpy(out, code, 6); };
bool operator==(const CCallsign &rhs) const;
bool operator!=(const CCallsign &rhs) const;
char GetModule(void) const;
bool HasSameCallsignWithWildcard(const CCallsign &callsign) const;
bool HasModule() const { return ('A' <= cs[9] && cs[9] <= 'Z'); }
void SetModule(char m);
bool IsValid() const;
friend std::ostream &operator<<(std::ostream &stream, const CCallsign &call);
bool HasSameCallsign(const CCallsign &call) const;
private:
uint8_t code[6];
char cs[10];
};

2
ip.h

@ -71,5 +71,3 @@ private:
mutable char straddr[INET6_ADDRSTRLEN];
bool is_set;
};
std::ostream &operator<<(std::ostream &stream, const CIp &Ip);

14
m17protocol.cpp

@ -225,7 +225,7 @@ void CM17Protocol::HandleQueue(void)
if ( !client->IsAMaster() && (client->GetReflectorModule() == packet->GetDestModule()) )
{
// packet->GetFrame().lich.addr_dst won't be correct after this.
client->GetCallsign().EncodeCallsign(packet->GetFrame().lich.addr_dst); // set the destination
client->GetCallsign().CodeOut(packet->GetFrame().lich.addr_dst); // set the destination
packet->SetCRC(crc.CalcCRC(packet->GetFrame().magic, sizeof(AM17Frame) - 2)); // recalculate the crc
Send(packet->GetFrame().magic, sizeof(AM17Frame), client->GetIp());
}
@ -416,7 +416,7 @@ bool CM17Protocol::IsValidConnect(const uint8_t *buf, CCallsign &cs, char *mod)
{
if (0 == memcmp(buf, "CONN", 4))
{
cs.DecodeCallsign(buf + 10);
cs.CodeIn(buf + 4);
if (cs.IsValid())
{
*mod = buf[10];
@ -431,7 +431,7 @@ bool CM17Protocol::IsValidDisconnect(const uint8_t *buf, CCallsign &cs)
{
if (0 == memcmp(buf, "DISC", 4))
{
cs.DecodeCallsign(buf+4);
cs.CodeIn(buf + 4);
if (cs.IsValid())
{
return true;
@ -444,7 +444,7 @@ bool CM17Protocol::IsValidKeepAlive(const uint8_t *buf, CCallsign &cs)
{
if (0 == memcmp(buf, "PING", 4))
{
cs.DecodeCallsign(buf+4);
cs.CodeIn(buf + 4);
if (cs.IsValid())
{
return true;
@ -475,7 +475,7 @@ void CM17Protocol::EncodeKeepAlivePacket(uint8_t *buf)
{
memcpy(buf, "PING", 4);
CCallsign cs(GetReflectorCallsign());
cs.EncodeCallsign(buf + 4);
cs.CodeOut(buf + 4);
}
void CM17Protocol::EncodeConnectPacket(uint8_t *buf, const char *Modules)
@ -483,7 +483,7 @@ void CM17Protocol::EncodeConnectPacket(uint8_t *buf, const char *Modules)
memcpy(buf, "CONN", 4);
CCallsign cs(GetReflectorCallsign());
cs.SetModule(Modules[0]);
cs.EncodeCallsign(buf + 4);
cs.CodeOut(buf + 4);
buf[10] = Modules[1];
}
@ -502,7 +502,7 @@ void CM17Protocol::EncodeDisconnectPacket(uint8_t *buf, char mod)
memcpy(buf, "DISC", 4);
CCallsign cs(GetReflectorCallsign());
cs.SetModule(mod);
cs.EncodeCallsign(buf + 4);
cs.CodeOut(buf + 4);
}
void CM17Protocol::EncodeDisconnectedPacket(uint8_t *buf)

2
main.cpp

@ -52,7 +52,7 @@ int main()
std::cout << "Starting " << cs << " " << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_REVISION << std::endl;
// initialize reflector
g_Reflector.SetCallsign(cs.c_str());
g_Reflector.SetCallsign(CCallsign(cs));
// and let it run

6
packet.cpp

@ -17,13 +17,15 @@
// with this software. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#include <arpa/inet.h>
#include "packet.h"
CPacket::CPacket(const uint8_t *buf)
{
memcpy(m17.magic, buf, sizeof(AM17Frame));
destination.DecodeCallsign(m17.lich.addr_dst);
source.DecodeCallsign(m17.lich.addr_src);
destination.CodeIn(m17.lich.addr_dst);
source.CodeIn(m17.lich.addr_src);
}
const CCallsign &CPacket::GetDestCallsign() const

1
packet.h

@ -21,6 +21,7 @@
#include <cstdint>
#include <string.h>
#include <memory>
#include "callsign.h"

Loading…
Cancel
Save