fix long standing dvmhost shutdown bug (object cleanup wasn't occuring due to bad state change handling); refactor FSC packet data classes; remove FSCResponse and FSCConnectResponse (these were ill conceived due to bad interpretation of TIA-102 specifications); correct FSCACK not properly decoding response user data after packet data; refactor the way the FSC message factory createMessage() function created instances of FSC packets; refactor how opening and closing the FSC port is handled; better implement the FSC state machine; correct bad response to an FSC_CONNECT (due to incorrect understanding of TIA-102 specifications);

82-dvmbridge---implement-notch-filter-for-2175hz-trc-guard-tone
Bryan Biedenkapp 1 year ago
parent ff0a5c57c7
commit da3a2a1869

@ -30,10 +30,8 @@
// FSC // FSC
#include "common/p25/dfsi/frames/fsc/FSCMessage.h" #include "common/p25/dfsi/frames/fsc/FSCMessage.h"
#include "common/p25/dfsi/frames/fsc/FSCResponse.h"
#include "common/p25/dfsi/frames/fsc/FSCACK.h" #include "common/p25/dfsi/frames/fsc/FSCACK.h"
#include "common/p25/dfsi/frames/fsc/FSCConnect.h" #include "common/p25/dfsi/frames/fsc/FSCConnect.h"
#include "common/p25/dfsi/frames/fsc/FSCConnectResponse.h"
#include "common/p25/dfsi/frames/fsc/FSCDisconnect.h" #include "common/p25/dfsi/frames/fsc/FSCDisconnect.h"
#include "common/p25/dfsi/frames/fsc/FSCHeartbeat.h" #include "common/p25/dfsi/frames/fsc/FSCHeartbeat.h"

@ -35,18 +35,6 @@ FSCACK::FSCACK() : FSCMessage(),
m_messageId = FSCMessageType::FSC_ACK; m_messageId = FSCMessageType::FSC_ACK;
} }
/* Initializes a instance of the FSCACK class. */
FSCACK::FSCACK(const uint8_t* data) : FSCMessage(data),
m_ackMessageId(FSCMessageType::FSC_INVALID),
m_ackVersion(1U),
m_ackCorrelationTag(0U),
m_responseCode(FSCAckResponseCode::CONTROL_ACK),
m_respLength(0U)
{
FSCACK::decode(data);
}
/* Decode a FSC ACK frame. */ /* Decode a FSC ACK frame. */
bool FSCACK::decode(const uint8_t* data) bool FSCACK::decode(const uint8_t* data)
@ -65,7 +53,7 @@ bool FSCACK::decode(const uint8_t* data)
delete responseData; delete responseData;
responseData = new uint8_t[m_respLength]; responseData = new uint8_t[m_respLength];
::memset(responseData, 0x00U, m_respLength); ::memset(responseData, 0x00U, m_respLength);
::memcpy(responseData, data, m_respLength); ::memcpy(responseData, data + 7U, m_respLength);
} }
else { else {
if (responseData != nullptr) if (responseData != nullptr)
@ -90,6 +78,6 @@ void FSCACK::encode(uint8_t* data)
data[6U] = m_respLength; // Response Data Length data[6U] = m_respLength; // Response Data Length
if (m_respLength > 0U && responseData != nullptr) { if (m_respLength > 0U && responseData != nullptr) {
::memcpy(data, responseData, m_respLength); ::memcpy(data + 7U, responseData, m_respLength);
} }
} }

@ -41,17 +41,12 @@ namespace p25
*/ */
class HOST_SW_API FSCACK : public FSCMessage { class HOST_SW_API FSCACK : public FSCMessage {
public: public:
static const uint8_t LENGTH = 6; static const uint8_t LENGTH = 7U;
/** /**
* @brief Initializes a copy instance of the FSCACK class. * @brief Initializes a copy instance of the FSCACK class.
*/ */
FSCACK(); FSCACK();
/**
* @brief Initializes a copy instance of the FSCACK class.
* @param data Buffer to containing FSCACK to decode.
*/
FSCACK(const uint8_t* data);
/** /**
* @brief Decode a FSC ACK frame. * @brief Decode a FSC ACK frame.
@ -78,7 +73,7 @@ namespace p25
/** /**
* @brief * @brief
*/ */
__READONLY_PROPERTY(uint8_t, ackCorrelationTag, AckCorrelationTag); __PROPERTY(uint8_t, ackCorrelationTag, AckCorrelationTag);
/** /**
* @brief Response code. * @brief Response code.
*/ */

@ -34,17 +34,6 @@ FSCConnect::FSCConnect() : FSCMessage(),
m_messageId = FSCMessageType::FSC_CONNECT; m_messageId = FSCMessageType::FSC_CONNECT;
} }
/* Initializes a instance of the FSCConnect class. */
FSCConnect::FSCConnect(const uint8_t* data) : FSCMessage(data),
m_vcBasePort(0U),
m_vcSSRC(0U),
m_fsHeartbeatPeriod(5U),
m_hostHeartbeatPeriod(5U)
{
FSCConnect::decode(data);
}
/* Decode a FSC connect frame. */ /* Decode a FSC connect frame. */
bool FSCConnect::decode(const uint8_t* data) bool FSCConnect::decode(const uint8_t* data)

@ -41,17 +41,12 @@ namespace p25
*/ */
class HOST_SW_API FSCConnect : public FSCMessage { class HOST_SW_API FSCConnect : public FSCMessage {
public: public:
static const uint8_t LENGTH = 11; static const uint8_t LENGTH = 11U;
/** /**
* @brief Initializes a copy instance of the FSCConnect class. * @brief Initializes a copy instance of the FSCConnect class.
*/ */
FSCConnect(); FSCConnect();
/**
* @brief Initializes a copy instance of the FSCConnect class.
* @param data Buffer to containing FSCConnect to decode.
*/
FSCConnect(const uint8_t* data);
/** /**
* @brief Decode a FSC connect frame. * @brief Decode a FSC connect frame.

@ -1,62 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Common Library
* 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
*
*/
#include "common/p25/dfsi/frames/fsc/FSCConnectResponse.h"
#include "common/p25/dfsi/DFSIDefines.h"
#include "common/Utils.h"
#include "common/Log.h"
#include <cassert>
#include <cstring>
using namespace p25::dfsi;
using namespace p25::dfsi::frames;
using namespace p25::dfsi::frames::fsc;
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a instance of the FSCConnectResponse class. */
FSCConnectResponse::FSCConnectResponse() : FSCResponse(),
m_vcBasePort(0U)
{
/* stub */
}
/* Initializes a instance of the FSCConnectResponse class. */
FSCConnectResponse::FSCConnectResponse(const uint8_t* data) : FSCResponse(data),
m_vcBasePort(0U)
{
FSCConnectResponse::decode(data);
}
/* Decode a FSC connect frame. */
bool FSCConnectResponse::decode(const uint8_t* data)
{
assert(data != nullptr);
FSCResponse::decode(data);
m_vcBasePort = __GET_UINT16B(data, 1U); // Voice Conveyance RTP Port
return true;
}
/* Encode a FSC connect frame. */
void FSCConnectResponse::encode(uint8_t* data)
{
assert(data != nullptr);
FSCResponse::encode(data);
__SET_UINT16B(m_vcBasePort, data, 1U); // Voice Conveyance RTP Port
}

@ -1,78 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Common Library
* 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
*
*/
/**
* @file FSCConnectResponse.h
* @ingroup dfsi_fsc_frames
* @file FSCConnectResponse.cpp
* @ingroup dfsi_fsc_frames
*/
#if !defined(__FSC_CONNECT_RESPONSE_H__)
#define __FSC_CONNECT_RESPONSE_H__
#include "Defines.h"
#include "common/Defines.h"
#include "common/Log.h"
#include "common/Utils.h"
#include "common/p25/dfsi/frames/FrameDefines.h"
#include "common/p25/dfsi/frames/fsc/FSCResponse.h"
namespace p25
{
namespace dfsi
{
namespace frames
{
namespace fsc
{
// ---------------------------------------------------------------------------
// Class Declaration
// ---------------------------------------------------------------------------
/**
* @brief Implements the FSC Connect Response Message.
* @ingroup dfsi_fsc_frames
*/
class HOST_SW_API FSCConnectResponse : public FSCResponse {
public:
static const uint8_t LENGTH = 3;
/**
* @brief Initializes a copy instance of the FSCConnectResponse class.
*/
FSCConnectResponse();
/**
* @brief Initializes a copy instance of the FSCConnectResponse class.
* @param data Buffer to containing FSCConnectResponse to decode.
*/
FSCConnectResponse(const uint8_t* data);
/**
* @brief Decode a FSC connect response frame.
* @param[in] data Buffer to containing FSCConnectResponse to decode.
*/
bool decode(const uint8_t* data) override;
/**
* @brief Encode a FSC connect response frame.
* @param[out] data Buffer to encode a FSCConnectResponse.
*/
void encode(uint8_t* data) override;
public:
/**
* @brief Voice Conveyance RTP Port.
*/
__PROPERTY(uint16_t, vcBasePort, VCBasePort);
};
} // namespace fsc
} // namespace frames
} // namespace dfsi
} // namespace p25
#endif // __FSC_CONNECT_RESPONSE_H__

@ -29,10 +29,3 @@ FSCDisconnect::FSCDisconnect() : FSCMessage()
{ {
m_messageId = FSCMessageType::FSC_DISCONNECT; m_messageId = FSCMessageType::FSC_DISCONNECT;
} }
/* Initializes a instance of the FSCDisconnect class. */
FSCDisconnect::FSCDisconnect(const uint8_t* data) : FSCMessage(data)
{
FSCMessage::decode(data);
}

@ -41,17 +41,12 @@ namespace p25
*/ */
class HOST_SW_API FSCDisconnect : public FSCMessage { class HOST_SW_API FSCDisconnect : public FSCMessage {
public: public:
static const uint8_t LENGTH = 3; static const uint8_t LENGTH = 3U;
/** /**
* @brief Initializes a copy instance of the FSCDisconnect class. * @brief Initializes a copy instance of the FSCDisconnect class.
*/ */
FSCDisconnect(); FSCDisconnect();
/**
* @brief Initializes a copy instance of the FSCDisconnect class.
* @param data Buffer to containing FSCDisconnect to decode.
*/
FSCDisconnect(const uint8_t* data);
}; };
} // namespace fsc } // namespace fsc
} // namespace frames } // namespace frames

@ -29,10 +29,3 @@ FSCHeartbeat::FSCHeartbeat() : FSCMessage()
{ {
m_messageId = FSCMessageType::FSC_HEARTBEAT; m_messageId = FSCMessageType::FSC_HEARTBEAT;
} }
/* Initializes a instance of the FSCHeartbeat class. */
FSCHeartbeat::FSCHeartbeat(const uint8_t* data) : FSCMessage(data)
{
/* stub */
}

@ -41,17 +41,12 @@ namespace p25
*/ */
class HOST_SW_API FSCHeartbeat : public FSCMessage { class HOST_SW_API FSCHeartbeat : public FSCMessage {
public: public:
static const uint8_t LENGTH = 3; static const uint8_t LENGTH = 3U;
/** /**
* @brief Initializes a copy instance of the FSCHeartbeat class. * @brief Initializes a copy instance of the FSCHeartbeat class.
*/ */
FSCHeartbeat(); FSCHeartbeat();
/**
* @brief Initializes a copy instance of the FSCHeartbeat class.
* @param data Buffer to containing FSCHeartbeat to decode.
*/
FSCHeartbeat(const uint8_t* data);
}; };
} // namespace fsc } // namespace fsc
} // namespace frames } // namespace frames

@ -29,21 +29,11 @@ using namespace p25::dfsi::frames::fsc;
FSCMessage::FSCMessage() : FSCMessage::FSCMessage() :
m_messageId(FSCMessageType::FSC_INVALID), m_messageId(FSCMessageType::FSC_INVALID),
m_version(1U), m_version(1U),
m_correlationTag(0U) m_correlationTag(1U)
{ {
/* stub */ /* stub */
} }
/* Initializes a instance of the FSCMessage class. */
FSCMessage::FSCMessage(const uint8_t* data) :
m_messageId(FSCMessageType::FSC_INVALID),
m_version(1U),
m_correlationTag(0U)
{
decode(data);
}
/* Decode a FSC message frame. */ /* Decode a FSC message frame. */
bool FSCMessage::decode(const uint8_t* data) bool FSCMessage::decode(const uint8_t* data)
@ -78,25 +68,32 @@ std::unique_ptr<FSCMessage> FSCMessage::createMessage(const uint8_t* data)
{ {
assert(data != nullptr); assert(data != nullptr);
uint8_t msg[FSCMessage::LENGTH + 1U]; uint8_t messageId = (FSCMessageType::E)(data[0U]); // Message ID
::memset(msg, 0x00U, FSCMessage::LENGTH);
uint8_t messageId = (FSCMessageType::E)(msg[0U]); // Message ID FSCMessage* message = nullptr;
// standard P25 reference opcodes // standard P25 reference opcodes
switch (messageId) { switch (messageId) {
case FSCMessageType::FSC_CONNECT: case FSCMessageType::FSC_CONNECT:
return std::unique_ptr<FSCMessage>(new FSCConnect(data)); message = new FSCConnect();
break;
case FSCMessageType::FSC_HEARTBEAT: case FSCMessageType::FSC_HEARTBEAT:
return std::unique_ptr<FSCMessage>(new FSCHeartbeat(data)); message = new FSCHeartbeat();
break;
case FSCMessageType::FSC_ACK: case FSCMessageType::FSC_ACK:
return std::unique_ptr<FSCMessage>(new FSCACK(data)); message = new FSCACK();
break;
case FSCMessageType::FSC_DISCONNECT: case FSCMessageType::FSC_DISCONNECT:
return std::unique_ptr<FSCMessage>(new FSCDisconnect(data)); message = new FSCDisconnect();
break;
default: default:
LogError(LOG_P25, "FSCMessage::create(), unknown message value, messageId = $%02X", messageId); LogError(LOG_P25, "FSCMessage::createMessage(), unknown message value, messageId = $%02X", messageId);
break; break;
} }
return nullptr; if (!message->decode(data)) {
return nullptr;
}
return std::unique_ptr<FSCMessage>(message);
} }

@ -46,11 +46,6 @@ namespace p25
* @brief Initializes a copy instance of the FSCMessage class. * @brief Initializes a copy instance of the FSCMessage class.
*/ */
FSCMessage(); FSCMessage();
/**
* @brief Initializes a copy instance of the FSCMessage class.
* @param data Buffer to containing FSCMessage to decode.
*/
FSCMessage(const uint8_t* data);
/** /**
* @brief Decode a FSC message frame. * @brief Decode a FSC message frame.

@ -1,60 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Common Library
* 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
*
*/
#include "common/p25/dfsi/frames/fsc/FSCResponse.h"
#include "common/p25/dfsi/DFSIDefines.h"
#include "common/Utils.h"
#include "common/Log.h"
#include <cassert>
#include <cstring>
using namespace p25::dfsi;
using namespace p25::dfsi::frames;
using namespace p25::dfsi::frames::fsc;
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a instance of the FSCResponse class. */
FSCResponse::FSCResponse() :
m_version(1U)
{
/* stub */
}
/* Initializes a instance of the FSCResponse class. */
FSCResponse::FSCResponse(const uint8_t* data) :
m_version(1U)
{
decode(data);
}
/* Decode a FSC message frame. */
bool FSCResponse::decode(const uint8_t* data)
{
assert(data != nullptr);
m_version = data[0U]; // Response Version
return true;
}
/* Encode a FSC message frame. */
void FSCResponse::encode(uint8_t* data)
{
assert(data != nullptr);
data[0U] = m_version; // Response Version
}

@ -1,77 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Common Library
* 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
*
*/
/**
* @file FSCResponse.h
* @ingroup dfsi_fsc_frames
* @file FSCResponse.cpp
* @ingroup dfsi_fsc_frames
*/
#if !defined(__FSC_RESPONSE_H__)
#define __FSC_RESPONSE_H__
#include "Defines.h"
#include "common/Defines.h"
#include "common/Log.h"
#include "common/Utils.h"
#include "common/p25/dfsi/frames/FrameDefines.h"
namespace p25
{
namespace dfsi
{
namespace frames
{
namespace fsc
{
// ---------------------------------------------------------------------------
// Class Declaration
// ---------------------------------------------------------------------------
/**
* @brief Base class FSC response messages derive from.
* @ingroup dfsi_fsc_frames
*/
class HOST_SW_API FSCResponse {
public:
static const uint8_t LENGTH = 1;
/**
* @brief Initializes a copy instance of the FSCResponse class.
*/
FSCResponse();
/**
* @brief Initializes a copy instance of the FSCResponse class.
* @param data Buffer to containing FSCResponse to decode.
*/
FSCResponse(const uint8_t* data);
/**
* @brief Decode a FSC message frame.
* @param[in] data Buffer to containing FSCResponse to decode.
*/
virtual bool decode(const uint8_t* data);
/**
* @brief Encode a FSC message frame.
* @param[out] data Buffer to encode a FSCResponse.
*/
virtual void encode(uint8_t* data);
public:
/**
* @brief Response Version.
*/
__PROTECTED_READONLY_PROPERTY(uint8_t, version, Version);
};
} // namespace fsc
} // namespace frames
} // namespace dfsi
} // namespace p25
#endif // __FSC_RESPONSE_H__

@ -601,7 +601,7 @@ bool Host::createModem()
} else { } else {
modemPort = new port::specialized::V24UDPPort(id, g_remoteAddress, g_remotePort, 0U, false, false, debug); modemPort = new port::specialized::V24UDPPort(id, g_remoteAddress, g_remotePort, 0U, false, false, debug);
} }
m_udpDSFIRemotePort = modemPort; m_udpDFSIRemotePort = modemPort;
} else { } else {
modemPort = new port::UDPPort(g_remoteAddress, g_remotePort); modemPort = new port::UDPPort(g_remoteAddress, g_remotePort);
} }
@ -687,6 +687,11 @@ bool Host::createModem()
m_modem->setResponseHandler(MODEM_RESP_HANDLER_BIND(Host::rmtPortModemHandler, this)); m_modem->setResponseHandler(MODEM_RESP_HANDLER_BIND(Host::rmtPortModemHandler, this));
} }
if (useFSCForUDP) {
modem::port::specialized::V24UDPPort* udpPort = dynamic_cast<modem::port::specialized::V24UDPPort*>(m_udpDFSIRemotePort);
udpPort->openFSC();
}
bool ret = m_modem->open(); bool ret = m_modem->open();
if (!ret) { if (!ret) {
delete m_modem; delete m_modem;

@ -64,7 +64,7 @@ Host::Host(const std::string& confFile) :
m_modem(nullptr), m_modem(nullptr),
m_modemRemote(false), m_modemRemote(false),
m_isModemDFSI(false), m_isModemDFSI(false),
m_udpDSFIRemotePort(nullptr), m_udpDFSIRemotePort(nullptr),
m_network(nullptr), m_network(nullptr),
m_modemRemotePort(nullptr), m_modemRemotePort(nullptr),
m_state(STATE_IDLE), m_state(STATE_IDLE),
@ -945,10 +945,9 @@ int Host::run()
} }
} }
if (m_udpDSFIRemotePort != nullptr) { if (m_udpDFSIRemotePort != nullptr) {
m_mainLoopStage = 11U; // intentional magic number m_mainLoopStage = 11U; // intentional magic number
modem::port::specialized::V24UDPPort* udpPort = dynamic_cast<modem::port::specialized::V24UDPPort*>(m_udpDSFIRemotePort); modem::port::specialized::V24UDPPort* udpPort = dynamic_cast<modem::port::specialized::V24UDPPort*>(m_udpDFSIRemotePort);
udpPort->clock(ms); udpPort->clock(ms);
} }
@ -1638,9 +1637,14 @@ void Host::setState(uint8_t state)
m_modeTimer.stop(); m_modeTimer.stop();
if (m_state == HOST_STATE_QUIT) { if (state == HOST_STATE_QUIT) {
::LogInfoEx(LOG_HOST, "Host is shutting down"); ::LogInfoEx(LOG_HOST, "Host is shutting down");
if (m_udpDFSIRemotePort != nullptr) {
modem::port::specialized::V24UDPPort* udpPort = dynamic_cast<modem::port::specialized::V24UDPPort*>(m_udpDFSIRemotePort);
udpPort->closeFSC();
}
if (m_modem != nullptr) { if (m_modem != nullptr) {
m_modem->close(); m_modem->close();
delete m_modem; delete m_modem;

@ -99,7 +99,7 @@ private:
modem::Modem* m_modem; modem::Modem* m_modem;
bool m_modemRemote; bool m_modemRemote;
bool m_isModemDFSI; bool m_isModemDFSI;
modem::port::IModemPort* m_udpDSFIRemotePort; modem::port::IModemPort* m_udpDFSIRemotePort;
network::Network* m_network; network::Network* m_network;
modem::port::IModemPort* m_modemRemotePort; modem::port::IModemPort* m_modemRemotePort;

@ -65,13 +65,12 @@ V24UDPPort::V24UDPPort(uint32_t peerId, const std::string& address, uint16_t mod
m_timeoutTimer(1000U, 30U), m_timeoutTimer(1000U, 30U),
m_reqConnectionTimer(1000U, 30U), m_reqConnectionTimer(1000U, 30U),
m_heartbeatTimer(1000U, 5U), m_heartbeatTimer(1000U, 5U),
m_reqConnectionToPeer(true),
m_establishedConnection(false),
m_random(), m_random(),
m_peerId(peerId), m_peerId(peerId),
m_streamId(0U), m_streamId(0U),
m_timestamp(INVALID_TS), m_timestamp(INVALID_TS),
m_pktSeq(0U), m_pktSeq(0U),
m_fscState(CS_NOT_CONNECTED),
m_modemState(STATE_P25), m_modemState(STATE_P25),
m_tx(false), m_tx(false),
m_debug(debug) m_debug(debug)
@ -122,7 +121,7 @@ void V24UDPPort::clock(uint32_t ms)
{ {
// if we have a FSC control socket // if we have a FSC control socket
if (m_controlSocket != nullptr) { if (m_controlSocket != nullptr) {
if (!m_establishedConnection && m_fscInitiator) { if ((m_fscState == CS_NOT_CONNECTED) && m_fscInitiator) {
if (!m_reqConnectionTimer.isRunning()) { if (!m_reqConnectionTimer.isRunning()) {
// make initial request // make initial request
writeConnect(); writeConnect();
@ -137,7 +136,7 @@ void V24UDPPort::clock(uint32_t ms)
} }
} }
if (m_establishedConnection) { if (m_fscState == CS_CONNECTED) {
m_heartbeatTimer.clock(ms); m_heartbeatTimer.clock(ms);
if (m_heartbeatTimer.isRunning() && m_heartbeatTimer.hasExpired()) { if (m_heartbeatTimer.isRunning() && m_heartbeatTimer.hasExpired()) {
writeHeartbeat(); writeHeartbeat();
@ -147,10 +146,12 @@ void V24UDPPort::clock(uint32_t ms)
m_timeoutTimer.clock(ms); m_timeoutTimer.clock(ms);
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) { if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
LogError(LOG_NET, "DFSI connection to the remote endpoint has timed out, disconnected"); LogError(LOG_NET, "V.24 UDP, DFSI connection to the remote endpoint has timed out, disconnected");
m_reqConnectionTimer.stop(); m_fscState = CS_NOT_CONNECTED;
m_reqConnectionToPeer = true; if (!m_fscInitiator)
m_establishedConnection = false; m_reqConnectionTimer.stop();
else
m_reqConnectionTimer.start();
m_heartbeatTimer.stop(); m_heartbeatTimer.stop();
m_timeoutTimer.stop(); m_timeoutTimer.stop();
} }
@ -170,18 +171,34 @@ void V24UDPPort::reset()
m_streamId = createStreamId(); m_streamId = createStreamId();
} }
/* Opens a connection to the port. */ /* Opens a connection to the FSC port. */
bool V24UDPPort::open() bool V24UDPPort::openFSC()
{ {
if (m_addrLen == 0U && m_ctrlAddrLen == 0U) { if (m_ctrlAddrLen == 0U) {
LogError(LOG_NET, "Unable to resolve the address of the modem"); LogError(LOG_NET, "Unable to resolve the address of the modem");
return false; return false;
} }
if (m_controlSocket != nullptr) { if (m_controlSocket != nullptr) {
return m_controlSocket->open(m_controlAddr); return m_controlSocket->open(m_controlAddr);
}
return false;
}
/* Opens a connection to the port. */
bool V24UDPPort::open()
{
if (m_controlSocket != nullptr) {
return true; // FSC mode always returns that the port was opened
} else { } else {
if (m_addrLen == 0U) {
LogError(LOG_NET, "Unable to resolve the address of the modem");
return false;
}
if (m_socket != nullptr) { if (m_socket != nullptr) {
return m_socket->open(m_addr); return m_socket->open(m_addr);
} }
@ -256,12 +273,33 @@ int V24UDPPort::write(const uint8_t* buffer, uint32_t length)
return -1; return -1;
} }
/* Closes the connection to the FSC port. */
void V24UDPPort::closeFSC()
{
if (m_controlSocket != nullptr) {
if (m_fscState == CS_CONNECTED) {
LogMessage(LOG_MODEM, "V.24 UDP, Closing DFSI FSC Connection, vcBasePort = %u", m_localPort);
FSCDisconnect discoMessage = FSCDisconnect();
uint8_t buffer[FSCDisconnect::LENGTH];
::memset(buffer, 0x00U, FSCDisconnect::LENGTH);
discoMessage.encode(buffer);
m_ctrlFrameQueue->write(buffer, FSCDisconnect::LENGTH, m_controlAddr, m_ctrlAddrLen);
Thread::sleep(500U);
}
m_controlSocket->close();
}
}
/* Closes the connection to the port. */ /* Closes the connection to the port. */
void V24UDPPort::close() void V24UDPPort::close()
{ {
if (m_controlSocket != nullptr)
m_controlSocket->close();
if (m_socket != nullptr) if (m_socket != nullptr)
m_socket->close(); m_socket->close();
} }
@ -319,108 +357,157 @@ void* V24UDPPort::threadedCtrlNetworkRx(void* arg)
} }
if (req->length > 0) { if (req->length > 0) {
if (network->m_reqConnectionToPeer && !network->m_establishedConnection) {
// FSC_CONNECT response -- is ... strange
if (req->buffer[0] == 1U) {
network->m_reqConnectionToPeer = false;
network->m_reqConnectionTimer.stop();
network->m_establishedConnection = true;
FSCConnectResponse resp = FSCConnectResponse(req->buffer);
uint16_t vcBasePort = resp.getVCBasePort();
network->m_localPort = vcBasePort;
network->createVCPort(vcBasePort);
network->m_socket->open(network->m_addr);
network->m_heartbeatTimer.start();
network->m_timeoutTimer.start();
LogMessage(LOG_MODEM, "Established DFSI FSC Connection, vcBasePort = %u", vcBasePort);
if (req->buffer != nullptr)
delete[] req->buffer;
delete req;
return nullptr;
}
}
std::unique_ptr<FSCMessage> message = FSCMessage::createMessage(req->buffer); std::unique_ptr<FSCMessage> message = FSCMessage::createMessage(req->buffer);
if (message != nullptr) { if (message != nullptr) {
switch (message->getMessageId()) switch (message->getMessageId()) {
{
case FSCMessageType::FSC_ACK: case FSCMessageType::FSC_ACK:
{ {
FSCACK* ackMessage = static_cast<FSCACK*>(message.get()); FSCACK* ackMessage = static_cast<FSCACK*>(message.get());
switch (ackMessage->getResponseCode()) if (network->m_debug)
LogDebug(LOG_MODEM, "V.24 UDP, ACK, ackMessageId = $%02X, ackResponseCode = $%02X, respLength = %u", ackMessage->getAckMessageId(), ackMessage->getResponseCode(), ackMessage->getResponseLength());
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:
{ {
case FSCAckResponseCode::CONTROL_NAK: switch (ackMessage->getAckMessageId()) {
case FSCAckResponseCode::CONTROL_NAK_CONNECTED: case FSCMessageType::FSC_CONNECT:
case FSCAckResponseCode::CONTROL_NAK_M_UNSUPP: {
case FSCAckResponseCode::CONTROL_NAK_V_UNSUPP: uint16_t vcBasePort = __GET_UINT16B(ackMessage->responseData, 1U);
case FSCAckResponseCode::CONTROL_NAK_F_UNSUPP:
case FSCAckResponseCode::CONTROL_NAK_PARMS: if (network->m_socket != nullptr) {
case FSCAckResponseCode::CONTROL_NAK_BUSY: network->m_socket->close();
LogError(LOG_MODEM, "V.24 UDP, ACK, ackMessageId = $%02X, ackResponseCode = $%02X", ackMessage->getAckMessageId(), ackMessage->getResponseCode()); delete network->m_socket;
network->m_socket = nullptr;
}
network->m_localPort = vcBasePort;
network->createVCPort(vcBasePort);
network->m_socket->open(network->m_addr);
network->m_fscState = CS_CONNECTED;
network->m_reqConnectionTimer.stop();
network->m_heartbeatTimer.start();
network->m_timeoutTimer.start();
LogMessage(LOG_MODEM, "V.24 UDP, Established DFSI FSC Connection, vcBasePort = %u", vcBasePort);
}
break; break;
case FSCAckResponseCode::CONTROL_ACK: case FSCMessageType::FSC_DISCONNECT:
{ {
if (ackMessage->getAckMessageId() == FSCMessageType::FSC_DISCONNECT) { if (network->m_socket != nullptr) {
network->m_reqConnectionTimer.stop(); network->m_socket->close();
network->m_reqConnectionToPeer = true; delete network->m_socket;
network->m_establishedConnection = false; network->m_socket = nullptr;
network->m_heartbeatTimer.stop();
network->m_timeoutTimer.stop();
} }
network->m_fscState = CS_NOT_CONNECTED;
if (!network->m_fscInitiator)
network->m_reqConnectionTimer.stop();
else
network->m_reqConnectionTimer.start();
network->m_heartbeatTimer.stop();
network->m_timeoutTimer.stop();
} }
break; break;
default: default:
LogError(LOG_MODEM, "V.24 UDP, unknown ACK opcode, ackMessageId = $%02X", ackMessage->getAckMessageId()); break;
break; }
} }
break;
default:
LogError(LOG_MODEM, "V.24 UDP, unknown ACK opcode, ackMessageId = $%02X", ackMessage->getAckMessageId());
break;
} }
break; }
break;
case FSCMessageType::FSC_CONNECT: case FSCMessageType::FSC_CONNECT:
{ {
if (network->m_socket != nullptr) { FSCConnect* connMessage = static_cast<FSCConnect*>(message.get());
network->m_socket->close(); FSCACK ackResp = FSCACK();
delete network->m_socket; ackResp.setCorrelationTag(connMessage->getCorrelationTag());
} ackResp.setAckMessageId(FSCMessageType::FSC_CONNECT);
ackResp.setResponseCode(FSCAckResponseCode::CONTROL_ACK);
ackResp.setAckCorrelationTag(connMessage->getCorrelationTag());
if (connMessage->getVersion() != 1U) {
ackResp.setResponseCode(FSCAckResponseCode::CONTROL_NAK_V_UNSUPP);
uint8_t buffer[FSCACK::LENGTH];
::memset(buffer, 0x00U, FSCACK::LENGTH);
ackResp.encode(buffer);
network->m_ctrlFrameQueue->write(buffer, FSCACK::LENGTH, network->m_controlAddr, network->m_ctrlAddrLen);
break;
}
if (network->m_socket != nullptr) {
network->m_socket->close();
delete network->m_socket;
network->m_socket = nullptr;
}
network->createVCPort(network->m_localPort); uint16_t vcPort = connMessage->getVCBasePort();
network->m_socket->open(network->m_addr); network->m_localPort = vcPort;
network->m_reqConnectionToPeer = false; network->createVCPort(network->m_localPort);
network->m_reqConnectionTimer.stop(); network->m_socket->open(network->m_addr);
network->m_establishedConnection = true;
network->m_heartbeatTimer.start();
network->m_timeoutTimer.start();
LogMessage(LOG_MODEM, "Incoming DFSI FSC Connection, vcBasePort = %u", network->m_localPort); network->m_fscState = CS_CONNECTED;
network->m_reqConnectionTimer.stop();
network->m_heartbeatTimer.start();
network->m_timeoutTimer.start();
uint8_t buffer[FSCConnectResponse::LENGTH]; LogMessage(LOG_MODEM, "V.24 UDP, Incoming DFSI FSC Connection, vcBasePort = %u", network->m_localPort);
::memset(buffer, 0x00U, FSCConnectResponse::LENGTH);
FSCConnectResponse resp = FSCConnectResponse(); // construct connect ACK response data
resp.setVCBasePort(network->m_localPort); uint8_t respData[3U];
resp.encode(buffer); ::memset(respData, 0x00U, 3U);
network->m_ctrlFrameQueue->write(buffer, FSCConnectResponse::LENGTH, network->m_controlAddr, network->m_ctrlAddrLen); respData[0U] = 1U; // Version 1
} __SET_UINT16B(network->m_localPort, respData, 1U);
break;
// pack ack
ackResp.setResponseLength(3U);
ackResp.responseData = respData;
uint8_t buffer[FSCACK::LENGTH + 3U];
::memset(buffer, 0x00U, FSCACK::LENGTH + 3U);
ackResp.encode(buffer);
network->m_ctrlFrameQueue->write(buffer, FSCACK::LENGTH + 3U, network->m_controlAddr, network->m_ctrlAddrLen);
}
break;
case FSCMessageType::FSC_DISCONNECT: case FSCMessageType::FSC_DISCONNECT:
{ {
LogMessage(LOG_MODEM, "DFSI FSC Disconnect"); LogMessage(LOG_MODEM, "V.24 UDP, DFSI FSC Disconnect, vcBasePort = %u", network->m_localPort);
network->m_reqConnectionTimer.stop();
network->m_reqConnectionToPeer = true; if (network->m_socket != nullptr) {
network->m_establishedConnection = false; network->m_socket->close();
network->m_heartbeatTimer.stop(); delete network->m_socket;
network->m_timeoutTimer.stop(); network->m_socket = nullptr;
} }
break;
network->m_fscState = CS_NOT_CONNECTED;
network->m_reqConnectionTimer.stop();
network->m_heartbeatTimer.stop();
network->m_timeoutTimer.stop();
}
break;
case FSCMessageType::FSC_HEARTBEAT: case FSCMessageType::FSC_HEARTBEAT:
network->m_timeoutTimer.start(); network->m_timeoutTimer.start();
@ -560,7 +647,7 @@ void V24UDPPort::createVCPort(uint16_t port)
void V24UDPPort::writeConnect() void V24UDPPort::writeConnect()
{ {
LogMessage(LOG_MODEM, "Attempting DFSI FSC Connection, peerId = %u, vcBasePort = %u", m_peerId, m_localPort); LogMessage(LOG_MODEM, "V.24 UDP, Attempting DFSI FSC Connection, peerId = %u, vcBasePort = %u", m_peerId, m_localPort);
FSCConnect connect = FSCConnect(); FSCConnect connect = FSCConnect();
connect.setFSHeartbeatPeriod(5U); // hardcoded? connect.setFSHeartbeatPeriod(5U); // hardcoded?
@ -573,6 +660,8 @@ void V24UDPPort::writeConnect()
connect.encode(buffer); connect.encode(buffer);
m_fscState = CS_CONNECTING;
m_ctrlFrameQueue->write(buffer, FSCConnect::LENGTH, m_controlAddr, m_ctrlAddrLen); m_ctrlFrameQueue->write(buffer, FSCConnect::LENGTH, m_controlAddr, m_ctrlAddrLen);
} }

@ -93,20 +93,25 @@ namespace modem
void reset(); void reset();
/** /**
* @brief Opens a connection to the serial port. * @brief Opens a connection to the FSC port.
* @returns bool True, if connection is opened, otherwise false.
*/
bool openFSC();
/**
* @brief Opens a connection to the port.
* @returns bool True, if connection is opened, otherwise false. * @returns bool True, if connection is opened, otherwise false.
*/ */
bool open() override; bool open() override;
/** /**
* @brief Reads data from the serial port. * @brief Reads data from the port.
* @param[out] buffer Buffer to read data from the port to. * @param[out] buffer Buffer to read data from the port to.
* @param length Length of data to read from the port. * @param length Length of data to read from the port.
* @returns int Actual length of data read from serial port. * @returns int Actual length of data read from serial port.
*/ */
int read(uint8_t* buffer, uint32_t length) override; int read(uint8_t* buffer, uint32_t length) override;
/** /**
* @brief Writes data to the serial port. * @brief Writes data to the port.
* @param[in] buffer Buffer containing data to write to port. * @param[in] buffer Buffer containing data to write to port.
* @param length Length of data to write to port. * @param length Length of data to write to port.
* @returns int Actual length of data written to the port. * @returns int Actual length of data written to the port.
@ -114,7 +119,11 @@ namespace modem
int write(const uint8_t* buffer, uint32_t length) override; int write(const uint8_t* buffer, uint32_t length) override;
/** /**
* @brief Closes the connection to the serial port. * @brief Closes the connection to the FSC port.
*/
void closeFSC();
/**
* @brief Closes the connection to the port.
*/ */
void close() override; void close() override;
@ -140,9 +149,6 @@ namespace modem
Timer m_reqConnectionTimer; Timer m_reqConnectionTimer;
Timer m_heartbeatTimer; Timer m_heartbeatTimer;
bool m_reqConnectionToPeer;
bool m_establishedConnection;
std::mt19937 m_random; std::mt19937 m_random;
uint32_t m_peerId; uint32_t m_peerId;
@ -151,6 +157,13 @@ namespace modem
uint32_t m_timestamp; uint32_t m_timestamp;
uint16_t m_pktSeq; uint16_t m_pktSeq;
enum CS_STATE : uint8_t {
CS_NOT_CONNECTED = 0,
CS_CONNECTING = 1,
CS_CONNECTED = 2
};
CS_STATE m_fscState;
uint8_t m_modemState; uint8_t m_modemState;
bool m_tx; bool m_tx;

Loading…
Cancel
Save

Powered by TurnKey Linux.