mirror of
https://github.com/g4klx/DMRGateway.git
synced 2026-02-07 07:54:22 +01:00
Add experimental RT8 GPS data handling.
This commit is contained in:
parent
8bc79767c5
commit
aa063ff205
111
APRSHelper.cpp
Normal file
111
APRSHelper.cpp
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright (C) 2017 Tony Bailey
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
************************************************************
|
||||
*
|
||||
* A wrapper class for the APRS utilities send GPS data to an APRS server
|
||||
*
|
||||
*/
|
||||
|
||||
#include "APRSHelper.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
CAPRSHelper::CAPRSHelper(const std::string& callsign, const std::string& suffix, const std::string& password, const std::string& address, unsigned int port)
|
||||
:
|
||||
m_writer(callsign, suffix, password, address, port),
|
||||
m_buffer(NULL)
|
||||
{
|
||||
m_buffer = new unsigned char[300U];
|
||||
}
|
||||
|
||||
CAPRSHelper::~CAPRSHelper()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
}
|
||||
|
||||
bool CAPRSHelper::open()
|
||||
{
|
||||
return m_writer.open();
|
||||
}
|
||||
|
||||
void CAPRSHelper::send(std::string callsign, float latitude, float longitude, int altitude )
|
||||
{
|
||||
unsigned char source[10U];
|
||||
copy( callsign.begin(), callsign.end(), source );
|
||||
|
||||
char type[11U];
|
||||
::strcpy(type, "MD-390/RT8");
|
||||
|
||||
// Source: Callsign
|
||||
// Type: Radio Type
|
||||
// symbol?:
|
||||
// default (unset) is a House '/-'
|
||||
// 0x24U
|
||||
// 0x25U
|
||||
// 0x26U - ??
|
||||
// 0x28U - Human
|
||||
// 0x29U - Normal Car '/>'
|
||||
// lat
|
||||
// long
|
||||
//::sprintf(m_buffer[4U], 0x28U);
|
||||
m_writer.write(source, type, 0x28U, latitude, longitude, altitude);
|
||||
}
|
||||
|
||||
void CAPRSHelper::close()
|
||||
{
|
||||
m_writer.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* Uncomment this section for local testing and build it without MMDVMHost in the Makefile
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
int main(void)
|
||||
{
|
||||
std::string callsign = "N9OTJ";
|
||||
std::string suffix = "11";
|
||||
std::string password = "14479";
|
||||
std::string address = "aprs.mcducklabs.com";
|
||||
int port = 14580;
|
||||
CAPRSHelper* helper = new CAPRSHelper(callsign, suffix, password, address, port);
|
||||
|
||||
helper->open();
|
||||
// Wait 6 seconds for the server to connect before sending data
|
||||
usleep(1000*1000*6);
|
||||
|
||||
// Send the GPS packet
|
||||
helper->send();
|
||||
|
||||
// Need to go into an endless loop and give the APRSWriterThread time to cycle through the message queue
|
||||
for (;;)
|
||||
{
|
||||
// Ctrl-C out of the test program once the packet is sent
|
||||
}
|
||||
|
||||
delete helper;
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
42
APRSHelper.h
Normal file
42
APRSHelper.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2017 by Tony Bailey
|
||||
*
|
||||
* 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(APRSHelper_H)
|
||||
#define APRSHelper_H
|
||||
|
||||
#include "APRSWriter.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class CAPRSHelper {
|
||||
public:
|
||||
CAPRSHelper(const std::string& callsign, const std::string& suffix, const std::string& password, const std::string& address, unsigned int port);
|
||||
~CAPRSHelper();
|
||||
|
||||
bool open();
|
||||
|
||||
void send(std::string callsign, float latitude, float longitude, int altitude);
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
CAPRSWriter m_writer;
|
||||
unsigned char* m_buffer;
|
||||
};
|
||||
|
||||
#endif
|
||||
202
APRSWriter.cpp
Normal file
202
APRSWriter.cpp
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* Copyright (C) 2010-2014,2016,2017 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 "APRSWriter.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
CAPRSWriter::CAPRSWriter(const std::string& callsign, const std::string& suffix, const std::string& password, const std::string& address, unsigned int port) :
|
||||
m_thread(NULL),
|
||||
m_enabled(false),
|
||||
m_idTimer(1000U, 20U * 60U), // 20 minutes
|
||||
m_callsign(callsign),
|
||||
m_txFrequency(0U),
|
||||
m_rxFrequency(0U),
|
||||
m_latitude(0.0F),
|
||||
m_longitude(0.0F),
|
||||
m_height(0)
|
||||
{
|
||||
assert(!callsign.empty());
|
||||
assert(!password.empty());
|
||||
assert(!address.empty());
|
||||
assert(port > 0U);
|
||||
|
||||
if (!suffix.empty()) {
|
||||
m_callsign.append("-");
|
||||
m_callsign.append(suffix.substr(0U, 2U));
|
||||
}
|
||||
|
||||
m_thread = new CAPRSWriterThread(m_callsign, password, address, port);
|
||||
}
|
||||
|
||||
CAPRSWriter::~CAPRSWriter()
|
||||
{
|
||||
}
|
||||
|
||||
void CAPRSWriter::setInfo(unsigned int txFrequency, unsigned int rxFrequency, float latitude, float longitude, int height)
|
||||
{
|
||||
m_txFrequency = txFrequency;
|
||||
m_rxFrequency = rxFrequency;
|
||||
m_latitude = latitude;
|
||||
m_longitude = longitude;
|
||||
m_height = height;
|
||||
}
|
||||
|
||||
bool CAPRSWriter::open()
|
||||
{
|
||||
return m_thread->start();
|
||||
}
|
||||
|
||||
void CAPRSWriter::write(const unsigned char* source, const char* type, unsigned char radio, float fLatitude, float fLongitude, int altitude)
|
||||
{
|
||||
assert(source != NULL);
|
||||
assert(type != NULL);
|
||||
|
||||
char callsign[11U];
|
||||
::memcpy(callsign, source, 10U);
|
||||
callsign[10U] = 0x00U;
|
||||
|
||||
size_t n = ::strspn(callsign, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
|
||||
callsign[n] = 0x00U;
|
||||
|
||||
double tempLat = ::fabs(fLatitude);
|
||||
double tempLong = ::fabs(fLongitude);
|
||||
|
||||
double latitude = ::floor(tempLat);
|
||||
double longitude = ::floor(tempLong);
|
||||
|
||||
latitude = (tempLat - latitude) * 60.0 + latitude * 100.0;
|
||||
longitude = (tempLong - longitude) * 60.0 + longitude * 100.0;
|
||||
|
||||
char lat[20U];
|
||||
::sprintf(lat, "%07.2lf", latitude);
|
||||
|
||||
char lon[20U];
|
||||
::sprintf(lon, "%08.2lf", longitude);
|
||||
|
||||
char symbol;
|
||||
switch (radio) {
|
||||
case 0x24U:
|
||||
case 0x28U:
|
||||
symbol = '[';
|
||||
break;
|
||||
case 0x25U:
|
||||
case 0x29U:
|
||||
symbol = '>';
|
||||
break;
|
||||
case 0x26U:
|
||||
symbol = 'r';
|
||||
break;
|
||||
default:
|
||||
symbol = '-';
|
||||
break;
|
||||
}
|
||||
|
||||
char output[300U];
|
||||
::sprintf(output, "%s-D>APDPRS,DMR*,qAR,%s:!%s%c/%s%c%c/A=%06.0f %s via MMDVM",
|
||||
callsign, m_callsign.c_str(),
|
||||
lat, (fLatitude < 0.0F) ? 'S' : 'N',
|
||||
lon, (fLongitude < 0.0F) ? 'W' : 'E',
|
||||
symbol, float(altitude) * 3.28F, type);
|
||||
|
||||
m_thread->write(output);
|
||||
}
|
||||
|
||||
void CAPRSWriter::clock(unsigned int ms)
|
||||
{
|
||||
m_idTimer.clock(ms);
|
||||
|
||||
if (m_idTimer.hasExpired()) {
|
||||
sendIdFrames();
|
||||
m_idTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
void CAPRSWriter::close()
|
||||
{
|
||||
m_thread->stop();
|
||||
}
|
||||
|
||||
void CAPRSWriter::sendIdFrames()
|
||||
{
|
||||
if (!m_thread->isConnected())
|
||||
return;
|
||||
|
||||
// Default values aren't passed on
|
||||
if (m_latitude == 0.0F && m_longitude == 0.0F)
|
||||
return;
|
||||
|
||||
char desc[100U];
|
||||
if (m_txFrequency != 0U) {
|
||||
float offset = float(int(m_rxFrequency) - int(m_txFrequency)) / 1000000.0F;
|
||||
::sprintf(desc, "MMDVM Voice %.5lfMHz %c%.4lfMHz",
|
||||
float(m_txFrequency) / 1000000.0F,
|
||||
offset < 0.0F ? '-' : '+',
|
||||
::fabs(offset));
|
||||
} else {
|
||||
::strcpy(desc, "MMDVM Voice");
|
||||
}
|
||||
|
||||
const char* band = "4m";
|
||||
if (m_txFrequency >= 1200000000U)
|
||||
band = "1.2";
|
||||
else if (m_txFrequency >= 420000000U)
|
||||
band = "440";
|
||||
else if (m_txFrequency >= 144000000U)
|
||||
band = "2m";
|
||||
else if (m_txFrequency >= 50000000U)
|
||||
band = "6m";
|
||||
else if (m_txFrequency >= 28000000U)
|
||||
band = "10m";
|
||||
|
||||
double tempLat = ::fabs(m_latitude);
|
||||
double tempLong = ::fabs(m_longitude);
|
||||
|
||||
double latitude = ::floor(tempLat);
|
||||
double longitude = ::floor(tempLong);
|
||||
|
||||
latitude = (tempLat - latitude) * 60.0 + latitude * 100.0;
|
||||
longitude = (tempLong - longitude) * 60.0 + longitude * 100.0;
|
||||
|
||||
char lat[20U];
|
||||
::sprintf(lat, "%04.2lf", latitude);
|
||||
|
||||
char lon[20U];
|
||||
::sprintf(lon, "%05.2lf", longitude);
|
||||
|
||||
std::string server = m_callsign;
|
||||
size_t pos = server.find_first_of('-');
|
||||
if (pos == std::string::npos)
|
||||
server.append("-S");
|
||||
else
|
||||
server.append("S");
|
||||
|
||||
char output[500U];
|
||||
::sprintf(output, "%s>APDG03,TCPIP*,qAC,%s:!%s%cD%s%c&/A=%06.0f%s %s",
|
||||
m_callsign.c_str(), server.c_str(),
|
||||
lat, (m_latitude < 0.0F) ? 'S' : 'N',
|
||||
lon, (m_longitude < 0.0F) ? 'W' : 'E',
|
||||
float(m_height) * 3.28F, band, desc);
|
||||
|
||||
m_thread->write(output);
|
||||
|
||||
m_idTimer.start();
|
||||
}
|
||||
56
APRSWriter.h
Normal file
56
APRSWriter.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (C) 2010,2011,2012,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 APRSWriter_H
|
||||
#define APRSWriter_H
|
||||
|
||||
#include "APRSWriterThread.h"
|
||||
#include "Timer.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class CAPRSWriter {
|
||||
public:
|
||||
CAPRSWriter(const std::string& callsign, const std::string& suffix, const std::string& password, const std::string& address, unsigned int port);
|
||||
~CAPRSWriter();
|
||||
|
||||
bool open();
|
||||
|
||||
void setInfo(unsigned int txFrequency, unsigned int rxFrequency, float latitude, float longitude, int height);
|
||||
|
||||
void write(const unsigned char* source, const char* type, unsigned char radio, float latitude, float longitude, int altitude);
|
||||
|
||||
void clock(unsigned int ms);
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
CAPRSWriterThread* m_thread;
|
||||
bool m_enabled;
|
||||
CTimer m_idTimer;
|
||||
std::string m_callsign;
|
||||
unsigned int m_txFrequency;
|
||||
unsigned int m_rxFrequency;
|
||||
float m_latitude;
|
||||
float m_longitude;
|
||||
int m_height;
|
||||
|
||||
void sendIdFrames();
|
||||
};
|
||||
|
||||
#endif
|
||||
248
APRSWriterThread.cpp
Normal file
248
APRSWriterThread.cpp
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* Copyright (C) 2010-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 "APRSWriterThread.h"
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <cctype>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
// #define DUMP_TX
|
||||
|
||||
const unsigned int CALLSIGN_LENGTH = 8U;
|
||||
|
||||
const unsigned int APRS_TIMEOUT = 10U;
|
||||
|
||||
CAPRSWriterThread::CAPRSWriterThread(const std::string& callsign, const std::string& password, const std::string& address, unsigned int port) :
|
||||
CThread(),
|
||||
m_username(callsign),
|
||||
m_password(password),
|
||||
m_socket(address, port),
|
||||
m_queue(20U, "APRS Queue"),
|
||||
m_exit(false),
|
||||
m_connected(false),
|
||||
m_APRSReadCallback(NULL),
|
||||
m_filter(),
|
||||
m_clientName("DMRGateway")
|
||||
{
|
||||
assert(!callsign.empty());
|
||||
assert(!password.empty());
|
||||
assert(!address.empty());
|
||||
assert(port > 0U);
|
||||
|
||||
m_username.resize(CALLSIGN_LENGTH, ' ');
|
||||
m_username.erase(std::find_if(m_username.rbegin(), m_username.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), m_username.end());
|
||||
std::transform(m_username.begin(), m_username.end(), m_username.begin(), ::toupper);
|
||||
}
|
||||
|
||||
CAPRSWriterThread::CAPRSWriterThread(const std::string& callsign, const std::string& password, const std::string& address, unsigned int port, const std::string& filter, const std::string& clientName) :
|
||||
CThread(),
|
||||
m_username(callsign),
|
||||
m_password(password),
|
||||
m_socket(address, port),
|
||||
m_queue(20U, "APRS Queue"),
|
||||
m_exit(false),
|
||||
m_connected(false),
|
||||
m_APRSReadCallback(NULL),
|
||||
m_filter(filter),
|
||||
m_clientName(clientName)
|
||||
{
|
||||
assert(!callsign.empty());
|
||||
assert(!password.empty());
|
||||
assert(!address.empty());
|
||||
assert(port > 0U);
|
||||
|
||||
m_username.resize(CALLSIGN_LENGTH, ' ');
|
||||
m_username.erase(std::find_if(m_username.rbegin(), m_username.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), m_username.end());
|
||||
std::transform(m_username.begin(), m_username.end(), m_username.begin(), ::toupper);
|
||||
}
|
||||
|
||||
CAPRSWriterThread::~CAPRSWriterThread()
|
||||
{
|
||||
m_username.clear();
|
||||
}
|
||||
|
||||
bool CAPRSWriterThread::start()
|
||||
{
|
||||
run();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CAPRSWriterThread::entry()
|
||||
{
|
||||
LogMessage("Starting the APRS Writer thread");
|
||||
|
||||
m_connected = connect();
|
||||
|
||||
try {
|
||||
while (!m_exit) {
|
||||
if (!m_connected) {
|
||||
m_connected = connect();
|
||||
|
||||
if (!m_connected){
|
||||
LogError("Reconnect attempt to the APRS server has failed");
|
||||
sleep(10000UL); // 10 secs
|
||||
}
|
||||
}
|
||||
|
||||
if (m_connected) {
|
||||
if (!m_queue.isEmpty()){
|
||||
char* p = NULL;
|
||||
m_queue.getData(&p, 1U);
|
||||
|
||||
LogMessage("APRS ==> %s", p);
|
||||
|
||||
::strcat(p, "\r\n");
|
||||
|
||||
bool ret = m_socket.write((unsigned char*)p, ::strlen(p));
|
||||
if (!ret) {
|
||||
m_connected = false;
|
||||
m_socket.close();
|
||||
LogError("Connection to the APRS thread has failed");
|
||||
}
|
||||
|
||||
delete[] p;
|
||||
}
|
||||
{
|
||||
std::string line;
|
||||
int length = m_socket.readLine(line, APRS_TIMEOUT);
|
||||
|
||||
if (length < 0) {
|
||||
m_connected = false;
|
||||
m_socket.close();
|
||||
LogError("Error when reading from the APRS server");
|
||||
}
|
||||
|
||||
if(length > 0 && line.at(0U) != '#'//check if we have something and if that something is an APRS frame
|
||||
&& m_APRSReadCallback != NULL)//do we have someone wanting an APRS Frame?
|
||||
{
|
||||
//wxLogMessage(wxT("Received APRS Frame : ") + line);
|
||||
m_APRSReadCallback(std::string(line));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (m_connected)
|
||||
m_socket.close();
|
||||
|
||||
while (!m_queue.isEmpty()) {
|
||||
char* p = NULL;
|
||||
m_queue.getData(&p, 1U);
|
||||
delete[] p;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
LogError("Exception raised in the APRS Writer thread - \"%s\"", e.what());
|
||||
}
|
||||
catch (...) {
|
||||
LogError("Unknown exception raised in the APRS Writer thread");
|
||||
}
|
||||
|
||||
LogMessage("Stopping the APRS Writer thread");
|
||||
}
|
||||
|
||||
void CAPRSWriterThread::setReadAPRSCallback(ReadAPRSFrameCallback cb)
|
||||
{
|
||||
m_APRSReadCallback = cb;
|
||||
}
|
||||
|
||||
void CAPRSWriterThread::write(const char* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
if (!m_connected)
|
||||
return;
|
||||
|
||||
unsigned int len = ::strlen(data);
|
||||
|
||||
char* p = new char[len + 5U];
|
||||
::strcpy(p, data);
|
||||
|
||||
m_queue.addData(&p, 1U);
|
||||
}
|
||||
|
||||
bool CAPRSWriterThread::isConnected() const
|
||||
{
|
||||
return m_connected;
|
||||
}
|
||||
|
||||
void CAPRSWriterThread::stop()
|
||||
{
|
||||
m_exit = true;
|
||||
|
||||
wait();
|
||||
}
|
||||
|
||||
bool CAPRSWriterThread::connect()
|
||||
{
|
||||
bool ret = m_socket.open();
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
//wait for lgin banner
|
||||
int length;
|
||||
std::string serverResponse;
|
||||
length = m_socket.readLine(serverResponse, APRS_TIMEOUT);
|
||||
if (length == 0) {
|
||||
LogError("No reply from the APRS server after %u seconds", APRS_TIMEOUT);
|
||||
m_socket.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
LogMessage("Received login banner : %s", serverResponse.c_str());
|
||||
|
||||
std::string filter(m_filter);
|
||||
if (filter.length() > 0)
|
||||
filter.insert(0U, " filter ");
|
||||
|
||||
char connectString[200U];
|
||||
::sprintf(connectString, "user %s pass %s vers %s%s\n", m_username.c_str(), m_password.c_str(), (m_clientName.length() ? m_clientName : "YSFGateway").c_str(), filter.c_str());
|
||||
|
||||
ret = m_socket.writeLine(std::string(connectString));
|
||||
if (!ret) {
|
||||
m_socket.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
length = m_socket.readLine(serverResponse, APRS_TIMEOUT);
|
||||
if (length == 0) {
|
||||
LogError("No reply from the APRS server after %u seconds", APRS_TIMEOUT);
|
||||
m_socket.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (length < 0) {
|
||||
LogError("Error when reading from the APRS server");
|
||||
m_socket.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
LogMessage("Response from APRS server: %s", serverResponse.c_str());
|
||||
|
||||
LogMessage("Connected to the APRS server");
|
||||
|
||||
return true;
|
||||
}
|
||||
62
APRSWriterThread.h
Normal file
62
APRSWriterThread.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2010,2011,2012,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 APRSWriterThread_H
|
||||
#define APRSWriterThread_H
|
||||
|
||||
#include "TCPSocket.h"
|
||||
#include "RingBuffer.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
typedef void (*ReadAPRSFrameCallback)(const std::string&);
|
||||
|
||||
class CAPRSWriterThread : public CThread {
|
||||
public:
|
||||
CAPRSWriterThread(const std::string& callsign, const std::string& password, const std::string& address, unsigned int port);
|
||||
CAPRSWriterThread(const std::string& callsign, const std::string& password, const std::string& address, unsigned int port, const std::string& filter, const std::string& clientName);
|
||||
virtual ~CAPRSWriterThread();
|
||||
|
||||
virtual bool start();
|
||||
|
||||
virtual bool isConnected() const;
|
||||
|
||||
virtual void write(const char* data);
|
||||
|
||||
virtual void entry();
|
||||
|
||||
virtual void stop();
|
||||
|
||||
void setReadAPRSCallback(ReadAPRSFrameCallback cb);
|
||||
|
||||
private:
|
||||
std::string m_username;
|
||||
std::string m_password;
|
||||
CTCPSocket m_socket;
|
||||
CRingBuffer<char*> m_queue;
|
||||
bool m_exit;
|
||||
bool m_connected;
|
||||
ReadAPRSFrameCallback m_APRSReadCallback;
|
||||
std::string m_filter;
|
||||
std::string m_clientName;
|
||||
|
||||
bool connect();
|
||||
};
|
||||
|
||||
#endif
|
||||
80
Conf.cpp
80
Conf.cpp
|
|
@ -30,6 +30,8 @@ enum SECTION {
|
|||
SECTION_NONE,
|
||||
SECTION_GENERAL,
|
||||
SECTION_LOG,
|
||||
SECTION_DMRID_LOOKUP,
|
||||
SECTION_APRS_FI,
|
||||
SECTION_VOICE,
|
||||
SECTION_DMR_NETWORK_1,
|
||||
SECTION_DMR_NETWORK_2,
|
||||
|
|
@ -53,6 +55,12 @@ m_logDisplayLevel(0U),
|
|||
m_logFileLevel(0U),
|
||||
m_logFilePath(),
|
||||
m_logFileRoot(),
|
||||
m_dmrIdLookupFile(),
|
||||
m_dmrIdLookupTime(0U),
|
||||
m_aprsEnabled(false),
|
||||
m_aprsServer(),
|
||||
m_aprsPort(0U),
|
||||
m_aprsPassword(),
|
||||
m_dmrNetwork1Enabled(false),
|
||||
m_dmrNetwork1Id(0U),
|
||||
m_dmrNetwork1Address(),
|
||||
|
|
@ -132,6 +140,10 @@ bool CConf::read()
|
|||
section = SECTION_GENERAL;
|
||||
else if (::strncmp(buffer, "[Log]", 5U) == 0)
|
||||
section = SECTION_LOG;
|
||||
else if (::strncmp(buffer, "[DMR Id Lookup]", 15U) == 0)
|
||||
section = SECTION_DMRID_LOOKUP;
|
||||
else if (::strncmp(buffer, "[aprs.fi]", 5U) == 0)
|
||||
section = SECTION_APRS_FI;
|
||||
else if (::strncmp(buffer, "[Voice]", 7U) == 0)
|
||||
section = SECTION_VOICE;
|
||||
else if (::strncmp(buffer, "[XLX Network 1]", 15U) == 0)
|
||||
|
|
@ -159,7 +171,17 @@ bool CConf::read()
|
|||
if (section == SECTION_GENERAL) {
|
||||
if (::strcmp(key, "Daemon") == 0)
|
||||
m_daemon = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "Timeout") == 0)
|
||||
if (::strcmp(key, "Callsign") == 0) {
|
||||
// Convert the callsign to upper case
|
||||
for (unsigned int i = 0U; value[i] != 0; i++)
|
||||
value[i] = ::toupper(value[i]);
|
||||
m_callsign = value;
|
||||
} else if (::strcmp(key, "Suffix") == 0) {
|
||||
// Convert the callsign to upper case
|
||||
for (unsigned int i = 0U; value[i] != 0; i++)
|
||||
value[i] = ::toupper(value[i]);
|
||||
m_suffix = value;
|
||||
}else if (::strcmp(key, "Timeout") == 0)
|
||||
m_timeout = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "RptAddress") == 0)
|
||||
m_rptAddress = value;
|
||||
|
|
@ -180,6 +202,20 @@ bool CConf::read()
|
|||
m_logFileLevel = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "DisplayLevel") == 0)
|
||||
m_logDisplayLevel = (unsigned int)::atoi(value);
|
||||
} else if (section == SECTION_DMRID_LOOKUP) {
|
||||
if (::strcmp(key, "File") == 0)
|
||||
m_dmrIdLookupFile = value;
|
||||
else if (::strcmp(key, "Time") == 0)
|
||||
m_dmrIdLookupTime = (unsigned int)::atoi(value);
|
||||
} else if (section == SECTION_APRS_FI) {
|
||||
if (::strcmp(key, "Enable") == 0)
|
||||
m_aprsEnabled = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "Server") == 0)
|
||||
m_aprsServer = value;
|
||||
else if (::strcmp(key, "Port") == 0)
|
||||
m_aprsPort = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "Password") == 0)
|
||||
m_aprsPassword = value;
|
||||
} else if (section == SECTION_VOICE) {
|
||||
if (::strcmp(key, "Enabled") == 0)
|
||||
m_voiceEnabled = ::atoi(value) == 1;
|
||||
|
|
@ -409,11 +445,22 @@ bool CConf::read()
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string CConf::getCallsign() const
|
||||
{
|
||||
return m_callsign;
|
||||
}
|
||||
|
||||
std::string CConf::getSuffix() const
|
||||
{
|
||||
return m_suffix;
|
||||
}
|
||||
|
||||
bool CConf::getDaemon() const
|
||||
{
|
||||
return m_daemon;
|
||||
}
|
||||
|
||||
|
||||
std::string CConf::getRptAddress() const
|
||||
{
|
||||
return m_rptAddress;
|
||||
|
|
@ -464,6 +511,37 @@ std::string CConf::getLogFileRoot() const
|
|||
return m_logFileRoot;
|
||||
}
|
||||
|
||||
std::string CConf::getDMRIdLookupFile() const
|
||||
{
|
||||
return m_dmrIdLookupFile;
|
||||
}
|
||||
|
||||
unsigned int CConf::getDMRIdLookupTime() const
|
||||
{
|
||||
return m_dmrIdLookupTime;
|
||||
}
|
||||
|
||||
bool CConf::getAPRSEnabled() const
|
||||
{
|
||||
return m_aprsEnabled;
|
||||
}
|
||||
|
||||
std::string CConf::getAPRSServer() const
|
||||
{
|
||||
return m_aprsServer;
|
||||
}
|
||||
|
||||
unsigned int CConf::getAPRSPort() const
|
||||
{
|
||||
return m_aprsPort;
|
||||
}
|
||||
|
||||
std::string CConf::getAPRSPassword() const
|
||||
{
|
||||
return m_aprsPassword;
|
||||
}
|
||||
|
||||
|
||||
bool CConf::getVoiceEnabled() const
|
||||
{
|
||||
return m_voiceEnabled;
|
||||
|
|
|
|||
23
Conf.h
23
Conf.h
|
|
@ -62,6 +62,8 @@ public:
|
|||
bool read();
|
||||
|
||||
// The General section
|
||||
std::string getCallsign() const;
|
||||
std::string getSuffix() const;
|
||||
bool getDaemon() const;
|
||||
unsigned int getTimeout() const;
|
||||
std::string getRptAddress() const;
|
||||
|
|
@ -76,6 +78,17 @@ public:
|
|||
std::string getLogFilePath() const;
|
||||
std::string getLogFileRoot() const;
|
||||
|
||||
// The DMR Id section
|
||||
std::string getDMRIdLookupFile() const;
|
||||
unsigned int getDMRIdLookupTime() const;
|
||||
|
||||
|
||||
// The aprs.fi section
|
||||
bool getAPRSEnabled() const;
|
||||
std::string getAPRSServer() const;
|
||||
unsigned int getAPRSPort() const;
|
||||
std::string getAPRSPassword() const;
|
||||
|
||||
// The Voice section
|
||||
bool getVoiceEnabled() const;
|
||||
std::string getVoiceLanguage() const;
|
||||
|
|
@ -143,6 +156,8 @@ public:
|
|||
|
||||
private:
|
||||
std::string m_file;
|
||||
std:: string m_callsign;
|
||||
std:: string m_suffix;
|
||||
bool m_daemon;
|
||||
std::string m_rptAddress;
|
||||
unsigned int m_rptPort;
|
||||
|
|
@ -160,6 +175,14 @@ private:
|
|||
std::string m_logFilePath;
|
||||
std::string m_logFileRoot;
|
||||
|
||||
std::string m_dmrIdLookupFile;
|
||||
unsigned int m_dmrIdLookupTime;
|
||||
|
||||
bool m_aprsEnabled;
|
||||
std::string m_aprsServer;
|
||||
unsigned int m_aprsPort;
|
||||
std::string m_aprsPassword;
|
||||
|
||||
bool m_dmrNetwork1Enabled;
|
||||
unsigned int m_dmrNetwork1Id;
|
||||
std::string m_dmrNetwork1Address;
|
||||
|
|
|
|||
106
DMRGateway.cpp
106
DMRGateway.cpp
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
||||
* MD-390/RT8 Modifications (C) 2017, John Ronan, EI7IG
|
||||
*
|
||||
* 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
|
||||
|
|
@ -32,6 +33,9 @@
|
|||
#include "Sync.h"
|
||||
#include "Log.h"
|
||||
#include "GitVersion.h"
|
||||
#include "BPTC19696.h"
|
||||
#include "APRSHelper.h"
|
||||
#include "DMRLookup.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
|
@ -58,6 +62,8 @@ const unsigned char COLOR_CODE = 3U;
|
|||
static bool m_killed = false;
|
||||
static int m_signal = 0;
|
||||
|
||||
CDMRLookup* m_lookup = NULL;
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
static void sigHandler(int signum)
|
||||
{
|
||||
|
|
@ -126,7 +132,9 @@ int main(int argc, char** argv)
|
|||
}
|
||||
|
||||
CDMRGateway::CDMRGateway(const std::string& confFile) :
|
||||
m_callsign(),
|
||||
m_conf(confFile),
|
||||
m_aprsHelper(NULL),
|
||||
m_repeater(NULL),
|
||||
m_dmrNetwork1(NULL),
|
||||
m_dmrNetwork2(NULL),
|
||||
|
|
@ -153,7 +161,8 @@ m_xlx2Rewrite(NULL),
|
|||
m_dmr1NetRewrites(),
|
||||
m_dmr1RFRewrites(),
|
||||
m_dmr2NetRewrites(),
|
||||
m_dmr2RFRewrites()
|
||||
m_dmr2RFRewrites(),
|
||||
m_lookup(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -250,6 +259,8 @@ int CDMRGateway::run()
|
|||
}
|
||||
}
|
||||
#endif
|
||||
m_callsign = m_conf.getCallsign();
|
||||
m_suffix = m_conf.getSuffix();
|
||||
|
||||
LogInfo(HEADER1);
|
||||
LogInfo(HEADER2);
|
||||
|
|
@ -258,7 +269,21 @@ int CDMRGateway::run()
|
|||
|
||||
LogMessage("DMRGateway-%s is starting", VERSION);
|
||||
LogMessage("Built %s %s (GitID #%.7s)", __TIME__, __DATE__, gitversion);
|
||||
|
||||
CDMRGateway::createAPRSHelper();
|
||||
|
||||
// For DMR we try to map IDs to callsigns
|
||||
std::string lookupFile = m_conf.getDMRIdLookupFile();
|
||||
unsigned int reloadTime = m_conf.getDMRIdLookupTime();
|
||||
|
||||
LogInfo("DMR Id Lookups");
|
||||
LogInfo(" File: %s", lookupFile.length() > 0U ? lookupFile.c_str() : "None");
|
||||
if (reloadTime > 0U)
|
||||
LogInfo(" Reload: %u hours", reloadTime);
|
||||
|
||||
m_lookup = new CDMRLookup(lookupFile, reloadTime);
|
||||
m_lookup->read();
|
||||
|
||||
ret = createMMDVM();
|
||||
if (!ret)
|
||||
return 1;
|
||||
|
|
@ -402,6 +427,8 @@ int CDMRGateway::run()
|
|||
|
||||
bool ret = m_repeater->read(data);
|
||||
if (ret) {
|
||||
extractGPSData(data);
|
||||
|
||||
unsigned int slotNo = data.getSlotNo();
|
||||
unsigned int srcId = data.getSrcId();
|
||||
unsigned int dstId = data.getDstId();
|
||||
|
|
@ -728,6 +755,12 @@ int CDMRGateway::run()
|
|||
delete timer[1U];
|
||||
delete timer[2U];
|
||||
|
||||
if (m_aprsHelper != NULL)
|
||||
m_aprsHelper->close();
|
||||
|
||||
if (m_lookup != NULL)
|
||||
m_lookup->stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1143,3 +1176,74 @@ void CDMRGateway::writeXLXLink(unsigned int srcId, unsigned int dstId, CDMRNetwo
|
|||
network->write(data);
|
||||
}
|
||||
}
|
||||
|
||||
void CDMRGateway::createAPRSHelper()
|
||||
{
|
||||
if (!m_conf.getAPRSEnabled())
|
||||
return;
|
||||
|
||||
std::string hostname = m_conf.getAPRSServer();
|
||||
unsigned int port = m_conf.getAPRSPort();
|
||||
std::string password = m_conf.getAPRSPassword();
|
||||
|
||||
m_aprsHelper = new CAPRSHelper(m_callsign, m_suffix, password, hostname, port);
|
||||
|
||||
bool ret = m_aprsHelper->open();
|
||||
if (!ret) {
|
||||
delete m_aprsHelper;
|
||||
m_aprsHelper = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CDMRGateway::extractGPSData(const CDMRData& data)
|
||||
{
|
||||
unsigned int slotNo = data.getSlotNo();
|
||||
unsigned int srcId = data.getSrcId();
|
||||
unsigned int dstId = data.getDstId();
|
||||
FLCO flco = data.getFLCO();
|
||||
|
||||
unsigned char type = data.getDataType();
|
||||
if (type == DT_RATE_12_DATA) {
|
||||
int8_t latSign = 0;
|
||||
int8_t longSign = 0;
|
||||
|
||||
LogDebug("1/2 Rate Header slot %d: src is %u, dest is %s%u", slotNo, srcId, flco == FLCO_GROUP ? "TG" : "", dstId);
|
||||
|
||||
std::string src = m_lookup->find(srcId);
|
||||
|
||||
CBPTC19696 bptc;
|
||||
unsigned char buffer[DMR_FRAME_LENGTH_BYTES];
|
||||
|
||||
data.getData(buffer);
|
||||
|
||||
unsigned char payload[12U];
|
||||
bptc.decode(buffer, payload);
|
||||
|
||||
// Have we a GPS fix
|
||||
if ((payload[0U] & 0x10U) >> 4) {
|
||||
if ((payload[0U] & 0x40U) >> 6)
|
||||
latSign = 1;
|
||||
else
|
||||
latSign = -1;
|
||||
|
||||
if ((payload[0U] & 0x20U) >> 5)
|
||||
longSign = 1;
|
||||
else
|
||||
longSign = -1;
|
||||
|
||||
uint8_t latDeg = ((payload[1U] & 0x1F) << 2) + ((payload[2U] & 0xC0) >> 6);
|
||||
uint8_t latMin = payload[2U] & 0x3F;
|
||||
float latSec = (payload[3U] << 6) + (payload[4U] & 0xFC);
|
||||
uint8_t lonDeg = ((payload[4U] & 0x03) << 6) + ((payload[5U] & 0xFC) >> 2);
|
||||
uint8_t lonMin = ((payload[5U] & 0x03) << 4) + ((payload[6U] & 0xF0) >> 4);
|
||||
float lonSec = ((payload[6U] & 0x0F) << 10) + (payload[7U] << 2) + ((payload[8U] & 0xC0) >> 6);
|
||||
int altitude = (((payload[8U] & 0x3F) << 8) + payload[9U]);
|
||||
|
||||
float latitude = latDeg + (latMin + latSec / 10000) / 60;
|
||||
float longitude = lonDeg + (lonMin + lonSec / 10000) / 60;
|
||||
LogDebug("Sending GPS position from %d", srcId);
|
||||
|
||||
m_aprsHelper->send(src.c_str(), latitude * latSign, longitude * longSign, altitude);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
#include "RewriteTG.h"
|
||||
#include "Rewrite.h"
|
||||
#include "Conf.h"
|
||||
#include "DMRLookup.h"
|
||||
#include "APRSHelper.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
@ -37,7 +39,11 @@ public:
|
|||
int run();
|
||||
|
||||
private:
|
||||
std::string m_callsign;
|
||||
std::string m_suffix;
|
||||
CConf m_conf;
|
||||
|
||||
CAPRSHelper* m_aprsHelper;
|
||||
IRepeaterProtocol* m_repeater;
|
||||
CDMRNetwork* m_dmrNetwork1;
|
||||
CDMRNetwork* m_dmrNetwork2;
|
||||
|
|
@ -65,6 +71,7 @@ private:
|
|||
std::vector<IRewrite*> m_dmr1RFRewrites;
|
||||
std::vector<IRewrite*> m_dmr2NetRewrites;
|
||||
std::vector<IRewrite*> m_dmr2RFRewrites;
|
||||
CDMRLookup* m_lookup;
|
||||
|
||||
bool createMMDVM();
|
||||
bool createDMRNetwork1();
|
||||
|
|
@ -72,6 +79,8 @@ private:
|
|||
bool createXLXNetwork1();
|
||||
bool createXLXNetwork2();
|
||||
void writeXLXLink(unsigned int srcId, unsigned int dstId, CDMRNetwork* network);
|
||||
void extractGPSData(const CDMRData& data);
|
||||
void createAPRSHelper();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
[General]
|
||||
Callsign=G9BF-DG
|
||||
Timeout=10
|
||||
RptAddress=127.0.0.1
|
||||
RptPort=62032
|
||||
LocalAddress=127.0.0.1
|
||||
LocalPort=62031
|
||||
Daemon=0
|
||||
Debug=0
|
||||
Debug=1
|
||||
|
||||
[Log]
|
||||
# Logging levels, 0=No logging
|
||||
|
|
@ -14,6 +15,19 @@ FileLevel=1
|
|||
FilePath=.
|
||||
FileRoot=DMRGateway
|
||||
|
||||
|
||||
[aprs.fi]
|
||||
Enable=1
|
||||
# Server=noam.aprs2.net
|
||||
Server=rotate.aprs2.net
|
||||
Port=14580
|
||||
Password=12345
|
||||
|
||||
[DMR Id Lookup]
|
||||
File=DMRIds.dat
|
||||
Time=24
|
||||
|
||||
|
||||
[Voice]
|
||||
Enabled=1
|
||||
Language=en_GB
|
||||
|
|
|
|||
|
|
@ -152,6 +152,9 @@
|
|||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="APRSHelper.h" />
|
||||
<ClInclude Include="APRSWriter.h" />
|
||||
<ClInclude Include="APRSWriterThread.h" />
|
||||
<ClInclude Include="BPTC19696.h" />
|
||||
<ClInclude Include="Conf.h" />
|
||||
<ClInclude Include="CRC.h" />
|
||||
|
|
@ -162,12 +165,14 @@
|
|||
<ClInclude Include="DMRFullLC.h" />
|
||||
<ClInclude Include="DMRGateway.h" />
|
||||
<ClInclude Include="DMRLC.h" />
|
||||
<ClInclude Include="DMRLookup.h" />
|
||||
<ClInclude Include="DMRNetwork.h" />
|
||||
<ClInclude Include="DMRSlotType.h" />
|
||||
<ClInclude Include="Golay2087.h" />
|
||||
<ClInclude Include="Hamming.h" />
|
||||
<ClInclude Include="Log.h" />
|
||||
<ClInclude Include="MMDVMNetwork.h" />
|
||||
<ClInclude Include="Mutex.h" />
|
||||
<ClInclude Include="PassAllPC.h" />
|
||||
<ClInclude Include="PassAllTG.h" />
|
||||
<ClInclude Include="QR1676.h" />
|
||||
|
|
@ -182,6 +187,7 @@
|
|||
<ClInclude Include="SHA256.h" />
|
||||
<ClInclude Include="StopWatch.h" />
|
||||
<ClInclude Include="Sync.h" />
|
||||
<ClInclude Include="TCPSocket.h" />
|
||||
<ClInclude Include="Thread.h" />
|
||||
<ClInclude Include="Timer.h" />
|
||||
<ClInclude Include="UDPSocket.h" />
|
||||
|
|
@ -190,6 +196,9 @@
|
|||
<ClInclude Include="Voice.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="APRSHelper.cpp" />
|
||||
<ClCompile Include="APRSWriter.cpp" />
|
||||
<ClCompile Include="APRSWriterThread.cpp" />
|
||||
<ClCompile Include="BPTC19696.cpp" />
|
||||
<ClCompile Include="Conf.cpp" />
|
||||
<ClCompile Include="CRC.cpp" />
|
||||
|
|
@ -199,12 +208,14 @@
|
|||
<ClCompile Include="DMRFullLC.cpp" />
|
||||
<ClCompile Include="DMRGateway.cpp" />
|
||||
<ClCompile Include="DMRLC.cpp" />
|
||||
<ClCompile Include="DMRLookup.cpp" />
|
||||
<ClCompile Include="DMRNetwork.cpp" />
|
||||
<ClCompile Include="DMRSlotType.cpp" />
|
||||
<ClCompile Include="Golay2087.cpp" />
|
||||
<ClCompile Include="Hamming.cpp" />
|
||||
<ClCompile Include="Log.cpp" />
|
||||
<ClCompile Include="MMDVMNetwork.cpp" />
|
||||
<ClCompile Include="Mutex.cpp" />
|
||||
<ClCompile Include="PassAllPC.cpp" />
|
||||
<ClCompile Include="PassAllTG.cpp" />
|
||||
<ClCompile Include="QR1676.cpp" />
|
||||
|
|
@ -218,6 +229,7 @@
|
|||
<ClCompile Include="SHA256.cpp" />
|
||||
<ClCompile Include="StopWatch.cpp" />
|
||||
<ClCompile Include="Sync.cpp" />
|
||||
<ClCompile Include="TCPSocket.cpp" />
|
||||
<ClCompile Include="Thread.cpp" />
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
<ClCompile Include="UDPSocket.cpp" />
|
||||
|
|
|
|||
|
|
@ -119,6 +119,24 @@
|
|||
<ClInclude Include="PassAllTG.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="APRSHelper.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="APRSWriter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="APRSWriterThread.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Mutex.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TCPSocket.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DMRLookup.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Conf.cpp">
|
||||
|
|
@ -220,5 +238,23 @@
|
|||
<ClCompile Include="PassAllTG.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="APRSHelper.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="APRSWriter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="APRSWriterThread.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Mutex.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TCPSocket.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DMRLookup.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
60258
DMRIds.dat
Normal file
60258
DMRIds.dat
Normal file
File diff suppressed because it is too large
Load diff
147
DMRLookup.cpp
Normal file
147
DMRLookup.cpp
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* 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 "DMRLookup.h"
|
||||
#include "Timer.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
|
||||
CDMRLookup::CDMRLookup(const std::string& filename, unsigned int reloadTime) :
|
||||
CThread(),
|
||||
m_filename(filename),
|
||||
m_reloadTime(reloadTime),
|
||||
m_table(),
|
||||
m_mutex(),
|
||||
m_stop(false)
|
||||
{
|
||||
}
|
||||
|
||||
CDMRLookup::~CDMRLookup()
|
||||
{
|
||||
}
|
||||
|
||||
bool CDMRLookup::read()
|
||||
{
|
||||
bool ret = load();
|
||||
|
||||
if (m_reloadTime > 0U)
|
||||
run();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CDMRLookup::entry()
|
||||
{
|
||||
LogInfo("Started the DMR Id lookup reload thread");
|
||||
|
||||
CTimer timer(1U, 3600U * m_reloadTime);
|
||||
timer.start();
|
||||
|
||||
while (!m_stop) {
|
||||
sleep(1000U);
|
||||
|
||||
timer.clock();
|
||||
if (timer.hasExpired()) {
|
||||
load();
|
||||
timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
LogInfo("Stopped the DMR Id lookup reload thread");
|
||||
}
|
||||
|
||||
void CDMRLookup::stop()
|
||||
{
|
||||
if (m_reloadTime == 0U) {
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
m_stop = true;
|
||||
|
||||
wait();
|
||||
}
|
||||
|
||||
std::string CDMRLookup::find(unsigned int id)
|
||||
{
|
||||
std::string callsign;
|
||||
|
||||
if (id == 0xFFFFFFU)
|
||||
return std::string("ALL");
|
||||
|
||||
m_mutex.lock();
|
||||
|
||||
try {
|
||||
callsign = m_table.at(id);
|
||||
} catch (...) {
|
||||
char text[10U];
|
||||
::sprintf(text, "%u", id);
|
||||
callsign = std::string(text);
|
||||
}
|
||||
|
||||
m_mutex.unlock();
|
||||
|
||||
return callsign;
|
||||
}
|
||||
|
||||
bool CDMRLookup::load()
|
||||
{
|
||||
FILE* fp = ::fopen(m_filename.c_str(), "rt");
|
||||
if (fp == NULL) {
|
||||
LogWarning("Cannot open the Id lookup file - %s", m_filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_mutex.lock();
|
||||
|
||||
// Remove the old entries
|
||||
m_table.clear();
|
||||
|
||||
char buffer[100U];
|
||||
while (::fgets(buffer, 100U, fp) != NULL) {
|
||||
if (buffer[0U] == '#')
|
||||
continue;
|
||||
|
||||
char* p1 = ::strtok(buffer, " \t\r\n");
|
||||
char* p2 = ::strtok(NULL, " \t\r\n");
|
||||
|
||||
if (p1 != NULL && p2 != NULL) {
|
||||
unsigned int id = (unsigned int)::atoi(p1);
|
||||
for (char* p = p2; *p != 0x00U; p++)
|
||||
*p = ::toupper(*p);
|
||||
|
||||
m_table[id] = std::string(p2);
|
||||
}
|
||||
}
|
||||
|
||||
m_mutex.unlock();
|
||||
|
||||
::fclose(fp);
|
||||
|
||||
size_t size = m_table.size();
|
||||
if (size == 0U)
|
||||
return false;
|
||||
|
||||
LogInfo("Loaded %u Ids to the callsign lookup table", size);
|
||||
|
||||
return true;
|
||||
}
|
||||
51
DMRLookup.h
Normal file
51
DMRLookup.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef DMRLookup_H
|
||||
#define DMRLookup_H
|
||||
|
||||
#include "Thread.h"
|
||||
#include "Mutex.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class CDMRLookup : public CThread {
|
||||
public:
|
||||
CDMRLookup(const std::string& filename, unsigned int reloadTime);
|
||||
virtual ~CDMRLookup();
|
||||
|
||||
bool read();
|
||||
|
||||
virtual void entry();
|
||||
|
||||
std::string find(unsigned int id);
|
||||
|
||||
void stop();
|
||||
|
||||
private:
|
||||
std::string m_filename;
|
||||
unsigned int m_reloadTime;
|
||||
std::unordered_map<unsigned int, std::string> m_table;
|
||||
CMutex m_mutex;
|
||||
bool m_stop;
|
||||
|
||||
bool load();
|
||||
};
|
||||
|
||||
#endif
|
||||
6
Makefile
6
Makefile
|
|
@ -4,9 +4,9 @@ CFLAGS = -g -O3 -Wall -std=c++0x -pthread
|
|||
LIBS = -lpthread
|
||||
LDFLAGS = -g
|
||||
|
||||
OBJECTS = BPTC19696.o Conf.o CRC.o DMRData.o DMREmbeddedData.o DMREMB.o DMRFullLC.o DMRGateway.o DMRLC.o DMRNetwork.o DMRSlotType.o Golay2087.o Hamming.o Log.o \
|
||||
MMDVMNetwork.o PassAllPC.o PassAllTG.o QR1676.o RepeaterProtocol.o Rewrite.o RewritePC.o RewriteSrc.o RewriteTG.o RewriteType.o RS129.o SHA256.o StopWatch.o \
|
||||
Sync.o Thread.o Timer.o UDPSocket.o Utils.o Voice.o
|
||||
OBJECTS = APRSWriter.o APRSWriterThread.o APRSHelper.o BPTC19696.o Conf.o CRC.o DMRData.o DMREmbeddedData.o DMREMB.o DMRFullLC.o DMRGateway.o DMRLC.o DMRLookup.o \
|
||||
DMRNetwork.o DMRSlotType.o Golay2087.o Hamming.o Log.o MMDVMNetwork.o Mutex.o PassAllPC.o PassAllTG.o QR1676.o RepeaterProtocol.o Rewrite.o RewritePC.o \
|
||||
RewriteSrc.o RewriteTG.o RewriteType.o RS129.o SHA256.o StopWatch.o Sync.o TCPSocket.o Thread.o Timer.o UDPSocket.o Utils.o Voice.o
|
||||
|
||||
all: DMRGateway
|
||||
|
||||
|
|
|
|||
65
Mutex.cpp
Normal file
65
Mutex.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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 "Mutex.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
CMutex::CMutex() :
|
||||
m_handle()
|
||||
{
|
||||
m_handle = ::CreateMutex(NULL, FALSE, NULL);
|
||||
}
|
||||
|
||||
CMutex::~CMutex()
|
||||
{
|
||||
::CloseHandle(m_handle);
|
||||
}
|
||||
|
||||
void CMutex::lock()
|
||||
{
|
||||
::WaitForSingleObject(m_handle, INFINITE);
|
||||
}
|
||||
|
||||
void CMutex::unlock()
|
||||
{
|
||||
::ReleaseMutex(m_handle);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
CMutex::CMutex() :
|
||||
m_mutex(PTHREAD_MUTEX_INITIALIZER)
|
||||
{
|
||||
}
|
||||
|
||||
CMutex::~CMutex()
|
||||
{
|
||||
}
|
||||
|
||||
void CMutex::lock()
|
||||
{
|
||||
::pthread_mutex_lock(&m_mutex);
|
||||
}
|
||||
|
||||
void CMutex::unlock()
|
||||
{
|
||||
::pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
#endif
|
||||
45
Mutex.h
Normal file
45
Mutex.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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(MUTEX_H)
|
||||
#define MUTEX_H
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
class CMutex
|
||||
{
|
||||
public:
|
||||
CMutex();
|
||||
~CMutex();
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
|
||||
private:
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
HANDLE m_handle;
|
||||
#else
|
||||
pthread_mutex_t m_mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
232
TCPSocket.cpp
Normal file
232
TCPSocket.cpp
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* Copyright (C) 2010-2013,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 "TCPSocket.h"
|
||||
#include "UDPSocket.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
typedef int ssize_t;
|
||||
#else
|
||||
#include <cerrno>
|
||||
#endif
|
||||
|
||||
CTCPSocket::CTCPSocket(const std::string& address, unsigned int port) :
|
||||
m_address(address),
|
||||
m_port(port),
|
||||
m_fd(-1)
|
||||
{
|
||||
assert(!address.empty());
|
||||
assert(port > 0U);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
WSAData data;
|
||||
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
|
||||
if (wsaRet != 0)
|
||||
LogError("Error from WSAStartup");
|
||||
#endif
|
||||
}
|
||||
|
||||
CTCPSocket::~CTCPSocket()
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CTCPSocket::open()
|
||||
{
|
||||
if (m_fd != -1)
|
||||
return true;
|
||||
|
||||
if (m_address.empty() || m_port == 0U)
|
||||
return false;
|
||||
|
||||
m_fd = ::socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (m_fd < 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Cannot create the TCP client socket, err=%d", ::GetLastError());
|
||||
#else
|
||||
LogError("Cannot create the TCP client socket, err=%d", errno);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_in addr;
|
||||
::memset(&addr, 0x00, sizeof(struct sockaddr_in));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(m_port);
|
||||
addr.sin_addr = CUDPSocket::lookup(m_address);
|
||||
|
||||
if (addr.sin_addr.s_addr == INADDR_NONE) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::connect(m_fd, (sockaddr*)&addr, sizeof(struct sockaddr_in)) == -1) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Cannot connect the TCP client socket, err=%d", ::GetLastError());
|
||||
#else
|
||||
LogError("Cannot connect the TCP client socket, err=%d", errno);
|
||||
#endif
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
int noDelay = 1;
|
||||
if (::setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&noDelay, sizeof(noDelay)) == -1) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Cannot set the TCP client socket option, err=%d", ::GetLastError());
|
||||
#else
|
||||
LogError("Cannot set the TCP client socket option, err=%d", errno);
|
||||
#endif
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CTCPSocket::read(unsigned char* buffer, unsigned int length, unsigned int secs, unsigned int msecs)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
assert(length > 0U);
|
||||
assert(m_fd != -1);
|
||||
|
||||
// Check that the recv() 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 after timeout
|
||||
timeval tv;
|
||||
tv.tv_sec = secs;
|
||||
tv.tv_usec = msecs * 1000;
|
||||
|
||||
int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv);
|
||||
if (ret < 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Error returned from TCP client select, err=%d", ::GetLastError());
|
||||
#else
|
||||
LogError("Error returned from TCP client select, err=%d", errno);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (!FD_ISSET((unsigned int)m_fd, &readFds))
|
||||
return 0;
|
||||
#else
|
||||
if (!FD_ISSET(m_fd, &readFds))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
ssize_t len = ::recv(m_fd, (char*)buffer, length, 0);
|
||||
if (len == 0) {
|
||||
return -2;
|
||||
} else if (len < 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Error returned from recv, err=%d", ::GetLastError());
|
||||
#else
|
||||
LogError("Error returned from recv, err=%d", errno);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int CTCPSocket::readLine(std::string& line, unsigned int secs)
|
||||
{
|
||||
// Maybe there is a better way to do this like reading blocks, pushing them for later calls
|
||||
// Nevermind, we'll read one char at a time for the time being.
|
||||
int resultCode;
|
||||
int len = 0;
|
||||
|
||||
line.clear();
|
||||
|
||||
char c[2U];
|
||||
c[1U] = 0x00U;
|
||||
|
||||
do
|
||||
{
|
||||
resultCode = read((unsigned char*)c, 1U, secs);
|
||||
if (resultCode == 1){
|
||||
line.append(c);
|
||||
len++;
|
||||
}
|
||||
} while (c[0U] != '\n' && resultCode == 1);
|
||||
|
||||
return resultCode <= 0 ? resultCode : len;
|
||||
}
|
||||
|
||||
bool CTCPSocket::write(const unsigned char* buffer, unsigned int length)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
assert(length > 0U);
|
||||
assert(m_fd != -1);
|
||||
|
||||
ssize_t ret = ::send(m_fd, (char *)buffer, length, 0);
|
||||
if (ret != ssize_t(length)) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Error returned from send, err=%d", ::GetLastError());
|
||||
#else
|
||||
LogError("Error returned from send, err=%d", errno);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CTCPSocket::writeLine(const std::string& line)
|
||||
{
|
||||
std::string lineCopy(line);
|
||||
if (lineCopy.length() > 0 && lineCopy.at(lineCopy.length() - 1) != '\n')
|
||||
lineCopy.append("\n");
|
||||
|
||||
//stupidly write one char after the other
|
||||
size_t len = lineCopy.length();
|
||||
bool result = true;
|
||||
for (size_t i = 0U; i < len && result; i++){
|
||||
unsigned char c = lineCopy.at(i);
|
||||
result = write(&c , 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CTCPSocket::close()
|
||||
{
|
||||
if (m_fd != -1) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::closesocket(m_fd);
|
||||
#else
|
||||
::close(m_fd);
|
||||
#endif
|
||||
m_fd = -1;
|
||||
}
|
||||
}
|
||||
58
TCPSocket.h
Normal file
58
TCPSocket.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (C) 2010,2011,2012,2013,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 TCPSocket_H
|
||||
#define TCPSocket_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 <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#else
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
class CTCPSocket {
|
||||
public:
|
||||
CTCPSocket(const std::string& address, unsigned int port);
|
||||
~CTCPSocket();
|
||||
|
||||
bool open();
|
||||
|
||||
int read(unsigned char* buffer, unsigned int length, unsigned int secs, unsigned int msecs = 0U);
|
||||
int readLine(std::string& line, unsigned int secs);
|
||||
bool write(const unsigned char* buffer, unsigned int length);
|
||||
bool writeLine(const std::string& line);
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
std::string m_address;
|
||||
unsigned short m_port;
|
||||
int m_fd;
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in a new issue