From 4ff688045fc7d0b5b6dd67eacc3a71d582af6163 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 17 Mar 2025 14:09:42 +0000 Subject: [PATCH] Update the C++ version and other changes. --- Conf.cpp | 78 +++++++++++++++++++++++----------------------- DMRGateway.cpp | 13 +++++--- DMRNetwork.cpp | 6 ++-- MMDVMNetwork.cpp | 2 +- MQTTConnection.cpp | 67 +++++++++++++++++++++------------------ MQTTConnection.h | 12 +++---- RemoteControl.cpp | 49 +++++++++++++++-------------- 7 files changed, 119 insertions(+), 108 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index e575dfd..59b21d6 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -26,23 +26,23 @@ const int BUFFER_SIZE = 500; -enum SECTION { - SECTION_NONE, - SECTION_GENERAL, - SECTION_LOG, - SECTION_VOICE, - SECTION_INFO, - SECTION_DMR_NETWORK_1, - SECTION_DMR_NETWORK_2, - SECTION_DMR_NETWORK_3, - SECTION_DMR_NETWORK_4, - SECTION_DMR_NETWORK_5, - SECTION_XLX_NETWORK, - SECTION_GPSD, - SECTION_APRS, - SECTION_MQTT, - SECTION_DYNAMIC_TG_CONTROL, - SECTION_REMOTE_COMMANDS +enum class SECTION { + NONE, + GENERAL, + LOG, + VOICE, + INFO, + DMR_NETWORK_1, + DMR_NETWORK_2, + DMR_NETWORK_3, + DMR_NETWORK_4, + DMR_NETWORK_5, + XLX_NETWORK, + GPSD, + APRS, + MQTT, + DYNAMIC_TG_CONTROL, + REMOTE_COMMANDS }; CConf::CConf(const std::string& file) : @@ -209,37 +209,37 @@ bool CConf::read() if (buffer[0U] == '[') { if (::strncmp(buffer, "[General]", 9U) == 0) - section = SECTION_GENERAL; + section = SECTION::GENERAL; else if (::strncmp(buffer, "[Log]", 5U) == 0) - section = SECTION_LOG; + section = SECTION::LOG; else if (::strncmp(buffer, "[Voice]", 7U) == 0) - section = SECTION_VOICE; + section = SECTION::VOICE; else if (::strncmp(buffer, "[Info]", 6U) == 0) - section = SECTION_INFO; + section = SECTION::INFO; else if (::strncmp(buffer, "[XLX Network]", 13U) == 0) - section = SECTION_XLX_NETWORK; + section = SECTION::XLX_NETWORK; else if (::strncmp(buffer, "[DMR Network 1]", 15U) == 0) - section = SECTION_DMR_NETWORK_1; + section = SECTION::DMR_NETWORK_1; else if (::strncmp(buffer, "[DMR Network 2]", 15U) == 0) - section = SECTION_DMR_NETWORK_2; + section = SECTION::DMR_NETWORK_2; else if (::strncmp(buffer, "[DMR Network 3]", 15U) == 0) - section = SECTION_DMR_NETWORK_3; + section = SECTION::DMR_NETWORK_3; else if (::strncmp(buffer, "[DMR Network 4]", 15U) == 0) - section = SECTION_DMR_NETWORK_4; + section = SECTION::DMR_NETWORK_4; else if (::strncmp(buffer, "[DMR Network 5]", 15U) == 0) - section = SECTION_DMR_NETWORK_5; + section = SECTION::DMR_NETWORK_5; else if (::strncmp(buffer, "[GPSD]", 6U) == 0) - section = SECTION_GPSD; + section = SECTION::GPSD; else if (::strncmp(buffer, "[APRS]", 6U) == 0) - section = SECTION_APRS; + section = SECTION::APRS; else if (::strncmp(buffer, "[MQTT]", 6U) == 0) - section = SECTION_MQTT; + section = SECTION::MQTT; else if (::strncmp(buffer, "[Dynamic TG Control]", 20U) == 0) - section = SECTION_DYNAMIC_TG_CONTROL; + section = SECTION::DYNAMIC_TG_CONTROL; else if (::strncmp(buffer, "[Remote Commands]", 17U) == 0) - section = SECTION_REMOTE_COMMANDS; + section = SECTION::REMOTE_COMMANDS; else - section = SECTION_NONE; + section = SECTION::NONE; continue; } @@ -290,12 +290,12 @@ bool CConf::read() m_ruleTrace = ::atoi(value) == 1; else if (::strcmp(key, "Debug") == 0) m_debug = ::atoi(value) == 1; - } else if (section == SECTION_LOG) { + } else if (section == SECTION::LOG) { if (::strcmp(key, "MQTTLevel") == 0) m_logMQTTLevel = (unsigned int)::atoi(value); else if (::strcmp(key, "DisplayLevel") == 0) m_logDisplayLevel = (unsigned int)::atoi(value); - } else if (section == SECTION_VOICE) { + } else if (section == SECTION::VOICE) { if (::strcmp(key, "Enabled") == 0) m_voiceEnabled = ::atoi(value) == 1; else if (::strcmp(key, "Language") == 0) @@ -354,7 +354,7 @@ bool CConf::read() m_xlxNetworkUserControl = ::atoi(value) ==1; else if (::strcmp(key, "Module") == 0) m_xlxNetworkModule = ::toupper(value[0]); - } else if (section == SECTION_DMR_NETWORK_1) { + } else if (section == SECTION::DMR_NETWORK_1) { if (::strcmp(key, "Enabled") == 0) m_dmrNetwork1Enabled = ::atoi(value) == 1; else if (::strcmp(key, "Name") == 0) @@ -980,7 +980,7 @@ bool CConf::read() m_aprsDescription = value; else if (::strcmp(key, "Symbol") == 0) m_aprsSymbol = value; - } else if (section == SECTION_MQTT) { + } else if (section == SECTION::MQTT) { if (::strcmp(key, "Address") == 0) m_mqttAddress = value; else if (::strcmp(key, "Port") == 0) @@ -989,10 +989,10 @@ bool CConf::read() m_mqttKeepalive = (unsigned int)::atoi(value); else if (::strcmp(key, "Name") == 0) m_mqttName = value; - } else if (section == SECTION_DYNAMIC_TG_CONTROL) { + } else if (section == SECTION::DYNAMIC_TG_CONTROL) { if (::strcmp(key, "Enable") == 0) m_dynamicTGControlEnabled = ::atoi(value) == 1; - } else if (section == SECTION_REMOTE_COMMANDS) { + } else if (section == SECTION::REMOTE_COMMANDS) { if (::strcmp(key, "Enable") == 0) m_remoteCommandsEnabled = ::atoi(value) == 1; } diff --git a/DMRGateway.cpp b/DMRGateway.cpp index 1c80577..765d399 100644 --- a/DMRGateway.cpp +++ b/DMRGateway.cpp @@ -2529,12 +2529,15 @@ void CDMRGateway::processDynamicTGControl(const std::string& command) { std::vector args; - std::stringstream tokeniser(command); - // Parse the original command into a vector of strings. - std::string token; - while (std::getline(tokeniser, token, ' ')) - args.push_back(token); + size_t start = command.find_first_not_of(' '); + while (start != std::string::npos) { + size_t end = command.find_first_of(' ', start); + + args.push_back(command.substr(start, end - start)); + + start = command.find_first_not_of(' ', end); + } if (args.at(0U) == "DynTG") { if (args.size() < 3) { diff --git a/DMRNetwork.cpp b/DMRNetwork.cpp index e7db7a8..8e96acd 100644 --- a/DMRNetwork.cpp +++ b/DMRNetwork.cpp @@ -369,7 +369,7 @@ void CDMRNetwork::clock(unsigned int ms) if (m_status == STATUS::RUNNING) { LogWarning("%s, Login to the master has failed, retrying login ...", m_name.c_str()); WriteJSONStatus("Failed login into DMR Network: " + m_name); - m_status = WAITING_LOGIN; + m_status = STATUS::WAITING_LOGIN; m_timeoutTimer.start(); m_retryTimer.start(); } else { @@ -403,7 +403,7 @@ void CDMRNetwork::clock(unsigned int ms) if (m_options.empty()) { LogMessage("%s, Logged into the master successfully", m_name.c_str()); WriteJSONStatus("Logged into DMR Network: " + m_name); - m_status = RUNNING; + m_status = STATUS::RUNNING; } else { LogDebug("%s, Sending options", m_name.c_str()); writeOptions(); @@ -415,7 +415,7 @@ void CDMRNetwork::clock(unsigned int ms) case STATUS::WAITING_OPTIONS: LogMessage("%s, Logged into the master successfully", m_name.c_str()); WriteJSONStatus("Logged into DMR Network: " + m_name); - m_status = RUNNING; + m_status = STATUS::RUNNING; m_timeoutTimer.start(); m_retryTimer.start(); break; diff --git a/MMDVMNetwork.cpp b/MMDVMNetwork.cpp index fcb0484..e0e0d4e 100644 --- a/MMDVMNetwork.cpp +++ b/MMDVMNetwork.cpp @@ -59,7 +59,7 @@ m_talkerAliasLen(0U) m_talkerAliasData = new unsigned char[50U]; CStopWatch stopWatch; - ::srand(stopWatch.start()); + ::srand((unsigned int)stopWatch.start()); } CMMDVMNetwork::~CMMDVMNetwork() diff --git a/MQTTConnection.cpp b/MQTTConnection.cpp index fa951e5..2fe0eba 100644 --- a/MQTTConnection.cpp +++ b/MQTTConnection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022,2023 by Jonathan Naylor G4KLX + * Copyright (C) 2022,2023,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,7 +21,7 @@ #include #include #include - +#include CMQTTConnection::CMQTTConnection(const std::string& host, unsigned short port, const std::string& name, const std::vector>& subs, unsigned int keepalive, MQTT_QOS qos) : m_host(host), @@ -30,7 +30,7 @@ m_name(name), m_subs(subs), m_keepalive(keepalive), m_qos(qos), -m_mosq(NULL), +m_mosq(nullptr), m_connected(false) { assert(!host.empty()); @@ -48,8 +48,13 @@ CMQTTConnection::~CMQTTConnection() bool CMQTTConnection::open() { - m_mosq = ::mosquitto_new(m_name.c_str(), true, this); - if (m_mosq == NULL){ + char name[50U]; + ::sprintf(name, "DMRGateway.%lld", ::time(nullptr)); + + ::fprintf(stdout, "DMRGateway (%s) connecting to MQTT as %s\n", m_name.c_str(), name); + + m_mosq = ::mosquitto_new(name, true, this); + if (m_mosq == nullptr){ ::fprintf(stderr, "MQTT Error newing: Out of memory.\n"); return false; } @@ -62,7 +67,7 @@ bool CMQTTConnection::open() int rc = ::mosquitto_connect(m_mosq, m_host.c_str(), m_port, m_keepalive); if (rc != MOSQ_ERR_SUCCESS) { ::mosquitto_destroy(m_mosq); - m_mosq = NULL; + m_mosq = nullptr; ::fprintf(stderr, "MQTT Error connecting: %s\n", ::mosquitto_strerror(rc)); return false; } @@ -71,7 +76,7 @@ bool CMQTTConnection::open() if (rc != MOSQ_ERR_SUCCESS) { ::mosquitto_disconnect(m_mosq); ::mosquitto_destroy(m_mosq); - m_mosq = NULL; + m_mosq = nullptr; ::fprintf(stderr, "MQTT Error loop starting: %s\n", ::mosquitto_strerror(rc)); return false; } @@ -81,38 +86,38 @@ bool CMQTTConnection::open() bool CMQTTConnection::publish(const char* topic, const char* text) { - assert(topic != NULL); - assert(text != NULL); + assert(topic != nullptr); + assert(text != nullptr); - return publish(topic, (unsigned char*)text, ::strlen(text)); + return publish(topic, (unsigned char*)text, (unsigned int)::strlen(text)); } bool CMQTTConnection::publish(const char* topic, const std::string& text) { - assert(topic != NULL); + assert(topic != nullptr); - return publish(topic, (unsigned char*)text.c_str(), text.size()); + return publish(topic, (unsigned char*)text.c_str(), (unsigned int)text.size()); } bool CMQTTConnection::publish(const char* topic, const unsigned char* data, unsigned int len) { - assert(topic != NULL); - assert(data != NULL); + assert(topic != nullptr); + assert(data != nullptr); if (!m_connected) return false; - if (::strchr(topic, '/') == NULL) { + if (::strchr(topic, '/') == nullptr) { char topicEx[100U]; ::sprintf(topicEx, "%s/%s", m_name.c_str(), topic); - int rc = ::mosquitto_publish(m_mosq, NULL, topicEx, len, data, static_cast(m_qos), false); + int rc = ::mosquitto_publish(m_mosq, nullptr, topicEx, len, data, static_cast(m_qos), false); if (rc != MOSQ_ERR_SUCCESS) { ::fprintf(stderr, "MQTT Error publishing: %s\n", ::mosquitto_strerror(rc)); return false; } } else { - int rc = ::mosquitto_publish(m_mosq, NULL, topic, len, data, static_cast(m_qos), false); + int rc = ::mosquitto_publish(m_mosq, nullptr, topic, len, data, static_cast(m_qos), false); if (rc != MOSQ_ERR_SUCCESS) { ::fprintf(stderr, "MQTT Error publishing: %s\n", ::mosquitto_strerror(rc)); return false; @@ -124,17 +129,17 @@ bool CMQTTConnection::publish(const char* topic, const unsigned char* data, unsi void CMQTTConnection::close() { - if (m_mosq != NULL) { + if (m_mosq != nullptr) { ::mosquitto_disconnect(m_mosq); ::mosquitto_destroy(m_mosq); - m_mosq = NULL; + m_mosq = nullptr; } } void CMQTTConnection::onConnect(mosquitto* mosq, void* obj, int rc) { - assert(mosq != NULL); - assert(obj != NULL); + assert(mosq != nullptr); + assert(obj != nullptr); ::fprintf(stdout, "MQTT: on_connect: %s\n", ::mosquitto_connack_string(rc)); if (rc != 0) { @@ -152,13 +157,13 @@ void CMQTTConnection::onConnect(mosquitto* mosq, void* obj, int rc) char topicEx[100U]; ::sprintf(topicEx, "%s/%s", p->m_name.c_str(), topic.c_str()); - rc = ::mosquitto_subscribe(mosq, NULL, topicEx, static_cast(p->m_qos)); + rc = ::mosquitto_subscribe(mosq, nullptr, topicEx, static_cast(p->m_qos)); if (rc != MOSQ_ERR_SUCCESS) { ::fprintf(stderr, "MQTT: error subscribing to %s - %s\n", topicEx, ::mosquitto_strerror(rc)); ::mosquitto_disconnect(mosq); } } else { - rc = ::mosquitto_subscribe(mosq, NULL, topic.c_str(), static_cast(p->m_qos)); + rc = ::mosquitto_subscribe(mosq, nullptr, topic.c_str(), static_cast(p->m_qos)); if (rc != MOSQ_ERR_SUCCESS) { ::fprintf(stderr, "MQTT: error subscribing to %s - %s\n", topic.c_str(), ::mosquitto_strerror(rc)); ::mosquitto_disconnect(mosq); @@ -169,9 +174,9 @@ void CMQTTConnection::onConnect(mosquitto* mosq, void* obj, int rc) void CMQTTConnection::onSubscribe(mosquitto* mosq, void* obj, int mid, int qosCount, const int* grantedQOS) { - assert(mosq != NULL); - assert(obj != NULL); - assert(grantedQOS != NULL); + assert(mosq != nullptr); + assert(obj != nullptr); + assert(grantedQOS != nullptr); for (int i = 0; i < qosCount; i++) ::fprintf(stdout, "MQTT: on_subscribe: %d:%d\n", i, grantedQOS[i]); @@ -179,9 +184,9 @@ void CMQTTConnection::onSubscribe(mosquitto* mosq, void* obj, int mid, int qosCo void CMQTTConnection::onMessage(mosquitto* mosq, void* obj, const mosquitto_message* message) { - assert(mosq != NULL); - assert(obj != NULL); - assert(message != NULL); + assert(mosq != nullptr); + assert(obj != nullptr); + assert(message != nullptr); CMQTTConnection* p = static_cast(obj); @@ -200,8 +205,8 @@ void CMQTTConnection::onMessage(mosquitto* mosq, void* obj, const mosquitto_mess void CMQTTConnection::onDisconnect(mosquitto* mosq, void* obj, int rc) { - assert(mosq != NULL); - assert(obj != NULL); + assert(mosq != nullptr); + assert(obj != nullptr); ::fprintf(stdout, "MQTT: on_disconnect: %s\n", ::mosquitto_reason_string(rc)); diff --git a/MQTTConnection.h b/MQTTConnection.h index 8fc98ce..9891b21 100644 --- a/MQTTConnection.h +++ b/MQTTConnection.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022,2023 by Jonathan Naylor G4KLX + * Copyright (C) 2022,2023,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 @@ -24,15 +24,15 @@ #include #include -enum MQTT_QOS { - MQTT_QOS_AT_MODE_ONCE = 0U, - MQTT_QOS_AT_LEAST_ONCE = 1U, - MQTT_QOS_EXACTLY_ONCE = 2U +enum class MQTT_QOS : int { + AT_MODE_ONCE = 0, + AT_LEAST_ONCE = 1, + EXACTLY_ONCE = 2 }; class CMQTTConnection { public: - CMQTTConnection(const std::string& host, unsigned short port, const std::string& name, const std::vector>& subs, unsigned int keepalive, MQTT_QOS qos = MQTT_QOS_EXACTLY_ONCE); + CMQTTConnection(const std::string& host, unsigned short port, const std::string& name, const std::vector>& subs, unsigned int keepalive, MQTT_QOS qos = MQTT_QOS::EXACTLY_ONCE); ~CMQTTConnection(); bool open(); diff --git a/RemoteControl.cpp b/RemoteControl.cpp index 9a254c8..62deb73 100644 --- a/RemoteControl.cpp +++ b/RemoteControl.cpp @@ -36,7 +36,7 @@ extern CMQTTConnection* m_mqtt; CRemoteControl::CRemoteControl(CDMRGateway* host) : m_host(host), -m_command(RCD_NONE), +m_command(REMOTE_COMMAND::NONE), m_args() { } @@ -47,46 +47,49 @@ CRemoteControl::~CRemoteControl() REMOTE_COMMAND CRemoteControl::processCommand(const std::string& command) { - m_command = RCD_NONE; + m_command = REMOTE_COMMAND::NONE; m_args.clear(); std::string replyStr = "OK"; - std::stringstream tokeniser(command); - // Parse the original command into a vector of strings. - std::string token; - while (std::getline(tokeniser, token, ' ')) - m_args.push_back(token); + size_t start = command.find_first_not_of(' '); + while (start != std::string::npos) { + size_t end = command.find_first_of(' ', start); + + m_args.push_back(command.substr(start, end - start)); + + start = command.find_first_not_of(' ', end); + } if (m_args.at(0U) == "enable" && m_args.size() >= ENABLE_ARGS) { if (m_args.at(1U) == "net1") - m_command = RCD_ENABLE_NETWORK1; + m_command = REMOTE_COMMAND::ENABLE_NETWORK1; else if (m_args.at(1U) == "net2") - m_command = RCD_ENABLE_NETWORK2; + m_command = REMOTE_COMMAND::ENABLE_NETWORK2; else if (m_args.at(1U) == "net3") - m_command = RCD_ENABLE_NETWORK3; + m_command = REMOTE_COMMAND::ENABLE_NETWORK3; else if (m_args.at(1U) == "net4") - m_command = RCD_ENABLE_NETWORK4; + m_command = REMOTE_COMMAND::ENABLE_NETWORK4; else if (m_args.at(1U) == "net5") - m_command = RCD_ENABLE_NETWORK5; + m_command = REMOTE_COMMAND::ENABLE_NETWORK5; else if (m_args.at(1U) == "xlx") - m_command = RCD_ENABLE_XLX; + m_command = REMOTE_COMMAND::ENABLE_XLX; else replyStr = "KO"; } else if (m_args.at(0U) == "disable" && m_args.size() >= DISABLE_ARGS) { if (m_args.at(1U) == "net1") - m_command = RCD_DISABLE_NETWORK1; + m_command = REMOTE_COMMAND::DISABLE_NETWORK1; else if (m_args.at(1U) == "net2") - m_command = RCD_DISABLE_NETWORK2; + m_command = REMOTE_COMMAND::DISABLE_NETWORK2; else if (m_args.at(1U) == "net3") - m_command = RCD_DISABLE_NETWORK3; + m_command = REMOTE_COMMAND::DISABLE_NETWORK3; else if (m_args.at(1U) == "net4") - m_command = RCD_DISABLE_NETWORK4; + m_command = REMOTE_COMMAND::DISABLE_NETWORK4; else if (m_args.at(1U) == "net5") - m_command = RCD_DISABLE_NETWORK5; + m_command = REMOTE_COMMAND::DISABLE_NETWORK5; else if (m_args.at(1U) == "xlx") - m_command = RCD_DISABLE_XLX; + m_command = REMOTE_COMMAND::DISABLE_XLX; else replyStr = "KO"; } else if (m_args.at(0U) == "status") { @@ -95,22 +98,22 @@ REMOTE_COMMAND CRemoteControl::processCommand(const std::string& command) else replyStr = "KO"; - m_command = RCD_CONNECTION_STATUS; + m_command = REMOTE_COMMAND::CONNECTION_STATUS; } else if (m_args.at(0U) == "hosts") { if (m_host != nullptr) m_host->buildNetworkHostsString(replyStr); else replyStr = "KO"; - m_command = RCD_CONFIG_HOSTS; + m_command = REMOTE_COMMAND::CONFIG_HOSTS; } else { replyStr = "KO"; } char buffer[200U]; - ::snprintf(buffer, 200, "%s remote command of \"%s\" received", ((m_command == RCD_NONE) ? "Invalid" : "Valid"), command.c_str()); + ::snprintf(buffer, 200, "%s remote command of \"%s\" received", ((m_command == REMOTE_COMMAND::NONE) ? "Invalid" : "Valid"), command.c_str()); - if (m_command == RCD_NONE) { + if (m_command == REMOTE_COMMAND::NONE) { m_args.clear(); LogWarning(buffer); } else {