Compare commits

...

48 commits

Author SHA1 Message Date
Jonathan Naylor b189b73eea
Merge pull request #336 from W0CHP/master
Refactor cURL and hostfile URL
2025-07-09 12:26:58 +01:00
Chipster 127cffd180 Refactor cURL and hostfile URL 2025-06-24 05:28:28 -05:00
Jonathan Naylor 598854b2e3
Merge pull request #335 from MW0MWZ/master
Remove MakeUpper config/code
2025-06-15 16:54:53 +01:00
MW0MWZ ac0ba050c7
Update Version.h
Version bump
2025-06-15 16:45:30 +01:00
Andrew Taylor 9df9a1aa16 Remove config opton / code for making hostfiles UPPER case 2025-06-15 16:32:44 +01:00
Jonathan Naylor 450fd77a09
Merge pull request #334 from f1rmb/f1rmb_nullptr_vs_NULL_with_getaddrinfo
Fix nullptr instead of NULL argument usage in getaddrinfo().
2025-06-09 13:40:32 +01:00
Jonathan Naylor 5eba410632
Merge pull request #333 from MW0MWZ/master
More work on #330
2025-06-09 13:39:41 +01:00
Daniel Caujolle-Bert f4b985d165 Fix nullptr instead of NULL argument usage in getaddrinfo().
Bump version.
2025-06-07 17:37:17 +02:00
MW0MWZ 8f88801628
Update WiresX.cpp
More places UPPERCASE matters
2025-05-26 01:08:33 +01:00
MW0MWZ 76fd6f4921
Update WiresX.cpp
Add some notes about specific radio models
2025-05-25 23:44:38 +01:00
Jonathan Naylor 00873b6cea
Merge pull request #332 from MW0MWZ/master
Match YSFGateway state with Radio State
2025-05-22 10:40:19 +01:00
root c260e55680 Match YSFGateway state with Radio State - when the radio is told the connection failed, it assumes there is no connection, so YSFGateway should drop the active reflector connection 2025-05-22 00:37:14 +01:00
Jonathan Naylor 75c8450870
Merge pull request #331 from MW0MWZ/master 2025-05-21 14:17:14 +01:00
root d583357cab Fix YSFGateway Crash on searching for a reflector with an ID that doesn't exist, code cleanup around the WiresX protocol 2025-05-20 00:50:36 +01:00
Jonathan Naylor 702d9e1312
Merge pull request #329 from MW0MWZ/patch-2
Update WiresX.cpp
2025-05-14 13:10:39 +01:00
MW0MWZ d2044019a4
Update WiresX.cpp
additional Uppercase on the ALL reply as well as the search.
2025-05-14 00:21:22 +01:00
MW0MWZ 41edfe53c7
Update WiresX.cpp
During WiresX mode Search, the reflector name should be Upper Case - this only matters during search - the normal display of the data can be mixed case.
2025-05-13 19:24:15 +01:00
Jonathan Naylor c3580fdcd3
Merge pull request #328 from MW0MWZ/patch-1
Update YSFReflectors.cpp
2025-05-13 13:41:18 +01:00
MW0MWZ af1cfbb251
Update YSFReflectors.cpp
Suggested code amendments to fix #326 and #310 
Code suggestions by an AI that can write better C++ than I can, please do vet this for sanity / accuracy before merge.
2025-05-13 11:42:16 +01:00
Jonathan Naylor f5a9843502 Use DVRef.com for the YSF refletor data. 2025-05-07 19:08:53 +01:00
Jonathan Naylor 5015034749
Merge pull request #325 from shawnchain/feat-expilict-reconnect-option
PR for #323 - cont.
2025-05-07 13:23:13 +01:00
Shawn 30596b3cc4 PR for #323 - cont.
- Add "Reconnect=0" configuration option to the [Network] section to avoid ambiguity
  - Keep the original behaviors when Revert=1 and Reconnect=1
  - Bugfix on Wires-DX reconnect (find reflector both by id and name)
2025-04-29 15:43:05 +08:00
Jonathan Naylor 811caaa823
Merge pull request #324 from shawnchain/feat-reconnect-on-wirex-dx-cmd 2025-04-27 11:59:45 +01:00
Shawn b7260b4bf8 Change the YSFGateway a little bit to auto-reconnect current timed-out reflector if WiresX DX command is received. That means if your hotspot lost the connection to the network reflector, just re-press the X button on your Yaesu device and everything will be back online again. 2025-04-27 18:20:48 +08:00
Jonathan Naylor e61d856c6b
Merge pull request #322 from shawnchain/fix-issue-321 2025-04-23 09:14:34 +01:00
Shawn daa1b56f3a Fix issue #321 2025-04-23 15:18:01 +08:00
Jonathan Naylor e57b43377c Update the C++ version. 2025-03-19 17:49:49 +00:00
Jonathan Naylor b536f95e7e
Merge pull request #319 from dg9ffm/patch-36
Update FCSRooms.txt
2025-03-13 12:06:49 +00:00
Jonathan Naylor 5ade21aaa2
Merge pull request #320 from dg9ffm/patch-37
Update FCSRooms.txt
2025-03-13 12:06:34 +00:00
dg9ffm 80a91b9dd8
Update FCSRooms.txt 2025-03-12 23:38:41 +01:00
dg9ffm 462eb2d571
Update FCSRooms.txt 2025-03-12 23:35:01 +01:00
Jonathan Naylor ebb50c3acc Update FCS31233 details 2025-01-08 13:31:27 +00:00
Jonathan Naylor f9431cbc0d Add the FT-991A to the YSF radio list for APRS-IS. 2024-12-18 14:49:38 +00:00
Jonathan Naylor 8011768b96 Fix signal logging. 2024-08-31 19:52:09 +01:00
Jonathan Naylor 6127174cfc Merge branch 'master' of github.com:g4klx/YSFClients 2024-08-28 17:04:42 +01:00
Jonathan Naylor ae29471f58 Update the signal handling. 2024-08-28 17:03:51 +01:00
Jonathan Naylor f811e65989
Merge pull request #315 from dg9ffm/patch-35
Update FCSRooms.txt
2024-08-28 15:46:51 +01:00
Jonathan Naylor 526f74c4ca
Merge pull request #314 from dg9ffm/patch-34
Update FCSRooms.txt
2024-08-28 15:46:40 +01:00
dg9ffm 5b6f6fb102
Update FCSRooms.txt
Update new FCS-Server and Rooms
2024-08-21 20:58:50 +02:00
dg9ffm 2af170c781
Update FCSRooms.txt
Update ne FCS-Server and Rooms
2024-08-21 20:56:05 +02:00
Jonathan Naylor 9ca8293609
Merge pull request #311 from k0mgs/patch-2
Update YSFHosts.txt
2024-07-11 13:03:34 +01:00
k0mgs 46659c916a
Update YSFHosts.txt
Add 31947 - K0MGS-LINK
2024-07-10 20:10:36 -05:00
Jonathan Naylor ca52eaf51e Clean up the code and remove an annoying bug. 2024-07-08 15:14:30 +01:00
Jonathan Naylor e67ddd1e87
Merge pull request #300 from hb9tob/master
Dirty patch for compatibility with the Ft-991a (and maybe the FT-991)
2024-07-07 17:11:23 +01:00
Jonathan Naylor aecc34ee64 Allow YSFClients to compile under Windows. 2024-04-22 13:15:25 +01:00
Jonathan Naylor dfe50c4245 Simplify the UDP socket handling. 2024-01-29 15:44:33 +00:00
hb9tob 91eccac90c fix 991a shame 2 2023-04-13 21:22:51 +02:00
hb9tob bed3cbebd6 fix 991a shame 2023-04-13 20:57:40 +02:00
76 changed files with 4034 additions and 4848 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2010-2014,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2010-2014,2016,2017,2018,2020,2025 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
@ -106,7 +106,7 @@ bool CAPRSWriter::open()
return false;
}
::gps_stream(&m_gpsdData, WATCH_ENABLE | WATCH_JSON, NULL);
::gps_stream(&m_gpsdData, WATCH_ENABLE | WATCH_JSON, nullptr);
LogMessage("Connected to GPSD");
}
@ -125,8 +125,8 @@ bool CAPRSWriter::open()
void CAPRSWriter::write(const unsigned char* source, const char* type, unsigned char radio, float fLatitude, float fLongitude)
{
assert(source != NULL);
assert(type != NULL);
assert(source != nullptr);
assert(type != nullptr);
char callsign[15U];
::memcpy(callsign, source, YSF_CALLSIGN_LENGTH);
@ -219,7 +219,7 @@ void CAPRSWriter::close()
#if defined(USE_GPSD)
if (m_gpsdEnabled) {
::gps_stream(&m_gpsdData, WATCH_DISABLE, NULL);
::gps_stream(&m_gpsdData, WATCH_DISABLE, nullptr);
::gps_close(&m_gpsdData);
}
#endif
@ -300,7 +300,7 @@ void CAPRSWriter::sendIdFrameMobile()
return;
#if GPSD_API_MAJOR_VERSION >= 7
if (::gps_read(&m_gpsdData, NULL, 0) <= 0)
if (::gps_read(&m_gpsdData, nullptr, 0) <= 0)
return;
#else
if (::gps_read(&m_gpsdData) <= 0)

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2025 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
@ -63,7 +63,7 @@ const uint16_t CCITT16_TABLE2[] = {
void CCRC::addCCITT16(unsigned char *in, unsigned int length)
{
assert(in != NULL);
assert(in != nullptr);
assert(length > 2U);
union {
@ -84,7 +84,7 @@ void CCRC::addCCITT16(unsigned char *in, unsigned int length)
bool CCRC::checkCCITT16(const unsigned char *in, unsigned int length)
{
assert(in != NULL);
assert(in != nullptr);
assert(length > 2U);
union {
@ -104,7 +104,7 @@ bool CCRC::checkCCITT16(const unsigned char *in, unsigned int length)
unsigned char CCRC::addCRC(const unsigned char* in, unsigned int length)
{
assert(in != NULL);
assert(in != nullptr);
unsigned char crc = 0U;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015-2020,2025 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
@ -27,17 +27,17 @@
const int BUFFER_SIZE = 500;
enum SECTION {
SECTION_NONE,
SECTION_GENERAL,
SECTION_INFO,
SECTION_LOG,
SECTION_APRS,
SECTION_YSF_NETWORK,
SECTION_FCS_NETWORK,
SECTION_IMRS_NETWORK,
SECTION_DGID,
SECTION_GPSD
enum class SECTION {
NONE,
GENERAL,
INFO,
LOG,
APRS,
YSF_NETWORK,
FCS_NETWORK,
IMRS_NETWORK,
DGID,
GPSD
};
CConf::CConf(const std::string& file) :
@ -71,7 +71,7 @@ m_aprsAddress(),
m_aprsPort(0U),
m_aprsSuffix(),
m_aprsDescription(),
m_aprsSymbol(),
m_aprsSymbol("/r"),
m_ysfNetHosts(),
m_ysfRFHangTime(60U),
m_ysfNetHangTime(60U),
@ -96,54 +96,54 @@ CConf::~CConf()
bool CConf::read()
{
FILE* fp = ::fopen(m_file.c_str(), "rt");
if (fp == NULL) {
if (fp == nullptr) {
::fprintf(stderr, "Couldn't open the .ini file - %s\n", m_file.c_str());
return false;
}
SECTION section = SECTION_NONE;
SECTION section = SECTION::NONE;
DGIdData* dgIdData = NULL;
DGIdData* dgIdData = nullptr;
char buffer[BUFFER_SIZE];
while (::fgets(buffer, BUFFER_SIZE, fp) != NULL) {
while (::fgets(buffer, BUFFER_SIZE, fp) != nullptr) {
if (buffer[0U] == '#')
continue;
if (buffer[0U] == '[') {
if (::strncmp(buffer, "[General]", 9U) == 0)
section = SECTION_GENERAL;
section = SECTION::GENERAL;
else if (::strncmp(buffer, "[Info]", 6U) == 0)
section = SECTION_INFO;
section = SECTION::INFO;
else if (::strncmp(buffer, "[Log]", 5U) == 0)
section = SECTION_LOG;
section = SECTION::LOG;
else if (::strncmp(buffer, "[APRS]", 6U) == 0)
section = SECTION_APRS;
section = SECTION::APRS;
else if (::strncmp(buffer, "[YSF Network]", 13U) == 0)
section = SECTION_YSF_NETWORK;
section = SECTION::YSF_NETWORK;
else if (::strncmp(buffer, "[FCS Network]", 13U) == 0)
section = SECTION_FCS_NETWORK;
section = SECTION::FCS_NETWORK;
else if (::strncmp(buffer, "[IMRS Network]", 14U) == 0)
section = SECTION_IMRS_NETWORK;
section = SECTION::IMRS_NETWORK;
else if (::strncmp(buffer, "[DGId=", 6U) == 0) {
section = SECTION_DGID;
section = SECTION::DGID;
dgIdData = new DGIdData;
dgIdData->m_dgId = (unsigned int)::atoi(buffer + 6U);
m_dgIdData.push_back(dgIdData);
} else if (::strncmp(buffer, "[GPSD]", 6U) == 0)
section = SECTION_GPSD;
section = SECTION::GPSD;
else
section = SECTION_NONE;
section = SECTION::NONE;
continue;
}
char* key = ::strtok(buffer, " \t=\r\n");
if (key == NULL)
if (key == nullptr)
continue;
char* value = ::strtok(NULL, "\r\n");
if (value == NULL)
char* value = ::strtok(nullptr, "\r\n");
if (value == nullptr)
continue;
// Remove quotes from the value
@ -155,7 +155,7 @@ bool CConf::read()
char *p;
// if value is not quoted, remove after # (to make comment)
if ((p = strchr(value, '#')) != NULL)
if ((p = strchr(value, '#')) != nullptr)
*p = '\0';
// remove trailing tab/space
@ -163,7 +163,7 @@ bool CConf::read()
*p = '\0';
}
if (section == SECTION_GENERAL) {
if (section == SECTION::GENERAL) {
if (::strcmp(key, "Callsign") == 0) {
// Convert the callsign to upper case
for (unsigned int i = 0U; value[i] != 0; i++)
@ -194,7 +194,7 @@ bool CConf::read()
m_debug = ::atoi(value) == 1;
else if (::strcmp(key, "Daemon") == 0)
m_daemon = ::atoi(value) == 1;
} else if (section == SECTION_INFO) {
} else if (section == SECTION::INFO) {
if (::strcmp(key, "TXFrequency") == 0)
m_txFrequency = (unsigned int)::atoi(value);
else if (::strcmp(key, "RXFrequency") == 0)
@ -209,7 +209,7 @@ bool CConf::read()
m_height = ::atoi(value);
else if (::strcmp(key, "Description") == 0)
m_description = value;
} else if (section == SECTION_LOG) {
} else if (section == SECTION::LOG) {
if (::strcmp(key, "FilePath") == 0)
m_logFilePath = value;
else if (::strcmp(key, "FileRoot") == 0)
@ -220,7 +220,7 @@ bool CConf::read()
m_logDisplayLevel = (unsigned int)::atoi(value);
else if (::strcmp(key, "FileRotate") == 0)
m_logFileRotate = ::atoi(value) == 1;
} else if (section == SECTION_APRS) {
} else if (section == SECTION::APRS) {
if (::strcmp(key, "Enable") == 0)
m_aprsEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Address") == 0)
@ -233,7 +233,7 @@ bool CConf::read()
m_aprsDescription = value;
else if (::strcmp(key, "Symbol") == 0)
m_aprsSymbol = value;
} else if (section == SECTION_YSF_NETWORK) {
} else if (section == SECTION::YSF_NETWORK) {
if (::strcmp(key, "Hosts") == 0)
m_ysfNetHosts = value;
else if (::strcmp(key, "RFHangTime") == 0)
@ -242,22 +242,22 @@ bool CConf::read()
m_ysfNetHangTime = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_ysfNetDebug = ::atoi(value) == 1;
} else if (section == SECTION_FCS_NETWORK) {
} else if (section == SECTION::FCS_NETWORK) {
if (::strcmp(key, "RFHangTime") == 0)
m_fcsRFHangTime = (unsigned int)::atoi(value);
else if (::strcmp(key, "NetHangTime") == 0)
m_fcsNetHangTime = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_fcsNetDebug = ::atoi(value) == 1;
} else if (section == SECTION_IMRS_NETWORK) {
} else if (section == SECTION::IMRS_NETWORK) {
if (::strcmp(key, "RFHangTime") == 0)
m_imrsRFHangTime = (unsigned int)::atoi(value);
else if (::strcmp(key, "NetHangTime") == 0)
m_imrsNetHangTime = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_imrsNetDebug = ::atoi(value) == 1;
} else if (section == SECTION_DGID) {
assert(dgIdData != NULL);
} else if (section == SECTION::DGID) {
assert(dgIdData != nullptr);
if (::strcmp(key, "Type") == 0) {
dgIdData->m_type = value;
dgIdData->m_static = false;
@ -296,14 +296,14 @@ bool CConf::read()
dgIdData->m_netDGId = (unsigned int)::atoi(value);
else if (::strcmp(key, "Destination") == 0) {
char* p1 = ::strtok(value, ",");
char* p2 = ::strtok(NULL, "\r\n");
char* p2 = ::strtok(nullptr, "\r\n");
IMRSDestination* dest = new IMRSDestination;
dest->m_dgId = (unsigned int)::atoi(p1);
dest->m_address = p2;
dgIdData->m_destinations.push_back(dest);
} else if (::strcmp(key, "Debug") == 0)
dgIdData->m_debug = ::atoi(value) == 1;
} else if (section == SECTION_GPSD) {
} else if (section == SECTION::GPSD) {
if (::strcmp(key, "Enable") == 0)
m_gpsdEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Address") == 0)

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016-2020,2024,2025 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
@ -63,6 +63,17 @@ const unsigned char DT_VD_MODE2 = 0x02U;
const unsigned char DT_VOICE_FR_MODE = 0x04U;
const unsigned char DT_DATA_FR_MODE = 0x08U;
static bool m_killed = false;
static int m_signal = 0;
#if !defined(_WIN32) && !defined(_WIN64)
static void sigHandler(int signum)
{
m_killed = true;
m_signal = signum;
}
#endif
int main(int argc, char** argv)
{
const char* iniFile = DEFAULT_INI_FILE;
@ -81,11 +92,40 @@ int main(int argc, char** argv)
}
}
CDGIdGateway* gateway = new CDGIdGateway(std::string(iniFile));
#if !defined(_WIN32) && !defined(_WIN64)
::signal(SIGINT, sigHandler);
::signal(SIGTERM, sigHandler);
::signal(SIGHUP, sigHandler);
#endif
int ret = gateway->run();
int ret = 0;
delete gateway;
do {
m_signal = 0;
m_killed = false;
CDGIdGateway* gateway = new CDGIdGateway(std::string(iniFile));
ret = gateway->run();
delete gateway;
switch (m_signal) {
case 0:
break;
case 2:
::LogInfo("DGIdGateway-%s exited on receipt of SIGINT", VERSION);
break;
case 15:
::LogInfo("DGIdGateway-%s exited on receipt of SIGTERM", VERSION);
break;
case 1:
::LogInfo("DGIdGateway-%s is restarting on receipt of SIGHUP", VERSION);
break;
default:
::LogInfo("DGIdGateway-%s exited on receipt of an unknown signal", VERSION);
break;
}
} while (m_signal == 1);
return ret;
}
@ -94,8 +134,8 @@ CDGIdGateway::CDGIdGateway(const std::string& configFile) :
m_callsign(),
m_suffix(),
m_conf(configFile),
m_writer(NULL),
m_gps(NULL)
m_writer(nullptr),
m_gps(nullptr)
{
CUDPSocket::startup();
}
@ -143,7 +183,7 @@ int CDGIdGateway::run()
// If we are currently root...
if (getuid() == 0) {
struct passwd* user = ::getpwnam("mmdvm");
if (user == NULL) {
if (user == nullptr) {
::fprintf(stderr, "Could not get the mmdvm user, exiting\n");
return -1;
}
@ -220,7 +260,7 @@ int CDGIdGateway::run()
ret = imrs->open();
if (!ret) {
delete imrs;
imrs = NULL;
imrs = nullptr;
}
unsigned int currentDGId = UNSET_DGID;
@ -228,7 +268,7 @@ int CDGIdGateway::run()
CDGIdNetwork* dgIdNetwork[100U];
for (unsigned int i = 0U; i < 100U; i++)
dgIdNetwork[i] = NULL;
dgIdNetwork[i] = nullptr;
std::vector<DGIdData*> dgIdData = m_conf.getDGIdData();
for (std::vector<DGIdData*>::const_iterator it = dgIdData.begin(); it != dgIdData.end(); ++it) {
@ -262,7 +302,7 @@ int CDGIdGateway::run()
unsigned int local = (*it)->m_local;
CYSFReflector* reflector = reflectors->findByName(name);
if (reflector != NULL) {
if (reflector != nullptr) {
dgIdNetwork[dgid] = new CYSFNetwork(local, reflector->m_name, reflector->m_addr, reflector->m_addrLen, m_callsign, statc, debug);
dgIdNetwork[dgid]->m_modes = DT_VD_MODE1 | DT_VD_MODE2 | DT_VOICE_FR_MODE | DT_DATA_FR_MODE;
dgIdNetwork[dgid]->m_static = statc;
@ -274,7 +314,7 @@ int CDGIdGateway::run()
LogWarning("Unknown YSF reflector: %s", name.c_str());
}
} else if (type == "IMRS") {
if (imrs != NULL) {
if (imrs != nullptr) {
std::vector<IMRSDestination*> destinations = (*it)->m_destinations;
std::vector<IMRSDest*> dests;
std::string name = (*it)->m_name;
@ -385,12 +425,12 @@ int CDGIdGateway::run()
}
}
if (dgIdNetwork[dgid] != NULL && dgIdNetwork[dgid] != imrs) {
if (dgIdNetwork[dgid] != nullptr && dgIdNetwork[dgid] != imrs) {
bool ret = dgIdNetwork[dgid]->open();
if (!ret) {
LogWarning("\tUnable to open connection");
delete dgIdNetwork[dgid];
dgIdNetwork[dgid] = NULL;
dgIdNetwork[dgid] = nullptr;
} else if (dgIdNetwork[dgid]->m_static) {
LogMessage("\tLinking at startup");
dgIdNetwork[dgid]->link();
@ -411,10 +451,10 @@ int CDGIdGateway::run()
LogMessage("DGIdGateway-%s is starting", VERSION);
LogMessage("Built %s %s (GitID #%.7s)", __TIME__, __DATE__, gitversion);
DGID_STATUS state = DS_NOTLINKED;
DGID_STATUS state = DGID_STATUS::NOTLINKED;
unsigned int nPips = 0U;
for (;;) {
while (!m_killed) {
unsigned char buffer[200U];
memset(buffer, 0U, 200U);
@ -428,29 +468,29 @@ int CDGIdGateway::run()
dgId = 0U;
if (currentDGId == UNSET_DGID) {
if (dgIdNetwork[dgId] != NULL && !dgIdNetwork[dgId]->m_static) {
if (dgIdNetwork[dgId] != nullptr && !dgIdNetwork[dgId]->m_static) {
dgIdNetwork[dgId]->link();
dgIdNetwork[dgId]->link();
dgIdNetwork[dgId]->link();
}
if (dgIdNetwork[dgId] != NULL) {
if (dgIdNetwork[dgId] != nullptr) {
std::string desc = dgIdNetwork[dgId]->getDesc(dgId);
LogMessage("DG-ID set to %u (%s) via RF", dgId, desc.c_str());
currentDGId = dgId;
state = DS_NOTLINKED;
state = DGID_STATUS::NOTLINKED;
} else {
LogMessage("DG-ID set to %u (None) via RF", dgId);
state = DS_NOTOPEN;
state = DGID_STATUS::NOTOPEN;
}
fromRF = true;
}
if (m_gps != NULL)
if (m_gps != nullptr)
m_gps->data(buffer + 14U, buffer + 35U, fich);
if (currentDGId != UNSET_DGID && dgIdNetwork[currentDGId] != NULL) {
if (currentDGId != UNSET_DGID && dgIdNetwork[currentDGId] != nullptr) {
// Only allow the wanted modes through
unsigned char dt = fich.getDT();
if ((dt == YSF_DT_VD_MODE1 && (dgIdNetwork[currentDGId]->m_modes & DT_VD_MODE1) != 0U) ||
@ -473,7 +513,7 @@ int CDGIdGateway::run()
}
if ((buffer[34U] & 0x01U) == 0x01U) {
if (m_gps != NULL)
if (m_gps != nullptr)
m_gps->reset();
if (nPips > 0U && fromRF)
bleepTimer.start();
@ -481,7 +521,7 @@ int CDGIdGateway::run()
}
for (unsigned int i = 0U; i < 100U; i++) {
if (dgIdNetwork[i] != NULL) {
if (dgIdNetwork[i] != nullptr) {
unsigned int len = dgIdNetwork[i]->read(i, buffer);
if (len > 0U && (i == currentDGId || currentDGId == UNSET_DGID)) {
CYSFFICH fich;
@ -502,7 +542,7 @@ int CDGIdGateway::run()
std::string desc = dgIdNetwork[i]->getDesc(i);
LogMessage("DG-ID set to %u (%s) via Network", i, desc.c_str());
currentDGId = i;
state = DS_LINKED;
state = DGID_STATUS::LINKED;
fromRF = false;
}
}
@ -516,16 +556,16 @@ int CDGIdGateway::run()
rptNetwork.clock(ms);
for (unsigned int i = 0U; i < 100U; i++) {
if (dgIdNetwork[i] != NULL)
if (dgIdNetwork[i] != nullptr)
dgIdNetwork[i]->clock(ms);
}
if (m_writer != NULL)
if (m_writer != nullptr)
m_writer->clock(ms);
inactivityTimer.clock(ms);
if (inactivityTimer.isRunning() && inactivityTimer.hasExpired()) {
if (dgIdNetwork[currentDGId] != NULL && !dgIdNetwork[currentDGId]->m_static) {
if (dgIdNetwork[currentDGId] != nullptr && !dgIdNetwork[currentDGId]->m_static) {
dgIdNetwork[currentDGId]->unlink();
dgIdNetwork[currentDGId]->unlink();
dgIdNetwork[currentDGId]->unlink();
@ -533,7 +573,7 @@ int CDGIdGateway::run()
LogMessage("DG-ID set to None via timeout");
state = DS_NOTLINKED;
state = DGID_STATUS::NOTLINKED;
currentDGId = UNSET_DGID;
inactivityTimer.stop();
@ -550,20 +590,20 @@ int CDGIdGateway::run()
nPips = 0U;
}
if (currentDGId != UNSET_DGID && dgIdNetwork[currentDGId] != NULL) {
if (currentDGId != UNSET_DGID && dgIdNetwork[currentDGId] != nullptr) {
DGID_STATUS netState = dgIdNetwork[currentDGId]->getStatus();
bool statc = dgIdNetwork[currentDGId]->m_static;
if (fromRF && state != DS_LINKED && netState != DS_LINKED && statc)
if (fromRF && state != DGID_STATUS::LINKED && netState != DGID_STATUS::LINKED && statc)
nPips = 3U;
else if (fromRF && state != DS_LINKED && netState == DS_LINKED)
else if (fromRF && state != DGID_STATUS::LINKED && netState == DGID_STATUS::LINKED)
nPips = 1U;
else if (fromRF && state == DS_LINKED && netState != DS_LINKED)
else if (fromRF && state == DGID_STATUS::LINKED && netState != DGID_STATUS::LINKED)
nPips = 3U;
state = netState;
} else {
if (fromRF && state != DS_NOTLINKED)
if (fromRF && state != DGID_STATUS::NOTLINKED)
nPips = 2U;
state = DS_NOTLINKED;
state = DGID_STATUS::NOTLINKED;
}
if (ms < 5U)
@ -573,14 +613,14 @@ int CDGIdGateway::run()
rptNetwork.unlink();
rptNetwork.close();
if (m_gps != NULL) {
if (m_gps != nullptr) {
m_writer->close();
delete m_writer;
delete m_gps;
}
for (unsigned int i = 0U; i < 100U; i++) {
if (dgIdNetwork[i] != NULL && dgIdNetwork[i] != imrs) {
if (dgIdNetwork[i] != nullptr && dgIdNetwork[i] != imrs) {
dgIdNetwork[i]->unlink();
dgIdNetwork[i]->unlink();
dgIdNetwork[i]->unlink();
@ -589,7 +629,7 @@ int CDGIdGateway::run()
}
}
if (imrs != NULL) {
if (imrs != nullptr) {
imrs->close();
delete imrs;
}
@ -635,7 +675,7 @@ void CDGIdGateway::createGPS()
bool ret = m_writer->open();
if (!ret) {
delete m_writer;
m_writer = NULL;
m_writer = nullptr;
return;
}

View file

@ -94,6 +94,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
@ -111,6 +114,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@ -124,6 +130,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
@ -141,6 +150,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="APRSWriter.cpp" />

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020,2025 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
@ -18,6 +18,13 @@
#include "DGIdNetwork.h"
CDGIdNetwork::CDGIdNetwork() :
m_modes(0U),
m_static(false),
m_rfHangTime(0U),
m_netHangTime(0U)
{
}
CDGIdNetwork::~CDGIdNetwork()
{

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020,2025 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
@ -21,15 +21,16 @@
#include <string>
enum DGID_STATUS {
DS_NOTOPEN,
DS_NOTLINKED,
DS_LINKING,
DS_LINKED
enum class DGID_STATUS {
NOTOPEN,
NOTLINKED,
LINKING,
LINKED
};
class CDGIdNetwork {
public:
CDGIdNetwork();
virtual ~CDGIdNetwork() = 0;
virtual std::string getDesc(unsigned int dgId) = 0;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2014,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2014,2016,2017,2018,2020,2021,2025 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
@ -35,8 +35,8 @@ m_debug(debug),
m_addr(),
m_addrLen(0U),
m_static(statc),
m_ping(NULL),
m_info(NULL),
m_ping(nullptr),
m_info(nullptr),
m_reflector(reflector),
m_print(),
m_buffer(1000U, "FCS Network Buffer"),
@ -44,7 +44,7 @@ m_n(0U),
m_sendPollTimer(1000U, 0U, 800U),
m_recvPollTimer(1000U, 60U),
m_resetTimer(1000U, 1U),
m_state(DS_NOTOPEN)
m_state(DGID_STATUS::NOTOPEN)
{
m_info = new unsigned char[100U];
::sprintf((char*)m_info, "%9u%9u%-6.6s%-12.12s%7u", rxFrequency, txFrequency, locator.c_str(), FCS_VERSION, id);
@ -85,7 +85,7 @@ bool CFCSNetwork::open()
{
if (m_addrLen == 0U) {
LogError("Unable to resolve the address of %s", m_reflector.c_str());
m_state = DS_NOTOPEN;
m_state = DGID_STATUS::NOTOPEN;
return false;
}
@ -93,10 +93,10 @@ bool CFCSNetwork::open()
bool ret = m_socket.open(m_addr);
if (!ret) {
m_state = DS_NOTOPEN;
m_state = DGID_STATUS::NOTOPEN;
return false;
} else {
m_state = DS_NOTLINKED;
m_state = DGID_STATUS::NOTLINKED;
return true;
}
}
@ -108,9 +108,9 @@ DGID_STATUS CFCSNetwork::getStatus()
void CFCSNetwork::write(unsigned int dgid, const unsigned char* data)
{
assert(data != NULL);
assert(data != nullptr);
if (m_state != DS_LINKED)
if (m_state != DGID_STATUS::LINKED)
return;
unsigned char buffer[130U];
@ -127,10 +127,10 @@ void CFCSNetwork::write(unsigned int dgid, const unsigned char* data)
void CFCSNetwork::link()
{
if (m_state != DS_NOTLINKED)
if (m_state != DGID_STATUS::NOTLINKED)
return;
m_state = DS_LINKING;
m_state = DGID_STATUS::LINKING;
m_sendPollTimer.start();
m_recvPollTimer.start();
@ -140,7 +140,7 @@ void CFCSNetwork::link()
void CFCSNetwork::unlink()
{
if (m_state != DS_LINKED)
if (m_state != DGID_STATUS::LINKED)
return;
m_socket.write((unsigned char*)"CLOSE ", 11U, m_addr, m_addrLen);
@ -150,20 +150,20 @@ void CFCSNetwork::unlink()
LogMessage("Unlinked from %s", m_print.c_str());
m_state = DS_NOTLINKED;
m_state = DGID_STATUS::NOTLINKED;
}
void CFCSNetwork::clock(unsigned int ms)
{
if (m_state == DS_NOTOPEN)
if (m_state == DGID_STATUS::NOTOPEN)
return;
m_recvPollTimer.clock(ms);
if (m_recvPollTimer.isRunning() && m_recvPollTimer.hasExpired()) {
if (m_static) {
m_state = DS_LINKING;
m_state = DGID_STATUS::LINKING;
} else {
m_state = DS_NOTLINKED;
m_state = DGID_STATUS::NOTLINKED;
m_sendPollTimer.stop();
}
@ -194,7 +194,7 @@ void CFCSNetwork::clock(unsigned int ms)
if (m_debug)
CUtils::dump(1U, "FCS Network Data Received", buffer, length);
if (m_state == DS_NOTLINKED)
if (m_state == DGID_STATUS::NOTLINKED)
return;
if (!CUDPSocket::match(addr, m_addr))
@ -206,10 +206,10 @@ void CFCSNetwork::clock(unsigned int ms)
if (length == 7 || length == 10) {
m_recvPollTimer.start();
if (m_state == DS_LINKING) {
if (m_state == DGID_STATUS::LINKING) {
LogMessage("Linked to %s", m_print.c_str());
m_state = DS_LINKED;
m_state = DGID_STATUS::LINKED;
if (m_debug)
CUtils::dump(1U, "FCS Network Data Sent", m_info, 100U);
@ -229,7 +229,7 @@ void CFCSNetwork::clock(unsigned int ms)
unsigned int CFCSNetwork::read(unsigned int dgid, unsigned char* data)
{
assert(data != NULL);
assert(data != nullptr);
if (m_buffer.isEmpty())
return 0U;
@ -261,12 +261,12 @@ void CFCSNetwork::close()
LogMessage("Closing FCS network connection");
m_state = DS_NOTOPEN;
m_state = DGID_STATUS::NOTOPEN;
}
void CFCSNetwork::writePoll()
{
if (m_state != DS_LINKING && m_state != DS_LINKED)
if (m_state != DGID_STATUS::LINKING && m_state != DGID_STATUS::LINKED)
return;
if (m_debug)

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017,2018,2020,2024,2025 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
@ -32,10 +32,10 @@ const unsigned char LONG_GPS[] = {0x47U, 0x64U};
CGPS::CGPS(CAPRSWriter* writer) :
m_writer(writer),
m_buffer(NULL),
m_buffer(nullptr),
m_sent(false)
{
assert(writer != NULL);
assert(writer != nullptr);
m_buffer = new unsigned char[300U];
}
@ -141,7 +141,7 @@ void CGPS::reset()
void CGPS::transmitGPS(const unsigned char* source)
{
assert(m_writer != NULL);
assert(m_writer != nullptr);
// We don't know who its from!
if (::memcmp(source, " ", YSF_CALLSIGN_LENGTH) == 0)
@ -258,6 +258,9 @@ void CGPS::transmitGPS(const unsigned char* source)
case 0x26U:
::strcpy(radio, "DR-1X");
break;
case 0x27U:
::strcpy(radio, "FT-991A");
break;
case 0x28U:
::strcpy(radio, "FT-2D");
break;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2010,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2010,2016,2025 by Jonathan Naylor G4KLX
* Copyright (C) 2002 by Robert H. Morelos-Zaragoza. All rights reserved.
*/
@ -1096,7 +1096,7 @@ unsigned int CGolay24128::decode24128(unsigned int code)
unsigned int CGolay24128::decode24128(unsigned char* bytes)
{
assert(bytes != NULL);
assert(bytes != nullptr);
unsigned int code = bytes[0U];
code <<= 8;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2014,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2014,2016,2017,2018,2020,2025 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
@ -31,7 +31,7 @@
CIMRSNetwork::CIMRSNetwork() :
m_socket(IMRS_PORT),
m_dgIds(),
m_state(DS_NOTOPEN)
m_state(DGID_STATUS::NOTOPEN)
{
}
@ -54,7 +54,7 @@ void CIMRSNetwork::addDGId(unsigned int dgId, const std::string& name, const std
std::string CIMRSNetwork::getDesc(unsigned int dgId)
{
IMRSDGId* ptr = find(dgId);
if (ptr == NULL)
if (ptr == nullptr)
return "IMRS: Unknown";
return "IMRS: " + ptr->m_name;
@ -71,10 +71,10 @@ bool CIMRSNetwork::open()
bool ret = m_socket.open();
if (!ret) {
m_state = DS_NOTOPEN;
m_state = DGID_STATUS::NOTOPEN;
return false;
} else {
m_state = DS_NOTLINKED;
m_state = DGID_STATUS::NOTLINKED;
return true;
}
}
@ -86,10 +86,10 @@ DGID_STATUS CIMRSNetwork::getStatus()
void CIMRSNetwork::write(unsigned int dgId, const unsigned char* data)
{
assert(data != NULL);
assert(data != nullptr);
IMRSDGId* ptr = find(dgId);
if (ptr == NULL)
if (ptr == nullptr)
return;
CUtils::dump(1U, "YSF Data Received", data, 155U);
@ -112,8 +112,8 @@ void CIMRSNetwork::write(unsigned int dgId, const unsigned char* data)
bool CIMRSNetwork::writeHeaderTrailer(IMRSDGId* ptr, CYSFFICH& fich, const unsigned char* data)
{
assert(ptr != NULL);
assert(data != NULL);
assert(ptr != nullptr);
assert(data != nullptr);
unsigned char buffer[200U];
@ -158,8 +158,8 @@ bool CIMRSNetwork::writeHeaderTrailer(IMRSDGId* ptr, CYSFFICH& fich, const unsig
bool CIMRSNetwork::writeData(IMRSDGId* ptr, CYSFFICH& fich, const unsigned char* data)
{
assert(ptr != NULL);
assert(data != NULL);
assert(ptr != nullptr);
assert(data != nullptr);
unsigned char buffer[200U];
unsigned int length = 0U;
@ -253,8 +253,8 @@ bool CIMRSNetwork::writeData(IMRSDGId* ptr, CYSFFICH& fich, const unsigned char*
void CIMRSNetwork::readHeaderTrailer(IMRSDGId* ptr, CYSFFICH& fich, const unsigned char* data)
{
assert(ptr != NULL);
assert(data != NULL);
assert(ptr != nullptr);
assert(data != nullptr);
unsigned char buffer[155U];
@ -298,8 +298,8 @@ void CIMRSNetwork::readHeaderTrailer(IMRSDGId* ptr, CYSFFICH& fich, const unsign
void CIMRSNetwork::readData(IMRSDGId* ptr, CYSFFICH& fich, const unsigned char* data)
{
assert(ptr != NULL);
assert(data != NULL);
assert(ptr != nullptr);
assert(data != nullptr);
unsigned char buffer[155U];
@ -352,7 +352,7 @@ void CIMRSNetwork::readData(IMRSDGId* ptr, CYSFFICH& fich, const unsigned char*
if (fn == 0U && ft == 1U) {
// Copy the DCH
payload.writeVoiceFRModeData(data + 7U, buffer + 35U);
// NULL the unused section
// nullptr the unused section
::memset(buffer + 35U + YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES + 45U, 0x00U, 9U);
// Copy the audio
::memcpy(buffer + 35U + YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES + 54U, data + 27U + 0U, 18U);
@ -403,7 +403,7 @@ void CIMRSNetwork::clock(unsigned int ms)
CUtils::dump(1U, "IMRS Network Data Received", buffer, length);
IMRSDGId* ptr = find(addr);
if (ptr == NULL)
if (ptr == nullptr)
return;
if (ptr->m_debug)
@ -428,10 +428,10 @@ void CIMRSNetwork::clock(unsigned int ms)
unsigned int CIMRSNetwork::read(unsigned int dgId, unsigned char* data)
{
assert(data != NULL);
assert(data != nullptr);
IMRSDGId* ptr = find(dgId);
if (ptr == NULL)
if (ptr == nullptr)
return 0U;
if (ptr->m_buffer.isEmpty())
@ -451,7 +451,7 @@ void CIMRSNetwork::close()
m_socket.close();
m_state = DS_NOTOPEN;
m_state = DGID_STATUS::NOTOPEN;
}
IMRSDGId* CIMRSNetwork::find(const sockaddr_storage& addr) const
@ -463,7 +463,7 @@ IMRSDGId* CIMRSNetwork::find(const sockaddr_storage& addr) const
}
}
return NULL;
return nullptr;
}
IMRSDGId* CIMRSNetwork::find(unsigned int dgId) const
@ -473,5 +473,5 @@ IMRSDGId* CIMRSNetwork::find(unsigned int dgId) const
return *it;
}
return NULL;
return nullptr;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2014,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2014,2016,2017,2018,2020,2025 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
@ -42,8 +42,8 @@ public:
m_dgId(0U),
m_name(),
m_seqNo(0U),
m_source(NULL),
m_dest(NULL),
m_source(nullptr),
m_dest(nullptr),
m_destinations(),
m_debug(false),
m_buffer(1000U, "IMRS Buffer")

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2020,2025 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
@ -37,7 +37,7 @@ static std::string m_filePath;
static std::string m_fileRoot;
static bool m_fileRotate = true;
static FILE* m_fpLog = NULL;
static FILE* m_fpLog = nullptr;
static bool m_daemon = false;
static unsigned int m_displayLevel = 2U;
@ -59,10 +59,10 @@ static bool logOpenRotate()
struct tm* tm = ::gmtime(&now);
if (tm->tm_mday == m_tm.tm_mday && tm->tm_mon == m_tm.tm_mon && tm->tm_year == m_tm.tm_year) {
if (m_fpLog != NULL)
if (m_fpLog != nullptr)
return true;
} else {
if (m_fpLog != NULL)
if (m_fpLog != nullptr)
::fclose(m_fpLog);
}
@ -73,7 +73,7 @@ static bool logOpenRotate()
::sprintf(filename, "%s/%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
#endif
if ((m_fpLog = ::fopen(filename, "a+t")) != NULL) {
if ((m_fpLog = ::fopen(filename, "a+t")) != nullptr) {
status = true;
#if !defined(_WIN32) && !defined(_WIN64)
@ -94,7 +94,7 @@ static bool logOpenNoRotate()
if (m_fileLevel == 0U)
return true;
if (m_fpLog != NULL)
if (m_fpLog != nullptr)
return true;
char filename[200U];
@ -104,7 +104,7 @@ static bool logOpenNoRotate()
::sprintf(filename, "%s/%s.log", m_filePath.c_str(), m_fileRoot.c_str());
#endif
if ((m_fpLog = ::fopen(filename, "a+t")) != NULL) {
if ((m_fpLog = ::fopen(filename, "a+t")) != nullptr) {
status = true;
#if !defined(_WIN32) && !defined(_WIN64)
@ -141,13 +141,13 @@ bool LogInitialise(bool daemon, const std::string& filePath, const std::string&
void LogFinalise()
{
if (m_fpLog != NULL)
if (m_fpLog != nullptr)
::fclose(m_fpLog);
}
void Log(unsigned int level, const char* fmt, ...)
{
assert(fmt != NULL);
assert(fmt != nullptr);
char buffer[501U];
#if defined(_WIN32) || defined(_WIN64)
@ -157,7 +157,7 @@ void Log(unsigned int level, const char* fmt, ...)
::sprintf(buffer, "%c: %04u-%02u-%02u %02u:%02u:%02u.%03u ", LEVELS[level], st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
#else
struct timeval now;
::gettimeofday(&now, NULL);
::gettimeofday(&now, nullptr);
struct tm* tm = ::gmtime(&now.tv_sec);
@ -167,7 +167,7 @@ void Log(unsigned int level, const char* fmt, ...)
va_list vl;
va_start(vl, fmt);
::vsnprintf(buffer + ::strlen(buffer), 500, fmt, vl);
::vsnprintf(buffer + ::strlen(buffer), 500 - ::strlen(buffer), fmt, vl);
va_end(vl);

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2009,2012,2013,2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2006-2009,2012,2013,2015,2016,2025 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
@ -30,12 +30,12 @@ public:
CRingBuffer(unsigned int length, const char* name) :
m_length(length),
m_name(name),
m_buffer(NULL),
m_buffer(nullptr),
m_iPtr(0U),
m_oPtr(0U)
{
assert(length > 0U);
assert(name != NULL);
assert(name != nullptr);
m_buffer = new T[length];

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2018,2025 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
@ -77,7 +77,7 @@ CStopWatch::~CStopWatch()
unsigned long long CStopWatch::time() const
{
struct timeval now;
::gettimeofday(&now, NULL);
::gettimeofday(&now, nullptr);
return now.tv_sec * 1000ULL + now.tv_usec / 1000ULL;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2025 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
@ -26,7 +26,7 @@
void CSync::add(unsigned char* data)
{
assert(data != NULL);
assert(data != nullptr);
::memcpy(data, YSF_SYNC_BYTES, YSF_SYNC_LENGTH_BYTES);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2020,2025 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
@ -31,9 +31,9 @@ CThread::~CThread()
bool CThread::run()
{
m_handle = ::CreateThread(NULL, 0, &helper, this, 0, NULL);
m_handle = ::CreateThread(nullptr, 0, &helper, this, 0, nullptr);
return m_handle != NULL;
return m_handle != nullptr;
}
@ -74,13 +74,13 @@ CThread::~CThread()
bool CThread::run()
{
return ::pthread_create(&m_thread, NULL, helper, this) == 0;
return ::pthread_create(&m_thread, nullptr, helper, this) == 0;
}
void CThread::wait()
{
::pthread_join(m_thread, NULL);
::pthread_join(m_thread, nullptr);
}
@ -90,7 +90,7 @@ void* CThread::helper(void* arg)
p->entry();
return NULL;
return nullptr;
}
void CThread::sleep(unsigned int ms)
@ -100,7 +100,7 @@ void CThread::sleep(unsigned int ms)
ts.tv_sec = ms / 1000U;
ts.tv_nsec = (ms % 1000U) * 1000000U;
::nanosleep(&ts, NULL);
::nanosleep(&ts, nullptr);
}
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2006-2016,2020,2024,2025 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
@ -34,29 +34,27 @@
#endif
CUDPSocket::CUDPSocket(const std::string& address, unsigned short port) :
m_address_save(address),
m_port_save(port),
m_counter(0U)
m_localAddress(address),
m_localPort(port),
#if defined(_WIN32) || defined(_WIN64)
m_fd(INVALID_SOCKET),
#else
m_fd(-1),
#endif
m_af(AF_UNSPEC)
{
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
m_af[i] = 0U;
m_fd[i] = -1;
}
}
CUDPSocket::CUDPSocket(unsigned short port) :
m_address_save(),
m_port_save(port),
m_counter(0U)
m_localAddress(),
m_localPort(port),
#if defined(_WIN32) || defined(_WIN64)
m_fd(INVALID_SOCKET),
#else
m_fd(-1),
#endif
m_af(AF_UNSPEC)
{
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
m_af[i] = 0U;
m_fd[i] = -1;
}
}
CUDPSocket::~CUDPSocket()
@ -93,10 +91,10 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned short port, sockadd
std::string portstr = std::to_string(port);
struct addrinfo *res;
/* port is always digits, no needs to lookup service */
/* Port is always digits, no needs to lookup service */
hints.ai_flags |= AI_NUMERICSERV;
int err = getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res);
int err = ::getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res);
if (err != 0) {
sockaddr_in* paddr = (sockaddr_in*)&addr;
::memset(paddr, 0x00U, address_length = sizeof(sockaddr_in));
@ -107,9 +105,11 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned short port, sockadd
return err;
}
::memcpy(&addr, res->ai_addr, address_length = res->ai_addrlen);
address_length = (unsigned int)res->ai_addrlen;
freeaddrinfo(res);
::memcpy(&addr, res->ai_addr, address_length);
::freeaddrinfo(res);
return 0;
}
@ -119,35 +119,35 @@ bool CUDPSocket::match(const sockaddr_storage& addr1, const sockaddr_storage& ad
if (addr1.ss_family != addr2.ss_family)
return false;
if (type == IMT_ADDRESS_AND_PORT) {
if (type == IPMATCHTYPE::ADDRESS_AND_PORT) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port);
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port);
default:
return false;
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port);
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port);
default:
return false;
}
} else if (type == IMT_ADDRESS_ONLY) {
} else if (type == IPMATCHTYPE::ADDRESS_ONLY) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr;
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr);
default:
return false;
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr;
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr);
default:
return false;
}
} else {
return false;
@ -156,42 +156,45 @@ bool CUDPSocket::match(const sockaddr_storage& addr1, const sockaddr_storage& ad
bool CUDPSocket::isNone(const sockaddr_storage& addr)
{
struct sockaddr_in *in = (struct sockaddr_in *)&addr;
struct sockaddr_in *in = (struct sockaddr_in*)&addr;
return ((addr.ss_family == AF_INET) && (in->sin_addr.s_addr == htonl(INADDR_NONE)));
}
bool CUDPSocket::open(const sockaddr_storage& address)
{
return open(address.ss_family);
m_af = address.ss_family;
return open();
}
bool CUDPSocket::open(unsigned int af)
bool CUDPSocket::open()
{
return open(0, af, m_address_save, m_port_save);
}
#if defined(_WIN32) || defined(_WIN64)
assert(m_fd == INVALID_SOCKET);
#else
assert(m_fd == -1);
#endif
bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned short port)
{
sockaddr_storage addr;
unsigned int addrlen;
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = af;
hints.ai_family = m_af;
/* to determine protocol family, call lookup() first. */
int err = lookup(address, port, addr, addrlen, hints);
// To determine protocol family, call lookup() on the local address first.
int err = lookup(m_localAddress, m_localPort, addr, addrlen, hints);
if (err != 0) {
LogError("The local address is invalid - %s", address.c_str());
LogError("The local address is invalid - %s", m_localAddress.c_str());
return false;
}
close(index);
m_af = addr.ss_family;
int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0);
if (fd < 0) {
m_fd = ::socket(m_af, SOCK_DGRAM, 0);
if (m_fd < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot create the UDP socket, err: %lu", ::GetLastError());
#else
@ -200,62 +203,58 @@ bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std
return false;
}
m_address[index] = address;
m_port[index] = port;
m_af[index] = addr.ss_family;
m_fd[index] = fd;
if (port > 0U) {
if (m_localPort > 0U) {
int reuse = 1;
if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError());
#else
LogError("Cannot set the UDP socket option, err: %d", errno);
#endif
close();
return false;
}
if (::bind(fd, (sockaddr*)&addr, addrlen) == -1) {
if (::bind(m_fd, (sockaddr*)&addr, addrlen) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot bind the UDP address, err: %lu", ::GetLastError());
#else
LogError("Cannot bind the UDP address, err: %d", errno);
#endif
close();
return false;
}
LogInfo("Opening UDP port on %hu", port);
LogInfo("Opening UDP port on %hu", m_localPort);
}
return true;
}
int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length)
int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int& addressLength)
{
assert(buffer != NULL);
assert(buffer != nullptr);
assert(length > 0U);
// Check that the readfrom() won't block
int i, n;
struct pollfd pfd[UDP_SOCKET_MAX];
for (i = n = 0; i < UDP_SOCKET_MAX; i++) {
if (m_fd[i] >= 0) {
pfd[n].fd = m_fd[i];
pfd[n].events = POLLIN;
n++;
}
}
// no socket descriptor to receive
if (n == 0)
#if defined(_WIN32) || defined(_WIN64)
if (m_fd == INVALID_SOCKET)
return 0;
#else
if (m_fd == -1)
return 0;
#endif
// Check that the readfrom() won't block
struct pollfd pfd;
pfd.fd = m_fd;
pfd.events = POLLIN;
pfd.revents = 0;
// Return immediately
#if defined(_WIN32) || defined(_WIN64)
int ret = WSAPoll(pfd, n, 0);
int ret = WSAPoll(&pfd, 1, 0);
#else
int ret = ::poll(pfd, n, 0);
int ret = ::poll(&pfd, 1, 0);
#endif
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
@ -266,14 +265,7 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
return -1;
}
int index;
for (i = 0; i < n; i++) {
// round robin
index = (i + m_counter) % n;
if (pfd[index].revents & POLLIN)
break;
}
if (i == n)
if ((pfd.revents & POLLIN) == 0)
return 0;
#if defined(_WIN32) || defined(_WIN64)
@ -283,9 +275,9 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
#endif
#if defined(_WIN32) || defined(_WIN64)
int len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr*)&address, &size);
#else
ssize_t len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr*)&address, &size);
#endif
if (len <= 0) {
#if defined(_WIN32) || defined(_WIN64)
@ -294,7 +286,7 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
LogError("Error returned from recvfrom, err: %d", errno);
if (len == -1 && errno == ENOTSOCK) {
LogMessage("Re-opening UDP port on %hu", m_port[index]);
LogMessage("Re-opening UDP port on %hu", m_localPort);
close();
open();
}
@ -302,43 +294,43 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
return -1;
}
m_counter++;
address_length = size;
addressLength = size;
return len;
}
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length)
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int addressLength)
{
assert(buffer != NULL);
assert(buffer != nullptr);
assert(length > 0U);
#if defined(_WIN32) || defined(_WIN64)
assert(m_fd != INVALID_SOCKET);
#else
assert(m_fd >= 0);
#endif
bool result = false;
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
if (m_fd[i] < 0 || m_af[i] != address.ss_family)
continue;
#if defined(_WIN32) || defined(_WIN64)
int ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
int ret = ::sendto(m_fd, (char*)buffer, length, 0, (sockaddr*)&address, addressLength);
#else
ssize_t ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
ssize_t ret = ::sendto(m_fd, (char*)buffer, length, 0, (sockaddr*)&address, addressLength);
#endif
if (ret < 0) {
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from sendto, err: %lu", ::GetLastError());
LogError("Error returned from sendto, err: %lu", ::GetLastError());
#else
LogError("Error returned from sendto, err: %d", errno);
LogError("Error returned from sendto, err: %d", errno);
#endif
} else {
} else {
#if defined(_WIN32) || defined(_WIN64)
if (ret == int(length))
result = true;
if (ret == int(length))
result = true;
#else
if (ret == ssize_t(length))
result = true;
if (ret == ssize_t(length))
result = true;
#endif
}
}
return result;
@ -346,18 +338,15 @@ bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const s
void CUDPSocket::close()
{
for (unsigned int i = 0; i < UDP_SOCKET_MAX; i++)
close(i);
}
void CUDPSocket::close(const unsigned int index)
{
if ((index < UDP_SOCKET_MAX) && (m_fd[index] >= 0)) {
#if defined(_WIN32) || defined(_WIN64)
::closesocket(m_fd[index]);
#else
::close(m_fd[index]);
#endif
m_fd[index] = -1;
if (m_fd != INVALID_SOCKET) {
::closesocket(m_fd);
m_fd = INVALID_SOCKET;
}
#else
if (m_fd >= 0) {
::close(m_fd);
m_fd = -1;
}
#endif
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2011,2013,2015,2016,2020,2024,2025 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
@ -35,13 +35,9 @@
#include <ws2tcpip.h>
#endif
#if !defined(UDP_SOCKET_MAX)
#define UDP_SOCKET_MAX 1
#endif
enum IPMATCHTYPE {
IMT_ADDRESS_AND_PORT,
IMT_ADDRESS_ONLY
enum class IPMATCHTYPE {
ADDRESS_AND_PORT,
ADDRESS_ONLY
};
class CUDPSocket {
@ -50,34 +46,34 @@ public:
CUDPSocket(unsigned short port = 0U);
~CUDPSocket();
bool open(unsigned int af = AF_UNSPEC);
bool open();
bool open(const sockaddr_storage& address);
bool open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned short port);
int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length);
bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length);
int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &addressLength);
bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int addressLength);
void close();
void close(const unsigned int index);
static void startup();
static void shutdown();
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& address_length);
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& address_length, struct addrinfo& hints);
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& addressLength);
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& addressLength, struct addrinfo& hints);
static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type = IMT_ADDRESS_AND_PORT);
static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type = IPMATCHTYPE::ADDRESS_AND_PORT);
static bool isNone(const sockaddr_storage& addr);
private:
std::string m_address_save;
unsigned short m_port_save;
std::string m_address[UDP_SOCKET_MAX];
unsigned short m_port[UDP_SOCKET_MAX];
unsigned int m_af[UDP_SOCKET_MAX];
int m_fd[UDP_SOCKET_MAX];
unsigned int m_counter;
std::string m_localAddress;
unsigned short m_localPort;
#if defined(_WIN32) || defined(_WIN64)
SOCKET m_fd;
int m_af;
#else
int m_fd;
sa_family_t m_af;
#endif
};
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009,2014,2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2009,2014,2015,2016,2025 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
@ -19,14 +19,14 @@
void CUtils::dump(const std::string& title, const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(data != nullptr);
dump(2U, title, data, length);
}
void CUtils::dump(int level, const std::string& title, const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(data != nullptr);
::Log(level, "%s", title.c_str());
@ -72,14 +72,14 @@ void CUtils::dump(int level, const std::string& title, const unsigned char* data
void CUtils::dump(const std::string& title, const bool* bits, unsigned int length)
{
assert(bits != NULL);
assert(bits != nullptr);
dump(2U, title, bits, length);
}
void CUtils::dump(int level, const std::string& title, const bool* bits, unsigned int length)
{
assert(bits != NULL);
assert(bits != nullptr);
unsigned char bytes[100U];
unsigned int nBytes = 0U;
@ -91,7 +91,7 @@ void CUtils::dump(int level, const std::string& title, const bool* bits, unsigne
void CUtils::byteToBitsBE(unsigned char byte, bool* bits)
{
assert(bits != NULL);
assert(bits != nullptr);
bits[0U] = (byte & 0x80U) == 0x80U;
bits[1U] = (byte & 0x40U) == 0x40U;
@ -105,7 +105,7 @@ void CUtils::byteToBitsBE(unsigned char byte, bool* bits)
void CUtils::byteToBitsLE(unsigned char byte, bool* bits)
{
assert(bits != NULL);
assert(bits != nullptr);
bits[0U] = (byte & 0x01U) == 0x01U;
bits[1U] = (byte & 0x02U) == 0x02U;
@ -119,7 +119,7 @@ void CUtils::byteToBitsLE(unsigned char byte, bool* bits)
void CUtils::bitsToByteBE(const bool* bits, unsigned char& byte)
{
assert(bits != NULL);
assert(bits != nullptr);
byte = bits[0U] ? 0x80U : 0x00U;
byte |= bits[1U] ? 0x40U : 0x00U;
@ -133,7 +133,7 @@ void CUtils::bitsToByteBE(const bool* bits, unsigned char& byte)
void CUtils::bitsToByteLE(const bool* bits, unsigned char& byte)
{
assert(bits != NULL);
assert(bits != nullptr);
byte = bits[0U] ? 0x01U : 0x00U;
byte |= bits[1U] ? 0x02U : 0x00U;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2021 by Jonathan Naylor G4KLX
* Copyright (C) 2015-2021,2023,2024,2025 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
@ -19,6 +19,6 @@
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20230212";
const char* VERSION = "20250607";
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2016,2025 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
@ -36,12 +36,12 @@ const uint32_t M = 2U;
const unsigned int K = 5U;
CYSFConvolution::CYSFConvolution() :
m_metrics1(NULL),
m_metrics2(NULL),
m_oldMetrics(NULL),
m_newMetrics(NULL),
m_decisions(NULL),
m_dp(NULL)
m_metrics1(nullptr),
m_metrics2(nullptr),
m_oldMetrics(nullptr),
m_newMetrics(nullptr),
m_decisions(nullptr),
m_dp(nullptr)
{
m_metrics1 = new uint16_t[16U];
m_metrics2 = new uint16_t[16U];
@ -98,7 +98,7 @@ void CYSFConvolution::decode(uint8_t s0, uint8_t s1)
void CYSFConvolution::chainback(unsigned char* out, unsigned int nBits)
{
assert(out != NULL);
assert(out != nullptr);
uint32_t state = 0U;
@ -115,8 +115,8 @@ void CYSFConvolution::chainback(unsigned char* out, unsigned int nBits)
void CYSFConvolution::encode(const unsigned char* in, unsigned char* out, unsigned int nBits) const
{
assert(in != NULL);
assert(out != NULL);
assert(in != nullptr);
assert(out != nullptr);
assert(nBits > 0U);
uint8_t d1 = 0U, d2 = 0U, d3 = 0U, d4 = 0U;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016,2017,2019,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017,2019,2020,2025 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
@ -55,7 +55,7 @@ const unsigned int INTERLEAVE_TABLE[] = {
38U, 78U, 118U, 158U, 198U};
CYSFFICH::CYSFFICH(const CYSFFICH& fich) :
m_fich(NULL)
m_fich(nullptr)
{
m_fich = new unsigned char[6U];
@ -63,7 +63,7 @@ m_fich(NULL)
}
CYSFFICH::CYSFFICH() :
m_fich(NULL)
m_fich(nullptr)
{
m_fich = new unsigned char[6U];
@ -77,7 +77,7 @@ CYSFFICH::~CYSFFICH()
bool CYSFFICH::decode(const unsigned char* bytes)
{
assert(bytes != NULL);
assert(bytes != nullptr);
// Skip the sync bytes
bytes += YSF_SYNC_LENGTH_BYTES;
@ -116,7 +116,7 @@ bool CYSFFICH::decode(const unsigned char* bytes)
void CYSFFICH::encode(unsigned char* bytes)
{
assert(bytes != NULL);
assert(bytes != nullptr);
// Skip the sync bytes
bytes += YSF_SYNC_LENGTH_BYTES;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,43 @@
#! /bin/bash
###############################################################################
#
# Copyright (C) 2025 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.
#
###############################################################################
#
# Full path to the YSFHosts hosts file
#
YSFHOSTS=/path/to/YSFHosts.txt
###############################################################################
#
# Do not edit below here
#
###############################################################################
# Check we are root
if [ "$(id -u)" != "0" ]
then
echo "This script must be run as root" 1>&2
exit 1
fi
# Download the YSFHosts.txt file
curl https://dvref.com/downloads/YSFHosts-resolved.txt > ${YSFHOSTS}
exit 0

View file

@ -1,91 +0,0 @@
#! /bin/bash
###############################################################################
#
# YSFHostsupdate.sh
#
# Copyright (C) 2016 by Tony Corbett G0WFV
# Adapted to YSFHosts by Paul Nannery KC2VRJ on 6/28/2016 with all crdeit
# to G0WFV for the orignal script.
#
# 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.
#
###############################################################################
#
# On a Linux based system, such as a Raspberry Pi, this script will perform all
# the steps required to maintain the YSFHosts.txt (or similar) file for you.
#
# It is designed to run from crontab and will download the YSFHosts from the
# master ysfreflector.de database and optionally keep a backup of previously
# created files for you.
#
# It will also prune the number of backup files according to a value specified
# by you in the configuration below.
#
# To install in root's crontab use the command ...
#
# sudo crontab -e
#
# ... and add the following line to the bottom of the file ...
#
# 0 0 * * * /path/to/script/YSFHostsupdate.sh 1>/dev/null 2>&1
#
# ... where /path/to/script/ should be replaced by the path to this script.
#
###############################################################################
#
# CONFIGURATION
#
# Full path to YSFHosts
YSFHOSTS=/path/to/YSFHosts.txt
# How many YSFHosts files do you want backed up (0 = do not keep backups)
YSFHOSTSFILEBACKUP=1
###############################################################################
#
# Do not edit below here
#
###############################################################################
# Check we are root
if [ "$(id -u)" != "0" ]
then
echo "This script must be run as root" 1>&2
exit 1
fi
# Create backup of old file
if [ ${YSFHOSTSFILEBACKUP} -ne 0 ]
then
cp ${YSFHOSTS} ${YSFHOSTS}.$(date +%d%m%y)
fi
# Prune backups
BACKUPCOUNT=$(ls ${YSFHOSTS}.* | wc -l)
BACKUPSTODELETE=$(expr ${BACKUPCOUNT} - ${YSFHOSTSFILEBACKUP})
if [ ${BACKUPCOUNT} -gt ${YSFHOSTSFILEBACKUP} ]
then
for f in $(ls -tr ${YSFHOSTS}.* | head -${BACKUPSTODELETE})
do
rm -f $f
done
fi
# Generate YSFHosts.txt file
curl https://register.ysfreflector.de/export_csv.php > ${YSFHOSTS}
exit 0

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2014,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2014,2016,2017,2018,2020,2025 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
@ -33,13 +33,13 @@ m_debug(debug),
m_addr(addr),
m_addrLen(addrLen),
m_static(true),
m_poll(NULL),
m_unlink(NULL),
m_poll(nullptr),
m_unlink(nullptr),
m_buffer(1000U, "YSF Network Buffer"),
m_sendPollTimer(1000U, 5U),
m_recvPollTimer(1000U, 60U),
m_name(name),
m_state(DS_NOTOPEN)
m_state(DGID_STATUS::NOTOPEN)
{
m_poll = new unsigned char[14U];
::memcpy(m_poll + 0U, "YSFP", 4U);
@ -62,13 +62,13 @@ m_debug(debug),
m_addr(addr),
m_addrLen(addrLen),
m_static(statc),
m_poll(NULL),
m_unlink(NULL),
m_poll(nullptr),
m_unlink(nullptr),
m_buffer(1000U, "YSF Network Buffer"),
m_sendPollTimer(1000U, 5U),
m_recvPollTimer(1000U, 60U),
m_name(name),
m_state(DS_NOTOPEN)
m_state(DGID_STATUS::NOTOPEN)
{
m_poll = new unsigned char[14U];
::memcpy(m_poll + 0U, "YSFP", 4U);
@ -105,7 +105,7 @@ bool CYSFNetwork::open()
{
if (m_addrLen == 0U) {
LogError("Unable to resolve the address of the YSF network");
m_state = DS_NOTOPEN;
m_state = DGID_STATUS::NOTOPEN;
return false;
}
@ -113,10 +113,10 @@ bool CYSFNetwork::open()
bool ret = m_socket.open(m_addr);
if (!ret) {
m_state = DS_NOTOPEN;
m_state = DGID_STATUS::NOTOPEN;
return false;
} else {
m_state = DS_NOTLINKED;
m_state = DGID_STATUS::NOTLINKED;
return true;
}
}
@ -128,9 +128,9 @@ DGID_STATUS CYSFNetwork::getStatus()
void CYSFNetwork::write(unsigned int dgid, const unsigned char* data)
{
assert(data != NULL);
assert(data != nullptr);
if (m_state != DS_LINKED)
if (m_state != DGID_STATUS::LINKED)
return;
if (m_debug)
@ -141,10 +141,10 @@ void CYSFNetwork::write(unsigned int dgid, const unsigned char* data)
void CYSFNetwork::link()
{
if (m_state != DS_NOTLINKED)
if (m_state != DGID_STATUS::NOTLINKED)
return;
m_state = DS_LINKING;
m_state = DGID_STATUS::LINKING;
m_sendPollTimer.start();
m_recvPollTimer.start();
@ -154,7 +154,7 @@ void CYSFNetwork::link()
void CYSFNetwork::writePoll()
{
if (m_state != DS_LINKING && m_state != DS_LINKED)
if (m_state != DGID_STATUS::LINKING && m_state != DGID_STATUS::LINKED)
return;
if (m_debug)
@ -165,7 +165,7 @@ void CYSFNetwork::writePoll()
void CYSFNetwork::unlink()
{
if (m_state != DS_LINKED)
if (m_state != DGID_STATUS::LINKED)
return;
m_sendPollTimer.stop();
@ -178,20 +178,20 @@ void CYSFNetwork::unlink()
LogMessage("Unlinked from %s", m_name.c_str());
m_state = DS_NOTLINKED;
m_state = DGID_STATUS::NOTLINKED;
}
void CYSFNetwork::clock(unsigned int ms)
{
if (m_state == DS_NOTOPEN)
if (m_state == DGID_STATUS::NOTOPEN)
return;
m_recvPollTimer.clock(ms);
if (m_recvPollTimer.isRunning() && m_recvPollTimer.hasExpired()) {
if (m_static) {
m_state = DS_LINKING;
m_state = DGID_STATUS::LINKING;
} else {
m_state = DS_NOTLINKED;
m_state = DGID_STATUS::NOTLINKED;
m_sendPollTimer.stop();
}
@ -224,13 +224,13 @@ void CYSFNetwork::clock(unsigned int ms)
if (::memcmp(buffer, "YSFP", 4U) == 0) {
m_recvPollTimer.start();
if (m_state == DS_LINKING) {
if (m_state == DGID_STATUS::LINKING) {
if (strcmp(m_name.c_str(), "MMDVM") == 0)
LogMessage("Link successful to %s", m_name.c_str());
else
LogMessage("Linked to %s", m_name.c_str());
m_state = DS_LINKED;
m_state = DGID_STATUS::LINKED;
}
}
@ -246,7 +246,7 @@ void CYSFNetwork::clock(unsigned int ms)
unsigned int CYSFNetwork::read(unsigned int dgid, unsigned char* data)
{
assert(data != NULL);
assert(data != nullptr);
if (m_buffer.isEmpty())
return 0U;
@ -265,5 +265,5 @@ void CYSFNetwork::close()
LogMessage("Closing YSF network connection");
m_state = DS_NOTOPEN;
m_state = DGID_STATUS::NOTOPEN;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016,2020 Jonathan Naylor, G4KLX
* Copyright (C) 2016,2020,2025 Jonathan Naylor, G4KLX
* Copyright (C) 2016 Mathias Weyland, HB9FRV
*
* This program is free software; you can redistribute it and/or modify
@ -86,8 +86,8 @@ CYSFPayload::~CYSFPayload()
bool CYSFPayload::readHeaderData(const unsigned char* data, unsigned char* dt)
{
assert(data != NULL);
assert(dt != NULL);
assert(data != nullptr);
assert(dt != nullptr);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -154,8 +154,8 @@ bool CYSFPayload::readHeaderData(const unsigned char* data, unsigned char* dt)
bool CYSFPayload::readVDMode1Data(const unsigned char* data, unsigned char* dt)
{
assert(data != NULL);
assert(dt != NULL);
assert(data != nullptr);
assert(dt != nullptr);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -195,8 +195,8 @@ bool CYSFPayload::readVDMode1Data(const unsigned char* data, unsigned char* dt)
bool CYSFPayload::readVDMode2Data(const unsigned char* data, unsigned char* dt)
{
assert(data != NULL);
assert(dt != NULL);
assert(data != nullptr);
assert(dt != nullptr);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -236,8 +236,8 @@ bool CYSFPayload::readVDMode2Data(const unsigned char* data, unsigned char* dt)
bool CYSFPayload::readDataFRModeData1(const unsigned char* data, unsigned char* dt)
{
assert(data != NULL);
assert(dt != NULL);
assert(data != nullptr);
assert(dt != nullptr);
::memset(dt, ' ', 20U);
@ -279,8 +279,8 @@ bool CYSFPayload::readDataFRModeData1(const unsigned char* data, unsigned char*
bool CYSFPayload::readVoiceFRModeData(const unsigned char* data, unsigned char* dt)
{
assert(data != NULL);
assert(dt != NULL);
assert(data != nullptr);
assert(dt != nullptr);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -314,8 +314,8 @@ bool CYSFPayload::readVoiceFRModeData(const unsigned char* data, unsigned char*
bool CYSFPayload::readDataFRModeData2(const unsigned char* data, unsigned char* dt)
{
assert(data != NULL);
assert(dt != NULL);
assert(data != nullptr);
assert(dt != nullptr);
::memset(dt, ' ', 20U);
@ -357,8 +357,8 @@ bool CYSFPayload::readDataFRModeData2(const unsigned char* data, unsigned char*
void CYSFPayload::writeHeaderData(const unsigned char* dt, unsigned char* data)
{
assert(dt != NULL);
assert(data != NULL);
assert(dt != nullptr);
assert(data != nullptr);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -374,7 +374,7 @@ void CYSFPayload::writeHeaderData(const unsigned char* dt, unsigned char* data)
CYSFConvolution conv;
conv.encode(output, convolved, 180U);
unsigned char bytes[45U];
unsigned char bytes[45U] = { 0x00U };
unsigned int j = 0U;
for (unsigned int i = 0U; i < 180U; i++) {
unsigned int n = INTERLEAVE_TABLE_9_20[i];
@ -431,8 +431,8 @@ void CYSFPayload::writeHeaderData(const unsigned char* dt, unsigned char* data)
void CYSFPayload::writeVDMode1Data(const unsigned char* dt, unsigned char* data)
{
assert(dt != NULL);
assert(data != NULL);
assert(dt != nullptr);
assert(data != nullptr);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -448,7 +448,7 @@ void CYSFPayload::writeVDMode1Data(const unsigned char* dt, unsigned char* data)
CYSFConvolution conv;
conv.encode(output, convolved, 180U);
unsigned char bytes[45U];
unsigned char bytes[45U] = { 0x00U };
unsigned int j = 0U;
for (unsigned int i = 0U; i < 180U; i++) {
unsigned int n = INTERLEAVE_TABLE_9_20[i];
@ -475,8 +475,8 @@ void CYSFPayload::writeVDMode1Data(const unsigned char* dt, unsigned char* data)
void CYSFPayload::writeVDMode2Data(const unsigned char* dt, unsigned char* data)
{
assert(dt != NULL);
assert(data != NULL);
assert(dt != nullptr);
assert(data != nullptr);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -492,7 +492,7 @@ void CYSFPayload::writeVDMode2Data(const unsigned char* dt, unsigned char* data)
CYSFConvolution conv;
conv.encode(output, convolved, 100U);
unsigned char bytes[25U];
unsigned char bytes[25U] = { 0x00U };
unsigned int j = 0U;
for (unsigned int i = 0U; i < 100U; i++) {
unsigned int n = INTERLEAVE_TABLE_5_20[i];
@ -519,8 +519,8 @@ void CYSFPayload::writeVDMode2Data(const unsigned char* dt, unsigned char* data)
void CYSFPayload::writeVoiceFRModeData(const unsigned char* dt, unsigned char* data)
{
assert(dt != NULL);
assert(data != NULL);
assert(dt != nullptr);
assert(data != nullptr);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -536,7 +536,7 @@ void CYSFPayload::writeVoiceFRModeData(const unsigned char* dt, unsigned char* d
CYSFConvolution conv;
conv.encode(output, convolved, 180U);
unsigned char bytes[45U];
unsigned char bytes[45U] = { 0x00U };
unsigned int j = 0U;
for (unsigned int i = 0U; i < 180U; i++) {
unsigned int n = INTERLEAVE_TABLE_9_20[i];
@ -558,8 +558,8 @@ void CYSFPayload::writeVoiceFRModeData(const unsigned char* dt, unsigned char* d
void CYSFPayload::writeDataFRModeData1(const unsigned char* dt, unsigned char* data)
{
assert(dt != NULL);
assert(data != NULL);
assert(dt != nullptr);
assert(data != nullptr);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -575,7 +575,7 @@ void CYSFPayload::writeDataFRModeData1(const unsigned char* dt, unsigned char* d
CYSFConvolution conv;
conv.encode(output, convolved, 180U);
unsigned char bytes[45U];
unsigned char bytes[45U] = { 0x00U };
unsigned int j = 0U;
for (unsigned int i = 0U; i < 180U; i++) {
unsigned int n = INTERLEAVE_TABLE_9_20[i];
@ -602,8 +602,8 @@ void CYSFPayload::writeDataFRModeData1(const unsigned char* dt, unsigned char* d
void CYSFPayload::writeDataFRModeData2(const unsigned char* dt, unsigned char* data)
{
assert(dt != NULL);
assert(data != NULL);
assert(dt != nullptr);
assert(data != nullptr);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -619,7 +619,7 @@ void CYSFPayload::writeDataFRModeData2(const unsigned char* dt, unsigned char* d
CYSFConvolution conv;
conv.encode(output, convolved, 180U);
unsigned char bytes[45U];
unsigned char bytes[45U] = { 0x00U };
unsigned int j = 0U;
for (unsigned int i = 0U; i < 180U; i++) {
unsigned int n = INTERLEAVE_TABLE_9_20[i];

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016-2020,2025 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
@ -43,24 +43,24 @@ CYSFReflectors::~CYSFReflectors()
bool CYSFReflectors::load()
{
FILE* fp = ::fopen(m_hostsFile.c_str(), "rt");
if (fp != NULL) {
if (fp != nullptr) {
char buffer[100U];
while (::fgets(buffer, 100U, fp) != NULL) {
while (::fgets(buffer, 100U, fp) != nullptr) {
if (buffer[0U] == '#')
continue;
char* p1 = ::strtok(buffer, ";\r\n");
char* p2 = ::strtok(NULL, ";\r\n");
char* p3 = ::strtok(NULL, ";\r\n");
char* p4 = ::strtok(NULL, ";\r\n");
char* p5 = ::strtok(NULL, ";\r\n");
char* p6 = ::strtok(NULL, "\r\n");
char* p2 = ::strtok(nullptr, ";\r\n");
char* p3 = ::strtok(nullptr, ";\r\n");
char* p4 = ::strtok(nullptr, ";\r\n");
char* p5 = ::strtok(nullptr, ";\r\n");
char* p6 = ::strtok(nullptr, "\r\n");
if (p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL && p5 != NULL && p6 != NULL) {
if (p1 != nullptr && p2 != nullptr && p3 != nullptr && p4 != nullptr && p5 != nullptr && p6 != nullptr) {
std::string host = std::string(p4);
unsigned short port = (unsigned short)::atoi(p5);
if (::strstr(p1, "YCS") == NULL && ::strstr(p2, "YCS") == NULL) {
if (::strstr(p1, "YCS") == nullptr && ::strstr(p2, "YCS") == nullptr) {
sockaddr_storage addr;
unsigned int addrLen;
if (CUDPSocket::lookup(host, port, addr, addrLen) == 0) {
@ -95,7 +95,7 @@ CYSFReflector* CYSFReflectors::findById(const std::string& id)
LogMessage("Trying to find non existent YSF reflector with an id of %s", id.c_str());
return NULL;
return nullptr;
}
CYSFReflector* CYSFReflectors::findByName(const std::string& name)
@ -107,6 +107,6 @@ CYSFReflector* CYSFReflectors::findByName(const std::string& name)
LogMessage("Trying to find non existent YSF reflector with a name of %s", name.c_str());
return NULL;
return nullptr;
}

38
DGIdGateway/prebuild.cmd Normal file
View file

@ -0,0 +1,38 @@
@echo off
REM This pre-build file is for MSVS VC++. It parses the git master hash and
REM converts it into GitVersion.h for compiling into builds. [George M1GEO]
cd %1
setlocal enabledelayedexpansion
set HEADFILE=..\.git\HEAD
set HASHFILE=0
if exist %HEADFILE% (
for /F "tokens=4 delims=/:" %%a in ('type %HEADFILE%') do set HEADBRANCH=%%a
set HASHFILE=..\.git\refs\heads\!HEADBRANCH!
echo Found Git HEAD file: %HEADFILE%
echo Git HEAD branch: !HEADBRANCH!
echo Git HASH file: !HASHFILE!
call :USEHASH
) else (
echo No head file :(
call :USENULL
)
goto :EOF
:USENULL
set GITHASH=0000000000000000000000000000000000000000
goto :WRITEGITVERSIONHEADER
:USEHASH
for /f %%i in ('type !HASHFILE!') do set GITHASH=%%i
goto :WRITEGITVERSIONHEADER
:WRITEGITVERSIONHEADER
echo // File contains Git commit ID SHA1 present at buildtime (prebuild.cmd) > GitVersion.h
echo const char *gitversion = "%GITHASH%"; >> GitVersion.h
echo Current Git HASH: %GITHASH%
goto :FINISHED
:FINISHED
echo GitVersion.h written...

View file

@ -10,6 +10,8 @@ The Gateways have ini files that contain the parameters for running the software
The MMDVM .ini file should have the IP address and port number of the client in the [System Fusion Network] settings.
The file that contains the information about the reachable YSF reflectors is held in the YSFHosts.txt files that should be donwloaded from the DVRef.com web site. A script to do this under Linux is included. This is handled automatically in WPSD and Pi-Star.
They build on 32-bit and 64-bit Linux as well as on Windows using Visual Studio 2019 on x86 and x64.
This software is licenced under the GPL v2 and is primarily intended for amateur and educational use.

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2010-2014,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2010-2014,2016,2017,2018,2020,2025 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
@ -106,7 +106,7 @@ bool CAPRSWriter::open()
return false;
}
::gps_stream(&m_gpsdData, WATCH_ENABLE | WATCH_JSON, NULL);
::gps_stream(&m_gpsdData, WATCH_ENABLE | WATCH_JSON, nullptr);
LogMessage("Connected to GPSD");
}
@ -125,8 +125,8 @@ bool CAPRSWriter::open()
void CAPRSWriter::write(const unsigned char* source, const char* type, unsigned char radio, float fLatitude, float fLongitude)
{
assert(source != NULL);
assert(type != NULL);
assert(source != nullptr);
assert(type != nullptr);
char callsign[15U];
::memcpy(callsign, source, YSF_CALLSIGN_LENGTH);
@ -219,7 +219,7 @@ void CAPRSWriter::close()
#if defined(USE_GPSD)
if (m_gpsdEnabled) {
::gps_stream(&m_gpsdData, WATCH_DISABLE, NULL);
::gps_stream(&m_gpsdData, WATCH_DISABLE, nullptr);
::gps_close(&m_gpsdData);
}
#endif
@ -300,7 +300,7 @@ void CAPRSWriter::sendIdFrameMobile()
return;
#if GPSD_API_MAJOR_VERSION >= 7
if (::gps_read(&m_gpsdData, NULL, 0) <= 0)
if (::gps_read(&m_gpsdData, nullptr, 0) <= 0)
return;
#else
if (::gps_read(&m_gpsdData) <= 0)

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2025 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
@ -63,7 +63,7 @@ const uint16_t CCITT16_TABLE2[] = {
void CCRC::addCCITT16(unsigned char *in, unsigned int length)
{
assert(in != NULL);
assert(in != nullptr);
assert(length > 2U);
union {
@ -84,7 +84,7 @@ void CCRC::addCCITT16(unsigned char *in, unsigned int length)
bool CCRC::checkCCITT16(const unsigned char *in, unsigned int length)
{
assert(in != NULL);
assert(in != nullptr);
assert(length > 2U);
union {
@ -104,7 +104,7 @@ bool CCRC::checkCCITT16(const unsigned char *in, unsigned int length)
unsigned char CCRC::addCRC(const unsigned char* in, unsigned int length)
{
assert(in != NULL);
assert(in != nullptr);
unsigned char crc = 0U;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015-2020,2025 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
@ -26,17 +26,17 @@
const int BUFFER_SIZE = 500;
enum SECTION {
SECTION_NONE,
SECTION_GENERAL,
SECTION_INFO,
SECTION_LOG,
SECTION_APRS,
SECTION_NETWORK,
SECTION_YSF_NETWORK,
SECTION_FCS_NETWORK,
SECTION_GPSD,
SECTION_REMOTE_COMMANDS
enum class SECTION {
NONE,
GENERAL,
INFO,
LOG,
APRS,
NETWORK,
YSF_NETWORK,
FCS_NETWORK,
GPSD,
REMOTE_COMMANDS
};
CConf::CConf(const std::string& file) :
@ -48,7 +48,6 @@ m_rptAddress(),
m_rptPort(0U),
m_myAddress(),
m_myPort(0U),
m_wiresXMakeUpper(true),
m_wiresXCommandPassthrough(false),
m_debug(false),
m_daemon(false),
@ -60,7 +59,6 @@ m_longitude(0.0F),
m_height(0),
m_name(),
m_description(),
m_aprsSymbol(),
m_logDisplayLevel(0U),
m_logFileLevel(0U),
m_logFilePath(),
@ -71,9 +69,11 @@ m_aprsAddress(),
m_aprsPort(0U),
m_aprsSuffix(),
m_aprsDescription(),
m_aprsSymbol("/r"),
m_networkStartup(),
m_networkOptions(),
m_networkInactivityTimeout(0U),
m_networkReconnect(false),
m_networkRevert(false),
m_networkDebug(false),
m_ysfNetworkEnabled(false),
@ -106,49 +106,49 @@ CConf::~CConf()
bool CConf::read()
{
FILE* fp = ::fopen(m_file.c_str(), "rt");
if (fp == NULL) {
if (fp == nullptr) {
::fprintf(stderr, "Couldn't open the .ini file - %s\n", m_file.c_str());
return false;
}
SECTION section = SECTION_NONE;
SECTION section = SECTION::NONE;
char buffer[BUFFER_SIZE];
while (::fgets(buffer, BUFFER_SIZE, fp) != NULL) {
while (::fgets(buffer, BUFFER_SIZE, fp) != nullptr) {
if (buffer[0U] == '#')
continue;
if (buffer[0U] == '[') {
if (::strncmp(buffer, "[General]", 9U) == 0)
section = SECTION_GENERAL;
section = SECTION::GENERAL;
else if (::strncmp(buffer, "[Info]", 6U) == 0)
section = SECTION_INFO;
section = SECTION::INFO;
else if (::strncmp(buffer, "[Log]", 5U) == 0)
section = SECTION_LOG;
section = SECTION::LOG;
else if (::strncmp(buffer, "[APRS]", 6U) == 0)
section = SECTION_APRS;
section = SECTION::APRS;
else if (::strncmp(buffer, "[Network]", 9U) == 0)
section = SECTION_NETWORK;
section = SECTION::NETWORK;
else if (::strncmp(buffer, "[YSF Network]", 13U) == 0)
section = SECTION_YSF_NETWORK;
section = SECTION::YSF_NETWORK;
else if (::strncmp(buffer, "[FCS Network]", 13U) == 0)
section = SECTION_FCS_NETWORK;
section = SECTION::FCS_NETWORK;
else if (::strncmp(buffer, "[GPSD]", 6U) == 0)
section = SECTION_GPSD;
section = SECTION::GPSD;
else if (::strncmp(buffer, "[Remote Commands]", 17U) == 0)
section = SECTION_REMOTE_COMMANDS;
section = SECTION::REMOTE_COMMANDS;
else
section = SECTION_NONE;
section = SECTION::NONE;
continue;
}
char* key = ::strtok(buffer, " \t=\r\n");
if (key == NULL)
if (key == nullptr)
continue;
char* value = ::strtok(NULL, "\r\n");
if (value == NULL)
char* value = ::strtok(nullptr, "\r\n");
if (value == nullptr)
continue;
// Remove quotes from the value
@ -160,7 +160,7 @@ bool CConf::read()
char *p;
// if value is not quoted, remove after # (to make comment)
if ((p = strchr(value, '#')) != NULL)
if ((p = strchr(value, '#')) != nullptr)
*p = '\0';
// remove trailing tab/space
@ -168,7 +168,7 @@ bool CConf::read()
*p = '\0';
}
if (section == SECTION_GENERAL) {
if (section == SECTION::GENERAL) {
if (::strcmp(key, "Callsign") == 0) {
// Convert the callsign to upper case
for (unsigned int i = 0U; value[i] != 0; i++)
@ -189,15 +189,13 @@ bool CConf::read()
m_myAddress = value;
else if (::strcmp(key, "LocalPort") == 0)
m_myPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "WiresXMakeUpper") == 0)
m_wiresXMakeUpper = ::atoi(value) == 1;
else if (::strcmp(key, "WiresXCommandPassthrough") == 0)
m_wiresXCommandPassthrough = ::atoi(value) == 1;
else if (::strcmp(key, "Debug") == 0)
m_debug = ::atoi(value) == 1;
else if (::strcmp(key, "Daemon") == 0)
m_daemon = ::atoi(value) == 1;
} else if (section == SECTION_INFO) {
} else if (section == SECTION::INFO) {
if (::strcmp(key, "TXFrequency") == 0)
m_txFrequency = (unsigned int)::atoi(value);
else if (::strcmp(key, "RXFrequency") == 0)
@ -214,7 +212,7 @@ bool CConf::read()
m_name = value;
else if (::strcmp(key, "Description") == 0)
m_description = value;
} else if (section == SECTION_LOG) {
} else if (section == SECTION::LOG) {
if (::strcmp(key, "FilePath") == 0)
m_logFilePath = value;
else if (::strcmp(key, "FileRoot") == 0)
@ -225,7 +223,7 @@ bool CConf::read()
m_logDisplayLevel = (unsigned int)::atoi(value);
else if (::strcmp(key, "FileRotate") == 0)
m_logFileRotate = ::atoi(value) == 1;
} else if (section == SECTION_APRS) {
} else if (section == SECTION::APRS) {
if (::strcmp(key, "Enable") == 0)
m_aprsEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Address") == 0)
@ -238,18 +236,20 @@ bool CConf::read()
m_aprsDescription = value;
else if (::strcmp(key, "Symbol") == 0)
m_aprsSymbol = value;
} else if (section == SECTION_NETWORK) {
} else if (section == SECTION::NETWORK) {
if (::strcmp(key, "Startup") == 0)
m_networkStartup = value;
else if (::strcmp(key, "Options") == 0)
m_networkOptions = value;
else if (::strcmp(key, "InactivityTimeout") == 0)
m_networkInactivityTimeout = (unsigned int)::atoi(value);
else if (::strcmp(key, "Reconnect") == 0)
m_networkReconnect = ::atoi(value) == 1;
else if (::strcmp(key, "Revert") == 0)
m_networkRevert = ::atoi(value) == 1;
else if (::strcmp(key, "Debug") == 0)
m_networkDebug = ::atoi(value) == 1;
} else if (section == SECTION_YSF_NETWORK) {
} else if (section == SECTION::YSF_NETWORK) {
if (::strcmp(key, "Enable") == 0)
m_ysfNetworkEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Port") == 0)
@ -274,21 +274,21 @@ bool CConf::read()
m_ysfNetworkYSF2P25Address = value;
else if (::strcmp(key, "YSF2P25Port") == 0)
m_ysfNetworkYSF2P25Port = (unsigned short)::atoi(value);
} else if (section == SECTION_FCS_NETWORK) {
} else if (section == SECTION::FCS_NETWORK) {
if (::strcmp(key, "Enable") == 0)
m_fcsNetworkEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Rooms") == 0)
m_fcsNetworkFile = value;
else if (::strcmp(key, "Port") == 0)
m_fcsNetworkPort = (unsigned short)::atoi(value);
} else if (section == SECTION_GPSD) {
} else if (section == SECTION::GPSD) {
if (::strcmp(key, "Enable") == 0)
m_gpsdEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Address") == 0)
m_gpsdAddress = value;
else if (::strcmp(key, "Port") == 0)
m_gpsdPort = value;
} else if (section == SECTION_REMOTE_COMMANDS) {
} else if (section == SECTION::REMOTE_COMMANDS) {
if (::strcmp(key, "Enable") == 0)
m_remoteCommandsEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Port") == 0)
@ -336,11 +336,6 @@ unsigned short CConf::getMyPort() const
return m_myPort;
}
bool CConf::getWiresXMakeUpper() const
{
return m_wiresXMakeUpper;
}
bool CConf::getWiresXCommandPassthrough() const
{
return m_wiresXCommandPassthrough;
@ -466,6 +461,11 @@ unsigned int CConf::getNetworkInactivityTimeout() const
return m_networkInactivityTimeout;
}
bool CConf::getNetworkReconnect() const
{
return m_networkReconnect;
}
bool CConf::getNetworkRevert() const
{
return m_networkRevert;

View file

@ -37,7 +37,6 @@ public:
unsigned short getRptPort() const;
std::string getMyAddress() const;
unsigned short getMyPort() const;
bool getWiresXMakeUpper() const;
bool getWiresXCommandPassthrough() const;
bool getDebug() const;
bool getDaemon() const;
@ -71,6 +70,7 @@ public:
std::string getNetworkStartup() const;
std::string getNetworkOptions() const;
unsigned int getNetworkInactivityTimeout() const;
bool getNetworkReconnect() const;
bool getNetworkRevert() const;
bool getNetworkDebug() const;
@ -111,7 +111,6 @@ private:
unsigned short m_rptPort;
std::string m_myAddress;
unsigned short m_myPort;
bool m_wiresXMakeUpper;
bool m_wiresXCommandPassthrough;
bool m_debug;
bool m_daemon;
@ -141,6 +140,7 @@ private:
std::string m_networkStartup;
std::string m_networkOptions;
unsigned int m_networkInactivityTimeout;
bool m_networkReconnect;
bool m_networkRevert;
bool m_networkDebug;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2012,2013,2015,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2012,2013,2015,2017,2018,2025 by Jonathan Naylor G4KLX
* Copyright (C) 2011 by DV Developer Group. DJ0ABR
*
* This program is free software; you can redistribute it and/or modify
@ -60,17 +60,17 @@ CDTMF::~CDTMF()
WX_STATUS CDTMF::decodeVDMode2(unsigned char* payload, bool end)
{
assert(payload != NULL);
assert(payload != nullptr);
payload += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
for (unsigned int offset = 5U; offset < 90U; offset += 18U) {
WX_STATUS status = decodeVDMode2Slice(payload + offset, end);
if (status != WXS_NONE)
if (status != WX_STATUS::NONE)
return status;
}
return WXS_NONE;
return WX_STATUS::NONE;
}
WX_STATUS CDTMF::decodeVDMode2Slice(unsigned char* ambe, bool end)
@ -167,43 +167,43 @@ WX_STATUS CDTMF::decodeVDMode2Slice(unsigned char* ambe, bool end)
WX_STATUS CDTMF::validate() const
{
if (m_command.empty())
return WXS_NONE;
return WX_STATUS::NONE;
size_t length = m_command.length();
char first = m_command.at(0U);
if (length == 1U && first == '#') {
return WXS_DISCONNECT;
return WX_STATUS::DISCONNECT;
} else if (length == 3U && first == 'A') {
for (unsigned int i = 1U; i < 3U; i++) {
char c = m_command.at(i);
if (c < '0' || c > '9')
return WXS_NONE;
return WX_STATUS::NONE;
}
return WXS_CONNECT_FCS;
return WX_STATUS::CONNECT_FCS;
} else if (length == 4U && first == 'A') {
for (unsigned int i = 1U; i < 4U; i++) {
char c = m_command.at(i);
if (c < '0' || c > '9')
return WXS_NONE;
return WX_STATUS::NONE;
}
return WXS_CONNECT_FCS;
return WX_STATUS::CONNECT_FCS;
} else if (length == 6U && first == '#') {
for (unsigned int i = 1U; i < 6U; i++) {
char c = m_command.at(i);
if (c < '0' || c > '9')
return WXS_NONE;
return WX_STATUS::NONE;
}
if (m_command == "#99999")
return WXS_DISCONNECT;
return WX_STATUS::DISCONNECT;
return WXS_CONNECT_YSF;
return WX_STATUS::CONNECT_YSF;
}
return WXS_NONE;
return WX_STATUS::NONE;
}
std::string CDTMF::getReflector()

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2014,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2014,2016,2017,2018,2020,2025 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
@ -34,17 +34,17 @@ m_socket(port),
m_debug(debug),
m_addr(),
m_addrLen(),
m_ping(NULL),
m_options(NULL),
m_ping(nullptr),
m_options(nullptr),
m_opt(),
m_info(NULL),
m_info(nullptr),
m_reflector(),
m_print(),
m_buffer(1000U, "FCS Network Buffer"),
m_n(0U),
m_pingTimer(1000U, 0U, 800U),
m_resetTimer(1000U, 1U),
m_state(FCS_UNLINKED)
m_state(FCS_STATE::UNLINKED)
{
m_info = new unsigned char[100U];
::sprintf((char*)m_info, "%9u%9u%-6.6s%-12.12s%7u", rxFrequency, txFrequency, locator.c_str(), FCS_VERSION, id);
@ -93,14 +93,14 @@ void CFCSNetwork::clearDestination()
m_pingTimer.stop();
m_resetTimer.stop();
m_state = FCS_UNLINKED;
m_state = FCS_STATE::UNLINKED;
}
void CFCSNetwork::write(const unsigned char* data)
{
assert(data != NULL);
assert(data != nullptr);
if (m_state != FCS_LINKED)
if (m_state != FCS_STATE::LINKED)
return;
unsigned char buffer[130U];
@ -117,7 +117,7 @@ void CFCSNetwork::write(const unsigned char* data)
bool CFCSNetwork::writeLink(const std::string& reflector)
{
if (m_state != FCS_LINKED) {
if (m_state != FCS_STATE::LINKED) {
std::string name = reflector.substr(0U, 6U);
if (m_addresses.count(name) == 0U) {
@ -140,7 +140,7 @@ bool CFCSNetwork::writeLink(const std::string& reflector)
m_print = reflector.substr(0U, 6U) + "-" + reflector.substr(6U);
m_state = FCS_LINKING;
m_state = FCS_STATE::LINKING;
m_pingTimer.start();
@ -156,7 +156,7 @@ void CFCSNetwork::setOptions(const std::string& options)
void CFCSNetwork::writeUnlink(unsigned int count)
{
if (m_state != FCS_LINKED)
if (m_state != FCS_STATE::LINKED)
return;
for (unsigned int i = 0U; i < count; i++)
@ -185,7 +185,7 @@ void CFCSNetwork::clock(unsigned int ms)
if (length <= 0)
return;
if (m_state == FCS_UNLINKED)
if (m_state == FCS_STATE::UNLINKED)
return;
if (!CUDPSocket::match(addr, m_addr))
@ -195,16 +195,16 @@ void CFCSNetwork::clock(unsigned int ms)
CUtils::dump(1U, "FCS Network Data Received", buffer, length);
if (length == 7) {
if (m_state == FCS_LINKING)
if (m_state == FCS_STATE::LINKING)
LogMessage("Linked to %s", m_print.c_str());
m_state = FCS_LINKED;
m_state = FCS_STATE::LINKED;
writeInfo();
writeOptions(m_print);
}
if (length == 10 && m_state == FCS_LINKING) {
if (length == 10 && m_state == FCS_STATE::LINKING) {
LogMessage("Linked to %s", m_print.c_str());
m_state = FCS_LINKED;
m_state = FCS_STATE::LINKED;
writeInfo();
writeOptions(m_print);
}
@ -218,7 +218,7 @@ void CFCSNetwork::clock(unsigned int ms)
unsigned int CFCSNetwork::read(unsigned char* data)
{
assert(data != NULL);
assert(data != nullptr);
if (m_buffer.isEmpty())
return 0U;
@ -264,7 +264,7 @@ void CFCSNetwork::close()
void CFCSNetwork::writeInfo()
{
if (m_state != FCS_LINKED)
if (m_state != FCS_STATE::LINKED)
return;
if (m_debug)
@ -275,7 +275,7 @@ void CFCSNetwork::writeInfo()
void CFCSNetwork::writePing()
{
if (m_state == FCS_UNLINKED)
if (m_state == FCS_STATE::UNLINKED)
return;
if (m_debug)
@ -286,7 +286,7 @@ void CFCSNetwork::writePing()
void CFCSNetwork::writeOptions(const std::string& reflector)
{
if (m_state != FCS_LINKED)
if (m_state != FCS_STATE::LINKED)
return;
if (m_opt.size() < 1)

View file

@ -28,10 +28,10 @@
#include <string>
#include <map>
enum FCS_STATE {
FCS_UNLINKED,
FCS_LINKING,
FCS_LINKED
enum class FCS_STATE {
UNLINKED,
LINKING,
LINKED
};
class CFCSNetwork {

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017,2018,2020,2024,2025 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
@ -32,10 +32,10 @@ const unsigned char LONG_GPS[] = {0x47U, 0x64U};
CGPS::CGPS(CAPRSWriter* writer) :
m_writer(writer),
m_buffer(NULL),
m_buffer(nullptr),
m_sent(false)
{
assert(writer != NULL);
assert(writer != nullptr);
m_buffer = new unsigned char[300U];
}
@ -141,7 +141,7 @@ void CGPS::reset()
void CGPS::transmitGPS(const unsigned char* source)
{
assert(m_writer != NULL);
assert(m_writer != nullptr);
// We don't know who its from!
if (::memcmp(source, " ", YSF_CALLSIGN_LENGTH) == 0)
@ -258,6 +258,9 @@ void CGPS::transmitGPS(const unsigned char* source)
case 0x26U:
::strcpy(radio, "DR-1X");
break;
case 0x27U:
::strcpy(radio, "FT-991A");
break;
case 0x28U:
::strcpy(radio, "FT-2D");
break;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2010,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2010,2016,2025 by Jonathan Naylor G4KLX
* Copyright (C) 2002 by Robert H. Morelos-Zaragoza. All rights reserved.
*/
@ -1096,7 +1096,7 @@ unsigned int CGolay24128::decode24128(unsigned int code)
unsigned int CGolay24128::decode24128(unsigned char* bytes)
{
assert(bytes != NULL);
assert(bytes != nullptr);
unsigned int code = bytes[0U];
code <<= 8;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2020,2025 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
@ -37,7 +37,7 @@ static std::string m_filePath;
static std::string m_fileRoot;
static bool m_fileRotate = true;
static FILE* m_fpLog = NULL;
static FILE* m_fpLog = nullptr;
static bool m_daemon = false;
static unsigned int m_displayLevel = 2U;
@ -59,10 +59,10 @@ static bool logOpenRotate()
struct tm* tm = ::gmtime(&now);
if (tm->tm_mday == m_tm.tm_mday && tm->tm_mon == m_tm.tm_mon && tm->tm_year == m_tm.tm_year) {
if (m_fpLog != NULL)
if (m_fpLog != nullptr)
return true;
} else {
if (m_fpLog != NULL)
if (m_fpLog != nullptr)
::fclose(m_fpLog);
}
@ -73,7 +73,7 @@ static bool logOpenRotate()
::sprintf(filename, "%s/%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
#endif
if ((m_fpLog = ::fopen(filename, "a+t")) != NULL) {
if ((m_fpLog = ::fopen(filename, "a+t")) != nullptr) {
status = true;
#if !defined(_WIN32) && !defined(_WIN64)
@ -94,7 +94,7 @@ static bool logOpenNoRotate()
if (m_fileLevel == 0U)
return true;
if (m_fpLog != NULL)
if (m_fpLog != nullptr)
return true;
char filename[200U];
@ -104,7 +104,7 @@ static bool logOpenNoRotate()
::sprintf(filename, "%s/%s.log", m_filePath.c_str(), m_fileRoot.c_str());
#endif
if ((m_fpLog = ::fopen(filename, "a+t")) != NULL) {
if ((m_fpLog = ::fopen(filename, "a+t")) != nullptr) {
status = true;
#if !defined(_WIN32) && !defined(_WIN64)
@ -141,13 +141,13 @@ bool LogInitialise(bool daemon, const std::string& filePath, const std::string&
void LogFinalise()
{
if (m_fpLog != NULL)
if (m_fpLog != nullptr)
::fclose(m_fpLog);
}
void Log(unsigned int level, const char* fmt, ...)
{
assert(fmt != NULL);
assert(fmt != nullptr);
char buffer[501U];
#if defined(_WIN32) || defined(_WIN64)
@ -157,7 +157,7 @@ void Log(unsigned int level, const char* fmt, ...)
::sprintf(buffer, "%c: %04u-%02u-%02u %02u:%02u:%02u.%03u ", LEVELS[level], st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
#else
struct timeval now;
::gettimeofday(&now, NULL);
::gettimeofday(&now, nullptr);
struct tm* tm = ::gmtime(&now.tv_sec);
@ -167,7 +167,7 @@ void Log(unsigned int level, const char* fmt, ...)
va_list vl;
va_start(vl, fmt);
::vsnprintf(buffer + ::strlen(buffer), 500, fmt, vl);
::vsnprintf(buffer + ::strlen(buffer), 500 - ::strlen(buffer), fmt, vl);
va_end(vl);

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2009,2012,2013,2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2006-2009,2012,2013,2015,2016,2025 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
@ -30,12 +30,12 @@ public:
CRingBuffer(unsigned int length, const char* name) :
m_length(length),
m_name(name),
m_buffer(NULL),
m_buffer(nullptr),
m_iPtr(0U),
m_oPtr(0U)
{
assert(length > 0U);
assert(name != NULL);
assert(name != nullptr);
m_buffer = new T[length];

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2018,2025 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
@ -77,7 +77,7 @@ CStopWatch::~CStopWatch()
unsigned long long CStopWatch::time() const
{
struct timeval now;
::gettimeofday(&now, NULL);
::gettimeofday(&now, nullptr);
return now.tv_sec * 1000ULL + now.tv_usec / 1000ULL;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2025 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
@ -26,7 +26,7 @@
void CSync::add(unsigned char* data)
{
assert(data != NULL);
assert(data != nullptr);
::memcpy(data, YSF_SYNC_BYTES, YSF_SYNC_LENGTH_BYTES);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2020,2025 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
@ -31,9 +31,9 @@ CThread::~CThread()
bool CThread::run()
{
m_handle = ::CreateThread(NULL, 0, &helper, this, 0, NULL);
m_handle = ::CreateThread(nullptr, 0, &helper, this, 0, nullptr);
return m_handle != NULL;
return m_handle != nullptr;
}
@ -74,13 +74,13 @@ CThread::~CThread()
bool CThread::run()
{
return ::pthread_create(&m_thread, NULL, helper, this) == 0;
return ::pthread_create(&m_thread, nullptr, helper, this) == 0;
}
void CThread::wait()
{
::pthread_join(m_thread, NULL);
::pthread_join(m_thread, nullptr);
}
@ -90,7 +90,7 @@ void* CThread::helper(void* arg)
p->entry();
return NULL;
return nullptr;
}
void CThread::sleep(unsigned int ms)
@ -100,7 +100,7 @@ void CThread::sleep(unsigned int ms)
ts.tv_sec = ms / 1000U;
ts.tv_nsec = (ms % 1000U) * 1000000U;
::nanosleep(&ts, NULL);
::nanosleep(&ts, nullptr);
}
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2006-2016,2020,2024,2025 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
@ -34,29 +34,27 @@
#endif
CUDPSocket::CUDPSocket(const std::string& address, unsigned short port) :
m_address_save(address),
m_port_save(port),
m_counter(0U)
m_localAddress(address),
m_localPort(port),
#if defined(_WIN32) || defined(_WIN64)
m_fd(INVALID_SOCKET),
#else
m_fd(-1),
#endif
m_af(AF_UNSPEC)
{
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
m_af[i] = 0U;
m_fd[i] = -1;
}
}
CUDPSocket::CUDPSocket(unsigned short port) :
m_address_save(),
m_port_save(port),
m_counter(0U)
m_localAddress(),
m_localPort(port),
#if defined(_WIN32) || defined(_WIN64)
m_fd(INVALID_SOCKET),
#else
m_fd(-1),
#endif
m_af(AF_UNSPEC)
{
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
m_af[i] = 0U;
m_fd[i] = -1;
}
}
CUDPSocket::~CUDPSocket()
@ -93,10 +91,10 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned short port, sockadd
std::string portstr = std::to_string(port);
struct addrinfo *res;
/* port is always digits, no needs to lookup service */
/* Port is always digits, no needs to lookup service */
hints.ai_flags |= AI_NUMERICSERV;
int err = getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res);
int err = ::getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res);
if (err != 0) {
sockaddr_in* paddr = (sockaddr_in*)&addr;
::memset(paddr, 0x00U, address_length = sizeof(sockaddr_in));
@ -107,9 +105,11 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned short port, sockadd
return err;
}
::memcpy(&addr, res->ai_addr, address_length = res->ai_addrlen);
address_length = (unsigned int)res->ai_addrlen;
freeaddrinfo(res);
::memcpy(&addr, res->ai_addr, address_length);
::freeaddrinfo(res);
return 0;
}
@ -119,35 +119,35 @@ bool CUDPSocket::match(const sockaddr_storage& addr1, const sockaddr_storage& ad
if (addr1.ss_family != addr2.ss_family)
return false;
if (type == IMT_ADDRESS_AND_PORT) {
if (type == IPMATCHTYPE::ADDRESS_AND_PORT) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port);
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port);
default:
return false;
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port);
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port);
default:
return false;
}
} else if (type == IMT_ADDRESS_ONLY) {
} else if (type == IPMATCHTYPE::ADDRESS_ONLY) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr;
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr);
default:
return false;
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr;
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr);
default:
return false;
}
} else {
return false;
@ -163,35 +163,38 @@ bool CUDPSocket::isNone(const sockaddr_storage& addr)
bool CUDPSocket::open(const sockaddr_storage& address)
{
return open(address.ss_family);
m_af = address.ss_family;
return open();
}
bool CUDPSocket::open(unsigned int af)
bool CUDPSocket::open()
{
return open(0, af, m_address_save, m_port_save);
}
#if defined(_WIN32) || defined(_WIN64)
assert(m_fd == INVALID_SOCKET);
#else
assert(m_fd == -1);
#endif
bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned short port)
{
sockaddr_storage addr;
unsigned int addrlen;
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = af;
hints.ai_family = m_af;
/* to determine protocol family, call lookup() first. */
int err = lookup(address, port, addr, addrlen, hints);
// To determine protocol family, call lookup() on the local address first.
int err = lookup(m_localAddress, m_localPort, addr, addrlen, hints);
if (err != 0) {
LogError("The local address is invalid - %s", address.c_str());
LogError("The local address is invalid - %s", m_localAddress.c_str());
return false;
}
close(index);
m_af = addr.ss_family;
int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0);
if (fd < 0) {
m_fd = ::socket(m_af, SOCK_DGRAM, 0);
if (m_fd < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot create the UDP socket, err: %lu", ::GetLastError());
#else
@ -200,62 +203,58 @@ bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std
return false;
}
m_address[index] = address;
m_port[index] = port;
m_af[index] = addr.ss_family;
m_fd[index] = fd;
if (port > 0U) {
if (m_localPort > 0U) {
int reuse = 1;
if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError());
#else
LogError("Cannot set the UDP socket option, err: %d", errno);
#endif
close();
return false;
}
if (::bind(fd, (sockaddr*)&addr, addrlen) == -1) {
if (::bind(m_fd, (sockaddr*)&addr, addrlen) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot bind the UDP address, err: %lu", ::GetLastError());
#else
LogError("Cannot bind the UDP address, err: %d", errno);
#endif
close();
return false;
}
LogInfo("Opening UDP port on %hu", port);
LogInfo("Opening UDP port on %hu", m_localPort);
}
return true;
}
int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length)
int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &addressLength)
{
assert(buffer != NULL);
assert(buffer != nullptr);
assert(length > 0U);
// Check that the readfrom() won't block
int i, n;
struct pollfd pfd[UDP_SOCKET_MAX];
for (i = n = 0; i < UDP_SOCKET_MAX; i++) {
if (m_fd[i] >= 0) {
pfd[n].fd = m_fd[i];
pfd[n].events = POLLIN;
n++;
}
}
// no socket descriptor to receive
if (n == 0)
#if defined(_WIN32) || defined(_WIN64)
if (m_fd == INVALID_SOCKET)
return 0;
#else
if (m_fd == -1)
return 0;
#endif
// Check that the readfrom() won't block
struct pollfd pfd;
pfd.fd = m_fd;
pfd.events = POLLIN;
pfd.revents = 0;
// Return immediately
#if defined(_WIN32) || defined(_WIN64)
int ret = WSAPoll(pfd, n, 0);
int ret = WSAPoll(&pfd, 1, 0);
#else
int ret = ::poll(pfd, n, 0);
int ret = ::poll(&pfd, 1, 0);
#endif
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
@ -266,14 +265,7 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
return -1;
}
int index;
for (i = 0; i < n; i++) {
// round robin
index = (i + m_counter) % n;
if (pfd[index].revents & POLLIN)
break;
}
if (i == n)
if ((pfd.revents & POLLIN) == 0)
return 0;
#if defined(_WIN32) || defined(_WIN64)
@ -283,9 +275,9 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
#endif
#if defined(_WIN32) || defined(_WIN64)
int len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
#else
ssize_t len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
#endif
if (len <= 0) {
#if defined(_WIN32) || defined(_WIN64)
@ -294,7 +286,7 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
LogError("Error returned from recvfrom, err: %d", errno);
if (len == -1 && errno == ENOTSOCK) {
LogMessage("Re-opening UDP port on %hu", m_port[index]);
LogMessage("Re-opening UDP port on %hu", m_localPort);
close();
open();
}
@ -302,43 +294,43 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
return -1;
}
m_counter++;
address_length = size;
addressLength = size;
return len;
}
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length)
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int addressLength)
{
assert(buffer != NULL);
assert(buffer != nullptr);
assert(length > 0U);
#if defined(_WIN32) || defined(_WIN64)
assert(m_fd != INVALID_SOCKET);
#else
assert(m_fd >= 0);
#endif
bool result = false;
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
if (m_fd[i] < 0 || m_af[i] != address.ss_family)
continue;
#if defined(_WIN32) || defined(_WIN64)
int ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, addressLength);
#else
ssize_t ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, addressLength);
#endif
if (ret < 0) {
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from sendto, err: %lu", ::GetLastError());
LogError("Error returned from sendto, err: %lu", ::GetLastError());
#else
LogError("Error returned from sendto, err: %d", errno);
LogError("Error returned from sendto, err: %d", errno);
#endif
} else {
} else {
#if defined(_WIN32) || defined(_WIN64)
if (ret == int(length))
result = true;
if (ret == int(length))
result = true;
#else
if (ret == ssize_t(length))
result = true;
if (ret == ssize_t(length))
result = true;
#endif
}
}
return result;
@ -346,18 +338,16 @@ bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const s
void CUDPSocket::close()
{
for (unsigned int i = 0; i < UDP_SOCKET_MAX; i++)
close(i);
#if defined(_WIN32) || defined(_WIN64)
if (m_fd != INVALID_SOCKET) {
::closesocket(m_fd);
m_fd = INVALID_SOCKET;
}
#else
if (m_fd >= 0) {
::close(m_fd);
m_fd = -1;
}
#endif
}
void CUDPSocket::close(const unsigned int index)
{
if ((index < UDP_SOCKET_MAX) && (m_fd[index] >= 0)) {
#if defined(_WIN32) || defined(_WIN64)
::closesocket(m_fd[index]);
#else
::close(m_fd[index]);
#endif
m_fd[index] = -1;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2011,2013,2015,2016,2020,2024,2025 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
@ -35,13 +35,9 @@
#include <ws2tcpip.h>
#endif
#if !defined(UDP_SOCKET_MAX)
#define UDP_SOCKET_MAX 1
#endif
enum IPMATCHTYPE {
IMT_ADDRESS_AND_PORT,
IMT_ADDRESS_ONLY
enum class IPMATCHTYPE {
ADDRESS_AND_PORT,
ADDRESS_ONLY
};
class CUDPSocket {
@ -50,34 +46,34 @@ public:
CUDPSocket(unsigned short port = 0U);
~CUDPSocket();
bool open(unsigned int af = AF_UNSPEC);
bool open();
bool open(const sockaddr_storage& address);
bool open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned short port);
int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length);
bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length);
int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &addressLength);
bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int addressLength);
void close();
void close(const unsigned int index);
static void startup();
static void shutdown();
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& address_length);
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& address_length, struct addrinfo& hints);
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& addressLength);
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& addressLength, struct addrinfo& hints);
static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type = IMT_ADDRESS_AND_PORT);
static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type = IPMATCHTYPE::ADDRESS_AND_PORT);
static bool isNone(const sockaddr_storage& addr);
private:
std::string m_address_save;
unsigned short m_port_save;
std::string m_address[UDP_SOCKET_MAX];
unsigned short m_port[UDP_SOCKET_MAX];
unsigned int m_af[UDP_SOCKET_MAX];
int m_fd[UDP_SOCKET_MAX];
unsigned int m_counter;
std::string m_localAddress;
unsigned short m_localPort;
#if defined(_WIN32) || defined(_WIN64)
SOCKET m_fd;
int m_af;
#else
int m_fd;
sa_family_t m_af;
#endif
};
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009,2014,2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2009,2014,2015,2016,2025 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
@ -19,14 +19,14 @@
void CUtils::dump(const std::string& title, const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(data != nullptr);
dump(2U, title, data, length);
}
void CUtils::dump(int level, const std::string& title, const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(data != nullptr);
::Log(level, "%s", title.c_str());
@ -72,14 +72,14 @@ void CUtils::dump(int level, const std::string& title, const unsigned char* data
void CUtils::dump(const std::string& title, const bool* bits, unsigned int length)
{
assert(bits != NULL);
assert(bits != nullptr);
dump(2U, title, bits, length);
}
void CUtils::dump(int level, const std::string& title, const bool* bits, unsigned int length)
{
assert(bits != NULL);
assert(bits != nullptr);
unsigned char bytes[100U];
unsigned int nBytes = 0U;
@ -91,7 +91,7 @@ void CUtils::dump(int level, const std::string& title, const bool* bits, unsigne
void CUtils::byteToBitsBE(unsigned char byte, bool* bits)
{
assert(bits != NULL);
assert(bits != nullptr);
bits[0U] = (byte & 0x80U) == 0x80U;
bits[1U] = (byte & 0x40U) == 0x40U;
@ -105,7 +105,7 @@ void CUtils::byteToBitsBE(unsigned char byte, bool* bits)
void CUtils::byteToBitsLE(unsigned char byte, bool* bits)
{
assert(bits != NULL);
assert(bits != nullptr);
bits[0U] = (byte & 0x01U) == 0x01U;
bits[1U] = (byte & 0x02U) == 0x02U;
@ -119,7 +119,7 @@ void CUtils::byteToBitsLE(unsigned char byte, bool* bits)
void CUtils::bitsToByteBE(const bool* bits, unsigned char& byte)
{
assert(bits != NULL);
assert(bits != nullptr);
byte = bits[0U] ? 0x80U : 0x00U;
byte |= bits[1U] ? 0x40U : 0x00U;
@ -133,7 +133,7 @@ void CUtils::bitsToByteBE(const bool* bits, unsigned char& byte)
void CUtils::bitsToByteLE(const bool* bits, unsigned char& byte)
{
assert(bits != NULL);
assert(bits != nullptr);
byte = bits[0U] ? 0x01U : 0x00U;
byte |= bits[1U] ? 0x02U : 0x00U;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2021 by Jonathan Naylor G4KLX
* Copyright (C) 2015-2021,2023,2024,2025 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
@ -19,6 +19,6 @@
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20230212";
const char* VERSION = "20250615";
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016,2017,2018,2019,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017,2018,2019,2020,2025 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
@ -27,8 +27,9 @@
#include <cstdio>
#include <cassert>
#include <cstdlib>
#include <cctype>
const unsigned char DX_REQ[] = {0x5DU, 0x71U, 0x5FU};
const unsigned char DX_REQ[] = {0x5DU, 0x71U, 0x5FU}; // Followed by 2B (FT-70D) 29 (FTM-100D) 28 (FT2D)
const unsigned char CONN_REQ[] = {0x5DU, 0x23U, 0x5FU};
const unsigned char DISC_REQ[] = {0x5DU, 0x2AU, 0x5FU};
const unsigned char ALL_REQ[] = {0x5DU, 0x66U, 0x5FU};
@ -48,26 +49,26 @@ m_callsign(callsign),
m_node(),
m_network(network),
m_reflectors(reflectors),
m_reflector(NULL),
m_reflector(nullptr),
m_id(),
m_name(),
m_command(NULL),
m_command(nullptr),
m_txFrequency(0U),
m_rxFrequency(0U),
m_timer(1000U, 1U),
m_seqNo(0U),
m_header(NULL),
m_csd1(NULL),
m_csd2(NULL),
m_csd3(NULL),
m_status(WXSI_NONE),
m_header(nullptr),
m_csd1(nullptr),
m_csd2(nullptr),
m_csd3(nullptr),
m_status(WXSI_STATUS::NONE),
m_start(0U),
m_search(),
m_busy(false),
m_busyTimer(3000U, 1U),
m_bufferTX(10000U, "YSF Wires-X TX Buffer")
{
assert(network != NULL);
assert(network != nullptr);
m_node = callsign;
if (suffix.size() > 0U) {
@ -187,35 +188,35 @@ bool CWiresX::start()
WX_STATUS CWiresX::process(const unsigned char* data, const unsigned char* source, const CYSFFICH& fich, bool wiresXCommandPassthrough)
{
assert(data != NULL);
assert(source != NULL);
assert(data != nullptr);
assert(source != nullptr);
unsigned char dt = fich.getDT();
if (dt != YSF_DT_DATA_FR_MODE)
return WXS_NONE;
return WX_STATUS::NONE;
unsigned char fi = fich.getFI();
if (fi != YSF_FI_COMMUNICATIONS)
return WXS_NONE;
return WX_STATUS::NONE;
CYSFPayload payload;
unsigned char fn = fich.getFN();
if (fn == 0U)
return WXS_NONE;
return WX_STATUS::NONE;
if (fn == 1U) {
bool valid = payload.readDataFRModeData2(data, m_command + 0U);
if (!valid)
return WXS_NONE;
return WX_STATUS::NONE;
} else {
bool valid = payload.readDataFRModeData1(data, m_command + (fn - 2U) * 40U + 20U);
if (!valid)
return WXS_NONE;
return WX_STATUS::NONE;
valid = payload.readDataFRModeData2(data, m_command + (fn - 2U) * 40U + 40U);
if (!valid)
return WXS_NONE;
return WX_STATUS::NONE;
}
unsigned char ft = fich.getFT();
@ -234,52 +235,52 @@ WX_STATUS CWiresX::process(const unsigned char* data, const unsigned char* sourc
}
if (!valid)
return WXS_NONE;
return WX_STATUS::NONE;
CUtils::dump(1U, "Received Wires-X command", m_command, cmd_len);
// If we are using WiresX Passthrough (we already know we are on a YSF2xxx room from YSFGateway
// YSFGateway.cpp is telling us to pass the command to the network, so do not process locally unless it's a disconnect
if (wiresXCommandPassthrough) {
if (::memcmp(m_command + 1U, DX_REQ, 3U) == 0) {
return WXS_NONE;
return WX_STATUS::NONE;
} else if (::memcmp(m_command + 1U, ALL_REQ, 3U) == 0) {
return WXS_NONE;
return WX_STATUS::NONE;
} else if (::memcmp(m_command + 1U, CONN_REQ, 3U) == 0) {
return WXS_NONE;
return WX_STATUS::NONE;
} else if (::memcmp(m_command + 1U, DISC_REQ, 3U) == 0) {
processDisconnect(source);
return WXS_DISCONNECT;
return WX_STATUS::DISCONNECT;
} else if (::memcmp(m_command + 1U, CAT_REQ, 3U) == 0) {
return WXS_NONE;
return WX_STATUS::NONE;
} else {
CUtils::dump("Unknown Wires-X command", m_command, cmd_len);
return WXS_NONE;
return WX_STATUS::NONE;
}
}
// Origional Code Here
else {
if (::memcmp(m_command + 1U, DX_REQ, 3U) == 0) {
processDX(source);
return WXS_NONE;
return WX_STATUS::RECONNECT_CURRENT;
} else if (::memcmp(m_command + 1U, ALL_REQ, 3U) == 0) {
processAll(source, m_command + 5U);
return WXS_NONE;
return WX_STATUS::NONE;
} else if (::memcmp(m_command + 1U, CONN_REQ, 3U) == 0) {
return processConnect(source, m_command + 5U);
} else if (::memcmp(m_command + 1U, DISC_REQ, 3U) == 0) {
processDisconnect(source);
return WXS_DISCONNECT;
return WX_STATUS::DISCONNECT;
} else if (::memcmp(m_command + 1U, CAT_REQ, 3U) == 0) {
processCategory(source, m_command + 5U);
return WXS_NONE;
return WX_STATUS::NONE;
} else {
CUtils::dump("Unknown Wires-X command", m_command, cmd_len);
return WXS_NONE;
return WX_STATUS::NONE;
}
}
}
return WXS_NONE;
return WX_STATUS::NONE;
}
CYSFReflector* CWiresX::getReflector() const
@ -296,7 +297,7 @@ void CWiresX::processDX(const unsigned char* source)
{
::LogDebug("Received DX from %10.10s", source);
m_status = WXSI_DX;
m_status = WXSI_STATUS::DX;
m_timer.start();
}
@ -329,7 +330,7 @@ void CWiresX::processCategory(const unsigned char* source, const unsigned char*
m_category.push_back(refl);
}
m_status = WXSI_CATEGORY;
m_status = WXSI_STATUS::CATEGORY;
m_timer.start();
}
@ -346,7 +347,7 @@ void CWiresX::processAll(const unsigned char* source, const unsigned char* data)
if (m_start > 0U)
m_start--;
m_status = WXSI_ALL;
m_status = WXSI_STATUS::ALL;
m_timer.start();
} else if (data[0U] == '1' && data[1U] == '1') {
@ -358,7 +359,7 @@ void CWiresX::processAll(const unsigned char* source, const unsigned char* data)
m_search = std::string((char*)(data + 5U), 16U);
m_status = WXSI_SEARCH;
m_status = WXSI_STATUS::SEARCH;
m_timer.start();
}
@ -374,19 +375,24 @@ WX_STATUS CWiresX::processConnect(const unsigned char* source, const unsigned ch
std::string id = std::string((char*)data, 5U);
m_reflector = m_reflectors.findById(id);
if (m_reflector == NULL)
return WXS_NONE;
if (m_reflector == nullptr) {
if(source != nullptr)
processDisconnect(source);
sendConnectFailedReply();
// Keep state on Radio matched with YSFGateway
return WX_STATUS::DISCONNECT;
}
m_status = WXSI_CONNECT;
m_status = WXSI_STATUS::CONNECT;
m_timer.start();
switch (m_reflector->m_type) {
case YT_YSF:
return WXS_CONNECT_YSF;
case YT_FCS:
return WXS_CONNECT_FCS;
case YSF_TYPE::YSF:
return WX_STATUS::CONNECT_YSF;
case YSF_TYPE::FCS:
return WX_STATUS::CONNECT_FCS;
default:
return WXS_NONE;
return WX_STATUS::NONE;
}
}
@ -397,18 +403,18 @@ void CWiresX::processConnect(CYSFReflector* reflector)
m_reflector = reflector;
m_status = WXSI_CONNECT;
m_status = WXSI_STATUS::CONNECT;
m_timer.start();
}
void CWiresX::processDisconnect(const unsigned char* source)
{
if (source != NULL)
if (source != nullptr)
::LogDebug("Received Disconect from %10.10s", source);
m_reflector = NULL;
m_reflector = nullptr;
m_status = WXSI_DISCONNECT;
m_status = WXSI_STATUS::DISCONNECT;
m_timer.start();
}
@ -421,29 +427,29 @@ void CWiresX::clock(unsigned int ms)
m_timer.clock(ms);
if (m_timer.isRunning() && m_timer.hasExpired()) {
switch (m_status) {
case WXSI_DX:
case WXSI_STATUS::DX:
sendDXReply();
break;
case WXSI_ALL:
case WXSI_STATUS::ALL:
sendAllReply();
break;
case WXSI_SEARCH:
case WXSI_STATUS::SEARCH:
sendSearchReply();
break;
case WXSI_CONNECT:
case WXSI_STATUS::CONNECT:
sendConnectReply();
break;
case WXSI_DISCONNECT:
case WXSI_STATUS::DISCONNECT:
sendDisconnectReply();
break;
case WXSI_CATEGORY:
case WXSI_STATUS::CATEGORY:
sendCategoryReply();
break;
default:
break;
}
m_status = WXSI_NONE;
m_status = WXSI_STATUS::NONE;
m_timer.stop();
}
@ -468,14 +474,14 @@ void CWiresX::clock(unsigned int ms)
void CWiresX::createReply(const unsigned char* data, unsigned int length, CYSFNetwork* network)
{
assert(data != NULL);
assert(data != nullptr);
assert(length > 0U);
bool isYSF2XX = true;
bool sendWiresXtoNetwork = true;
// If we don't explicitly pass a network, use the default one.
if (network == NULL) {
isYSF2XX = false;
if (network == nullptr) {
sendWiresXtoNetwork = false;
network = m_network;
}
@ -520,7 +526,7 @@ void CWiresX::createReply(const unsigned char* data, unsigned int length, CYSFNe
buffer[34U] = seqNo;
seqNo += 2U;
writeData(buffer, network, isYSF2XX);
writeData(buffer, network, sendWiresXtoNetwork);
fich.setFI(YSF_FI_COMMUNICATIONS);
@ -567,7 +573,7 @@ void CWiresX::createReply(const unsigned char* data, unsigned int length, CYSFNe
buffer[34U] = seqNo;
seqNo += 2U;
writeData(buffer, network, isYSF2XX);
writeData(buffer, network, sendWiresXtoNetwork);
fn++;
if (fn >= 8U) {
@ -587,13 +593,13 @@ void CWiresX::createReply(const unsigned char* data, unsigned int length, CYSFNe
buffer[34U] = seqNo | 0x01U;
writeData(buffer, network, isYSF2XX);
writeData(buffer, network, sendWiresXtoNetwork);
}
void CWiresX::writeData(const unsigned char* buffer, CYSFNetwork* network, bool isYSF2XX)
void CWiresX::writeData(const unsigned char* buffer, CYSFNetwork* network, bool sendWiresXtoNetwork)
{
if (isYSF2XX) {
// Send YSF2XXX Wires-X reply directly to the network
if (sendWiresXtoNetwork) {
// Send WiresX directly to the network
network->write(buffer);
} else {
// Send host Wires-X reply using ring buffer
@ -642,22 +648,22 @@ void CWiresX::sendDXReply()
for (unsigned int i = 0U; i < 14U; i++)
data[i + 20U] = m_name.at(i);
if (m_reflector == NULL) {
data[34U] = '1';
data[35U] = '2';
if (m_reflector == nullptr) {
data[34U] = '1'; // 0,1,2 seem Valid
data[35U] = '2'; // 0 = Offline 1 = Busy 2 = Disconnect 3 = Normal
data[57U] = '0';
data[58U] = '0';
data[59U] = '0';
} else {
data[34U] = '1';
data[35U] = '5';
data[34U] = '1'; // 0,1,2 seem Valid
data[35U] = '3'; // 0 = Offline 1 = Busy 2 = Disconnect 3 = Normal
for (unsigned int i = 0U; i < 5U; i++)
data[i + 36U] = m_reflector->m_id.at(i);
for (unsigned int i = 0U; i < 16U; i++)
data[i + 41U] = m_reflector->m_name.at(i);
data[i + 41U] = std::toupper(m_reflector->m_name.at(i));
for (unsigned int i = 0U; i < 3U; i++)
data[i + 57U] = m_reflector->m_count.at(i);
@ -718,7 +724,7 @@ void CWiresX::sendConnect(CYSFNetwork* network)
void CWiresX::sendConnectReply()
{
assert(m_reflector != NULL);
assert(m_reflector != nullptr);
unsigned char data[110U];
::memset(data, 0x00U, 110U);
@ -738,14 +744,14 @@ void CWiresX::sendConnectReply()
for (unsigned int i = 0U; i < 14U; i++)
data[i + 20U] = m_name.at(i);
data[34U] = '1';
data[35U] = '5';
data[34U] = '1'; // 0,1,2 seem Valid
data[35U] = '3'; // 0 = Offline 1 = Busy 2 = Disconnect 3 = Normal
for (unsigned int i = 0U; i < 5U; i++)
data[i + 36U] = m_reflector->m_id.at(i);
data[i + 36U] = m_reflector->m_id.at(i);
for (unsigned int i = 0U; i < 16U; i++)
data[i + 41U] = m_reflector->m_name.at(i);
data[i + 41U] = std::toupper(m_reflector->m_name.at(i));
for (unsigned int i = 0U; i < 3U; i++)
data[i + 57U] = m_reflector->m_count.at(i);
@ -769,6 +775,43 @@ void CWiresX::sendConnectReply()
m_seqNo++;
}
void CWiresX::sendConnectFailedReply()
{
unsigned char data[110U];
::memset(data, 0x00U, 110U);
::memset(data, ' ', 90U);
data[0U] = m_seqNo;
for (unsigned int i = 0U; i < 4U; i++)
data[i + 1U] = CONN_RESP[i];
for (unsigned int i = 0U; i < 5U; i++)
data[i + 5U] = m_id.at(i);
for (unsigned int i = 0U; i < 10U; i++)
data[i + 10U] = m_node.at(i);
for (unsigned int i = 0U; i < 14U; i++)
data[i + 20U] = m_name.at(i);
data[34U] = '1'; // 0,1,2 seem Valid
data[35U] = '0'; // 0 = Offline 1 = Busy 2 = Disconnect 3 = Normal
data[57U] = '0';
data[58U] = '0';
data[59U] = '0';
data[89U] = 0x03U; // End of data marker
data[90U] = CCRC::addCRC(data, 90U);
CUtils::dump(1U, "Connect Failed Reply", data, 91U);
createReply(data, 91U);
m_seqNo++;
}
void CWiresX::sendDisconnectReply()
{
unsigned char data[110U];
@ -789,8 +832,8 @@ void CWiresX::sendDisconnectReply()
for (unsigned int i = 0U; i < 14U; i++)
data[i + 20U] = m_name.at(i);
data[34U] = '1';
data[35U] = '2';
data[34U] = '1'; // 0,1,2 seem Valid
data[35U] = '2'; // 0 = Offline 1 = Busy 2 = Disconnect 3 = Normal
data[57U] = '0';
data[58U] = '0';
@ -830,13 +873,13 @@ void CWiresX::sendAllReply()
for (unsigned int i = 0U; i < 10U; i++)
data[i + 12U] = m_node.at(i);
unsigned int total = curr.size();
unsigned int total = (unsigned int)curr.size();
if (total > 999U) total = 999U;
unsigned int n = curr.size() - m_start;
unsigned int n = (unsigned int)curr.size() - m_start;
if (n > 20U) n = 20U;
::sprintf((char*)(data + 22U), "%03u%03u", n, total);
::sprintf((char*)(data + 22U), "%03u%03u", 20U, total);
data[28U] = 0x0DU;
@ -852,7 +895,7 @@ void CWiresX::sendAllReply()
data[i + offset + 1U] = refl->m_id.at(i);
for (unsigned int i = 0U; i < 16U; i++)
data[i + offset + 6U] = refl->m_name.at(i);
data[i + offset + 6U] = std::toupper(refl->m_name.at(i));
for (unsigned int i = 0U; i < 3U; i++)
data[i + offset + 22U] = refl->m_count.at(i);
@ -868,7 +911,16 @@ void CWiresX::sendAllReply()
unsigned int k = 1029U - offset;
for(unsigned int i = 0U; i < k; i++)
data[i + offset] = 0x20U;
{
if (i % 50U == 49 && i>0)
{
data[i + offset] = 0x0DU;
}
else
{
data[i + offset] = 0x20U;
}
}
offset += k;
@ -914,13 +966,13 @@ void CWiresX::sendSearchReply()
data[22U] = '1';
unsigned int total = search.size();
unsigned int total = (unsigned int)search.size();
if (total > 999U) total = 999U;
unsigned int n = search.size() - m_start;
unsigned int n = (unsigned int)search.size() - m_start;
if (n > 20U) n = 20U;
::sprintf((char*)(data + 23U), "%02u%03u", n, total);
::sprintf((char*)(data + 23U), "%02u%03u", 20U, total);
data[28U] = 0x0DU;
@ -936,7 +988,7 @@ void CWiresX::sendSearchReply()
data[i + offset + 1U] = refl->m_id.at(i);
for (unsigned int i = 0U; i < 16U; i++)
data[i + offset + 6U] = refl->m_name.at(i);
data[i + offset + 6U] = std::toupper(refl->m_name.at(i));
for (unsigned int i = 0U; i < 3U; i++)
data[i + offset + 22U] = refl->m_count.at(i);
@ -951,8 +1003,12 @@ void CWiresX::sendSearchReply()
}
unsigned int k = 1029U - offset;
for(unsigned int i = 0U; i < k; i++)
data[i + offset] = 0x20U;
for (unsigned int i = 0U; i < k; i++) {
if (((i % 50U) == 49U) && (i > 0U))
data[i + offset] = 0x0DU;
else
data[i + offset] = 0x20U;
}
offset += k;
@ -1023,11 +1079,11 @@ void CWiresX::sendCategoryReply()
for (unsigned int i = 0U; i < 10U; i++)
data[i + 12U] = m_node.at(i);
unsigned int n = m_category.size();
unsigned int n = (unsigned int)m_category.size();
if (n > 20U)
n = 20U;
::sprintf((char*)(data + 22U), "%03u%03u", n, n);
::sprintf((char*)(data + 22U), "%03u%03u", 20U, n);
data[28U] = 0x0DU;
@ -1043,7 +1099,7 @@ void CWiresX::sendCategoryReply()
data[i + offset + 1U] = refl->m_id.at(i);
for (unsigned int i = 0U; i < 16U; i++)
data[i + offset + 6U] = refl->m_name.at(i);
data[i + offset + 6U] = std::toupper(refl->m_name.at(i));
for (unsigned int i = 0U; i < 3U; i++)
data[i + offset + 22U] = refl->m_count.at(i);
@ -1058,8 +1114,12 @@ void CWiresX::sendCategoryReply()
}
unsigned int k = 1029U - offset;
for(unsigned int i = 0U; i < k; i++)
data[i + offset] = 0x20U;
for (unsigned int i = 0U; i < k; i++) {
if (((i % 50U) == 49U) && (i > 0U))
data[i + offset] = 0x0DU;
else
data[i + offset] = 0x20U;
}
offset += k;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016,2017,2018,2019,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017,2018,2019,2020,2025 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
@ -28,21 +28,22 @@
#include <string>
enum WX_STATUS {
WXS_NONE,
WXS_CONNECT_YSF,
WXS_CONNECT_FCS,
WXS_DISCONNECT
enum class WX_STATUS {
NONE,
CONNECT_YSF,
CONNECT_FCS,
DISCONNECT,
RECONNECT_CURRENT
};
enum WXSI_STATUS {
WXSI_NONE,
WXSI_DX,
WXSI_CONNECT,
WXSI_DISCONNECT,
WXSI_ALL,
WXSI_SEARCH,
WXSI_CATEGORY
enum class WXSI_STATUS {
NONE,
DX,
CONNECT,
DISCONNECT,
ALL,
SEARCH,
CATEGORY
};
class CWiresX {
@ -66,7 +67,7 @@ public:
void setReflector(CYSFReflector* reflector);
void processConnect(CYSFReflector* reflector);
void processDisconnect(const unsigned char* source = NULL);
void processDisconnect(const unsigned char* source = nullptr);
void sendConnect(CYSFNetwork* network);
@ -105,14 +106,15 @@ private:
void sendDXReply();
void sendConnectReply();
void sendConnectFailedReply();
void sendDisconnectReply();
void sendAllReply();
void sendSearchReply();
void sendSearchNotFoundReply();
void sendCategoryReply();
void createReply(const unsigned char* data, unsigned int length, CYSFNetwork* network = NULL);
void writeData(const unsigned char* data, CYSFNetwork* network, bool isYSF2XX);
void createReply(const unsigned char* data, unsigned int length, CYSFNetwork* network = nullptr);
void writeData(const unsigned char* data, CYSFNetwork* network, bool sendWiresXtoNetwork);
unsigned char calculateFT(unsigned int length, unsigned int offset) const;
};

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2016,2025 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
@ -36,12 +36,12 @@ const uint32_t M = 2U;
const unsigned int K = 5U;
CYSFConvolution::CYSFConvolution() :
m_metrics1(NULL),
m_metrics2(NULL),
m_oldMetrics(NULL),
m_newMetrics(NULL),
m_decisions(NULL),
m_dp(NULL)
m_metrics1(nullptr),
m_metrics2(nullptr),
m_oldMetrics(nullptr),
m_newMetrics(nullptr),
m_decisions(nullptr),
m_dp(nullptr)
{
m_metrics1 = new uint16_t[16U];
m_metrics2 = new uint16_t[16U];
@ -98,7 +98,7 @@ void CYSFConvolution::decode(uint8_t s0, uint8_t s1)
void CYSFConvolution::chainback(unsigned char* out, unsigned int nBits)
{
assert(out != NULL);
assert(out != nullptr);
uint32_t state = 0U;
@ -115,8 +115,8 @@ void CYSFConvolution::chainback(unsigned char* out, unsigned int nBits)
void CYSFConvolution::encode(const unsigned char* in, unsigned char* out, unsigned int nBits) const
{
assert(in != NULL);
assert(out != NULL);
assert(in != nullptr);
assert(out != nullptr);
assert(nBits > 0U);
uint8_t d1 = 0U, d2 = 0U, d3 = 0U, d4 = 0U;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016,2017,2019,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017,2019,2020,2025 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
@ -55,7 +55,7 @@ const unsigned int INTERLEAVE_TABLE[] = {
38U, 78U, 118U, 158U, 198U };
CYSFFICH::CYSFFICH(const CYSFFICH& fich) :
m_fich(NULL)
m_fich(nullptr)
{
m_fich = new unsigned char[6U];
@ -63,7 +63,7 @@ m_fich(NULL)
}
CYSFFICH::CYSFFICH() :
m_fich(NULL)
m_fich(nullptr)
{
m_fich = new unsigned char[6U];
@ -77,7 +77,7 @@ CYSFFICH::~CYSFFICH()
bool CYSFFICH::decode(const unsigned char* bytes)
{
assert(bytes != NULL);
assert(bytes != nullptr);
// Skip the sync bytes
bytes += YSF_SYNC_LENGTH_BYTES;
@ -116,7 +116,7 @@ bool CYSFFICH::decode(const unsigned char* bytes)
void CYSFFICH::encode(unsigned char* bytes)
{
assert(bytes != NULL);
assert(bytes != nullptr);
// Skip the sync bytes
bytes += YSF_SYNC_LENGTH_BYTES;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016-2020,2024,2025 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
@ -50,6 +50,17 @@ const char* DEFAULT_INI_FILE = "/etc/YSFGateway.ini";
#include <cmath>
#include <algorithm>
static bool m_killed = false;
static int m_signal = 0;
#if !defined(_WIN32) && !defined(_WIN64)
static void sigHandler(int signum)
{
m_killed = true;
m_signal = signum;
}
#endif
int main(int argc, char** argv)
{
const char* iniFile = DEFAULT_INI_FILE;
@ -68,11 +79,40 @@ int main(int argc, char** argv)
}
}
CYSFGateway* gateway = new CYSFGateway(std::string(iniFile));
#if !defined(_WIN32) && !defined(_WIN64)
::signal(SIGINT, sigHandler);
::signal(SIGTERM, sigHandler);
::signal(SIGHUP, sigHandler);
#endif
int ret = gateway->run();
int ret = 0;
delete gateway;
do {
m_signal = 0;
m_killed = false;
CYSFGateway* gateway = new CYSFGateway(std::string(iniFile));
ret = gateway->run();
delete gateway;
switch (m_signal) {
case 0:
break;
case 2:
::LogInfo("YSFGateway-%s exited on receipt of SIGINT", VERSION);
break;
case 15:
::LogInfo("YSFGateway-%s exited on receipt of SIGTERM", VERSION);
break;
case 1:
::LogInfo("YSFGateway-%s is restarting on receipt of SIGHUP", VERSION);
break;
default:
::LogInfo("YSFGateway-%s exited on receipt of an unknown signal", VERSION);
break;
}
} while (m_signal == 1);
return ret;
}
@ -81,14 +121,14 @@ CYSFGateway::CYSFGateway(const std::string& configFile) :
m_callsign(),
m_suffix(),
m_conf(configFile),
m_writer(NULL),
m_gps(NULL),
m_reflectors(NULL),
m_wiresX(NULL),
m_writer(nullptr),
m_gps(nullptr),
m_reflectors(nullptr),
m_wiresX(nullptr),
m_dtmf(),
m_ysfNetwork(NULL),
m_fcsNetwork(NULL),
m_linkType(LINK_NONE),
m_ysfNetwork(nullptr),
m_fcsNetwork(nullptr),
m_linkType(LINK_TYPE::NONE),
m_current(),
m_startup(),
m_options(),
@ -96,7 +136,7 @@ m_exclude(false),
m_inactivityTimer(1000U),
m_lostTimer(1000U, 120U),
m_fcsNetworkEnabled(false),
m_remoteSocket(NULL)
m_remoteSocket(nullptr)
{
CUDPSocket::startup();
}
@ -143,7 +183,7 @@ int CYSFGateway::run()
// If we are currently root...
if (getuid() == 0) {
struct passwd* user = ::getpwnam("mmdvm");
if (user == NULL) {
if (user == nullptr) {
::fprintf(stderr, "Could not get the mmdvm user, exiting\n");
return -1;
}
@ -239,9 +279,8 @@ int CYSFGateway::run()
std::string fileName = m_conf.getYSFNetworkHosts();
unsigned int reloadTime = m_conf.getYSFNetworkReloadTime();
bool wiresXMakeUpper = m_conf.getWiresXMakeUpper();
m_reflectors = new CYSFReflectors(fileName, reloadTime, wiresXMakeUpper);
m_reflectors = new CYSFReflectors(fileName, reloadTime);
m_reflectors->reload();
createWiresX(&rptNetwork);
@ -253,13 +292,14 @@ int CYSFGateway::run()
ret = m_remoteSocket->open();
if (!ret) {
delete m_remoteSocket;
m_remoteSocket = NULL;
m_remoteSocket = nullptr;
}
}
m_startup = m_conf.getNetworkStartup();
m_options = m_conf.getNetworkOptions();
bool revert = m_conf.getNetworkRevert();
bool reconnect = m_conf.getNetworkReconnect();
bool wiresXCommandPassthrough = m_conf.getWiresXCommandPassthrough();
startupLinking();
@ -270,7 +310,7 @@ int CYSFGateway::run()
LogMessage("YSFGateway-%s is starting", VERSION);
LogMessage("Built %s %s (GitID #%.7s)", __TIME__, __DATE__, gitversion);
for (;;) {
while (!m_killed) {
unsigned char buffer[200U];
memset(buffer, 0U, 200U);
@ -282,29 +322,29 @@ int CYSFGateway::run()
unsigned char dt = fich.getDT();
CYSFReflector* reflector = m_wiresX->getReflector();
if (m_ysfNetwork != NULL && m_linkType == LINK_YSF && wiresXCommandPassthrough && reflector->m_wiresX) {
if (m_ysfNetwork != nullptr && m_linkType == LINK_TYPE::YSF && wiresXCommandPassthrough && reflector != nullptr && reflector->m_wiresX) {
processDTMF(buffer, dt);
processWiresX(buffer, fich, true, wiresXCommandPassthrough);
processWiresX(buffer, fich, reflector->m_wiresX, wiresXCommandPassthrough); // Honour reflector->m_wiresX status
} else {
processDTMF(buffer, dt);
processWiresX(buffer, fich, false, wiresXCommandPassthrough);
reflector = m_wiresX->getReflector(); //reflector may have changed
if (m_ysfNetwork != NULL && m_linkType == LINK_YSF && reflector->m_wiresX)
processWiresX(buffer, fich, false, wiresXCommandPassthrough); // Remove the assumption that wiresXCommandPassthrough is set
reflector = m_wiresX->getReflector(); // reflector may have changed
if (m_ysfNetwork != nullptr && m_linkType == LINK_TYPE::YSF && reflector != nullptr && reflector->m_wiresX)
m_exclude = (dt == YSF_DT_DATA_FR_MODE);
}
if (m_gps != NULL)
if (m_gps != nullptr)
m_gps->data(buffer + 14U, buffer + 35U, fich);
}
if (m_ysfNetwork != NULL && m_linkType == LINK_YSF && !m_exclude) {
if (m_ysfNetwork != nullptr && m_linkType == LINK_TYPE::YSF && !m_exclude) {
if (::memcmp(buffer + 0U, "YSFD", 4U) == 0) {
m_ysfNetwork->write(buffer);
m_inactivityTimer.start();
}
}
if (m_fcsNetwork != NULL && m_linkType == LINK_FCS && !m_exclude) {
if (m_fcsNetwork != nullptr && m_linkType == LINK_TYPE::FCS && !m_exclude) {
if (::memcmp(buffer + 0U, "YSFD", 4U) == 0) {
m_fcsNetwork->write(buffer);
m_inactivityTimer.start();
@ -312,16 +352,16 @@ int CYSFGateway::run()
}
if ((buffer[34U] & 0x01U) == 0x01U) {
if (m_gps != NULL)
if (m_gps != nullptr)
m_gps->reset();
m_dtmf.reset();
m_exclude = false;
}
}
if (m_ysfNetwork != NULL) {
if (m_ysfNetwork != nullptr) {
while (m_ysfNetwork->read(buffer) > 0U) {
if (m_linkType == LINK_YSF) {
if (m_linkType == LINK_TYPE::YSF) {
// Only pass through YSF data packets
if (::memcmp(buffer + 0U, "YSFD", 4U) == 0 && !m_wiresX->isBusy())
rptNetwork.write(buffer);
@ -331,9 +371,9 @@ int CYSFGateway::run()
}
}
if (m_fcsNetwork != NULL) {
if (m_fcsNetwork != nullptr) {
while (m_fcsNetwork->read(buffer) > 0U) {
if (m_linkType == LINK_FCS) {
if (m_linkType == LINK_TYPE::FCS) {
// Only pass through YSF data packets
if (::memcmp(buffer + 0U, "YSFD", 4U) == 0 && !m_wiresX->isBusy())
rptNetwork.write(buffer);
@ -343,59 +383,41 @@ int CYSFGateway::run()
}
}
if (m_remoteSocket != NULL)
if (m_remoteSocket != nullptr)
processRemoteCommands();
unsigned int ms = stopWatch.elapsed();
stopWatch.start();
rptNetwork.clock(ms);
if (m_ysfNetwork != NULL)
if (m_ysfNetwork != nullptr)
m_ysfNetwork->clock(ms);
if (m_fcsNetwork != NULL)
if (m_fcsNetwork != nullptr)
m_fcsNetwork->clock(ms);
if (m_writer != NULL)
if (m_writer != nullptr)
m_writer->clock(ms);
m_wiresX->clock(ms);
m_inactivityTimer.clock(ms);
if (m_inactivityTimer.isRunning() && m_inactivityTimer.hasExpired()) {
if (revert) {
if (m_current != m_startup) {
if (m_linkType == LINK_YSF) {
m_wiresX->processDisconnect();
m_ysfNetwork->writeUnlink(3U);
m_ysfNetwork->clearDestination();
}
if (m_linkType == LINK_FCS) {
m_fcsNetwork->writeUnlink(3U);
m_fcsNetwork->clearDestination();
}
m_current.clear();
m_lostTimer.stop();
m_linkType = LINK_NONE;
if (m_linkType != LINK_TYPE::NONE && m_current != m_startup) {
LogMessage("Reverting to startup ref due to inactivity");
disconnectCurrentReflector();
startupLinking();
} else if (m_linkType == LINK_TYPE::NONE && reconnect) {
// reconnect if current one is timeout and reconnect = 1
LogMessage("Reconnecting startup reflector ...");
startupLinking();
}
} else {
if (m_linkType == LINK_YSF) {
if (m_linkType != LINK_TYPE::NONE && !reconnect) {
LogMessage("Disconnecting due to inactivity");
m_wiresX->processDisconnect();
m_ysfNetwork->writeUnlink(3U);
m_ysfNetwork->clearDestination();
disconnectCurrentReflector();
} else if (m_linkType == LINK_TYPE::NONE && reconnect) {
LogMessage("Reconnecting reflector ...");
reconnectReflector(m_current);
}
if (m_linkType == LINK_FCS) {
LogMessage("Disconnecting due to inactivity");
m_fcsNetwork->writeUnlink(3U);
m_fcsNetwork->clearDestination();
}
m_current.clear();
m_lostTimer.stop();
m_linkType = LINK_NONE;
}
m_inactivityTimer.start();
@ -403,21 +425,20 @@ int CYSFGateway::run()
m_lostTimer.clock(ms);
if (m_lostTimer.isRunning() && m_lostTimer.hasExpired()) {
if (m_linkType == LINK_YSF) {
if (m_linkType == LINK_TYPE::YSF) {
LogWarning("Link has failed, polls lost");
m_wiresX->processDisconnect();
m_ysfNetwork->clearDestination();
}
if (m_fcsNetwork != NULL) {
if (m_fcsNetwork != nullptr) {
LogWarning("Link has failed, polls lost");
m_fcsNetwork->clearDestination();
}
m_current.clear();
m_inactivityTimer.start();
m_lostTimer.stop();
m_linkType = LINK_NONE;
m_linkType = LINK_TYPE::NONE;
}
if (ms < 5U)
@ -426,23 +447,23 @@ int CYSFGateway::run()
rptNetwork.clearDestination();
if (m_gps != NULL) {
if (m_gps != nullptr) {
m_writer->close();
delete m_writer;
delete m_gps;
}
if (m_ysfNetwork != NULL) {
if (m_ysfNetwork != nullptr) {
m_ysfNetwork->clearDestination();
delete m_ysfNetwork;
}
if (m_fcsNetwork != NULL) {
if (m_fcsNetwork != nullptr) {
m_fcsNetwork->close();
delete m_fcsNetwork;
}
if (m_remoteSocket != NULL) {
if (m_remoteSocket != nullptr) {
m_remoteSocket->close();
delete m_remoteSocket;
}
@ -491,7 +512,7 @@ void CYSFGateway::createGPS()
bool ret = m_writer->open();
if (!ret) {
delete m_writer;
m_writer = NULL;
m_writer = nullptr;
return;
}
@ -500,7 +521,7 @@ void CYSFGateway::createGPS()
void CYSFGateway::createWiresX(CYSFNetwork* rptNetwork)
{
assert(rptNetwork != NULL);
assert(rptNetwork != nullptr);
m_wiresX = new CWiresX(m_callsign, m_suffix, rptNetwork, *m_reflectors);
@ -538,17 +559,23 @@ void CYSFGateway::createWiresX(CYSFNetwork* rptNetwork)
m_wiresX->start();
}
void CYSFGateway::processWiresX(const unsigned char* buffer, const CYSFFICH& fich, bool dontProcessWiresXLocal, bool wiresXCommandPassthrough)
void CYSFGateway::processWiresX(const unsigned char* buffer, const CYSFFICH& fich, bool wiresXEnabledReflector, bool wiresXCommandPassthrough)
{
assert(buffer != NULL);
assert(buffer != nullptr);
WX_STATUS status;
if (wiresXEnabledReflector && wiresXCommandPassthrough) { // If these are BOTH true, then we ignore anything but a WiresX disconnect
status = m_wiresX->process(buffer + 35U, buffer + 14U, fich, true);
} else { // Otherwise process all WiresX commands locally
status = m_wiresX->process(buffer + 35U, buffer + 14U, fich, false);
}
WX_STATUS status = m_wiresX->process(buffer + 35U, buffer + 14U, fich, dontProcessWiresXLocal);
switch (status) {
case WXS_CONNECT_YSF: {
if (m_linkType == LINK_YSF)
case WX_STATUS::CONNECT_YSF: {
if (m_linkType == LINK_TYPE::YSF)
m_ysfNetwork->writeUnlink(3U);
if (m_linkType == LINK_FCS) {
if (m_linkType == LINK_TYPE::FCS) {
m_fcsNetwork->writeUnlink(3U);
m_fcsNetwork->clearDestination();
}
@ -562,7 +589,7 @@ void CYSFGateway::processWiresX(const unsigned char* buffer, const CYSFFICH& fic
m_current = reflector->m_id;
m_inactivityTimer.start();
m_lostTimer.start();
m_linkType = LINK_YSF;
m_linkType = LINK_TYPE::YSF;
// If we are linking to a YSF2xxx mode, send the YSF2xxx gateway the link command too
if (reflector->m_wiresX && wiresXCommandPassthrough) {
@ -571,19 +598,19 @@ void CYSFGateway::processWiresX(const unsigned char* buffer, const CYSFFICH& fic
}
}
break;
case WXS_CONNECT_FCS: {
if (m_linkType == LINK_YSF) {
case WX_STATUS::CONNECT_FCS: {
if (m_linkType == LINK_TYPE::YSF) {
m_ysfNetwork->writeUnlink(3U);
m_ysfNetwork->clearDestination();
}
if (m_linkType == LINK_FCS)
if (m_linkType == LINK_TYPE::FCS)
m_fcsNetwork->writeUnlink(3U);
m_current.clear();
m_inactivityTimer.start();
m_lostTimer.stop();
m_linkType = LINK_NONE;
m_linkType = LINK_TYPE::NONE;
CYSFReflector* reflector = m_wiresX->getReflector();
LogMessage("Connect to %s - \"%s\" has been requested by %10.10s", reflector->m_id.c_str(), reflector->m_name.c_str(), buffer + 14U);
@ -595,17 +622,18 @@ void CYSFGateway::processWiresX(const unsigned char* buffer, const CYSFFICH& fic
if (ok) {
m_current = name;
m_lostTimer.start();
m_linkType = LINK_FCS;
m_linkType = LINK_TYPE::FCS;
} else {
LogMessage("Unknown reflector - %s", name.c_str());
}
}
break;
case WXS_DISCONNECT:
if (m_linkType == LINK_YSF) {
case WX_STATUS::DISCONNECT:
if (m_linkType == LINK_TYPE::YSF) {
LogMessage("Disconnect has been requested by %10.10s", buffer + 14U);
if ( (wiresXCommandPassthrough) && (::memcmp(buffer + 0U, "YSFD", 4U) == 0) ) {
if ( (wiresXEnabledReflector && wiresXCommandPassthrough) && (::memcmp(buffer + 0U, "YSFD", 4U) == 0) ) {
// Send the disconnect to the YSF2xxx gateway too
LogMessage("Forward WiresX Disconnect to Network");
m_ysfNetwork->write(buffer);
}
@ -615,9 +643,9 @@ void CYSFGateway::processWiresX(const unsigned char* buffer, const CYSFFICH& fic
m_current.clear();
m_inactivityTimer.start();
m_lostTimer.stop();
m_linkType = LINK_NONE;
m_linkType = LINK_TYPE::NONE;
}
if (m_linkType == LINK_FCS) {
if (m_linkType == LINK_TYPE::FCS) {
LogMessage("Disconnect has been requested by %10.10s", buffer + 14U);
m_fcsNetwork->writeUnlink(3U);
@ -626,7 +654,13 @@ void CYSFGateway::processWiresX(const unsigned char* buffer, const CYSFFICH& fic
m_current.clear();
m_inactivityTimer.start();
m_lostTimer.stop();
m_linkType = LINK_NONE;
m_linkType = LINK_TYPE::NONE;
}
break;
case WX_STATUS::RECONNECT_CURRENT: {
if (m_linkType == LINK_TYPE::NONE && !m_current.empty())
reconnectReflector(m_current);
}
break;
default:
@ -636,9 +670,9 @@ void CYSFGateway::processWiresX(const unsigned char* buffer, const CYSFFICH& fic
void CYSFGateway::processDTMF(unsigned char* buffer, unsigned char dt)
{
assert(buffer != NULL);
assert(buffer != nullptr);
WX_STATUS status = WXS_NONE;
WX_STATUS status = WX_STATUS::NONE;
switch (dt) {
case YSF_DT_VD_MODE2:
status = m_dtmf.decodeVDMode2(buffer + 35U, (buffer[34U] & 0x01U) == 0x01U);
@ -648,16 +682,16 @@ void CYSFGateway::processDTMF(unsigned char* buffer, unsigned char dt)
}
switch (status) {
case WXS_CONNECT_YSF: {
case WX_STATUS::CONNECT_YSF: {
std::string id = m_dtmf.getReflector();
CYSFReflector* reflector = m_reflectors->findById(id);
if (reflector != NULL) {
if (reflector != nullptr) {
m_wiresX->processConnect(reflector);
if (m_linkType == LINK_YSF)
if (m_linkType == LINK_TYPE::YSF)
m_ysfNetwork->writeUnlink(3U);
if (m_linkType == LINK_FCS) {
if (m_linkType == LINK_TYPE::FCS) {
m_fcsNetwork->writeUnlink(3U);
m_fcsNetwork->clearDestination();
}
@ -670,11 +704,11 @@ void CYSFGateway::processDTMF(unsigned char* buffer, unsigned char dt)
m_current = id;
m_inactivityTimer.start();
m_lostTimer.start();
m_linkType = LINK_YSF;
m_linkType = LINK_TYPE::YSF;
}
}
break;
case WXS_CONNECT_FCS: {
case WX_STATUS::CONNECT_FCS: {
std::string raw = m_dtmf.getReflector();
std::string id = "FCS00";
std::string idShort = "FCS";
@ -690,18 +724,18 @@ void CYSFGateway::processDTMF(unsigned char* buffer, unsigned char dt)
return;
}
if (m_linkType == LINK_YSF) {
if (m_linkType == LINK_TYPE::YSF) {
m_wiresX->processDisconnect();
m_ysfNetwork->writeUnlink(3U);
m_ysfNetwork->clearDestination();
}
if (m_linkType == LINK_FCS)
if (m_linkType == LINK_TYPE::FCS)
m_fcsNetwork->writeUnlink(3U);
m_current.clear();
m_inactivityTimer.stop();
m_lostTimer.stop();
m_linkType = LINK_NONE;
m_linkType = LINK_TYPE::NONE;
LogMessage("Connect via DTMF to %s has been requested by %10.10s", id.c_str(), buffer + 14U);
@ -710,14 +744,14 @@ void CYSFGateway::processDTMF(unsigned char* buffer, unsigned char dt)
m_current = id;
m_inactivityTimer.start();
m_lostTimer.start();
m_linkType = LINK_FCS;
m_linkType = LINK_TYPE::FCS;
} else {
LogMessage("Unknown reflector - %s", id.c_str());
}
}
break;
case WXS_DISCONNECT:
if (m_linkType == LINK_YSF) {
case WX_STATUS::DISCONNECT:
if (m_linkType == LINK_TYPE::YSF) {
m_wiresX->processDisconnect();
LogMessage("Disconnect via DTMF has been requested by %10.10s", buffer + 14U);
@ -728,9 +762,9 @@ void CYSFGateway::processDTMF(unsigned char* buffer, unsigned char dt)
m_current.clear();
m_inactivityTimer.start();
m_lostTimer.stop();
m_linkType = LINK_NONE;
m_linkType = LINK_TYPE::NONE;
}
if (m_linkType == LINK_FCS) {
if (m_linkType == LINK_TYPE::FCS) {
LogMessage("Disconnect via DTMF has been requested by %10.10s", buffer + 14U);
m_fcsNetwork->writeUnlink(3U);
@ -739,7 +773,7 @@ void CYSFGateway::processDTMF(unsigned char* buffer, unsigned char dt)
m_current.clear();
m_inactivityTimer.start();
m_lostTimer.stop();
m_linkType = LINK_NONE;
m_linkType = LINK_TYPE::NONE;
}
break;
default:
@ -800,11 +834,11 @@ std::string CYSFGateway::calculateLocator()
void CYSFGateway::startupLinking()
{
if (!m_startup.empty()) {
if (m_startup.substr(0U, 3U) == "FCS" && m_fcsNetwork != NULL) {
if (m_startup.substr(0U, 3U) == "FCS" && m_fcsNetwork != nullptr) {
m_current.clear();
m_inactivityTimer.stop();
m_lostTimer.stop();
m_linkType = LINK_NONE;
m_linkType = LINK_TYPE::NONE;
bool ok = m_fcsNetwork->writeLink(m_startup);
m_fcsNetwork->setOptions(m_options);
@ -815,18 +849,18 @@ void CYSFGateway::startupLinking()
m_current = m_startup;
m_inactivityTimer.start();
m_lostTimer.start();
m_linkType = LINK_FCS;
m_linkType = LINK_TYPE::FCS;
} else {
LogMessage("Unknown reflector - %s", m_startup.c_str());
}
} else if (m_ysfNetwork != NULL) {
} else if (m_ysfNetwork != nullptr) {
m_current.clear();
m_inactivityTimer.stop();
m_lostTimer.stop();
m_linkType = LINK_NONE;
m_linkType = LINK_TYPE::NONE;
CYSFReflector* reflector = m_reflectors->findByName(m_startup);
if (reflector != NULL) {
if (reflector != nullptr) {
LogMessage("Automatic (re-)connection to %5.5s - \"%s\"", reflector->m_id.c_str(), reflector->m_name.c_str());
m_ysfNetwork->setOptions(m_options);
@ -839,7 +873,7 @@ void CYSFGateway::startupLinking()
m_current = m_startup;
m_inactivityTimer.start();
m_lostTimer.start();
m_linkType = LINK_YSF;
m_linkType = LINK_TYPE::YSF;
}
}
}
@ -847,23 +881,80 @@ void CYSFGateway::startupLinking()
LogMessage("No connection startup");
}
void CYSFGateway::reconnectReflector(const std::string& refNameOrId) {
if (refNameOrId.substr(0U, 3U) == "FCS" && m_fcsNetwork != nullptr) {
m_inactivityTimer.stop();
m_lostTimer.stop();
bool ok = m_fcsNetwork->writeLink(refNameOrId);
m_fcsNetwork->setOptions(m_options);
if (ok) {
LogMessage("(re-)connection to %s", refNameOrId.c_str());
m_inactivityTimer.start();
m_lostTimer.start();
m_linkType = LINK_TYPE::FCS;
}
} else if (m_ysfNetwork != nullptr) {
m_inactivityTimer.stop();
m_lostTimer.stop();
CYSFReflector* reflector = m_reflectors->findById(refNameOrId);
if (reflector == nullptr)
reflector = m_reflectors->findByName(refNameOrId);
if (reflector != nullptr) {
LogMessage("(re-)connection to %5.5s - \"%s\"", reflector->m_id.c_str(), reflector->m_name.c_str());
m_wiresX->setReflector(reflector);
m_ysfNetwork->setDestination(reflector->m_name, reflector->m_addr, reflector->m_addrLen);
m_ysfNetwork->setOptions(m_options);
m_ysfNetwork->writePoll(3U);
m_inactivityTimer.start();
m_lostTimer.start();
m_linkType = LINK_TYPE::YSF;
}
}
}
void CYSFGateway::disconnectCurrentReflector() {
if (m_linkType == LINK_TYPE::YSF) {
m_wiresX->processDisconnect();
m_ysfNetwork->writeUnlink(3U);
m_ysfNetwork->clearDestination();
}
if (m_linkType == LINK_TYPE::FCS) {
m_fcsNetwork->writeUnlink(3U);
m_fcsNetwork->clearDestination();
}
// m_current.clear();
m_lostTimer.stop();
m_linkType = LINK_TYPE::NONE;
}
void CYSFGateway::readFCSRoomsFile(const std::string& filename)
{
FILE* fp = ::fopen(filename.c_str(), "rt");
if (fp == NULL)
if (fp == nullptr)
return;
unsigned int count = 0U;
char buffer[200U];
while (::fgets(buffer, 200, fp) != NULL) {
while (::fgets(buffer, 200, fp) != nullptr) {
if (buffer[0U] == '#')
continue;
char* p1 = ::strtok(buffer, ";");
char* p2 = ::strtok(NULL, ";");
char* p2 = ::strtok(nullptr, ";");
if (p1 != NULL && p2 != NULL) {
if (p1 != nullptr && p2 != nullptr) {
m_wiresX->addFCSRoom(p1, p2);
count++;
}
@ -886,17 +977,17 @@ void CYSFGateway::processRemoteCommands()
if ((::memcmp(buffer + 0U, "LinkYSF", 7U) == 0) && (strlen((char*)buffer + 0U) > 8)) {
std::string id = std::string((char*)(buffer + 8U));
// Left trim
id.erase(id.begin(), std::find_if(id.begin(), id.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
id.erase(id.begin(), std::find_if(id.begin(), id.end(), [](unsigned char ch) { return !std::isspace(ch); }));
CYSFReflector* reflector = m_reflectors->findById(id);
if (reflector == NULL)
if (reflector == nullptr)
reflector = m_reflectors->findByName(id);
if (reflector != NULL) {
if (reflector != nullptr) {
m_wiresX->processConnect(reflector);
if (m_linkType == LINK_YSF)
if (m_linkType == LINK_TYPE::YSF)
m_ysfNetwork->writeUnlink(3U);
if (m_linkType == LINK_FCS) {
if (m_linkType == LINK_TYPE::FCS) {
m_fcsNetwork->writeUnlink(3U);
m_fcsNetwork->clearDestination();
}
@ -909,7 +1000,7 @@ void CYSFGateway::processRemoteCommands()
m_current = id;
m_inactivityTimer.start();
m_lostTimer.start();
m_linkType = LINK_YSF;
m_linkType = LINK_TYPE::YSF;
} else {
LogWarning("Invalid YSF reflector id/name - \"%s\"", id.c_str());
return;
@ -917,7 +1008,7 @@ void CYSFGateway::processRemoteCommands()
} else if ((::memcmp(buffer + 0U, "LinkFCS", 7U) == 0) && (strlen((char*)buffer + 0U) > 8)) {
std::string raw = std::string((char*)(buffer + 8U));
// Left trim
raw.erase(raw.begin(), std::find_if(raw.begin(), raw.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
raw.erase(raw.begin(), std::find_if(raw.begin(), raw.end(), [](unsigned char ch) { return !std::isspace(ch); }));
std::string id = "FCS00";
std::string idShort = "FCS";
if (raw.length() == 3U) {
@ -930,18 +1021,18 @@ void CYSFGateway::processRemoteCommands()
return;
}
if (m_linkType == LINK_YSF) {
if (m_linkType == LINK_TYPE::YSF) {
m_wiresX->processDisconnect();
m_ysfNetwork->writeUnlink(3U);
m_ysfNetwork->clearDestination();
}
if (m_linkType == LINK_FCS)
if (m_linkType == LINK_TYPE::FCS)
m_fcsNetwork->writeUnlink(3U);
m_current.clear();
m_inactivityTimer.stop();
m_lostTimer.stop();
m_linkType = LINK_NONE;
m_linkType = LINK_TYPE::NONE;
LogMessage("Connect by remote command to %s", id.c_str());
@ -950,12 +1041,12 @@ void CYSFGateway::processRemoteCommands()
m_current = id;
m_inactivityTimer.start();
m_lostTimer.start();
m_linkType = LINK_FCS;
m_linkType = LINK_TYPE::FCS;
} else {
LogMessage("Unknown reflector - %s", id.c_str());
}
} else if (::memcmp(buffer + 0U, "UnLink", 6U) == 0) {
if (m_linkType == LINK_YSF) {
if (m_linkType == LINK_TYPE::YSF) {
m_wiresX->processDisconnect();
LogMessage("Disconnect by remote command");
@ -966,9 +1057,9 @@ void CYSFGateway::processRemoteCommands()
m_current.clear();
m_inactivityTimer.stop();
m_lostTimer.stop();
m_linkType = LINK_NONE;
m_linkType = LINK_TYPE::NONE;
}
if (m_linkType == LINK_FCS) {
if (m_linkType == LINK_TYPE::FCS) {
LogMessage("Disconnect by remote command");
m_fcsNetwork->writeUnlink(3U);
@ -977,13 +1068,13 @@ void CYSFGateway::processRemoteCommands()
m_current.clear();
m_inactivityTimer.stop();
m_lostTimer.stop();
m_linkType = LINK_NONE;
m_linkType = LINK_TYPE::NONE;
}
} else if (::memcmp(buffer + 0U, "status", 6U) == 0) {
std::string state = std::string("ysf:") + (((m_ysfNetwork == NULL) && (m_fcsNetwork == NULL)) ? "n/a" : ((m_linkType != LINK_NONE) ? "conn" : "disc"));
std::string state = std::string("ysf:") + (((m_ysfNetwork == nullptr) && (m_fcsNetwork == nullptr)) ? "n/a" : ((m_linkType != LINK_TYPE::NONE) ? "conn" : "disc"));
m_remoteSocket->write((unsigned char*)state.c_str(), (unsigned int)state.length(), addr, addrLen);
} else if (::memcmp(buffer + 0U, "host", 4U) == 0) {
std::string ref = ((((m_ysfNetwork == NULL) && (m_fcsNetwork == NULL)) || (m_linkType == LINK_NONE)) ? "NONE" : m_current);
std::string ref = ((((m_ysfNetwork == nullptr) && (m_fcsNetwork == nullptr)) || (m_linkType == LINK_TYPE::NONE)) ? "NONE" : m_current);
std::string host = std::string("ysf:\"") + ref + "\"";
m_remoteSocket->write((unsigned char*)host.c_str(), (unsigned int)host.length(), addr, addrLen);
} else {

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017,2018,2020,2025 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
@ -32,10 +32,10 @@
#include <string>
enum LINK_TYPE {
LINK_NONE,
LINK_YSF,
LINK_FCS
enum class LINK_TYPE {
NONE,
YSF,
FCS
};
class CYSFGateway
@ -68,8 +68,10 @@ private:
CUDPSocket* m_remoteSocket;
void startupLinking();
void reconnectReflector(const std::string& nameOrId);
void disconnectCurrentReflector();
std::string calculateLocator();
void processWiresX(const unsigned char* buffer, const CYSFFICH& fich, bool dontProcessWiresXLocal, bool wiresXCommandPassthrough);
void processWiresX(const unsigned char* buffer, const CYSFFICH& fich, bool wiresXEnabledReflector, bool wiresXCommandPassthrough);
void processDTMF(unsigned char* buffer, unsigned char dt);
void createWiresX(CYSFNetwork* rptNetwork);
void createGPS();

View file

@ -7,7 +7,6 @@ RptAddress=127.0.0.1
RptPort=3200
LocalAddress=127.0.0.1
LocalPort=4200
WiresXMakeUpper=1
WiresXCommandPassthrough=0
Debug=0
Daemon=0
@ -44,6 +43,7 @@ Suffix=Y
# book DG-ID for Reflector
# Options=20;21;
InactivityTimeout=10
Reconnect=0
Revert=0
Debug=0

View file

@ -94,6 +94,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@ -108,6 +111,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
@ -126,6 +132,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
@ -144,6 +153,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="APRSWriter.h" />

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,43 @@
#! /bin/bash
###############################################################################
#
# Copyright (C) 2025 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.
#
###############################################################################
#
# Full path to the YSFHosts hosts file
#
YSFHOSTS=/path/to/YSFHosts.txt
###############################################################################
#
# Do not edit below here
#
###############################################################################
# Check we are root
if [ "$(id -u)" != "0" ]
then
echo "This script must be run as root" 1>&2
exit 1
fi
# Download the YSFHosts.txt file
curl --fail --silent -S -L -o ${YSFHOSTS} -A "YSFGateway - G4KLX" https://hostfiles.refcheck.radio/YSFHosts.txt
exit 0

View file

@ -1,91 +0,0 @@
#! /bin/bash
###############################################################################
#
# YSFHostsupdate.sh
#
# Copyright (C) 2016 by Tony Corbett G0WFV
# Adapted to YSFHosts by Paul Nannery KC2VRJ on 6/28/2016 with all crdeit
# to G0WFV for the orignal script.
#
# 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.
#
###############################################################################
#
# On a Linux based system, such as a Raspberry Pi, this script will perform all
# the steps required to maintain the YSFHosts.txt (or similar) file for you.
#
# It is designed to run from crontab and will download the YSFHosts from the
# master ysfreflector.de database and optionally keep a backup of previously
# created files for you.
#
# It will also prune the number of backup files according to a value specified
# by you in the configuration below.
#
# To install in root's crontab use the command ...
#
# sudo crontab -e
#
# ... and add the following line to the bottom of the file ...
#
# 0 0 * * * /path/to/script/YSFHostsupdate.sh 1>/dev/null 2>&1
#
# ... where /path/to/script/ should be replaced by the path to this script.
#
###############################################################################
#
# CONFIGURATION
#
# Full path to YSFHosts
YSFHOSTS=/path/to/YSFHosts.txt
# How many YSFHosts files do you want backed up (0 = do not keep backups)
YSFHOSTSFILEBACKUP=1
###############################################################################
#
# Do not edit below here
#
###############################################################################
# Check we are root
if [ "$(id -u)" != "0" ]
then
echo "This script must be run as root" 1>&2
exit 1
fi
# Create backup of old file
if [ ${YSFHOSTSFILEBACKUP} -ne 0 ]
then
cp ${YSFHOSTS} ${YSFHOSTS}.$(date +%d%m%y)
fi
# Prune backups
BACKUPCOUNT=$(ls ${YSFHOSTS}.* | wc -l)
BACKUPSTODELETE=$(expr ${BACKUPCOUNT} - ${YSFHOSTSFILEBACKUP})
if [ ${BACKUPCOUNT} -gt ${YSFHOSTSFILEBACKUP} ]
then
for f in $(ls -tr ${YSFHOSTS}.* | head -${BACKUPSTODELETE})
do
rm -f $f
done
fi
# Generate YSFHosts.txt file
curl https://register.ysfreflector.de/export_csv.php > ${YSFHOSTS}
exit 0

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2014,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2014,2016,2017,2018,2020,2025 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
@ -32,10 +32,10 @@ m_socket(address, port),
m_debug(debug),
m_addr(),
m_addrLen(0U),
m_poll(NULL),
m_options(NULL),
m_poll(nullptr),
m_options(nullptr),
m_opt(),
m_unlink(NULL),
m_unlink(nullptr),
m_buffer(1000U, "YSF Network Buffer"),
m_pollTimer(1000U, 5U),
m_name(),
@ -65,10 +65,10 @@ m_socket(port),
m_debug(debug),
m_addr(),
m_addrLen(0U),
m_poll(NULL),
m_options(NULL),
m_poll(nullptr),
m_options(nullptr),
m_opt(),
m_unlink(NULL),
m_unlink(nullptr),
m_buffer(1000U, "YSF Network Buffer"),
m_pollTimer(1000U, 5U),
m_name(),
@ -119,6 +119,8 @@ bool CYSFNetwork::setDestination(const std::string& name, const sockaddr_storage
m_addrLen = addrLen;
m_linked = false;
close();
bool ret = open();
if (ret) {
m_pollTimer.start();
@ -140,7 +142,7 @@ void CYSFNetwork::clearDestination()
void CYSFNetwork::write(const unsigned char* data)
{
assert(data != NULL);
assert(data != nullptr);
if (m_addrLen == 0U)
return;
@ -249,7 +251,7 @@ void CYSFNetwork::clock(unsigned int ms)
unsigned int CYSFNetwork::read(unsigned char* data)
{
assert(data != NULL);
assert(data != nullptr);
if (m_buffer.isEmpty())
return 0U;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 Jonathan Naylor, G4KLX
* Copyright (C) 2016,2025 Jonathan Naylor, G4KLX
* Copyright (C) 2016 Mathias Weyland, HB9FRV
*
* This program is free software; you can redistribute it and/or modify
@ -86,8 +86,8 @@ CYSFPayload::~CYSFPayload()
bool CYSFPayload::readVDMode1Data(const unsigned char* data, unsigned char* dt)
{
assert(data != NULL);
assert(dt != NULL);
assert(data != nullptr);
assert(dt != nullptr);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -131,8 +131,8 @@ bool CYSFPayload::readVDMode1Data(const unsigned char* data, unsigned char* dt)
bool CYSFPayload::readVDMode2Data(const unsigned char* data, unsigned char* dt)
{
assert(data != NULL);
assert(dt != NULL);
assert(data != nullptr);
assert(dt != nullptr);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -176,8 +176,8 @@ bool CYSFPayload::readVDMode2Data(const unsigned char* data, unsigned char* dt)
bool CYSFPayload::readDataFRModeData1(const unsigned char* data, unsigned char* dt)
{
assert(data != NULL);
assert(dt != NULL);
assert(data != nullptr);
assert(dt != nullptr);
::memset(dt, ' ', 20U);
@ -223,8 +223,8 @@ bool CYSFPayload::readDataFRModeData1(const unsigned char* data, unsigned char*
bool CYSFPayload::readDataFRModeData2(const unsigned char* data, unsigned char* dt)
{
assert(data != NULL);
assert(dt != NULL);
assert(data != nullptr);
assert(dt != nullptr);
::memset(dt, ' ', 20U);
@ -270,8 +270,8 @@ bool CYSFPayload::readDataFRModeData2(const unsigned char* data, unsigned char*
void CYSFPayload::writeDataFRModeData1(const unsigned char* dt, unsigned char* data)
{
assert(dt != NULL);
assert(data != NULL);
assert(dt != nullptr);
assert(data != nullptr);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -287,7 +287,7 @@ void CYSFPayload::writeDataFRModeData1(const unsigned char* dt, unsigned char* d
CYSFConvolution conv;
conv.encode(output, convolved, 180U);
unsigned char bytes[45U];
unsigned char bytes[45U] = { 0x00U };
unsigned int j = 0U;
for (unsigned int i = 0U; i < 180U; i++) {
unsigned int n = INTERLEAVE_TABLE_9_20[i];
@ -314,8 +314,8 @@ void CYSFPayload::writeDataFRModeData1(const unsigned char* dt, unsigned char* d
void CYSFPayload::writeDataFRModeData2(const unsigned char* dt, unsigned char* data)
{
assert(dt != NULL);
assert(data != NULL);
assert(dt != nullptr);
assert(data != nullptr);
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
@ -331,7 +331,7 @@ void CYSFPayload::writeDataFRModeData2(const unsigned char* dt, unsigned char* d
CYSFConvolution conv;
conv.encode(output, convolved, 180U);
unsigned char bytes[45U];
unsigned char bytes[45U] = { 0x00U };
unsigned int j = 0U;
for (unsigned int i = 0U; i < 180U; i++) {
unsigned int n = INTERLEAVE_TABLE_9_20[i];

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2021 by Jonathan Naylor G4KLX
* Copyright (C) 2016-2021,2025 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
@ -26,7 +26,7 @@
#include <cstring>
#include <cctype>
CYSFReflectors::CYSFReflectors(const std::string& hostsFile, unsigned int reloadTime, bool makeUpper) :
CYSFReflectors::CYSFReflectors(const std::string& hostsFile, unsigned int reloadTime) :
m_hostsFile(hostsFile),
m_parrotAddress(),
m_parrotPort(0U),
@ -40,7 +40,6 @@ m_fcsRooms(),
m_newReflectors(),
m_currReflectors(),
m_search(),
m_makeUpper(makeUpper),
m_timer(1000U, reloadTime * 60U)
{
if (reloadTime > 0U)
@ -61,8 +60,8 @@ CYSFReflectors::~CYSFReflectors()
static bool refComparison(const CYSFReflector* r1, const CYSFReflector* r2)
{
assert(r1 != NULL);
assert(r2 != NULL);
assert(r1 != nullptr);
assert(r2 != nullptr);
std::string name1 = r1->m_name;
std::string name2 = r2->m_name;
@ -113,20 +112,20 @@ bool CYSFReflectors::load()
m_newReflectors.clear();
FILE* fp = ::fopen(m_hostsFile.c_str(), "rt");
if (fp != NULL) {
if (fp != nullptr) {
char buffer[100U];
while (::fgets(buffer, 100U, fp) != NULL) {
while (::fgets(buffer, 100U, fp) != nullptr) {
if (buffer[0U] == '#')
continue;
char* p1 = ::strtok(buffer, ";\r\n");
char* p2 = ::strtok(NULL, ";\r\n");
char* p3 = ::strtok(NULL, ";\r\n");
char* p4 = ::strtok(NULL, ";\r\n");
char* p5 = ::strtok(NULL, ";\r\n");
char* p6 = ::strtok(NULL, "\r\n");
char* p2 = ::strtok(nullptr, ";\r\n");
char* p3 = ::strtok(nullptr, ";\r\n");
char* p4 = ::strtok(nullptr, ";\r\n");
char* p5 = ::strtok(nullptr, ";\r\n");
char* p6 = ::strtok(nullptr, "\r\n");
if (p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL && p5 != NULL && p6 != NULL) {
if (p1 != nullptr && p2 != nullptr && p3 != nullptr && p4 != nullptr && p5 != nullptr && p6 != nullptr) {
std::string host = std::string(p4);
unsigned short port = (unsigned short)::atoi(p5);
@ -141,9 +140,8 @@ bool CYSFReflectors::load()
refl->m_addr = addr;
refl->m_addrLen = addrLen;
refl->m_count = std::string(p6);
refl->m_type = YT_YSF;
refl->m_wiresX = (refl->m_name.compare(0, 3, "XLX") == 0);
refl->m_type = YSF_TYPE::YSF;
refl->m_wiresX = ( refl->m_name.compare(0, 3, "XLX") == 0 || refl->m_name.compare(2, 4, "-XLX") == 0 );
refl->m_name.resize(16U, ' ');
refl->m_desc.resize(14U, ' ');
@ -172,7 +170,7 @@ bool CYSFReflectors::load()
refl->m_addr = addr;
refl->m_addrLen = addrLen;
refl->m_count = "000";
refl->m_type = YT_YSF;
refl->m_type = YSF_TYPE::YSF;
refl->m_wiresX = false;
m_newReflectors.push_back(refl);
@ -195,7 +193,7 @@ bool CYSFReflectors::load()
refl->m_addr = addr;
refl->m_addrLen = addrLen;
refl->m_count = "000";
refl->m_type = YT_YSF;
refl->m_type = YSF_TYPE::YSF;
refl->m_wiresX = true;
m_newReflectors.push_back(refl);
@ -218,7 +216,7 @@ bool CYSFReflectors::load()
refl->m_addr = addr;
refl->m_addrLen = addrLen;
refl->m_count = "000";
refl->m_type = YT_YSF;
refl->m_type = YSF_TYPE::YSF;
refl->m_wiresX = true;
m_newReflectors.push_back(refl);
@ -241,7 +239,7 @@ bool CYSFReflectors::load()
refl->m_addr = addr;
refl->m_addrLen = addrLen;
refl->m_count = "000";
refl->m_type = YT_YSF;
refl->m_type = YSF_TYPE::YSF;
refl->m_wiresX = true;
m_newReflectors.push_back(refl);
@ -272,7 +270,7 @@ bool CYSFReflectors::load()
refl->m_desc = desc;
refl->m_addrLen = 0U;
refl->m_count = "000";
refl->m_type = YT_FCS;
refl->m_type = YSF_TYPE::FCS;
refl->m_wiresX = false;
refl->m_name.resize(16U, ' ');
@ -285,13 +283,6 @@ bool CYSFReflectors::load()
if (size == 0U)
return false;
if (m_makeUpper) {
for (std::vector<CYSFReflector*>::iterator it = m_newReflectors.begin(); it != m_newReflectors.end(); ++it) {
std::transform((*it)->m_name.begin(), (*it)->m_name.end(), (*it)->m_name.begin(), ::toupper);
std::transform((*it)->m_desc.begin(), (*it)->m_desc.end(), (*it)->m_desc.begin(), ::toupper);
}
}
std::sort(m_newReflectors.begin(), m_newReflectors.end(), refComparison);
return true;
@ -306,7 +297,7 @@ CYSFReflector* CYSFReflectors::findById(const std::string& id)
LogMessage("Trying to find non existent YSF reflector with an id of %s", id.c_str());
return NULL;
return nullptr;
}
bool CYSFReflectors::findById(unsigned int id) const
@ -325,9 +316,6 @@ bool CYSFReflectors::findById(unsigned int id) const
CYSFReflector* CYSFReflectors::findByName(const std::string& name)
{
std::string fullName = name;
if (m_makeUpper) {
std::transform(fullName.begin(), fullName.end(), fullName.begin(), ::toupper);
}
fullName.resize(16U, ' ');
for (std::vector<CYSFReflector*>::const_iterator it = m_currReflectors.cbegin(); it != m_currReflectors.cend(); ++it) {
@ -337,7 +325,7 @@ CYSFReflector* CYSFReflectors::findByName(const std::string& name)
LogMessage("Trying to find non existent YSF reflector with a name of %s", name.c_str());
return NULL;
return nullptr;
}
std::vector<CYSFReflector*>& CYSFReflectors::current()
@ -350,7 +338,7 @@ std::vector<CYSFReflector*>& CYSFReflectors::search(const std::string& name)
m_search.clear();
std::string trimmed = name;
trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), trimmed.end());
trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), trimmed.end());
std::transform(trimmed.begin(), trimmed.end(), trimmed.begin(), ::toupper);
// Removed now un-used variable
@ -358,13 +346,13 @@ std::vector<CYSFReflector*>& CYSFReflectors::search(const std::string& name)
for (std::vector<CYSFReflector*>::iterator it = m_currReflectors.begin(); it != m_currReflectors.end(); ++it) {
std::string reflector = (*it)->m_name;
reflector.erase(std::find_if(reflector.rbegin(), reflector.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), reflector.end());
reflector.erase(std::find_if(reflector.rbegin(), reflector.rend(),[](unsigned char ch) { return !std::isspace(ch); }).base(),reflector.end());
std::transform(reflector.begin(), reflector.end(), reflector.begin(), ::toupper);
// Original match function - only matches start of string.
// if (trimmed == reflector.substr(0U, len))
// m_search.push_back(*it);
// New match function searches the whole string
for (unsigned int refSrcPos = 0U; refSrcPos < reflector.length(); refSrcPos++) {
if (reflector.substr(refSrcPos, trimmed.length()) == trimmed) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2021 by Jonathan Naylor G4KLX
* Copyright (C) 2016-2021,2025 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
@ -25,9 +25,9 @@
#include <vector>
#include <string>
enum YSF_TYPE {
YT_YSF,
YT_FCS
enum class YSF_TYPE {
YSF,
FCS
};
class CYSFReflector {
@ -39,7 +39,7 @@ public:
m_count("000"),
m_addr(),
m_addrLen(0U),
m_type(YT_YSF),
m_type(YSF_TYPE::YSF),
m_wiresX(false)
{
}
@ -56,7 +56,7 @@ public:
class CYSFReflectors {
public:
CYSFReflectors(const std::string& hostsFile, unsigned int reloadTime, bool makeUpper);
CYSFReflectors(const std::string& hostsFile, unsigned int reloadTime);
~CYSFReflectors();
void setParrot(const std::string& address, unsigned short port);
@ -92,7 +92,6 @@ private:
std::vector<CYSFReflector*> m_newReflectors;
std::vector<CYSFReflector*> m_currReflectors;
std::vector<CYSFReflector*> m_search;
bool m_makeUpper;
CTimer m_timer;
bool findById(unsigned int id) const;

38
YSFGateway/prebuild.cmd Normal file
View file

@ -0,0 +1,38 @@
@echo off
REM This pre-build file is for MSVS VC++. It parses the git master hash and
REM converts it into GitVersion.h for compiling into builds. [George M1GEO]
cd %1
setlocal enabledelayedexpansion
set HEADFILE=..\.git\HEAD
set HASHFILE=0
if exist %HEADFILE% (
for /F "tokens=4 delims=/:" %%a in ('type %HEADFILE%') do set HEADBRANCH=%%a
set HASHFILE=..\.git\refs\heads\!HEADBRANCH!
echo Found Git HEAD file: %HEADFILE%
echo Git HEAD branch: !HEADBRANCH!
echo Git HASH file: !HASHFILE!
call :USEHASH
) else (
echo No head file :(
call :USENULL
)
goto :EOF
:USENULL
set GITHASH=0000000000000000000000000000000000000000
goto :WRITEGITVERSIONHEADER
:USEHASH
for /f %%i in ('type !HASHFILE!') do set GITHASH=%%i
goto :WRITEGITVERSIONHEADER
:WRITEGITVERSIONHEADER
echo // File contains Git commit ID SHA1 present at buildtime (prebuild.cmd) > GitVersion.h
echo const char *gitversion = "%GITHASH%"; >> GitVersion.h
echo Current Git HASH: %GITHASH%
goto :FINISHED
:FINISHED
echo GitVersion.h written...

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2014,2016,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2014,2016,2018,2020,2025 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
@ -47,7 +47,7 @@ bool CNetwork::write(const unsigned char* data)
if (m_addrLen == 0U)
return true;
assert(data != NULL);
assert(data != nullptr);
return m_socket.write(data, 155U, m_addr, m_addrLen);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2025 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
@ -23,7 +23,7 @@
#include <cstring>
CParrot::CParrot(unsigned int timeout) :
m_data(NULL),
m_data(nullptr),
m_length(timeout * 1550U + 1000U),
m_used(0U),
m_ptr(0U)
@ -40,7 +40,7 @@ CParrot::~CParrot()
bool CParrot::write(const unsigned char* data)
{
assert(data != NULL);
assert(data != nullptr);
if ((m_length - m_used) < 1000U)
return false;
@ -64,7 +64,7 @@ void CParrot::clear()
unsigned int CParrot::read(unsigned char* data)
{
assert(data != NULL);
assert(data != nullptr);
if (m_used == 0U)
return 0U;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2018,2025 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
@ -77,7 +77,7 @@ CStopWatch::~CStopWatch()
unsigned long long CStopWatch::time() const
{
struct timeval now;
::gettimeofday(&now, NULL);
::gettimeofday(&now, nullptr);
return now.tv_sec * 1000ULL + now.tv_usec / 1000ULL;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2025 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
@ -31,9 +31,9 @@ CThread::~CThread()
bool CThread::run()
{
m_handle = ::CreateThread(NULL, 0, &helper, this, 0, NULL);
m_handle = ::CreateThread(nullptr, 0, &helper, this, 0, nullptr);
return m_handle != NULL;
return m_handle != nullptr;
}
@ -74,13 +74,13 @@ CThread::~CThread()
bool CThread::run()
{
return ::pthread_create(&m_thread, NULL, helper, this) == 0;
return ::pthread_create(&m_thread, nullptr, helper, this) == 0;
}
void CThread::wait()
{
::pthread_join(m_thread, NULL);
::pthread_join(m_thread, nullptr);
}
@ -90,7 +90,7 @@ void* CThread::helper(void* arg)
p->entry();
return NULL;
return nullptr;
}
void CThread::sleep(unsigned int ms)

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2006-2016,2020,2024,2025 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
@ -34,29 +34,27 @@
#endif
CUDPSocket::CUDPSocket(const std::string& address, unsigned short port) :
m_address_save(address),
m_port_save(port),
m_counter(0U)
m_localAddress(address),
m_localPort(port),
#if defined(_WIN32) || defined(_WIN64)
m_fd(INVALID_SOCKET),
#else
m_fd(-1),
#endif
m_af(AF_UNSPEC)
{
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
m_af[i] = 0U;
m_fd[i] = -1;
}
}
CUDPSocket::CUDPSocket(unsigned short port) :
m_address_save(),
m_port_save(port),
m_counter(0U)
m_localAddress(),
m_localPort(port),
#if defined(_WIN32) || defined(_WIN64)
m_fd(INVALID_SOCKET),
#else
m_fd(-1),
#endif
m_af(AF_UNSPEC)
{
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
m_af[i] = 0U;
m_fd[i] = -1;
}
}
CUDPSocket::~CUDPSocket()
@ -93,10 +91,10 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned short port, sockadd
std::string portstr = std::to_string(port);
struct addrinfo *res;
/* port is always digits, no needs to lookup service */
/* Port is always digits, no needs to lookup service */
hints.ai_flags |= AI_NUMERICSERV;
int err = getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res);
int err = ::getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res);
if (err != 0) {
sockaddr_in* paddr = (sockaddr_in*)&addr;
::memset(paddr, 0x00U, address_length = sizeof(sockaddr_in));
@ -107,9 +105,11 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned short port, sockadd
return err;
}
::memcpy(&addr, res->ai_addr, address_length = res->ai_addrlen);
address_length = (unsigned int)res->ai_addrlen;
freeaddrinfo(res);
::memcpy(&addr, res->ai_addr, address_length);
::freeaddrinfo(res);
return 0;
}
@ -119,35 +119,35 @@ bool CUDPSocket::match(const sockaddr_storage& addr1, const sockaddr_storage& ad
if (addr1.ss_family != addr2.ss_family)
return false;
if (type == IMT_ADDRESS_AND_PORT) {
if (type == IPMATCHTYPE::ADDRESS_AND_PORT) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port);
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port);
default:
return false;
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port);
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port);
default:
return false;
}
} else if (type == IMT_ADDRESS_ONLY) {
} else if (type == IPMATCHTYPE::ADDRESS_ONLY) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr;
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr);
default:
return false;
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr;
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr);
default:
return false;
}
} else {
return false;
@ -163,35 +163,38 @@ bool CUDPSocket::isNone(const sockaddr_storage& addr)
bool CUDPSocket::open(const sockaddr_storage& address)
{
return open(address.ss_family);
m_af = address.ss_family;
return open();
}
bool CUDPSocket::open(unsigned int af)
bool CUDPSocket::open()
{
return open(0, af, m_address_save, m_port_save);
}
#if defined(_WIN32) || defined(_WIN64)
assert(m_fd == INVALID_SOCKET);
#else
assert(m_fd == -1);
#endif
bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned short port)
{
sockaddr_storage addr;
unsigned int addrlen;
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = af;
hints.ai_family = m_af;
/* to determine protocol family, call lookup() first. */
int err = lookup(address, port, addr, addrlen, hints);
// To determine protocol family, call lookup() on the local address first.
int err = lookup(m_localAddress, m_localPort, addr, addrlen, hints);
if (err != 0) {
LogError("The local address is invalid - %s", address.c_str());
LogError("The local address is invalid - %s", m_localAddress.c_str());
return false;
}
close(index);
m_af = addr.ss_family;
int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0);
if (fd < 0) {
m_fd = ::socket(m_af, SOCK_DGRAM, 0);
if (m_fd < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot create the UDP socket, err: %lu", ::GetLastError());
#else
@ -200,62 +203,58 @@ bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std
return false;
}
m_address[index] = address;
m_port[index] = port;
m_af[index] = addr.ss_family;
m_fd[index] = fd;
if (port > 0U) {
if (m_localPort > 0U) {
int reuse = 1;
if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError());
#else
LogError("Cannot set the UDP socket option, err: %d", errno);
#endif
close();
return false;
}
if (::bind(fd, (sockaddr*)&addr, addrlen) == -1) {
if (::bind(m_fd, (sockaddr*)&addr, addrlen) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot bind the UDP address, err: %lu", ::GetLastError());
#else
LogError("Cannot bind the UDP address, err: %d", errno);
#endif
close();
return false;
}
LogInfo("Opening UDP port on %hu", port);
LogInfo("Opening UDP port on %hu", m_localPort);
}
return true;
}
int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length)
int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &addressLength)
{
assert(buffer != NULL);
assert(buffer != nullptr);
assert(length > 0U);
// Check that the readfrom() won't block
int i, n;
struct pollfd pfd[UDP_SOCKET_MAX];
for (i = n = 0; i < UDP_SOCKET_MAX; i++) {
if (m_fd[i] >= 0) {
pfd[n].fd = m_fd[i];
pfd[n].events = POLLIN;
n++;
}
}
// no socket descriptor to receive
if (n == 0)
#if defined(_WIN32) || defined(_WIN64)
if (m_fd == INVALID_SOCKET)
return 0;
#else
if (m_fd == -1)
return 0;
#endif
// Check that the readfrom() won't block
struct pollfd pfd;
pfd.fd = m_fd;
pfd.events = POLLIN;
pfd.revents = 0;
// Return immediately
#if defined(_WIN32) || defined(_WIN64)
int ret = WSAPoll(pfd, n, 0);
int ret = WSAPoll(&pfd, 1, 0);
#else
int ret = ::poll(pfd, n, 0);
int ret = ::poll(&pfd, 1, 0);
#endif
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
@ -266,14 +265,7 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
return -1;
}
int index;
for (i = 0; i < n; i++) {
// round robin
index = (i + m_counter) % n;
if (pfd[index].revents & POLLIN)
break;
}
if (i == n)
if ((pfd.revents & POLLIN) == 0)
return 0;
#if defined(_WIN32) || defined(_WIN64)
@ -283,9 +275,9 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
#endif
#if defined(_WIN32) || defined(_WIN64)
int len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
#else
ssize_t len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
#endif
if (len <= 0) {
#if defined(_WIN32) || defined(_WIN64)
@ -294,7 +286,7 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
LogError("Error returned from recvfrom, err: %d", errno);
if (len == -1 && errno == ENOTSOCK) {
LogMessage("Re-opening UDP port on %hu", m_port[index]);
LogMessage("Re-opening UDP port on %hu", m_localPort);
close();
open();
}
@ -302,43 +294,43 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
return -1;
}
m_counter++;
address_length = size;
addressLength = size;
return len;
}
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length)
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int addressLength)
{
assert(buffer != NULL);
assert(buffer != nullptr);
assert(length > 0U);
#if defined(_WIN32) || defined(_WIN64)
assert(m_fd != INVALID_SOCKET);
#else
assert(m_fd >= 0);
#endif
bool result = false;
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
if (m_fd[i] < 0 || m_af[i] != address.ss_family)
continue;
#if defined(_WIN32) || defined(_WIN64)
int ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, addressLength);
#else
ssize_t ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, addressLength);
#endif
if (ret < 0) {
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from sendto, err: %lu", ::GetLastError());
LogError("Error returned from sendto, err: %lu", ::GetLastError());
#else
LogError("Error returned from sendto, err: %d", errno);
LogError("Error returned from sendto, err: %d", errno);
#endif
} else {
} else {
#if defined(_WIN32) || defined(_WIN64)
if (ret == int(length))
result = true;
if (ret == int(length))
result = true;
#else
if (ret == ssize_t(length))
result = true;
if (ret == ssize_t(length))
result = true;
#endif
}
}
return result;
@ -346,18 +338,16 @@ bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const s
void CUDPSocket::close()
{
for (unsigned int i = 0; i < UDP_SOCKET_MAX; i++)
close(i);
#if defined(_WIN32) || defined(_WIN64)
if (m_fd != INVALID_SOCKET) {
::closesocket(m_fd);
m_fd = INVALID_SOCKET;
}
#else
if (m_fd >= 0) {
::close(m_fd);
m_fd = -1;
}
#endif
}
void CUDPSocket::close(const unsigned int index)
{
if ((index < UDP_SOCKET_MAX) && (m_fd[index] >= 0)) {
#if defined(_WIN32) || defined(_WIN64)
::closesocket(m_fd[index]);
#else
::close(m_fd[index]);
#endif
m_fd[index] = -1;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2011,2013,2015,2016,2020,2024,2025 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
@ -35,13 +35,9 @@
#include <ws2tcpip.h>
#endif
#if !defined(UDP_SOCKET_MAX)
#define UDP_SOCKET_MAX 1
#endif
enum IPMATCHTYPE {
IMT_ADDRESS_AND_PORT,
IMT_ADDRESS_ONLY
enum class IPMATCHTYPE {
ADDRESS_AND_PORT,
ADDRESS_ONLY
};
class CUDPSocket {
@ -50,34 +46,34 @@ public:
CUDPSocket(unsigned short port = 0U);
~CUDPSocket();
bool open(unsigned int af = AF_UNSPEC);
bool open();
bool open(const sockaddr_storage& address);
bool open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned short port);
int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length);
bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length);
int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &addressLength);
bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int addressLength);
void close();
void close(const unsigned int index);
static void startup();
static void shutdown();
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& address_length);
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& address_length, struct addrinfo& hints);
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& addressLength);
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& addressLength, struct addrinfo& hints);
static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type = IMT_ADDRESS_AND_PORT);
static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type = IPMATCHTYPE::ADDRESS_AND_PORT);
static bool isNone(const sockaddr_storage& addr);
private:
std::string m_address_save;
unsigned short m_port_save;
std::string m_address[UDP_SOCKET_MAX];
unsigned short m_port[UDP_SOCKET_MAX];
unsigned int m_af[UDP_SOCKET_MAX];
int m_fd[UDP_SOCKET_MAX];
unsigned int m_counter;
std::string m_localAddress;
unsigned short m_localPort;
#if defined(_WIN32) || defined(_WIN64)
SOCKET m_fd;
int m_af;
#else
int m_fd;
sa_family_t m_af;
#endif
};
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2020,2024,2025 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
@ -19,6 +19,6 @@
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20201101";
const char* VERSION = "20250607";
#endif

View file

@ -94,6 +94,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@ -108,6 +111,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
@ -126,6 +132,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
@ -144,6 +153,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="StopWatch.h" />

38
YSFParrot/prebuild.cmd Normal file
View file

@ -0,0 +1,38 @@
@echo off
REM This pre-build file is for MSVS VC++. It parses the git master hash and
REM converts it into GitVersion.h for compiling into builds. [George M1GEO]
cd %1
setlocal enabledelayedexpansion
set HEADFILE=..\.git\HEAD
set HASHFILE=0
if exist %HEADFILE% (
for /F "tokens=4 delims=/:" %%a in ('type %HEADFILE%') do set HEADBRANCH=%%a
set HASHFILE=..\.git\refs\heads\!HEADBRANCH!
echo Found Git HEAD file: %HEADFILE%
echo Git HEAD branch: !HEADBRANCH!
echo Git HASH file: !HASHFILE!
call :USEHASH
) else (
echo No head file :(
call :USENULL
)
goto :EOF
:USENULL
set GITHASH=0000000000000000000000000000000000000000
goto :WRITEGITVERSIONHEADER
:USEHASH
for /f %%i in ('type !HASHFILE!') do set GITHASH=%%i
goto :WRITEGITVERSIONHEADER
:WRITEGITVERSIONHEADER
echo // File contains Git commit ID SHA1 present at buildtime (prebuild.cmd) > GitVersion.h
echo const char *gitversion = "%GITHASH%"; >> GitVersion.h
echo Current Git HASH: %GITHASH%
goto :FINISHED
:FINISHED
echo GitVersion.h written...