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.
1372 lines
64 KiB
1372 lines
64 KiB
// 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) 2015,2016,2017,2018 Jonathan Naylor, G4KLX
|
|
* Copyright (C) 2020-2026 Bryan Biedenkapp, N2PLL
|
|
*
|
|
*/
|
|
/**
|
|
* @defgroup network_core Networking Core
|
|
* @brief Implementation for the core networking.
|
|
* @ingroup common
|
|
* @defgroup socket Sockets
|
|
* @brief Implementation for handling network sockets.
|
|
* @ingroup network_core
|
|
*
|
|
* @file BaseNetwork.h
|
|
* @ingroup network_core
|
|
* @file BaseNetwork.cpp
|
|
* @ingroup network_core
|
|
*/
|
|
#if !defined(__BASE_NETWORK_H__)
|
|
#define __BASE_NETWORK_H__
|
|
|
|
#include "common/Defines.h"
|
|
#include "common/analog/data/NetData.h"
|
|
#include "common/dmr/data/NetData.h"
|
|
#include "common/p25/data/DataHeader.h"
|
|
#include "common/p25/data/LowSpeedData.h"
|
|
#include "common/p25/lc/LC.h"
|
|
#include "common/p25/Audio.h"
|
|
#include "common/nxdn/lc/RTCH.h"
|
|
#include "common/json/json.h"
|
|
#include "common/network/FrameQueue.h"
|
|
#include "common/network/udp/Socket.h"
|
|
#include "common/RingBuffer.h"
|
|
#include "common/Utils.h"
|
|
|
|
#include <string>
|
|
#include <cstdint>
|
|
#include <random>
|
|
#include <unordered_map>
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Constants
|
|
// ---------------------------------------------------------------------------
|
|
|
|
#define DVM_RAND_MIN 0x00000001
|
|
#define DVM_RAND_MAX 0xfffffffe
|
|
|
|
#define TAG_DMR_DATA "DMRD"
|
|
#define TAG_P25_DATA "P25D"
|
|
#define TAG_NXDN_DATA "NXDD"
|
|
#define TAG_ANALOG_DATA "ANOD"
|
|
|
|
#define TAG_REPEATER_LOGIN "RPTL"
|
|
#define TAG_REPEATER_AUTH "RPTK"
|
|
#define TAG_REPEATER_CONFIG "RPTC"
|
|
|
|
#define TAG_REPEATER_PING "RPTP"
|
|
#define TAG_REPEATER_GRANT "RPTG"
|
|
#define TAG_REPEATER_KEY "RKEY"
|
|
|
|
#define TAG_INCALL_CTRL "ICC "
|
|
|
|
#define TAG_TRANSFER "TRNS"
|
|
#define TAG_TRANSFER_ACT_LOG "TRNSLOG"
|
|
#define TAG_TRANSFER_DIAG_LOG "TRNSDIAG"
|
|
#define TAG_TRANSFER_STATUS "TRNSSTS"
|
|
#define TAG_TRANSFER_PATCH_STATUS "TRNSPTCH"
|
|
|
|
#define TAG_ANNOUNCE "ANNC"
|
|
#define TAG_PEER_REPLICA "REPL"
|
|
|
|
#define MAX_PEER_PING_TIME 60U // 60 seconds
|
|
|
|
namespace network
|
|
{
|
|
// ---------------------------------------------------------------------------
|
|
// Constants
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const uint32_t PACKET_PAD = 8U;
|
|
|
|
const uint32_t MSG_HDR_SIZE = 24U;
|
|
const uint32_t MSG_ANNC_GRP_AFFIL = 6U;
|
|
const uint32_t MSG_ANNC_GRP_UNAFFIL = 3U;
|
|
const uint32_t MSG_ANNC_UNIT_REG = 3U;
|
|
const uint32_t DMR_PACKET_LENGTH = 55U; // 20 byte header + DMR_FRAME_LENGTH_BYTES + 2 byte trailer
|
|
const uint32_t P25_LDU1_PACKET_LENGTH = 193U; // 24 byte header + DFSI data + 1 byte frame type + 12 byte enc sync
|
|
const uint32_t P25_LDU2_PACKET_LENGTH = 181U; // 24 byte header + DFSI data + 1 byte frame type
|
|
const uint32_t P25_TSDU_PACKET_LENGTH = 69U; // 24 byte header + TSDU data
|
|
const uint32_t P25_TDULC_PACKET_LENGTH = 78U; // 24 byte header + TDULC data
|
|
const uint32_t P25_P2_PACKET_LENGTH = 66U; // 24 byte header + P25_P2_FRAME_LENGTH_BYTES + 2 byte trailer
|
|
const uint32_t NXDN_PACKET_LENGTH = 70U; // 20 byte header + NXDN_FRAME_LENGTH_BYTES + 2 byte trailer
|
|
const uint32_t ANALOG_PACKET_LENGTH = 344U; // 20 byte header + AUDIO_SAMPLES_LENGTH_BYTES + 4 byte trailer
|
|
|
|
const uint32_t HA_PARAMS_ENTRY_LEN = 20U;
|
|
|
|
/**
|
|
* @brief Network Peer Connection Status
|
|
* @ingroup network_core
|
|
*/
|
|
enum NET_CONN_STATUS {
|
|
// Common States
|
|
NET_STAT_WAITING_CONNECT, //!< Waiting for Connection
|
|
NET_STAT_WAITING_LOGIN, //!< Waiting for Login
|
|
NET_STAT_WAITING_AUTHORISATION, //!< Waiting for Authorization
|
|
NET_STAT_WAITING_CONFIG, //!< Waiting for Configuration
|
|
NET_STAT_RUNNING, //!< Peer Running
|
|
|
|
// Master States
|
|
NET_STAT_RPTL_RECEIVED, //!< Login Received
|
|
NET_STAT_CHALLENGE_SENT, //!< Authentication Challenge Sent
|
|
|
|
NET_STAT_MST_RUNNING, //!< Master Running
|
|
|
|
NET_STAT_INVALID = 0x7FFFFFF //!< Invalid
|
|
};
|
|
|
|
/**
|
|
* @brief Network Peer NAK Reasons
|
|
* @ingroup network_core
|
|
*/
|
|
enum NET_CONN_NAK_REASON {
|
|
NET_CONN_NAK_GENERAL_FAILURE, //!< General Failure
|
|
|
|
NET_CONN_NAK_MODE_NOT_ENABLED, //!< Mode Not Enabled
|
|
NET_CONN_NAK_ILLEGAL_PACKET, //!< Illegal Packet
|
|
|
|
NET_CONN_NAK_FNE_UNAUTHORIZED, //!< FNE Unauthorized
|
|
NET_CONN_NAK_BAD_CONN_STATE, //!< Bad Connection State
|
|
NET_CONN_NAK_INVALID_CONFIG_DATA, //!< Invalid Configuration Data
|
|
NET_CONN_NAK_PEER_RESET, //!< Peer Reset
|
|
NET_CONN_NAK_PEER_ACL, //!< Peer ACL
|
|
|
|
NET_CONN_NAK_FNE_MAX_CONN, //!< FNE Maximum Connections
|
|
NET_CONN_NAK_FNE_DUPLICATE_CONN, //!< FNE Duplicate Connection
|
|
|
|
NET_CONN_NAK_INVALID = 0xFFFF //!< Invalid
|
|
};
|
|
|
|
/**
|
|
* @brief Network Control Enumerations
|
|
* @note These values are used typically for terminators to specify specific DVM in-band control operations.
|
|
* @ingroup network_core
|
|
*/
|
|
enum CONTROL_BYTE {
|
|
NET_CTRL_GRANT_DEMAND = 0x80U, //!< Grant Demand
|
|
NET_CTRL_GRANT_DENIAL = 0x40U, //!< Grant Denial
|
|
NET_CTRL_SWITCH_OVER = 0x20U, //!< Call Source RID Switch Over
|
|
NET_CTRL_GRANT_ENCRYPT = 0x08U, //!< Grant Encrypt
|
|
NET_CTRL_U2U = 0x01U, //!< Unit-to-Unit
|
|
};
|
|
|
|
/**
|
|
* @brief Peer Connection Class Enumerations
|
|
* @note These values define which connection class a peer connection belongs to. This is used for determining how
|
|
* to handle traffic from the peer.
|
|
* @ingroup network_core
|
|
*/
|
|
enum PEER_CONN_CLASS {
|
|
PEER_CONN_CLASS_UNKNOWN, //!< Unknown
|
|
|
|
PEER_CONN_CLASS_NEIGHBOR, //!< Neighbor FNE Peer
|
|
|
|
PEER_CONN_CLASS_STANDARD, //!< Standard Peer
|
|
|
|
PEER_CONN_CLASS_SYSVIEW, //!< SysView Peer
|
|
PEER_CONN_CLASS_CONSOLE, //!< Console Peer
|
|
|
|
// this should always be last
|
|
PEER_CONN_CLASS_INVALID
|
|
};
|
|
|
|
/**
|
|
* @brief RTP Stream Multiplex Validation Return Codes
|
|
* @ingroup network_core
|
|
*/
|
|
enum MULTIPLEX_RET_CODE {
|
|
MUX_VALID_SUCCESS = 0U, //!< Successful Validation
|
|
|
|
MUX_LOST_FRAMES = 1U, //!< Lost Frames
|
|
MUX_OUT_OF_ORDER = 2U //!< Out-of-Order
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Class Declaration
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/**
|
|
* @brief Handles dealing with maintaining RTP sequencing for multiple multiplexed RTP streams.
|
|
* @ingroup fne_network
|
|
*/
|
|
class HOST_SW_API RTPStreamMultiplex {
|
|
public:
|
|
auto operator=(RTPStreamMultiplex&) -> RTPStreamMultiplex& = delete;
|
|
auto operator=(RTPStreamMultiplex&&) -> RTPStreamMultiplex& = delete;
|
|
RTPStreamMultiplex(RTPStreamMultiplex&) = delete;
|
|
|
|
/**
|
|
* @brief Initializes a new instance of the RTPStreamMultiplex class.
|
|
*/
|
|
RTPStreamMultiplex() :
|
|
m_mutex(),
|
|
m_streamSeqNos()
|
|
{
|
|
/* stub */
|
|
}
|
|
/**
|
|
* @brief Finalizes a instance of the RTPStreamMultiplex class.
|
|
*/
|
|
~RTPStreamMultiplex()
|
|
{
|
|
m_streamSeqNos.clear();
|
|
}
|
|
|
|
/**
|
|
* @brief Helper to verify the given RTP sequence for the given multiplexed RTP stream.
|
|
* @param streamId Stream ID.
|
|
* @param pktSeq Packet Sequence.
|
|
* @param func Network function.
|
|
* @param[out] lastRxSeq Last Received Sequence.
|
|
* @return MULTIPLEX_RET_CODE Return code.
|
|
*/
|
|
MULTIPLEX_RET_CODE verifyStream(uint64_t streamId, uint16_t pktSeq, uint8_t func, uint16_t* lastRxSeq)
|
|
{
|
|
MULTIPLEX_RET_CODE ret = MUX_VALID_SUCCESS;
|
|
if (pktSeq == RTP_END_OF_CALL_SEQ) {
|
|
// only reset packet sequences if we're a PROTOCOL or RPTC function
|
|
if ((func == NET_FUNC::PROTOCOL) || (func == NET_FUNC::RPTC)) {
|
|
erasePktSeq(streamId); // attempt to erase packet sequence for the stream
|
|
}
|
|
} else {
|
|
if (hasPktSeq(streamId)) {
|
|
*lastRxSeq = getPktSeq(streamId);
|
|
|
|
if (*lastRxSeq == RTP_END_OF_CALL_SEQ) {
|
|
// reset the received sequence back to 0
|
|
setPktSeq(streamId, 0U);
|
|
}
|
|
else {
|
|
if ((pktSeq >= *lastRxSeq) || (pktSeq == 0U)) {
|
|
// if the sequence isn't 0, and is greater then the last received sequence + 1 frame
|
|
// assume a packet was lost
|
|
if ((pktSeq != 0U) && pktSeq >= *lastRxSeq + 1U) {
|
|
ret = MUX_LOST_FRAMES;
|
|
}
|
|
|
|
setPktSeq(streamId, pktSeq);
|
|
}
|
|
else {
|
|
if (pktSeq < *lastRxSeq) {
|
|
ret = MUX_OUT_OF_ORDER;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Helper to return the current count of multiplexed RTP streams.
|
|
* @returns size_t Count of stored streams.
|
|
*/
|
|
size_t streamCount()
|
|
{
|
|
return m_streamSeqNos.size();
|
|
}
|
|
|
|
/**
|
|
* @brief Helper to determine if the given multiplexed stream has a stored RTP sequence.
|
|
* @param streamId Stream ID.
|
|
* @returns bool True, if stream ID has a stored RTP sequence, otherwise false.
|
|
*/
|
|
bool hasPktSeq(uint64_t streamId)
|
|
{
|
|
bool ret = false;
|
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
|
|
|
// determine if the stream has a current sequence no and return
|
|
{
|
|
auto it = m_streamSeqNos.find(streamId);
|
|
if (it == m_streamSeqNos.end()) {
|
|
ret = false;
|
|
}
|
|
else {
|
|
ret = true;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Helper to get the stored RTP sequence for the given multiplexed stream.
|
|
* @param streamId Stream ID.
|
|
* @returns uint16_t Sequence number.
|
|
*/
|
|
uint16_t getPktSeq(uint64_t streamId)
|
|
{
|
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
|
|
|
// find the current sequence no and return
|
|
uint32_t pktSeq = 0U;
|
|
{
|
|
auto it = m_streamSeqNos.find(streamId);
|
|
if (it == m_streamSeqNos.end()) {
|
|
pktSeq = RTP_END_OF_CALL_SEQ;
|
|
} else {
|
|
pktSeq = m_streamSeqNos[streamId];
|
|
}
|
|
}
|
|
|
|
return pktSeq;
|
|
}
|
|
|
|
/**
|
|
* @brief Helper to set the stored RTP sequence for the given multiplexed stream.
|
|
* @param streamId Stream ID.
|
|
* @param seq Sequence number.
|
|
*/
|
|
void setPktSeq(uint64_t streamId, uint16_t seq)
|
|
{
|
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
|
auto it = m_streamSeqNos.find(streamId);
|
|
if (it == m_streamSeqNos.end()) {
|
|
m_streamSeqNos.insert({streamId, seq});
|
|
} else {
|
|
m_streamSeqNos[streamId] = seq;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Helper to increment the stored RTP sequence for the given multiplexed stream.
|
|
* @param streamId Stream ID.
|
|
* @returns uint16_t Incremented packet sequence.
|
|
*/
|
|
uint16_t incPktSeq(uint64_t streamId)
|
|
{
|
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
|
|
|
uint32_t pktSeq = 0U;
|
|
auto it = m_streamSeqNos.find(streamId);
|
|
if (it == m_streamSeqNos.end()) {
|
|
m_streamSeqNos.insert({streamId, pktSeq});
|
|
} else {
|
|
pktSeq = m_streamSeqNos[streamId];
|
|
++pktSeq;
|
|
|
|
if (pktSeq > (RTP_END_OF_CALL_SEQ - 1U))
|
|
pktSeq = 0U;
|
|
|
|
m_streamSeqNos[streamId] = pktSeq;
|
|
}
|
|
|
|
return pktSeq;
|
|
}
|
|
|
|
/**
|
|
* @brief Helper to erase the stored RTP sequence for the given multiplexed stream.
|
|
* @param streamId Stream ID.
|
|
*/
|
|
void erasePktSeq(uint64_t streamId)
|
|
{
|
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
|
|
|
// find the sequence no and erase
|
|
{
|
|
auto entry = m_streamSeqNos.find(streamId);
|
|
if (entry != m_streamSeqNos.end()) {
|
|
m_streamSeqNos.erase(streamId);
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::recursive_mutex m_mutex;
|
|
std::unordered_map<uint64_t, uint16_t> m_streamSeqNos;
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Class Declaration
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/**
|
|
* @brief Implements the base networking logic.
|
|
* @ingroup network_core
|
|
*/
|
|
class HOST_SW_API BaseNetwork {
|
|
public:
|
|
/**
|
|
* @brief Initializes a new instance of the BaseNetwork class.
|
|
* @param peerId Unique ID of this modem on the network.
|
|
* @param duplex Flag indicating full-duplex operation.
|
|
* @param debug Flag indicating whether network debug is enabled.
|
|
* @param slot1 Flag indicating whether DMR/P25 Phase 2 slot 1 is enabled for network traffic.
|
|
* @param slot2 Flag indicating whether DMR/P25 Phase 2 slot 2 is enabled for network traffic.
|
|
* @param allowActivityTransfer Flag indicating that the system activity logs will be sent to the network.
|
|
* @param allowDiagnosticTransfer Flag indicating that the system diagnostic logs will be sent to the network.
|
|
* @param localPort Local port used to listen for incoming data.
|
|
*/
|
|
BaseNetwork(uint32_t peerId, bool duplex, bool debug, bool slot1, bool slot2, bool allowActivityTransfer, bool allowDiagnosticTransfer,
|
|
uint16_t localPort = 0U);
|
|
/**
|
|
* @brief Finalizes a instance of the BaseNetwork class.
|
|
*/
|
|
virtual ~BaseNetwork();
|
|
|
|
/**
|
|
* @brief Gets the frame queue for the network.
|
|
*/
|
|
FrameQueue* getFrameQueue() const { return m_frameQueue; }
|
|
|
|
/**
|
|
* @brief Helper to enable or disable packet dump logging.
|
|
* @param enable Flag indicating whether packet dump logging is enabled.
|
|
*/
|
|
void setPacketDump(bool enable)
|
|
{
|
|
m_packetDump = enable;
|
|
if (m_frameQueue != nullptr)
|
|
m_frameQueue->setDebug(enable);
|
|
}
|
|
|
|
/**
|
|
* @brief Writes a grant request to the network.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the group affiliation
|
|
* announcement message. The message is 24 bytes in length.
|
|
*
|
|
* Byte 0 1 2 3
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Reserved |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | | Source ID |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Source ID | Destination ID |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Destination ID | Reserved |S| Reserverd |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Mode | Reserved |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* \endcode
|
|
* @param mode Digital Mode.
|
|
* @param srcId Source Radio ID.
|
|
* @param dstId Destination Radio ID.
|
|
* @param slot DMR slot number (if DMR).
|
|
* @param unitToUnit Flag indicating if this grant is unit-to-unit.
|
|
* @returns bool True, if grant request was sent, otherwise false.
|
|
*/
|
|
bool writeGrantReq(const uint8_t mode, const uint32_t srcId, const uint32_t dstId, const uint8_t slot, const bool unitToUnit);
|
|
|
|
/**
|
|
* @brief Writes a enc. key request to the network.
|
|
* @param kId Key ID.
|
|
* @param algId Algorithm ID.
|
|
* @param srcId Source Radio ID.
|
|
* @returns bool True, if request was sent, otherwise false.
|
|
*/
|
|
bool writeKeyReq(const uint16_t kId, const uint8_t algId, const uint32_t srcId = 0U);
|
|
|
|
/**
|
|
* @brief Writes a LLA enc. key request to the network.
|
|
* @param srcId Source Radio ID.
|
|
* @returns bool True, if request was sent, otherwise false.
|
|
*/
|
|
bool writeLLAKeyReq(const uint32_t srcId);
|
|
|
|
/**
|
|
* @brief Writes the local activity log to the network.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the activity log message.
|
|
* The message is variable length bytes.
|
|
*
|
|
* Byte 0 1 2 3
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Reserved |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | | Log Message . |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Log Message ................................................. |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* \endcode
|
|
* @param message Textual string to send as activity log information.
|
|
* @returns bool True, if message was sent, otherwise false.
|
|
*/
|
|
virtual bool writeActLog(const char* message);
|
|
|
|
/**
|
|
* @brief Writes the local diagnostic logs to the network.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the diagnostic log message.
|
|
* The message is variable length bytes.
|
|
*
|
|
* Byte 0 1 2 3
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Reserved |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | | Log Message . |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Log Message ................................................. |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* \endcode
|
|
* @returns bool True, if message was sent, otherwise false.
|
|
*/
|
|
virtual bool writeDiagLog(const char* message);
|
|
|
|
/**
|
|
* @brief Writes the local status to the network.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the peer status message.
|
|
* The message is variable length bytes.
|
|
*
|
|
* Byte 0 1 2 3
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Reserved |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | | Variable |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Length JSON Payload ......................................... |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
*
|
|
* The JSON payload is variable length and looks like this:
|
|
* {
|
|
* "state": <Modem State>,
|
|
* "isTxCW": <Boolean flag indicating if the end-point is transmitting CW>,
|
|
* "fixedMode": <Boolean flag indicating if the end-point is operating in fixed mode>,
|
|
* "dmrTSCCEnable": <Boolean flag indicating whether or not dedicated DMR TSCC is enabled>,
|
|
* "dmrCC": <Boolean flag indicating whether or not DMR CC is enabled>,
|
|
* "p25CtrlEnable": <Boolean flag indicating whether or not dedicatd P25 control is enabled>,
|
|
* "p25CC": <Boolean flag indicating whether or not P25 CC is enabled>,
|
|
* "nxdnCtrlEnable": <Boolean flag indicating whether or not dedicatd NXDN control is enabled>,
|
|
* "nxdnCC": <Boolean flag indicating whether or not NXDN CC is enabled>,
|
|
* "tx": <Boolean flag indicating whether end-point is transmitting>,
|
|
* "channelId": <Channel ID from the IDEN channel bandplan>,
|
|
* "channelNo": <Channel Number from the IDEN channel bandplan>,
|
|
* "lastDstId": <Last destination ID transmitted, may revert to 0 after a call ends>,
|
|
* "lastSrcId": <Last source ID transmitted, may revert to 0 after a call ends>,
|
|
* "peerId": <Unique Peer Identification Number>,
|
|
* "sysId": <System ID>,
|
|
* "siteId": <Site ID>,
|
|
* "p25RfssId": <P25 RFSS ID>,
|
|
* "p25NetId": <P25 WACN/Network ID>,
|
|
* "p25NAC": <P25 NAC>,
|
|
* "vcChannels": [
|
|
* {
|
|
* "channelId": <Channel ID from the IDEN channel bandplan>,
|
|
* "channelNo": <Channel Number from the IDEN channel bandplan>,
|
|
* "tx": <Boolean flag indicating whether end-point is transmitting>,
|
|
* "lastDstId": <Last destination ID transmitted, may revert to 0 after a call ends>,
|
|
* "lastSrcId": <Last source ID transmitted, may revert to 0 after a call ends>,
|
|
* }
|
|
* ],
|
|
* "modem": {
|
|
* "portType": "<Port Type>",
|
|
* "modemPort": "<Modem Port>",
|
|
* "portSpeed": <Port Speed>,
|
|
* "rxLevel": <Configured Rx Level>,
|
|
* "cwTxLevel": <Configured CWID Tx Level>,
|
|
* "dmrTxLevel": <Configured DMR Tx Level>,
|
|
* "p25TxLevel": <Configured P25 Tx Level>,
|
|
* "nxdnTxLevel": <Configured NXDN Tx Level>,
|
|
* "rxDCOffset": <Configured Rx DC Offset>,
|
|
* "txDCOffset": <Configured Tx DC Offset>,
|
|
* "fdmaPremables": <Configured FDMA Preambles>,
|
|
* "dmrRxDelay": <Configured DMR Rx Delay>,
|
|
* "p25CorrCount": <Configured P25 Correlation Count>,
|
|
* "rxFrequency": <Peer Rx Frequency in Hz>,
|
|
* "txFrequency": <Peer Tx Frequency in Hz>,
|
|
* "rxTuning": <Peer Rx Tuning Offset>,
|
|
* "txTuning": <Peer Tx Tuning Offset>,
|
|
* "rxFrequencyEffective": <Peer Rx Effective Frequency in Hz>,
|
|
* "txFrequencyEffective": <Peer Tx Effective Frequency in Hz>,
|
|
* "v24Connected": <Boolean indicating V.24 is connected (if a V.24 modem)>,
|
|
* "protoVer": <Protocol version>
|
|
* }
|
|
* }
|
|
* \endcode
|
|
* @param obj JSON object representing the local peer status.
|
|
* @returns bool True, if peer status was sent, otherwise false.
|
|
*/
|
|
virtual bool writePeerStatus(json::object obj);
|
|
|
|
/**
|
|
* @brief Writes a group affiliation to the network.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the group affiliation
|
|
* announcement message. The message is 6 bytes in length.
|
|
*
|
|
* Byte 0 1 2 3
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Source ID | Dest ID |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* \endcode
|
|
* @param srcId Source Radio ID.
|
|
* @param dstId Destination Talkgroup ID.
|
|
* @returns bool True, if group affiliation announcement was sent, otherwise false.
|
|
*/
|
|
virtual bool announceGroupAffiliation(uint32_t srcId, uint32_t dstId);
|
|
/**
|
|
* @brief Writes a group affiliation removal to the network.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the unit registration
|
|
* announcement message. The message is 3 bytes in length.
|
|
*
|
|
* Byte 0 1 2
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Source ID |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* \endcode
|
|
* @param srcId Source Radio ID.
|
|
* @returns bool True, if group affiliation announcement was sent, otherwise false.
|
|
*/
|
|
virtual bool announceGroupAffiliationRemoval(uint32_t srcId);
|
|
|
|
/**
|
|
* @brief Writes a unit registration to the network.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the unit registration
|
|
* announcement message. The message is 3 bytes in length.
|
|
*
|
|
* Byte 0 1 2
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Source ID |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* \endcode
|
|
* @param srcId Source Radio ID.
|
|
* @returns bool True, if unit registration announcement was sent, otherwise false.
|
|
*/
|
|
virtual bool announceUnitRegistration(uint32_t srcId);
|
|
/**
|
|
* @brief Writes a unit deregistration to the network.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the unit deregistration
|
|
* announcement message. The message is 3 bytes in length.
|
|
*
|
|
* Byte 0 1 2
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Source ID |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* \endcode
|
|
* @param srcId Source Radio ID.
|
|
* @returns bool True, if unit deregistration announcement was sent, otherwise false.
|
|
*/
|
|
virtual bool announceUnitDeregistration(uint32_t srcId);
|
|
|
|
/**
|
|
* @brief Writes a complete update of the peer affiliation list to the network.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the repeater/end point login message.
|
|
* The message is variable bytes in length.
|
|
*
|
|
* Each affiliation update entry is 7 bytes.
|
|
*
|
|
* Byte 0 1 2 3
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Number of entries |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Entry: Source ID | E: Dst Id |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Entry: Destination ID |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* \endcode
|
|
* @param affs Complete map of peer unit affiliations.
|
|
* @returns bool True, if affiliation update announcement was sent, otherwise false.
|
|
*/
|
|
virtual bool announceAffiliationUpdate(const std::unordered_map<uint32_t, uint32_t> affs);
|
|
|
|
/**
|
|
* @brief Writes a complete update of the peer's unit registration list to the network.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the repeater/end point login message.
|
|
* The message is variable bytes in length.
|
|
*
|
|
* Each unit registration update entry is 3 bytes.
|
|
*
|
|
* Byte 0 1 2 3
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Number of entries |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Entry: Source ID |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* \endcode
|
|
* @param regs Complete list of unit registrations.
|
|
* @returns bool True, if unit registration update announcement was sent, otherwise false.
|
|
*/
|
|
virtual bool announceUnitRegUpdate(const std::vector<uint32_t> regs);
|
|
|
|
/**
|
|
* @brief Writes a complete update of the peer's voice channel list to the network.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the repeater/end point login message.
|
|
* The message is variable bytes in length.
|
|
*
|
|
* Each peer ID entry is 4 bytes.
|
|
*
|
|
* Byte 0 1 2 3
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Number of entries |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Entry: Peer ID |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* \endcode
|
|
* @param peers List of voice channel peers.
|
|
* @returns bool True, if peer update announcement was sent, otherwise false.
|
|
*/
|
|
virtual bool announceSiteVCs(const std::vector<uint32_t> peers);
|
|
|
|
/**
|
|
* @brief Updates the timer by the passed number of milliseconds.
|
|
* @param ms Number of milliseconds.
|
|
*/
|
|
virtual void clock(uint32_t ms) = 0;
|
|
|
|
/**
|
|
* @brief Opens connection to the network.
|
|
* @returns bool True, if connection to network opened, otherwise false.
|
|
*/
|
|
virtual bool open() = 0;
|
|
|
|
/**
|
|
* @brief Closes connection to the network.
|
|
*/
|
|
virtual void close() = 0;
|
|
|
|
/**
|
|
* @brief Resets the DMR ring buffer for the given slot.
|
|
* @param slotNo DMR slot number.
|
|
*/
|
|
virtual void resetDMR(uint32_t slotNo);
|
|
/**
|
|
* @brief Resets the P25 ring buffer.
|
|
*/
|
|
virtual void resetP25();
|
|
/**
|
|
* @brief Resets the P25 Phase 2 ring buffer for the given slot.
|
|
* @param slotNo P25 Phase 2 slot number.
|
|
*/
|
|
virtual void resetP25P2(uint32_t slotNo);
|
|
/**
|
|
* @brief Resets the NXDN ring buffer.
|
|
*/
|
|
virtual void resetNXDN();
|
|
/**
|
|
* @brief Resets the analog ring buffer.
|
|
*/
|
|
virtual void resetAnalog();
|
|
|
|
/**
|
|
* @brief Gets the current DMR stream ID.
|
|
* @param slotNo DMR slot to get stream ID for.
|
|
* @return uint32_t Stream ID for the given DMR slot.
|
|
*/
|
|
uint32_t getDMRStreamId(uint32_t slotNo) const;
|
|
/**
|
|
* @brief Gets the current P25 stream ID.
|
|
* @return uint32_t Stream ID.
|
|
*/
|
|
uint32_t getP25StreamId() const { return m_p25StreamId; }
|
|
/**
|
|
* @brief Gets the current P25 Phase 2 stream ID.
|
|
* @param slotNo P25 Phase 2 slot to get stream ID for.
|
|
* @return uint32_t Stream ID for the given P25 Phase 2 slot.
|
|
*/
|
|
uint32_t getP25P2StreamId(uint32_t slotNo) const;
|
|
/**
|
|
* @brief Gets the current NXDN stream ID.
|
|
* @return uint32_t Stream ID.
|
|
*/
|
|
uint32_t getNXDNStreamId() const { return m_nxdnStreamId; }
|
|
/**
|
|
* @brief Gets the current analog stream ID.
|
|
* @return uint32_t Stream ID.
|
|
*/
|
|
uint32_t getAnalogStreamId() const { return m_analogStreamId; }
|
|
|
|
/**
|
|
* @brief Helper to send a data message to the master.
|
|
* @param opcode Opcode.
|
|
* @param data Buffer to write to the network.
|
|
* @param length Length of buffer to write.
|
|
* @param pktSeq RTP packet sequence.
|
|
* @param streamId Stream ID.
|
|
* @param metadata Flag indicating the message should be sent to the metadata port.
|
|
* @param peerId If non-zero, overrides the peer ID sent in the packet to the master.
|
|
* @param ssrc If non-zero, overrides the RTP synchronization source ID sent in the packet to the master.
|
|
* @returns bool True, if message was sent, otherwise false.
|
|
*/
|
|
bool writeMaster(FrameQueue::OpcodePair opcode, const uint8_t* data, uint32_t length,
|
|
uint16_t pktSeq, uint32_t streamId, bool metadata = false, uint32_t peerId = 0U, uint32_t ssrc = 0U);
|
|
|
|
// Digital Mobile Radio
|
|
/**
|
|
* @brief Reads DMR raw frame data from the DMR ring buffer.
|
|
* @param[out] ret Flag indicating whether or not data was received.
|
|
* @param[out] frameLength Length in bytes of received frame.
|
|
* @returns UInt8Array Buffer containing received frame.
|
|
*/
|
|
virtual UInt8Array readDMR(bool& ret, uint32_t& frameLength);
|
|
/**
|
|
* @brief Writes DMR frame data to the network.
|
|
* @param[in] data Instance of the dmr::data::NetData class containing the DMR message.
|
|
* @param noSequence Flag indicating the message should be sent with no RTP sequence (65535).
|
|
* @returns bool True, if message was sent, otherwise false.
|
|
*/
|
|
virtual bool writeDMR(const dmr::data::NetData& data, bool noSequence = false);
|
|
|
|
/**
|
|
* @brief Helper to test if the DMR ring buffer has data.
|
|
* @returns bool True, if the network DMR ring buffer has data, otherwise false.
|
|
*/
|
|
bool hasDMRData() const;
|
|
|
|
// Project 25
|
|
/**
|
|
* @brief Reads P25 raw frame data from the P25 ring buffer.
|
|
* @param[out] ret Flag indicating whether or not data was received.
|
|
* @param[out] frameLength Length in bytes of received frame.
|
|
* @returns UInt8Array Buffer containing received frame.
|
|
*/
|
|
virtual UInt8Array readP25(bool& ret, uint32_t& frameLength);
|
|
/**
|
|
* @brief Helper to test if the given buffer contains a complete set of P25 LDU voice vectors for the given DUID type.
|
|
* @param[in] data Buffer containing the data to check.
|
|
* @param len Length of the data buffer.
|
|
* @param[in] duid P25 DUID type.
|
|
* @returns bool True, if the buffer contains P25 LDU voice vectors for the given DUID type, otherwise false.
|
|
*/
|
|
static bool hasLDUVectors(const uint8_t* data, uint32_t len, P25DEF::DUID::E duid);
|
|
/**
|
|
* @brief Helper to reconstruct P25 LDU voice vectors from the given DFSI data.
|
|
* @param[in] dfsiData Buffer containing the DFSI data to reconstruct from.
|
|
* @param len Length of the DFSI data buffer.
|
|
* @param[in] dfsiLC Instance of p25::dfsi::LC containing the DFSI link control data.
|
|
* @param[in] duid P25 DUID type.
|
|
* @param[out] outLDU Buffer to write the reconstructed LDU voice vectors to.
|
|
* @returns uint8_t Number of missing frames, 9 if reconstruction failed, otherwise the number of missing frames.
|
|
*/
|
|
static uint8_t reconstructLDUVectors(const uint8_t* dfsiData, uint32_t len, p25::dfsi::LC* dfsiLC, P25DEF::DUID::E duid,
|
|
uint8_t* outLDU);
|
|
/**
|
|
* @brief Writes P25 LDU1 frame data to the network.
|
|
* @param[in] control Instance of p25::lc::LC containing link control data.
|
|
* @param[in] lsd Instance of p25::data::LowSpeedData containing low speed data.
|
|
* @param[in] data Buffer containing P25 LDU1 data to send.
|
|
* @param[in] frameType DVM P25 frame type.
|
|
* @param[in] controlByte DVM Network Control Byte.
|
|
* @returns bool True, if message was sent, otherwise false.
|
|
*/
|
|
virtual bool writeP25LDU1(const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, const uint8_t* data,
|
|
P25DEF::FrameType::E frameType, uint8_t controlByte = 0U);
|
|
/**
|
|
* @brief Writes P25 LDU2 frame data to the network.
|
|
* @param[in] control Instance of p25::lc::LC containing link control data.
|
|
* @param[in] lsd Instance of p25::data::LowSpeedData containing low speed data.
|
|
* @param[in] data Buffer containing P25 LDU2 data to send.
|
|
* @param[in] controlByte DVM Network Control Byte.
|
|
* @returns bool True, if message was sent, otherwise false.
|
|
*/
|
|
virtual bool writeP25LDU2(const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, const uint8_t* data,
|
|
uint8_t controlByte = 0U);
|
|
/**
|
|
* @brief Writes P25 TDU frame data to the network.
|
|
* @param[in] control Instance of p25::lc::LC containing link control data.
|
|
* @param[in] lsd Instance of p25::data::LowSpeedData containing low speed data.
|
|
* @param[in] controlByte DVM control byte.
|
|
* @returns bool True, if message was sent, otherwise false.
|
|
*/
|
|
virtual bool writeP25TDU(const p25::lc::LC& control, const p25::data::LowSpeedData& lsd, const uint8_t controlByte = 0U);
|
|
/**
|
|
* @brief Writes P25 TSDU frame data to the network.
|
|
* @param[in] control Instance of p25::lc::LC containing link control data.
|
|
* @param[in] data Buffer containing P25 TSDU data to send.
|
|
* @returns bool True, if message was sent, otherwise false.
|
|
*/
|
|
virtual bool writeP25TSDU(const p25::lc::LC& control, const uint8_t* data);
|
|
/**
|
|
* @brief Writes P25 TDULC frame data to the network.
|
|
* @param[in] control Instance of p25::lc::LC containing link control data.
|
|
* @param[in] data Buffer containing P25 TDULC data to send.
|
|
* @returns bool True, if message was sent, otherwise false.
|
|
*/
|
|
virtual bool writeP25TDULC(const p25::lc::LC& control, const uint8_t* data);
|
|
/**
|
|
* @brief Writes P25 PDU frame data to the network.
|
|
* @param[in] dataHeader Instance of p25::data::DataHeader containing PDU header data.
|
|
* @param currentBlock Current block index being sent.
|
|
* @param[in] data Buffer containing P25 PDU block data to send.
|
|
* @param len Length of P25 PDU block data.
|
|
* @param lastBlock Flag indicating whether or not this is the last block of PDU data.
|
|
* @returns bool True, if message was sent, otherwise false.
|
|
*/
|
|
virtual bool writeP25PDU(const p25::data::DataHeader& header, const uint8_t currentBlock, const uint8_t* data,
|
|
const uint32_t len, bool lastBlock);
|
|
|
|
/**
|
|
* @brief Reads P25 Phase 2 raw frame data from the P25 Phase 2 ring buffer.
|
|
* @param[out] ret Flag indicating whether or not data was received.
|
|
* @param[out] frameLength Length in bytes of received frame.
|
|
* @returns UInt8Array Buffer containing received frame.
|
|
*/
|
|
virtual UInt8Array readP25P2(bool& ret, uint32_t& frameLength);
|
|
/**
|
|
* @brief Writes P25 Phase 2 frame data to the network.
|
|
* @param[in] control Instance of p25::lc::LC containing link control data.
|
|
* @param[in] duid P25 Phase 2 DUID type.
|
|
* @param[in] slot P25 Phase 2 slot number.
|
|
* @param[in] data Buffer containing P25 Phase 2 data to send.
|
|
* @param[in] controlByte DVM control byte.
|
|
* @returns bool True, if message was sent, otherwise false.
|
|
*/
|
|
virtual bool writeP25P2(const p25::lc::LC& control, p25::defines::P2_DUID::E duid, uint8_t slot, const uint8_t* data,
|
|
const uint8_t controlByte = 0U);
|
|
|
|
/**
|
|
* @brief Helper to test if the P25 ring buffer has data.
|
|
* @returns bool True, if the network P25 ring buffer has data, otherwise false.
|
|
*/
|
|
bool hasP25Data() const;
|
|
|
|
/**
|
|
* @brief Helper to test if the P25 Phase 2 ring buffer has data.
|
|
* @returns bool True, if the network P25 Phase 2 ring buffer has data, otherwise false.
|
|
*/
|
|
bool hasP25P2Data() const;
|
|
|
|
/**
|
|
* @brief Helper to validate a P25 network frame length.
|
|
* @param frameLength P25 encapsulated frame length.
|
|
* @param len Network packet length.
|
|
* @return bool True, if validated, otherwise false.
|
|
*/
|
|
bool validateP25FrameLength(uint8_t& frameLength, const uint32_t len, const P25DEF::DUID::E duid);
|
|
|
|
// Next Generation Digital Narrowband
|
|
/**
|
|
* @brief Reads NXDN raw frame data from the NXDN ring buffer.
|
|
* @param[out] ret Flag indicating whether or not data was received.
|
|
* @param[out] frameLength Length in bytes of received frame.
|
|
* @returns UInt8Array Buffer containing received frame.
|
|
*/
|
|
virtual UInt8Array readNXDN(bool& ret, uint32_t& frameLength);
|
|
/**
|
|
* @brief Writes NXDN frame data to the network.
|
|
* @param[in] lc Instance of nxdn::lc::RTCH containing link control data.
|
|
* @param[in] data Buffer containing RTCH data to send.
|
|
* @param[in] len Length of buffer.
|
|
* @param noSequence Flag indicating the message should be sent with no RTP sequence (65535).
|
|
* @returns bool True, if message was sent, otherwise false.
|
|
*/
|
|
virtual bool writeNXDN(const nxdn::lc::RTCH& lc, const uint8_t* data, const uint32_t len, bool noSequence = false);
|
|
|
|
/**
|
|
* @brief Helper to test if the NXDN ring buffer has data.
|
|
* @returns bool True, if the network NXDN ring buffer has data, otherwise false.
|
|
*/
|
|
bool hasNXDNData() const;
|
|
|
|
// Analog Audio
|
|
/**
|
|
* @brief Reads analog MuLaw audio frame data from the analog ring buffer.
|
|
* @param[out] ret Flag indicating whether or not data was received.
|
|
* @param[out] frameLength Length in bytes of received frame.
|
|
* @returns UInt8Array Buffer containing received frame.
|
|
*/
|
|
virtual UInt8Array readAnalog(bool& ret, uint32_t& frameLength);
|
|
/**
|
|
* @brief Writes analog MuLaw audio frame data to the network.
|
|
* @param[in] data Instance of the analog::data::NetData class containing the analog message.
|
|
* @param noSequence Flag indicating the message should be sent with no RTP sequence (65535).
|
|
* @returns bool True, if message was sent, otherwise false.
|
|
*/
|
|
virtual bool writeAnalog(const analog::data::NetData& data, bool noSequence = false);
|
|
|
|
/**
|
|
* @brief Helper to test if the analog ring buffer has data.
|
|
* @returns bool True, if the network analog ring buffer has data, otherwise false.
|
|
*/
|
|
bool hasAnalogData() const;
|
|
|
|
public:
|
|
/**
|
|
* @brief Gets the peer ID of the network.
|
|
*/
|
|
DECLARE_PROTECTED_RO_PROPERTY(uint32_t, peerId, PeerId);
|
|
/**
|
|
* @brief Gets the current status of the network.
|
|
*/
|
|
DECLARE_PROTECTED_RO_PROPERTY(NET_CONN_STATUS, status, Status);
|
|
|
|
/**
|
|
* @brief Unix socket storage containing the connected address.
|
|
*/
|
|
DECLARE_PROTECTED_RO_PROPERTY_PLAIN(sockaddr_storage, addr);
|
|
/**
|
|
* @brief Length of the sockaddr_storage structure.
|
|
*/
|
|
DECLARE_PROTECTED_RO_PROPERTY_PLAIN(uint32_t, addrLen);
|
|
|
|
/**
|
|
* @brief Flag indicating whether network DMR/P25 Phase 2 slot 1 traffic is permitted.
|
|
*/
|
|
DECLARE_PROTECTED_RO_PROPERTY(bool, slot1, Slot1);
|
|
/**
|
|
* @brief Flag indicating whether network DMR/P25 Phase 2 slot 2 traffic is permitted.
|
|
*/
|
|
DECLARE_PROTECTED_RO_PROPERTY(bool, slot2, Slot2);
|
|
|
|
/**
|
|
* @brief Flag indicating whether network traffic is duplex.
|
|
*/
|
|
DECLARE_PROTECTED_RO_PROPERTY(bool, duplex, Duplex);
|
|
|
|
protected:
|
|
bool m_allowActivityTransfer;
|
|
bool m_allowDiagnosticTransfer;
|
|
|
|
bool m_packetDump;
|
|
bool m_debug;
|
|
|
|
udp::Socket* m_socket;
|
|
FrameQueue* m_frameQueue;
|
|
|
|
RingBuffer<uint8_t> m_rxDMRData;
|
|
RingBuffer<uint8_t> m_rxP25Data;
|
|
RingBuffer<uint8_t> m_rxP25P2Data;
|
|
RingBuffer<uint8_t> m_rxNXDNData;
|
|
RingBuffer<uint8_t> m_rxAnalogData;
|
|
|
|
std::mt19937 m_random;
|
|
|
|
uint32_t* m_dmrStreamId;
|
|
uint32_t m_p25StreamId;
|
|
uint32_t* m_p25P2StreamId;
|
|
uint32_t m_nxdnStreamId;
|
|
uint32_t m_analogStreamId;
|
|
|
|
/**
|
|
* @brief Helper to update the RTP packet sequence.
|
|
* @param reset Flag indicating the current RTP packet sequence value should be reset.
|
|
* @returns uint16_t RTP packet sequence.
|
|
*/
|
|
uint16_t pktSeq(bool reset = false);
|
|
|
|
/**
|
|
* @brief Generates a new stream ID.
|
|
* @returns uint32_t New stream ID.
|
|
*/
|
|
uint32_t createStreamId() { std::uniform_int_distribution<uint32_t> dist(DVM_RAND_MIN, DVM_RAND_MAX); return dist(m_random); }
|
|
|
|
/**
|
|
* @brief Creates an DMR frame message.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the DMR frame
|
|
* message header. The header is 20 bytes in length.
|
|
*
|
|
* Byte 0 1 2 3
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Protocol Tag (DMRD) |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Seq No. | Source ID |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Destination ID | Reserved |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Reserved | Control Flags |S|G| Data Type |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Reserved |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
*
|
|
* S = Slot Number (clear Slot 1, set Slot 2)
|
|
* G = Group Flag
|
|
*
|
|
* The data starting at offset 20 for 33 bytes of the raw DMR frame.
|
|
*
|
|
* DMR frame message has 2 trailing bytes:
|
|
*
|
|
* Byte 53 54
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | BER | RSSI |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* \endcode
|
|
* @param[out] length Length of network message buffer.
|
|
* @param streamId Stream ID.
|
|
* @param data Instance of the dmr::data::Data class containing the DMR message.
|
|
* @returns UInt8Array Buffer containing the built network message.
|
|
*/
|
|
UInt8Array createDMR_Message(uint32_t& length, const uint32_t streamId, const dmr::data::NetData& data);
|
|
|
|
/**
|
|
* @brief Creates an P25 frame message header.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the P25 frame
|
|
* message header. The header is 24 bytes in length.
|
|
*
|
|
* Byte 0 1 2 3
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Protocol Tag (P25D) |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | LCO | Source ID |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Destination ID | System ID |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | System ID | Reserved | Control Flags | MFId |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Network ID |S|Rsvd |P2 DUID|
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | LSD1 | LSD2 | DUID | Frame Length |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
*
|
|
* S = Slot Number (clear Slot 1, set Slot 2)
|
|
*
|
|
* The data starting at offset 20 for variable number of bytes (DUID dependant)
|
|
* is the P25 frame.
|
|
*
|
|
* If the P25 frame message is a LDU1, it contains 13 trailing bytes that
|
|
* contain the frame type, and encryption data.
|
|
*
|
|
* Byte 180 181 182 183
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Frame Type | Algorithm ID | Key ID |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Message Indicator |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | |
|
|
* +-+-+-+-+-+-+-+-+
|
|
* \endcode
|
|
* @param buffer Buffer to store the P25 network message header.
|
|
* @param duid P25 DUID.
|
|
* @param[in] control Instance of p25::lc::LC containing link control data.
|
|
* @param[in] lsd Instance of p25::data::LowSpeedData containing low speed data.
|
|
* @param[in] frameType DVM P25 frame type.
|
|
* @param[in] controlByte DVM Network Control Byte.
|
|
*/
|
|
void createP25_MessageHdr(uint8_t* buffer, p25::defines::DUID::E duid, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd,
|
|
p25::defines::FrameType::E frameType = p25::defines::FrameType::DATA_UNIT, uint8_t controlByte = 0U);
|
|
|
|
/**
|
|
* @brief Creates an P25 LDU1 frame message.
|
|
*
|
|
* The data packed into a P25 LDU1 frame message is near standard DFSI messaging, just instead of
|
|
* 9 individual frames, they are packed into a single message one right after another.
|
|
*
|
|
* @param[out] length Length of network message buffer.
|
|
* @param[in] control Instance of p25::lc::LC containing link control data.
|
|
* @param[in] lsd Instance of p25::data::LowSpeedData containing low speed data.
|
|
* @param[in] data Buffer containing P25 LDU1 data to send.
|
|
* @param[in] frameType DVM P25 frame type.
|
|
* @param[in] controlByte DVM Network Control Byte.
|
|
* @returns UInt8Array Buffer containing the built network message.
|
|
*/
|
|
UInt8Array createP25_LDU1Message(uint32_t& length, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd,
|
|
const uint8_t* data, p25::defines::FrameType::E frameType, uint8_t controlByte = 0U);
|
|
/**
|
|
* @brief Creates an P25 LDU2 frame message.
|
|
*
|
|
* The data packed into a P25 LDU2 frame message is near standard DFSI messaging, just instead of
|
|
* 9 individual frames, they are packed into a single message one right after another.
|
|
*
|
|
* @param[out] length Length of network message buffer.
|
|
* @param[in] control Instance of p25::lc::LC containing link control data.
|
|
* @param[in] lsd Instance of p25::data::LowSpeedData containing low speed data.
|
|
* @param[in] data Buffer containing P25 LDU2 data to send.
|
|
* @param[in] controlByte DVM Network Control Byte.
|
|
* @returns UInt8Array Buffer containing the built network message.
|
|
*/
|
|
UInt8Array createP25_LDU2Message(uint32_t& length, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd,
|
|
const uint8_t* data, uint8_t controlByte = 0U);
|
|
|
|
/**
|
|
* @brief Creates an P25 TDU frame message.
|
|
*
|
|
* The data packed into a P25 TDU frame message is essentially just a message header with control bytes
|
|
* set.
|
|
*
|
|
* @param[out] length Length of network message buffer.
|
|
* @param[in] control Instance of p25::lc::LC containing link control data.
|
|
* @param[in] lsd Instance of p25::data::LowSpeedData containing low speed data.
|
|
* @param controlByte DVM control byte.
|
|
* @returns UInt8Array Buffer containing the built network message.
|
|
*/
|
|
UInt8Array createP25_TDUMessage(uint32_t& length, const p25::lc::LC& control, const p25::data::LowSpeedData& lsd,
|
|
const uint8_t controlByte);
|
|
|
|
/**
|
|
* @brief Creates an P25 TSDU frame message.
|
|
*
|
|
* The data packed into a P25 TSDU frame message is essentially just a message header with the FEC encoded
|
|
* raw TSDU data.
|
|
*
|
|
* @param[out] length Length of network message buffer.
|
|
* @param[in] control Instance of p25::lc::LC containing link control data.
|
|
* @param[in] data Buffer containing P25 TSDU data to send.
|
|
* @returns UInt8Array Buffer containing the built network message.
|
|
*/
|
|
UInt8Array createP25_TSDUMessage(uint32_t& length, const p25::lc::LC& control, const uint8_t* data);
|
|
|
|
/**
|
|
* @brief Creates an P25 TDULC frame message.
|
|
*
|
|
* The data packed into a P25 TDULC frame message is essentially just a message header with the FEC encoded
|
|
* raw TDULC data.
|
|
*
|
|
* @param[out] length Length of network message buffer.
|
|
* @param[in] control Instance of p25::lc::LC containing link control data.
|
|
* @param[in] data Buffer containing P25 TDULC data to send.
|
|
* @returns UInt8Array Buffer containing the built network message.
|
|
*/
|
|
UInt8Array createP25_TDULCMessage(uint32_t& length, const p25::lc::LC& control, const uint8_t* data);
|
|
|
|
/**
|
|
* @brief Creates an P25 PDU frame message.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the P25 frame
|
|
* message header used for a PDU. The header is 24 bytes in length.
|
|
*
|
|
* Byte 0 1 2 3
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Protocol Tag (P25D) |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* |C| SAP | Reserved |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | PDU Length (Bytes) | Reserved |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | | MFId |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Reserved |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Blk to Flw | Current Block | DUID | Frame Length |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
*
|
|
* C = Confirmed PDU Flag
|
|
*
|
|
* The data starting at offset 24 for variable number of bytes (DUID dependant)
|
|
* is the P25 frame.
|
|
* \endcode
|
|
* @param[out] length Length of network message buffer.
|
|
* @param[in] header Instance of p25::data::DataHeader containing PDU header data.
|
|
* @param currentBlock Current block index being sent.
|
|
* @param[in] data Buffer containing P25 PDU block data to send.
|
|
* @param len Length of P25 PDU block data.
|
|
* @returns UInt8Array Buffer containing the built network message.
|
|
*/
|
|
UInt8Array createP25_PDUMessage(uint32_t& length, const p25::data::DataHeader& header, const uint8_t currentBlock,
|
|
const uint8_t* data, const uint32_t len);
|
|
|
|
/**
|
|
* @brief Creates an P25 Phase 2 frame message.
|
|
* \code{.unparsed}
|
|
*
|
|
* The data packed into a P25 Phase 2 frame message is essentially just a message header with the FEC encoded
|
|
* raw Phase 2 data.
|
|
*
|
|
* The data starting at offset 24 for 40 bytes of the raw P25 Phase 2 frame.
|
|
*
|
|
* \endcode
|
|
* @param[out] length Length of network message buffer.
|
|
* @param[in] control Instance of p25::lc::LC containing link control data.
|
|
* @param duid P25 Phase 2 DUID.
|
|
* @param[in] slot P25 Phase 2 slot (clear Slot 1, set Slot 2).
|
|
* @param[in] data Buffer containing P25 LDU2 data to send.
|
|
* @param[in] controlByte DVM Network Control Byte.
|
|
* @param data Instance of the dmr::data::Data class containing the DMR message.
|
|
* @returns UInt8Array Buffer containing the built network message.
|
|
*/
|
|
UInt8Array createP25P2_Message(uint32_t& length, const p25::lc::LC& control, p25::defines::P2_DUID::E duid,
|
|
const bool slot, const uint8_t* data, uint8_t controlByte = 0U);
|
|
|
|
/**
|
|
* @brief Creates an NXDN frame message.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the NXDN frame
|
|
* message header. The header is 24 bytes in length.
|
|
*
|
|
* Byte 0 1 2 3
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Protocol Tag (NXDD) |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Message Type | Source ID |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Destination ID | Reserved |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Reserved | Control Flags |R|G| Reserved |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Reserved |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | | Frame Length |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
*
|
|
* G = Group Flag
|
|
*
|
|
* The data starting at offset 24 for 48 bytes if the raw NXDN frame.
|
|
* \endcode
|
|
* @param[out] length Length of network message buffer.
|
|
* @param[in] lc Instance of nxdn::lc::RTCH containing link control data.
|
|
* @param[in] data Buffer containing RTCH data to send.
|
|
* @param[in] len Length of buffer.
|
|
* @returns UInt8Array Buffer containing the built network message.
|
|
*/
|
|
UInt8Array createNXDN_Message(uint32_t& length, const nxdn::lc::RTCH& lc, const uint8_t* data, const uint32_t len);
|
|
|
|
/**
|
|
* @brief Creates an analog frame message.
|
|
* \code{.unparsed}
|
|
* Below is the representation of the data layout for the analog frame
|
|
* message header. The header is 20 bytes in length.
|
|
*
|
|
* Byte 0 1 2 3
|
|
* Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Protocol Tag (ANOD) |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Seq No. | Source ID |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Destination ID | Reserved |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Reserved | Control Flags | R | Data Type |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Reserved |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
*
|
|
* The data starting at offset 20 for 320 bytes of the raw analog frame.
|
|
* \endcode
|
|
* @param[out] length Length of network message buffer.
|
|
* @param streamId Stream ID.
|
|
* @param data Instance of the analog::data::Data class containing the analog message.
|
|
* @returns UInt8Array Buffer containing the built network message.
|
|
*/
|
|
UInt8Array createAnalog_Message(uint32_t& length, const uint32_t streamId, const analog::data::NetData& data);
|
|
|
|
private:
|
|
uint16_t m_pktSeq;
|
|
|
|
p25::Audio m_audio;
|
|
};
|
|
} // namespace network
|
|
|
|
#endif // __BASE_NETWORK_H__
|