From 16ef9dcda742b2059e9934f272a9fa5f77c82f24 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 4 Oct 2016 17:32:13 +0100 Subject: [PATCH] Add the logging framework to the Parrot. --- YSFParrot/Log.cpp | 136 ++++++++++++++++++++++++++++ YSFParrot/Log.h | 36 ++++++++ YSFParrot/Makefile | 2 +- YSFParrot/Makefile.Solaris | 2 +- YSFParrot/Network.cpp | 15 ++- YSFParrot/Network.h | 4 +- YSFParrot/Parrot.cpp | 1 - YSFParrot/UDPSocket.cpp | 37 ++++---- YSFParrot/Utils.cpp | 5 +- YSFParrot/YSFDefines.h | 49 ---------- YSFParrot/YSFParrot.cpp | 39 +++++--- YSFParrot/YSFParrot.h | 3 +- YSFParrot/YSFParrot.vcxproj | 3 +- YSFParrot/YSFParrot.vcxproj.filters | 9 +- 14 files changed, 242 insertions(+), 99 deletions(-) create mode 100644 YSFParrot/Log.cpp create mode 100644 YSFParrot/Log.h delete mode 100644 YSFParrot/YSFDefines.h diff --git a/YSFParrot/Log.cpp b/YSFParrot/Log.cpp new file mode 100644 index 0000000..e289fe3 --- /dev/null +++ b/YSFParrot/Log.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Log.h" + +#if defined(_WIN32) || defined(_WIN64) +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include + +static unsigned int m_fileLevel = 2U; +static std::string m_filePath; +static std::string m_fileRoot; + +static FILE* m_fpLog = NULL; + +static unsigned int m_displayLevel = 2U; + +static struct tm m_tm; + +static char LEVELS[] = " DMIWEF"; + +static bool LogOpen() +{ + if (m_fileLevel == 0U) + return true; + + time_t now; + ::time(&now); + + 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) + return true; + } else { + if (m_fpLog != NULL) + ::fclose(m_fpLog); + } + + char filename[50U]; +#if defined(_WIN32) || defined(_WIN64) + ::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); +#else + ::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 + + m_fpLog = ::fopen(filename, "a+t"); + m_tm = *tm; + + return m_fpLog != NULL; +} + +bool LogInitialise(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel) +{ + m_filePath = filePath; + m_fileRoot = fileRoot; + m_fileLevel = fileLevel; + m_displayLevel = displayLevel; + return ::LogOpen(); +} + +void LogFinalise() +{ + if (m_fpLog != NULL) + ::fclose(m_fpLog); +} + +void Log(unsigned int level, const char* fmt, ...) +{ + assert(fmt != NULL); + + char buffer[300U]; +#if defined(_WIN32) || defined(_WIN64) + SYSTEMTIME st; + ::GetSystemTime(&st); + + ::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); + + struct tm* tm = ::gmtime(&now.tv_sec); + + ::sprintf(buffer, "%c: %04d-%02d-%02d %02d:%02d:%02d.%03lu ", LEVELS[level], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000U); +#endif + + va_list vl; + va_start(vl, fmt); + + ::vsprintf(buffer + ::strlen(buffer), fmt, vl); + + va_end(vl); + + if (level >= m_fileLevel && m_fileLevel != 0U) { + bool ret = ::LogOpen(); + if (!ret) + return; + + ::fprintf(m_fpLog, "%s\n", buffer); + ::fflush(m_fpLog); + } + + if (level >= m_displayLevel && m_displayLevel != 0U) { + ::fprintf(stdout, "%s\n", buffer); + ::fflush(stdout); + } + + if (level == 6U) { // Fatal + ::fclose(m_fpLog); + exit(1); + } +} diff --git a/YSFParrot/Log.h b/YSFParrot/Log.h new file mode 100644 index 0000000..d671ef9 --- /dev/null +++ b/YSFParrot/Log.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if !defined(LOG_H) +#define LOG_H + +#include + +#define LogDebug(fmt, ...) Log(1U, fmt, ##__VA_ARGS__) +#define LogMessage(fmt, ...) Log(2U, fmt, ##__VA_ARGS__) +#define LogInfo(fmt, ...) Log(3U, fmt, ##__VA_ARGS__) +#define LogWarning(fmt, ...) Log(4U, fmt, ##__VA_ARGS__) +#define LogError(fmt, ...) Log(5U, fmt, ##__VA_ARGS__) +#define LogFatal(fmt, ...) Log(6U, fmt, ##__VA_ARGS__) + +extern void Log(unsigned int level, const char* fmt, ...); + +extern bool LogInitialise(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel); +extern void LogFinalise(); + +#endif diff --git a/YSFParrot/Makefile b/YSFParrot/Makefile index d098a5a..d27c4cd 100644 --- a/YSFParrot/Makefile +++ b/YSFParrot/Makefile @@ -4,7 +4,7 @@ CFLAGS = -g -O3 -Wall -std=c++0x LIBS = LDFLAGS = -g -OBJECTS = Network.o Parrot.o StopWatch.o Timer.o UDPSocket.o Utils.o YSFParrot.o +OBJECTS = Log.o Network.o Parrot.o StopWatch.o Timer.o UDPSocket.o Utils.o YSFParrot.o all: YSFParrot diff --git a/YSFParrot/Makefile.Solaris b/YSFParrot/Makefile.Solaris index 1a8b431..8cad679 100644 --- a/YSFParrot/Makefile.Solaris +++ b/YSFParrot/Makefile.Solaris @@ -4,7 +4,7 @@ CFLAGS = -g -O3 -Wall -std=c++0x LIBS = -lsocket LDFLAGS = -g -OBJECTS = Network.o Parrot.o StopWatch.o Timer.o UDPSocket.o Utils.o YSFParrot.o +OBJECTS = Log.o Network.o Parrot.o StopWatch.o Timer.o UDPSocket.o Utils.o YSFParrot.o all: YSFParrot diff --git a/YSFParrot/Network.cpp b/YSFParrot/Network.cpp index 3f5c785..13958e4 100644 --- a/YSFParrot/Network.cpp +++ b/YSFParrot/Network.cpp @@ -16,9 +16,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "YSFDefines.h" #include "Network.h" #include "Utils.h" +#include "Log.h" #include #include @@ -26,11 +26,10 @@ const unsigned int BUFFER_LENGTH = 200U; -CNetwork::CNetwork(unsigned int port, bool debug) : +CNetwork::CNetwork(unsigned int port) : m_socket(port), m_address(), m_port(0U), -m_debug(debug), m_buffer(1000U, "YSF Network") { } @@ -41,7 +40,7 @@ CNetwork::~CNetwork() bool CNetwork::open() { - ::fprintf(stdout, "Opening YSF network connection\n"); + LogInfo("Opening YSF network connection"); return m_socket.open(); } @@ -53,8 +52,7 @@ bool CNetwork::write(const unsigned char* data) assert(data != NULL); - if (m_debug) - CUtils::dump(1U, "YSF Network Data Sent", data, 155U); + CUtils::dump(1U, "YSF Network Data Sent", data, 155U); return m_socket.write(data, 155U, m_address, m_port); } @@ -113,8 +111,7 @@ void CNetwork::clock(unsigned int ms) m_address.s_addr = address.s_addr; m_port = port; - if (m_debug) - CUtils::dump(1U, "YSF Network Data Received", buffer, length); + CUtils::dump(1U, "YSF Network Data Received", buffer, length); m_buffer.addData(buffer, 155U); } @@ -140,5 +137,5 @@ void CNetwork::close() { m_socket.close(); - ::fprintf(stdout, "Closing YSF network connection\n"); + LogInfo("Closing YSF network connection"); } diff --git a/YSFParrot/Network.h b/YSFParrot/Network.h index 16501ea..a285f5f 100644 --- a/YSFParrot/Network.h +++ b/YSFParrot/Network.h @@ -19,7 +19,6 @@ #ifndef Network_H #define Network_H -#include "YSFDefines.h" #include "RingBuffer.h" #include "UDPSocket.h" @@ -28,7 +27,7 @@ class CNetwork { public: - CNetwork(unsigned int port, bool debug); + CNetwork(unsigned int port); ~CNetwork(); bool open(); @@ -47,7 +46,6 @@ private: CUDPSocket m_socket; in_addr m_address; unsigned int m_port; - bool m_debug; CRingBuffer m_buffer; bool writePoll(const in_addr& address, unsigned int port); diff --git a/YSFParrot/Parrot.cpp b/YSFParrot/Parrot.cpp index 865eb36..5c7b534 100644 --- a/YSFParrot/Parrot.cpp +++ b/YSFParrot/Parrot.cpp @@ -17,7 +17,6 @@ */ #include "Parrot.h" -#include "YSFDefines.h" #include #include diff --git a/YSFParrot/UDPSocket.cpp b/YSFParrot/UDPSocket.cpp index 733edd0..733dd20 100644 --- a/YSFParrot/UDPSocket.cpp +++ b/YSFParrot/UDPSocket.cpp @@ -17,6 +17,7 @@ */ #include "UDPSocket.h" +#include "Log.h" #include @@ -37,7 +38,7 @@ m_fd(-1) WSAData data; int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); if (wsaRet != 0) - ::fprintf(stderr, "Error from WSAStartup\n"); + LogError("Error from WSAStartup"); #endif } @@ -50,7 +51,7 @@ m_fd(-1) WSAData data; int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); if (wsaRet != 0) - ::fprintf(stderr, "Error from WSAStartup\n"); + LogError("Error from WSAStartup"); #endif } @@ -77,7 +78,7 @@ in_addr CUDPSocket::lookup(const std::string& hostname) return addr; } - ::fprintf(stderr, "Cannot find address for host %s\n", hostname.c_str()); + LogError("Cannot find address for host %s", hostname.c_str()); addr.s_addr = INADDR_NONE; return addr; @@ -94,7 +95,7 @@ in_addr CUDPSocket::lookup(const std::string& hostname) return addr; } - ::fprintf(stderr, "Cannot find address for host %s\n", hostname.c_str()); + LogError("Cannot find address for host %s", hostname.c_str()); addr.s_addr = INADDR_NONE; return addr; @@ -106,9 +107,9 @@ bool CUDPSocket::open() m_fd = ::socket(PF_INET, SOCK_DGRAM, 0); if (m_fd < 0) { #if defined(_WIN32) || defined(_WIN64) - ::fprintf(stderr, "Cannot create the UDP socket, err: %lu\n", ::GetLastError()); + LogError("Cannot create the UDP socket, err: %lu", ::GetLastError()); #else - ::fprintf(stderr, "Cannot create the UDP socket, err: %d\n", errno); + LogError("Cannot create the UDP socket, err: %d", errno); #endif return false; } @@ -127,7 +128,7 @@ bool CUDPSocket::open() addr.sin_addr.s_addr = ::inet_addr(m_address.c_str()); #endif if (addr.sin_addr.s_addr == INADDR_NONE) { - ::fprintf(stderr, "The local address is invalid - %s\n", m_address.c_str()); + LogError("The local address is invalid - %s", m_address.c_str()); return false; } } @@ -135,21 +136,23 @@ bool CUDPSocket::open() int reuse = 1; if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) { #if defined(_WIN32) || defined(_WIN64) - ::fprintf(stderr, "Cannot set the UDP socket option, err: %lu\n", ::GetLastError()); + LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError()); #else - ::fprintf(stderr, "Cannot set the UDP socket option, err: %d\n", errno); + LogError("Cannot set the UDP socket option, err: %d", errno); #endif return false; } if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { #if defined(_WIN32) || defined(_WIN64) - ::fprintf(stderr, "Cannot bind the UDP address, err: %lu\n", ::GetLastError()); + LogError("Cannot bind the UDP address, err: %lu", ::GetLastError()); #else - ::fprintf(stderr, "Cannot bind the UDP address, err: %d\n", errno); + LogError("Cannot bind the UDP address, err: %d", errno); #endif return false; } + + LogInfo("Opening UDP port on %u", m_port); } return true; @@ -177,9 +180,9 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& addres int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv); if (ret < 0) { #if defined(_WIN32) || defined(_WIN64) - ::fprintf(stderr, "Error returned from UDP select, err: %lu\n", ::GetLastError()); + LogError("Error returned from UDP select, err: %lu", ::GetLastError()); #else - ::fprintf(stderr, "Error returned from UDP select, err: %d\n", errno); + LogError("Error returned from UDP select, err: %d", errno); #endif return -1; } @@ -201,9 +204,9 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& addres #endif if (len <= 0) { #if defined(_WIN32) || defined(_WIN64) - ::fprintf(stderr, "Error returned from recvfrom, err: %lu\n", ::GetLastError()); + LogError("Error returned from recvfrom, err: %lu", ::GetLastError()); #else - ::fprintf(stderr, "Error returned from recvfrom, err: %d\n", errno); + LogError("Error returned from recvfrom, err: %d", errno); #endif return -1; } @@ -233,9 +236,9 @@ bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const i #endif if (ret < 0) { #if defined(_WIN32) || defined(_WIN64) - ::fprintf(stderr, "Error returned from sendto, err: %lu\n", ::GetLastError()); + LogError("Error returned from sendto, err: %lu", ::GetLastError()); #else - ::fprintf(stderr, "Error returned from sendto, err: %d\n", errno); + LogError("Error returned from sendto, err: %d", errno); #endif return false; } diff --git a/YSFParrot/Utils.cpp b/YSFParrot/Utils.cpp index d5b2c75..49ded13 100644 --- a/YSFParrot/Utils.cpp +++ b/YSFParrot/Utils.cpp @@ -12,6 +12,7 @@ */ #include "Utils.h" +#include "Log.h" #include #include @@ -27,7 +28,7 @@ void CUtils::dump(int level, const std::string& title, const unsigned char* data { assert(data != NULL); - ::fprintf(stdout, "%s\n", title.c_str()); + ::Log(level, "%s", title.c_str()); unsigned int offset = 0U; @@ -58,7 +59,7 @@ void CUtils::dump(int level, const std::string& title, const unsigned char* data output += '*'; - ::fprintf(stdout, "%04X: %s\n", offset, output.c_str()); + ::Log(level, "%04X: %s", offset, output.c_str()); offset += 16U; diff --git a/YSFParrot/YSFDefines.h b/YSFParrot/YSFDefines.h deleted file mode 100644 index 348d1bc..0000000 --- a/YSFParrot/YSFDefines.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if !defined(YSFDefines_H) -#define YSFDefines_H - -const unsigned int YSF_FRAME_LENGTH_BYTES = 120U; - -const unsigned char YSF_SYNC_BYTES[] = {0xD4U, 0x71U, 0xC9U, 0x63U, 0x4DU}; -const unsigned int YSF_SYNC_LENGTH_BYTES = 5U; - -const unsigned int YSF_FICH_LENGTH_BYTES = 25U; - -const unsigned char YSF_SYNC_OK = 0x01U; - -const unsigned int YSF_CALLSIGN_LENGTH = 10U; - -const unsigned char YSF_FI_HEADER = 0x00U; -const unsigned char YSF_FI_COMMUNICATIONS = 0x01U; -const unsigned char YSF_FI_TERMINATOR = 0x02U; -const unsigned char YSF_FI_TEST = 0x03U; - -const unsigned char YSF_DT_VD_MODE1 = 0x00U; -const unsigned char YSF_DT_DATA_FR_MODE = 0x01U; -const unsigned char YSF_DT_VD_MODE2 = 0x02U; -const unsigned char YSF_DT_VOICE_FR_MODE = 0x03U; - -const unsigned char YSF_CM_GROUP = 0x00U; -const unsigned char YSF_CM_INDIVIDUAL = 0x03U; - -const unsigned char YSF_MR_NOT_BUSY = 0x01U; -const unsigned char YSF_MR_BUSY = 0x02U; - -#endif diff --git a/YSFParrot/YSFParrot.cpp b/YSFParrot/YSFParrot.cpp index 08420d3..198be7f 100644 --- a/YSFParrot/YSFParrot.cpp +++ b/YSFParrot/YSFParrot.cpp @@ -22,31 +22,42 @@ #include "Network.h" #include "Version.h" #include "Timer.h" +#include "Log.h" #include #include +#include int main(int argc, char** argv) { if (argc == 1) { - ::fprintf(stderr, "Usage: YSFParrot \n"); + ::fprintf(stderr, "Usage: YSFParrot [-d] \n"); return 1; } - unsigned int port = ::atoi(argv[1]); + unsigned int n = 1U; + + bool debug = false; + if (::strcmp(argv[1], "-d") == 0) { + debug = true; + n = 2U; + } + + unsigned int port = ::atoi(argv[n]); if (port == 0U) { - ::fprintf(stderr, "YSFParrot: invalid port number\n"); + ::fprintf(stderr, "YSFParrot: invalid port number - %s\n", argv[n]); return 1; } - CYSFParrot parrot(port); + CYSFParrot parrot(port, debug); parrot.run(); return 0; } -CYSFParrot::CYSFParrot(unsigned int port) : -m_port(port) +CYSFParrot::CYSFParrot(unsigned int port, bool debug) : +m_port(port), +m_debug(debug) { } @@ -56,12 +67,16 @@ CYSFParrot::~CYSFParrot() void CYSFParrot::run() { + ::LogInitialise(".", "YSFParrot", m_debug ? 1U : 2U, m_debug ? 1U : 2U); + CParrot parrot(180U); - CNetwork network(m_port, false); + CNetwork network(m_port); bool ret = network.open(); - if (!ret) + if (!ret) { + ::LogFinalise(); return; + } CStopWatch stopWatch; stopWatch.start(); @@ -73,7 +88,7 @@ void CYSFParrot::run() unsigned int count = 0U; bool playing = false; - ::fprintf(stdout, "Starting YSFParrot-%s\n", VERSION); + LogInfo("Starting YSFParrot-%s", VERSION); for (;;) { unsigned char buffer[200U]; @@ -84,7 +99,7 @@ void CYSFParrot::run() watchdogTimer.start(); if ((buffer[34U] & 0x01U) == 0x01U) { - ::fprintf(stdout, "Received end of transmission\n"); + LogDebug("Received end of transmission"); turnaroundTimer.start(); watchdogTimer.stop(); parrot.end(); @@ -123,7 +138,7 @@ void CYSFParrot::run() turnaroundTimer.clock(ms); if (watchdogTimer.isRunning() && watchdogTimer.hasExpired()) { - ::fprintf(stdout, "Network watchdog has expired\n"); + LogDebug("Network watchdog has expired"); turnaroundTimer.start(); watchdogTimer.stop(); parrot.end(); @@ -139,4 +154,6 @@ void CYSFParrot::run() } network.close(); + + ::LogFinalise(); } diff --git a/YSFParrot/YSFParrot.h b/YSFParrot/YSFParrot.h index 5248c85..eb11476 100644 --- a/YSFParrot/YSFParrot.h +++ b/YSFParrot/YSFParrot.h @@ -22,13 +22,14 @@ class CYSFParrot { public: - CYSFParrot(unsigned int port); + CYSFParrot(unsigned int port, bool debug); ~CYSFParrot(); void run(); private: unsigned int m_port; + bool m_debug; }; #endif diff --git a/YSFParrot/YSFParrot.vcxproj b/YSFParrot/YSFParrot.vcxproj index 590ddcf..cf30687 100644 --- a/YSFParrot/YSFParrot.vcxproj +++ b/YSFParrot/YSFParrot.vcxproj @@ -146,6 +146,7 @@ + @@ -153,11 +154,11 @@ - + diff --git a/YSFParrot/YSFParrot.vcxproj.filters b/YSFParrot/YSFParrot.vcxproj.filters index 80097de..14606c8 100644 --- a/YSFParrot/YSFParrot.vcxproj.filters +++ b/YSFParrot/YSFParrot.vcxproj.filters @@ -17,9 +17,6 @@ Header Files - - Header Files - Header Files @@ -41,6 +38,9 @@ Header Files + + Header Files + @@ -64,5 +64,8 @@ Source Files + + Source Files + \ No newline at end of file