diff --git a/DPlusAuthenticator.cpp b/DPlusAuthenticator.cpp index 51b3d13..ffbdafe 100644 --- a/DPlusAuthenticator.cpp +++ b/DPlusAuthenticator.cpp @@ -47,7 +47,7 @@ CDPlusAuthenticator::~CDPlusAuthenticator() int CDPlusAuthenticator::Process(CQnetDB &db, const bool reflectors, const bool repeaters) // return true if everything went okay { - int result = client.Open(m_address, AF_UNSPEC, "20001"); + int result = client.Open(m_address, AF_UNSPEC, "20001", false); if (result) { fprintf(stderr, "DPlus Authorization failed: %s\n", gai_strerror(result)); diff --git a/QnetGateway.cpp b/QnetGateway.cpp index 93c4310..b7f8591 100644 --- a/QnetGateway.cpp +++ b/QnetGateway.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include "IRCDDB.h" #include "IRCutils.h" @@ -50,7 +51,7 @@ #include "QnetGateway.h" #include "Utilities.h" -const std::string GW_VERSION("QnetGateway-60706"); +const std::string GW_VERSION("QnetGateway-261105"); int CQnetGateway::FindIndex(const int i) const { @@ -335,6 +336,7 @@ bool CQnetGateway::ReadConfig(const std::string &cfgFile) cfg.GetValue(path+"irc", estr, LOG_IRC); cfg.GetValue(path+"dtmf", estr, LOG_DTMF); cfg.GetValue(path+"debug", estr, LOG_DEBUG); + cfg.GetValue(path+"aprs", estr, LOG_APRS); // file path.assign("file_"); @@ -2184,186 +2186,53 @@ void CQnetGateway::APRSBeaconThread() char rcv_buf[512]; time_t tnow = 0; - /* - Every 20 seconds, the remote APRS host sends a KEEPALIVE packet-comment - on the TCP/APRS port. - If we have not received any KEEPALIVE packet-comment after 5 minutes - we must assume that the remote APRS host is down or disappeared - or has dropped the connection. In these cases, we must re-connect. - There are 3 keepalive packets in one minute, or every 20 seconds. - In 5 minutes, we should have received a total of 15 keepalive packets. - */ - int16_t THRESHOLD_COUNTDOWN = 15; - - time_t last_keepalive_time; - time(&last_keepalive_time); - time_t last_beacon_time = 0; /* This thread is also saying to the APRS_HOST that we are ALIVE */ while (keep_running) { - if (aprs->aprs_sock.GetFD() == -1) + // start up the aprs client + while (keep_running and (aprs->aprs_sock.GetFD() < 0)) { - aprs->Open(OWNER); + aprs->Open(OWNER, GW_VERSION); if (aprs->aprs_sock.GetFD() == -1) - sleep(1); - else - THRESHOLD_COUNTDOWN = 15; + sleep(5); } + // see if it's time to update aprs beacon time(&tnow); - if ((tnow - last_beacon_time) > (Rptr.aprs_interval * 60)) + if ((tnow - last_beacon_time) >= (Rptr.aprs_interval * 60)) { - for (int16_t i=0; i<3; i++) + // update each channel, A B C + for (int i=0; i<3; i++) { - if (Rptr.mod[i].defined) + if (Rptr.mod[i].defined and aprs->aprs_sock.GetFD() >= 0) { - float tmp_lat = fabs(Rptr.mod[i].latitude); - float tmp_lon = fabs(Rptr.mod[i].longitude); - float lat = floor(tmp_lat); - float lon = floor(tmp_lon); - lat = (tmp_lat - lat) * 60.0F + lat * 100.0F; - lon = (tmp_lon - lon) * 60.0F + lon * 100.0F; - - char lat_s[15], lon_s[15]; - if (lat >= 1000.0F) - sprintf(lat_s, "%.2f", lat); - else if (lat >= 100.0F) - sprintf(lat_s, "0%.2f", lat); - else if (lat >= 10.0F) - sprintf(lat_s, "00%.2f", lat); - else - sprintf(lat_s, "000%.2f", lat); - - if (lon >= 10000.0F) - sprintf(lon_s, "%.2f", lon); - else if (lon >= 1000.0F) - sprintf(lon_s, "0%.2f", lon); - else if (lon >= 100.0F) - sprintf(lon_s, "00%.2f", lon); - else if (lon >= 10.0F) - sprintf(lon_s, "000%.2f", lon); - else - sprintf(lon_s, "0000%.2f", lon); - - /* send to aprs */ - sprintf(snd_buf, "%s>APJI23,TCPIP*,qAC,%sS:!%s%cD%s%c&RNG%04u %s %s", - Rptr.mod[i].call.c_str(), Rptr.mod[i].call.c_str(), - lat_s, (Rptr.mod[i].latitude < 0.0) ? 'S' : 'N', - lon_s, (Rptr.mod[i].longitude < 0.0) ? 'W' : 'E', - (unsigned int)Rptr.mod[i].range, Rptr.mod[i].band.c_str(), GW_VERSION.c_str()); - if (LOG_DEBUG) - printf("APRS Beacon =[%s]\n", snd_buf); - strcat(snd_buf, "\r\n"); - - while (keep_running) - { - if (aprs->aprs_sock.GetFD() == -1) - { - aprs->Open(OWNER); - if (aprs->aprs_sock.GetFD() == -1) - sleep(1); - else - THRESHOLD_COUNTDOWN = 15; - } - else - { - int rc = aprs->aprs_sock.Write((uint8_t *)snd_buf, strlen(snd_buf)); - if (rc < 0) - { - if ((errno == EPIPE) || - (errno == ECONNRESET) || - (errno == ETIMEDOUT) || - (errno == ECONNABORTED) || - (errno == ESHUTDOWN) || - (errno == EHOSTUNREACH) || - (errno == ENETRESET) || - (errno == ENETDOWN) || - (errno == ENETUNREACH) || - (errno == EHOSTDOWN) || - (errno == ENOTCONN)) - { - printf("send_aprs_beacon: APRS_HOST closed connection,error=%d\n",errno); - aprs->aprs_sock.Close(); - } - else if (errno == EWOULDBLOCK) - { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - else - { - /* Cant do nothing about it */ - printf("send_aprs_beacon failed, error=%d\n", errno); - break; - } - } - else - { - // printf("APRS beacon sent\n"); - break; + auto line = Rptr.mod[i].position_ss.str(); + if (aprs->aprs_sock.WriteLine(line)) { + aprs->aprs_sock.Close(); + } else { + if (aprs->aprs_sock.ReadLine(line)) { + aprs->aprs_sock.Close(); + } else { + if (aprs->m_debug) { + printf("APRS packet ackn: %s\n", line.c_str()); } + time(&last_beacon_time); } - int rc = aprs->aprs_sock.Read((uint8_t *)rcv_buf, sizeof(rcv_buf)); - if (rc > 0) - THRESHOLD_COUNTDOWN = 15; } } - int rc = aprs->aprs_sock.Read((uint8_t *)rcv_buf, sizeof(rcv_buf)); - if (rc > 0) - THRESHOLD_COUNTDOWN = 15; - } - time(&last_beacon_time); - } - /* - Are we still receiving from APRS host ? - */ - int rc = aprs->aprs_sock.Read((uint8_t *)rcv_buf, sizeof(rcv_buf)); - if (rc < 0) - { - if ((errno == EPIPE) || - (errno == ECONNRESET) || - (errno == ETIMEDOUT) || - (errno == ECONNABORTED) || - (errno == ESHUTDOWN) || - (errno == EHOSTUNREACH) || - (errno == ENETRESET) || - (errno == ENETDOWN) || - (errno == ENETUNREACH) || - (errno == EHOSTDOWN) || - (errno == ENOTCONN)) - { - printf("send_aprs_beacon: recv error: APRS_HOST closed connection,error=%d\n",errno); - aprs->aprs_sock.Close(); } } - else if (rc == 0) - { - printf("send_aprs_beacon: recv: APRS shutdown\n"); - aprs->aprs_sock.Close(); - } - else - THRESHOLD_COUNTDOWN = 15; - - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - /* 20 seconds passed already ? */ - time(&tnow); - if ((tnow - last_keepalive_time) > 20) - { - /* we should be receving keepalive packets ONLY if the connection is alive */ - if (aprs->aprs_sock.GetFD() >= 0) - { - if (THRESHOLD_COUNTDOWN > 0) - THRESHOLD_COUNTDOWN--; - - if (THRESHOLD_COUNTDOWN == 0) - { - printf("APRS host keepalive timeout\n"); - aprs->aprs_sock.Close(); - } + // Are we still receiving keepalives from APRS host ? + if (keep_running and aprs->aprs_sock.GetFD() >= 0) { + std::string line; + if (aprs->aprs_sock.ReadLine(line)) { + aprs->aprs_sock.Close(); + } else { + if (aprs->m_debug) + printf("APRS keep alive: %s\n", line.c_str()); } - /* reset timer */ - time(&last_keepalive_time); } } printf("APRS beacon thread exiting...\n"); @@ -2535,6 +2404,28 @@ void CQnetGateway::qrgs_and_maps() return; } +// Helper to convert decimal degrees to APRS DDMM.hh format +std::string CQnetGateway::convertToAprsCoordinate(double decimalDegrees, bool isLatitude) +{ + double absolute = std::abs(decimalDegrees); + int degrees = static_cast(absolute); + double minutes = (absolute - degrees) * 60.0; + + std::stringstream ss; + if (isLatitude) { + // DDMM.hh (2 digits for degrees) + ss << std::setw(2) << std::setfill('0') << degrees; + ss << std::setw(5) << std::setfill('0') << std::fixed << std::setprecision(2) << minutes; + ss << (decimalDegrees >= 0 ? 'N' : 'S'); + } else { + // DDDMM.hh (3 digits for degrees) + ss << std::setw(3) << std::setfill('0') << degrees; + ss << std::setw(5) << std::setfill('0') << std::fixed << std::setprecision(2) << minutes; + ss << (decimalDegrees >= 0 ? 'E' : 'W'); + } + return ss.str(); +} + bool CQnetGateway::Initialize(const std::string &path) { int16_t i; @@ -2631,7 +2522,7 @@ bool CQnetGateway::Initialize(const std::string &path) if (APRS_ENABLE) { - aprs = new CAPRS(&Rptr); + aprs = new CAPRS(&Rptr, LOG_APRS); if (aprs) aprs->Init(); else @@ -2639,8 +2530,17 @@ bool CQnetGateway::Initialize(const std::string &path) printf("aprs class init failed!\nAPRS will be turned off"); APRS_ENABLE = false; } + for (int i=0; i<3; i++) { + if (Rptr.mod[i].defined) { + Rptr.mod[i].position_ss << Rptr.mod[i].call << ">APRS,TCPIP*:" + << '!' << convertToAprsCoordinate(Rptr.mod[i].latitude, true) << 'D' << convertToAprsCoordinate(Rptr.mod[i].longitude,false) << '&' + << Rptr.mod[i].band << " Voice (DStar) " + << std::fixed << std::setprecision(4) << std::showpos + << Rptr.mod[i].frequency << "MHz " << Rptr.mod[i].offset << "MHz QnetGateway"; + } + } + compute_aprs_hash(); } - compute_aprs_hash(); for (int j=0; j<2; j++) { diff --git a/QnetGateway.h b/QnetGateway.h index ea6b5b1..7a53406 100644 --- a/QnetGateway.h +++ b/QnetGateway.h @@ -115,7 +115,7 @@ private: std::string OWNER, owner, FILE_DTMF, FILE_ECHOTEST, IRCDDB_PASSWORD[2], FILE_QNVOICE_FILE, DASH_SHOW_ORDER; bool GATEWAY_SEND_QRGS_MAP, GATEWAY_HEADER_REGEN, APRS_ENABLE, playNotInCache, showLastHeard; - bool LOG_DEBUG, LOG_IRC, LOG_DTMF, LOG_QSO, IS_HF[3]; + bool LOG_APRS, LOG_DEBUG, LOG_IRC, LOG_DTMF, LOG_QSO, IS_HF[3]; int DASH_REFRESH, TIMING_PLAY_WAIT, TIMING_PLAY_DELAY, TIMING_TIMEOUT_ECHO, TIMING_TIMEOUT_VOICEMAIL, TIMING_TIMEOUT_REMOTE_G2, TIMING_TIMEOUT_LOCAL_RPTR, dtmf_digit; @@ -178,6 +178,9 @@ private: int dtmf_last_frame[3]; unsigned int dtmf_counter[3]; + // helper + std::string convertToAprsCoordinate(double decimalDegrees, bool isLatitude); + bool VoicePacketIsSync(const uint8_t *text) const; int open_port(const SPORTIP *pip, int family); void calcPFCS(uint8_t *packet, int len); diff --git a/TCPReaderWriterClient.cpp b/TCPReaderWriterClient.cpp index ef27fe8..d50f2e4 100644 --- a/TCPReaderWriterClient.cpp +++ b/TCPReaderWriterClient.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX - * Copyright (C) 2019 by Thomas A. Early N7TAE + * Copyright (C) 2019,2026 by Thomas A. Early N7TAE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,25 +27,26 @@ CTCPReaderWriterClient::CTCPReaderWriterClient() : m_fd(-1) { } -bool CTCPReaderWriterClient::Open(const std::string &address, int family, const std::string &port) +bool CTCPReaderWriterClient::Open(const std::string &address, int family, const std::string &port, const bool debug) { + const char *where { "TCP Open ERROR:" }; m_address = address; m_port = port; if (m_fd != -1) { - fprintf(stderr, "ERROR: port for '%s' is already open!\n", m_address.c_str()); + fprintf(stderr, "%s port for '%s' is already open!\n", where, m_address.c_str()); return true; } if (0 == m_address.size() || 0 == m_port.size() || 0 == std::stoul(m_port)) { - fprintf(stderr, "ERROR: '[%s]:%s' is malformed!\n", m_address.c_str(), m_port.c_str()); + fprintf(stderr, "%s '[%s]:%s' is malformed!\n", where, m_address.c_str(), m_port.c_str()); return true; } - if (AF_INET!=family && AF_INET6!=family && AF_UNSPEC!=family) + if (AF_INET!=family and AF_INET6!=family and AF_UNSPEC!=family) { - fprintf(stderr, "ERROR: family must be AF_INET, AF_INET6 or AF_UNSPEC\n"); + fprintf(stderr, "%s family must be AF_INET, AF_INET6 or AF_UNSPEC\n", where); return true; } @@ -53,19 +54,18 @@ bool CTCPReaderWriterClient::Open(const std::string &address, int family, const memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; - //hints.ai_flags = AI_PASSIVE; hints.ai_protocol = IPPROTO_TCP; struct addrinfo *res; int s = EAI_AGAIN; int count = 0; - while (EAI_AGAIN==s and count++<20) + while (s and count++<20) { // connecting to a server, so we can wait until it's ready s = getaddrinfo(m_address.c_str(), m_port.c_str(), &hints, &res); if (s && s != EAI_AGAIN) { - fprintf(stderr, "ERROR: getaddrinfo of %s: %s\n", m_address.c_str(), gai_strerror(s)); + fprintf(stderr, "%s getaddrinfo of %s: %s\n", where, m_address.c_str(), gai_strerror(s)); return true; } std::this_thread::sleep_for(std::chrono::seconds(3)); @@ -73,7 +73,7 @@ bool CTCPReaderWriterClient::Open(const std::string &address, int family, const if (EAI_AGAIN == s) { - fprintf(stderr, "ERROR getaddrinfo of %s failed 20 times\n", m_address.c_str()); + fprintf(stderr, "%s getaddrinfo of %s failed 20 times\n", where, m_address.c_str()); return true; } @@ -82,10 +82,21 @@ bool CTCPReaderWriterClient::Open(const std::string &address, int family, const { m_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (m_fd == -1) + { + if (debug) fprintf(stderr, "%s socket() error - %s\n", where, strerror(errno)); continue; + } + int flag = 1; + if (setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag))) + { + if (debug) fprintf(stderr, "%s setsockopt(TCP_NODELAY) - %s\n", where, strerror(errno)); + Close(); + continue; + } if (connect(m_fd, rp->ai_addr, rp->ai_addrlen)) { + if (debug) fprintf(stderr, "%s connect() - %s\n", where, strerror(errno)); Close(); continue; } @@ -104,7 +115,7 @@ bool CTCPReaderWriterClient::Open(const std::string &address, int family, const addr = &(addr6->sin6_addr); } if (inet_ntop(rp->ai_family, addr, buf, INET6_ADDRSTRLEN)) - fprintf(stderr, "Successfully connected to %s at [%s]:%s\n", m_address.c_str(), buf, m_port.c_str()); + printf("Successfully connected to %s at [%s]:%s\n", m_address.c_str(), buf, m_port.c_str()); break; } } @@ -112,7 +123,7 @@ bool CTCPReaderWriterClient::Open(const std::string &address, int family, const if (rp == NULL) { - fprintf(stderr, "Could not connect to any system returned by %s\n", m_address.c_str()); + fprintf(stderr, "%s Could not connect to %s\n", where, m_address.c_str()); m_fd = -1; return true; } @@ -122,17 +133,15 @@ bool CTCPReaderWriterClient::Open(const std::string &address, int family, const int CTCPReaderWriterClient::ReadExact(uint8_t *buf, const unsigned int length) { - unsigned int offset = 0U; + unsigned int read = 0U; - do - { - int n = Read(buf + offset, length - offset); - if (n < 0) + do { + int n = Read(buf + read, length - read); + if (n < 1) return n; - offset += n; - } - while ((length - offset) > 0U); + read += n; + } while ((length - read) > 0U); return length; } @@ -147,68 +156,57 @@ int CTCPReaderWriterClient::Read(uint8_t* buffer, const unsigned int length) if (len <= 0) { if (len < 0) - fprintf(stderr, "Error returned from recv, err=%d\n", errno); + fprintf(stderr, "TCP Read() ERROR: %s\n", strerror(errno)); + else + fprintf(stderr, "TCP Read() ERROR: Port closed by server\n"); return -1; } return len; } -int CTCPReaderWriterClient::ReadLine(std::string& line) +bool CTCPReaderWriterClient::ReadLine(std::string& line) { uint8_t c; - int resultCode; - int len = 0; - line = ""; + int rtv; - do - { - resultCode = Read(&c, 1); - if(resultCode == 1) - { + do { + rtv = Read(&c, 1); + if (('\r' != c) and ('\n' != c) and (rtv == 1)) line += c; - len++; - } - } - while(c != '\n' && resultCode == 1); + } while(c != '\n' && rtv == 1); - return resultCode <= 0 ? resultCode : len; + return (rtv <= 0) ? true : false; } -int CTCPReaderWriterClient::Write(const uint8_t *buffer, const unsigned int length) +bool CTCPReaderWriterClient::Write(const void *pvoid, const unsigned int length) { - assert(buffer != NULL); + assert(pvoid != NULL); assert(length > 0U); assert(m_fd != -1); + unsigned int wrote = 0; + uint8_t *buffer = (uint8_t *)pvoid; - ssize_t ret = send(m_fd, (char *)buffer, length, 0); - if (ret != ssize_t(length)) - { - if (ret < 0) - fprintf(stderr, "Error returned from send, err=%s\n", strerror(errno)); - else - fprintf(stderr, "Error only wrote %d of %d bytes\n", int(ret), int(length)); - return -1; + while (wrote < length) { + ssize_t ret = send(m_fd, buffer+wrote, length-wrote, 0); + if (ret <= 0) + { + if (ret < 0) + fprintf(stderr, "ERROR - TCP Write send(): %s\n", strerror(errno)); + else + fprintf(stderr, "ERROR - TCP Write: port closed by server\n"); + return true; + } + wrote += ret; } - return ret; + return false; } -bool CTCPReaderWriterClient::WriteLine(const std::string& line) +bool CTCPReaderWriterClient::WriteLine(std::string& line) { - std::string lineCopy(line); - if(lineCopy.size() > 0 && lineCopy.at(lineCopy.size() - 1) != '\n') - lineCopy.append("\n"); - - size_t len = lineCopy.size(); - bool result = true; - for(size_t i = 0; i < len && result; i++) - { - uint8_t c = lineCopy.at(i); - result = Write(&c, 1); - } - - return result; + line.append("\r\n"); + return Write(line.c_str(), line.size()); } void CTCPReaderWriterClient::Close() diff --git a/TCPReaderWriterClient.h b/TCPReaderWriterClient.h index bd96cf8..915b092 100644 --- a/TCPReaderWriterClient.h +++ b/TCPReaderWriterClient.h @@ -3,7 +3,7 @@ /* end of inma once */ /* * Copyright (C) 2010,2011,2012,2013 by Jonathan Naylor G4KLX - * Copyright (C) 2019 by Thomas A. Early N7TAE + * Copyright (C) 2019,2026 by Thomas A. Early N7TAE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,12 +38,12 @@ class CTCPReaderWriterClient public: CTCPReaderWriterClient(); - bool Open(const std::string &address, int family, const std::string &port); + bool Open(const std::string &address, int family, const std::string &port, bool debug); int ReadExact(uint8_t *buffer, const unsigned int length); int Read(uint8_t *buffer, const unsigned int length); - int ReadLine(std::string &line); - int Write(const uint8_t* buffer, const unsigned int length); - bool WriteLine(const std::string &line); + bool ReadLine(std::string &line); + bool Write(const void* buffer, const unsigned int length); + bool WriteLine(std::string &line); int GetFD() { return m_fd; } void Close(); diff --git a/aprs.cpp b/aprs.cpp index bd469e9..f66bf3a 100644 --- a/aprs.cpp +++ b/aprs.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2020 by Thomas A. Early N7TAE + * Copyright (C) 2016-2020,2026 by Thomas A. Early N7TAE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,9 +26,17 @@ #include #include +#include #include "aprs.h" +CAPRS::CAPRS(SRPTR *prptr, bool debug) : m_rptr(prptr), m_debug(debug) {} + +CAPRS::~CAPRS() +{ + aprs_sock.Close(); +} + // This is called when header comes in from repeater void CAPRS::SelectBand(int16_t rptr_idx, uint16_t streamID) { @@ -120,16 +128,16 @@ void CAPRS::ProcessText(uint16_t streamID, uint8_t seq, uint8_t *buf) if (rc == -1) { if ((errno == EPIPE) || - (errno == ECONNRESET) || - (errno == ETIMEDOUT) || - (errno == ECONNABORTED) || - (errno == ESHUTDOWN) || - (errno == EHOSTUNREACH) || - (errno == ENETRESET) || - (errno == ENETDOWN) || - (errno == ENETUNREACH) || - (errno == EHOSTDOWN) || - (errno == ENOTCONN)) + (errno == ECONNRESET) || + (errno == ETIMEDOUT) || + (errno == ECONNABORTED) || + (errno == ESHUTDOWN) || + (errno == EHOSTUNREACH) || + (errno == ENETRESET) || + (errno == ENETDOWN) || + (errno == ENETUNREACH) || + (errno == EHOSTDOWN) || + (errno == ENOTCONN)) { printf("CAPRS::ProcessText(): APRS_HOST closed connection, error=%d\n",errno); aprs_sock.Close(); @@ -251,11 +259,9 @@ unsigned int CAPRS::GetData(int16_t rptr_idx, uint8_t *data, unsigned int len) return l; } -void CAPRS::Open(const std::string OWNER) +void CAPRS::Open(const std::string &OWNER, const std::string &NAME) { - char snd_buf[512]; - char rcv_buf[512]; - while (aprs_sock.Open(m_rptr->aprs.ip, AF_UNSPEC, std::to_string(m_rptr->aprs.port))) + while (aprs_sock.Open(m_rptr->aprs.ip, AF_UNSPEC, std::to_string(m_rptr->aprs.port), m_debug)) { fprintf(stderr, "Failed to open %s, retry in 10 seconds...\n", m_rptr->aprs.ip.c_str()); std::this_thread::sleep_for(std::chrono::seconds(10)); @@ -263,41 +269,32 @@ void CAPRS::Open(const std::string OWNER) /* login to aprs */ //sprintf(snd_buf, "user %s pass %d vers QnetGateway 9 UDP 5 ", OWNER.c_str(), m_rptr->aprs_hash); - sprintf(snd_buf, "user %s pass %d vers QnetGateway-9 ", OWNER.c_str(), m_rptr->aprs_hash); + std::stringstream ss; + ss << "user " << OWNER << " pass " << m_rptr->aprs_hash << " version " << NAME; /* add the user's filter */ if (m_rptr->aprs_filter.length()) { - strcat(snd_buf, "filter "); - strcat(snd_buf, m_rptr->aprs_filter.c_str()); + ss << " filter " << m_rptr->aprs_filter; } - //printf("APRS Login command:[%s]\n", snd_buf); - strcat(snd_buf, "\r\n"); + std::string str(ss.str()); + if (m_debug) + printf("APRS Login: %s\n", str.c_str()); - while (true) - { - int rc = aprs_sock.Write((uint8_t *)snd_buf, strlen(snd_buf)); - if (rc < 0) - { - if (errno == EWOULDBLOCK) - { - aprs_sock.Read((uint8_t *)rcv_buf, sizeof(rcv_buf)); - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - else - { - printf("APRS Login command failed, error=%d\n", errno); - break; - } - } - else - { - // printf("APRS Login command sent\n"); - break; - } + if (aprs_sock.WriteLine(str)) { + fprintf(stderr, "Could write login into aprs\n"); + aprs_sock.Close(); + return; + } + + if (aprs_sock.ReadLine(str)) { + fprintf(stderr, "Did not receive aprs login ackn\n"); + aprs_sock.Close(); + return; } - aprs_sock.Read((uint8_t *)rcv_buf, sizeof(rcv_buf)); - //printf("APRS Login returned: %s", rcv_buf); + + if (m_debug) + printf("APRS Login returned: %s\n", str.c_str()); return; } @@ -457,18 +454,3 @@ unsigned int CAPRS::CalcCRC(uint8_t* buf, unsigned int len) } return (~my_crc & 0xffff); } - -CAPRS::CAPRS(SRPTR *prptr) -{ - m_rptr = prptr; -} - -CAPRS::~CAPRS() -{ - aprs_sock.Close(); -} - -void CAPRS::CloseSock() -{ - aprs_sock.Close(); -} diff --git a/aprs.h b/aprs.h index 8ee6a88..a2b4efd 100644 --- a/aprs.h +++ b/aprs.h @@ -1,7 +1,6 @@ #pragma once -/* - * Copyright (C) 2016 by Thomas A. Early N7TAE +/* Copyright (C) 2016,2026 by Thomas A. Early N7TAE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +18,7 @@ */ #include +#include #include #include #include @@ -43,6 +43,7 @@ using SMOD = struct aprs_module std::string band; /* 23cm ... */ double frequency, offset, latitude, longitude, range, agl; std::string desc1, desc2, url, package_version; + std::stringstream position_ss; }; using SRPTR = struct aprs_info @@ -59,15 +60,16 @@ using SRPTR = struct aprs_info class CAPRS { public: + // data + const bool m_debug; // functions - CAPRS(SRPTR *prptr); + CAPRS(SRPTR *prptr, bool debug); ~CAPRS(); SRPTR *m_rptr; void SelectBand(int16_t rptr_idx, uint16_t streamID); void ProcessText(uint16_t streamID, uint8_t seq, uint8_t *buf); - void Open(const std::string OWNER); + void Open(const std::string &OWNER, const std::string &NAME); void Init(); - void CloseSock(); CTCPReaderWriterClient aprs_sock; private: diff --git a/defaults b/defaults index 54b41b3..bbcbe0a 100644 --- a/defaults +++ b/defaults @@ -174,6 +174,7 @@ log_qso_d=false # QSO info goes into the log log_irc_d=false # IRC debug info log_dtmf_d=false # DTMF debug info log_debug_d=false # WARNING, can produce a large number of log entries! +log_aprs_d=false # APRS debug info ########################################################################################################################## # diff --git a/ircddb/IRCClient.cpp b/ircddb/IRCClient.cpp index f35ebf4..7fd4bd9 100644 --- a/ircddb/IRCClient.cpp +++ b/ircddb/IRCClient.cpp @@ -8,8 +8,9 @@ #include "IRCutils.h" #include "IRCDDBApp.h" -IRCClient::IRCClient(IRCDDBApp *app, const std::string &update_channel, const std::string &hostName, unsigned int port, const std::string &callsign, const std::string &password, const std::string &versionInfo) +IRCClient::IRCClient(IRCDDBApp *app, const std::string &update_channel, const std::string &hostName, unsigned int port, const std::string &callsign, const std::string &password, const std::string &versionInfo, bool logirc) { + logIRC = logirc; safeStringCopy(host_name, hostName.c_str(), sizeof host_name); @@ -79,7 +80,7 @@ void IRCClient::Entry() else if (0 == strcmp(host_name, "ircv6.openquad.net")) fam = AF_INET6; - if (! ircSock.Open(host_name, fam, std::to_string(port))) + if (! ircSock.Open(host_name, fam, std::to_string(port), logIRC)) { state = 4; timer = 0; diff --git a/ircddb/IRCClient.h b/ircddb/IRCClient.h index 0490ec1..b8a47e8 100644 --- a/ircddb/IRCClient.h +++ b/ircddb/IRCClient.h @@ -14,7 +14,7 @@ class IRCDDBApp; class IRCClient { public: - IRCClient(IRCDDBApp *app, const std::string &update_channel, const std::string &hostName, unsigned int port, const std::string &callsign, const std::string &password, const std::string &versionInfo); + IRCClient(IRCDDBApp *app, const std::string &update_channel, const std::string &hostName, unsigned int port, const std::string &callsign, const std::string &password, const std::string &versionInfo, bool logirc); virtual ~IRCClient(); bool startWork(); @@ -34,6 +34,7 @@ private: std::string password; bool terminateThread; + bool logIRC; IRCReceiver receiver; IRCMessageQueue *recvQ; diff --git a/ircddb/IRCDDB.cpp b/ircddb/IRCDDB.cpp index 8afe471..873a1aa 100644 --- a/ircddb/IRCDDB.cpp +++ b/ircddb/IRCDDB.cpp @@ -10,7 +10,7 @@ CIRCDDB::CIRCDDB(const std::string &hostName, unsigned int port, const std::stri const std::string update_channel("#dstar"); app = new IRCDDBApp(update_channel, &cache, log_irc); - client = new IRCClient(app, update_channel, hostName, port, callsign, password, versionInfo); + client = new IRCClient(app, update_channel, hostName, port, callsign, password, versionInfo, log_irc); } CIRCDDB::~CIRCDDB() diff --git a/qnconfig b/qnconfig index 8b3f3e8..03b4ee8 100755 --- a/qnconfig +++ b/qnconfig @@ -178,6 +178,7 @@ FileMenu () { fi echo echo " Additional entries in log files (in /usr/local/var)" + echo -n "al : APRS logging = "; EvaluateVar log_aprs{,d} echo -n "cl : Call(QSO) logging = "; EvaluateVar log_qso{,_d} echo -n "il : IRC logging = "; EvaluateVar log_irc{,_d} echo -n "dl : DTMF logging = "; EvaluateVar log_dtmf{,_d} @@ -209,6 +210,7 @@ FileMenu () { elif [[ "$key" == vf* ]]; then file_qnvoicefile="$value" elif [[ "$key" == gf* ]]; then file_gwys="$value" elif [[ "$key" == ad* ]]; then file_announce_dir="$value" + elif [[ "$key" == al* ]]; then SetBooleanValue log_aprs "$value" elif [[ "$key" == cl* ]]; then SetBooleanValue log_qso "$value" elif [[ "$key" == il* ]]; then SetBooleanValue log_irc "$value" elif [[ "$key" == dl* ]]; then SetBooleanValue log_dtmf "$value" @@ -690,6 +692,7 @@ WriteCFGFile () { [ -z "${link_acknowledge+x}" ] || echo "link_acknowledge=${link_acknowledge}" >> $outFile [ -z "${link_max_dongles+x}" ] || echo "link_max_dongles=${link_max_dongles}" >> $outFile # log_ section + [ -z "${log_aprs+x}" ] || echo "log_aprs=${log_aprs}" >> $outFile [ -z "${log_qso+x}" ] || echo "log_qso=${log_qso}" >> $outFile [ -z "${log_irc+x}" ] || echo "log_irc=${log_irc}" >> $outFile [ -z "${log_dtmf+x}" ] || echo "log_dtmf=${log_dtmf}" >> $outFile