commit
4c53d23c12
@ -0,0 +1,15 @@
|
|||||||
|
Debug
|
||||||
|
Release
|
||||||
|
x64
|
||||||
|
MMDVMHost
|
||||||
|
*.o
|
||||||
|
*.opendb
|
||||||
|
*.bak
|
||||||
|
*.obj
|
||||||
|
*~
|
||||||
|
*.sdf
|
||||||
|
*.log
|
||||||
|
*.zip
|
||||||
|
*.exe
|
||||||
|
*.user
|
||||||
|
.vs
|
@ -0,0 +1,19 @@
|
|||||||
|
CC = gcc
|
||||||
|
CXX = g++
|
||||||
|
CFLAGS = -g -O3 -Wall -std=c++0x
|
||||||
|
LIBS =
|
||||||
|
LDFLAGS = -g
|
||||||
|
|
||||||
|
OBJECTS = Network.o Parrot.o StopWatch.o Timer.o UDPSocket.o Utils.o YSFParrot.o
|
||||||
|
|
||||||
|
all: YSFParrot
|
||||||
|
|
||||||
|
YSFParrot: $(OBJECTS)
|
||||||
|
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o YSFParrot
|
||||||
|
|
||||||
|
%.o: %.cpp
|
||||||
|
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) YSFParrot *.o *.d *.bak *~
|
||||||
|
|
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2014,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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 "YSFDefines.h"
|
||||||
|
#include "Network.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
const unsigned int BUFFER_LENGTH = 200U;
|
||||||
|
|
||||||
|
CNetwork::CNetwork(unsigned int port, bool debug) :
|
||||||
|
m_socket(port),
|
||||||
|
m_address(),
|
||||||
|
m_port(0U),
|
||||||
|
m_debug(debug),
|
||||||
|
m_buffer(1000U, "YSF Network"),
|
||||||
|
m_pollTimer(1000U, 60U)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CNetwork::~CNetwork()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNetwork::open()
|
||||||
|
{
|
||||||
|
::fprintf(stdout, "Opening YSF network connection\n");
|
||||||
|
|
||||||
|
if (m_address.s_addr == INADDR_NONE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_pollTimer.start();
|
||||||
|
|
||||||
|
return m_socket.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNetwork::write(const unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "YSF Network Data Sent", data, 155U);
|
||||||
|
|
||||||
|
return m_socket.write(data, 155U, m_address, m_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNetwork::writePoll()
|
||||||
|
{
|
||||||
|
unsigned char buffer[20U];
|
||||||
|
|
||||||
|
buffer[0] = 'Y';
|
||||||
|
buffer[1] = 'S';
|
||||||
|
buffer[2] = 'F';
|
||||||
|
buffer[3] = 'P';
|
||||||
|
|
||||||
|
buffer[4U] = 'P';
|
||||||
|
buffer[5U] = 'A';
|
||||||
|
buffer[6U] = 'R';
|
||||||
|
buffer[7U] = 'R';
|
||||||
|
buffer[8U] = 'O';
|
||||||
|
buffer[9U] = 'T';
|
||||||
|
buffer[10U] = ' ';
|
||||||
|
buffer[11U] = ' ';
|
||||||
|
buffer[12U] = ' ';
|
||||||
|
buffer[13U] = ' ';
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "YSF Network Poll Sent", buffer, 14U);
|
||||||
|
|
||||||
|
return m_socket.write(buffer, 14U, m_address, m_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNetwork::clock(unsigned int ms)
|
||||||
|
{
|
||||||
|
m_pollTimer.clock(ms);
|
||||||
|
if (m_pollTimer.hasExpired()) {
|
||||||
|
writePoll();
|
||||||
|
m_pollTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char buffer[BUFFER_LENGTH];
|
||||||
|
|
||||||
|
in_addr address;
|
||||||
|
unsigned int port;
|
||||||
|
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port);
|
||||||
|
if (length <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_address.s_addr = address.s_addr;
|
||||||
|
m_port = port;
|
||||||
|
|
||||||
|
// Ignore incoming polls
|
||||||
|
if (::memcmp(buffer, "YSFP", 4U) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Invalid packet type?
|
||||||
|
if (::memcmp(buffer, "YSFD", 4U) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "YSF Network Data Received", buffer, length);
|
||||||
|
|
||||||
|
m_buffer.addData(buffer, 155U);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CNetwork::read(unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
if (m_buffer.isEmpty())
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
m_buffer.getData(data, 155U);
|
||||||
|
|
||||||
|
return 155U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNetwork::close()
|
||||||
|
{
|
||||||
|
m_socket.close();
|
||||||
|
|
||||||
|
::fprintf(stdout, "Closing YSF network connection\n");
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2014,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef Network_H
|
||||||
|
#define Network_H
|
||||||
|
|
||||||
|
#include "YSFDefines.h"
|
||||||
|
#include "RingBuffer.h"
|
||||||
|
#include "UDPSocket.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CNetwork {
|
||||||
|
public:
|
||||||
|
CNetwork(unsigned int port, bool debug);
|
||||||
|
~CNetwork();
|
||||||
|
|
||||||
|
bool open();
|
||||||
|
|
||||||
|
bool write(const unsigned char* data);
|
||||||
|
|
||||||
|
unsigned int read(unsigned char* data);
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
|
void clock(unsigned int ms);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CUDPSocket m_socket;
|
||||||
|
in_addr m_address;
|
||||||
|
unsigned int m_port;
|
||||||
|
bool m_debug;
|
||||||
|
CRingBuffer<unsigned char> m_buffer;
|
||||||
|
CTimer m_pollTimer;
|
||||||
|
|
||||||
|
bool writePoll();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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 "Parrot.h"
|
||||||
|
#include "YSFDefines.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
CParrot::CParrot(unsigned int timeout) :
|
||||||
|
m_data(NULL),
|
||||||
|
m_length(timeout * 1550U + 1000U),
|
||||||
|
m_used(0U),
|
||||||
|
m_ptr(0U)
|
||||||
|
{
|
||||||
|
assert(timeout > 0U);
|
||||||
|
|
||||||
|
m_data = new unsigned char[m_length];
|
||||||
|
}
|
||||||
|
|
||||||
|
CParrot::~CParrot()
|
||||||
|
{
|
||||||
|
delete[] m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CParrot::write(const unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
if ((m_length - m_used) < 1000U)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
::memcpy(m_data + m_used, data, 155U);
|
||||||
|
m_used += 155U;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CParrot::end()
|
||||||
|
{
|
||||||
|
m_ptr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CParrot::read(unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
if (m_used == 0U)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
::memcpy(data, m_data + m_ptr, 155U);
|
||||||
|
m_ptr += 155U;
|
||||||
|
|
||||||
|
if (m_ptr >= m_used)
|
||||||
|
m_used = 0U;
|
||||||
|
|
||||||
|
return 155U;
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(Parrot_H)
|
||||||
|
#define Parrot_H
|
||||||
|
|
||||||
|
class CParrot
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CParrot(unsigned int timeout);
|
||||||
|
~CParrot();
|
||||||
|
|
||||||
|
bool write(const unsigned char* data);
|
||||||
|
|
||||||
|
unsigned int read(unsigned char* data);
|
||||||
|
|
||||||
|
void end();
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned char* m_data;
|
||||||
|
unsigned int m_length;
|
||||||
|
unsigned int m_used;
|
||||||
|
unsigned int m_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006-2009,2012,2013,2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RingBuffer_H
|
||||||
|
#define RingBuffer_H
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
template<class T> class CRingBuffer {
|
||||||
|
public:
|
||||||
|
CRingBuffer(unsigned int length, const char* name) :
|
||||||
|
m_length(length),
|
||||||
|
m_name(name),
|
||||||
|
m_buffer(NULL),
|
||||||
|
m_iPtr(0U),
|
||||||
|
m_oPtr(0U)
|
||||||
|
{
|
||||||
|
assert(length > 0U);
|
||||||
|
assert(name != NULL);
|
||||||
|
|
||||||
|
m_buffer = new T[length];
|
||||||
|
|
||||||
|
::memset(m_buffer, 0x00, m_length * sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
~CRingBuffer()
|
||||||
|
{
|
||||||
|
delete[] m_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool addData(const T* buffer, unsigned int nSamples)
|
||||||
|
{
|
||||||
|
if (nSamples >= freeSpace()) {
|
||||||
|
::fprintf(stderr, "**** Overflow in %s ring buffer, %u >= %u\n", m_name, nSamples, freeSpace());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < nSamples; i++) {
|
||||||
|
m_buffer[m_iPtr++] = buffer[i];
|
||||||
|
|
||||||
|
if (m_iPtr == m_length)
|
||||||
|
m_iPtr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getData(T* buffer, unsigned int nSamples)
|
||||||
|
{
|
||||||
|
if (dataSize() < nSamples) {
|
||||||
|
::fprintf(stderr, "**** Underflow in %s ring buffer, %u < %u\n", m_name, dataSize(), nSamples);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < nSamples; i++) {
|
||||||
|
buffer[i] = m_buffer[m_oPtr++];
|
||||||
|
|
||||||
|
if (m_oPtr == m_length)
|
||||||
|
m_oPtr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool peek(T* buffer, unsigned int nSamples)
|
||||||
|
{
|
||||||
|
if (dataSize() < nSamples) {
|
||||||
|
::fprintf(stderr, "**** Underflow peek in %s ring buffer, %u < %u\n", m_name, dataSize(), nSamples);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ptr = m_oPtr;
|
||||||
|
for (unsigned int i = 0U; i < nSamples; i++) {
|
||||||
|
buffer[i] = m_buffer[ptr++];
|
||||||
|
|
||||||
|
if (ptr == m_length)
|
||||||
|
ptr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
m_iPtr = 0U;
|
||||||
|
m_oPtr = 0U;
|
||||||
|
|
||||||
|
::memset(m_buffer, 0x00, m_length * sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int freeSpace() const
|
||||||
|
{
|
||||||
|
if (m_oPtr == m_iPtr)
|
||||||
|
return m_length;
|
||||||
|
|
||||||
|
if (m_oPtr > m_iPtr)
|
||||||
|
return m_oPtr - m_iPtr;
|
||||||
|
|
||||||
|
return (m_length + m_oPtr) - m_iPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int dataSize() const
|
||||||
|
{
|
||||||
|
return m_length - freeSpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasSpace(unsigned int length) const
|
||||||
|
{
|
||||||
|
return freeSpace() > length;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasData() const
|
||||||
|
{
|
||||||
|
return m_oPtr != m_iPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEmpty() const
|
||||||
|
{
|
||||||
|
return m_oPtr == m_iPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int m_length;
|
||||||
|
const char* m_name;
|
||||||
|
T* m_buffer;
|
||||||
|
unsigned int m_iPtr;
|
||||||
|
unsigned int m_oPtr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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 "StopWatch.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
|
||||||
|
CStopWatch::CStopWatch() :
|
||||||
|
m_frequency(),
|
||||||
|
m_start()
|
||||||
|
{
|
||||||
|
::QueryPerformanceFrequency(&m_frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
CStopWatch::~CStopWatch()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long CStopWatch::start()
|
||||||
|
{
|
||||||
|
::QueryPerformanceCounter(&m_start);
|
||||||
|
|
||||||
|
return (unsigned long)(m_start.QuadPart / m_frequency.QuadPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CStopWatch::elapsed()
|
||||||
|
{
|
||||||
|
LARGE_INTEGER now;
|
||||||
|
::QueryPerformanceCounter(&now);
|
||||||
|
|
||||||
|
LARGE_INTEGER temp;
|
||||||
|
temp.QuadPart = (now.QuadPart - m_start.QuadPart) * 1000;
|
||||||
|
|
||||||
|
return (unsigned int)(temp.QuadPart / m_frequency.QuadPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
CStopWatch::CStopWatch() :
|
||||||
|
m_start()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CStopWatch::~CStopWatch()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long CStopWatch::start()
|
||||||
|
{
|
||||||
|
::gettimeofday(&m_start, NULL);
|
||||||
|
|
||||||
|
return m_start.tv_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CStopWatch::elapsed()
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
::gettimeofday(&now, NULL);
|
||||||
|
|
||||||
|
unsigned int elapsed = (now.tv_sec - m_start.tv_sec) * 1000U;
|
||||||
|
elapsed += now.tv_usec / 1000U;
|
||||||
|
elapsed -= m_start.tv_usec / 1000U;
|
||||||
|
|
||||||
|
return elapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(STOPWATCH_H)
|
||||||
|
#define STOPWATCH_H
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <sys/time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CStopWatch
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CStopWatch();
|
||||||
|
~CStopWatch();
|
||||||
|
|
||||||
|
unsigned long start();
|
||||||
|
unsigned int elapsed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
LARGE_INTEGER m_frequency;
|
||||||
|
LARGE_INTEGER m_start;
|
||||||
|
#else
|
||||||
|
struct timeval m_start;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009,2010,2015 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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 "Timer.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
CTimer::CTimer(unsigned int ticksPerSec, unsigned int secs, unsigned int msecs) :
|
||||||
|
m_ticksPerSec(ticksPerSec),
|
||||||
|
m_timeout(0U),
|
||||||
|
m_timer(0U)
|
||||||
|
{
|
||||||
|
assert(ticksPerSec > 0U);
|
||||||
|
|
||||||
|
if (secs > 0U || msecs > 0U) {
|
||||||
|
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
|
||||||
|
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
|
||||||
|
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CTimer::~CTimer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTimer::setTimeout(unsigned int secs, unsigned int msecs)
|
||||||
|
{
|
||||||
|
if (secs > 0U || msecs > 0U) {
|
||||||
|
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
|
||||||
|
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
|
||||||
|
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
|
||||||
|
} else {
|
||||||
|
m_timeout = 0U;
|
||||||
|
m_timer = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CTimer::getTimeout() const
|
||||||
|
{
|
||||||
|
if (m_timeout == 0U)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
return (m_timeout - 1U) / m_ticksPerSec;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CTimer::getTimer() const
|
||||||
|
{
|
||||||
|
if (m_timer == 0U)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
return (m_timer - 1U) / m_ticksPerSec;
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009,2010,2011,2014 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef Timer_H
|
||||||
|
#define Timer_H
|
||||||
|
|
||||||
|
class CTimer {
|
||||||
|
public:
|
||||||
|
CTimer(unsigned int ticksPerSec, unsigned int secs = 0U, unsigned int msecs = 0U);
|
||||||
|
~CTimer();
|
||||||
|
|
||||||
|
void setTimeout(unsigned int secs, unsigned int msecs = 0U);
|
||||||
|
|
||||||
|
unsigned int getTimeout() const;
|
||||||
|
unsigned int getTimer() const;
|
||||||
|
|
||||||
|
unsigned int getRemaining()
|
||||||
|
{
|
||||||
|
if (m_timeout == 0U || m_timer == 0U)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
if (m_timer >= m_timeout)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
return (m_timeout - m_timer) / m_ticksPerSec;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isRunning()
|
||||||
|
{
|
||||||
|
return m_timer > 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start(unsigned int secs, unsigned int msecs = 0U)
|
||||||
|
{
|
||||||
|
setTimeout(secs, msecs);
|
||||||
|
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void start()
|
||||||
|
{
|
||||||
|
if (m_timeout > 0U)
|
||||||
|
m_timer = 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop()
|
||||||
|
{
|
||||||
|
m_timer = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasExpired()
|
||||||
|
{
|
||||||
|
if (m_timeout == 0U || m_timer == 0U)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_timer >= m_timeout)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clock(unsigned int ticks = 1U)
|
||||||
|
{
|
||||||
|
if (m_timer > 0U && m_timeout > 0U)
|
||||||
|
m_timer += ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int m_ticksPerSec;
|
||||||
|
unsigned int m_timeout;
|
||||||
|
unsigned int m_timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,261 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006-2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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 "UDPSocket.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#if !defined(_WIN32) && !defined(_WIN64)
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstring>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) :
|
||||||
|
m_address(address),
|
||||||
|
m_port(port),
|
||||||
|
m_fd(-1)
|
||||||
|
{
|
||||||
|
assert(!address.empty());
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
WSAData data;
|
||||||
|
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
|
||||||
|
if (wsaRet != 0)
|
||||||
|
::fprintf(stderr, "Error from WSAStartup\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CUDPSocket::CUDPSocket(unsigned int port) :
|
||||||
|
m_address(),
|
||||||
|
m_port(port),
|
||||||
|
m_fd(-1)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
WSAData data;
|
||||||
|
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
|
||||||
|
if (wsaRet != 0)
|
||||||
|
::fprintf(stderr, "Error from WSAStartup\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CUDPSocket::~CUDPSocket()
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::WSACleanup();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
in_addr CUDPSocket::lookup(const std::string& hostname)
|
||||||
|
{
|
||||||
|
in_addr addr;
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
unsigned long address = ::inet_addr(hostname.c_str());
|
||||||
|
if (address != INADDR_NONE && address != INADDR_ANY) {
|
||||||
|
addr.s_addr = address;
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct hostent* hp = ::gethostbyname(hostname.c_str());
|
||||||
|
if (hp != NULL) {
|
||||||
|
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
::fprintf(stderr, "Cannot find address for host %s\n", hostname.c_str());
|
||||||
|
|
||||||
|
addr.s_addr = INADDR_NONE;
|
||||||
|
return addr;
|
||||||
|
#else
|
||||||
|
in_addr_t address = ::inet_addr(hostname.c_str());
|
||||||
|
if (address != in_addr_t(-1)) {
|
||||||
|
addr.s_addr = address;
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct hostent* hp = ::gethostbyname(hostname.c_str());
|
||||||
|
if (hp != NULL) {
|
||||||
|
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
::fprintf(stderr, "Cannot find address for host %s\n", hostname.c_str());
|
||||||
|
|
||||||
|
addr.s_addr = INADDR_NONE;
|
||||||
|
return addr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CUDPSocket::open()
|
||||||
|
{
|
||||||
|
m_fd = ::socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (m_fd < 0) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::fprintf(stderr, "Cannot create the UDP socket, err: %lu\n", ::GetLastError());
|
||||||
|
#else
|
||||||
|
::fprintf(stderr, "Cannot create the UDP socket, err: %d\n", errno);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_port > 0U) {
|
||||||
|
sockaddr_in addr;
|
||||||
|
::memset(&addr, 0x00, sizeof(sockaddr_in));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(m_port);
|
||||||
|
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
|
||||||
|
if (!m_address.empty()) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
|
||||||
|
#else
|
||||||
|
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
|
||||||
|
#endif
|
||||||
|
if (addr.sin_addr.s_addr == INADDR_NONE) {
|
||||||
|
::fprintf(stderr, "The local address is invalid - %s\n", m_address.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int reuse = 1;
|
||||||
|
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::fprintf(stderr, "Cannot set the UDP socket option, err: %lu\n", ::GetLastError());
|
||||||
|
#else
|
||||||
|
::fprintf(stderr, "Cannot set the UDP socket option, err: %d\n", errno);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::fprintf(stderr, "Cannot bind the UDP address, err: %lu\n", ::GetLastError());
|
||||||
|
#else
|
||||||
|
::fprintf(stderr, "Cannot bind the UDP address, err: %d\n", errno);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port)
|
||||||
|
{
|
||||||
|
assert(buffer != NULL);
|
||||||
|
assert(length > 0U);
|
||||||
|
|
||||||
|
// Check that the readfrom() won't block
|
||||||
|
fd_set readFds;
|
||||||
|
FD_ZERO(&readFds);
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
FD_SET((unsigned int)m_fd, &readFds);
|
||||||
|
#else
|
||||||
|
FD_SET(m_fd, &readFds);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Return immediately
|
||||||
|
timeval tv;
|
||||||
|
tv.tv_sec = 0L;
|
||||||
|
tv.tv_usec = 0L;
|
||||||
|
|
||||||
|
int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv);
|
||||||
|
if (ret < 0) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::fprintf(stderr, "Error returned from UDP select, err: %lu\n", ::GetLastError());
|
||||||
|
#else
|
||||||
|
::fprintf(stderr, "Error returned from UDP select, err: %d\n", errno);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sockaddr_in addr;
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
int size = sizeof(sockaddr_in);
|
||||||
|
#else
|
||||||
|
socklen_t size = sizeof(sockaddr_in);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size);
|
||||||
|
#else
|
||||||
|
ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size);
|
||||||
|
#endif
|
||||||
|
if (len <= 0) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::fprintf(stderr, "Error returned from recvfrom, err: %lu\n", ::GetLastError());
|
||||||
|
#else
|
||||||
|
::fprintf(stderr, "Error returned from recvfrom, err: %d\n", errno);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
address = addr.sin_addr;
|
||||||
|
port = ntohs(addr.sin_port);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port)
|
||||||
|
{
|
||||||
|
assert(buffer != NULL);
|
||||||
|
assert(length > 0U);
|
||||||
|
|
||||||
|
sockaddr_in addr;
|
||||||
|
::memset(&addr, 0x00, sizeof(sockaddr_in));
|
||||||
|
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr = address;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
|
||||||
|
#else
|
||||||
|
ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
|
||||||
|
#endif
|
||||||
|
if (ret < 0) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::fprintf(stderr, "Error returned from sendto, err: %lu\n", ::GetLastError());
|
||||||
|
#else
|
||||||
|
::fprintf(stderr, "Error returned from sendto, err: %d\n", errno);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
if (ret != int(length))
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
if (ret != ssize_t(length))
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUDPSocket::close()
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::closesocket(m_fd);
|
||||||
|
#else
|
||||||
|
::close(m_fd);
|
||||||
|
#endif
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2011,2013,2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UDPSocket_H
|
||||||
|
#define UDPSocket_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#if !defined(_WIN32) && !defined(_WIN64)
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#else
|
||||||
|
#include <winsock.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CUDPSocket {
|
||||||
|
public:
|
||||||
|
CUDPSocket(const std::string& address, unsigned int port = 0U);
|
||||||
|
CUDPSocket(unsigned int port = 0U);
|
||||||
|
~CUDPSocket();
|
||||||
|
|
||||||
|
bool open();
|
||||||
|
|
||||||
|
int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port);
|
||||||
|
bool write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port);
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
|
static in_addr lookup(const std::string& hostName);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_address;
|
||||||
|
unsigned short m_port;
|
||||||
|
int m_fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009,2014,2015,2016 Jonathan Naylor, G4KLX
|
||||||
|
*
|
||||||
|
* 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; version 2 of the License.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
void CUtils::dump(const std::string& title, const unsigned char* data, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
dump(2U, title, data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUtils::dump(int level, const std::string& title, const unsigned char* data, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
::fprintf(stdout, "%s\n", title.c_str());
|
||||||
|
|
||||||
|
unsigned int offset = 0U;
|
||||||
|
|
||||||
|
while (length > 0U) {
|
||||||
|
std::string output;
|
||||||
|
|
||||||
|
unsigned int bytes = (length > 16U) ? 16U : length;
|
||||||
|
|
||||||
|
for (unsigned i = 0U; i < bytes; i++) {
|
||||||
|
char temp[10U];
|
||||||
|
::sprintf(temp, "%02X ", data[offset + i]);
|
||||||
|
output += temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = bytes; i < 16U; i++)
|
||||||
|
output += " ";
|
||||||
|
|
||||||
|
output += " *";
|
||||||
|
|
||||||
|
for (unsigned i = 0U; i < bytes; i++) {
|
||||||
|
unsigned char c = data[offset + i];
|
||||||
|
|
||||||
|
if (::isprint(c))
|
||||||
|
output += c;
|
||||||
|
else
|
||||||
|
output += '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
output += '*';
|
||||||
|
|
||||||
|
::fprintf(stdout, "%04X: %s\n", offset, output.c_str());
|
||||||
|
|
||||||
|
offset += 16U;
|
||||||
|
|
||||||
|
if (length >= 16U)
|
||||||
|
length -= 16U;
|
||||||
|
else
|
||||||
|
length = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUtils::dump(const std::string& title, const bool* bits, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(bits != NULL);
|
||||||
|
|
||||||
|
dump(2U, title, bits, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUtils::dump(int level, const std::string& title, const bool* bits, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(bits != NULL);
|
||||||
|
|
||||||
|
unsigned char bytes[100U];
|
||||||
|
unsigned int nBytes = 0U;
|
||||||
|
for (unsigned int n = 0U; n < length; n += 8U, nBytes++)
|
||||||
|
bitsToByteBE(bits + n, bytes[nBytes]);
|
||||||
|
|
||||||
|
dump(level, title, bytes, nBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUtils::byteToBitsBE(unsigned char byte, bool* bits)
|
||||||
|
{
|
||||||
|
assert(bits != NULL);
|
||||||
|
|
||||||
|
bits[0U] = (byte & 0x80U) == 0x80U;
|
||||||
|
bits[1U] = (byte & 0x40U) == 0x40U;
|
||||||
|
bits[2U] = (byte & 0x20U) == 0x20U;
|
||||||
|
bits[3U] = (byte & 0x10U) == 0x10U;
|
||||||
|
bits[4U] = (byte & 0x08U) == 0x08U;
|
||||||
|
bits[5U] = (byte & 0x04U) == 0x04U;
|
||||||
|
bits[6U] = (byte & 0x02U) == 0x02U;
|
||||||
|
bits[7U] = (byte & 0x01U) == 0x01U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUtils::byteToBitsLE(unsigned char byte, bool* bits)
|
||||||
|
{
|
||||||
|
assert(bits != NULL);
|
||||||
|
|
||||||
|
bits[0U] = (byte & 0x01U) == 0x01U;
|
||||||
|
bits[1U] = (byte & 0x02U) == 0x02U;
|
||||||
|
bits[2U] = (byte & 0x04U) == 0x04U;
|
||||||
|
bits[3U] = (byte & 0x08U) == 0x08U;
|
||||||
|
bits[4U] = (byte & 0x10U) == 0x10U;
|
||||||
|
bits[5U] = (byte & 0x20U) == 0x20U;
|
||||||
|
bits[6U] = (byte & 0x40U) == 0x40U;
|
||||||
|
bits[7U] = (byte & 0x80U) == 0x80U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUtils::bitsToByteBE(const bool* bits, unsigned char& byte)
|
||||||
|
{
|
||||||
|
assert(bits != NULL);
|
||||||
|
|
||||||
|
byte = bits[0U] ? 0x80U : 0x00U;
|
||||||
|
byte |= bits[1U] ? 0x40U : 0x00U;
|
||||||
|
byte |= bits[2U] ? 0x20U : 0x00U;
|
||||||
|
byte |= bits[3U] ? 0x10U : 0x00U;
|
||||||
|
byte |= bits[4U] ? 0x08U : 0x00U;
|
||||||
|
byte |= bits[5U] ? 0x04U : 0x00U;
|
||||||
|
byte |= bits[6U] ? 0x02U : 0x00U;
|
||||||
|
byte |= bits[7U] ? 0x01U : 0x00U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUtils::bitsToByteLE(const bool* bits, unsigned char& byte)
|
||||||
|
{
|
||||||
|
assert(bits != NULL);
|
||||||
|
|
||||||
|
byte = bits[0U] ? 0x01U : 0x00U;
|
||||||
|
byte |= bits[1U] ? 0x02U : 0x00U;
|
||||||
|
byte |= bits[2U] ? 0x04U : 0x00U;
|
||||||
|
byte |= bits[3U] ? 0x08U : 0x00U;
|
||||||
|
byte |= bits[4U] ? 0x10U : 0x00U;
|
||||||
|
byte |= bits[5U] ? 0x20U : 0x00U;
|
||||||
|
byte |= bits[6U] ? 0x40U : 0x00U;
|
||||||
|
byte |= bits[7U] ? 0x80U : 0x00U;
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009,2014,2015 by Jonathan Naylor, G4KLX
|
||||||
|
*
|
||||||
|
* 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; version 2 of the License.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef Utils_H
|
||||||
|
#define Utils_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CUtils {
|
||||||
|
public:
|
||||||
|
static void dump(const std::string& title, const unsigned char* data, unsigned int length);
|
||||||
|
static void dump(int level, const std::string& title, const unsigned char* data, unsigned int length);
|
||||||
|
|
||||||
|
static void dump(const std::string& title, const bool* bits, unsigned int length);
|
||||||
|
static void dump(int level, const std::string& title, const bool* bits, unsigned int length);
|
||||||
|
|
||||||
|
static void byteToBitsBE(unsigned char byte, bool* bits);
|
||||||
|
static void byteToBitsLE(unsigned char byte, bool* bits);
|
||||||
|
|
||||||
|
static void bitsToByteBE(const bool* bits, unsigned char& byte);
|
||||||
|
static void bitsToByteLE(const bool* bits, unsigned char& byte);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(YSFDefines_H)
|
||||||
|
#define YSFDefines_H
|
||||||
|
|
||||||
|
const unsigned int YSF_FRAME_LENGTH_BYTES = 120U;
|
||||||
|
|
||||||
|
const unsigned char YSF_SYNC_BYTES[] = {0xD4U, 0x71U, 0xC9U, 0x63U, 0x4DU};
|
||||||
|
const unsigned int YSF_SYNC_LENGTH_BYTES = 5U;
|
||||||
|
|
||||||
|
const unsigned int YSF_FICH_LENGTH_BYTES = 25U;
|
||||||
|
|
||||||
|
const unsigned char YSF_SYNC_OK = 0x01U;
|
||||||
|
|
||||||
|
const unsigned int YSF_CALLSIGN_LENGTH = 10U;
|
||||||
|
|
||||||
|
const unsigned char YSF_FI_HEADER = 0x00U;
|
||||||
|
const unsigned char YSF_FI_COMMUNICATIONS = 0x01U;
|
||||||
|
const unsigned char YSF_FI_TERMINATOR = 0x02U;
|
||||||
|
const unsigned char YSF_FI_TEST = 0x03U;
|
||||||
|
|
||||||
|
const unsigned char YSF_DT_VD_MODE1 = 0x00U;
|
||||||
|
const unsigned char YSF_DT_DATA_FR_MODE = 0x01U;
|
||||||
|
const unsigned char YSF_DT_VD_MODE2 = 0x02U;
|
||||||
|
const unsigned char YSF_DT_VOICE_FR_MODE = 0x03U;
|
||||||
|
|
||||||
|
const unsigned char YSF_CM_GROUP = 0x00U;
|
||||||
|
const unsigned char YSF_CM_INDIVIDUAL = 0x03U;
|
||||||
|
|
||||||
|
const unsigned char YSF_MR_NOT_BUSY = 0x01U;
|
||||||
|
const unsigned char YSF_MR_BUSY = 0x02U;
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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 "StopWatch.h"
|
||||||
|
#include "YSFParrot.h"
|
||||||
|
#include "Parrot.h"
|
||||||
|
#include "Network.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if (argc == 1) {
|
||||||
|
::fprintf(stderr, "Usage: YSFParrot <port>\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int port = ::atoi(argv[1]);
|
||||||
|
if (port == 0U) {
|
||||||
|
::fprintf(stderr, "YSFParrot: invalid port number\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CYSFParrot parrot(port);
|
||||||
|
parrot.run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CYSFParrot::CYSFParrot(unsigned int port) :
|
||||||
|
m_port(port)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CYSFParrot::~CYSFParrot()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CYSFParrot::run()
|
||||||
|
{
|
||||||
|
CParrot parrot(180U);
|
||||||
|
CNetwork network(m_port, false);
|
||||||
|
|
||||||
|
bool ret = network.open();
|
||||||
|
if (!ret)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CStopWatch stopWatch;
|
||||||
|
stopWatch.start();
|
||||||
|
|
||||||
|
CTimer watchdogTimer(1000U, 0U, 1500U);
|
||||||
|
CTimer turnaroundTimer(1000U, 2U);
|
||||||
|
|
||||||
|
CStopWatch playoutTimer;
|
||||||
|
unsigned int count = 0U;
|
||||||
|
bool playing = false;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
unsigned char buffer[200U];
|
||||||
|
|
||||||
|
unsigned int len = network.read(buffer);
|
||||||
|
if (len > 0U) {
|
||||||
|
parrot.write(buffer);
|
||||||
|
watchdogTimer.start();
|
||||||
|
|
||||||
|
if (buffer[34U] == 0x01U) {
|
||||||
|
::fprintf(stdout, "Received end of transmission\n");
|
||||||
|
turnaroundTimer.start();
|
||||||
|
watchdogTimer.stop();
|
||||||
|
parrot.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (turnaroundTimer.isRunning() && turnaroundTimer.hasExpired()) {
|
||||||
|
if (!playing) {
|
||||||
|
playoutTimer.start();
|
||||||
|
playing = true;
|
||||||
|
count = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A frame every 100ms
|
||||||
|
unsigned int wanted = playoutTimer.elapsed() / 100U;
|
||||||
|
while (count < wanted) {
|
||||||
|
len = parrot.read(buffer);
|
||||||
|
if (len > 0U) {
|
||||||
|
network.write(buffer);
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
turnaroundTimer.stop();
|
||||||
|
playing = false;
|
||||||
|
count = wanted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ms = stopWatch.elapsed();
|
||||||
|
stopWatch.start();
|
||||||
|
|
||||||
|
network.clock(ms);
|
||||||
|
watchdogTimer.clock(ms);
|
||||||
|
turnaroundTimer.clock(ms);
|
||||||
|
|
||||||
|
if (watchdogTimer.isRunning() && watchdogTimer.hasExpired()) {
|
||||||
|
::fprintf(stdout, "Network watchdog has expired\n");
|
||||||
|
turnaroundTimer.start();
|
||||||
|
watchdogTimer.stop();
|
||||||
|
parrot.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ms < 5U) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::Sleep(5UL); // 5ms
|
||||||
|
#else
|
||||||
|
::usleep(5000); // 5ms
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
network.close();
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(YSFParrot_H)
|
||||||
|
#define YSFParrot_H
|
||||||
|
|
||||||
|
class CYSFParrot
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CYSFParrot(unsigned int port);
|
||||||
|
~CYSFParrot();
|
||||||
|
|
||||||
|
void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int m_port;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="UDPSocket.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Timer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="YSFDefines.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="RingBuffer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Network.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Parrot.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Utils.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="YSFParrot.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="StopWatch.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="UDPSocket.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Timer.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Network.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Parrot.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Utils.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="YSFParrot.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="StopWatch.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
@ -0,0 +1,19 @@
|
|||||||
|
CC = gcc
|
||||||
|
CXX = g++
|
||||||
|
CFLAGS = -g -O3 -Wall -std=c++0x
|
||||||
|
LIBS =
|
||||||
|
LDFLAGS = -g
|
||||||
|
|
||||||
|
OBJECTS = Network.o StopWatch.o Timer.o UDPSocket.o Utils.o YSFReflector.o
|
||||||
|
|
||||||
|
all: YSFReflector
|
||||||
|
|
||||||
|
YSFParrot: $(OBJECTS)
|
||||||
|
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o YSFReflector
|
||||||
|
|
||||||
|
%.o: %.cpp
|
||||||
|
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) YSFReflector *.o *.d *.bak *~
|
||||||
|
|
@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2014,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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 "YSFDefines.h"
|
||||||
|
#include "Network.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
const unsigned int BUFFER_LENGTH = 200U;
|
||||||
|
|
||||||
|
CNetwork::CNetwork(unsigned int port, bool debug) :
|
||||||
|
m_socket(port),
|
||||||
|
m_address(),
|
||||||
|
m_port(0U),
|
||||||
|
m_callsign(),
|
||||||
|
m_debug(debug),
|
||||||
|
m_buffer(1000U, "YSF Network")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CNetwork::~CNetwork()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNetwork::open()
|
||||||
|
{
|
||||||
|
::fprintf(stdout, "Opening YSF network connection\n");
|
||||||
|
|
||||||
|
return m_socket.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNetwork::writeData(const unsigned char* data, const in_addr& address, unsigned int port)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "YSF Network Data Sent", data, 155U);
|
||||||
|
|
||||||
|
return m_socket.write(data, 155U, address, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNetwork::writePoll(const in_addr& address, unsigned int port)
|
||||||
|
{
|
||||||
|
unsigned char buffer[20U];
|
||||||
|
|
||||||
|
buffer[0] = 'Y';
|
||||||
|
buffer[1] = 'S';
|
||||||
|
buffer[2] = 'F';
|
||||||
|
buffer[3] = 'P';
|
||||||
|
|
||||||
|
buffer[4U] = 'R';
|
||||||
|
buffer[5U] = 'E';
|
||||||
|
buffer[6U] = 'F';
|
||||||
|
buffer[7U] = 'L';
|
||||||
|
buffer[8U] = 'E';
|
||||||
|
buffer[9U] = 'C';
|
||||||
|
buffer[10U] = 'T';
|
||||||
|
buffer[11U] = 'O';
|
||||||
|
buffer[12U] = 'R';
|
||||||
|
buffer[13U] = ' ';
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "YSF Network Poll Sent", buffer, 14U);
|
||||||
|
|
||||||
|
return m_socket.write(buffer, 14U, address, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNetwork::clock(unsigned int ms)
|
||||||
|
{
|
||||||
|
unsigned char buffer[BUFFER_LENGTH];
|
||||||
|
|
||||||
|
in_addr address;
|
||||||
|
unsigned int port;
|
||||||
|
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port);
|
||||||
|
if (length <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Handle incoming polls
|
||||||
|
if (::memcmp(buffer, "YSFP", 4U) == 0) {
|
||||||
|
m_callsign = std::string((char*)(buffer + 4U), YSF_CALLSIGN_LENGTH);
|
||||||
|
m_address = address;
|
||||||
|
m_port = port;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid packet type?
|
||||||
|
if (::memcmp(buffer, "YSFD", 4U) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Simulate a poll with the data
|
||||||
|
m_callsign = std::string((char*)(buffer + 4U), YSF_CALLSIGN_LENGTH);
|
||||||
|
m_address = address;
|
||||||
|
m_port = port;
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "YSF Network Data Received", buffer, length);
|
||||||
|
|
||||||
|
m_buffer.addData(buffer, 155U);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CNetwork::readData(unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
if (m_buffer.isEmpty())
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
m_buffer.getData(data, 155U);
|
||||||
|
|
||||||
|
return 155U;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNetwork::readPoll(std::string& callsign, in_addr& address, unsigned int& port)
|
||||||
|
{
|
||||||
|
if (m_port == 0U)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
callsign = m_callsign;
|
||||||
|
address = m_address;
|
||||||
|
port = m_port;
|
||||||
|
|
||||||
|
m_port = 0U;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNetwork::close()
|
||||||
|
{
|
||||||
|
m_socket.close();
|
||||||
|
|
||||||
|
::fprintf(stdout, "Closing YSF network connection\n");
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2014,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef Network_H
|
||||||
|
#define Network_H
|
||||||
|
|
||||||
|
#include "YSFDefines.h"
|
||||||
|
#include "RingBuffer.h"
|
||||||
|
#include "UDPSocket.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CNetwork {
|
||||||
|
public:
|
||||||
|
CNetwork(unsigned int port, bool debug);
|
||||||
|
~CNetwork();
|
||||||
|
|
||||||
|
bool open();
|
||||||
|
|
||||||
|
bool writeData(const unsigned char* data, const in_addr& address, unsigned int port);
|
||||||
|
bool writePoll(const in_addr& address, unsigned int port);
|
||||||
|
|
||||||
|
unsigned int readData(unsigned char* data);
|
||||||
|
bool readPoll(std::string& callsign, in_addr& address, unsigned int& port);
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
|
void clock(unsigned int ms);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CUDPSocket m_socket;
|
||||||
|
in_addr m_address;
|
||||||
|
unsigned int m_port;
|
||||||
|
std::string m_callsign;
|
||||||
|
bool m_debug;
|
||||||
|
CRingBuffer<unsigned char> m_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006-2009,2012,2013,2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RingBuffer_H
|
||||||
|
#define RingBuffer_H
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
template<class T> class CRingBuffer {
|
||||||
|
public:
|
||||||
|
CRingBuffer(unsigned int length, const char* name) :
|
||||||
|
m_length(length),
|
||||||
|
m_name(name),
|
||||||
|
m_buffer(NULL),
|
||||||
|
m_iPtr(0U),
|
||||||
|
m_oPtr(0U)
|
||||||
|
{
|
||||||
|
assert(length > 0U);
|
||||||
|
assert(name != NULL);
|
||||||
|
|
||||||
|
m_buffer = new T[length];
|
||||||
|
|
||||||
|
::memset(m_buffer, 0x00, m_length * sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
~CRingBuffer()
|
||||||
|
{
|
||||||
|
delete[] m_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool addData(const T* buffer, unsigned int nSamples)
|
||||||
|
{
|
||||||
|
if (nSamples >= freeSpace()) {
|
||||||
|
::fprintf(stderr, "**** Overflow in %s ring buffer, %u >= %u\n", m_name, nSamples, freeSpace());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < nSamples; i++) {
|
||||||
|
m_buffer[m_iPtr++] = buffer[i];
|
||||||
|
|
||||||
|
if (m_iPtr == m_length)
|
||||||
|
m_iPtr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getData(T* buffer, unsigned int nSamples)
|
||||||
|
{
|
||||||
|
if (dataSize() < nSamples) {
|
||||||
|
::fprintf(stderr, "**** Underflow in %s ring buffer, %u < %u\n", m_name, dataSize(), nSamples);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < nSamples; i++) {
|
||||||
|
buffer[i] = m_buffer[m_oPtr++];
|
||||||
|
|
||||||
|
if (m_oPtr == m_length)
|
||||||
|
m_oPtr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool peek(T* buffer, unsigned int nSamples)
|
||||||
|
{
|
||||||
|
if (dataSize() < nSamples) {
|
||||||
|
::fprintf(stderr, "**** Underflow peek in %s ring buffer, %u < %u\n", m_name, dataSize(), nSamples);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ptr = m_oPtr;
|
||||||
|
for (unsigned int i = 0U; i < nSamples; i++) {
|
||||||
|
buffer[i] = m_buffer[ptr++];
|
||||||
|
|
||||||
|
if (ptr == m_length)
|
||||||
|
ptr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
m_iPtr = 0U;
|
||||||
|
m_oPtr = 0U;
|
||||||
|
|
||||||
|
::memset(m_buffer, 0x00, m_length * sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int freeSpace() const
|
||||||
|
{
|
||||||
|
if (m_oPtr == m_iPtr)
|
||||||
|
return m_length;
|
||||||
|
|
||||||
|
if (m_oPtr > m_iPtr)
|
||||||
|
return m_oPtr - m_iPtr;
|
||||||
|
|
||||||
|
return (m_length + m_oPtr) - m_iPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int dataSize() const
|
||||||
|
{
|
||||||
|
return m_length - freeSpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasSpace(unsigned int length) const
|
||||||
|
{
|
||||||
|
return freeSpace() > length;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasData() const
|
||||||
|
{
|
||||||
|
return m_oPtr != m_iPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEmpty() const
|
||||||
|
{
|
||||||
|
return m_oPtr == m_iPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int m_length;
|
||||||
|
const char* m_name;
|
||||||
|
T* m_buffer;
|
||||||
|
unsigned int m_iPtr;
|
||||||
|
unsigned int m_oPtr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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 "StopWatch.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
|
||||||
|
CStopWatch::CStopWatch() :
|
||||||
|
m_frequency(),
|
||||||
|
m_start()
|
||||||
|
{
|
||||||
|
::QueryPerformanceFrequency(&m_frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
CStopWatch::~CStopWatch()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long CStopWatch::start()
|
||||||
|
{
|
||||||
|
::QueryPerformanceCounter(&m_start);
|
||||||
|
|
||||||
|
return (unsigned long)(m_start.QuadPart / m_frequency.QuadPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CStopWatch::elapsed()
|
||||||
|
{
|
||||||
|
LARGE_INTEGER now;
|
||||||
|
::QueryPerformanceCounter(&now);
|
||||||
|
|
||||||
|
LARGE_INTEGER temp;
|
||||||
|
temp.QuadPart = (now.QuadPart - m_start.QuadPart) * 1000;
|
||||||
|
|
||||||
|
return (unsigned int)(temp.QuadPart / m_frequency.QuadPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
CStopWatch::CStopWatch() :
|
||||||
|
m_start()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CStopWatch::~CStopWatch()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long CStopWatch::start()
|
||||||
|
{
|
||||||
|
::gettimeofday(&m_start, NULL);
|
||||||
|
|
||||||
|
return m_start.tv_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CStopWatch::elapsed()
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
::gettimeofday(&now, NULL);
|
||||||
|
|
||||||
|
unsigned int elapsed = (now.tv_sec - m_start.tv_sec) * 1000U;
|
||||||
|
elapsed += now.tv_usec / 1000U;
|
||||||
|
elapsed -= m_start.tv_usec / 1000U;
|
||||||
|
|
||||||
|
return elapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(STOPWATCH_H)
|
||||||
|
#define STOPWATCH_H
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <sys/time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CStopWatch
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CStopWatch();
|
||||||
|
~CStopWatch();
|
||||||
|
|
||||||
|
unsigned long start();
|
||||||
|
unsigned int elapsed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
LARGE_INTEGER m_frequency;
|
||||||
|
LARGE_INTEGER m_start;
|
||||||
|
#else
|
||||||
|
struct timeval m_start;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009,2010,2015 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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 "Timer.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
CTimer::CTimer(unsigned int ticksPerSec, unsigned int secs, unsigned int msecs) :
|
||||||
|
m_ticksPerSec(ticksPerSec),
|
||||||
|
m_timeout(0U),
|
||||||
|
m_timer(0U)
|
||||||
|
{
|
||||||
|
assert(ticksPerSec > 0U);
|
||||||
|
|
||||||
|
if (secs > 0U || msecs > 0U) {
|
||||||
|
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
|
||||||
|
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
|
||||||
|
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CTimer::~CTimer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTimer::setTimeout(unsigned int secs, unsigned int msecs)
|
||||||
|
{
|
||||||
|
if (secs > 0U || msecs > 0U) {
|
||||||
|
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
|
||||||
|
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
|
||||||
|
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
|
||||||
|
} else {
|
||||||
|
m_timeout = 0U;
|
||||||
|
m_timer = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CTimer::getTimeout() const
|
||||||
|
{
|
||||||
|
if (m_timeout == 0U)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
return (m_timeout - 1U) / m_ticksPerSec;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CTimer::getTimer() const
|
||||||
|
{
|
||||||
|
if (m_timer == 0U)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
return (m_timer - 1U) / m_ticksPerSec;
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009,2010,2011,2014 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef Timer_H
|
||||||
|
#define Timer_H
|
||||||
|
|
||||||
|
class CTimer {
|
||||||
|
public:
|
||||||
|
CTimer(unsigned int ticksPerSec, unsigned int secs = 0U, unsigned int msecs = 0U);
|
||||||
|
~CTimer();
|
||||||
|
|
||||||
|
void setTimeout(unsigned int secs, unsigned int msecs = 0U);
|
||||||
|
|
||||||
|
unsigned int getTimeout() const;
|
||||||
|
unsigned int getTimer() const;
|
||||||
|
|
||||||
|
unsigned int getRemaining()
|
||||||
|
{
|
||||||
|
if (m_timeout == 0U || m_timer == 0U)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
if (m_timer >= m_timeout)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
return (m_timeout - m_timer) / m_ticksPerSec;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isRunning()
|
||||||
|
{
|
||||||
|
return m_timer > 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start(unsigned int secs, unsigned int msecs = 0U)
|
||||||
|
{
|
||||||
|
setTimeout(secs, msecs);
|
||||||
|
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void start()
|
||||||
|
{
|
||||||
|
if (m_timeout > 0U)
|
||||||
|
m_timer = 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop()
|
||||||
|
{
|
||||||
|
m_timer = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasExpired()
|
||||||
|
{
|
||||||
|
if (m_timeout == 0U || m_timer == 0U)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_timer >= m_timeout)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clock(unsigned int ticks = 1U)
|
||||||
|
{
|
||||||
|
if (m_timer > 0U && m_timeout > 0U)
|
||||||
|
m_timer += ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int m_ticksPerSec;
|
||||||
|
unsigned int m_timeout;
|
||||||
|
unsigned int m_timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,261 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006-2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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 "UDPSocket.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#if !defined(_WIN32) && !defined(_WIN64)
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstring>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) :
|
||||||
|
m_address(address),
|
||||||
|
m_port(port),
|
||||||
|
m_fd(-1)
|
||||||
|
{
|
||||||
|
assert(!address.empty());
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
WSAData data;
|
||||||
|
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
|
||||||
|
if (wsaRet != 0)
|
||||||
|
::fprintf(stderr, "Error from WSAStartup\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CUDPSocket::CUDPSocket(unsigned int port) :
|
||||||
|
m_address(),
|
||||||
|
m_port(port),
|
||||||
|
m_fd(-1)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
WSAData data;
|
||||||
|
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
|
||||||
|
if (wsaRet != 0)
|
||||||
|
::fprintf(stderr, "Error from WSAStartup\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CUDPSocket::~CUDPSocket()
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::WSACleanup();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
in_addr CUDPSocket::lookup(const std::string& hostname)
|
||||||
|
{
|
||||||
|
in_addr addr;
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
unsigned long address = ::inet_addr(hostname.c_str());
|
||||||
|
if (address != INADDR_NONE && address != INADDR_ANY) {
|
||||||
|
addr.s_addr = address;
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct hostent* hp = ::gethostbyname(hostname.c_str());
|
||||||
|
if (hp != NULL) {
|
||||||
|
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
::fprintf(stderr, "Cannot find address for host %s\n", hostname.c_str());
|
||||||
|
|
||||||
|
addr.s_addr = INADDR_NONE;
|
||||||
|
return addr;
|
||||||
|
#else
|
||||||
|
in_addr_t address = ::inet_addr(hostname.c_str());
|
||||||
|
if (address != in_addr_t(-1)) {
|
||||||
|
addr.s_addr = address;
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct hostent* hp = ::gethostbyname(hostname.c_str());
|
||||||
|
if (hp != NULL) {
|
||||||
|
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
::fprintf(stderr, "Cannot find address for host %s\n", hostname.c_str());
|
||||||
|
|
||||||
|
addr.s_addr = INADDR_NONE;
|
||||||
|
return addr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CUDPSocket::open()
|
||||||
|
{
|
||||||
|
m_fd = ::socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (m_fd < 0) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::fprintf(stderr, "Cannot create the UDP socket, err: %lu\n", ::GetLastError());
|
||||||
|
#else
|
||||||
|
::fprintf(stderr, "Cannot create the UDP socket, err: %d\n", errno);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_port > 0U) {
|
||||||
|
sockaddr_in addr;
|
||||||
|
::memset(&addr, 0x00, sizeof(sockaddr_in));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(m_port);
|
||||||
|
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
|
||||||
|
if (!m_address.empty()) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
|
||||||
|
#else
|
||||||
|
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
|
||||||
|
#endif
|
||||||
|
if (addr.sin_addr.s_addr == INADDR_NONE) {
|
||||||
|
::fprintf(stderr, "The local address is invalid - %s\n", m_address.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int reuse = 1;
|
||||||
|
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::fprintf(stderr, "Cannot set the UDP socket option, err: %lu\n", ::GetLastError());
|
||||||
|
#else
|
||||||
|
::fprintf(stderr, "Cannot set the UDP socket option, err: %d\n", errno);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::fprintf(stderr, "Cannot bind the UDP address, err: %lu\n", ::GetLastError());
|
||||||
|
#else
|
||||||
|
::fprintf(stderr, "Cannot bind the UDP address, err: %d\n", errno);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port)
|
||||||
|
{
|
||||||
|
assert(buffer != NULL);
|
||||||
|
assert(length > 0U);
|
||||||
|
|
||||||
|
// Check that the readfrom() won't block
|
||||||
|
fd_set readFds;
|
||||||
|
FD_ZERO(&readFds);
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
FD_SET((unsigned int)m_fd, &readFds);
|
||||||
|
#else
|
||||||
|
FD_SET(m_fd, &readFds);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Return immediately
|
||||||
|
timeval tv;
|
||||||
|
tv.tv_sec = 0L;
|
||||||
|
tv.tv_usec = 0L;
|
||||||
|
|
||||||
|
int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv);
|
||||||
|
if (ret < 0) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::fprintf(stderr, "Error returned from UDP select, err: %lu\n", ::GetLastError());
|
||||||
|
#else
|
||||||
|
::fprintf(stderr, "Error returned from UDP select, err: %d\n", errno);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sockaddr_in addr;
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
int size = sizeof(sockaddr_in);
|
||||||
|
#else
|
||||||
|
socklen_t size = sizeof(sockaddr_in);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size);
|
||||||
|
#else
|
||||||
|
ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size);
|
||||||
|
#endif
|
||||||
|
if (len <= 0) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::fprintf(stderr, "Error returned from recvfrom, err: %lu\n", ::GetLastError());
|
||||||
|
#else
|
||||||
|
::fprintf(stderr, "Error returned from recvfrom, err: %d\n", errno);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
address = addr.sin_addr;
|
||||||
|
port = ntohs(addr.sin_port);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port)
|
||||||
|
{
|
||||||
|
assert(buffer != NULL);
|
||||||
|
assert(length > 0U);
|
||||||
|
|
||||||
|
sockaddr_in addr;
|
||||||
|
::memset(&addr, 0x00, sizeof(sockaddr_in));
|
||||||
|
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr = address;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
|
||||||
|
#else
|
||||||
|
ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
|
||||||
|
#endif
|
||||||
|
if (ret < 0) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::fprintf(stderr, "Error returned from sendto, err: %lu\n", ::GetLastError());
|
||||||
|
#else
|
||||||
|
::fprintf(stderr, "Error returned from sendto, err: %d\n", errno);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
if (ret != int(length))
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
if (ret != ssize_t(length))
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUDPSocket::close()
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::closesocket(m_fd);
|
||||||
|
#else
|
||||||
|
::close(m_fd);
|
||||||
|
#endif
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2011,2013,2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UDPSocket_H
|
||||||
|
#define UDPSocket_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#if !defined(_WIN32) && !defined(_WIN64)
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#else
|
||||||
|
#include <winsock.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CUDPSocket {
|
||||||
|
public:
|
||||||
|
CUDPSocket(const std::string& address, unsigned int port = 0U);
|
||||||
|
CUDPSocket(unsigned int port = 0U);
|
||||||
|
~CUDPSocket();
|
||||||
|
|
||||||
|
bool open();
|
||||||
|
|
||||||
|
int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port);
|
||||||
|
bool write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port);
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
|
static in_addr lookup(const std::string& hostName);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_address;
|
||||||
|
unsigned short m_port;
|
||||||
|
int m_fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009,2014,2015,2016 Jonathan Naylor, G4KLX
|
||||||
|
*
|
||||||
|
* 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; version 2 of the License.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
void CUtils::dump(const std::string& title, const unsigned char* data, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
dump(2U, title, data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUtils::dump(int level, const std::string& title, const unsigned char* data, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
::fprintf(stdout, "%s\n", title.c_str());
|
||||||
|
|
||||||
|
unsigned int offset = 0U;
|
||||||
|
|
||||||
|
while (length > 0U) {
|
||||||
|
std::string output;
|
||||||
|
|
||||||
|
unsigned int bytes = (length > 16U) ? 16U : length;
|
||||||
|
|
||||||
|
for (unsigned i = 0U; i < bytes; i++) {
|
||||||
|
char temp[10U];
|
||||||
|
::sprintf(temp, "%02X ", data[offset + i]);
|
||||||
|
output += temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = bytes; i < 16U; i++)
|
||||||
|
output += " ";
|
||||||
|
|
||||||
|
output += " *";
|
||||||
|
|
||||||
|
for (unsigned i = 0U; i < bytes; i++) {
|
||||||
|
unsigned char c = data[offset + i];
|
||||||
|
|
||||||
|
if (::isprint(c))
|
||||||
|
output += c;
|
||||||
|
else
|
||||||
|
output += '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
output += '*';
|
||||||
|
|
||||||
|
::fprintf(stdout, "%04X: %s\n", offset, output.c_str());
|
||||||
|
|
||||||
|
offset += 16U;
|
||||||
|
|
||||||
|
if (length >= 16U)
|
||||||
|
length -= 16U;
|
||||||
|
else
|
||||||
|
length = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUtils::dump(const std::string& title, const bool* bits, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(bits != NULL);
|
||||||
|
|
||||||
|
dump(2U, title, bits, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUtils::dump(int level, const std::string& title, const bool* bits, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(bits != NULL);
|
||||||
|
|
||||||
|
unsigned char bytes[100U];
|
||||||
|
unsigned int nBytes = 0U;
|
||||||
|
for (unsigned int n = 0U; n < length; n += 8U, nBytes++)
|
||||||
|
bitsToByteBE(bits + n, bytes[nBytes]);
|
||||||
|
|
||||||
|
dump(level, title, bytes, nBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUtils::byteToBitsBE(unsigned char byte, bool* bits)
|
||||||
|
{
|
||||||
|
assert(bits != NULL);
|
||||||
|
|
||||||
|
bits[0U] = (byte & 0x80U) == 0x80U;
|
||||||
|
bits[1U] = (byte & 0x40U) == 0x40U;
|
||||||
|
bits[2U] = (byte & 0x20U) == 0x20U;
|
||||||
|
bits[3U] = (byte & 0x10U) == 0x10U;
|
||||||
|
bits[4U] = (byte & 0x08U) == 0x08U;
|
||||||
|
bits[5U] = (byte & 0x04U) == 0x04U;
|
||||||
|
bits[6U] = (byte & 0x02U) == 0x02U;
|
||||||
|
bits[7U] = (byte & 0x01U) == 0x01U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUtils::byteToBitsLE(unsigned char byte, bool* bits)
|
||||||
|
{
|
||||||
|
assert(bits != NULL);
|
||||||
|
|
||||||
|
bits[0U] = (byte & 0x01U) == 0x01U;
|
||||||
|
bits[1U] = (byte & 0x02U) == 0x02U;
|
||||||
|
bits[2U] = (byte & 0x04U) == 0x04U;
|
||||||
|
bits[3U] = (byte & 0x08U) == 0x08U;
|
||||||
|
bits[4U] = (byte & 0x10U) == 0x10U;
|
||||||
|
bits[5U] = (byte & 0x20U) == 0x20U;
|
||||||
|
bits[6U] = (byte & 0x40U) == 0x40U;
|
||||||
|
bits[7U] = (byte & 0x80U) == 0x80U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUtils::bitsToByteBE(const bool* bits, unsigned char& byte)
|
||||||
|
{
|
||||||
|
assert(bits != NULL);
|
||||||
|
|
||||||
|
byte = bits[0U] ? 0x80U : 0x00U;
|
||||||
|
byte |= bits[1U] ? 0x40U : 0x00U;
|
||||||
|
byte |= bits[2U] ? 0x20U : 0x00U;
|
||||||
|
byte |= bits[3U] ? 0x10U : 0x00U;
|
||||||
|
byte |= bits[4U] ? 0x08U : 0x00U;
|
||||||
|
byte |= bits[5U] ? 0x04U : 0x00U;
|
||||||
|
byte |= bits[6U] ? 0x02U : 0x00U;
|
||||||
|
byte |= bits[7U] ? 0x01U : 0x00U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUtils::bitsToByteLE(const bool* bits, unsigned char& byte)
|
||||||
|
{
|
||||||
|
assert(bits != NULL);
|
||||||
|
|
||||||
|
byte = bits[0U] ? 0x01U : 0x00U;
|
||||||
|
byte |= bits[1U] ? 0x02U : 0x00U;
|
||||||
|
byte |= bits[2U] ? 0x04U : 0x00U;
|
||||||
|
byte |= bits[3U] ? 0x08U : 0x00U;
|
||||||
|
byte |= bits[4U] ? 0x10U : 0x00U;
|
||||||
|
byte |= bits[5U] ? 0x20U : 0x00U;
|
||||||
|
byte |= bits[6U] ? 0x40U : 0x00U;
|
||||||
|
byte |= bits[7U] ? 0x80U : 0x00U;
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009,2014,2015 by Jonathan Naylor, G4KLX
|
||||||
|
*
|
||||||
|
* 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; version 2 of the License.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef Utils_H
|
||||||
|
#define Utils_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CUtils {
|
||||||
|
public:
|
||||||
|
static void dump(const std::string& title, const unsigned char* data, unsigned int length);
|
||||||
|
static void dump(int level, const std::string& title, const unsigned char* data, unsigned int length);
|
||||||
|
|
||||||
|
static void dump(const std::string& title, const bool* bits, unsigned int length);
|
||||||
|
static void dump(int level, const std::string& title, const bool* bits, unsigned int length);
|
||||||
|
|
||||||
|
static void byteToBitsBE(unsigned char byte, bool* bits);
|
||||||
|
static void byteToBitsLE(unsigned char byte, bool* bits);
|
||||||
|
|
||||||
|
static void bitsToByteBE(const bool* bits, unsigned char& byte);
|
||||||
|
static void bitsToByteLE(const bool* bits, unsigned char& byte);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(YSFDefines_H)
|
||||||
|
#define YSFDefines_H
|
||||||
|
|
||||||
|
const unsigned int YSF_FRAME_LENGTH_BYTES = 120U;
|
||||||
|
|
||||||
|
const unsigned char YSF_SYNC_BYTES[] = {0xD4U, 0x71U, 0xC9U, 0x63U, 0x4DU};
|
||||||
|
const unsigned int YSF_SYNC_LENGTH_BYTES = 5U;
|
||||||
|
|
||||||
|
const unsigned int YSF_FICH_LENGTH_BYTES = 25U;
|
||||||
|
|
||||||
|
const unsigned char YSF_SYNC_OK = 0x01U;
|
||||||
|
|
||||||
|
const unsigned int YSF_CALLSIGN_LENGTH = 10U;
|
||||||
|
|
||||||
|
const unsigned char YSF_FI_HEADER = 0x00U;
|
||||||
|
const unsigned char YSF_FI_COMMUNICATIONS = 0x01U;
|
||||||
|
const unsigned char YSF_FI_TERMINATOR = 0x02U;
|
||||||
|
const unsigned char YSF_FI_TEST = 0x03U;
|
||||||
|
|
||||||
|
const unsigned char YSF_DT_VD_MODE1 = 0x00U;
|
||||||
|
const unsigned char YSF_DT_DATA_FR_MODE = 0x01U;
|
||||||
|
const unsigned char YSF_DT_VD_MODE2 = 0x02U;
|
||||||
|
const unsigned char YSF_DT_VOICE_FR_MODE = 0x03U;
|
||||||
|
|
||||||
|
const unsigned char YSF_CM_GROUP = 0x00U;
|
||||||
|
const unsigned char YSF_CM_INDIVIDUAL = 0x03U;
|
||||||
|
|
||||||
|
const unsigned char YSF_MR_NOT_BUSY = 0x01U;
|
||||||
|
const unsigned char YSF_MR_BUSY = 0x02U;
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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 "YSFReflector.h"
|
||||||
|
#include "StopWatch.h"
|
||||||
|
#include "Network.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if (argc == 1) {
|
||||||
|
::fprintf(stderr, "Usage: YSFReflector <port>\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int port = ::atoi(argv[1]);
|
||||||
|
if (port == 0U) {
|
||||||
|
::fprintf(stderr, "YSFReflector: invalid port number\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CYSFReflector Reflector(port);
|
||||||
|
Reflector.run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CYSFReflector::CYSFReflector(unsigned int port) :
|
||||||
|
m_port(port),
|
||||||
|
m_repeaters()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CYSFReflector::~CYSFReflector()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CYSFReflector::run()
|
||||||
|
{
|
||||||
|
CNetwork network(m_port, false);
|
||||||
|
|
||||||
|
bool ret = network.open();
|
||||||
|
if (!ret)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CStopWatch stopWatch;
|
||||||
|
stopWatch.start();
|
||||||
|
|
||||||
|
CTimer pollTimer(1000U, 60U);
|
||||||
|
pollTimer.start();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
unsigned char buffer[200U];
|
||||||
|
|
||||||
|
unsigned int len = network.readData(buffer);
|
||||||
|
if (len > 0U) {
|
||||||
|
std::string callsign = std::string((char*)(buffer + 4U), YSF_CALLSIGN_LENGTH);
|
||||||
|
CYSFRepeater* rpt = findRepeater(callsign);
|
||||||
|
if (rpt != NULL) {
|
||||||
|
for (auto it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
|
||||||
|
if ((*it)->m_callsign != callsign)
|
||||||
|
network.writeData(buffer, (*it)->m_address, (*it)->m_port);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
::fprintf(stdout, "Data received from an unknown repeater - %s\n", callsign.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh/add repeaters based on their polls
|
||||||
|
std::string callsign;
|
||||||
|
in_addr address;
|
||||||
|
unsigned int port;
|
||||||
|
bool ret = network.readPoll(callsign, address, port);
|
||||||
|
if (ret) {
|
||||||
|
CYSFRepeater* rpt = findRepeater(callsign);
|
||||||
|
if (rpt == NULL) {
|
||||||
|
::fprintf(stdout, "Adding %s\n", callsign.c_str());
|
||||||
|
rpt = new CYSFRepeater;
|
||||||
|
rpt->m_timer.start();
|
||||||
|
rpt->m_callsign = callsign;
|
||||||
|
rpt->m_address = address;
|
||||||
|
rpt->m_port = port;
|
||||||
|
m_repeaters.push_back(rpt);
|
||||||
|
} else {
|
||||||
|
rpt->m_timer.start();
|
||||||
|
rpt->m_address = address;
|
||||||
|
rpt->m_port = port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ms = stopWatch.elapsed();
|
||||||
|
stopWatch.start();
|
||||||
|
|
||||||
|
network.clock(ms);
|
||||||
|
|
||||||
|
pollTimer.clock(ms);
|
||||||
|
if (pollTimer.hasExpired()) {
|
||||||
|
for (auto it = m_repeaters.begin(); it != m_repeaters.end(); ++it)
|
||||||
|
network.writePoll((*it)->m_address, (*it)->m_port);
|
||||||
|
pollTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any repeaters that haven't reported for a while
|
||||||
|
for (auto it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
|
||||||
|
(*it)->m_timer.clock(ms);
|
||||||
|
if ((*it)->m_timer.hasExpired()) {
|
||||||
|
::fprintf(stdout, "Removing %s\n", (*it)->m_callsign.c_str());
|
||||||
|
m_repeaters.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ms < 5U) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::Sleep(5UL); // 5ms
|
||||||
|
#else
|
||||||
|
::usleep(5000); // 5ms
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
network.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
CYSFRepeater* CYSFReflector::findRepeater(const std::string& callsign) const
|
||||||
|
{
|
||||||
|
for (auto it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
|
||||||
|
if ((*it)->m_callsign == callsign)
|
||||||
|
return *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(YSFReflector_H)
|
||||||
|
#define YSFReflector_H
|
||||||
|
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
|
#if !defined(_WIN32) && !defined(_WIN64)
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#else
|
||||||
|
#include <winsock.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class CYSFRepeater {
|
||||||
|
public:
|
||||||
|
CYSFRepeater() :
|
||||||
|
m_callsign(),
|
||||||
|
m_address(),
|
||||||
|
m_port(0U),
|
||||||
|
m_timer(1000U, 300U)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string m_callsign;
|
||||||
|
in_addr m_address;
|
||||||
|
unsigned int m_port;
|
||||||
|
CTimer m_timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CYSFReflector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CYSFReflector(unsigned int port);
|
||||||
|
~CYSFReflector();
|
||||||
|
|
||||||
|
void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int m_port;
|
||||||
|
std::vector<CYSFRepeater*> m_repeaters;
|
||||||
|
|
||||||
|
CYSFRepeater* findRepeater(const std::string& callsign) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,59 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="Network.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Timer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="UDPSocket.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Utils.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="YSFDefines.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="YSFReflector.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="RingBuffer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="StopWatch.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Network.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Timer.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="UDPSocket.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Utils.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="YSFReflector.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="StopWatch.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
Loading…
Reference in new issue