You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
4.4 KiB
127 lines
4.4 KiB
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Digital Voice Modem - FNE Call Simulator
|
|
* GPLv2 Open Source. Use is subject to license terms.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright (C) 2026 Bryan Biedenkapp, N2PLL
|
|
*
|
|
*/
|
|
#include "CallSimNetwork.h"
|
|
|
|
using namespace network;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Public Class Members
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/* Clocks the shared FNE connection while excluding concurrent writers. */
|
|
|
|
void CallSimNetwork::clockConnection(uint32_t ms)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_writeMutex);
|
|
clock(ms);
|
|
}
|
|
|
|
/* Writes a DMR frame using call-specific RTP state. */
|
|
|
|
bool CallSimNetwork::writeDMRCall(const dmr::data::NetData& data, CallStreamState& stream, bool end)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_writeMutex);
|
|
if (stream.streamId == 0U)
|
|
stream.streamId = createStreamId();
|
|
|
|
uint32_t messageLength = 0U;
|
|
UInt8Array message = createDMR_Message(messageLength, stream.streamId, data);
|
|
if (message == nullptr)
|
|
return false;
|
|
|
|
return writeMaster({ NET_FUNC::PROTOCOL, NET_SUBFUNC::PROTOCOL_SUBFUNC_DMR }, message.get(), messageLength,
|
|
nextSequence(stream, end), stream.streamId);
|
|
}
|
|
|
|
/* Writes a P25 LDU1 using call-specific RTP state. */
|
|
|
|
bool CallSimNetwork::writeP25LDU1Call(const p25::lc::LC& control, const p25::data::LowSpeedData& lsd,
|
|
const uint8_t* data, CallStreamState& stream)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_writeMutex);
|
|
uint32_t messageLength = 0U;
|
|
UInt8Array message = createP25_LDU1Message(messageLength, control, lsd, data, P25DEF::FrameType::DATA_UNIT, 0U);
|
|
if (message == nullptr)
|
|
return false;
|
|
|
|
return writeMaster({ NET_FUNC::PROTOCOL, NET_SUBFUNC::PROTOCOL_SUBFUNC_P25 }, message.get(), messageLength,
|
|
nextSequence(stream, false), stream.streamId);
|
|
}
|
|
|
|
/* Writes a P25 LDU2 using call-specific RTP state. */
|
|
|
|
bool CallSimNetwork::writeP25LDU2Call(const p25::lc::LC& control, const p25::data::LowSpeedData& lsd,
|
|
const uint8_t* data, CallStreamState& stream)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_writeMutex);
|
|
uint32_t messageLength = 0U;
|
|
UInt8Array message = createP25_LDU2Message(messageLength, control, lsd, data, 0U);
|
|
if (message == nullptr)
|
|
return false;
|
|
|
|
return writeMaster({ NET_FUNC::PROTOCOL, NET_SUBFUNC::PROTOCOL_SUBFUNC_P25 }, message.get(), messageLength,
|
|
nextSequence(stream, false), stream.streamId);
|
|
}
|
|
|
|
/* Writes a terminating P25 TDU using call-specific RTP state. */
|
|
|
|
bool CallSimNetwork::writeP25TDUCall(const p25::lc::LC& control, const p25::data::LowSpeedData& lsd,
|
|
CallStreamState& stream)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_writeMutex);
|
|
uint32_t messageLength = 0U;
|
|
UInt8Array message = createP25_TDUMessage(messageLength, control, lsd, 0U);
|
|
if (message == nullptr)
|
|
return false;
|
|
|
|
return writeMaster({ NET_FUNC::PROTOCOL, NET_SUBFUNC::PROTOCOL_SUBFUNC_P25 }, message.get(), messageLength,
|
|
nextSequence(stream, true), stream.streamId);
|
|
}
|
|
|
|
/* Writes an NXDN frame using call-specific RTP state. */
|
|
|
|
bool CallSimNetwork::writeNXDNCall(const nxdn::lc::RTCH& control, const uint8_t* data, uint32_t length,
|
|
CallStreamState& stream, bool end)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_writeMutex);
|
|
uint32_t messageLength = 0U;
|
|
UInt8Array message = createNXDN_Message(messageLength, control, data, length);
|
|
if (message == nullptr)
|
|
return false;
|
|
|
|
return writeMaster({ NET_FUNC::PROTOCOL, NET_SUBFUNC::PROTOCOL_SUBFUNC_NXDN }, message.get(), messageLength,
|
|
nextSequence(stream, end), stream.streamId);
|
|
}
|
|
|
|
/* Writes a group-call grant request while excluding concurrent frame writers. */
|
|
|
|
bool CallSimNetwork::writeGroupGrantRequest(uint8_t mode, uint32_t srcId, uint32_t dstId, uint8_t slot)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_writeMutex);
|
|
return writeGrantReq(mode, srcId, dstId, slot, false, 0U);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Private Class Members
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/* Allocates an RTP stream ID on first use and returns the next sequence. */
|
|
|
|
uint16_t CallSimNetwork::nextSequence(CallStreamState& stream, bool end)
|
|
{
|
|
if (stream.streamId == 0U)
|
|
stream.streamId = createStreamId();
|
|
|
|
if (end)
|
|
return RTP_END_OF_CALL_SEQ;
|
|
|
|
return stream.sequence++;
|
|
}
|