Use MQTT for KISS format packet data in and out of the host.

This commit is contained in:
Jonathan Naylor
2023-07-28 19:16:31 +01:00
parent e4de1951cc
commit c1dc441f28
11 changed files with 105 additions and 270 deletions

View File

@@ -18,6 +18,7 @@
#include "AX25Network.h" #include "AX25Network.h"
#include "AX25Defines.h" #include "AX25Defines.h"
#include "MQTTConnection.h"
#include "Utils.h" #include "Utils.h"
#include "Log.h" #include "Log.h"
@@ -27,139 +28,126 @@
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
const unsigned int BUFFER_LENGTH = 500U; // In Log.cpp
extern CMQTTConnection* m_mqtt;
CAX25Network::CAX25Network(bool debug) :
CAX25Network::CAX25Network(const std::string& port, unsigned int speed, bool debug) : m_buffer(1000U, "AX.25 buffer"),
m_serial(port, speed, false),
m_txData(NULL),
m_rxData(NULL),
m_rxLength(0U),
m_rxLastChar(0U),
m_debug(debug), m_debug(debug),
m_enabled(false) m_enabled(false)
{ {
assert(!port.empty());
assert(speed > 0U);
m_txData = new unsigned char[BUFFER_LENGTH];
m_rxData = new unsigned char[BUFFER_LENGTH];
} }
CAX25Network::~CAX25Network() CAX25Network::~CAX25Network()
{ {
delete[] m_txData;
delete[] m_rxData;
} }
bool CAX25Network::open() bool CAX25Network::open()
{ {
LogMessage("Opening AX25 network connection"); LogMessage("Opening AX.25 network connection");
return m_serial.open(); return true;
} }
bool CAX25Network::write(const unsigned char* data, unsigned int length) bool CAX25Network::write(const unsigned char* data, unsigned int length)
{ {
assert(data != NULL); assert(data != NULL);
assert(m_mqtt != NULL);
if (!m_enabled) if (!m_enabled)
return true; return true;
unsigned char txData[500U];
unsigned int txLength = 0U; unsigned int txLength = 0U;
m_txData[txLength++] = AX25_FEND; txData[txLength++] = AX25_FEND;
m_txData[txLength++] = AX25_KISS_DATA; txData[txLength++] = AX25_KISS_DATA;
for (unsigned int i = 0U; i < length; i++) { for (unsigned int i = 0U; i < length; i++) {
unsigned char c = data[i]; unsigned char c = data[i];
switch (c) { switch (c) {
case AX25_FEND: case AX25_FEND:
m_txData[txLength++] = AX25_FESC; txData[txLength++] = AX25_FESC;
m_txData[txLength++] = AX25_TFEND; txData[txLength++] = AX25_TFEND;
break; break;
case AX25_FESC: case AX25_FESC:
m_txData[txLength++] = AX25_FESC; txData[txLength++] = AX25_FESC;
m_txData[txLength++] = AX25_TFESC; txData[txLength++] = AX25_TFESC;
break; break;
default: default:
m_txData[txLength++] = c; txData[txLength++] = c;
break; break;
} }
} }
m_txData[txLength++] = AX25_FEND; txData[txLength++] = AX25_FEND;
if (m_debug) if (m_debug)
CUtils::dump(1U, "AX25 Network Data Sent", m_txData, txLength); CUtils::dump(1U, "AX.25 Network Data Sent", txData, txLength);
return m_serial.write(m_txData, txLength); m_mqtt->publish("ax25-out", txData, txLength);
return true;
} }
unsigned int CAX25Network::read(unsigned char* data, unsigned int length) unsigned int CAX25Network::read(unsigned char* data, unsigned int length)
{ {
assert(data != NULL); assert(data != NULL);
assert(length > 0U);
if (!m_buffer.isEmpty())
return 0U;
unsigned int dataLen = 0U;
m_buffer.getData((unsigned char*)&dataLen, sizeof(unsigned int));
assert(length >= dataLen);
m_buffer.getData(data, dataLen);
return dataLen;
}
void CAX25Network::setData(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(length > 0U);
if (m_debug)
CUtils::dump(1U, "AX.25 Network Data Received", data, length);
if (data[0U] != AX25_FEND)
return;
bool complete = false; bool complete = false;
unsigned char c; unsigned char rxData[500U];
while (m_serial.read(&c, 1U) > 0) { unsigned int rxLength = 0U;
if (m_rxLength == 0U && c == AX25_FEND) unsigned char lastChar = 0x00U;
m_rxData[m_rxLength++] = c;
else if (m_rxLength > 0U)
m_rxData[m_rxLength++] = c;
if (m_rxLength > 1U && c == AX25_FEND) { for (unsigned int i = 2U; i < length; i++) {
complete = true; unsigned char c = data[i];
break;
}
}
if (!m_enabled)
return 0U;
if (!complete)
return 0U;
if (m_rxLength == 0U)
return 0U;
if (m_rxData[1U] != AX25_KISS_DATA) {
m_rxLength = 0U;
return 0U;
}
complete = false;
unsigned int dataLen = 0U;
for (unsigned int i = 2U; i < m_rxLength; i++) {
unsigned char c = m_rxData[i];
if (c == AX25_FEND) { if (c == AX25_FEND) {
complete = true; complete = true;
break; break;
} else if (c == AX25_TFEND && m_rxLastChar == AX25_FESC) { } else if (c == AX25_TFEND && lastChar == AX25_FESC) {
data[dataLen++] = AX25_FEND; rxData[rxLength++] = AX25_FEND;
} else if (c == AX25_TFESC && m_rxLastChar == AX25_FESC) { } else if (c == AX25_TFESC && lastChar == AX25_FESC) {
data[dataLen++] = AX25_FESC; rxData[rxLength++] = AX25_FESC;
} else { } else {
data[dataLen++] = c; rxData[rxLength++] = c;
} }
m_rxLastChar = c; lastChar = c;
} }
if (!complete) if (!complete)
return 0U; return;
if (m_debug) m_buffer.addData((unsigned char*)&rxLength, sizeof(unsigned int));
CUtils::dump(1U, "AX25 Network Data Received", m_rxData, m_rxLength); m_buffer.addData(rxData, rxLength);
m_rxLength = 0U;
m_rxLastChar = 0U;
return dataLen;
} }
void CAX25Network::reset() void CAX25Network::reset()
@@ -168,19 +156,15 @@ void CAX25Network::reset()
void CAX25Network::close() void CAX25Network::close()
{ {
m_serial.close(); LogMessage("Closing AX.25 network connection");
LogMessage("Closing AX25 network connection");
} }
void CAX25Network::enable(bool enabled) void CAX25Network::enable(bool enabled)
{ {
m_enabled = enabled; m_enabled = enabled;
if (enabled != m_enabled) { if (enabled != m_enabled)
m_rxLastChar = 0U; m_buffer.clear();
m_rxLength = 0U;
}
} }
#endif #endif

View File

@@ -23,18 +23,14 @@
#if defined(USE_AX25) #if defined(USE_AX25)
#if defined(_WIN32) || defined(_WIN64) #include "RingBuffer.h"
#include "UARTController.h"
#else
#include "PseudoTTYController.h"
#endif
#include <cstdint> #include <cstdint>
#include <string> #include <string>
class CAX25Network { class CAX25Network {
public: public:
CAX25Network(const std::string& port, unsigned int speed, bool debug); CAX25Network(bool debug);
~CAX25Network(); ~CAX25Network();
bool open(); bool open();
@@ -45,22 +41,16 @@ public:
unsigned int read(unsigned char* data, unsigned int length); unsigned int read(unsigned char* data, unsigned int length);
void setData(const unsigned char* data, unsigned int length);
void reset(); void reset();
void close(); void close();
private: private:
#if defined(_WIN32) || defined(_WIN64) CRingBuffer<unsigned char> m_buffer;
CUARTController m_serial; bool m_debug;
#else bool m_enabled;
CPseudoTTYController m_serial;
#endif
unsigned char* m_txData;
unsigned char* m_rxData;
unsigned int m_rxLength;
unsigned char m_rxLastChar;
bool m_debug;
bool m_enabled;
}; };
#endif #endif

View File

@@ -399,8 +399,6 @@ m_fmNetworkDebug(false),
#endif #endif
#if defined(USE_AX25) #if defined(USE_AX25)
m_ax25NetworkEnabled(false), m_ax25NetworkEnabled(false),
m_ax25NetworkPort(),
m_ax25NetworkSpeed(9600U),
m_ax25NetworkDebug(false), m_ax25NetworkDebug(false),
#endif #endif
m_lockFileEnabled(false), m_lockFileEnabled(false),
@@ -1208,10 +1206,6 @@ bool CConf::read()
} else if (section == SECTION_AX25_NETWORK) { } else if (section == SECTION_AX25_NETWORK) {
if (::strcmp(key, "Enable") == 0) if (::strcmp(key, "Enable") == 0)
m_ax25NetworkEnabled = ::atoi(value) == 1; m_ax25NetworkEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Port") == 0)
m_ax25NetworkPort = value;
else if (::strcmp(key, "Speed") == 0)
m_ax25NetworkSpeed = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0) else if (::strcmp(key, "Debug") == 0)
m_ax25NetworkDebug = ::atoi(value) == 1; m_ax25NetworkDebug = ::atoi(value) == 1;
#endif #endif
@@ -2450,16 +2444,6 @@ bool CConf::getAX25NetworkEnabled() const
return m_ax25NetworkEnabled; return m_ax25NetworkEnabled;
} }
std::string CConf::getAX25NetworkPort() const
{
return m_ax25NetworkPort;
}
unsigned int CConf::getAX25NetworkSpeed() const
{
return m_ax25NetworkSpeed;
}
bool CConf::getAX25NetworkDebug() const bool CConf::getAX25NetworkDebug() const
{ {
return m_ax25NetworkDebug; return m_ax25NetworkDebug;

4
Conf.h
View File

@@ -374,8 +374,6 @@ public:
#if defined(USE_AX25) #if defined(USE_AX25)
// The AX.25 Network section // The AX.25 Network section
bool getAX25NetworkEnabled() const; bool getAX25NetworkEnabled() const;
std::string getAX25NetworkPort() const;
unsigned int getAX25NetworkSpeed() const;
bool getAX25NetworkDebug() const; bool getAX25NetworkDebug() const;
#endif #endif
@@ -711,8 +709,6 @@ private:
#if defined(USE_AX25) #if defined(USE_AX25)
bool m_ax25NetworkEnabled; bool m_ax25NetworkEnabled;
std::string m_ax25NetworkPort;
unsigned int m_ax25NetworkSpeed;
bool m_ax25NetworkDebug; bool m_ax25NetworkDebug;
#endif #endif

View File

@@ -298,8 +298,6 @@ Debug=0
[AX.25 Network] [AX.25 Network]
Enable=1 Enable=1
Port=/dev/ttyp7
Speed=9600
Debug=0 Debug=0
[Lock File] [Lock File]

View File

@@ -361,6 +361,11 @@ int CMMDVMHost::run()
if (m_conf.getRemoteControlEnabled()) if (m_conf.getRemoteControlEnabled())
subscriptions.push_back(std::make_pair("command", CMMDVMHost::onCommand)); subscriptions.push_back(std::make_pair("command", CMMDVMHost::onCommand));
#if defined(USE_AX25)
if (m_ax25Enabled && !m_modem->hasAX25())
subscriptions.push_back(std::make_pair("ax25-in", CMMDVMHost::onAX25));
#endif
m_mqtt = new CMQTTConnection(m_conf.getMQTTHost(), m_conf.getMQTTPort(), m_conf.getMQTTName(), subscriptions, m_conf.getMQTTKeepalive()); m_mqtt = new CMQTTConnection(m_conf.getMQTTHost(), m_conf.getMQTTPort(), m_conf.getMQTTName(), subscriptions, m_conf.getMQTTKeepalive());
ret = m_mqtt->open(); ret = m_mqtt->open();
if (!ret) { if (!ret) {
@@ -2243,15 +2248,11 @@ bool CMMDVMHost::createFMNetwork()
#if defined(USE_AX25) #if defined(USE_AX25)
bool CMMDVMHost::createAX25Network() bool CMMDVMHost::createAX25Network()
{ {
std::string port = m_conf.getAX25NetworkPort();
unsigned int speed = m_conf.getAX25NetworkSpeed();
bool debug = m_conf.getAX25NetworkDebug(); bool debug = m_conf.getAX25NetworkDebug();
LogInfo("AX.25 Network Parameters"); LogInfo("AX.25 Network Parameters");
LogInfo(" Port: %s", port.c_str());
LogInfo(" Speed: %u", speed);
m_ax25Network = new CAX25Network(port, speed, debug); m_ax25Network = new CAX25Network(debug);
bool ret = m_ax25Network->open(); bool ret = m_ax25Network->open();
if (!ret) { if (!ret) {
@@ -3638,6 +3639,17 @@ void CMMDVMHost::writeSerial(const unsigned char* message, unsigned int length)
m_modem->writeSerialData(message, length); m_modem->writeSerialData(message, length);
} }
#if defined(USE_AX25)
void CMMDVMHost::writeAX25(const unsigned char* message, unsigned int length)
{
assert(host != NULL);
assert(message != NULL);
assert(m_ax25Network != NULL);
m_ax25Network->setData(message, length);
}
#endif
void CMMDVMHost::onCommand(const unsigned char* command, unsigned int length) void CMMDVMHost::onCommand(const unsigned char* command, unsigned int length)
{ {
assert(host != NULL); assert(host != NULL);
@@ -3654,3 +3666,13 @@ void CMMDVMHost::onDisplay(const unsigned char* message, unsigned int length)
host->writeSerial(message, length); host->writeSerial(message, length);
} }
#if defined(USE_AX25)
void CMMDVMHost::onAX25(const unsigned char* message, unsigned int length)
{
assert(host != NULL);
assert(message != NULL);
host->writeAX25(message, length);
}
#endif

View File

@@ -222,7 +222,9 @@ private:
bool createAX25Network(); bool createAX25Network();
#endif #endif
void writeSerial(const unsigned char* message, unsigned int length); void writeSerial(const unsigned char* message, unsigned int length);
#if defined(USE_AX25)
void writeAX25(const unsigned char* message, unsigned int length);
#endif
void remoteControl(const std::string& commandString); void remoteControl(const std::string& commandString);
void processModeCommand(unsigned char mode, unsigned int timeout); void processModeCommand(unsigned char mode, unsigned int timeout);
void processEnableCommand(bool& mode, bool enabled); void processEnableCommand(bool& mode, bool enabled);
@@ -237,6 +239,9 @@ private:
static void onDisplay(const unsigned char* message, unsigned int length); static void onDisplay(const unsigned char* message, unsigned int length);
static void onCommand(const unsigned char* command, unsigned int length); static void onCommand(const unsigned char* command, unsigned int length);
#if defined(USE_AX25)
static void onAX25(const unsigned char* message, unsigned int length);
#endif
}; };
#endif #endif

View File

@@ -13,7 +13,7 @@ OBJECTS = \
Hamming.o I2CController.o IIRDirectForm1Filter.o Log.o M17Control.o M17Convolution.o M17CRC.o M17LSF.o M17Network.o M17Utils.o MMDVMHost.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 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 \ 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 \ NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \
POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o StopWatch.o Sync.o Thread.o \ POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialPort.o StopWatch.o Sync.o Thread.o \
Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o Timer.o UARTController.o UDPController.o UDPSocket.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o

View File

@@ -1,94 +0,0 @@
/*
* Copyright (C) 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
* 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 "PseudoTTYController.h"
#if defined(USE_AX25)
#if !defined(_WIN32) && !defined(_WIN64)
#include "Log.h"
#include <cstring>
#include <cassert>
#include <cstdlib>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <cerrno>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#if defined(__linux__)
#include <pty.h>
#else
#include <util.h>
#endif
CPseudoTTYController::CPseudoTTYController(const std::string& symlink, unsigned int speed, bool assertRTS) :
CUARTController(speed, assertRTS),
m_symlink(symlink)
{
}
CPseudoTTYController::~CPseudoTTYController()
{
}
bool CPseudoTTYController::open()
{
assert(m_fd == -1);
int slavefd;
char slave[300];
int result = ::openpty(&m_fd, &slavefd, slave, NULL, NULL);
if (result < 0) {
LogError("Cannot open the pseudo tty - errno : %d", errno);
return false;
}
// Remove any previous stale symlink
::unlink(m_symlink.c_str());
int ret = ::symlink(slave, m_symlink.c_str());
if (ret != 0) {
LogError("Cannot make symlink to %s with %s", slave, m_symlink.c_str());
close();
return false;
}
LogMessage("Made symbolic link from %s to %s", slave, m_symlink.c_str());
m_device = std::string(::ttyname(m_fd));
return setRaw();
}
void CPseudoTTYController::close()
{
CUARTController::close();
::unlink(m_symlink.c_str());
}
#endif
#endif

View File

@@ -1,50 +0,0 @@
/*
* Copyright (C) 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
* 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 PseudoTTYController_H
#define PseudoTTYController_H
#include "Defines.h"
#if defined(USE_AX25)
#if !defined(_WIN32) && !defined(_WIN64)
#include <cstring>
#include "UARTController.h"
class CPseudoTTYController : public CUARTController {
public:
CPseudoTTYController(const std::string& symlink, unsigned int speed, bool assertRTS = false);
virtual ~CPseudoTTYController();
virtual bool open();
virtual void close();
protected:
std::string m_symlink;
};
#endif
#endif
#endif

View File

@@ -19,6 +19,6 @@
#if !defined(VERSION_H) #if !defined(VERSION_H)
#define VERSION_H #define VERSION_H
const char* VERSION = "20230726"; const char* VERSION = "20230728";
#endif #endif