From 3c48b8f61b92db1c9a063b81316475ce297e7c50 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 20 Jun 2023 16:33:33 +0100 Subject: [PATCH] Add support for passthrough of serial data from MQTT to the spare serial port on an MMDVM modem/hotspot. --- MMDVMHost.cpp | 14 ++++++++++ MMDVMHost.h | 2 ++ MMDVMHost.vcxproj | 2 -- MMDVMHost.vcxproj.filters | 6 ---- MQTTConnection.cpp | 20 +++++++++++++ MQTTConnection.h | 1 + Makefile | 2 +- Modem.cpp | 31 +++++++++++--------- Modem.h | 6 ++-- ModemSerialPort.cpp | 59 --------------------------------------- ModemSerialPort.h | 42 ---------------------------- 11 files changed, 59 insertions(+), 126 deletions(-) delete mode 100644 ModemSerialPort.cpp delete mode 100644 ModemSerialPort.h diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 9d02059..6df625e 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1191,6 +1191,10 @@ int CMMDVMHost::run() m_modem->writeTransparentData(data, len); } + len = m_modem->readSerialData(data); + if (len > 0U) + m_mqtt->publish("display", data, len); + unsigned int ms = stopWatch.elapsed(); stopWatch.start(); @@ -2784,6 +2788,13 @@ void CMMDVMHost::writeJSONMessage(const std::string& message) WriteJSON("MMDVM", json); } +void CMMDVMHost::writeSerial(const std::string& message) +{ + assert(m_modem != NULL); + + m_modem->writeSerialData((unsigned char*)message.c_str(), message.length()); +} + void CMMDVMHost::onCommand(const std::string& command) { assert(host != NULL); @@ -2793,5 +2804,8 @@ void CMMDVMHost::onCommand(const std::string& command) void CMMDVMHost::onDisplay(const std::string& message) { + assert(host != NULL); + + host->writeSerial(message); } diff --git a/MMDVMHost.h b/MMDVMHost.h index cff69cc..a975036 100644 --- a/MMDVMHost.h +++ b/MMDVMHost.h @@ -131,6 +131,8 @@ private: bool createFMNetwork(); bool createAX25Network(); + void writeSerial(const std::string& message); + void remoteControl(const std::string& commandString); void processModeCommand(unsigned char mode, unsigned int timeout); void processEnableCommand(bool& mode, bool enabled); diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 456c4a0..5181fa8 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -199,7 +199,6 @@ - @@ -299,7 +298,6 @@ - diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 77f9351..0e87459 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -188,9 +188,6 @@ Header Files - - Header Files - Header Files @@ -478,9 +475,6 @@ Source Files - - Source Files - Source Files diff --git a/MQTTConnection.cpp b/MQTTConnection.cpp index 69190b8..1f5826b 100644 --- a/MQTTConnection.cpp +++ b/MQTTConnection.cpp @@ -99,6 +99,26 @@ bool CMQTTConnection::publish(const char* topic, const char* text) return true; } +bool CMQTTConnection::publish(const char* topic, const unsigned char* data, unsigned int len) +{ + assert(topic != NULL); + assert(data != NULL); + + if (!m_connected) + return false; + + 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); + if (rc != MOSQ_ERR_SUCCESS) { + ::fprintf(stderr, "MQTT Error publishing: %s\n", ::mosquitto_strerror(rc)); + return false; + } + + return true; +} + void CMQTTConnection::close() { if (m_mosq != NULL) { diff --git a/MQTTConnection.h b/MQTTConnection.h index dedfc76..ae39eb2 100644 --- a/MQTTConnection.h +++ b/MQTTConnection.h @@ -38,6 +38,7 @@ public: bool open(); bool publish(const char* topic, const char* text); + bool publish(const char* topic, const unsigned char* data, unsigned int len); void close(); diff --git a/Makefile b/Makefile index 41c2482..f54ca77 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ OBJECTS = \ DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o \ DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o \ Hamming.o I2CController.o IIRDirectForm1Filter.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o MMDVMHost.o \ - MQTTConnection.o Modem.o ModemPort.o ModemSerialPort.o Mutex.o NullController.o NXDNAudio.o NXDNControl.o \ + MQTTConnection.o Modem.o ModemPort.o Mutex.o NullController.o NXDNAudio.o NXDNControl.o \ NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o \ NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o PseudoTTYController.o POCSAGControl.o \ POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o StopWatch.o Sync.o SHA256.o Thread.o \ diff --git a/Modem.cpp b/Modem.cpp index 5669918..899572e 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -898,10 +898,15 @@ void CModem::clock(unsigned int ms) printDebug(); break; - case MMDVM_SERIAL_DATA: - if (m_trace) - CUtils::dump(1U, "RX Serial Data", m_buffer, m_length); - m_rxSerialData.addData(m_buffer + m_offset, m_length - m_offset); + case MMDVM_SERIAL_DATA: { + if (m_trace) + CUtils::dump(1U, "RX Serial Data", m_buffer, m_length); + + unsigned char data = m_length - m_offset; + m_rxSerialData.addData(&data, 1U); + + m_rxSerialData.addData(m_buffer + m_offset, m_length - m_offset); + } break; default: @@ -1301,18 +1306,18 @@ unsigned int CModem::readTransparentData(unsigned char* data) return len; } -unsigned int CModem::readSerial(unsigned char* data, unsigned int length) +unsigned int CModem::readSerialData(unsigned char* data) { assert(data != NULL); - assert(length > 0U); - unsigned int n = 0U; - while (!m_rxSerialData.isEmpty() && n < length) { - m_rxSerialData.getData(data + n, 1U); - n++; - } + if (m_rxSerialData.isEmpty()) + return 0U; - return n; + unsigned char len = 0U; + m_rxSerialData.getData(&len, 1U); + m_rxSerialData.getData(data, len); + + return len; } bool CModem::hasDStarSpace() const @@ -1879,7 +1884,7 @@ bool CModem::writeIPInfo(const std::string& address) return ret != int(length + 4U); } -bool CModem::writeSerial(const unsigned char* data, unsigned int length) +bool CModem::writeSerialData(const unsigned char* data, unsigned int length) { assert(m_port != NULL); assert(data != NULL); diff --git a/Modem.h b/Modem.h index 0a69311..fbe4526 100644 --- a/Modem.h +++ b/Modem.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018,2020,2021 by Jonathan Naylor G4KLX + * Copyright (C) 2011-2018,2020,2021,2023 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 @@ -131,8 +131,8 @@ public: bool writeTransparentData(const unsigned char* data, unsigned int length); unsigned int readTransparentData(unsigned char* data); - bool writeSerial(const unsigned char* data, unsigned int length); - unsigned int readSerial(unsigned char* data, unsigned int length); + bool writeSerialData(const unsigned char* data, unsigned int length); + unsigned int readSerialData(unsigned char* data); unsigned char getMode() const; bool setMode(unsigned char mode); diff --git a/ModemSerialPort.cpp b/ModemSerialPort.cpp deleted file mode 100644 index aa0a194..0000000 --- a/ModemSerialPort.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* -* Copyright (C) 2016,2020,2021 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 "ModemSerialPort.h" - -#include -#include - -IModemSerialPort::IModemSerialPort(CModem* modem) : -m_modem(modem) -{ - assert(modem != NULL); -} - -IModemSerialPort::~IModemSerialPort() -{ -} - -bool IModemSerialPort::open() -{ - return true; -} - -int IModemSerialPort::write(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - bool ret = m_modem->writeSerial(data, length); - - return ret ? int(length) : -1; -} - -int IModemSerialPort::read(unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - return m_modem->readSerial(data, length); -} - -void IModemSerialPort::close() -{ -} diff --git a/ModemSerialPort.h b/ModemSerialPort.h deleted file mode 100644 index 9a64426..0000000 --- a/ModemSerialPort.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -* Copyright (C) 2016,2020,2021 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. -*/ - -#ifndef ModemSerialPort_H -#define ModemSerialPort_H - -#include "SerialPort.h" -#include "Modem.h" - -class IModemSerialPort : public ISerialPort { -public: - IModemSerialPort(CModem* modem); - virtual ~IModemSerialPort(); - - virtual bool open(); - - virtual int read(unsigned char* buffer, unsigned int length); - - virtual int write(const unsigned char* buffer, unsigned int length); - - virtual void close(); - -private: - CModem* m_modem; -}; - -#endif