refactor RTP code slightly to better handle tracking the RTP timestamp properly;

pull/48/head
Bryan Biedenkapp 2 years ago
parent 5ed3d79a0b
commit eba4db6104

@ -12,7 +12,7 @@
// //
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * 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 * 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 * it under the terms of the GNU General Public License as published by
@ -30,6 +30,7 @@
*/ */
#include "Defines.h" #include "Defines.h"
#include "common/dmr/DMRDefines.h" #include "common/dmr/DMRDefines.h"
#include "common/nxdn/NXDNDefines.h"
#include "common/p25/dfsi/DFSIDefines.h" #include "common/p25/dfsi/DFSIDefines.h"
#include "common/p25/dfsi/LC.h" #include "common/p25/dfsi/LC.h"
#include "edac/SHA256.h" #include "edac/SHA256.h"
@ -301,8 +302,9 @@ UInt8Array BaseNetwork::readDMR(bool& ret, uint32_t& frameLength)
/// Writes DMR frame data to the network. /// Writes DMR frame data to the network.
/// </summary> /// </summary>
/// <param name="data"></param> /// <param name="data"></param>
/// <param name="noSequence"></param>
/// <returns></returns> /// <returns></returns>
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) if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING)
return false; return false;
@ -336,7 +338,16 @@ bool BaseNetwork::writeDMR(const dmr::data::Data& data)
return false; 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]);
} }
/// <summary> /// <summary>
@ -463,7 +474,12 @@ bool BaseNetwork::writeP25TDU(const p25::lc::LC& control, const p25::data::LowSp
return false; 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);
} }
/// <summary> /// <summary>
@ -489,7 +505,7 @@ bool BaseNetwork::writeP25TSDU(const p25::lc::LC& control, const uint8_t* data)
return false; 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);
} }
/// <summary> /// <summary>
@ -499,9 +515,10 @@ bool BaseNetwork::writeP25TSDU(const p25::lc::LC& control, const uint8_t* data)
/// <param name="currentBlock"></param> /// <param name="currentBlock"></param>
/// <param name="data"></param> /// <param name="data"></param>
/// <param name="len"></param> /// <param name="len"></param>
/// <param name="lastBlock"></param>
/// <returns></returns> /// <returns></returns>
bool BaseNetwork::writeP25PDU(const p25::data::DataHeader& header, const uint8_t currentBlock, 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) if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING)
return false; return false;
@ -518,7 +535,12 @@ bool BaseNetwork::writeP25PDU(const p25::data::DataHeader& header, const uint8_t
return false; 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);
} }
/// <summary> /// <summary>
@ -572,8 +594,9 @@ UInt8Array BaseNetwork::readNXDN(bool& ret, uint32_t& frameLength)
/// <param name="lc"></param> /// <param name="lc"></param>
/// <param name="data"></param> /// <param name="data"></param>
/// <param name="len"></param> /// <param name="len"></param>
/// <param name="noSequence"></param>
/// <returns></returns> /// <returns></returns>
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) if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING)
return false; return false;
@ -590,7 +613,17 @@ bool BaseNetwork::writeNXDN(const nxdn::lc::RTCH& lc, const uint8_t* data, const
return false; 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);
} }
/// <summary> /// <summary>
@ -622,7 +655,7 @@ uint16_t BaseNetwork::pktSeq(bool reset)
uint16_t curr = m_pktSeq; uint16_t curr = m_pktSeq;
++m_pktSeq; ++m_pktSeq;
if (m_pktSeq > UINT16_MAX) { if (m_pktSeq >= RTP_END_OF_CALL_SEQ - 1U) {
m_pktSeq = 0U; m_pktSeq = 0U;
} }

@ -12,7 +12,7 @@
// //
/* /*
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX * 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 * 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 * it under the terms of the GNU General Public License as published by
@ -191,7 +191,7 @@ namespace network
/// <summary>Reads DMR raw frame data from the DMR ring buffer.</summary> /// <summary>Reads DMR raw frame data from the DMR ring buffer.</summary>
virtual UInt8Array readDMR(bool& ret, uint32_t& frameLength); virtual UInt8Array readDMR(bool& ret, uint32_t& frameLength);
/// <summary>Writes DMR frame data to the network.</summary> /// <summary>Writes DMR frame data to the network.</summary>
virtual bool writeDMR(const dmr::data::Data& data); virtual bool writeDMR(const dmr::data::Data& data, bool noSequence = false);
/// <summary>Helper to test if the DMR ring buffer has data.</summary> /// <summary>Helper to test if the DMR ring buffer has data.</summary>
bool hasDMRData() const; bool hasDMRData() const;
@ -210,7 +210,7 @@ namespace network
virtual bool writeP25TSDU(const p25::lc::LC& control, const uint8_t* data); virtual bool writeP25TSDU(const p25::lc::LC& control, const uint8_t* data);
/// <summary>Writes P25 PDU frame data to the network.</summary> /// <summary>Writes P25 PDU frame data to the network.</summary>
virtual bool writeP25PDU(const p25::data::DataHeader& header, const uint8_t currentBlock, const uint8_t* data, 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);
/// <summary>Helper to test if the P25 ring buffer has data.</summary> /// <summary>Helper to test if the P25 ring buffer has data.</summary>
bool hasP25Data() const; bool hasP25Data() const;
@ -219,7 +219,7 @@ namespace network
/// <summary>Reads NXDN raw frame data from the NXDN ring buffer.</summary> /// <summary>Reads NXDN raw frame data from the NXDN ring buffer.</summary>
virtual UInt8Array readNXDN(bool& ret, uint32_t& frameLength); virtual UInt8Array readNXDN(bool& ret, uint32_t& frameLength);
/// <summary>Writes NXDN frame data to the network.</summary> /// <summary>Writes NXDN frame data to the network.</summary>
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);
/// <summary>Helper to test if the NXDN ring buffer has data.</summary> /// <summary>Helper to test if the NXDN ring buffer has data.</summary>
bool hasNXDNData() const; bool hasNXDNData() const;

@ -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 * 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 * it under the terms of the GNU General Public License as published by
@ -51,7 +51,8 @@ using namespace network::frame;
/// <param name="socket">Local port used to listen for incoming data.</param> /// <param name="socket">Local port used to listen for incoming data.</param>
/// <param name="peerId">Unique ID of this modem on the network.</param> /// <param name="peerId">Unique ID of this modem on the network.</param>
FrameQueue::FrameQueue(UDPSocket* socket, uint32_t peerId, bool debug) : RawFrameQueue(socket, debug), FrameQueue::FrameQueue(UDPSocket* socket, uint32_t peerId, bool debug) : RawFrameQueue(socket, debug),
m_peerId(peerId) m_peerId(peerId),
m_streamTimestamps()
{ {
assert(peerId < 999999999U); assert(peerId < 999999999U);
} }
@ -189,6 +190,21 @@ void FrameQueue::enqueueMessage(const uint8_t* message, uint32_t length, uint32_
assert(message != nullptr); assert(message != nullptr);
assert(length > 0U); 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; 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]; uint8_t* buffer = new uint8_t[bufferLen];
::memset(buffer, 0x00U, bufferLen); ::memset(buffer, 0x00U, bufferLen);
@ -197,6 +213,7 @@ void FrameQueue::enqueueMessage(const uint8_t* message, uint32_t length, uint32_
header.setExtension(true); header.setExtension(true);
header.setPayloadType(DVM_RTP_PAYLOAD_TYPE); header.setPayloadType(DVM_RTP_PAYLOAD_TYPE);
header.setTimestamp(timestamp);
header.setSequence(rtpSeq); header.setSequence(rtpSeq);
header.setSSRC(ssrc); header.setSSRC(ssrc);
@ -208,6 +225,21 @@ void FrameQueue::enqueueMessage(const uint8_t* message, uint32_t length, uint32_
header.encode(buffer); 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(); RTPFNEHeader fneHeader = RTPFNEHeader();
fneHeader.setCRC(edac::CRC::createCRC16(message, length * 8U)); fneHeader.setCRC(edac::CRC::createCRC16(message, length * 8U));
fneHeader.setStreamId(streamId); fneHeader.setStreamId(streamId);
@ -224,7 +256,7 @@ void FrameQueue::enqueueMessage(const uint8_t* message, uint32_t length, uint32_
if (m_debug) if (m_debug)
Utils::dump(1U, "FrameQueue::enqueueMessage() Buffered Message", buffer, bufferLen); Utils::dump(1U, "FrameQueue::enqueueMessage() Buffered Message", buffer, bufferLen);
UDPDatagram* dgram = new UDPDatagram; UDPDatagram *dgram = new UDPDatagram;
dgram->buffer = buffer; dgram->buffer = buffer;
dgram->length = bufferLen; dgram->length = bufferLen;
dgram->address = addr; dgram->address = addr;
@ -232,3 +264,11 @@ void FrameQueue::enqueueMessage(const uint8_t* message, uint32_t length, uint32_
m_buffers.push_back(dgram); m_buffers.push_back(dgram);
} }
/// <summary>
/// Helper method to clear any tracked stream timestamps.
/// </summary>
void FrameQueue::clearTimestamps()
{
m_streamTimestamps.clear();
}

@ -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 * 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 * 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/RTPFNEHeader.h"
#include "common/network/RawFrameQueue.h" #include "common/network/RawFrameQueue.h"
#include <unordered_map>
namespace network namespace network
{ {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -64,8 +66,12 @@ namespace network
void enqueueMessage(const uint8_t* message, uint32_t length, uint32_t streamId, uint32_t peerId, 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); uint32_t ssrc, OpcodePair opcode, uint16_t rtpSeq, sockaddr_storage& addr, uint32_t addrLen);
/// <summary>Helper method to clear any tracked stream timestamps.</summary>
void clearTimestamps();
private: private:
uint32_t m_peerId; uint32_t m_peerId;
std::unordered_map<uint32_t, uint32_t> m_streamTimestamps;
}; };
} // namespace network } // namespace network

@ -40,6 +40,8 @@
#define RTP_FNE_HEADER_LENGTH_BYTES 16 #define RTP_FNE_HEADER_LENGTH_BYTES 16
#define RTP_FNE_HEADER_LENGTH_EXT_LEN 4 #define RTP_FNE_HEADER_LENGTH_EXT_LEN 4
#define RTP_END_OF_CALL_SEQ 65535
namespace network namespace network
{ {
namespace frame namespace frame

@ -38,7 +38,6 @@ using namespace network::frame;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
hrc::hrc_t RTPHeader::m_wcStart = hrc::hrc_t(); hrc::hrc_t RTPHeader::m_wcStart = hrc::hrc_t();
uint32_t RTPHeader::m_prevTimestamp = INVALID_TS;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Public Class Members // Public Class Members
@ -57,9 +56,7 @@ RTPHeader::RTPHeader() :
m_timestamp(INVALID_TS), m_timestamp(INVALID_TS),
m_ssrc(0U) m_ssrc(0U)
{ {
std::random_device rd; /* stub */
std::mt19937 mt(rd());
m_random = mt;
} }
/// <summary> /// <summary>
@ -114,15 +111,10 @@ void RTPHeader::encode(uint8_t* data)
data[2U] = (m_seq >> 8) & 0xFFU; // Sequence MSB data[2U] = (m_seq >> 8) & 0xFFU; // Sequence MSB
data[3U] = (m_seq >> 0) & 0xFFU; // Sequence LSB 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 timeSinceStart = hrc::diffNow(m_wcStart);
uint64_t microSeconds = timeSinceStart * RTP_GENERIC_CLOCK_RATE; uint64_t microSeconds = timeSinceStart * RTP_GENERIC_CLOCK_RATE;
m_timestamp = uint32_t(microSeconds / 1000000); 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 __SET_UINT32(m_timestamp, data, 4U); // Timestamp
@ -135,5 +127,4 @@ void RTPHeader::encode(uint8_t* data)
void RTPHeader::resetStartTime() void RTPHeader::resetStartTime()
{ {
m_wcStart = hrc::hrc_t(); m_wcStart = hrc::hrc_t();
m_prevTimestamp = INVALID_TS;
} }

@ -29,7 +29,6 @@
#include "common/Defines.h" #include "common/Defines.h"
#include <chrono> #include <chrono>
#include <random>
#include <string> #include <string>
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -87,9 +86,6 @@ namespace network
private: private:
static std::chrono::time_point<std::chrono::high_resolution_clock> m_wcStart; static std::chrono::time_point<std::chrono::high_resolution_clock> m_wcStart;
static uint32_t m_prevTimestamp;
std::mt19937 m_random;
}; };
} // namespace frame } // namespace frame
} // namespace network } // namespace network

@ -166,6 +166,7 @@ void FNENetwork::clock(uint32_t ms)
// roll the RTP timestamp if no call is in progress // roll the RTP timestamp if no call is in progress
if (!m_callInProgress) { if (!m_callInProgress) {
frame::RTPHeader::resetStartTime(); frame::RTPHeader::resetStartTime();
m_frameQueue->clearTimestamps();
} }
m_maintainenceTimer.start(); m_maintainenceTimer.start();
@ -206,6 +207,10 @@ void FNENetwork::clock(uint32_t ms)
uint16_t pktSeq = rtpHeader.getSequence(); uint16_t pktSeq = rtpHeader.getSequence();
if (connection != nullptr) { if (connection != nullptr) {
if (pktSeq == RTP_END_OF_CALL_SEQ) {
connection->pktLastSeq(pktSeq);
connection->pktNextSeq(0U);
} else {
if ((connection->currStreamId() == streamId) && (pktSeq != connection->pktNextSeq())) { if ((connection->currStreamId() == streamId) && (pktSeq != connection->pktNextSeq())) {
LogWarning(LOG_NET, "PEER %u Stream %u out-of-sequence; %u != %u", peerId, streamId, pktSeq, connection->pktNextSeq()); LogWarning(LOG_NET, "PEER %u Stream %u out-of-sequence; %u != %u", peerId, streamId, pktSeq, connection->pktNextSeq());
} }
@ -217,6 +222,7 @@ void FNENetwork::clock(uint32_t ms)
connection->pktNextSeq(0U); connection->pktNextSeq(0U);
} }
} }
}
m_peers[peerId] = connection; m_peers[peerId] = connection;
} }
@ -1048,7 +1054,7 @@ bool FNENetwork::writePeerACK(uint32_t peerId, const uint8_t* data, uint32_t len
::memcpy(buffer + 6U, data, length); ::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);
} }
/// <summary> /// <summary>
@ -1067,7 +1073,7 @@ bool FNENetwork::writePeerNAK(uint32_t peerId, const char* tag)
__SET_UINT32(peerId, buffer, 6U); // Peer ID __SET_UINT32(peerId, buffer, 6U); // Peer ID
LogWarning(LOG_NET, "%s from unauth PEER %u", tag, peerId); 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);
} }
/// <summary> /// <summary>

@ -12,7 +12,7 @@
// //
/* /*
* Copyright (C) 2015,2016,2017,2018 Jonathan Naylor, G4KLX * 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 * 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 * it under the terms of the GNU General Public License as published by
@ -1158,7 +1158,8 @@ void Slot::notifyCC_TouchGrant(uint32_t dstId)
/// <param name="data"></param> /// <param name="data"></param>
/// <param name="dataType"></param> /// <param name="dataType"></param>
/// <param name="errors"></param> /// <param name="errors"></param>
void Slot::writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t errors) /// <param name="noSequence"></param>
void Slot::writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t errors, bool noSequence)
{ {
assert(data != nullptr); assert(data != nullptr);
assert(m_rfLC != nullptr); assert(m_rfLC != nullptr);
@ -1175,8 +1176,9 @@ void Slot::writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t errors)
/// <param name="srcId"></param> /// <param name="srcId"></param>
/// <param name="dstId"></param> /// <param name="dstId"></param>
/// <param name="errors"></param> /// <param name="errors"></param>
/// <param name="noSequence"></param>
void Slot::writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t flco, uint32_t srcId, 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); 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); dmrData.setData(data + 2U);
m_network->writeDMR(dmrData); m_network->writeDMR(dmrData, noSequence);
} }
/// <summary> /// <summary>

@ -292,10 +292,10 @@ namespace dmr
void notifyCC_TouchGrant(uint32_t dstId); void notifyCC_TouchGrant(uint32_t dstId);
/// <summary>Write data frame to the network.</summary> /// <summary>Write data frame to the network.</summary>
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);
/// <summary>Write data frame to the network.</summary> /// <summary>Write data frame to the network.</summary>
void writeNetwork(const uint8_t* data, uint8_t dataType, uint8_t flco, uint32_t srcId, 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);
/// <summary>Helper to write RF end of frame data.</summary> /// <summary>Helper to write RF end of frame data.</summary>
void writeEndRF(bool writeEnd = false); void writeEndRF(bool writeEnd = false);

@ -12,7 +12,7 @@
// //
/* /*
* Copyright (C) 2015,2016,2017,2018 Jonathan Naylor, G4KLX * 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 * 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 * 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) if (m_slot->m_duplex)
m_slot->addFrame(data); 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; return true;

@ -12,7 +12,7 @@
// //
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * 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 * 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 * it under the terms of the GNU General Public License as published by
@ -296,6 +296,11 @@ void Network::clock(uint32_t ms)
m_pktSeq = rtpHeader.getSequence(); m_pktSeq = rtpHeader.getSequence();
if (m_pktSeq == RTP_END_OF_CALL_SEQ) {
m_pktSeq = 0U;
m_pktLastSeq = 0U;
}
// process incoming message frame opcodes // process incoming message frame opcodes
switch (fneHeader.getFunction()) { switch (fneHeader.getFunction()) {
case NET_FUNC_PROTOCOL: case NET_FUNC_PROTOCOL:
@ -746,7 +751,7 @@ bool Network::writeConfig()
Utils::dump(1U, "Network Message, Configuration", (uint8_t*)buffer, json.length() + 8U); 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);
} }
/// <summary> /// <summary>
@ -760,5 +765,5 @@ bool Network::writePing()
if (m_debug) if (m_debug)
Utils::dump(1U, "Network Message, Ping", buffer, 11U); 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());
} }

@ -1217,5 +1217,5 @@ void Control::writeEndNet()
m_networkWatchdog.stop(); m_networkWatchdog.stop();
if (m_network != nullptr) if (m_network != nullptr)
m_network->resetP25(); m_network->resetNXDN();
} }

@ -11,7 +11,7 @@
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) // 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 * 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 * 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()) if (m_nxdn->m_rfTimeout.isRunning() && m_nxdn->m_rfTimeout.hasExpired())
return; return;
m_nxdn->m_network->writeNXDN(m_nxdn->m_rfLC, data, len); m_nxdn->m_network->writeNXDN(m_nxdn->m_rfLC, data, len, true);
} }
/* /*

@ -1408,7 +1408,6 @@ void Control::processFrameLoss()
writeRF_TDU(false); writeRF_TDU(false);
m_voice->m_lastDUID = P25_DUID_TDU; m_voice->m_lastDUID = P25_DUID_TDU;
//m_voice->writeNetwork(data + 2U, P25_DUID_TDU);
m_voice->writeNet_TDU(); m_voice->writeNet_TDU();
m_rfState = RS_RF_LISTENING; m_rfState = RS_RF_LISTENING;

@ -12,7 +12,7 @@
// //
/* /*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX * 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 * 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 * 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) && if ((m_rfDataHeader.getFormat() != PDU_FMT_AMBT) &&
(m_rfDataHeader.getFormat() != PDU_FMT_RSP) && (m_rfDataHeader.getFormat() != PDU_FMT_RSP) &&
(m_rfDataHeader.getSAP() != PDU_SAP_REG)) { (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) && if ((m_rfDataHeader.getFormat() != PDU_FMT_AMBT) &&
(m_rfDataHeader.getFormat() != PDU_FMT_RSP) && (m_rfDataHeader.getFormat() != PDU_FMT_RSP) &&
(m_rfDataHeader.getSAP() != PDU_SAP_REG)) { (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; 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) && if ((m_rfDataHeader.getFormat() != PDU_FMT_AMBT) &&
(m_rfDataHeader.getFormat() != PDU_FMT_RSP) && (m_rfDataHeader.getFormat() != PDU_FMT_RSP) &&
(m_rfDataHeader.getSAP() != PDU_SAP_REG)) { (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++; m_rfDataBlockCnt++;
@ -874,7 +874,8 @@ Data::~Data()
/// <param name="currentBlock"></param> /// <param name="currentBlock"></param>
/// <param name="data"></param> /// <param name="data"></param>
/// <param name="len"></param> /// <param name="len"></param>
void Data::writeNetwork(const uint8_t currentBlock, const uint8_t *data, uint32_t len) /// <param name="lastBlock"></param>
void Data::writeNetwork(const uint8_t currentBlock, const uint8_t *data, uint32_t len, bool lastBlock)
{ {
assert(data != nullptr); 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); // 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);
} }
/// <summary> /// <summary>

@ -12,7 +12,7 @@
// //
/* /*
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX * 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 * 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 * it under the terms of the GNU General Public License as published by
@ -124,7 +124,7 @@ namespace p25
~Data(); ~Data();
/// <summary>Write data processed from RF to the network.</summary> /// <summary>Write data processed from RF to the network.</summary>
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);
/// <summary>Helper to write a P25 PDU packet.</summary> /// <summary>Helper to write a P25 PDU packet.</summary>
void writeRF_PDU(const uint8_t* pdu, uint32_t bitLength, bool noNulls = false); void writeRF_PDU(const uint8_t* pdu, uint32_t bitLength, bool noNulls = false);

Loading…
Cancel
Save

Powered by TurnKey Linux.