diff --git a/src/common/network/BaseNetwork.cpp b/src/common/network/BaseNetwork.cpp
index 6ffc6533..93afec03 100644
--- a/src/common/network/BaseNetwork.cpp
+++ b/src/common/network/BaseNetwork.cpp
@@ -12,7 +12,7 @@
//
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
-* Copyright (C) 2020-2023 by Bryan Biedenkapp N2PLL
+* Copyright (C) 2020-2024 by Bryan Biedenkapp N2PLL
*
* 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
@@ -30,6 +30,7 @@
*/
#include "Defines.h"
#include "common/dmr/DMRDefines.h"
+#include "common/nxdn/NXDNDefines.h"
#include "common/p25/dfsi/DFSIDefines.h"
#include "common/p25/dfsi/LC.h"
#include "edac/SHA256.h"
@@ -301,8 +302,9 @@ UInt8Array BaseNetwork::readDMR(bool& ret, uint32_t& frameLength)
/// Writes DMR frame data to the network.
///
///
+///
///
-bool BaseNetwork::writeDMR(const dmr::data::Data& data)
+bool BaseNetwork::writeDMR(const dmr::data::Data& data, bool noSequence)
{
if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING)
return false;
@@ -336,7 +338,16 @@ bool BaseNetwork::writeDMR(const dmr::data::Data& data)
return false;
}
- return writeMaster({ NET_FUNC_PROTOCOL, NET_PROTOCOL_SUBFUNC_DMR }, message.get(), messageLength, pktSeq(resetSeq), m_dmrStreamId[slotIndex]);
+ uint16_t seq = pktSeq(resetSeq);
+ if (dataType == dmr::DT_TERMINATOR_WITH_LC) {
+ seq = RTP_END_OF_CALL_SEQ;
+ }
+
+ if (noSequence) {
+ seq = RTP_END_OF_CALL_SEQ;
+ }
+
+ return writeMaster({ NET_FUNC_PROTOCOL, NET_PROTOCOL_SUBFUNC_DMR }, message.get(), messageLength, seq, m_dmrStreamId[slotIndex]);
}
///
@@ -463,7 +474,12 @@ bool BaseNetwork::writeP25TDU(const p25::lc::LC& control, const p25::data::LowSp
return false;
}
- return writeMaster({ NET_FUNC_PROTOCOL, NET_PROTOCOL_SUBFUNC_P25 }, message.get(), messageLength, pktSeq(resetSeq), m_p25StreamId);
+ uint16_t seq = pktSeq(resetSeq);
+ if (controlByte == 0x00U) {
+ seq = RTP_END_OF_CALL_SEQ;
+ }
+
+ return writeMaster({ NET_FUNC_PROTOCOL, NET_PROTOCOL_SUBFUNC_P25 }, message.get(), messageLength, seq, m_p25StreamId);
}
///
@@ -489,7 +505,7 @@ bool BaseNetwork::writeP25TSDU(const p25::lc::LC& control, const uint8_t* data)
return false;
}
- return writeMaster({ NET_FUNC_PROTOCOL, NET_PROTOCOL_SUBFUNC_P25 }, message.get(), messageLength, pktSeq(resetSeq), m_p25StreamId);
+ return writeMaster({ NET_FUNC_PROTOCOL, NET_PROTOCOL_SUBFUNC_P25 }, message.get(), messageLength, RTP_END_OF_CALL_SEQ, m_p25StreamId);
}
///
@@ -499,9 +515,10 @@ bool BaseNetwork::writeP25TSDU(const p25::lc::LC& control, const uint8_t* data)
///
///
///
+///
///
bool BaseNetwork::writeP25PDU(const p25::data::DataHeader& header, const uint8_t currentBlock, const uint8_t* data,
- const uint32_t len)
+ const uint32_t len, bool lastBlock)
{
if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING)
return false;
@@ -518,7 +535,12 @@ bool BaseNetwork::writeP25PDU(const p25::data::DataHeader& header, const uint8_t
return false;
}
- return writeMaster({ NET_FUNC_PROTOCOL, NET_PROTOCOL_SUBFUNC_P25 }, message.get(), messageLength, pktSeq(resetSeq), m_p25StreamId);
+ uint16_t seq = pktSeq(resetSeq);
+ if (lastBlock) {
+ seq = RTP_END_OF_CALL_SEQ;
+ }
+
+ return writeMaster({ NET_FUNC_PROTOCOL, NET_PROTOCOL_SUBFUNC_P25 }, message.get(), messageLength, seq, m_p25StreamId);
}
///
@@ -572,8 +594,9 @@ UInt8Array BaseNetwork::readNXDN(bool& ret, uint32_t& frameLength)
///
///
///
+///
///
-bool BaseNetwork::writeNXDN(const nxdn::lc::RTCH& lc, const uint8_t* data, const uint32_t len)
+bool BaseNetwork::writeNXDN(const nxdn::lc::RTCH& lc, const uint8_t* data, const uint32_t len, bool noSequence)
{
if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING)
return false;
@@ -590,7 +613,17 @@ bool BaseNetwork::writeNXDN(const nxdn::lc::RTCH& lc, const uint8_t* data, const
return false;
}
- return writeMaster({ NET_FUNC_PROTOCOL, NET_PROTOCOL_SUBFUNC_NXDN }, message.get(), messageLength, pktSeq(resetSeq), m_nxdnStreamId);
+ uint16_t seq = pktSeq(resetSeq);
+ if (lc.getMessageType() == nxdn::RTCH_MESSAGE_TYPE_TX_REL ||
+ lc.getMessageType() == nxdn::RTCH_MESSAGE_TYPE_TX_REL_EX) {
+ seq = RTP_END_OF_CALL_SEQ;
+ }
+
+ if (noSequence) {
+ seq = RTP_END_OF_CALL_SEQ;
+ }
+
+ return writeMaster({ NET_FUNC_PROTOCOL, NET_PROTOCOL_SUBFUNC_NXDN }, message.get(), messageLength, seq, m_nxdnStreamId);
}
///
@@ -622,7 +655,7 @@ uint16_t BaseNetwork::pktSeq(bool reset)
uint16_t curr = m_pktSeq;
++m_pktSeq;
- if (m_pktSeq > UINT16_MAX) {
+ if (m_pktSeq >= RTP_END_OF_CALL_SEQ - 1U) {
m_pktSeq = 0U;
}
diff --git a/src/common/network/BaseNetwork.h b/src/common/network/BaseNetwork.h
index 75320698..4d9b444d 100644
--- a/src/common/network/BaseNetwork.h
+++ b/src/common/network/BaseNetwork.h
@@ -12,7 +12,7 @@
//
/*
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
-* Copyright (C) 2020-2023 by Bryan Biedenkapp N2PLL
+* Copyright (C) 2020-2024 by Bryan Biedenkapp N2PLL
*
* 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
@@ -191,7 +191,7 @@ namespace network
/// Reads DMR raw frame data from the DMR ring buffer.
virtual UInt8Array readDMR(bool& ret, uint32_t& frameLength);
/// Writes DMR frame data to the network.
- virtual bool writeDMR(const dmr::data::Data& data);
+ virtual bool writeDMR(const dmr::data::Data& data, bool noSequence = false);
/// Helper to test if the DMR ring buffer has data.
bool hasDMRData() const;
@@ -210,7 +210,7 @@ namespace network
virtual bool writeP25TSDU(const p25::lc::LC& control, const uint8_t* data);
/// Writes P25 PDU frame data to the network.
virtual bool writeP25PDU(const p25::data::DataHeader& header, const uint8_t currentBlock, const uint8_t* data,
- const uint32_t len);
+ const uint32_t len, bool lastBlock);
/// Helper to test if the P25 ring buffer has data.
bool hasP25Data() const;
@@ -219,7 +219,7 @@ namespace network
/// Reads NXDN raw frame data from the NXDN ring buffer.
virtual UInt8Array readNXDN(bool& ret, uint32_t& frameLength);
/// Writes NXDN frame data to the network.
- virtual bool writeNXDN(const nxdn::lc::RTCH& lc, const uint8_t* data, const uint32_t len);
+ virtual bool writeNXDN(const nxdn::lc::RTCH& lc, const uint8_t* data, const uint32_t len, bool noSequence = false);
/// Helper to test if the NXDN ring buffer has data.
bool hasNXDNData() const;
diff --git a/src/common/network/FrameQueue.cpp b/src/common/network/FrameQueue.cpp
index 1af0ddd8..6298667e 100644
--- a/src/common/network/FrameQueue.cpp
+++ b/src/common/network/FrameQueue.cpp
@@ -7,7 +7,7 @@
*
*/
/*
-* Copyright (C) 2023 by Bryan Biedenkapp N2PLL
+* Copyright (C) 2023-2024 by Bryan Biedenkapp N2PLL
*
* 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
@@ -51,7 +51,8 @@ using namespace network::frame;
/// Local port used to listen for incoming data.
/// Unique ID of this modem on the network.
FrameQueue::FrameQueue(UDPSocket* socket, uint32_t peerId, bool debug) : RawFrameQueue(socket, debug),
- m_peerId(peerId)
+ m_peerId(peerId),
+ m_streamTimestamps()
{
assert(peerId < 999999999U);
}
@@ -189,6 +190,21 @@ void FrameQueue::enqueueMessage(const uint8_t* message, uint32_t length, uint32_
assert(message != nullptr);
assert(length > 0U);
+ uint32_t timestamp = INVALID_TS;
+ if (streamId != 0U) {
+ auto entry = m_streamTimestamps.find(streamId);
+ if (entry != m_streamTimestamps.end()) {
+ timestamp = entry->second;
+ }
+
+ if (timestamp != INVALID_TS) {
+ timestamp += (RTP_GENERIC_CLOCK_RATE / 133);
+ if (m_debug)
+ LogDebug(LOG_NET, "FrameQueue::enqueueMessage() RTP streamId = %u, previous TS = %u, TS = %u, rtpSeq = %u", streamId, m_streamTimestamps[streamId], timestamp, rtpSeq);
+ m_streamTimestamps[streamId] = timestamp;
+ }
+ }
+
uint32_t bufferLen = RTP_HEADER_LENGTH_BYTES + RTP_EXTENSION_HEADER_LENGTH_BYTES + RTP_FNE_HEADER_LENGTH_BYTES + length;
uint8_t* buffer = new uint8_t[bufferLen];
::memset(buffer, 0x00U, bufferLen);
@@ -197,6 +213,7 @@ void FrameQueue::enqueueMessage(const uint8_t* message, uint32_t length, uint32_
header.setExtension(true);
header.setPayloadType(DVM_RTP_PAYLOAD_TYPE);
+ header.setTimestamp(timestamp);
header.setSequence(rtpSeq);
header.setSSRC(ssrc);
@@ -208,6 +225,21 @@ void FrameQueue::enqueueMessage(const uint8_t* message, uint32_t length, uint32_
header.encode(buffer);
+ if (streamId != 0U && timestamp == INVALID_TS && rtpSeq != RTP_END_OF_CALL_SEQ) {
+ if (m_debug)
+ LogDebug(LOG_NET, "FrameQueue::enqueueMessage() RTP streamId = %u, initial TS = %u, rtpSeq = %u", streamId, header.getTimestamp(), rtpSeq);
+ m_streamTimestamps[streamId] = header.getTimestamp();
+ }
+
+ if (streamId != 0U && rtpSeq == RTP_END_OF_CALL_SEQ) {
+ auto entry = m_streamTimestamps.find(streamId);
+ if (entry != m_streamTimestamps.end()) {
+ if (m_debug)
+ LogDebug(LOG_NET, "FrameQueue::enqueueMessage() RTP streamId = %u, rtpSeq = %u", streamId, rtpSeq);
+ m_streamTimestamps.erase(streamId);
+ }
+ }
+
RTPFNEHeader fneHeader = RTPFNEHeader();
fneHeader.setCRC(edac::CRC::createCRC16(message, length * 8U));
fneHeader.setStreamId(streamId);
@@ -224,7 +256,7 @@ void FrameQueue::enqueueMessage(const uint8_t* message, uint32_t length, uint32_
if (m_debug)
Utils::dump(1U, "FrameQueue::enqueueMessage() Buffered Message", buffer, bufferLen);
- UDPDatagram* dgram = new UDPDatagram;
+ UDPDatagram *dgram = new UDPDatagram;
dgram->buffer = buffer;
dgram->length = bufferLen;
dgram->address = addr;
@@ -232,3 +264,11 @@ void FrameQueue::enqueueMessage(const uint8_t* message, uint32_t length, uint32_
m_buffers.push_back(dgram);
}
+
+///
+/// Helper method to clear any tracked stream timestamps.
+///
+void FrameQueue::clearTimestamps()
+{
+ m_streamTimestamps.clear();
+}
diff --git a/src/common/network/FrameQueue.h b/src/common/network/FrameQueue.h
index 5b8209ba..ba8c4d87 100644
--- a/src/common/network/FrameQueue.h
+++ b/src/common/network/FrameQueue.h
@@ -7,7 +7,7 @@
*
*/
/*
-* Copyright (C) 2023 by Bryan Biedenkapp N2PLL
+* Copyright (C) 2023-2024 by Bryan Biedenkapp N2PLL
*
* 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
@@ -31,6 +31,8 @@
#include "common/network/RTPFNEHeader.h"
#include "common/network/RawFrameQueue.h"
+#include
+
namespace network
{
// ---------------------------------------------------------------------------
@@ -64,8 +66,12 @@ namespace network
void enqueueMessage(const uint8_t* message, uint32_t length, uint32_t streamId, uint32_t peerId,
uint32_t ssrc, OpcodePair opcode, uint16_t rtpSeq, sockaddr_storage& addr, uint32_t addrLen);
+ /// Helper method to clear any tracked stream timestamps.
+ void clearTimestamps();
+
private:
uint32_t m_peerId;
+ std::unordered_map m_streamTimestamps;
};
} // namespace network
diff --git a/src/common/network/RTPFNEHeader.h b/src/common/network/RTPFNEHeader.h
index 2d56df8c..6042abbd 100644
--- a/src/common/network/RTPFNEHeader.h
+++ b/src/common/network/RTPFNEHeader.h
@@ -40,6 +40,8 @@
#define RTP_FNE_HEADER_LENGTH_BYTES 16
#define RTP_FNE_HEADER_LENGTH_EXT_LEN 4
+#define RTP_END_OF_CALL_SEQ 65535
+
namespace network
{
namespace frame
diff --git a/src/common/network/RTPHeader.cpp b/src/common/network/RTPHeader.cpp
index 0df754ff..62d9b1c5 100644
--- a/src/common/network/RTPHeader.cpp
+++ b/src/common/network/RTPHeader.cpp
@@ -38,7 +38,6 @@ using namespace network::frame;
// ---------------------------------------------------------------------------
hrc::hrc_t RTPHeader::m_wcStart = hrc::hrc_t();
-uint32_t RTPHeader::m_prevTimestamp = INVALID_TS;
// ---------------------------------------------------------------------------
// Public Class Members
@@ -57,9 +56,7 @@ RTPHeader::RTPHeader() :
m_timestamp(INVALID_TS),
m_ssrc(0U)
{
- std::random_device rd;
- std::mt19937 mt(rd());
- m_random = mt;
+ /* stub */
}
///
@@ -114,15 +111,10 @@ void RTPHeader::encode(uint8_t* data)
data[2U] = (m_seq >> 8) & 0xFFU; // Sequence MSB
data[3U] = (m_seq >> 0) & 0xFFU; // Sequence LSB
- if (m_prevTimestamp == INVALID_TS) {
+ if (m_timestamp == INVALID_TS) {
uint64_t timeSinceStart = hrc::diffNow(m_wcStart);
uint64_t microSeconds = timeSinceStart * RTP_GENERIC_CLOCK_RATE;
m_timestamp = uint32_t(microSeconds / 1000000);
- m_prevTimestamp = m_timestamp;
- }
- else {
- m_timestamp = m_prevTimestamp + (RTP_GENERIC_CLOCK_RATE / 133);
- m_prevTimestamp = m_timestamp;
}
__SET_UINT32(m_timestamp, data, 4U); // Timestamp
@@ -135,5 +127,4 @@ void RTPHeader::encode(uint8_t* data)
void RTPHeader::resetStartTime()
{
m_wcStart = hrc::hrc_t();
- m_prevTimestamp = INVALID_TS;
}
diff --git a/src/common/network/RTPHeader.h b/src/common/network/RTPHeader.h
index cf15d516..adc8bb24 100644
--- a/src/common/network/RTPHeader.h
+++ b/src/common/network/RTPHeader.h
@@ -29,7 +29,6 @@
#include "common/Defines.h"
#include
-#include
#include
// ---------------------------------------------------------------------------
@@ -87,9 +86,6 @@ namespace network
private:
static std::chrono::time_point m_wcStart;
- static uint32_t m_prevTimestamp;
-
- std::mt19937 m_random;
};
} // namespace frame
} // namespace network
diff --git a/src/fne/network/FNENetwork.cpp b/src/fne/network/FNENetwork.cpp
index d0bd4f98..332d71ee 100644
--- a/src/fne/network/FNENetwork.cpp
+++ b/src/fne/network/FNENetwork.cpp
@@ -166,6 +166,7 @@ void FNENetwork::clock(uint32_t ms)
// roll the RTP timestamp if no call is in progress
if (!m_callInProgress) {
frame::RTPHeader::resetStartTime();
+ m_frameQueue->clearTimestamps();
}
m_maintainenceTimer.start();
@@ -206,15 +207,20 @@ void FNENetwork::clock(uint32_t ms)
uint16_t pktSeq = rtpHeader.getSequence();
if (connection != nullptr) {
- if ((connection->currStreamId() == streamId) && (pktSeq != connection->pktNextSeq())) {
- LogWarning(LOG_NET, "PEER %u Stream %u out-of-sequence; %u != %u", peerId, streamId, pktSeq, connection->pktNextSeq());
- }
-
- connection->currStreamId(streamId);
- connection->pktLastSeq(pktSeq);
- connection->pktNextSeq(pktSeq + 1);
- if (connection->pktNextSeq() > UINT16_MAX) {
+ if (pktSeq == RTP_END_OF_CALL_SEQ) {
+ connection->pktLastSeq(pktSeq);
connection->pktNextSeq(0U);
+ } else {
+ if ((connection->currStreamId() == streamId) && (pktSeq != connection->pktNextSeq())) {
+ LogWarning(LOG_NET, "PEER %u Stream %u out-of-sequence; %u != %u", peerId, streamId, pktSeq, connection->pktNextSeq());
+ }
+
+ connection->currStreamId(streamId);
+ connection->pktLastSeq(pktSeq);
+ connection->pktNextSeq(pktSeq + 1);
+ if (connection->pktNextSeq() > UINT16_MAX) {
+ connection->pktNextSeq(0U);
+ }
}
}
@@ -1048,7 +1054,7 @@ bool FNENetwork::writePeerACK(uint32_t peerId, const uint8_t* data, uint32_t len
::memcpy(buffer + 6U, data, length);
}
- return writePeer(peerId, { NET_FUNC_ACK, NET_SUBFUNC_NOP }, buffer, length + 10U, 0U, false, true);
+ return writePeer(peerId, { NET_FUNC_ACK, NET_SUBFUNC_NOP }, buffer, length + 10U, RTP_END_OF_CALL_SEQ, false, true);
}
///
@@ -1067,7 +1073,7 @@ bool FNENetwork::writePeerNAK(uint32_t peerId, const char* tag)
__SET_UINT32(peerId, buffer, 6U); // Peer ID
LogWarning(LOG_NET, "%s from unauth PEER %u", tag, peerId);
- return writePeer(peerId, { NET_FUNC_NAK, NET_SUBFUNC_NOP }, buffer, 10U, 0U, false, true);
+ return writePeer(peerId, { NET_FUNC_NAK, NET_SUBFUNC_NOP }, buffer, 10U, RTP_END_OF_CALL_SEQ, false, true);
}
///
diff --git a/src/host/dmr/Slot.cpp b/src/host/dmr/Slot.cpp
index 3152c8d3..3688368e 100644
--- a/src/host/dmr/Slot.cpp
+++ b/src/host/dmr/Slot.cpp
@@ -12,7 +12,7 @@
//
/*
* Copyright (C) 2015,2016,2017,2018 Jonathan Naylor, G4KLX
-* Copyright (C) 2017-2023 by Bryan Biedenkapp N2PLL
+* Copyright (C) 2017-2024 by Bryan Biedenkapp N2PLL
*
* 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
@@ -1158,7 +1158,8 @@ void Slot::notifyCC_TouchGrant(uint32_t dstId)
///
///
///
-void Slot::writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t errors)
+///
+void Slot::writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t errors, bool noSequence)
{
assert(data != nullptr);
assert(m_rfLC != nullptr);
@@ -1175,8 +1176,9 @@ void Slot::writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t errors)
///
///
///
+///
void Slot::writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t flco, uint32_t srcId,
- uint32_t dstId, uint8_t errors)
+ uint32_t dstId, uint8_t errors, bool noSequence)
{
assert(data != nullptr);
@@ -1201,7 +1203,7 @@ void Slot::writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t flco, uin
dmrData.setData(data + 2U);
- m_network->writeDMR(dmrData);
+ m_network->writeDMR(dmrData, noSequence);
}
///
diff --git a/src/host/dmr/Slot.h b/src/host/dmr/Slot.h
index 3b36576c..869462a3 100644
--- a/src/host/dmr/Slot.h
+++ b/src/host/dmr/Slot.h
@@ -292,10 +292,10 @@ namespace dmr
void notifyCC_TouchGrant(uint32_t dstId);
/// Write data frame to the network.
- void writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t errors = 0U);
+ void writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t errors = 0U, bool noSequence = false);
/// Write data frame to the network.
void writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t flco, uint32_t srcId,
- uint32_t dstId, uint8_t errors = 0U);
+ uint32_t dstId, uint8_t errors = 0U, bool noSequence = false);
/// Helper to write RF end of frame data.
void writeEndRF(bool writeEnd = false);
diff --git a/src/host/dmr/packet/ControlSignaling.cpp b/src/host/dmr/packet/ControlSignaling.cpp
index d8725fb9..f0233029 100644
--- a/src/host/dmr/packet/ControlSignaling.cpp
+++ b/src/host/dmr/packet/ControlSignaling.cpp
@@ -12,7 +12,7 @@
//
/*
* Copyright (C) 2015,2016,2017,2018 Jonathan Naylor, G4KLX
-* Copyright (C) 2017-2023 by Bryan Biedenkapp N2PLL
+* Copyright (C) 2017-2024 by Bryan Biedenkapp N2PLL
*
* 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
@@ -394,7 +394,7 @@ bool ControlSignaling::process(uint8_t* data, uint32_t len)
if (m_slot->m_duplex)
m_slot->addFrame(data);
- m_slot->writeNetwork(data, DT_CSBK, gi ? FLCO_GROUP : FLCO_PRIVATE, srcId, dstId);
+ m_slot->writeNetwork(data, DT_CSBK, gi ? FLCO_GROUP : FLCO_PRIVATE, srcId, dstId, 0U, true);
}
return true;
diff --git a/src/host/network/Network.cpp b/src/host/network/Network.cpp
index b212c9dc..b91f9546 100644
--- a/src/host/network/Network.cpp
+++ b/src/host/network/Network.cpp
@@ -12,7 +12,7 @@
//
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
-* Copyright (C) 2017-2023 by Bryan Biedenkapp N2PLL
+* Copyright (C) 2017-2024 by Bryan Biedenkapp N2PLL
*
* 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
@@ -295,6 +295,11 @@ void Network::clock(uint32_t ms)
}
m_pktSeq = rtpHeader.getSequence();
+
+ if (m_pktSeq == RTP_END_OF_CALL_SEQ) {
+ m_pktSeq = 0U;
+ m_pktLastSeq = 0U;
+ }
// process incoming message frame opcodes
switch (fneHeader.getFunction()) {
@@ -732,7 +737,7 @@ bool Network::writeConfig()
rcon["port"].set(m_restApiPort); // REST API Port
config["rcon"].set(rcon);
- config["software"].set(std::string(software)); // Software ID
+ config["software"].set(std::string(software)); // Software ID
json::value v = json::value(config);
std::string json = v.serialize();
@@ -746,7 +751,7 @@ bool Network::writeConfig()
Utils::dump(1U, "Network Message, Configuration", (uint8_t*)buffer, json.length() + 8U);
}
- return writeMaster({ NET_FUNC_RPTC, NET_SUBFUNC_NOP }, (uint8_t*)buffer, json.length() + 8U, pktSeq(), m_loginStreamId);
+ return writeMaster({ NET_FUNC_RPTC, NET_SUBFUNC_NOP }, (uint8_t*)buffer, json.length() + 8U, RTP_END_OF_CALL_SEQ, m_loginStreamId);
}
///
@@ -760,5 +765,5 @@ bool Network::writePing()
if (m_debug)
Utils::dump(1U, "Network Message, Ping", buffer, 11U);
- return writeMaster({ NET_FUNC_PING, NET_SUBFUNC_NOP }, buffer, 1U, 0U, createStreamId());
+ return writeMaster({ NET_FUNC_PING, NET_SUBFUNC_NOP }, buffer, 1U, RTP_END_OF_CALL_SEQ, createStreamId());
}
diff --git a/src/host/nxdn/Control.cpp b/src/host/nxdn/Control.cpp
index 7223bec8..c4baae04 100644
--- a/src/host/nxdn/Control.cpp
+++ b/src/host/nxdn/Control.cpp
@@ -1217,5 +1217,5 @@ void Control::writeEndNet()
m_networkWatchdog.stop();
if (m_network != nullptr)
- m_network->resetP25();
+ m_network->resetNXDN();
}
diff --git a/src/host/nxdn/packet/ControlSignaling.cpp b/src/host/nxdn/packet/ControlSignaling.cpp
index b9d03c9e..c93677d4 100644
--- a/src/host/nxdn/packet/ControlSignaling.cpp
+++ b/src/host/nxdn/packet/ControlSignaling.cpp
@@ -11,7 +11,7 @@
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
-* Copyright (C) 2022-2023 by Bryan Biedenkapp N2PLL
+* Copyright (C) 2022-2024 by Bryan Biedenkapp N2PLL
*
* 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
@@ -371,7 +371,7 @@ void ControlSignaling::writeNetwork(const uint8_t *data, uint32_t len)
if (m_nxdn->m_rfTimeout.isRunning() && m_nxdn->m_rfTimeout.hasExpired())
return;
- m_nxdn->m_network->writeNXDN(m_nxdn->m_rfLC, data, len);
+ m_nxdn->m_network->writeNXDN(m_nxdn->m_rfLC, data, len, true);
}
/*
diff --git a/src/host/p25/Control.cpp b/src/host/p25/Control.cpp
index f8280594..b9481633 100644
--- a/src/host/p25/Control.cpp
+++ b/src/host/p25/Control.cpp
@@ -1408,7 +1408,6 @@ void Control::processFrameLoss()
writeRF_TDU(false);
m_voice->m_lastDUID = P25_DUID_TDU;
- //m_voice->writeNetwork(data + 2U, P25_DUID_TDU);
m_voice->writeNet_TDU();
m_rfState = RS_RF_LISTENING;
diff --git a/src/host/p25/packet/Data.cpp b/src/host/p25/packet/Data.cpp
index 45788ac9..a8d56997 100644
--- a/src/host/p25/packet/Data.cpp
+++ b/src/host/p25/packet/Data.cpp
@@ -12,7 +12,7 @@
//
/*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX
-* Copyright (C) 2017-2022 by Bryan Biedenkapp N2PLL
+* Copyright (C) 2017-2024 by Bryan Biedenkapp N2PLL
*
* 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
@@ -185,7 +185,7 @@ bool Data::process(uint8_t* data, uint32_t len)
if ((m_rfDataHeader.getFormat() != PDU_FMT_AMBT) &&
(m_rfDataHeader.getFormat() != PDU_FMT_RSP) &&
(m_rfDataHeader.getSAP() != PDU_SAP_REG)) {
- writeNetwork(0, buffer, P25_PDU_FEC_LENGTH_BYTES);
+ writeNetwork(0U, buffer, P25_PDU_FEC_LENGTH_BYTES, false);
}
}
@@ -225,7 +225,7 @@ bool Data::process(uint8_t* data, uint32_t len)
if ((m_rfDataHeader.getFormat() != PDU_FMT_AMBT) &&
(m_rfDataHeader.getFormat() != PDU_FMT_RSP) &&
(m_rfDataHeader.getSAP() != PDU_SAP_REG)) {
- writeNetwork(1, buffer, P25_PDU_FEC_LENGTH_BYTES);
+ writeNetwork(1U, buffer, P25_PDU_FEC_LENGTH_BYTES, false);
}
offset += P25_PDU_FEC_LENGTH_BITS;
@@ -292,7 +292,7 @@ bool Data::process(uint8_t* data, uint32_t len)
if ((m_rfDataHeader.getFormat() != PDU_FMT_AMBT) &&
(m_rfDataHeader.getFormat() != PDU_FMT_RSP) &&
(m_rfDataHeader.getSAP() != PDU_SAP_REG)) {
- writeNetwork(m_rfDataBlockCnt, buffer, P25_PDU_FEC_LENGTH_BYTES);
+ writeNetwork(m_rfDataBlockCnt, buffer, P25_PDU_FEC_LENGTH_BYTES, m_rfData[i].getLastBlock());
}
m_rfDataBlockCnt++;
@@ -874,7 +874,8 @@ Data::~Data()
///
///
///
-void Data::writeNetwork(const uint8_t currentBlock, const uint8_t *data, uint32_t len)
+///
+void Data::writeNetwork(const uint8_t currentBlock, const uint8_t *data, uint32_t len, bool lastBlock)
{
assert(data != nullptr);
@@ -886,7 +887,7 @@ void Data::writeNetwork(const uint8_t currentBlock, const uint8_t *data, uint32_
// Utils::dump(1U, "Outgoing Network PDU Frame", data, len);
- m_p25->m_network->writeP25PDU(m_rfDataHeader, currentBlock, data, len);
+ m_p25->m_network->writeP25PDU(m_rfDataHeader, currentBlock, data, len, lastBlock);
}
///
diff --git a/src/host/p25/packet/Data.h b/src/host/p25/packet/Data.h
index f8d2a34d..727a6a4f 100644
--- a/src/host/p25/packet/Data.h
+++ b/src/host/p25/packet/Data.h
@@ -12,7 +12,7 @@
//
/*
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
-* Copyright (C) 2017-2022 by Bryan Biedenkapp N2PLL
+* Copyright (C) 2017-2024 by Bryan Biedenkapp N2PLL
*
* 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
@@ -124,7 +124,7 @@ namespace p25
~Data();
/// Write data processed from RF to the network.
- void writeNetwork(const uint8_t currentBlock, const uint8_t* data, uint32_t len);
+ void writeNetwork(const uint8_t currentBlock, const uint8_t* data, uint32_t len, bool lastBlock);
/// Helper to write a P25 PDU packet.
void writeRF_PDU(const uint8_t* pdu, uint32_t bitLength, bool noNulls = false);