From 19d8f2237f1aa8d4564dbe723aa8f65f2d56831d Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Tue, 7 Jan 2025 17:15:35 -0500 Subject: [PATCH] refactor FSC (it was entirely just broken); --- configs/config.example.yml | 6 +- src/common/p25/dfsi/frames/fsc/FSCACK.cpp | 2 +- src/common/p25/dfsi/frames/fsc/FSCConnect.cpp | 2 +- .../dfsi/frames/fsc/FSCConnectResponse.cpp | 2 +- .../p25/dfsi/frames/fsc/FSCDisconnect.cpp | 4 +- .../p25/dfsi/frames/fsc/FSCHeartbeat.cpp | 4 +- src/common/p25/dfsi/frames/fsc/FSCMessage.h | 2 +- src/host/Host.Config.cpp | 11 +- .../modem/port/specialized/V24UDPPort.cpp | 174 ++++++++++-------- src/host/modem/port/specialized/V24UDPPort.h | 7 +- 10 files changed, 125 insertions(+), 89 deletions(-) diff --git a/configs/config.example.yml b/configs/config.example.yml index e366f611..ebb3b421 100644 --- a/configs/config.example.yml +++ b/configs/config.example.yml @@ -590,8 +590,10 @@ system: jitter: 200 # Timer which will reset local/remote call flags if frames aren't received longer than this time in ms callTimeout: 200 - # Flag indicating when operating in V.24 UDP mode should the FSC protocol be used to negotiate connection. - useFSC: false + # Flag indicating when operating in V.24 UDP mode, the FSC protocol should be used to negotiate connection. + fsc: false + # Flag indicating when operating in V.24 UDP mode, this instance should initiate the FSC protocol handshake. + initiator: false # Sets received the signal offset from DC. rxDCOffset: 0 # Valid values between -128 and 128 diff --git a/src/common/p25/dfsi/frames/fsc/FSCACK.cpp b/src/common/p25/dfsi/frames/fsc/FSCACK.cpp index 2fa01505..10abc999 100644 --- a/src/common/p25/dfsi/frames/fsc/FSCACK.cpp +++ b/src/common/p25/dfsi/frames/fsc/FSCACK.cpp @@ -44,7 +44,7 @@ FSCACK::FSCACK(const uint8_t* data) : FSCMessage(data), m_responseCode(FSCAckResponseCode::CONTROL_ACK), m_respLength(0U) { - decode(data); + FSCACK::decode(data); } /* Decode a FSC ACK frame. */ diff --git a/src/common/p25/dfsi/frames/fsc/FSCConnect.cpp b/src/common/p25/dfsi/frames/fsc/FSCConnect.cpp index ce7d3666..9d3f6fdd 100644 --- a/src/common/p25/dfsi/frames/fsc/FSCConnect.cpp +++ b/src/common/p25/dfsi/frames/fsc/FSCConnect.cpp @@ -42,7 +42,7 @@ FSCConnect::FSCConnect(const uint8_t* data) : FSCMessage(data), m_fsHeartbeatPeriod(5U), m_hostHeartbeatPeriod(5U) { - decode(data); + FSCConnect::decode(data); } /* Decode a FSC connect frame. */ diff --git a/src/common/p25/dfsi/frames/fsc/FSCConnectResponse.cpp b/src/common/p25/dfsi/frames/fsc/FSCConnectResponse.cpp index 6af0a65e..d93332ed 100644 --- a/src/common/p25/dfsi/frames/fsc/FSCConnectResponse.cpp +++ b/src/common/p25/dfsi/frames/fsc/FSCConnectResponse.cpp @@ -36,7 +36,7 @@ FSCConnectResponse::FSCConnectResponse() : FSCResponse(), FSCConnectResponse::FSCConnectResponse(const uint8_t* data) : FSCResponse(data), m_vcBasePort(0U) { - decode(data); + FSCConnectResponse::decode(data); } /* Decode a FSC connect frame. */ diff --git a/src/common/p25/dfsi/frames/fsc/FSCDisconnect.cpp b/src/common/p25/dfsi/frames/fsc/FSCDisconnect.cpp index f6f79c01..03255b49 100644 --- a/src/common/p25/dfsi/frames/fsc/FSCDisconnect.cpp +++ b/src/common/p25/dfsi/frames/fsc/FSCDisconnect.cpp @@ -4,7 +4,7 @@ * GPLv2 Open Source. Use is subject to license terms. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright (C) 2024 Bryan Biedenkapp, N2PLL + * Copyright (C) 2024-2025 Bryan Biedenkapp, N2PLL * */ #include "common/p25/dfsi/frames/fsc/FSCDisconnect.h" @@ -34,5 +34,5 @@ FSCDisconnect::FSCDisconnect() : FSCMessage() FSCDisconnect::FSCDisconnect(const uint8_t* data) : FSCMessage(data) { - decode(data); + FSCMessage::decode(data); } diff --git a/src/common/p25/dfsi/frames/fsc/FSCHeartbeat.cpp b/src/common/p25/dfsi/frames/fsc/FSCHeartbeat.cpp index 43aef62e..a37613a2 100644 --- a/src/common/p25/dfsi/frames/fsc/FSCHeartbeat.cpp +++ b/src/common/p25/dfsi/frames/fsc/FSCHeartbeat.cpp @@ -4,7 +4,7 @@ * GPLv2 Open Source. Use is subject to license terms. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright (C) 2024 Bryan Biedenkapp, N2PLL + * Copyright (C) 2024-2025 Bryan Biedenkapp, N2PLL * */ #include "common/p25/dfsi/frames/fsc/FSCHeartbeat.h" @@ -34,5 +34,5 @@ FSCHeartbeat::FSCHeartbeat() : FSCMessage() FSCHeartbeat::FSCHeartbeat(const uint8_t* data) : FSCMessage(data) { - decode(data); + /* stub */ } diff --git a/src/common/p25/dfsi/frames/fsc/FSCMessage.h b/src/common/p25/dfsi/frames/fsc/FSCMessage.h index 1772c86c..2b5b6252 100644 --- a/src/common/p25/dfsi/frames/fsc/FSCMessage.h +++ b/src/common/p25/dfsi/frames/fsc/FSCMessage.h @@ -82,7 +82,7 @@ namespace p25 /** * @brief */ - __PROTECTED_READONLY_PROPERTY(uint8_t, correlationTag, CorrelationTag); + __PROPERTY(uint8_t, correlationTag, CorrelationTag); }; } // namespace fsc } // namespace frames diff --git a/src/host/Host.Config.cpp b/src/host/Host.Config.cpp index 67a5a536..4f8318ad 100644 --- a/src/host/Host.Config.cpp +++ b/src/host/Host.Config.cpp @@ -7,7 +7,7 @@ * @package DVM / Modem Host Software * @license GPLv2 License (https://opensource.org/licenses/GPL-2.0) * -* Copyright (C) 2017-2024 Bryan Biedenkapp, N2PLL +* Copyright (C) 2017-2025 Bryan Biedenkapp, N2PLL * */ #include "Defines.h" @@ -461,8 +461,9 @@ bool Host::createModem() bool rtrt = dfsiParams["rtrt"].as(true); bool diu = dfsiParams["diu"].as(true); uint16_t jitter = dfsiParams["jitter"].as(200U); - bool useFSCForUDP = dfsiParams["useFSC"].as(false); uint16_t dfsiCallTimeout = dfsiParams["callTimeout"].as(200U); + bool useFSCForUDP = dfsiParams["fsc"].as(false); + bool fscInitiator = dfsiParams["initiator"].as(false); // clamp fifo sizes if (dmrFifoLength < DMR_TX_BUFFER_LEN) { @@ -580,6 +581,7 @@ bool Host::createModem() LogInfo(" DFSI Jitter Size: %u ms", jitter); if (g_remoteModemMode) { LogInfo(" DFSI Use FSC: %s", useFSCForUDP ? "yes" : "no"); + LogInfo(" DFSI FSC Initiator: %s", fscInitiator ? "yes" : "no"); } } @@ -594,9 +596,10 @@ bool Host::createModem() if (modemMode == MODEM_MODE_DFSI) { yaml::Node networkConf = m_conf["network"]; uint32_t id = networkConf["id"].as(1000U); - modemPort = new port::specialized::V24UDPPort(id, g_remoteAddress, g_remotePort, 0U, useFSCForUDP, debug); if (useFSCForUDP) { - modemPort = new port::specialized::V24UDPPort(id, g_remoteAddress, g_remotePort + 1U, g_remotePort, useFSCForUDP, debug); + modemPort = new port::specialized::V24UDPPort(id, g_remoteAddress, g_remotePort + 1U, g_remotePort, true, fscInitiator, debug); + } else { + modemPort = new port::specialized::V24UDPPort(id, g_remoteAddress, g_remotePort, 0U, false, false, debug); } m_udpDSFIRemotePort = modemPort; } else { diff --git a/src/host/modem/port/specialized/V24UDPPort.cpp b/src/host/modem/port/specialized/V24UDPPort.cpp index 2a875319..941fb529 100644 --- a/src/host/modem/port/specialized/V24UDPPort.cpp +++ b/src/host/modem/port/specialized/V24UDPPort.cpp @@ -50,7 +50,7 @@ std::mutex V24UDPPort::m_bufferMutex; /* Initializes a new instance of the V24UDPPort class. */ -V24UDPPort::V24UDPPort(uint32_t peerId, const std::string& address, uint16_t modemPort, uint16_t controlPort, bool useFSC, bool debug) : +V24UDPPort::V24UDPPort(uint32_t peerId, const std::string& address, uint16_t modemPort, uint16_t controlPort, bool useFSC, bool fscInitiator, bool debug) : m_socket(nullptr), m_localPort(modemPort), m_controlSocket(nullptr), @@ -61,6 +61,8 @@ V24UDPPort::V24UDPPort(uint32_t peerId, const std::string& address, uint16_t mod m_addrLen(0U), m_ctrlAddrLen(0U), m_buffer(2000U, "UDP Port Ring Buffer"), + m_fscInitiator(fscInitiator), + m_timeoutTimer(1000U, 30U), m_reqConnectionTimer(1000U, 30U), m_heartbeatTimer(1000U, 5U), m_reqConnectionToPeer(true), @@ -120,7 +122,7 @@ void V24UDPPort::clock(uint32_t ms) { // if we have a FSC control socket if (m_controlSocket != nullptr) { - if (m_reqConnectionToPeer) { + if (!m_establishedConnection && m_fscInitiator) { if (!m_reqConnectionTimer.isRunning()) { // make initial request writeConnect(); @@ -130,6 +132,7 @@ void V24UDPPort::clock(uint32_t ms) if (m_reqConnectionTimer.isRunning() && m_reqConnectionTimer.hasExpired()) { // make another request writeConnect(); + m_reqConnectionTimer.start(); } } } @@ -142,6 +145,16 @@ void V24UDPPort::clock(uint32_t ms) } } + m_timeoutTimer.clock(ms); + if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) { + LogError(LOG_NET, "PEER %u connection to the DFSI endpoint has timed out, disconnected"); + m_reqConnectionTimer.stop(); + m_reqConnectionToPeer = true; + m_establishedConnection = false; + m_heartbeatTimer.stop(); + m_timeoutTimer.stop(); + } + processCtrlNetwork(); } @@ -268,7 +281,7 @@ void V24UDPPort::processCtrlNetwork() // read message UInt8Array buffer = m_ctrlFrameQueue->read(length, address, addrLen); if (length > 0) { - if (m_debug) + //if (m_debug) Utils::dump(1U, "FSC Control Network Message", buffer.get(), length); V24PacketRequest* req = new V24PacketRequest(); @@ -299,6 +312,8 @@ void* V24UDPPort::threadedCtrlNetworkRx(void* arg) ::pthread_detach(req->thread); #endif // defined(_WIN32) + uint64_t now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + V24UDPPort* network = static_cast(req->obj); if (network == nullptr) { delete req; @@ -306,7 +321,7 @@ void* V24UDPPort::threadedCtrlNetworkRx(void* arg) } if (req->length > 0) { - if (network->m_reqConnectionToPeer) { + if (network->m_reqConnectionToPeer && !network->m_establishedConnection) { // FSC_CONNECT response -- is ... strange if (req->buffer[0] == 1U) { network->m_reqConnectionToPeer = false; @@ -319,91 +334,100 @@ void* V24UDPPort::threadedCtrlNetworkRx(void* arg) network->m_localPort = vcBasePort; network->createVCPort(vcBasePort); network->m_heartbeatTimer.start(); + network->m_timeoutTimer.start(); - uint8_t buffer[FSCConnectResponse::LENGTH]; - ::memset(buffer, 0x00U, FSCConnectResponse::LENGTH); - - resp.setVCBasePort(network->m_localPort); - resp.encode(buffer); + LogMessage(LOG_MODEM, "Established DFSI FSC Connection, vcBasePort = %u", vcBasePort); - network->m_ctrlFrameQueue->write(buffer, FSCConnectResponse::LENGTH, network->m_controlAddr, network->m_ctrlAddrLen); + if (req->buffer != nullptr) + delete[] req->buffer; + delete req; + return nullptr; } } - else - { - std::unique_ptr message = FSCMessage::createMessage(req->buffer); - if (message != nullptr) { - switch (message->getMessageId()) - { - case FSCMessageType::FSC_ACK: + + std::unique_ptr message = FSCMessage::createMessage(req->buffer); + if (message != nullptr) { + switch (message->getMessageId()) + { + case FSCMessageType::FSC_ACK: + { + FSCACK* ackMessage = static_cast(message.get()); + switch (ackMessage->getResponseCode()) { - FSCACK* ackMessage = static_cast(message.get()); - switch (ackMessage->getResponseCode()) - { - case FSCAckResponseCode::CONTROL_NAK: - case FSCAckResponseCode::CONTROL_NAK_CONNECTED: - case FSCAckResponseCode::CONTROL_NAK_M_UNSUPP: - case FSCAckResponseCode::CONTROL_NAK_V_UNSUPP: - case FSCAckResponseCode::CONTROL_NAK_F_UNSUPP: - case FSCAckResponseCode::CONTROL_NAK_PARMS: - case FSCAckResponseCode::CONTROL_NAK_BUSY: - LogError(LOG_MODEM, "V.24 UDP, ACK, ackMessageId = $%02X, ackResponseCode = $%02X", ackMessage->getAckMessageId(), ackMessage->getResponseCode()); - break; - - case FSCAckResponseCode::CONTROL_ACK: - { - if (ackMessage->getAckMessageId() == FSCMessageType::FSC_DISCONNECT) { - network->m_reqConnectionTimer.stop(); - network->m_reqConnectionToPeer = false; - network->m_establishedConnection = false; - network->m_heartbeatTimer.stop(); - } + case FSCAckResponseCode::CONTROL_NAK: + case FSCAckResponseCode::CONTROL_NAK_CONNECTED: + case FSCAckResponseCode::CONTROL_NAK_M_UNSUPP: + case FSCAckResponseCode::CONTROL_NAK_V_UNSUPP: + case FSCAckResponseCode::CONTROL_NAK_F_UNSUPP: + case FSCAckResponseCode::CONTROL_NAK_PARMS: + case FSCAckResponseCode::CONTROL_NAK_BUSY: + LogError(LOG_MODEM, "V.24 UDP, ACK, ackMessageId = $%02X, ackResponseCode = $%02X", ackMessage->getAckMessageId(), ackMessage->getResponseCode()); + break; + + case FSCAckResponseCode::CONTROL_ACK: + { + if (ackMessage->getAckMessageId() == FSCMessageType::FSC_DISCONNECT) { + network->m_reqConnectionTimer.stop(); + network->m_reqConnectionToPeer = true; + network->m_establishedConnection = false; + network->m_heartbeatTimer.stop(); + network->m_timeoutTimer.stop(); } - break; + } + break; - default: - LogError(LOG_MODEM, "V.24 UDP, unknown ACK opcode, ackMessageId = $%02X", ackMessage->getAckMessageId()); - break; - } + default: + LogError(LOG_MODEM, "V.24 UDP, unknown ACK opcode, ackMessageId = $%02X", ackMessage->getAckMessageId()); + break; + } + } + break; + + case FSCMessageType::FSC_CONNECT: + { + if (network->m_socket != nullptr) { + network->m_socket->close(); + delete network->m_socket; } - break; - case FSCMessageType::FSC_CONNECT: - { - network->createVCPort(network->m_localPort); - network->m_heartbeatTimer.start(); + network->createVCPort(network->m_localPort); - uint8_t buffer[FSCConnectResponse::LENGTH]; - ::memset(buffer, 0x00U, FSCConnectResponse::LENGTH); + network->m_reqConnectionToPeer = false; + network->m_reqConnectionTimer.stop(); + network->m_establishedConnection = true; + network->m_heartbeatTimer.start(); + network->m_timeoutTimer.start(); - FSCConnectResponse resp = FSCConnectResponse(req->buffer); - resp.setVCBasePort(network->m_localPort); - resp.encode(buffer); + LogMessage(LOG_MODEM, "Incoming DFSI FSC Connection, vcBasePort = %u", network->m_localPort); - network->m_ctrlFrameQueue->write(buffer, FSCConnectResponse::LENGTH, network->m_controlAddr, network->m_ctrlAddrLen); - } - break; + uint8_t buffer[FSCConnectResponse::LENGTH]; + ::memset(buffer, 0x00U, FSCConnectResponse::LENGTH); - case FSCMessageType::FSC_DISCONNECT: - { - network->m_reqConnectionTimer.stop(); - network->m_reqConnectionToPeer = false; - network->m_establishedConnection = false; - network->m_heartbeatTimer.stop(); - } - break; + FSCConnectResponse resp = FSCConnectResponse(); + resp.setVCBasePort(network->m_localPort); + resp.encode(buffer); - case FSCMessageType::FSC_HEARTBEAT: - { - if (network->m_establishedConnection) { - network->writeHeartbeat(); - } - } - break; + network->m_ctrlFrameQueue->write(buffer, FSCConnectResponse::LENGTH, network->m_controlAddr, network->m_ctrlAddrLen); + } + break; + + case FSCMessageType::FSC_DISCONNECT: + { + LogMessage(LOG_MODEM, "DFSI FSC Disconnect"); + network->m_reqConnectionTimer.stop(); + network->m_reqConnectionToPeer = true; + network->m_establishedConnection = false; + network->m_heartbeatTimer.stop(); + network->m_timeoutTimer.stop(); + } + break; - default: - break; - } + case FSCMessageType::FSC_HEARTBEAT: + network->m_timeoutTimer.start(); + break; + + default: + break; } } } @@ -536,6 +560,8 @@ void V24UDPPort::createVCPort(uint16_t port) void V24UDPPort::writeConnect() { + LogMessage(LOG_MODEM, "Attempting DFSI FSC Connection, peerId = %u, vcBasePort = %u", m_peerId, m_localPort); + FSCConnect connect = FSCConnect(); connect.setFSHeartbeatPeriod(5U); // hardcoded? connect.setHostHeartbeatPeriod(5U); // hardcoded? diff --git a/src/host/modem/port/specialized/V24UDPPort.h b/src/host/modem/port/specialized/V24UDPPort.h index 808c32ab..6b2d8392 100644 --- a/src/host/modem/port/specialized/V24UDPPort.h +++ b/src/host/modem/port/specialized/V24UDPPort.h @@ -72,9 +72,10 @@ namespace modem * @param modemPort Port number. * @param controlPort Control Port number. * @param useFSC Flag indicating whether or not FSC handshakes are used to setup communications. + * @param fscInitiator Flag indicating whether or not the FSC handshake should be initiated when the port is opened. * @param debug Flag indicating whether network debug is enabled. */ - V24UDPPort(uint32_t peerId, const std::string& modemAddress, uint16_t modemPort, uint16_t controlPort = 0U, bool useFSC = false, bool debug = false); + V24UDPPort(uint32_t peerId, const std::string& modemAddress, uint16_t modemPort, uint16_t controlPort = 0U, bool useFSC = false, bool fscInitiator = false, bool debug = false); /** * @brief Finalizes a instance of the V24UDPPort class. */ @@ -132,6 +133,10 @@ namespace modem RingBuffer m_buffer; + bool m_fscInitiator; + + Timer m_timeoutTimer; + Timer m_reqConnectionTimer; Timer m_heartbeatTimer;