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) 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.
/// </summary>
/// <param name="data"></param>
/// <param name="noSequence"></param>
/// <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)
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]);
}
/// <summary>
@ -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);
}
/// <summary>
@ -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);
}
/// <summary>
@ -499,9 +515,10 @@ bool BaseNetwork::writeP25TSDU(const p25::lc::LC& control, const uint8_t* data)
/// <param name="currentBlock"></param>
/// <param name="data"></param>
/// <param name="len"></param>
/// <param name="lastBlock"></param>
/// <returns></returns>
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);
}
/// <summary>
@ -572,8 +594,9 @@ UInt8Array BaseNetwork::readNXDN(bool& ret, uint32_t& frameLength)
/// <param name="lc"></param>
/// <param name="data"></param>
/// <param name="len"></param>
/// <param name="noSequence"></param>
/// <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)
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);
}
/// <summary>
@ -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;
}

@ -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
/// <summary>Reads DMR raw frame data from the DMR ring buffer.</summary>
virtual UInt8Array readDMR(bool& ret, uint32_t& frameLength);
/// <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>
bool hasDMRData() const;
@ -210,7 +210,7 @@ namespace network
virtual bool writeP25TSDU(const p25::lc::LC& control, const uint8_t* data);
/// <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,
const uint32_t len);
const uint32_t len, bool lastBlock);
/// <summary>Helper to test if the P25 ring buffer has data.</summary>
bool hasP25Data() const;
@ -219,7 +219,7 @@ namespace network
/// <summary>Reads NXDN raw frame data from the NXDN ring buffer.</summary>
virtual UInt8Array readNXDN(bool& ret, uint32_t& frameLength);
/// <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>
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
* 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="peerId">Unique ID of this modem on the network.</param>
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);
}
/// <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
* 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 <unordered_map>
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);
/// <summary>Helper method to clear any tracked stream timestamps.</summary>
void clearTimestamps();
private:
uint32_t m_peerId;
std::unordered_map<uint32_t, uint32_t> m_streamTimestamps;
};
} // namespace network

@ -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

@ -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 */
}
/// <summary>
@ -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;
}

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

@ -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);
}
/// <summary>
@ -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);
}
/// <summary>

@ -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)
/// <param name="data"></param>
/// <param name="dataType"></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(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="dstId"></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,
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);
}
/// <summary>

@ -292,10 +292,10 @@ namespace dmr
void notifyCC_TouchGrant(uint32_t dstId);
/// <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>
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>
void writeEndRF(bool writeEnd = false);

@ -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;

@ -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
@ -296,6 +296,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()) {
case NET_FUNC_PROTOCOL:
@ -732,7 +737,7 @@ bool Network::writeConfig()
rcon["port"].set<uint16_t>(m_restApiPort); // REST API Port
config["rcon"].set<json::object>(rcon);
config["software"].set<std::string>(std::string(software)); // Software ID
config["software"].set<std::string>(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);
}
/// <summary>
@ -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());
}

@ -1217,5 +1217,5 @@ void Control::writeEndNet()
m_networkWatchdog.stop();
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)
//
/*
* 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);
}
/*

@ -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;

@ -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()
/// <param name="currentBlock"></param>
/// <param name="data"></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);
@ -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);
}
/// <summary>

@ -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();
/// <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>
void writeRF_PDU(const uint8_t* pdu, uint32_t bitLength, bool noNulls = false);

Loading…
Cancel
Save

Powered by TurnKey Linux.