From b058539a71123285132fae2b2be14e22e29a86f9 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 3 Mar 2020 15:03:07 +0000 Subject: [PATCH] Add a reconnection backoff timer for APRS reporting. --- YSFGateway/APRSWriter.cpp | 14 +++++----- YSFGateway/APRSWriterThread.cpp | 45 ++++++++++++++++++++++++++++----- YSFGateway/APRSWriterThread.h | 8 +++++- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/YSFGateway/APRSWriter.cpp b/YSFGateway/APRSWriter.cpp index ae64aef..e74a39e 100644 --- a/YSFGateway/APRSWriter.cpp +++ b/YSFGateway/APRSWriter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014,2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2010-2014,2016,2017,2018,2020 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 @@ -168,6 +168,8 @@ void CAPRSWriter::clock(unsigned int ms) { m_idTimer.clock(ms); + m_thread->clock(ms); + if (m_socket != NULL) { if (m_idTimer.hasExpired()) { pollGPS(); @@ -289,9 +291,9 @@ void CAPRSWriter::sendIdFrameMobile() if (pLatitude == NULL || pLongitude == NULL || pAltitude == NULL) return; - float rawLatitude = ::atof(pLatitude); - float rawLongitude = ::atof(pLongitude); - float rawAltitude = ::atof(pAltitude); + float rawLatitude = float(::atof(pLatitude)); + float rawLongitude = float(::atof(pLongitude)); + float rawAltitude = float(::atof(pAltitude)); char desc[200U]; if (m_txFrequency != 0U) { @@ -345,8 +347,8 @@ void CAPRSWriter::sendIdFrameMobile() lon, (rawLongitude < 0.0F) ? 'W' : 'E'); if (pBearing != NULL && pVelocity != NULL) { - float rawBearing = ::atof(pBearing); - float rawVelocity = ::atof(pVelocity); + float rawBearing = float(::atof(pBearing)); + float rawVelocity = float(::atof(pVelocity)); ::sprintf(output + ::strlen(output), "%03.0f/%03.0f", rawBearing, rawVelocity * 0.539957F); } diff --git a/YSFGateway/APRSWriterThread.cpp b/YSFGateway/APRSWriterThread.cpp index 93e2e48..c388609 100644 --- a/YSFGateway/APRSWriterThread.cpp +++ b/YSFGateway/APRSWriterThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2010-2014,2016,2020 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 @@ -41,6 +41,8 @@ m_socket(address, port), m_queue(20U, "APRS Queue"), m_exit(false), m_connected(false), +m_reconnectTimer(1000U), +m_tries(1U), m_APRSReadCallback(NULL), m_filter(), m_clientName("YSFGateway") @@ -63,6 +65,8 @@ m_socket(address, port), m_queue(20U, "APRS Queue"), m_exit(false), m_connected(false), +m_reconnectTimer(1000U), +m_tries(1U), m_APRSReadCallback(NULL), m_filter(filter), m_clientName(clientName) @@ -94,19 +98,28 @@ void CAPRSWriterThread::entry() LogMessage("Starting the APRS Writer thread"); m_connected = connect(); + if (!m_connected) { + LogError("Connect attempt to the APRS server has failed"); + startReconnectionTimer(); + } try { while (!m_exit) { if (!m_connected) { - m_connected = connect(); + if (m_reconnectTimer.isRunning() && m_reconnectTimer.hasExpired()) { + m_reconnectTimer.stop(); - if (!m_connected){ - LogError("Reconnect attempt to the APRS server has failed"); - sleep(10000UL); // 10 secs + m_connected = connect(); + if (!m_connected) { + LogError("Reconnect attempt to the APRS server has failed"); + startReconnectionTimer(); + } } } if (m_connected) { + m_tries = 0U; + if (!m_queue.isEmpty()){ char* p = NULL; m_queue.getData(&p, 1U); @@ -115,11 +128,12 @@ void CAPRSWriterThread::entry() ::strcat(p, "\r\n"); - bool ret = m_socket.write((unsigned char*)p, ::strlen(p)); + bool ret = m_socket.write((unsigned char*)p, (unsigned int)::strlen(p)); if (!ret) { m_connected = false; m_socket.close(); LogError("Connection to the APRS thread has failed"); + startReconnectionTimer(); } delete[] p; @@ -132,6 +146,7 @@ void CAPRSWriterThread::entry() m_connected = false; m_socket.close(); LogError("Error when reading from the APRS server"); + startReconnectionTimer(); } if(length > 0 && line.at(0U) != '#'//check if we have something and if that something is an APRS frame @@ -176,7 +191,7 @@ void CAPRSWriterThread::write(const char* data) if (!m_connected) return; - unsigned int len = ::strlen(data); + unsigned int len = (unsigned int)::strlen(data); char* p = new char[len + 5U]; ::strcpy(p, data); @@ -196,6 +211,11 @@ void CAPRSWriterThread::stop() wait(); } +void CAPRSWriterThread::clock(unsigned int ms) +{ + m_reconnectTimer.clock(ms); +} + bool CAPRSWriterThread::connect() { bool ret = m_socket.open(); @@ -246,3 +266,14 @@ bool CAPRSWriterThread::connect() return true; } + +void CAPRSWriterThread::startReconnectionTimer() +{ + // Clamp at a ten minutes reconnect time + m_tries++; + if (m_tries > 10U) + m_tries = 10U; + + m_reconnectTimer.setTimeout(m_tries * 60U); + m_reconnectTimer.start(); +} diff --git a/YSFGateway/APRSWriterThread.h b/YSFGateway/APRSWriterThread.h index 42bfd67..c86c23a 100644 --- a/YSFGateway/APRSWriterThread.h +++ b/YSFGateway/APRSWriterThread.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010,2011,2012,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2010,2011,2012,2016,2020 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,6 +21,7 @@ #include "TCPSocket.h" #include "RingBuffer.h" +#include "Timer.h" #include "Thread.h" #include @@ -45,6 +46,8 @@ public: void setReadAPRSCallback(ReadAPRSFrameCallback cb); + void clock(unsigned int ms); + private: std::string m_username; std::string m_password; @@ -52,11 +55,14 @@ private: CRingBuffer m_queue; bool m_exit; bool m_connected; + CTimer m_reconnectTimer; + unsigned int m_tries; ReadAPRSFrameCallback m_APRSReadCallback; std::string m_filter; std::string m_clientName; bool connect(); + void startReconnectionTimer(); }; #endif