R04H31 Merge to Master (#89)

* simplify and refactor peer-link packet handling;

* bump version number to match dev branch; alter logging for peer-link data;

* warn on packets generated over 4K;

* don't clear map directly, use clear() helper;

* use parens vs braces for initializers; correct case fall-thru on SysView;

* for clarity relabel RPT_CLOSING and MST_CLOSING to RPT_DISC and MST_DISC;

* discontinue support for TRANSFER command on the traffic port entirely; hide useAlternatePortForDiagnostics and allowActivityTransfer options in FNE configuration; add stern warnings and alerts if the FNE disabled either useAlternatePortForDiagnostics or allowActivityTransfer (these are really critical operations); alert in peer log if the master does not report support for the alternate port for diagnostics;

* make oversized packet warning clearer (this warning is not a end-user warning, the user can't do antyhing about this this is a developer BUGBUG warning);

* apply recv timeout on InfluxDB operations (this hopefully will prevent stuck queries if the InfluxDB server dies while query is in progress);

* prevent InfluxDB query from becoming stuck in a tight infinite loop within select();

* don't bother handling responses from the influx query, remove fluxQL (we don't make queries with this library);

* cleanup unused vars;

* generate an error log if a fluxql worker fails to write data to influx;

* implement support to save/retain configuration pushed from peer link connections;

* fix memory leak caused by not deleting unused packetbuffer;

* refactor ACL updates;

* refactor log messages for channels to be <channel ID>-<channel No> in most cases where applicable;

* add more <channel ID>-<channel No> changes;

* whoops wrong variable type;

* correct fatal bug where update lookup timer was never started;

* check the RF state at the bottom of a talkgroup hang expiration timer for RF talkgroup activity, if the state is not listening, handle the end of call as if it was a frame loss;

* fix potential memory leak in PacketBuffer fragmenter, the encoder was not deleting the storage buffer before end of scope;

* ensure decompressed buffer is deleted;

* ensure decompressed buffer is deleted in error conditions too;

* add support to disable adjacent site broadcast;

* lay the groundwork for explicit channel configuration;

* [EXPERIMENTAL] implement experimental support for a CC to define explicit channel identity information for voice channels (NOTE: this does *NOT* implement support for hotspots to operate in explicit channel mode!);

* don't use the concurrent::unordered_map for this (this gives me great pause for a problem...);

* add some extra debug trace;

* add some extra debug trace;

* display MI data during calibration; update modem submodule;

* this is ugly, and I hate it, but to fix very strange WIN32 deadlock situations, we'll selectively use our concurrent unordered_map on non-WIN32, and on WIN32 use the std unordered_map + a local mutex;

* update modem submodule; change P25 Voice MI logging messages from DEBUG to MESSAGE; fix issue in HostSetup/HostCal where PDU header decoding was broken;

* only dump MI data if the call is encrypted (don't bother displaying zeros for a clear call);

* whoops check right variable;

* cleanup and clarify MI logging;

* cleanup and clarify MI logging (again LDU2 was out of log sequence);

* hate me later, dont use a colon as the string separator for the MI bytes, use equals;

* log DMR PI MI dta;

* refactor debug messaging for HDU;

* reorganize core meta-programming macros, move class property macros into ClassProperties.h, move bit manipulation into BitManipulation.h, move VLA into VariableLengthArray.h; rename meta-programming macros for clarity most of these macros declare some sort of variable and/or functions, as such I'm dropping the notation for __BLAHBLAH and using DECLARE_BLAHBLAH instead; better document class property meta-programming macros; refactor __GET/__SET_UINT16 into __GET/__SET_UINT24 these macros set 24-bit values from and to buffers, this will reduce programming confusion;

* add property documentation for some KMM classes;

* correct file copyright headers;

* change commenting to reflect section more clearly;

* use proper GPL license for file;

* detect arch and properly update internal variable;

* handle instance where the system does not return a valid processor type for arch detection;

* display target arch along side host arch if we're cross compiling;

* strip newlines;

* fix missing parens around response encoding;
pull/91/head 2025-05-25
Bryan Biedenkapp 9 months ago committed by GitHub
parent 5e31e9a642
commit 738ee918d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -42,6 +42,7 @@ option(COMPILE_WIN32 "Compile for Win32" off)
if (COMPILE_WIN32)
set(ARCH amd64)
set(CMAKE_SYSTEM_PROCESSOR amd64)
message(CHECK_START "Detect Host Architecture - ${ARCH}")
# No TUI for this
set(ENABLE_TUI_SUPPORT OFF)
@ -49,7 +50,25 @@ if (COMPILE_WIN32)
else()
set(CMAKE_C_COMPILER /usr/bin/gcc CACHE STRING "C compiler")
set(CMAKE_CXX_COMPILER /usr/bin/g++ CACHE STRING "C++ compiler")
# detect and set architecture
set(ARCH amd64)
if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
set(ARCH amd64)
set(CMAKE_SYSTEM_PROCESSOR amd64)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE amd64)
else()
if (CMAKE_SYSTEM_PROCESSOR MATCHES "")
execute_process(COMMAND uname -m OUTPUT_VARIABLE CMAKE_SYSTEM_PROCESSOR)
string(REGEX REPLACE "\n$" "" CMAKE_SYSTEM_PROCESSOR "${CMAKE_SYSTEM_PROCESSOR}")
set(ARCH ${CMAKE_SYSTEM_PROCESSOR})
else()
set(ARCH ${CMAKE_SYSTEM_PROCESSOR})
endif (CMAKE_SYSTEM_PROCESSOR MATCHES "")
endif (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
message(CHECK_START "Detect Host Architecture - ${ARCH}")
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE amd64)
endif (COMPILE_WIN32)
@ -60,6 +79,7 @@ if (CROSS_COMPILE_ARM)
set(CMAKE_SYSTEM_PROCESSOR armhf)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE armhf)
set(OPENSSL_ROOT_DIR /usr/lib/arm-linux-gnueabihf)
message(CHECK_START "Target Architecture - ${ARCH}")
message(CHECK_START "Cross compiling for 32-bit ARM - ${CMAKE_C_COMPILER}")
endif (CROSS_COMPILE_ARM)
if (CROSS_COMPILE_AARCH64)
@ -69,6 +89,7 @@ if (CROSS_COMPILE_AARCH64)
set(CMAKE_SYSTEM_PROCESSOR arm64)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE arm64)
set(OPENSSL_ROOT_DIR /usr/lib/aarch64-linux-gnu)
message(CHECK_START "Target Architecture - ${ARCH}")
message(CHECK_START "Cross compiling for 64-bit ARM - ${CMAKE_C_COMPILER}")
endif (CROSS_COMPILE_AARCH64)
@ -107,6 +128,7 @@ if (CROSS_COMPILE_RPI_ARM)
set(ARCH armhf)
set(CMAKE_SYSTEM_PROCESSOR armhf)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE armhf)
message(CHECK_START "Target Architecture - ${ARCH}")
message(CHECK_START "Cross compiling for (old RPi) 32-bit ARM - ${CMAKE_C_COMPILER}")
# No TUI for this

@ -224,6 +224,8 @@ protocols:
enableTimeDateAnn: false
# Flag indicating whether or not the source ID validation before granting disabled.
disableGrantSourceIdCheck: false
# Flag indicating whether or not the adjacent site broadcasts are disabled.
disableAdjSiteBroadcast: false
# Flag indicating immediate TSDUs will be sent twice.
redundantImmediate: true
# Flag indicating whether redundant grant responses should be transmitted.
@ -401,8 +403,10 @@ system:
supervisor: false
# Channel Identity (corresponds to the appropriate entry in the iden_table file).
# Note: When using explicit channels, this represents the transmit channel number.
channelId: 2
# Channel Number (used to calculate actual host frequency based on the identity table).
# Note: When using explicit channels, this represents the transmit channel number.
channelNo: 1
#
@ -429,9 +433,17 @@ system:
#
voiceChNo:
# Channel Identity (corresponds to the appropriate entry in the iden_table file).
# Note: When using explicit channels, this represents the transmit channel identity.
- channelId: 2
# Channel Number (used to calculate actual host frequency based on the identity table).
# Note: When using explicit channels, this represents the transmit channel number.
channelNo: 1
# Rx Channel Identity (corresponds to the appropriate entry in the iden_table file).
# Note: When this is defined, the voice channel is using explicit channel frequencies.
#rxChannelId: 2
# Rx Channel Number (used to calculate actual host frequency based on the identity table).
# Note: when this is defined, the voice channel is using explicit channel frequencies.
#rxChannelNo: 2
# RPC IP Address for voice channel.
rpcAddress: 127.0.0.1
# RPC Port number for voice channel.

@ -38,6 +38,8 @@ master:
# Hostname/IP address to listen on (blank for all).
address: 0.0.0.0
# Port number to listen on.
# NOTE: This port number includes itself for traffic, and master port + 1 for diagnostics and activity logging. (For
# example, a master port of 62031 will use 62032 for diagnostic and activity messages.)
port: 62031
# FNE access password.
password: RPT1234
@ -211,22 +213,16 @@ system:
# Maximum number of missable pings before a peer is considered disconnected.
maxMissedPings: 10
# Time in minutes between updates of the talkgroup rules.
tgRuleUpdateTime: 10
# Time in minutes between updates of the ACL rules.
aclRuleUpdateTime: 10
# Flag indicating the TGID information for this master will be sent to its peers.
sendTalkgroups: true
# Flag indicating the FNE should use an alternate port dedicated to diagnostic and activity
# log processing. This port number is always: master port + 1 (so for example, a master port
# of 62031 will use 62032 for diagnostic and activity messages.)
# NOTE: Disabling useAlternatePortForDiagnostics will result in some tools like, SysView, to stop working properly.
# SysView requires useAlternatePortForDiagnostics to receive peer status updates.
useAlternatePortForDiagnostics: true
# Flag indicating whether or not the host activity log will be sent to the network.
# NOTE: Disabling allowActivityTransfer will result in some tools like, SysView, to stop working properly.
# SysView requires allowActivityTransfer to receive peer status updates.
allowActivityTransfer: true
# Flag indicating when this FNE instance receives peer link configuration updates, it will save those
# peer link configurations.
peerLinkSaveACL: false
# Flag indicating whether or not the host diagnostic log will be sent to the network.
allowDiagnosticTransfer: true

@ -263,7 +263,7 @@ int main(int argc, char** argv)
#endif
uint32_t hash = ::strtoul(__GIT_VER_HASH__, 0, 16);
__SET_UINT32(hash, g_gitHashBytes, 0U);
SET_UINT32(hash, g_gitHashBytes, 0U);
if (argv[0] != nullptr && *argv[0] != 0)
g_progExe = std::string(argv[0]);

@ -324,7 +324,7 @@ HostBridge::HostBridge(const std::string& confFile) :
m_voxSampleLevel(30.0f),
m_dropTimeMS(180U),
m_localDropTime(1000U, 0U, 180U),
m_udpCallClock(1000U, 0U, 80U),
m_udpCallClock(1000U, 0U, 160U),
m_udpHangTime(1000U, 0U, 180U),
m_udpDropTime(1000U, 0U, 180U),
m_detectAnalogMDC1200(false),
@ -1100,9 +1100,6 @@ bool HostBridge::createNetwork()
if (m_udpUseULaw && m_udpMetadata)
m_udpMetadata = false; // metadata isn't supported when encoding uLaw
if (m_udpSilenceDuringHang && m_udpRTPFrames)
m_udpCallClock = Timer(1000U, 0U, 160U); // packets every 160ms
yaml::Node tekConf = networkConf["tek"];
bool tekEnable = tekConf["enable"].as<bool>(false);
std::string tekAlgo = tekConf["tekAlgo"].as<std::string>();
@ -1326,14 +1323,13 @@ void HostBridge::processUDPAudio()
if (m_udpNoIncludeLength) {
pcmLength = length;
} else {
pcmLength = __GET_UINT32(buffer, 0U);
pcmLength = GET_UINT32(buffer, 0U);
}
if (m_udpRTPFrames || m_udpUsrp)
pcmLength = MBE_SAMPLES_LENGTH * 2U;
UInt8Array __pcm = std::make_unique<uint8_t[]>(pcmLength);
uint8_t* pcm = __pcm.get();
DECLARE_UINT8_ARRAY(pcm, pcmLength);
if (!m_udpUsrp) {
if (m_udpRTPFrames) {
@ -1404,7 +1400,7 @@ void HostBridge::processUDPAudio()
}
if (m_udpMetadata) {
req->srcId = __GET_UINT32(buffer, pcmLength + 8U);
req->srcId = GET_UINT32(buffer, pcmLength + 8U);
}
m_udpPackets.push_back(req);
@ -1454,8 +1450,8 @@ void HostBridge::processDMRNetwork(uint8_t* buffer, uint32_t length)
// process network message header
uint8_t seqNo = buffer[4U];
uint32_t srcId = __GET_UINT16(buffer, 5U);
uint32_t dstId = __GET_UINT16(buffer, 8U);
uint32_t srcId = GET_UINT24(buffer, 5U);
uint32_t dstId = GET_UINT24(buffer, 8U);
FLCO::E flco = (buffer[15U] & 0x40U) == 0x40U ? FLCO::PRIVATE : FLCO::GROUP;
@ -1699,7 +1695,7 @@ void HostBridge::decodeDMRAudioFrame(uint8_t* ambe, uint32_t srcId, uint32_t dst
::memcpy(audioData, pcm, MBE_SAMPLES_LENGTH);
}
else {
__SET_UINT32(MBE_SAMPLES_LENGTH, audioData, 0U);
SET_UINT32(MBE_SAMPLES_LENGTH, audioData, 0U);
::memcpy(audioData + 4U, pcm, MBE_SAMPLES_LENGTH);
}
@ -1720,19 +1716,19 @@ void HostBridge::decodeDMRAudioFrame(uint8_t* ambe, uint32_t srcId, uint32_t dst
}
}
else {
__SET_UINT32((MBE_SAMPLES_LENGTH * 2U), audioData, 0U);
SET_UINT32((MBE_SAMPLES_LENGTH * 2U), audioData, 0U);
::memcpy(audioData + 4U, pcm, MBE_SAMPLES_LENGTH * 2U);
}
}
else {
length = (MBE_SAMPLES_LENGTH * 2U) + 12U;
audioData = new uint8_t[(MBE_SAMPLES_LENGTH * 2U) + 12U]; // PCM + (4 bytes (PCM length) + 4 bytes (srcId) + 4 bytes (dstId))
__SET_UINT32((MBE_SAMPLES_LENGTH * 2U), audioData, 0U);
SET_UINT32((MBE_SAMPLES_LENGTH * 2U), audioData, 0U);
::memcpy(audioData + 4U, pcm, MBE_SAMPLES_LENGTH * 2U);
// embed destination and source IDs
__SET_UINT32(dstId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 4U));
__SET_UINT32(srcId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 8U));
SET_UINT32(dstId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 4U));
SET_UINT32(srcId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 8U));
}
}
else {
@ -1743,7 +1739,7 @@ void HostBridge::decodeDMRAudioFrame(uint8_t* ambe, uint32_t srcId, uint32_t dst
m_usrpSeqNo++;
usrpHeader[15U] = 1; // set PTT state to true
__SET_UINT32(m_usrpSeqNo, usrpHeader, 4U);
SET_UINT32(m_usrpSeqNo, usrpHeader, 4U);
::memcpy(usrpHeader, "USRP", 4);
::memcpy(audioData, usrpHeader, USRP_HEADER_LENGTH); // copy USRP header into the UDP payload
@ -1975,8 +1971,8 @@ void HostBridge::processP25Network(uint8_t* buffer, uint32_t length)
// handle LDU, TDU or TSDU frame
uint8_t lco = buffer[4U];
uint32_t srcId = __GET_UINT16(buffer, 5U);
uint32_t dstId = __GET_UINT16(buffer, 8U);
uint32_t srcId = GET_UINT24(buffer, 5U);
uint32_t dstId = GET_UINT24(buffer, 8U);
uint8_t lsd1 = buffer[20U];
uint8_t lsd2 = buffer[21U];
@ -2026,7 +2022,7 @@ void HostBridge::processP25Network(uint8_t* buffer, uint32_t length)
if (frameType == FrameType::HDU_VALID) {
m_callAlgoId = buffer[181U];
if (m_callAlgoId != ALGO_UNENCRYPT) {
callKID = __GET_UINT16B(buffer, 182U);
callKID = GET_UINT16(buffer, 182U);
if (m_callAlgoId != m_tekAlgoId && callKID != m_tekKeyId) {
m_callAlgoId = ALGO_UNENCRYPT;
@ -2089,7 +2085,7 @@ void HostBridge::processP25Network(uint8_t* buffer, uint32_t length)
if (duid == DUID::LDU2 && !m_ignoreCall) {
m_callAlgoId = data[88U];
callKID = __GET_UINT16B(buffer, 89U);
callKID = GET_UINT16(buffer, 89U);
}
if (m_callAlgoId != ALGO_UNENCRYPT) {
@ -2379,7 +2375,7 @@ void HostBridge::decodeP25AudioFrame(uint8_t* ldu, uint32_t srcId, uint32_t dstI
::memcpy(audioData, pcm, MBE_SAMPLES_LENGTH);
}
else {
__SET_UINT32(MBE_SAMPLES_LENGTH, audioData, 0U);
SET_UINT32(MBE_SAMPLES_LENGTH, audioData, 0U);
::memcpy(audioData + 4U, pcm, MBE_SAMPLES_LENGTH);
}
@ -2400,19 +2396,19 @@ void HostBridge::decodeP25AudioFrame(uint8_t* ldu, uint32_t srcId, uint32_t dstI
}
}
else {
__SET_UINT32((MBE_SAMPLES_LENGTH * 2U), audioData, 0U);
SET_UINT32((MBE_SAMPLES_LENGTH * 2U), audioData, 0U);
::memcpy(audioData + 4U, pcm, MBE_SAMPLES_LENGTH * 2U);
}
}
else {
length = (MBE_SAMPLES_LENGTH * 2U) + 12U;
audioData = new uint8_t[(MBE_SAMPLES_LENGTH * 2U) + 12U]; // PCM + (4 bytes (PCM length) + 4 bytes (srcId) + 4 bytes (dstId))
__SET_UINT32((MBE_SAMPLES_LENGTH * 2U), audioData, 0U);
SET_UINT32((MBE_SAMPLES_LENGTH * 2U), audioData, 0U);
::memcpy(audioData + 4U, pcm, MBE_SAMPLES_LENGTH * 2U);
// embed destination and source IDs
__SET_UINT32(dstId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 4U));
__SET_UINT32(srcId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 8U));
SET_UINT32(dstId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 4U));
SET_UINT32(srcId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 8U));
}
}
else {
@ -2423,7 +2419,7 @@ void HostBridge::decodeP25AudioFrame(uint8_t* ldu, uint32_t srcId, uint32_t dstI
m_usrpSeqNo++;
usrpHeader[15U] = 1; // set PTT state to true
__SET_UINT32(m_usrpSeqNo, usrpHeader, 4U);
SET_UINT32(m_usrpSeqNo, usrpHeader, 4U);
::memcpy(usrpHeader, "USRP", 4);
::memcpy(audioData, usrpHeader, USRP_HEADER_LENGTH); // copy USRP header into the UDP payload
@ -2669,8 +2665,7 @@ void HostBridge::generatePreambleTone()
ma_waveform_set_frequency(&m_maSineWaveform, m_preambleTone);
ma_uint32 pcmBytes = frameCount * ma_get_bytes_per_frame(m_maDevice.capture.format, m_maDevice.capture.channels);
UInt8Array __sine = std::make_unique<uint8_t[]>(pcmBytes);
uint8_t* sine = __sine.get();
DECLARE_UINT8_ARRAY(sine, pcmBytes);
ma_waveform_read_pcm_frames(&m_maSineWaveform, sine, frameCount, NULL);
@ -2956,8 +2951,7 @@ void* HostBridge::threadAudioProcess(void* arg)
if (bridge->m_audioDetect && !bridge->m_callInProgress) {
ma_uint32 pcmBytes = MBE_SAMPLES_LENGTH * ma_get_bytes_per_frame(bridge->m_maDevice.capture.format, bridge->m_maDevice.capture.channels);
UInt8Array __pcm = std::make_unique<uint8_t[]>(pcmBytes);
uint8_t* pcm = __pcm.get();
DECLARE_UINT8_ARRAY(pcm, pcmBytes);
int pcmIdx = 0;
for (uint32_t smpIdx = 0; smpIdx < MBE_SAMPLES_LENGTH; smpIdx++) {
@ -3095,7 +3089,6 @@ void* HostBridge::threadUDPAudioProcess(void* arg)
}
}
bridge->m_inputAudio.addData(samples, MBE_SAMPLES_LENGTH);
bridge->m_trafficFromUDP = true;
// force start a call if one isn't already in progress

@ -4,6 +4,8 @@
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (c) 2011 Matthew Kaufman
*
*/
/*-
* mdc_common.c

@ -4,6 +4,8 @@
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (c) 2011 Matthew Kaufman
*
*/
/*-
* mdc_decode.c

@ -4,6 +4,8 @@
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (c) 2011 Matthew Kaufman
*
*/
/**
* @file mdc_decode.h

@ -4,6 +4,8 @@
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (c) 2011 Matthew Kaufman
*
*/
/*-
* mdc_encode.c

@ -4,6 +4,8 @@
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (c) 2011 Matthew Kaufman
*
*/
/**
* @file mdc_encode.h

@ -192,8 +192,7 @@ bool PeerNetwork::writeConfig()
json::value v = json::value(config);
std::string json = v.serialize();
CharArray __buffer = std::make_unique<char[]>(json.length() + 9U);
char* buffer = __buffer.get();
DECLARE_CHAR_ARRAY(buffer, json.length() + 9U);
::memcpy(buffer + 0U, TAG_REPEATER_CONFIG, 4U);
::snprintf(buffer + 8U, json.length() + 1U, "%s", json.c_str());

@ -0,0 +1,118 @@
// 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) 2025 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file BitManipulation.h
* @ingroup common
*/
#pragma once
#if !defined(__BIT_MANIPULATION_H__)
#define __BIT_MANIPULATION_H__
#if !defined(__COMMON_DEFINES_H__)
#warning "BitManipulation.h included before Defines.h, please check include order"
#include "common/Defines.h"
#endif
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
/**
* @brief Bit mask table used for WRITE_BIT and READ_BIT.
* @ingroup utils
*/
const uint8_t BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
// ---------------------------------------------------------------------------
// Macros
// ---------------------------------------------------------------------------
/**
* @brief Macro helper to write a specific bit in a byte array.
* @ingroup common
* @param p Byte array.
* @param i Bit offset.
* @param b Bit to write.
*/
#define WRITE_BIT(p, i, b) p[(i) >> 3] = (b) ? (p[(i) >> 3] | BIT_MASK_TABLE[(i) & 7]) : (p[(i) >> 3] & ~BIT_MASK_TABLE[(i) & 7])
/**
* @brief Macro helper to read a specific bit from a byte array.
* @ingroup common
* @param p Byte array.
* @param i Bit offset.
* @returns bool Bit.
*/
#define READ_BIT(p, i) (p[(i) >> 3] & BIT_MASK_TABLE[(i) & 7])
/**
* @brief Sets a uint32_t into 4 bytes of a buffer/array. (32-bit value).
* @ingroup common
* @param val uint32_t value to set
* @param buffer uint8_t buffer to set value on
* @param offset Offset within uint8_t buffer
*/
#define SET_UINT32(val, buffer, offset) \
buffer[0U + offset] = (val >> 24) & 0xFFU; \
buffer[1U + offset] = (val >> 16) & 0xFFU; \
buffer[2U + offset] = (val >> 8) & 0xFFU; \
buffer[3U + offset] = (val >> 0) & 0xFFU;
/**
* @brief Gets a uint32_t consisting of 4 bytes from a buffer/array. (32-bit value).
* @ingroup common
* @param buffer uint8_t buffer to get value from
* @param offset Offset within uint8_t buffer
*/
#define GET_UINT32(buffer, offset) \
(buffer[offset + 0U] << 24) | \
(buffer[offset + 1U] << 16) | \
(buffer[offset + 2U] << 8) | \
(buffer[offset + 3U] << 0);
/**
* @brief Sets a uint32_t into 3 bytes of a buffer/array. (24-bit value).
* @ingroup common
* @param val uint32_t value to set
* @param buffer uint8_t buffer to set value on
* @param offset Offset within uint8_t buffer
*/
#define SET_UINT24(val, buffer, offset) \
buffer[0U + offset] = (val >> 16) & 0xFFU; \
buffer[1U + offset] = (val >> 8) & 0xFFU; \
buffer[2U + offset] = (val >> 0) & 0xFFU;
/**
* @brief Gets a uint32_t consisting of 3 bytes from a buffer/array. (24-bit value).
* @ingroup common
* @param buffer uint8_t buffer to get value from
* @param offset Offset within uint8_t buffer
*/
#define GET_UINT24(buffer, offset) \
(buffer[offset + 0U] << 16) | \
(buffer[offset + 1U] << 8) | \
(buffer[offset + 2U] << 0);
/**
* @brief Sets a uint16_t into 2 bytes of a buffer/array. (16-bit value).
* @ingroup common
* @param val uint16_t value to set
* @param buffer uint8_t buffer to set value on
* @param offset Offset within uint8_t buffer
*/
#define SET_UINT16(val, buffer, offset) \
buffer[0U + offset] = (val >> 8) & 0xFFU; \
buffer[1U + offset] = (val >> 0) & 0xFFU;
/**
* @brief Gets a uint16_t consisting of 2 bytes from a buffer/array. (16-bit value).
* @ingroup common
* @param buffer uint8_t buffer to get value from
* @param offset Offset within uint8_t buffer
*/
#define GET_UINT16(buffer, offset) \
((buffer[offset + 0U] << 8) & 0xFF00U) | \
((buffer[offset + 1U] << 0) & 0x00FFU);
#endif // __BIT_MANIPULATION_H__

@ -0,0 +1,188 @@
// 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) 2025 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file ClassProperties.h
* @ingroup common
*/
#pragma once
#if !defined(__CLASS_PROPERTIES_H__)
#define __CLASS_PROPERTIES_H__
#if !defined(__COMMON_DEFINES_H__)
#warning "ClassProperties.h included before Defines.h, please check include order"
#include "common/Defines.h"
#endif
// ---------------------------------------------------------------------------
// Macros
// ---------------------------------------------------------------------------
/**
* @addtogroup common
* @{
*/
/**
* Class Copy Code Pattern
*/
/**
* @brief Declare a private copy implementation.
* This requires the copy(const type& data) to be declared in the class definition.
* @ingroup common
* @param type Atomic type.
*/
#define DECLARE_COPY(type) \
private: virtual void copy(const type& data); \
public: __forceinline type& operator=(const type& data) { \
if (this != &data) { \
copy(data); \
} \
return *this; \
}
/**
* @brief Declare a protected copy implementation.
* This requires the copy(const type& data) to be declared in the class definition.
* @ingroup common
* @param type Atomic type.
*/
#define DECLARE_PROTECTED_COPY(type) \
protected: virtual void copy(const type& data); \
public: __forceinline type& operator=(const type& data) { \
if (this != &data) { \
copy(data); \
} \
return *this; \
}
/**
* Property Declaration
* These macros should always be used LAST in a "public" section of a class definition.
*/
/**
* @brief Declare a read-only get property.
* This creates a "property" that is read-only and can only be set internally to the class. Properties created
* with this macro generate an internal variable with the name "m_<variableName>", and a getter method
* with the name "get<propertyName>()". The getter method is inline and returns the value of the internal
* variable. The internal variable is private, and the getter method is public.
* @ingroup common
* @param type Atomic type for property.
* @param variableName Variable name for property.
* @param propName Property name.
*/
#define DECLARE_RO_PROPERTY(type, variableName, propName) \
private: type m_##variableName; \
public: __forceinline type get##propName(void) const { return m_##variableName; }
/**
* @brief Declare a read-only get property.
* This creates a "property" that is read-only and can only be set internally to the class. Properties created
* with this macro generate an internal variable with the name "m_<variableName>", and a getter method
* with the name "get<propertyName>()". The getter method is inline and returns the value of the internal
* variable. The internal variable is protected, and the getter method is public.
* @ingroup common
* @param type Atomic type for property.
* @param variableName Variable name for property.
* @param propName Property name.
*/
#define DECLARE_PROTECTED_RO_PROPERTY(type, variableName, propName) \
protected: type m_##variableName; \
public: __forceinline type get##propName(void) const { return m_##variableName; }
/**
* @brief Declare a read-only property, does not use "get" prefix for getter.
* This creates a "property" that is read-only and can only be set internally to the class. Properties created
* with this macro generate an internal variable with the name "m_<variableName>", and a getter method
* with the name "<variableName>()". The getter method is inline and returns the value of the internal
* variable. The internal variable is private, and the getter method is public.
* @ingroup common
* @param type Atomic type for property.
* @param variableName Variable name for property.
*/
#define DECLARE_PROTECTED_RO_PROPERTY_PLAIN(type, variableName) \
protected: type m_##variableName; \
public: __forceinline type variableName(void) const { return m_##variableName; }
/**
* @brief Declare a read-only get property, does not use "get" prefix for getter.
* This creates a "property" that is read-only and can only be set internally to the class. Properties created
* with this macro generate an internal variable with the name "m_<variableName>", and a getter method
* with the name "<variableName>()". The getter method is inline and returns the value of the internal
* variable. The internal variable is private, and the getter method is public.
* @ingroup common
* @param type Atomic type for property.
* @param variableName Variable name for property.
*/
#define DECLARE_RO_PROPERTY_PLAIN(type, variableName) \
private: type m_##variableName; \
public: __forceinline type variableName(void) const { return m_##variableName; }
/**
* @brief Declare a get and set private property.
* This creates a "property" that is read/write. Properties created with this macro generate an internal variable
* with the name "m_<variableName>", a getter method with the name "get<propertyName>()", and a setter method
* with the name "set<propertyName>(value)". The getter method is inline and returns the value of the internal variable.
* The internal variable is private, and the getter and setter methods are public.
* @ingroup common
* @param type Atomic type for property.
* @param variableName Variable name for property.
* @param propName Property name.
*/
#define DECLARE_PROPERTY(type, variableName, propName) \
private: type m_##variableName; \
public: __forceinline type get##propName(void) const { return m_##variableName; } \
__forceinline void set##propName(type val) { m_##variableName = val; }
/**
* @brief Declare a get and set protected property.
* This creates a "property" that is read/write. Properties created with this macro generate an internal variable
* with the name "m_<variableName>", a getter method with the name "get<propertyName>()", and a setter method
* with the name "set<propertyName>(value)". The getter method is inline and returns the value of the internal variable.
* The internal variable is protected, and the getter and setter methods are public.
* @ingroup common
* @param type Atomic type for property.
* @param variableName Variable name for property.
* @param propName Property name.
*/
#define DECLARE_PROTECTED_PROPERTY(type, variableName, propName) \
protected: type m_##variableName; \
public: __forceinline type get##propName(void) const { return m_##variableName; } \
__forceinline void set##propName(type val) { m_##variableName = val; }
/**
* @brief Declare a private property, does not use "get"/"set" prefix.
* This creates a "property" that is read/write. Properties created with this macro generate an internal variable
* with the name "m_<variableName>", and a getter method with the name "<variableName>()", and a setter method
* "<propertyName>(value)". The getter method is inline and returns the value of the internal variable. The internal
* variable is private, and the getter and setter methods are public.
* @ingroup common
* @param type Atomic type for property.
* @param variableName Variable name for property.
*/
#define DECLARE_PROPERTY_PLAIN(type, variableName) \
private: type m_##variableName; \
public: __forceinline type variableName(void) const { return m_##variableName; } \
__forceinline void variableName(type val) { m_##variableName = val; }
/**
* @brief Declare a protected property, does not use "get"/"set" prefix.
* This creates a "property" that is read/write. Properties created with this macro generate an internal variable
* with the name "m_<variableName>", and a getter method with the name "<variableName>()", and a setter method
* "<propertyName>(value)". The getter method is inline and returns the value of the internal variable. The internal
* variable is protected, and the getter and setter methods are public.
* @ingroup common
* @param type Atomic type for property.
* @param variableName Variable name for property.
*/
#define DECLARE_PROTECTED_PROPERTY_PLAIN(type, variableName) \
protected: type m_##variableName; \
public: __forceinline type variableName(void) const { return m_##variableName; } \
__forceinline void variableName(type val) { m_##variableName = val; }
/** @} */
#endif // __CLASS_PROPERTIES_H__

@ -5,7 +5,7 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX
* Copyright (C) 2018-2024 Bryan Biedenkapp, N2PLL
* Copyright (C) 2018-2025 Bryan Biedenkapp, N2PLL
*
*/
/**
@ -21,6 +21,7 @@
* @file Defines.h
* @ingroup common
*/
#pragma once
#if !defined(__COMMON_DEFINES_H__)
#define __COMMON_DEFINES_H__
@ -93,6 +94,14 @@ typedef unsigned long long ulong64_t;
#define PACK(decl) __pragma(pack(push, 1)) decl __pragma(pack(pop))
#endif
// ---------------------------------------------------------------------------
// Meta-Programming Macro Includes
// ---------------------------------------------------------------------------
#include "common/ClassProperties.h"
#include "common/BitManipulation.h"
#include "common/VariableLengthArray.h"
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
@ -108,7 +117,7 @@ typedef unsigned long long ulong64_t;
#define __EXE_NAME__ ""
#define VERSION_MAJOR "04"
#define VERSION_MINOR "30"
#define VERSION_MINOR "31"
#define VERSION_REV "H"
#define __NETVER__ "DVM_R" VERSION_MAJOR VERSION_REV VERSION_MINOR
@ -193,121 +202,6 @@ const uint8_t IP_COMPRESS_NONE = 0x00U;
const uint8_t IP_COMPRESS_RFC1144_COMPRESS = 0x01U;
const uint8_t IP_COMPRESS_RFC1144_UNCOMPRESS = 0x02U;
// ---------------------------------------------------------------------------
// Class Helper Macros
// ---------------------------------------------------------------------------
/**
* Class Copy Code Pattern
*/
/**
* @brief Creates a private copy implementation.
* This requires the copy(const type& data) to be declared in the class definition.
* @param type Atomic type.
*/
#define __COPY(type) \
private: virtual void copy(const type& data); \
public: __forceinline type& operator=(const type& data) { \
if (this != &data) { \
copy(data); \
} \
return *this; \
}
/**
* @brief Creates a protected copy implementation.
* This requires the copy(const type& data) to be declared in the class definition.
* @param type Atomic type.
*/
#define __PROTECTED_COPY(type) \
protected: virtual void copy(const type& data); \
public: __forceinline type& operator=(const type& data) { \
if (this != &data) { \
copy(data); \
} \
return *this; \
}
/**
* Property Creation
* These macros should always be used LAST in the "public" section of a class definition.
*/
/**
* @brief Creates a read-only get property.
* @param type Atomic type for property.
* @param variableName Variable name for property.
* @param propName Property name.
*/
#define __READONLY_PROPERTY(type, variableName, propName) \
private: type m_##variableName; \
public: __forceinline type get##propName(void) const { return m_##variableName; }
/**
* @brief Creates a read-only get property.
* @param type Atomic type for property.
* @param variableName Variable name for property.
* @param propName Property name.
*/
#define __PROTECTED_READONLY_PROPERTY(type, variableName, propName) \
protected: type m_##variableName; \
public: __forceinline type get##propName(void) const { return m_##variableName; }
/**
* @brief Creates a read-only get property, does not use "get".
* @param type Atomic type for property.
* @param variableName Variable name for property.
*/
#define __PROTECTED_READONLY_PROPERTY_PLAIN(type, variableName) \
protected: type m_##variableName; \
public: __forceinline type variableName(void) const { return m_##variableName; }
/**
* @brief Creates a read-only get property, does not use "get".
* @param type Atomic type for property.
* @param variableName Variable name for property.
*/
#define __READONLY_PROPERTY_PLAIN(type, variableName) \
private: type m_##variableName; \
public: __forceinline type variableName(void) const { return m_##variableName; }
/**
* @brief Creates a get and set private property.
* @param type Atomic type for property.
* @param variableName Variable name for property.
* @param propName Property name.
*/
#define __PROPERTY(type, variableName, propName) \
private: type m_##variableName; \
public: __forceinline type get##propName(void) const { return m_##variableName; } \
__forceinline void set##propName(type val) { m_##variableName = val; }
/**
* @brief Creates a get and set protected property.
* @param type Atomic type for property.
* @param variableName Variable name for property.
* @param propName Property name.
*/
#define __PROTECTED_PROPERTY(type, variableName, propName) \
protected: type m_##variableName; \
public: __forceinline type get##propName(void) const { return m_##variableName; } \
__forceinline void set##propName(type val) { m_##variableName = val; }
/**
* @brief Creates a get and set private property, does not use "get"/"set".
* @param type Atomic type for property.
* @param variableName Variable name for property.
*/
#define __PROPERTY_PLAIN(type, variableName) \
private: type m_##variableName; \
public: __forceinline type variableName(void) const { return m_##variableName; }\
__forceinline void variableName(type val) { m_##variableName = val; }
/**
* @brief Creates a get and set protected property, does not use "get"/"set".
* @param type Atomic type for property.
* @param variableName Variable name for property.
*/
#define __PROTECTED_PROPERTY_PLAIN(type, variableName) \
protected: type m_##variableName; \
public: __forceinline type variableName(void) const { return m_##variableName; }\
__forceinline void variableName(type val) { m_##variableName = val; }
/** @} */
#endif // __COMMON_DEFINES_H__

@ -134,7 +134,7 @@ public:
/**
* @brief Flag indicating if the thread was started.
*/
__PROTECTED_READONLY_PROPERTY_PLAIN(bool, started);
DECLARE_PROTECTED_RO_PROPERTY_PLAIN(bool, started);
};
#endif // __THREAD_H__

@ -115,11 +115,11 @@ public:
/**
* @brief Maximum number of worker threads.
*/
__PROPERTY(uint16_t, maxWorkerCnt, MaxWorkerCnt);
DECLARE_PROPERTY(uint16_t, maxWorkerCnt, MaxWorkerCnt);
/**
* @brief Maximum number of queued tasks.
*/
__PROPERTY(uint16_t, maxQueuedTasks, MaxQueuedTasks);
DECLARE_PROPERTY(uint16_t, maxQueuedTasks, MaxQueuedTasks);
private:

@ -5,11 +5,11 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2009,2014,2015 Jonathan Naylor, G4KLX
* Copyright (C) 2018-2024 Bryan Biedenkapp, N2PLL
* Copyright (C) 2018-2025 Bryan Biedenkapp, N2PLL
*
*/
/**
* @defgroup utils Utility Routines
* @defgroup utils Common Utility Routines
* @brief Defines and implements utility routines.
* @ingroup common
*
@ -31,17 +31,24 @@
#endif // !defined(WIN32)
// ---------------------------------------------------------------------------
// Constants
// Macros
// ---------------------------------------------------------------------------
/**
* @brief Bit mask table used for WRITE_BIT and READ_BIT.
* @brief Pointer magic to get the memory address of a floating point number.
* @ingroup utils
* @param x Floating Point Variable
*/
const uint8_t BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
#define __FLOAT_ADDR(x) (*(uint32_t*)& x)
/**
* @brief Pointer magic to get the memory address of a double precision number.
* @ingroup utils
* @param x Double Precision Variable
*/
#define __DOUBLE_ADDR(x) (*(uint64_t*)& x)
// ---------------------------------------------------------------------------
// Inlines
// Inline Global Functions
// ---------------------------------------------------------------------------
/**
@ -153,115 +160,6 @@ inline std::string strtoupper(const std::string value) {
return v;
}
// ---------------------------------------------------------------------------
// Macros
// ---------------------------------------------------------------------------
/**
* @brief Pointer magic to get the memory address of a floating point number.
* @ingroup utils
* @param x Floating Point Variable
*/
#define __FLOAT_ADDR(x) (*(uint32_t*)& x)
/**
* @brief Pointer magic to get the memory address of a double precision number.
* @ingroup utils
* @param x Double Precision Variable
*/
#define __DOUBLE_ADDR(x) (*(uint64_t*)& x)
/**
* @brief Macro helper to write a specific bit in a byte array.
* @ingroup utils
* @param p Byte array.
* @param i Bit offset.
* @param b Bit to write.
*/
#define WRITE_BIT(p, i, b) p[(i) >> 3] = (b) ? (p[(i) >> 3] | BIT_MASK_TABLE[(i) & 7]) : (p[(i) >> 3] & ~BIT_MASK_TABLE[(i) & 7])
/**
* @brief Macro helper to read a specific bit from a byte array.
* @ingroup utils
* @param p Byte array.
* @param i Bit offset.
* @returns bool Bit.
*/
#define READ_BIT(p, i) (p[(i) >> 3] & BIT_MASK_TABLE[(i) & 7])
/**
* @brief Sets a uint32_t into 4 bytes.
* @ingroup utils
* @param val uint32_t value to set
* @param buffer uint8_t buffer to set value on
* @param offset Offset within uint8_t buffer
*/
#define __SET_UINT32(val, buffer, offset) \
buffer[0U + offset] = (val >> 24) & 0xFFU; \
buffer[1U + offset] = (val >> 16) & 0xFFU; \
buffer[2U + offset] = (val >> 8) & 0xFFU; \
buffer[3U + offset] = (val >> 0) & 0xFFU;
/**
* @brief Gets a uint32_t consisting of 4 bytes.
* @ingroup utils
* @param buffer uint8_t buffer to get value from
* @param offset Offset within uint8_t buffer
*/
#define __GET_UINT32(buffer, offset) \
(buffer[offset + 0U] << 24) | \
(buffer[offset + 1U] << 16) | \
(buffer[offset + 2U] << 8) | \
(buffer[offset + 3U] << 0);
/**
* @brief Sets a uint32_t into 3 bytes.
* @ingroup utils
* @param val uint32_t value to set
* @param buffer uint8_t buffer to set value on
* @param offset Offset within uint8_t buffer
*/
#define __SET_UINT16(val, buffer, offset) \
buffer[0U + offset] = (val >> 16) & 0xFFU; \
buffer[1U + offset] = (val >> 8) & 0xFFU; \
buffer[2U + offset] = (val >> 0) & 0xFFU;
/**
* @brief Gets a uint32_t consisting of 3 bytes. (This is a shortened uint32_t).
* @ingroup utils
* @param buffer uint8_t buffer to get value from
* @param offset Offset within uint8_t buffer
*/
#define __GET_UINT16(buffer, offset) \
(buffer[offset + 0U] << 16) | \
(buffer[offset + 1U] << 8) | \
(buffer[offset + 2U] << 0);
/**
* @brief Sets a uint16_t into 2 bytes.
* @ingroup utils
* @param val uint16_t value to set
* @param buffer uint8_t buffer to set value on
* @param offset Offset within uint8_t buffer
*/
#define __SET_UINT16B(val, buffer, offset) \
buffer[0U + offset] = (val >> 8) & 0xFFU; \
buffer[1U + offset] = (val >> 0) & 0xFFU;
/**
* @brief Gets a uint16_t consisting of 2 bytes.
* @ingroup utils
* @param buffer uint8_t buffer to get value from
* @param offset Offset within uint8_t buffer
*/
#define __GET_UINT16B(buffer, offset) \
((buffer[offset + 0U] << 8) & 0xFF00U) | \
((buffer[offset + 1U] << 0) & 0x00FFU);
/**
* @brief Unique uint8_t array.
* @ingroup utils
*/
typedef std::unique_ptr<uint8_t[]> UInt8Array;
/**
* @brief Unique char array.
* @ingroup utils
*/
typedef std::unique_ptr<char[]> CharArray;
// ---------------------------------------------------------------------------
// Class Declaration
// ---------------------------------------------------------------------------

@ -0,0 +1,82 @@
// 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) 2025 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file VariableLengthArray.h
* @ingroup common
*/
#pragma once
#if !defined(__VARIABLE_LENGTH_ARRAY_H__)
#define __VARIABLE_LENGTH_ARRAY_H__
#if !defined(__COMMON_DEFINES_H__)
#warning "VariableLengthArray.h included before Defines.h, please check include order"
#include "common/Defines.h"
#endif
// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------
/**
* @addtogroup common
* @{
*/
/**
* @brief Unique uint8_t array.
* @ingroup common
*/
typedef std::unique_ptr<uint8_t[]> UInt8Array;
/**
* @brief Unique char array.
* @ingroup common
*/
typedef std::unique_ptr<char[]> CharArray;
/** @} */
// ---------------------------------------------------------------------------
// Macros
// ---------------------------------------------------------------------------
/**
* @addtogroup common
* @{
*/
/**
* @brief Declares a unique uint8_t array/buffer.
* This macro creates a unique pointer to a uint8_t array of the specified length and initializes it to zero.
* The resulting pointer is named after the parameter name passed to the macro.
* @param name Name of array/buffer.
* @param len Length of array/buffer.
*/
#define DECLARE_UINT8_ARRAY(name, len) \
UInt8Array __##name##__UInt8Array = std::make_unique<uint8_t[]>(len); \
uint8_t* name = __##name##__UInt8Array.get(); \
::memset(name, 0x00U, len);
/**
* @brief Declares a unique char array/buffer.
* This macro creates a unique pointer to a uint8_t array of the specified length and initializes it to zero.
* The resulting pointer is named after the parameter name passed to the macro.
* @ingroup common
* @param name Name of array/buffer.
* @param len Length of array/buffer.
*/
#define DECLARE_CHAR_ARRAY(name, len) \
CharArray __##name##__CharArray = std::make_unique<char[]>(len); \
char* name = __##name##__CharArray.get(); \
::memset(name, 0, len);
/** @} */
#endif // __VARIABLE_LENGTH_ARRAY_H__

@ -5,7 +5,7 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2019-2024 Bryan Biedenkapp, N2PLL
* Copyright (C) 2019-2025 Bryan Biedenkapp, N2PLL
*
*/
/**
@ -209,6 +209,15 @@ namespace dmr
const uint8_t FID_DVM_OCS = 0x9CU;
/** @} */
/** @name Encryption Algorithms */
/** @brief ARC4 */
const uint8_t ALGO_ARC4 = 0x01U;
/** @brief DES-OFB */
const uint8_t ALGO_DES = 0x02U;
/** @brief AES-256 */
const uint8_t ALGO_AES_256 = 0x05U;
/** @} */
/** @name LC Service Options */
const uint8_t LC_SVC_OPT_EMERGENCY = 0x80U;
const uint8_t LC_SVC_OPT_PRIVACY = 0x40U;

@ -156,27 +156,27 @@ namespace dmr
/**
* @brief DMR site model type.
*/
__READONLY_PROPERTY_PLAIN(defines::SiteModel::E, siteModel);
DECLARE_RO_PROPERTY_PLAIN(defines::SiteModel::E, siteModel);
/**
* @brief DMR site network ID.
*/
__READONLY_PROPERTY_PLAIN(uint16_t, netId);
DECLARE_RO_PROPERTY_PLAIN(uint16_t, netId);
/**
* @brief DMR site ID.
*/
__READONLY_PROPERTY_PLAIN(uint16_t, siteId);
DECLARE_RO_PROPERTY_PLAIN(uint16_t, siteId);
/**
* @brief DMR partition ID.
*/
__READONLY_PROPERTY_PLAIN(uint8_t, parId);
DECLARE_RO_PROPERTY_PLAIN(uint8_t, parId);
/**
* @brief DMR require registration.
*/
__READONLY_PROPERTY_PLAIN(bool, requireReg);
DECLARE_RO_PROPERTY_PLAIN(bool, requireReg);
/**
* @brief Flag indicating whether this site is a linked active network member.
*/
__READONLY_PROPERTY_PLAIN(bool, netActive);
DECLARE_RO_PROPERTY_PLAIN(bool, netActive);
/** @} */
};
} // namespace dmr

@ -56,12 +56,12 @@ namespace dmr
/**
* @brief DMR access color code.
*/
__PROPERTY(uint8_t, colorCode, ColorCode);
DECLARE_PROPERTY(uint8_t, colorCode, ColorCode);
/**
* @brief Slot data type.
*/
__PROPERTY(defines::DataType::E, dataType, DataType);
DECLARE_PROPERTY(defines::DataType::E, dataType, DataType);
};
} // namespace dmr

@ -102,12 +102,12 @@ namespace dmr
/**
* @brief Sets the data block serial number.
*/
__PROPERTY(uint8_t, serialNo, SerialNo);
DECLARE_PROPERTY(uint8_t, serialNo, SerialNo);
/**
* @brief Flag indicating this is the last block in a sequence of block.
*/
__PROPERTY(bool, lastBlock, LastBlock);
DECLARE_PROPERTY(bool, lastBlock, LastBlock);
private:
edac::BPTC19696 m_bptc;

@ -106,82 +106,82 @@ namespace dmr
/**
* @brief Flag indicating whether the data header is group or individual.
*/
__PROPERTY(bool, GI, GI);
DECLARE_PROPERTY(bool, GI, GI);
/**
* @brief Flag indicating whether the data header requires acknowledgement.
*/
__PROPERTY(bool, A, A);
DECLARE_PROPERTY(bool, A, A);
/**
* @brief Data packet format.
*/
__PROPERTY(defines::DPF::E, DPF, DPF);
DECLARE_PROPERTY(defines::DPF::E, DPF, DPF);
/**
* @brief Service access point.
*/
__PROPERTY(uint8_t, sap, SAP);
DECLARE_PROPERTY(uint8_t, sap, SAP);
/**
* @brief Fragment Sequence Number.
*/
__PROPERTY(uint8_t, fsn, FSN);
DECLARE_PROPERTY(uint8_t, fsn, FSN);
/**
* @brief Send Sequence Number.
*/
__PROPERTY(uint8_t, Ns, Ns);
DECLARE_PROPERTY(uint8_t, Ns, Ns);
/**
* @brief Gets the number of data blocks following the header.
*/
__PROPERTY(uint32_t, blocksToFollow, BlocksToFollow);
DECLARE_PROPERTY(uint32_t, blocksToFollow, BlocksToFollow);
/**
* @brief Count of block padding.
*/
__PROPERTY(uint8_t, padLength, PadLength);
DECLARE_PROPERTY(uint8_t, padLength, PadLength);
/**
* @brief Full Message Flag.
*/
__PROPERTY(bool, F, FullMesage);
DECLARE_PROPERTY(bool, F, FullMesage);
/**
* @brief Synchronize Flag.
*/
__PROPERTY(bool, S, Synchronize);
DECLARE_PROPERTY(bool, S, Synchronize);
/**
* @brief Unified Data or Defined Data Format.
*/
__PROPERTY(uint8_t, dataFormat, DataFormat);
DECLARE_PROPERTY(uint8_t, dataFormat, DataFormat);
/**
* @brief Source ID.
*/
__PROPERTY(uint32_t, srcId, SrcId);
DECLARE_PROPERTY(uint32_t, srcId, SrcId);
/**
* @brief Destination ID.
*/
__PROPERTY(uint32_t, dstId, DstId);
DECLARE_PROPERTY(uint32_t, dstId, DstId);
/**
* @brief Response class.
*/
__PROPERTY(uint8_t, rspClass, ResponseClass);
DECLARE_PROPERTY(uint8_t, rspClass, ResponseClass);
/**
* @brief Response type.
*/
__PROPERTY(uint8_t, rspType, ResponseType);
DECLARE_PROPERTY(uint8_t, rspType, ResponseType);
/**
* @brief Response status.
*/
__PROPERTY(uint8_t, rspStatus, ResponseStatus);
DECLARE_PROPERTY(uint8_t, rspStatus, ResponseStatus);
/**
* @brief Source Port.
*/
__PROPERTY(uint8_t, srcPort, SrcPort);
DECLARE_PROPERTY(uint8_t, srcPort, SrcPort);
/**
* @brief Destination Port.
*/
__PROPERTY(uint8_t, dstPort, DstPort);
DECLARE_PROPERTY(uint8_t, dstPort, DstPort);
private:
edac::BPTC19696 m_bptc;

@ -56,17 +56,17 @@ namespace dmr
/**
* @brief DMR access color code.
*/
__PROPERTY(uint8_t, colorCode, ColorCode);
DECLARE_PROPERTY(uint8_t, colorCode, ColorCode);
/**
* @brief Flag indicating whether the privacy indicator is set or not.
*/
__PROPERTY(bool, PI, PI);
DECLARE_PROPERTY(bool, PI, PI);
/**
* @brief Link control start/stop.
*/
__PROPERTY(uint8_t, LCSS, LCSS);
DECLARE_PROPERTY(uint8_t, LCSS, LCSS);
};
} // namespace data
} // namespace dmr

@ -96,11 +96,11 @@ namespace dmr
/**
* @brief Flag indicating whether or not the embedded data is valid.
*/
__READONLY_PROPERTY_PLAIN(bool, valid);
DECLARE_RO_PROPERTY_PLAIN(bool, valid);
/**
* @brief Full-link control opcode.
*/
__READONLY_PROPERTY(defines::FLCO::E, FLCO, FLCO);
DECLARE_RO_PROPERTY(defines::FLCO::E, FLCO, FLCO);
private:
LC_STATE m_state;

@ -69,51 +69,51 @@ namespace dmr
/**
* @brief DMR slot number.
*/
__PROPERTY(uint32_t, slotNo, SlotNo);
DECLARE_PROPERTY(uint32_t, slotNo, SlotNo);
/**
* @brief Source ID.
*/
__PROPERTY(uint32_t, srcId, SrcId);
DECLARE_PROPERTY(uint32_t, srcId, SrcId);
/**
* @brief Destination ID.
*/
__PROPERTY(uint32_t, dstId, DstId);
DECLARE_PROPERTY(uint32_t, dstId, DstId);
/**
* @brief Sets the full-link control opcode.
*/
__PROPERTY(defines::FLCO::E, flco, FLCO);
DECLARE_PROPERTY(defines::FLCO::E, flco, FLCO);
/**
* @brief
*/
__PROPERTY(uint8_t, control, Control);
DECLARE_PROPERTY(uint8_t, control, Control);
/**
* @brief
*/
__PROPERTY(uint8_t, n, N);
DECLARE_PROPERTY(uint8_t, n, N);
/**
* @brief Sequence number.
*/
__PROPERTY(uint8_t, seqNo, SeqNo);
DECLARE_PROPERTY(uint8_t, seqNo, SeqNo);
/**
* @brief Embedded data type.
*/
__PROPERTY(defines::DataType::E, dataType, DataType);
DECLARE_PROPERTY(defines::DataType::E, dataType, DataType);
/**
* @brief Bit Error Rate.
*/
__PROPERTY(uint8_t, ber, BER);
DECLARE_PROPERTY(uint8_t, ber, BER);
/**
* @brief Received Signal Strength Indicator.
*/
__PROPERTY(uint8_t, rssi, RSSI);
DECLARE_PROPERTY(uint8_t, rssi, RSSI);
private:
uint8_t* m_data;

@ -117,116 +117,116 @@ namespace dmr
/**
* @brief DMR access color code.
*/
__PROTECTED_PROPERTY(uint8_t, colorCode, ColorCode);
DECLARE_PROTECTED_PROPERTY(uint8_t, colorCode, ColorCode);
/**
* @brief Flag indicating this is the last CSBK in a sequence of CSBKs.
*/
__PROTECTED_PROPERTY(bool, lastBlock, LastBlock);
DECLARE_PROTECTED_PROPERTY(bool, lastBlock, LastBlock);
/**
* @brief Flag indicating whether the CSBK is a Cdef block.
*/
__PROTECTED_PROPERTY(bool, Cdef, Cdef);
DECLARE_PROTECTED_PROPERTY(bool, Cdef, Cdef);
/**
* @brief CSBK opcode.
*/
__PROTECTED_PROPERTY(uint8_t, CSBKO, CSBKO);
DECLARE_PROTECTED_PROPERTY(uint8_t, CSBKO, CSBKO);
/**
* @brief */
__PROTECTED_PROPERTY(uint8_t, FID, FID);
DECLARE_PROTECTED_PROPERTY(uint8_t, FID, FID);
/**
* @brief Flag indicating whether the CSBK is group or individual.
*/
__PROTECTED_PROPERTY(bool, GI, GI);
DECLARE_PROTECTED_PROPERTY(bool, GI, GI);
/**
* @brief Source ID.
*/
__PROTECTED_PROPERTY(uint32_t, srcId, SrcId);
DECLARE_PROTECTED_PROPERTY(uint32_t, srcId, SrcId);
/**
* @brief Destination ID.
*/
__PROTECTED_PROPERTY(uint32_t, dstId, DstId);
DECLARE_PROTECTED_PROPERTY(uint32_t, dstId, DstId);
/**
* @brief
*/
__PROTECTED_READONLY_PROPERTY(bool, dataContent, DataContent);
DECLARE_PROTECTED_RO_PROPERTY(bool, dataContent, DataContent);
/**
* @brief Number of blocks to follow.
*/
__PROTECTED_PROPERTY(uint8_t, CBF, CBF);
DECLARE_PROTECTED_PROPERTY(uint8_t, CBF, CBF);
/**
* @brief Data type for this CSBK.
*/
__PROTECTED_PROPERTY(defines::DataType::E, dataType, DataType);
DECLARE_PROTECTED_PROPERTY(defines::DataType::E, dataType, DataType);
/** @} */
/** @name Common Service Options */
/**
* @brief Flag indicating the emergency bits are set.
*/
__PROTECTED_PROPERTY(bool, emergency, Emergency);
DECLARE_PROTECTED_PROPERTY(bool, emergency, Emergency);
/**
* @brief Flag indicating that privacy is enabled.
*/
__PROTECTED_PROPERTY(bool, privacy, Privacy);
DECLARE_PROTECTED_PROPERTY(bool, privacy, Privacy);
/**
* @brief Flag indicating that supplementary data is required.
*/
__PROTECTED_PROPERTY(bool, supplementData, SupplementData);
DECLARE_PROTECTED_PROPERTY(bool, supplementData, SupplementData);
/**
* @brief Priority level for the traffic.
*/
__PROTECTED_PROPERTY(uint8_t, priority, Priority);
DECLARE_PROTECTED_PROPERTY(uint8_t, priority, Priority);
/**
* @brief Flag indicating a broadcast service.
*/
__PROTECTED_PROPERTY(bool, broadcast, Broadcast);
DECLARE_PROTECTED_PROPERTY(bool, broadcast, Broadcast);
/**
* @brief Flag indicating a proxy.
*/
__PROTECTED_PROPERTY(bool, proxy, Proxy);
DECLARE_PROTECTED_PROPERTY(bool, proxy, Proxy);
/**
* @brief Response information.
*/
__PROTECTED_PROPERTY(uint8_t, response, Response);
DECLARE_PROTECTED_PROPERTY(uint8_t, response, Response);
/**
* @brief Reason type.
*/
__PROTECTED_PROPERTY(uint8_t, reason, Reason);
DECLARE_PROTECTED_PROPERTY(uint8_t, reason, Reason);
/** @} */
/** @name Tier 3 */
/**
* @brief Site offset timing.
*/
__PROTECTED_PROPERTY(bool, siteOffsetTiming, SiteOffsetTiming);
DECLARE_PROTECTED_PROPERTY(bool, siteOffsetTiming, SiteOffsetTiming);
/**
* @brief Broadcast Logical Channel ID 1.
*/
__PROTECTED_PROPERTY(uint16_t, logicalCh1, LogicalCh1);
DECLARE_PROTECTED_PROPERTY(uint16_t, logicalCh1, LogicalCh1);
/**
* @brief Broadcast Logical Channel ID 2.
*/
__PROTECTED_PROPERTY(uint16_t, logicalCh2, LogicalCh2);
DECLARE_PROTECTED_PROPERTY(uint16_t, logicalCh2, LogicalCh2);
/**
* @brief Logical Channel Slot Number.
*/
__PROTECTED_PROPERTY(uint8_t, slotNo, SlotNo);
DECLARE_PROTECTED_PROPERTY(uint8_t, slotNo, SlotNo);
/** @} */
/** @name Local Site data */
/**
* @brief Local Site Identity Entry.
*/
__PROTECTED_PROPERTY_PLAIN(::lookups::IdenTable, siteIdenEntry);
DECLARE_PROTECTED_PROPERTY_PLAIN(::lookups::IdenTable, siteIdenEntry);
/** @} */
protected:
@ -261,7 +261,7 @@ namespace dmr
*/
void encode(uint8_t* data, const uint8_t* payload);
__PROTECTED_COPY(CSBK);
DECLARE_PROTECTED_COPY(CSBK);
private:
uint8_t* m_raw;

@ -80,49 +80,49 @@ namespace dmr
/**
* @brief Flag indicating whether link protection is enabled.
*/
__PROPERTY(bool, PF, PF);
DECLARE_PROPERTY(bool, PF, PF);
/**
* @brief Full-link control opcode.
*/
__PROPERTY(defines::FLCO::E, FLCO, FLCO);
DECLARE_PROPERTY(defines::FLCO::E, FLCO, FLCO);
/**
* @brief Feature ID
*/
__PROPERTY(uint8_t, FID, FID);
DECLARE_PROPERTY(uint8_t, FID, FID);
/**
* @brief Source ID.
*/
__PROPERTY(uint32_t, srcId, SrcId);
DECLARE_PROPERTY(uint32_t, srcId, SrcId);
/**
* @brief Destination ID.
*/
__PROPERTY(uint32_t, dstId, DstId);
DECLARE_PROPERTY(uint32_t, dstId, DstId);
/** @} */
/** @name Service Options */
/**
* @brief Flag indicating the emergency bits are set.
*/
__PROPERTY(bool, emergency, Emergency);
DECLARE_PROPERTY(bool, emergency, Emergency);
/**
* @brief Flag indicating that encryption is enabled.
*/
__PROPERTY(bool, encrypted, Encrypted);
DECLARE_PROPERTY(bool, encrypted, Encrypted);
/**
* @brief Flag indicating broadcast operation.
*/
__PROPERTY(bool, broadcast, Broadcast);
DECLARE_PROPERTY(bool, broadcast, Broadcast);
/**
* @brief Flag indicating OVCM operation.
*/
__PROPERTY(bool, ovcm, OVCM);
DECLARE_PROPERTY(bool, ovcm, OVCM);
/**
* @brief Priority level for the traffic.
*/
__PROPERTY(uint8_t, priority, Priority);
DECLARE_PROPERTY(uint8_t, priority, Priority);
/** @} */
private:

@ -7,7 +7,7 @@
* @package DVM / Common Library
* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
*
* Copyright (C) 2021,2024 Bryan Biedenkapp, N2PLL
* Copyright (C) 2021,2024,2025 Bryan Biedenkapp, N2PLL
*
*/
#include "Defines.h"
@ -160,3 +160,25 @@ void PrivacyLC::getData(bool* bits) const
Utils::byteToBitsBE(bytes[8U], bits + 64U);
Utils::byteToBitsBE(bytes[9U], bits + 72U);
}
/*
** Encryption data
*/
/* Sets the encryption message indicator. */
void PrivacyLC::setMI(const uint8_t* mi)
{
assert(mi != nullptr);
::memcpy(m_mi, mi, MI_LENGTH_BYTES);
}
/* Gets the encryption message indicator. */
void PrivacyLC::getMI(uint8_t* mi) const
{
assert(mi != nullptr);
::memcpy(mi, m_mi, MI_LENGTH_BYTES);
}

@ -7,7 +7,7 @@
* @package DVM / Common Library
* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
*
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
* Copyright (C) 2021,2025 Bryan Biedenkapp, N2PLL
*
*/
/**
@ -65,35 +65,48 @@ namespace dmr
*/
void getData(bool* bits) const;
/** @name Encryption data */
/**
* @brief Sets the encryption message indicator.
* @param[in] mi Buffer containing the 9-byte Message Indicator.
*/
void setMI(const uint8_t* mi);
/**
* @brief Gets the encryption message indicator.
* @param[out] mi Buffer containing the 9-byte Message Indicator.
*/
void getMI(uint8_t* mi) const;
/** @} */
public:
/** @name Common Data */
/**
* @brief Feature ID
*/
__PROPERTY(uint8_t, FID, FID);
DECLARE_PROPERTY(uint8_t, FID, FID);
/**
* @brief Destination ID.
*/
__PROPERTY(uint32_t, dstId, DstId);
DECLARE_PROPERTY(uint32_t, dstId, DstId);
/** @} */
/** @name Service Options */
/**
* @brief Flag indicating a group/talkgroup operation.
*/
__PROPERTY(bool, group, Group);
DECLARE_PROPERTY(bool, group, Group);
/** @} */
/** @name Encryption data */
/**
* @brief Encryption algorithm ID.
*/
__PROPERTY(uint8_t, algId, AlgId);
DECLARE_PROPERTY(uint8_t, algId, AlgId);
/**
* @brief Encryption key ID.
*/
__PROPERTY(uint32_t, kId, KId);
DECLARE_PROPERTY(uint32_t, kId, KId);
/** @} */
private:

@ -61,22 +61,22 @@ namespace dmr
/**
* @brief Aloha Site Time Slot Synchronization.
*/
__PROPERTY(bool, siteTSSync, SiteTSSync);
DECLARE_PROPERTY(bool, siteTSSync, SiteTSSync);
/**
* @brief Aloha MS mask.
*/
__PROPERTY(uint8_t, alohaMask, AlohaMask);
DECLARE_PROPERTY(uint8_t, alohaMask, AlohaMask);
/**
* @brief Backoff Number.
*/
__PROPERTY(uint8_t, backoffNo, BackoffNo);
DECLARE_PROPERTY(uint8_t, backoffNo, BackoffNo);
/**
* @brief Random Access Wait Delay.
*/
__PROPERTY(uint8_t, nRandWait, NRandWait);
DECLARE_PROPERTY(uint8_t, nRandWait, NRandWait);
__COPY(CSBK_ALOHA);
DECLARE_COPY(CSBK_ALOHA);
};
} // namespace csbk
} // namespace lc

@ -61,36 +61,36 @@ namespace dmr
/**
* @brief Broadcast Announcment Type.
*/
__PROPERTY(uint8_t, anncType, AnncType);
DECLARE_PROPERTY(uint8_t, anncType, AnncType);
/**
* @brief Broadcast Hibernation Flag.
*/
__PROPERTY(bool, hibernating, Hibernating);
DECLARE_PROPERTY(bool, hibernating, Hibernating);
/**
* @brief Broadcast Announce/Withdraw Channel 1 Flag.
*/
__PROPERTY(bool, annWdCh1, AnnWdCh1);
DECLARE_PROPERTY(bool, annWdCh1, AnnWdCh1);
/**
* @brief Broadcast Announce/Withdraw Channel 2 Flag.
*/
__PROPERTY(bool, annWdCh2, AnnWdCh2);
DECLARE_PROPERTY(bool, annWdCh2, AnnWdCh2);
/**
* @brief Require Registration.
*/
__PROPERTY(bool, requireReg, RequireReg);
DECLARE_PROPERTY(bool, requireReg, RequireReg);
/**
* @brief System Identity.
*/
__PROPERTY(uint32_t, systemId, SystemId);
DECLARE_PROPERTY(uint32_t, systemId, SystemId);
/**
* @brief Backoff Number.
*/
__PROPERTY(uint8_t, backoffNo, BackoffNo);
DECLARE_PROPERTY(uint8_t, backoffNo, BackoffNo);
__COPY(CSBK_BROADCAST);
DECLARE_COPY(CSBK_BROADCAST);
};
} // namespace csbk
} // namespace lc

@ -61,9 +61,9 @@ namespace dmr
/**
* @brief Base Station ID.
*/
__READONLY_PROPERTY(uint32_t, bsId, BSId);
DECLARE_RO_PROPERTY(uint32_t, bsId, BSId);
__COPY(CSBK_BSDWNACT);
DECLARE_COPY(CSBK_BSDWNACT);
};
} // namespace csbk
} // namespace lc

@ -61,9 +61,9 @@ namespace dmr
/**
* @brief Extended function opcode.
*/
__PROPERTY(uint8_t, extendedFunction, ExtendedFunction);
DECLARE_PROPERTY(uint8_t, extendedFunction, ExtendedFunction);
__COPY(CSBK_EXT_FNCT);
DECLARE_COPY(CSBK_EXT_FNCT);
};
} // namespace csbk
} // namespace lc

@ -64,9 +64,9 @@ namespace dmr
/**
* @brief Maintainence Kind.
*/
__PROPERTY(uint8_t, maintKind, MaintKind);
DECLARE_PROPERTY(uint8_t, maintKind, MaintKind);
__COPY(CSBK_MAINT);
DECLARE_COPY(CSBK_MAINT);
};
} // namespace csbk
} // namespace lc

@ -61,9 +61,9 @@ namespace dmr
/**
* @brief Service Kind.
*/
__PROPERTY(uint8_t, serviceKind, ServiceKind);
DECLARE_PROPERTY(uint8_t, serviceKind, ServiceKind);
__COPY(CSBK_NACK_RSP);
DECLARE_COPY(CSBK_NACK_RSP);
};
} // namespace csbk
} // namespace lc

@ -61,17 +61,17 @@ namespace dmr
/**
* @brief Service Options.
*/
__PROPERTY(uint8_t, serviceOptions, ServiceOptions);
DECLARE_PROPERTY(uint8_t, serviceOptions, ServiceOptions);
/**
* @brief Service Extra Options.
*/
__PROPERTY(uint8_t, serviceExtra, ServiceExtra);
DECLARE_PROPERTY(uint8_t, serviceExtra, ServiceExtra);
/**
* @brief Service Kind.
*/
__PROPERTY(uint8_t, serviceKind, ServiceKind);
DECLARE_PROPERTY(uint8_t, serviceKind, ServiceKind);
__COPY(CSBK_RAND);
DECLARE_COPY(CSBK_RAND);
};
} // namespace csbk
} // namespace lc

@ -61,9 +61,9 @@ namespace dmr
/**
* @brief Flag indicating whether the grant is a late entry.
*/
__PROPERTY(bool, lateEntry, LateEntry);
DECLARE_PROPERTY(bool, lateEntry, LateEntry);
__COPY(CSBK_TV_GRANT);
DECLARE_COPY(CSBK_TV_GRANT);
};
} // namespace csbk
} // namespace lc

@ -48,6 +48,8 @@ namespace lookups
VoiceChData() :
m_chId(0U),
m_chNo(0U),
m_rxChId(0xFFU),
m_rxChNo(0xFFFFU),
m_address(),
m_port(),
m_password(),
@ -67,6 +69,31 @@ namespace lookups
VoiceChData(uint8_t chId, uint32_t chNo, std::string address, uint16_t port, std::string password, bool ssl = false) :
m_chId(chId),
m_chNo(chNo),
m_rxChId(0xFFU),
m_rxChNo(0xFFFFU),
m_address(address),
m_port(port),
m_password(password),
m_ssl(ssl)
{
/* stub */
}
/**
* @brief Initializes a new instance of the VoiceChData class.
* @param chId Voice Channel Identity.
* @param chNo Voice Channel Number.
* @param chId Voice Rx Channel Identity.
* @param chNo Voice Rx Channel Number.
* @param address RPC/REST API Address.
* @param port RPC/REST API Port.
* @param password RPC/REST API Password.
* @param ssl Flag indicating REST is using SSL.
*/
VoiceChData(uint8_t chId, uint32_t chNo, uint8_t rxChId, uint32_t rxChNo, std::string address, uint16_t port, std::string password, bool ssl = false) :
m_chId(chId),
m_chNo(chNo),
m_rxChId(rxChId),
m_rxChNo(rxChNo),
m_address(address),
m_port(port),
m_password(password),
@ -84,6 +111,8 @@ namespace lookups
if (this != &data) {
m_chId = data.m_chId;
m_chNo = data.m_chNo;
m_rxChId = data.m_rxChId;
m_rxChNo = data.m_rxChNo;
m_address = data.m_address;
m_port = data.m_port;
m_password = data.m_password;
@ -103,32 +132,56 @@ namespace lookups
* @returns True, if channel is valid, otherwise false.
*/
bool isValidCh() const { return m_chNo != 0U; }
/**
* @brief Helper to determine if the Rx channel identity is valid.
* @returns True, if channel identity is valid, otherwise false.
*/
bool isValidRxChId() const { return m_rxChId != 0U && m_rxChId != 0xFFU; }
/**
* @brief Helper to determine if the Rx channel is valid.
* @returns True, if channel is valid, otherwise false.
*/
bool isValidRxCh() const { return m_rxChNo != 0U && m_rxChNo != 0xFFFFU; }
/**
* @brief Helper to determine if the channel is explicitly defined with independant Rx and Tx channels.
* @returns True, if channel is explicit, otherwise false.
*/
bool isExplicitCh() const { return (m_rxChId != 0xFFU && m_rxChId > 0U) && (m_rxChNo != 0xFFFFU && m_rxChNo > 0U); }
public:
/**
* @brief Voice Channel Identity.
*/
__READONLY_PROPERTY_PLAIN(uint8_t, chId);
DECLARE_RO_PROPERTY_PLAIN(uint8_t, chId);
/**
* @brief Voice Channel Number.
*/
__READONLY_PROPERTY_PLAIN(uint32_t, chNo);
DECLARE_RO_PROPERTY_PLAIN(uint32_t, chNo);
/**
* @brief Voice Rx Channel Identity.
*/
DECLARE_RO_PROPERTY_PLAIN(uint8_t, rxChId);
/**
* @brief Voice Rx Channel Number.
*/
DECLARE_RO_PROPERTY_PLAIN(uint32_t, rxChNo);
/**
* @brief RPC/REST API Address.
*/
__PROPERTY_PLAIN(std::string, address);
DECLARE_PROPERTY_PLAIN(std::string, address);
/**
* @brief RPC/REST API Port.
*/
__PROPERTY_PLAIN(uint16_t, port);
DECLARE_PROPERTY_PLAIN(uint16_t, port);
/**
* @brief RPC/REST API Password.
*/
__READONLY_PROPERTY_PLAIN(std::string, password);
DECLARE_RO_PROPERTY_PLAIN(std::string, password);
/**
* @brief Flag indicating REST is using SSL.
*/
__PROPERTY_PLAIN(bool, ssl);
DECLARE_PROPERTY_PLAIN(bool, ssl);
};
// ---------------------------------------------------------------------------

@ -91,23 +91,23 @@ namespace lookups
/**
* @brief Channel ID for this entry.
*/
__READONLY_PROPERTY_PLAIN(uint8_t, channelId);
DECLARE_RO_PROPERTY_PLAIN(uint8_t, channelId);
/**
* @brief Base frequency for this entry.
*/
__READONLY_PROPERTY_PLAIN(uint32_t, baseFrequency);
DECLARE_RO_PROPERTY_PLAIN(uint32_t, baseFrequency);
/**
* @brief Channel spacing in kHz for this entry.
*/
__READONLY_PROPERTY_PLAIN(float, chSpaceKhz);
DECLARE_RO_PROPERTY_PLAIN(float, chSpaceKhz);
/**
* @brief Channel transmit offset in MHz for this entry.
*/
__READONLY_PROPERTY_PLAIN(float, txOffsetMhz);
DECLARE_RO_PROPERTY_PLAIN(float, txOffsetMhz);
/**
* @brief Channel bandwith in kHz for this entry.
*/
__READONLY_PROPERTY_PLAIN(float, chBandwidthKhz);
DECLARE_RO_PROPERTY_PLAIN(float, chBandwidthKhz);
};
// ---------------------------------------------------------------------------

@ -118,27 +118,27 @@ namespace lookups
/**
* @brief Peer ID.
*/
__PROPERTY_PLAIN(uint32_t, peerId);
DECLARE_PROPERTY_PLAIN(uint32_t, peerId);
/**
* @breif Peer Alias
*/
__PROPERTY_PLAIN(std::string, peerAlias);
DECLARE_PROPERTY_PLAIN(std::string, peerAlias);
/**
* @brief Per Peer Password.
*/
__PROPERTY_PLAIN(std::string, peerPassword);
DECLARE_PROPERTY_PLAIN(std::string, peerPassword);
/**
* @brief Flag indicating if the peer participates in peer link and should be sent configuration.
*/
__PROPERTY_PLAIN(bool, peerLink);
DECLARE_PROPERTY_PLAIN(bool, peerLink);
/**
* @brief Flag indicating if the peer can request encryption keys.
*/
__PROPERTY_PLAIN(bool, canRequestKeys);
DECLARE_PROPERTY_PLAIN(bool, canRequestKeys);
/**
* @brief Flag indicating if the peer is default.
*/
__READONLY_PROPERTY_PLAIN(bool, peerDefault);
DECLARE_RO_PROPERTY_PLAIN(bool, peerDefault);
};
// ---------------------------------------------------------------------------

@ -116,19 +116,19 @@ namespace lookups
/**
* @brief Flag indicating if the radio is enabled.
*/
__READONLY_PROPERTY_PLAIN(bool, radioEnabled);
DECLARE_RO_PROPERTY_PLAIN(bool, radioEnabled);
/**
* @brief Flag indicating if the radio is default.
*/
__READONLY_PROPERTY_PLAIN(bool, radioDefault);
DECLARE_RO_PROPERTY_PLAIN(bool, radioDefault);
/**
* @brief Alias for the radio.
*/
__READONLY_PROPERTY_PLAIN(std::string, radioAlias);
DECLARE_RO_PROPERTY_PLAIN(std::string, radioAlias);
/**
* @brief IP Address for the radio.
*/
__READONLY_PROPERTY_PLAIN(std::string, radioIPAddress);
DECLARE_RO_PROPERTY_PLAIN(std::string, radioIPAddress);
};
// ---------------------------------------------------------------------------

@ -91,11 +91,11 @@ namespace lookups
/**
* @brief Talkgroup ID.
*/
__PROPERTY_PLAIN(uint32_t, tgId);
DECLARE_PROPERTY_PLAIN(uint32_t, tgId);
/**
* @brief Talkgroup DMR slot.
*/
__PROPERTY_PLAIN(uint8_t, tgSlot);
DECLARE_PROPERTY_PLAIN(uint8_t, tgSlot);
};
// ---------------------------------------------------------------------------
@ -160,15 +160,15 @@ namespace lookups
/**
* @brief Peer ID.
*/
__PROPERTY_PLAIN(uint32_t, peerId);
DECLARE_PROPERTY_PLAIN(uint32_t, peerId);
/**
* @brief Talkgroup ID.
*/
__PROPERTY_PLAIN(uint32_t, tgId);
DECLARE_PROPERTY_PLAIN(uint32_t, tgId);
/**
* @brief Talkgroup DMR slot.
*/
__PROPERTY_PLAIN(uint8_t, tgSlot);
DECLARE_PROPERTY_PLAIN(uint8_t, tgSlot);
};
// ---------------------------------------------------------------------------
@ -382,45 +382,45 @@ namespace lookups
/**
* @brief Flag indicating whether the rule is active.
*/
__PROPERTY_PLAIN(bool, active);
DECLARE_PROPERTY_PLAIN(bool, active);
/**
* @brief Flag indicating whether this talkgroup will only repeat with affiliations.
*/
__PROPERTY_PLAIN(bool, affiliated);
DECLARE_PROPERTY_PLAIN(bool, affiliated);
/**
* @brief Flag indicating whether or not the talkgroup is a parrot.
*/
__PROPERTY_PLAIN(bool, parrot);
DECLARE_PROPERTY_PLAIN(bool, parrot);
/**
* @brief List of peer IDs included by this rule.
*/
__PROPERTY_PLAIN(std::vector<uint32_t>, inclusion);
DECLARE_PROPERTY_PLAIN(std::vector<uint32_t>, inclusion);
/**
* @brief List of peer IDs excluded by this rule.
*/
__PROPERTY_PLAIN(std::vector<uint32_t>, exclusion);
DECLARE_PROPERTY_PLAIN(std::vector<uint32_t>, exclusion);
/**
* @brief List of rewrites performed by this rule.
*/
__PROPERTY_PLAIN(std::vector<TalkgroupRuleRewrite>, rewrite);
DECLARE_PROPERTY_PLAIN(std::vector<TalkgroupRuleRewrite>, rewrite);
/**
* @brief List of always send performed by this rule.
*/
__PROPERTY_PLAIN(std::vector<uint32_t>, alwaysSend);
DECLARE_PROPERTY_PLAIN(std::vector<uint32_t>, alwaysSend);
/**
* @brief List of peer IDs preferred by this rule.
*/
__PROPERTY_PLAIN(std::vector<uint32_t>, preferred);
DECLARE_PROPERTY_PLAIN(std::vector<uint32_t>, preferred);
/**
* @brief List of radios IDs permitted to transmit on the talkgroup.
*/
__PROPERTY_PLAIN(std::vector<uint32_t>, permittedRIDs);
DECLARE_PROPERTY_PLAIN(std::vector<uint32_t>, permittedRIDs);
/**
* @brief Flag indicating whether or not the talkgroup is a non-preferred.
*/
__PROPERTY_PLAIN(bool, nonPreferred);
DECLARE_PROPERTY_PLAIN(bool, nonPreferred);
};
// ---------------------------------------------------------------------------
@ -506,19 +506,19 @@ namespace lookups
/**
* @brief Textual name for the routing rule.
*/
__PROPERTY_PLAIN(std::string, name);
DECLARE_PROPERTY_PLAIN(std::string, name);
/**
* @brief (Optional) Secondary textual name for the routing rule.
*/
__PROPERTY_PLAIN(std::string, nameAlias);
DECLARE_PROPERTY_PLAIN(std::string, nameAlias);
/**
* @brief Configuration for the routing rule.
*/
__PROPERTY_PLAIN(TalkgroupRuleConfig, config);
DECLARE_PROPERTY_PLAIN(TalkgroupRuleConfig, config);
/**
* @brief Source talkgroup information for the routing rule.
*/
__PROPERTY_PLAIN(TalkgroupRuleGroupVoiceSource, source);
DECLARE_PROPERTY_PLAIN(TalkgroupRuleGroupVoiceSource, source);
};
// ---------------------------------------------------------------------------
@ -661,15 +661,15 @@ namespace lookups
/**
* @brief Number indicating the number of seconds to hang on a talkgroup.
*/
__PROPERTY_PLAIN(uint32_t, groupHangTime);
DECLARE_PROPERTY_PLAIN(uint32_t, groupHangTime);
/**
* @brief Flag indicating whether or not the network layer should send the talkgroups to peers.
*/
__PROPERTY_PLAIN(bool, sendTalkgroups);
DECLARE_PROPERTY_PLAIN(bool, sendTalkgroups);
/**
* @brief List of group voice rules.
*/
__PROPERTY_PLAIN(std::vector<TalkgroupRuleGroupVoice>, groupVoice);
DECLARE_PROPERTY_PLAIN(std::vector<TalkgroupRuleGroupVoice>, groupVoice);
};
} // namespace lookups

@ -101,8 +101,8 @@ bool BaseNetwork::writeGrantReq(const uint8_t mode, const uint32_t srcId, const
uint8_t buffer[MSG_HDR_SIZE];
::memset(buffer, 0x00U, MSG_HDR_SIZE);
__SET_UINT32(srcId, buffer, 11U); // Source Address
__SET_UINT32(dstId, buffer, 15U); // Destination Address
SET_UINT32(srcId, buffer, 11U); // Source Address
SET_UINT32(dstId, buffer, 15U); // Destination Address
buffer[19U] = slot; // Slot Number
if (unitToUnit)
@ -220,8 +220,8 @@ bool BaseNetwork::announceGroupAffiliation(uint32_t srcId, uint32_t dstId)
uint8_t buffer[DATA_PACKET_LENGTH];
__SET_UINT16(srcId, buffer, 0U);
__SET_UINT16(dstId, buffer, 3U);
SET_UINT24(srcId, buffer, 0U);
SET_UINT24(dstId, buffer, 3U);
return writeMaster({ NET_FUNC::ANNOUNCE, NET_SUBFUNC::ANNC_SUBFUNC_GRP_AFFIL }, buffer, MSG_ANNC_GRP_AFFIL, RTP_END_OF_CALL_SEQ, 0U);
}
@ -235,7 +235,7 @@ bool BaseNetwork::announceGroupAffiliationRemoval(uint32_t srcId)
uint8_t buffer[DATA_PACKET_LENGTH];
__SET_UINT16(srcId, buffer, 0U);
SET_UINT24(srcId, buffer, 0U);
return writeMaster({ NET_FUNC::ANNOUNCE, NET_SUBFUNC::ANNC_SUBFUNC_GRP_UNAFFIL }, buffer, MSG_ANNC_GRP_UNAFFIL, RTP_END_OF_CALL_SEQ, 0U);
}
@ -249,7 +249,7 @@ bool BaseNetwork::announceUnitRegistration(uint32_t srcId)
uint8_t buffer[DATA_PACKET_LENGTH];
__SET_UINT16(srcId, buffer, 0U);
SET_UINT24(srcId, buffer, 0U);
return writeMaster({ NET_FUNC::ANNOUNCE, NET_SUBFUNC::ANNC_SUBFUNC_UNIT_REG }, buffer, MSG_ANNC_UNIT_REG, RTP_END_OF_CALL_SEQ, 0U);
}
@ -263,7 +263,7 @@ bool BaseNetwork::announceUnitDeregistration(uint32_t srcId)
uint8_t buffer[DATA_PACKET_LENGTH];
__SET_UINT16(srcId, buffer, 0U);
SET_UINT24(srcId, buffer, 0U);
return writeMaster({ NET_FUNC::ANNOUNCE, NET_SUBFUNC::ANNC_SUBFUNC_UNIT_DEREG }, buffer, MSG_ANNC_UNIT_REG, RTP_END_OF_CALL_SEQ, 0U);
}
@ -275,17 +275,15 @@ bool BaseNetwork::announceAffiliationUpdate(const std::unordered_map<uint32_t, u
if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING)
return false;
UInt8Array __buffer = std::make_unique<uint8_t[]>(4U + (affs.size() * 8U));
uint8_t* buffer = __buffer.get();
::memset(buffer, 0x00U, 4U + (affs.size() * 8U));
DECLARE_UINT8_ARRAY(buffer, 4U + (affs.size() * 8U));
__SET_UINT32(affs.size(), buffer, 0U);
SET_UINT32(affs.size(), buffer, 0U);
// write talkgroup IDs to active TGID payload
uint32_t offs = 4U;
for (auto it : affs) {
__SET_UINT16(it.first, buffer, offs);
__SET_UINT16(it.second, buffer, offs + 4U);
SET_UINT24(it.first, buffer, offs);
SET_UINT24(it.second, buffer, offs + 4U);
offs += 8U;
}
@ -299,16 +297,14 @@ bool BaseNetwork::announceSiteVCs(const std::vector<uint32_t> peers)
if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING)
return false;
UInt8Array __buffer = std::make_unique<uint8_t[]>(4U + (peers.size() * 4U));
uint8_t* buffer = __buffer.get();
::memset(buffer, 0x00U, 4U + (peers.size() * 4U));
DECLARE_UINT8_ARRAY(buffer, 4U + (peers.size() * 4U));
__SET_UINT32(peers.size(), buffer, 0U);
SET_UINT32(peers.size(), buffer, 0U);
// write peer IDs to active TGID payload
uint32_t offs = 4U;
for (auto it : peers) {
__SET_UINT32(it, buffer, offs);
SET_UINT32(it, buffer, offs);
offs += 4U;
}
@ -762,10 +758,10 @@ UInt8Array BaseNetwork::createDMR_Message(uint32_t& length, const uint32_t strea
::memcpy(buffer + 0U, TAG_DMR_DATA, 4U);
uint32_t srcId = data.getSrcId(); // Source Address
__SET_UINT16(srcId, buffer, 5U);
SET_UINT24(srcId, buffer, 5U);
uint32_t dstId = data.getDstId(); // Target Address
__SET_UINT16(dstId, buffer, 8U);
SET_UINT24(dstId, buffer, 8U);
uint32_t slotNo = data.getSlotNo();
@ -826,20 +822,20 @@ void BaseNetwork::createP25_MessageHdr(uint8_t* buffer, p25::defines::DUID::E du
buffer[4U] = control.getLCO(); // LCO
uint32_t srcId = control.getSrcId(); // Source Address
__SET_UINT16(srcId, buffer, 5U);
SET_UINT24(srcId, buffer, 5U);
uint32_t dstId = control.getDstId(); // Target Address
__SET_UINT16(dstId, buffer, 8U);
SET_UINT24(dstId, buffer, 8U);
uint16_t sysId = control.getSiteData().sysId(); // System ID
__SET_UINT16B(sysId, buffer, 11U);
SET_UINT16(sysId, buffer, 11U);
buffer[14U] = 0U; // Control Bits
buffer[15U] = control.getMFId(); // MFId
uint32_t netId = control.getSiteData().netId(); // Network ID
__SET_UINT16(netId, buffer, 16U);
SET_UINT24(netId, buffer, 16U);
buffer[20U] = lsd.getLSD1(); // LSD 1
buffer[21U] = lsd.getLSD2(); // LSD 2
@ -855,7 +851,7 @@ void BaseNetwork::createP25_MessageHdr(uint8_t* buffer, p25::defines::DUID::E du
buffer[181U] = control.getAlgId(); // Algorithm ID
uint32_t kid = control.getKId();
__SET_UINT16B(kid, buffer, 182U); // Key ID
SET_UINT16(kid, buffer, 182U); // Key ID
// copy MI data
uint8_t mi[MI_LENGTH_BYTES];
@ -1125,7 +1121,7 @@ UInt8Array BaseNetwork::createP25_PDUMessage(uint32_t& length, const p25::data::
buffer[4U] |= 0x80U;
}
__SET_UINT16(len, buffer, 8U); // PDU Length [bytes]
SET_UINT24(len, buffer, 8U); // PDU Length [bytes]
buffer[15U] = header.getMFId(); // MFId
@ -1164,10 +1160,10 @@ UInt8Array BaseNetwork::createNXDN_Message(uint32_t& length, const nxdn::lc::RTC
buffer[4U] = lc.getMessageType(); // Message Type
uint32_t srcId = lc.getSrcId(); // Source Address
__SET_UINT16(srcId, buffer, 5U);
SET_UINT24(srcId, buffer, 5U);
uint32_t dstId = lc.getDstId(); // Target Address
__SET_UINT16(dstId, buffer, 8U);
SET_UINT24(dstId, buffer, 8U);
buffer[14U] = 0U; // Control Bits

@ -444,34 +444,34 @@ namespace network
/**
* @brief Gets the peer ID of the network.
*/
__PROTECTED_READONLY_PROPERTY(uint32_t, peerId, PeerId);
DECLARE_PROTECTED_RO_PROPERTY(uint32_t, peerId, PeerId);
/**
* @brief Gets the current status of the network.
*/
__PROTECTED_READONLY_PROPERTY(NET_CONN_STATUS, status, Status);
DECLARE_PROTECTED_RO_PROPERTY(NET_CONN_STATUS, status, Status);
/**
* @brief Unix socket storage containing the connected address.
*/
__PROTECTED_READONLY_PROPERTY_PLAIN(sockaddr_storage, addr);
DECLARE_PROTECTED_RO_PROPERTY_PLAIN(sockaddr_storage, addr);
/**
* @brief Length of the sockaddr_storage structure.
*/
__PROTECTED_READONLY_PROPERTY_PLAIN(uint32_t, addrLen);
DECLARE_PROTECTED_RO_PROPERTY_PLAIN(uint32_t, addrLen);
/**
* @brief Flag indicating whether network DMR slot 1 traffic is permitted.
*/
__PROTECTED_READONLY_PROPERTY(bool, slot1, DMRSlot1);
DECLARE_PROTECTED_RO_PROPERTY(bool, slot1, DMRSlot1);
/**
* @brief Flag indicating whether network DMR slot 2 traffic is permitted.
*/
__PROTECTED_READONLY_PROPERTY(bool, slot2, DMRSlot2);
DECLARE_PROTECTED_RO_PROPERTY(bool, slot2, DMRSlot2);
/**
* @brief Flag indicating whether network traffic is duplex.
*/
__PROTECTED_READONLY_PROPERTY(bool, duplex, Duplex);
DECLARE_PROTECTED_RO_PROPERTY(bool, duplex, Duplex);
protected:
bool m_useAlternatePortForDiagnostics;

@ -32,6 +32,9 @@ using namespace network::frame;
FrameQueue::FrameQueue(udp::Socket* socket, uint32_t peerId, bool debug) : RawFrameQueue(socket, debug),
m_peerId(peerId),
#if defined(_WIN32)
m_streamTSMtx(),
#endif // defined(_WIN32)
m_streamTimestamps()
{
assert(peerId < 999999999U);
@ -148,6 +151,12 @@ bool FrameQueue::write(const uint8_t* message, uint32_t length, uint32_t streamI
uint32_t bufferLen = 0U;
uint8_t* buffer = generateMessage(message, length, streamId, peerId, ssrc, opcode, rtpSeq, &bufferLen);
// bryanb: this is really a developer warning not a end-user warning, there's nothing the end-users can do about
// this message
if (bufferLen > (DATA_PACKET_LENGTH - OVERSIZED_PACKET_WARN)) {
LogDebug(LOG_NET, "FrameQueue::write(), WARN: packet length is possibly oversized, possible data truncation - BUGBUG");
}
bool ret = true;
if (!m_socket->write(buffer, bufferLen, addr, addrLen)) {
// LogError(LOG_NET, "Failed writing data to the network");
@ -183,6 +192,12 @@ void FrameQueue::enqueueMessage(const uint8_t* message, uint32_t length, uint32_
uint32_t bufferLen = 0U;
uint8_t* buffer = generateMessage(message, length, streamId, peerId, ssrc, opcode, rtpSeq, &bufferLen);
// bryanb: this is really a developer warning not a end-user warning, there's nothing the end-users can do about
// this message
if (bufferLen > (DATA_PACKET_LENGTH - OVERSIZED_PACKET_WARN)) {
LogDebug(LOG_NET, "FrameQueue::enqueueMessage(), WARN: packet length is possibly oversized, possible data truncation - BUGBUG");
}
udp::UDPDatagram *dgram = new udp::UDPDatagram;
dgram->buffer = buffer;
dgram->length = bufferLen;
@ -219,7 +234,11 @@ uint8_t* FrameQueue::generateMessage(const uint8_t* message, uint32_t length, ui
uint32_t timestamp = INVALID_TS;
if (streamId != 0U) {
#if defined(_WIN32)
std::lock_guard<std::mutex> lock(m_streamTSMtx);
#else
m_streamTimestamps.lock(false);
#endif // defined(_WIN32)
auto entry = m_streamTimestamps.find(streamId);
if (entry != m_streamTimestamps.end()) {
timestamp = entry->second;
@ -231,7 +250,9 @@ uint8_t* FrameQueue::generateMessage(const uint8_t* message, uint32_t length, ui
LogDebugEx(LOG_NET, "FrameQueue::generateMessage()", "RTP streamId = %u, previous TS = %u, TS = %u, rtpSeq = %u", streamId, m_streamTimestamps[streamId], timestamp, rtpSeq);
m_streamTimestamps[streamId] = timestamp;
}
#if !defined(_WIN32)
m_streamTimestamps.unlock();
#endif // defined(_WIN32)
}
uint32_t bufferLen = RTP_HEADER_LENGTH_BYTES + RTP_EXTENSION_HEADER_LENGTH_BYTES + RTP_FNE_HEADER_LENGTH_BYTES + length;
@ -253,21 +274,34 @@ uint8_t* FrameQueue::generateMessage(const uint8_t* message, uint32_t length, ui
timestamp = (uint32_t)system_clock::ntp::now();
header.setTimestamp(timestamp);
#if defined(_WIN32)
std::lock_guard<std::mutex> lock(m_streamTSMtx);
m_streamTimestamps.insert({ streamId, timestamp });
#else
m_streamTimestamps.insert(streamId, timestamp);
#endif // defined(_WIN32)
}
header.encode(buffer);
if (streamId != 0U && rtpSeq == RTP_END_OF_CALL_SEQ) {
#if defined(_WIN32)
std::lock_guard<std::mutex> lock(m_streamTSMtx);
#else
m_streamTimestamps.lock(false);
#endif // defined(_WIN32)
auto entry = m_streamTimestamps.find(streamId);
if (entry != m_streamTimestamps.end()) {
if (m_debug)
LogDebugEx(LOG_NET, "FrameQueue::generateMessage()", "RTP streamId = %u, rtpSeq = %u", streamId, rtpSeq);
#if !defined(_WIN32)
m_streamTimestamps.unlock();
#endif // defined(_WIN32)
m_streamTimestamps.erase(streamId);
}
#if !defined(_WIN32)
m_streamTimestamps.unlock();
#endif // defined(_WIN32)
}
RTPFNEHeader fneHeader = RTPFNEHeader();

@ -115,7 +115,12 @@ namespace network
private:
uint32_t m_peerId;
#if defined(_WIN32)
std::mutex m_streamTSMtx;
std::unordered_map<uint32_t, uint32_t> m_streamTimestamps;
#else
concurrent::unordered_map<uint32_t, uint32_t> m_streamTimestamps;
#endif // defined(_WIN32)
/**
* @brief Generate RTP message for the frame queue.

@ -210,8 +210,7 @@ bool NetRPC::req(uint16_t func, const json::object& request, RPCType reply, sock
header.setMessageLength(json.length() + 1U);
// generate message
CharArray __message = std::make_unique<char[]>(json.length() + 1U);
char* message = __message.get();
DECLARE_CHAR_ARRAY(message, json.length() + 1U);
::snprintf(message, json.length() + 1U, "%s", json.c_str());
@ -223,8 +222,7 @@ bool NetRPC::req(uint16_t func, const json::object& request, RPCType reply, sock
header.setCRC(crc);
// generate RPC message
UInt8Array __buffer = std::make_unique<uint8_t[]>(json.length() + 9U);
uint8_t* buffer = __buffer.get();
DECLARE_UINT8_ARRAY(buffer, json.length() + 9U);
header.encode(buffer);
::memcpy(buffer + 8U, message, json.length() + 1U);
@ -338,8 +336,7 @@ bool NetRPC::reply(uint16_t func, json::object& reply, sockaddr_storage& address
header.setMessageLength(json.length() + 1U);
// generate message
CharArray __message = std::make_unique<char[]>(json.length() + 1U);
char* message = __message.get();
DECLARE_CHAR_ARRAY(message, json.length() + 1U);
::snprintf(message, json.length() + 1U, "%s", json.c_str());
@ -347,8 +344,7 @@ bool NetRPC::reply(uint16_t func, json::object& reply, sockaddr_storage& address
header.setCRC(crc);
// generate RPC message
UInt8Array __buffer = std::make_unique<uint8_t[]>(json.length() + 9U);
uint8_t* buffer = __buffer.get();
DECLARE_UINT8_ARRAY(buffer, json.length() + 9U);
header.encode(buffer);
::memcpy(buffer + 8U, message, json.length() + 1U);

@ -444,10 +444,10 @@ void Network::clock(uint32_t ms)
if (m_ridLookup != nullptr) {
// update RID lists
uint32_t len = __GET_UINT32(buffer, 6U);
uint32_t len = GET_UINT32(buffer, 6U);
uint32_t offs = 11U;
for (uint32_t i = 0; i < len; i++) {
uint32_t id = __GET_UINT16(buffer, offs);
uint32_t id = GET_UINT24(buffer, offs);
m_ridLookup->toggleEntry(id, true);
offs += 4U;
}
@ -470,10 +470,10 @@ void Network::clock(uint32_t ms)
if (m_ridLookup != nullptr) {
// update RID lists
uint32_t len = __GET_UINT32(buffer, 6U);
uint32_t len = GET_UINT32(buffer, 6U);
uint32_t offs = 11U;
for (uint32_t i = 0; i < len; i++) {
uint32_t id = __GET_UINT16(buffer, offs);
uint32_t id = GET_UINT24(buffer, offs);
m_ridLookup->toggleEntry(id, false);
offs += 4U;
}
@ -497,10 +497,10 @@ void Network::clock(uint32_t ms)
if (m_tidLookup != nullptr) {
// update TGID lists
uint32_t len = __GET_UINT32(buffer, 6U);
uint32_t len = GET_UINT32(buffer, 6U);
uint32_t offs = 11U;
for (uint32_t i = 0; i < len; i++) {
uint32_t id = __GET_UINT16(buffer, offs);
uint32_t id = GET_UINT24(buffer, offs);
uint8_t slot = (buffer[offs + 3U]) & 0x03U;
bool affiliated = (buffer[offs + 3U] & 0x40U) == 0x40U;
bool nonPreferred = (buffer[offs + 3U] & 0x80U) == 0x80U;
@ -547,10 +547,10 @@ void Network::clock(uint32_t ms)
if (m_tidLookup != nullptr) {
// update TGID lists
uint32_t len = __GET_UINT32(buffer, 6U);
uint32_t len = GET_UINT32(buffer, 6U);
uint32_t offs = 11U;
for (uint32_t i = 0; i < len; i++) {
uint32_t id = __GET_UINT16(buffer, offs);
uint32_t id = GET_UINT24(buffer, offs);
uint8_t slot = (buffer[offs + 3U]);
lookups::TalkgroupRuleGroupVoice tid = m_tidLookup->find(id, slot);
@ -588,7 +588,7 @@ void Network::clock(uint32_t ms)
{
if (m_enabled && m_dmrEnabled) {
NET_ICC::ENUM command = (NET_ICC::ENUM)buffer[10U];
uint32_t dstId = __GET_UINT16(buffer, 11U);
uint32_t dstId = GET_UINT24(buffer, 11U);
uint8_t slot = buffer[14U];
// fire off DMR in-call callback if we have one
@ -602,7 +602,7 @@ void Network::clock(uint32_t ms)
{
if (m_enabled && m_p25Enabled) {
NET_ICC::ENUM command = (NET_ICC::ENUM)buffer[10U];
uint32_t dstId = __GET_UINT16(buffer, 11U);
uint32_t dstId = GET_UINT24(buffer, 11U);
// fire off P25 in-call callback if we have one
if (m_p25InCallCallback != nullptr) {
@ -615,7 +615,7 @@ void Network::clock(uint32_t ms)
{
if (m_enabled && m_nxdnEnabled) {
NET_ICC::ENUM command = (NET_ICC::ENUM)buffer[10U];
uint32_t dstId = __GET_UINT16(buffer, 11U);
uint32_t dstId = GET_UINT24(buffer, 11U);
// fire off NXDN in-call callback if we have one
if (m_nxdnInCallCallback != nullptr) {
@ -677,7 +677,7 @@ void Network::clock(uint32_t ms)
// then 10 bytes and process the reason value
uint16_t reason = 0U;
if (length > 10) {
reason = __GET_UINT16B(buffer, 10U);
reason = GET_UINT16(buffer, 10U);
switch (reason) {
case NET_CONN_NAK_MODE_NOT_ENABLED:
LogWarning(LOG_NET, "PEER %u master NAK; digital mode not enabled on FNE, remotePeerId = %u", m_peerId, rtpHeader.getSSRC());
@ -773,6 +773,11 @@ void Network::clock(uint32_t ms)
m_useAlternatePortForDiagnostics = (buffer[6U] & 0x80U) == 0x80U;
if (m_useAlternatePortForDiagnostics) {
LogMessage(LOG_NET, "PEER %u RPTC ACK, master commanded alternate port for diagnostics and activity logging, remotePeerId = %u", m_peerId, rtpHeader.getSSRC());
} else {
// disable diagnostic and activity logging automatically if the master doesn't utilize the alternate port
m_allowDiagnosticTransfer = false;
m_allowActivityTransfer = false;
LogWarning(LOG_NET, "PEER %u RPTC ACK, master does not enable alternate port for diagnostics and activity logging, diagnostic and activity logging are disabled, remotePeerId = %u", m_peerId, rtpHeader.getSSRC());
}
}
break;
@ -781,9 +786,9 @@ void Network::clock(uint32_t ms)
}
}
break;
case NET_FUNC::MST_CLOSING: // Master Shutdown
case NET_FUNC::MST_DISC: // Master Disconnect
{
LogError(LOG_NET, "PEER %u master is closing down, remotePeerId = %u", m_peerId, m_remotePeerId);
LogError(LOG_NET, "PEER %u master disconnect, remotePeerId = %u", m_peerId, m_remotePeerId);
m_status = NET_STAT_WAITING_CONNECT;
// fire off peer disconnected callback if we have one
@ -895,7 +900,7 @@ void Network::close()
uint8_t buffer[1U];
::memset(buffer, 0x00U, 1U);
writeMaster({ NET_FUNC::RPT_CLOSING, NET_SUBFUNC::NOP }, buffer, 1U, pktSeq(true), createStreamId());
writeMaster({ NET_FUNC::RPT_DISC, NET_SUBFUNC::NOP }, buffer, 1U, pktSeq(true), createStreamId());
}
m_socket->close();
@ -934,7 +939,7 @@ bool Network::writeLogin()
uint8_t buffer[8U];
::memcpy(buffer + 0U, TAG_REPEATER_LOGIN, 4U);
__SET_UINT32(m_peerId, buffer, 4U); // Peer ID
SET_UINT32(m_peerId, buffer, 4U); // Peer ID
if (m_debug)
Utils::dump(1U, "Network Message, Login", buffer, 8U);
@ -962,7 +967,7 @@ bool Network::writeAuthorisation()
uint8_t out[40U];
::memcpy(out + 0U, TAG_REPEATER_AUTH, 4U);
__SET_UINT32(m_peerId, out, 4U); // Peer ID
SET_UINT32(m_peerId, out, 4U); // Peer ID
edac::SHA256 sha256;
sha256.buffer(in, (uint32_t)(size + sizeof(uint32_t)), out + 8U);
@ -1025,8 +1030,7 @@ bool Network::writeConfig()
json::value v = json::value(config);
std::string json = v.serialize();
CharArray __buffer = std::make_unique<char[]>(json.length() + 9U);
char* buffer = __buffer.get();
DECLARE_CHAR_ARRAY(buffer, json.length() + 9U);
::memcpy(buffer + 0U, TAG_REPEATER_CONFIG, 4U);
::snprintf(buffer + 8U, json.length() + 1U, "%s", json.c_str());

@ -222,7 +222,7 @@ namespace network
/**
* @brief Last received RTP sequence number.
*/
__READONLY_PROPERTY_PLAIN(uint16_t, pktLastSeq);
DECLARE_RO_PROPERTY_PLAIN(uint16_t, pktLastSeq);
protected:
std::string m_address;

@ -0,0 +1,229 @@
// 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) 2025 Bryan Biedenkapp, N2PLL
*
*/
#include "Defines.h"
#include "network/PacketBuffer.h"
#include "Log.h"
#include "Utils.h"
using namespace network;
using namespace compress;
#include <cassert>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the PacketBuffer class. */
PacketBuffer::PacketBuffer(bool compression, const char* name) :
fragments(),
m_compression(compression),
m_name(name)
{
/* stub */
}
/* Finalizes a instance of the PacketBuffer class. */
PacketBuffer::~PacketBuffer()
{
clear();
}
/* Decode a network packet fragment. */
bool PacketBuffer::decode(const uint8_t* data, uint8_t** message, uint32_t* outLength)
{
assert(data != nullptr);
*message = nullptr;
if (outLength != nullptr) {
*outLength = 0;
}
uint8_t curBlock = data[8U];
uint8_t blockCnt = data[9U];
Fragment* frag = new Fragment();
// if this is the first block store sizes and initialize temp buffer
if (curBlock == 0U) {
uint32_t size = GET_UINT32(data, 0U);
uint32_t compressedSize = GET_UINT32(data, 4U);
frag->size = size;
frag->compressedSize = compressedSize;
}
// scope is intentional
{
frag->blockId = curBlock;
if (frag->size < FRAG_BLOCK_SIZE)
frag->data = new uint8_t[FRAG_BLOCK_SIZE + 1U];
else
frag->data = new uint8_t[frag->size + 1U];
::memcpy(frag->data, data + FRAG_HDR_SIZE, FRAG_BLOCK_SIZE);
// Utils::dump(1U, "Block Payload", frag->data, FRAG_BLOCK_SIZE);
fragments.insert(curBlock, frag);
}
LogInfoEx(LOG_NET, "%s, Inbound Packet Fragment, block %u of %u, rxFragments = %u", m_name, curBlock, blockCnt, fragments.size());
// do we have all the blocks?
if (fragments.size() == blockCnt + 1U) {
uint8_t* buffer = nullptr;
fragments.lock(false);
if (fragments[0] == nullptr) {
LogError(LOG_NET, "%s, Packet Fragment, error missing block 0? Packet dropped.", m_name);
fragments.unlock();
clear();
return false;
}
if (fragments[0]->size == 0U) {
LogError(LOG_NET, "%s, Packet Fragment, error missing size information", m_name);
fragments.unlock();
clear();
return false;
}
if (fragments[0]->compressedSize == 0U) {
LogError(LOG_NET, "%s, Packet Fragment, error missing compressed size information", m_name);
fragments.unlock();
clear();
return false;
}
uint32_t compressedLen = fragments[0]->compressedSize;
uint32_t len = fragments[0]->size;
buffer = new uint8_t[len +1U];
::memset(buffer, 0x00U, len + 1U);
if (fragments.size() == 1U) {
::memcpy(buffer, fragments[0U]->data, len);
} else {
for (uint8_t i = 0U; i < fragments.size(); i++) {
uint32_t offs = i * FRAG_BLOCK_SIZE;
::memcpy(buffer + offs, fragments[i]->data, FRAG_BLOCK_SIZE);
}
}
if (m_compression) {
uint32_t decompressedLen = 0U;
*message = Compression::decompress(buffer, compressedLen, &decompressedLen);
// check that we got the appropriate data
if (decompressedLen == len && message != nullptr) {
if (outLength != nullptr) {
*outLength = len;
}
fragments.unlock();
clear();
return true;
}
}
else {
*message = buffer;
if (outLength != nullptr) {
*outLength = len;
}
fragments.unlock();
clear();
return true;
}
fragments.unlock();
}
return false;
}
/* Encode a network packet fragment. */
void PacketBuffer::encode(uint8_t* data, uint32_t length)
{
assert(data != nullptr);
assert(length > 0U);
// erase any buffered fragments
clear();
// create temporary buffer
uint32_t compressedLen = 0U;
uint8_t* buffer = nullptr;
if (m_compression) {
buffer = Compression::compress(data, length, &compressedLen);
} else {
buffer = new uint8_t[length];
::memset(buffer, 0x00U, length);
::memcpy(buffer, data, length);
compressedLen = length;
}
// create packet fragments
uint8_t blockCnt = (compressedLen / FRAG_BLOCK_SIZE) + (compressedLen % FRAG_BLOCK_SIZE ? 1U : 0U);
uint32_t offs = 0U;
for (uint8_t i = 0U; i < blockCnt; i++) {
// build dataset
uint16_t bufSize = FRAG_SIZE;
Fragment* frag = new Fragment();
frag->blockId = i;
frag->data = new uint8_t[bufSize];
::memset(frag->data, 0x00U, bufSize);
if (i == 0U) {
SET_UINT32(length, frag->data, 0U);
frag->size = length;
SET_UINT32(compressedLen, frag->data, 4U);
frag->compressedSize = compressedLen;
}
frag->data[8U] = i;
frag->data[9U] = blockCnt - 1U;
uint32_t blockSize = FRAG_BLOCK_SIZE;
if (offs + FRAG_BLOCK_SIZE > compressedLen)
blockSize = FRAG_BLOCK_SIZE - ((offs + FRAG_BLOCK_SIZE) - compressedLen);
::memcpy(frag->data + FRAG_HDR_SIZE, buffer + offs, blockSize);
offs += FRAG_BLOCK_SIZE;
fragments.insert(i, frag);
LogInfoEx(LOG_NET, "%s, Outbound Packet Fragment, block %u of %u, txFragments = %u", m_name, i, blockCnt - 1U, fragments.size());
}
delete[] buffer;
}
/* Helper to clear currently buffered fragments. */
void PacketBuffer::clear()
{
fragments.lock(false);
for (auto entry : fragments) {
Fragment* frag = entry.second;
if (frag != nullptr) {
if (frag->data != nullptr)
delete[] frag->data;
frag->data = nullptr;
delete frag;
}
}
fragments.unlock();
fragments.clear();
}

@ -0,0 +1,112 @@
// 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) 2025 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file PacketBuffer.h
* @ingroup network_core
* @file PacketBuffer.cpp
* @ingroup network_core
*/
#if !defined(__PACKET_BUFFER_H__)
#define __PACKET_BUFFER_H__
#include "common/Defines.h"
#include "common/concurrent/unordered_map.h"
#include "common/zlib/Compression.h"
#include <unordered_map>
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
#define FRAG_HDR_SIZE 10
#define FRAG_BLOCK_SIZE 534
#define FRAG_SIZE (FRAG_HDR_SIZE + FRAG_BLOCK_SIZE)
namespace network
{
// ---------------------------------------------------------------------------
// Class Declaration
// ---------------------------------------------------------------------------
/**
* @brief Represents a fragmented packet buffer.
* @ingroup network_core
*/
class HOST_SW_API PacketBuffer {
public:
/**
* @brief Initializes a new instance of the PacketBuffer class.
* @param compression Flag indicating whether packet data should be compressed automatically.
* @param name Name of buffer.
*/
explicit PacketBuffer(bool compression, const char* name);
/**
* @brief Finalizes a instance of the PacketBuffer class.
*/
~PacketBuffer();
/**
* @brief Decode a network packet fragment.
* @param[in] data Buffer containing packet fragment to decode.
* @param[out] message Buffer containing assembled message.
* @param[out] outLength Length of assembled message.
*/
bool decode(const uint8_t* data, uint8_t** message, uint32_t* outLength);
/**
* @brief Encode a network packet fragment.
* @param[out] data Message to encode.
* @param length Length of message.
*/
void encode(uint8_t* data, uint32_t length);
/**
* @brief Helper to clear currently buffered fragments.
*/
void clear();
public:
/**
* @brief Represents a packet buffer fragment.
*/
class Fragment {
public:
/**
* @brief Compressed size of the packet.
*/
uint32_t compressedSize;
/**
* @brief Uncompressed size of the packet.
*/
uint32_t size;
/**
* @brief Size of the packet fragment block.
*/
uint32_t blockSize;
/**
* @brief Block ID of the fragment.
*/
uint8_t blockId;
/**
* @brief Fragment data.
*/
uint8_t* data;
};
concurrent::unordered_map<uint8_t, Fragment*> fragments;
private:
bool m_compression;
const char* m_name;
};
} // namespace network
#endif // __PACKET_BUFFER_H__

@ -40,8 +40,8 @@ bool RPCHeader::decode(const uint8_t* data)
assert(data != nullptr);
m_crc16 = (data[0U] << 8) | (data[1U] << 0); // CRC-16
m_func = __GET_UINT16B(data, 2U); // Function
m_messageLength = __GET_UINT32(data, 4U); // Message Length
m_func = GET_UINT16(data, 2U); // Function
m_messageLength = GET_UINT32(data, 4U); // Message Length
return true;
}
@ -54,7 +54,7 @@ void RPCHeader::encode(uint8_t* data)
data[0U] = (m_crc16 >> 8) & 0xFFU; // CRC-16 MSB
data[1U] = (m_crc16 >> 0) & 0xFFU; // CRC-16 LSB
__SET_UINT16B(m_func, data, 2U); // Function
SET_UINT16(m_func, data, 2U); // Function
__SET_UINT32(m_messageLength, data, 4U); // Message Length
SET_UINT32(m_messageLength, data, 4U); // Message Length
}

@ -72,15 +72,15 @@ namespace network
/**
* @brief Payload packet CRC-16.
*/
__PROPERTY(uint16_t, crc16, CRC);
DECLARE_PROPERTY(uint16_t, crc16, CRC);
/**
* @brief Function.
*/
__PROPERTY(uint16_t, func, Function);
DECLARE_PROPERTY(uint16_t, func, Function);
/**
* @brief Message Length.
*/
__PROPERTY(uint32_t, messageLength, MessageLength);
DECLARE_PROPERTY(uint32_t, messageLength, MessageLength);
};
} // namespace frame
} // namespace network

@ -73,11 +73,11 @@ namespace network
/**
* @brief Format of the extension header payload contained within the packet.
*/
__PROTECTED_PROPERTY(uint16_t, payloadType, PayloadType);
DECLARE_PROTECTED_PROPERTY(uint16_t, payloadType, PayloadType);
/**
* @brief Length of the extension header payload (in 32-bit units).
*/
__PROTECTED_PROPERTY(uint16_t, payloadLength, PayloadLength);
DECLARE_PROTECTED_PROPERTY(uint16_t, payloadLength, PayloadLength);
};
} // namespace frame
} // namespace network

@ -55,9 +55,9 @@ bool RTPFNEHeader::decode(const uint8_t* data)
m_crc16 = (data[4U] << 8) | (data[5U] << 0); // CRC-16
m_func = (NET_FUNC::ENUM)data[6U]; // Function
m_subFunc = (NET_SUBFUNC::ENUM)data[7U]; // Sub-Function
m_streamId = __GET_UINT32(data, 8U); // Stream ID
m_peerId = __GET_UINT32(data, 12U); // Peer ID
m_messageLength = __GET_UINT32(data, 16U); // Message Length
m_streamId = GET_UINT32(data, 8U); // Stream ID
m_peerId = GET_UINT32(data, 12U); // Peer ID
m_messageLength = GET_UINT32(data, 16U); // Message Length
return true;
}
@ -77,7 +77,7 @@ void RTPFNEHeader::encode(uint8_t* data)
data[6U] = m_func; // Function
data[7U] = m_subFunc; // Sub-Function
__SET_UINT32(m_streamId, data, 8U); // Stream ID
__SET_UINT32(m_peerId, data, 12U); // Peer ID
__SET_UINT32(m_messageLength, data, 16U); // Message Length
SET_UINT32(m_streamId, data, 8U); // Stream ID
SET_UINT32(m_peerId, data, 12U); // Peer ID
SET_UINT32(m_messageLength, data, 16U); // Message Length
}

@ -27,8 +27,6 @@
// Constants
// ---------------------------------------------------------------------------
#define PEER_LINK_BLOCK_SIZE 534
#define RTP_FNE_HEADER_LENGTH_BYTES 16
#define RTP_FNE_HEADER_LENGTH_EXT_LEN 4
@ -48,7 +46,7 @@ namespace network
enum ENUM : uint8_t {
ILLEGAL = 0xFFU, //! Illegal Function
PROTOCOL = 0x00U, //! Network Protocol Function
PROTOCOL = 0x00U, //! Digital Protocol Function
MASTER = 0x01U, //! Network Master Function
@ -56,8 +54,8 @@ namespace network
RPTK = 0x61U, //! Repeater Authorisation
RPTC = 0x62U, //! Repeater Configuration
RPT_CLOSING = 0x70U, //! Repeater Closing
MST_CLOSING = 0x71U, //! Master Closing
RPT_DISC = 0x70U, //! Repeater Disconnect
MST_DISC = 0x71U, //! Master Disconnect
PING = 0x74U, //! Ping
PONG = 0x75U, //! Pong
@ -184,27 +182,27 @@ namespace network
/**
* @brief Traffic payload packet CRC-16.
*/
__PROPERTY(uint16_t, crc16, CRC);
DECLARE_PROPERTY(uint16_t, crc16, CRC);
/**
* @brief Function.
*/
__PROPERTY(NET_FUNC::ENUM, func, Function);
DECLARE_PROPERTY(NET_FUNC::ENUM, func, Function);
/**
* @brief Sub-function.
*/
__PROPERTY(NET_SUBFUNC::ENUM, subFunc, SubFunction);
DECLARE_PROPERTY(NET_SUBFUNC::ENUM, subFunc, SubFunction);
/**
* @brief Traffic Stream ID.
*/
__PROPERTY(uint32_t, streamId, StreamId);
DECLARE_PROPERTY(uint32_t, streamId, StreamId);
/**
* @brief Traffic Peer ID.
*/
__PROPERTY(uint32_t, peerId, PeerId);
DECLARE_PROPERTY(uint32_t, peerId, PeerId);
/**
* @brief Traffic Message Length.
*/
__PROPERTY(uint32_t, messageLength, MessageLength);
DECLARE_PROPERTY(uint32_t, messageLength, MessageLength);
};
} // namespace frame
} // namespace network

@ -66,8 +66,8 @@ bool RTPHeader::decode(const uint8_t* data)
m_payloadType = (data[1U] & 0x7FU); // Payload Type
m_seq = (data[2U] << 8) | (data[3U] << 0); // Sequence
m_timestamp = __GET_UINT32(data, 4U); // Timestamp
m_ssrc = __GET_UINT32(data, 8U); // Synchronization Source ID
m_timestamp = GET_UINT32(data, 4U); // Timestamp
m_ssrc = GET_UINT32(data, 8U); // Synchronization Source ID
return true;
}
@ -93,8 +93,8 @@ void RTPHeader::encode(uint8_t* data)
m_timestamp = uint32_t(microSeconds / 1000000);
}
__SET_UINT32(m_timestamp, data, 4U); // Timestamp
__SET_UINT32(m_ssrc, data, 8U); // Synchronization Source Identifier
SET_UINT32(m_timestamp, data, 4U); // Timestamp
SET_UINT32(m_ssrc, data, 8U); // Synchronization Source Identifier
}
/* Helper to reset the start timestamp. */

@ -85,39 +85,39 @@ namespace network
/**
* @brief RTP Protocol Version.
*/
__READONLY_PROPERTY(uint8_t, version, Version);
DECLARE_RO_PROPERTY(uint8_t, version, Version);
/**
* @brief Flag indicating if the packet has trailing padding.
*/
__READONLY_PROPERTY(bool, padding, Padding);
DECLARE_RO_PROPERTY(bool, padding, Padding);
/**
* @brief Flag indicating the presence of an extension header.
*/
__PROPERTY(bool, extension, Extension);
DECLARE_PROPERTY(bool, extension, Extension);
/**
* @brief Count of contributing source IDs that follow the SSRC.
*/
__READONLY_PROPERTY(uint8_t, cc, CSRCCount);
DECLARE_RO_PROPERTY(uint8_t, cc, CSRCCount);
/**
* @brief Flag indicating application-specific behavior.
*/
__PROPERTY(bool, marker, Marker);
DECLARE_PROPERTY(bool, marker, Marker);
/**
* @brief Format of the payload contained within the packet.
*/
__PROPERTY(uint8_t, payloadType, PayloadType);
DECLARE_PROPERTY(uint8_t, payloadType, PayloadType);
/**
* @brief Sequence number for the RTP packet.
*/
__PROPERTY(uint16_t, seq, Sequence);
DECLARE_PROPERTY(uint16_t, seq, Sequence);
/**
* @brief RTP packet timestamp.
*/
__PROPERTY(uint32_t, timestamp, Timestamp);
DECLARE_PROPERTY(uint32_t, timestamp, Timestamp);
/**
* @brief Synchronization Source ID.
*/
__PROPERTY(uint32_t, ssrc, SSRC);
DECLARE_PROPERTY(uint32_t, ssrc, SSRC);
private:
static std::chrono::time_point<std::chrono::high_resolution_clock> m_wcStart;

@ -106,6 +106,12 @@ bool RawFrameQueue::write(const uint8_t* message, uint32_t length, sockaddr_stor
if (m_debug)
Utils::dump(1U, "RawFrameQueue::write() Message", buffer, length);
// bryanb: this is really a developer warning not a end-user warning, there's nothing the end-users can do about
// this message
if (length > (DATA_PACKET_LENGTH - OVERSIZED_PACKET_WARN)) {
LogDebug(LOG_NET, "RawFrameQueue::write(), WARN: packet length is possibly oversized, possible data truncation - BUGBUG");
}
bool ret = true;
if (!m_socket->write(buffer, length, addr, addrLen, lenWritten)) {
// LogError(LOG_NET, "Failed writing data to the network");
@ -136,6 +142,12 @@ void RawFrameQueue::enqueueMessage(const uint8_t* message, uint32_t length, sock
Thread::sleep(2U);
}
// bryanb: this is really a developer warning not a end-user warning, there's nothing the end-users can do about
// this message
if (length > (DATA_PACKET_LENGTH - OVERSIZED_PACKET_WARN)) {
LogDebug(LOG_NET, "RawFrameQueue::enqueueMessage(), WARN: packet length is possibly oversized, possible data truncation - BUGBUG");
}
uint8_t* buffer = new uint8_t[length];
::memset(buffer, 0x00U, length);
::memcpy(buffer, message, length);

@ -29,6 +29,7 @@ namespace network
// ---------------------------------------------------------------------------
const uint32_t DATA_PACKET_LENGTH = 8192U;
const uint32_t OVERSIZED_PACKET_WARN = 1536U;
const uint8_t MAX_FAILED_READ_CNT_LOGGING = 5U;
// ---------------------------------------------------------------------------

@ -239,7 +239,7 @@ ssize_t Socket::read(uint8_t* buffer, uint32_t length, sockaddr_storage& address
}
// does the network packet contain the appropriate magic leader?
uint16_t magic = __GET_UINT16B(buffer, 0U);
uint16_t magic = GET_UINT16(buffer, 0U);
if (magic == AES_WRAPPED_PCKT_MAGIC) {
uint32_t cryptedLen = (len - 2U) * sizeof(uint8_t);
uint8_t* cryptoBuffer = buffer + 2U;
@ -347,7 +347,7 @@ bool Socket::write(const uint8_t* buffer, uint32_t length, const sockaddr_storag
delete[] cryptoBuffer;
if (crypted != nullptr) {
::memcpy(out.get() + 2U, crypted, cryptedLen);
__SET_UINT16B(AES_WRAPPED_PCKT_MAGIC, out.get(), 0U);
SET_UINT16(AES_WRAPPED_PCKT_MAGIC, out.get(), 0U);
delete[] crypted;
length = cryptedLen + 2U;
} else {
@ -494,10 +494,9 @@ bool Socket::write(BufferVector& buffers, ssize_t* lenWritten) noexcept
// Utils::dump(1U, "Socket::write() crypted", crypted, cryptedLen);
// finalize
UInt8Array __outBuf = std::make_unique<uint8_t[]>(cryptedLen + 2U);
uint8_t* out = __outBuf.get();
DECLARE_UINT8_ARRAY(out, cryptedLen + 2U);
::memcpy(out + 2U, crypted, cryptedLen);
__SET_UINT16B(AES_WRAPPED_PCKT_MAGIC, out, 0U);
SET_UINT16(AES_WRAPPED_PCKT_MAGIC, out, 0U);
// cleanup buffers and replace with new
delete[] crypted;

@ -217,7 +217,7 @@ namespace network
/**
* @brief Virtual Interface associated name.
*/
__PROPERTY(std::string, name, Name);
DECLARE_PROPERTY(std::string, name, Name);
private:
struct viface_queues m_queues;

@ -173,39 +173,39 @@ namespace nxdn
/**
* @brief NXDN location ID.
*/
__READONLY_PROPERTY_PLAIN(uint32_t, locId);
DECLARE_RO_PROPERTY_PLAIN(uint32_t, locId);
/**
* @brief Channel ID.
*/
__READONLY_PROPERTY_PLAIN(uint8_t, channelId);
DECLARE_RO_PROPERTY_PLAIN(uint8_t, channelId);
/**
* @brief Channel number.
*/
__READONLY_PROPERTY_PLAIN(uint32_t, channelNo);
DECLARE_RO_PROPERTY_PLAIN(uint32_t, channelNo);
/**
* @brief Site Information 1.
*/
__READONLY_PROPERTY_PLAIN(uint8_t, siteInfo1);
DECLARE_RO_PROPERTY_PLAIN(uint8_t, siteInfo1);
/**
* @brief Site Information 2.
*/
__READONLY_PROPERTY_PLAIN(uint8_t, siteInfo2);
DECLARE_RO_PROPERTY_PLAIN(uint8_t, siteInfo2);
/**
* @brief Flag indicating whether this site data is for an adjacent site.
*/
__READONLY_PROPERTY_PLAIN(bool, isAdjSite);
DECLARE_RO_PROPERTY_PLAIN(bool, isAdjSite);
/**
* @brief Callsign.
*/
__READONLY_PROPERTY_PLAIN(std::string, callsign);
DECLARE_RO_PROPERTY_PLAIN(std::string, callsign);
/**
* @brief NXDN require registration.
*/
__READONLY_PROPERTY_PLAIN(bool, requireReg);
DECLARE_RO_PROPERTY_PLAIN(bool, requireReg);
/**
* @brief Flag indicating whether this site is a linked active network member.
*/
__READONLY_PROPERTY_PLAIN(bool, netActive);
DECLARE_RO_PROPERTY_PLAIN(bool, netActive);
/** @} */
};
} // namespace nxdn

@ -82,29 +82,29 @@ namespace nxdn
/**
* @brief Radio Access Number
*/
__PROPERTY(uint8_t, ran, RAN);
DECLARE_PROPERTY(uint8_t, ran, RAN);
/**
* @brief Channel Structure
*/
__PROPERTY(defines::ChStructure::E, structure, Structure);
DECLARE_PROPERTY(defines::ChStructure::E, structure, Structure);
/**
* @brief Flag indicating whether the inbound CAC is long or short.
*/
__PROPERTY(bool, longInbound, LongInbound);
DECLARE_PROPERTY(bool, longInbound, LongInbound);
// Collision Control Field
/**
* @brief Idle/Busy.
*/
__PROPERTY(bool, idleBusy, IdleBusy);
DECLARE_PROPERTY(bool, idleBusy, IdleBusy);
/**
* @brief Tx Continuously.
*/
__PROPERTY(bool, txContinuous, TxContinuous);
DECLARE_PROPERTY(bool, txContinuous, TxContinuous);
/**
* @brief Receive/No Receive.
*/
__PROPERTY(bool, receive, Receive);
DECLARE_PROPERTY(bool, receive, Receive);
private:
uint8_t* m_data;

@ -75,19 +75,19 @@ namespace nxdn
/**
* @brief RF Channel Type
*/
__PROPERTY(defines::RFChannelType::E, rfct, RFCT);
DECLARE_PROPERTY(defines::RFChannelType::E, rfct, RFCT);
/**
* @brief Functional Channel Type
*/
__PROPERTY(defines::FuncChannelType::E, fct, FCT);
DECLARE_PROPERTY(defines::FuncChannelType::E, fct, FCT);
/**
* @brief Channel Options
*/
__PROPERTY(defines::ChOption::E, option, Option);
DECLARE_PROPERTY(defines::ChOption::E, option, Option);
/**
* @brief Flag indicating outbound traffic direction
*/
__PROPERTY(bool, outbound, Outbound);
DECLARE_PROPERTY(bool, outbound, Outbound);
private:
uint8_t m_lich;

@ -82,11 +82,11 @@ namespace nxdn
/**
* @brief Radio Access Number
*/
__PROPERTY(uint8_t, ran, RAN);
DECLARE_PROPERTY(uint8_t, ran, RAN);
/**
* @brief Channel Structure
*/
__PROPERTY(defines::ChStructure::E, structure, Structure);
DECLARE_PROPERTY(defines::ChStructure::E, structure, Structure);
private:
uint8_t* m_data;

@ -80,7 +80,7 @@ namespace nxdn
/**
* @brief Radio Access Number
*/
__PROPERTY(uint8_t, ran, RAN);
DECLARE_PROPERTY(uint8_t, ran, RAN);
private:
uint8_t* m_data;

@ -65,45 +65,45 @@ namespace nxdn
/**
* @brief Flag indicating if confirmed delivery is needed.
*/
__PROPERTY(bool, delivery, Delivery);
DECLARE_PROPERTY(bool, delivery, Delivery);
/**
* @brief Flag indicating if the packet is a selective retry packet.
*/
__PROPERTY(bool, selectiveRetry, SelectiveRetry);
DECLARE_PROPERTY(bool, selectiveRetry, SelectiveRetry);
/**
* @brief Count of data blocks in t he transmission packet.
*/
__PROPERTY(uint8_t, blockCount, BlockCount);
DECLARE_PROPERTY(uint8_t, blockCount, BlockCount);
/**
* @brief Number of padding octets of the last block.
*/
__PROPERTY(uint8_t, padCount, PadCount);
DECLARE_PROPERTY(uint8_t, padCount, PadCount);
/**
* @brief Flag indicating the first fragment.
*/
__PROPERTY(bool, start, Start);
DECLARE_PROPERTY(bool, start, Start);
/**
* @brief Flag indicating if the Tx fragment count circulates.
*/
__PROPERTY(bool, circular, Circular);
DECLARE_PROPERTY(bool, circular, Circular);
/**
* @brief The number and sequence of fragments.
*/
__PROPERTY(uint16_t, fragmentCount, FragmentCount);
DECLARE_PROPERTY(uint16_t, fragmentCount, FragmentCount);
// Response Data
/**
* @brief Response class.
*/
__PROPERTY(uint8_t, rspClass, ResponseClass);
DECLARE_PROPERTY(uint8_t, rspClass, ResponseClass);
/**
* @brief Response type.
*/
__PROPERTY(uint8_t, rspType, ResponseType);
DECLARE_PROPERTY(uint8_t, rspType, ResponseType);
/**
* @brief Error Block Flag.
*/
__PROPERTY(uint16_t, rspErrorBlock, ResponseErrorBlock);
DECLARE_PROPERTY(uint16_t, rspErrorBlock, ResponseErrorBlock);
};
} // namespace lc
} // namespace nxdn

@ -104,82 +104,82 @@ namespace nxdn
/**
* @brief Message Type
*/
__PROTECTED_PROPERTY(uint8_t, messageType, MessageType);
DECLARE_PROTECTED_PROPERTY(uint8_t, messageType, MessageType);
/**
* @brief Source ID.
*/
__PROTECTED_PROPERTY(uint16_t, srcId, SrcId);
DECLARE_PROTECTED_PROPERTY(uint16_t, srcId, SrcId);
/**
* @brief Destination ID.
*/
__PROTECTED_PROPERTY(uint16_t, dstId, DstId);
DECLARE_PROTECTED_PROPERTY(uint16_t, dstId, DstId);
/**
* @brief Location ID.
*/
__PROTECTED_PROPERTY(uint32_t, locId, LocId);
DECLARE_PROTECTED_PROPERTY(uint32_t, locId, LocId);
/**
* @brief Registration Option.
*/
__PROTECTED_PROPERTY(uint8_t, regOption, RegOption);
DECLARE_PROTECTED_PROPERTY(uint8_t, regOption, RegOption);
/**
* @brief Version Number.
*/
__PROTECTED_PROPERTY(uint8_t, version, Version);
DECLARE_PROTECTED_PROPERTY(uint8_t, version, Version);
/**
* @brief Cause Response.
*/
__PROTECTED_PROPERTY(uint8_t, causeRsp, CauseResponse);
DECLARE_PROTECTED_PROPERTY(uint8_t, causeRsp, CauseResponse);
/**
* @brief Voice channel number.
*/
__PROTECTED_PROPERTY(uint32_t, grpVchNo, GrpVchNo);
DECLARE_PROTECTED_PROPERTY(uint32_t, grpVchNo, GrpVchNo);
/** @} */
/** @name Call Data */
/**
* @brief Call Type
*/
__PROTECTED_PROPERTY(uint8_t, callType, CallType);
DECLARE_PROTECTED_PROPERTY(uint8_t, callType, CallType);
/** @} */
/** @name Common Call Options */
/**
* @brief Flag indicating the emergency bits are set.
*/
__PROTECTED_PROPERTY(bool, emergency, Emergency);
DECLARE_PROTECTED_PROPERTY(bool, emergency, Emergency);
/**
* @brief Flag indicating that encryption is enabled.
*/
__PROTECTED_PROPERTY(bool, encrypted, Encrypted);
DECLARE_PROTECTED_PROPERTY(bool, encrypted, Encrypted);
/**
* @brief Flag indicating priority paging.
*/
__PROTECTED_PROPERTY(bool, priority, Priority);
DECLARE_PROTECTED_PROPERTY(bool, priority, Priority);
/**
* @brief Flag indicating a group/talkgroup operation.
*/
__PROTECTED_PROPERTY(bool, group, Group);
DECLARE_PROTECTED_PROPERTY(bool, group, Group);
/**
* @brief Flag indicating a half/full duplex operation.
*/
__PROTECTED_PROPERTY(bool, duplex, Duplex);
DECLARE_PROTECTED_PROPERTY(bool, duplex, Duplex);
/**
* @brief Transmission mode.
*/
__PROTECTED_PROPERTY(uint8_t, transmissionMode, TransmissionMode);
DECLARE_PROTECTED_PROPERTY(uint8_t, transmissionMode, TransmissionMode);
/** @} */
/** @name Local Site data */
/**
* @brief Local Site Identity Entry.
*/
__PROTECTED_PROPERTY_PLAIN(lookups::IdenTable, siteIdenEntry);
DECLARE_PROTECTED_PROPERTY_PLAIN(lookups::IdenTable, siteIdenEntry);
/** @} */
protected:
@ -206,7 +206,7 @@ namespace nxdn
*/
void encode(uint8_t* data, const uint8_t* rcch, uint32_t length, uint32_t offset = 0U);
__PROTECTED_COPY(RCCH);
DECLARE_PROTECTED_COPY(RCCH);
};
} // namespace lc
} // namespace nxdn

@ -89,92 +89,92 @@ namespace nxdn
/**
* @brief Message Type
*/
__PROPERTY(uint8_t, messageType, MessageType);
DECLARE_PROPERTY(uint8_t, messageType, MessageType);
/**
* @brief Call Type
*/
__PROPERTY(uint8_t, callType, CallType);
DECLARE_PROPERTY(uint8_t, callType, CallType);
/**
* @brief Source ID.
*/
__PROPERTY(uint16_t, srcId, SrcId);
DECLARE_PROPERTY(uint16_t, srcId, SrcId);
/**
* @brief Destination ID.
*/
__PROPERTY(uint16_t, dstId, DstId);
DECLARE_PROPERTY(uint16_t, dstId, DstId);
/** @} */
/** @name Common Call Options */
/**
* @brief Flag indicating the emergency bits are set.
*/
__PROPERTY(bool, emergency, Emergency);
DECLARE_PROPERTY(bool, emergency, Emergency);
/**
* @brief Flag indicating that encryption is enabled.
*/
__PROPERTY(bool, encrypted, Encrypted);
DECLARE_PROPERTY(bool, encrypted, Encrypted);
/**
* @brief Flag indicating priority paging.
*/
__PROPERTY(bool, priority, Priority);
DECLARE_PROPERTY(bool, priority, Priority);
/**
* @brief Flag indicating a group/talkgroup operation.
*/
__PROPERTY(bool, group, Group);
DECLARE_PROPERTY(bool, group, Group);
/**
* @brief Flag indicating a half/full duplex operation.
*/
__PROPERTY(bool, duplex, Duplex);
DECLARE_PROPERTY(bool, duplex, Duplex);
/**
* @brief Transmission mode.
*/
__PROPERTY(uint8_t, transmissionMode, TransmissionMode);
DECLARE_PROPERTY(uint8_t, transmissionMode, TransmissionMode);
/** @} */
/** @name Data Call Data */
/**
* @brief Data packet information.
*/
__PROPERTY(PacketInformation, packetInfo, PacketInfo);
DECLARE_PROPERTY(PacketInformation, packetInfo, PacketInfo);
/**
* @brief Data packet information.
*/
__PROPERTY(PacketInformation, rsp, Response);
DECLARE_PROPERTY(PacketInformation, rsp, Response);
/**
* @brief Data packet frame number.
*/
__PROPERTY(uint8_t, dataFrameNumber, DataFrameNumber);
DECLARE_PROPERTY(uint8_t, dataFrameNumber, DataFrameNumber);
/**
* @brief Data packet block number.
*/
__PROPERTY(uint8_t, dataBlockNumber, DataBlockNumber);
DECLARE_PROPERTY(uint8_t, dataBlockNumber, DataBlockNumber);
/** @} */
/** @name Header Delay Data */
/**
* @brief Delay count.
*/
__PROPERTY(uint16_t, delayCount, DelayCount);
DECLARE_PROPERTY(uint16_t, delayCount, DelayCount);
/** @} */
/** @name Encryption data */
/**
* @brief Encryption algorithm ID.
*/
__PROPERTY(uint8_t, algId, AlgId);
DECLARE_PROPERTY(uint8_t, algId, AlgId);
/**
* @brief Encryption key ID.
*/
__PROPERTY(uint8_t, kId, KId);
DECLARE_PROPERTY(uint8_t, kId, KId);
/** @} */
/**
* @brief Cause Response.
*/
__PROPERTY(uint8_t, causeRsp, CauseResponse);
DECLARE_PROPERTY(uint8_t, causeRsp, CauseResponse);
private:
static bool m_verbose;

@ -57,7 +57,7 @@ void MESSAGE_TYPE_REG::encode(uint8_t* data, uint32_t length, uint32_t offset)
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
rcch[1U] = (m_regOption << 3) + // Registration Option
(m_siteData.locId() >> 22U) & 0x03U; // Location ID
((m_siteData.locId() >> 22U) & 0x03U); // Location ID
uint16_t systemCode = (m_siteData.locId() >> 12U) << 7U;
rcch[2U] = (systemCode >> 8U) & 0x03U; // ...

@ -66,25 +66,25 @@ namespace nxdn
/**
* @brief Count of BCCH frames per RCCH superframe.
*/
__PROPERTY(uint8_t, bcchCnt, BcchCnt);
DECLARE_PROPERTY(uint8_t, bcchCnt, BcchCnt);
/**
* @brief Count of RCCH frame groupings per RCCH superframe.
*/
__PROPERTY(uint8_t, rcchGroupingCnt, RcchGroupingCnt);
DECLARE_PROPERTY(uint8_t, rcchGroupingCnt, RcchGroupingCnt);
/**
* @brief Count of CCCH/UPCH paging frames per RCCH superframe.
*/
__PROPERTY(uint8_t, ccchPagingCnt, CcchPagingCnt);
DECLARE_PROPERTY(uint8_t, ccchPagingCnt, CcchPagingCnt);
/**
* @brief Count of CCCH/UPCH multi-purpose frames per RCCH superframe.
*/
__PROPERTY(uint8_t, ccchMultiCnt, CcchMultiCnt);
DECLARE_PROPERTY(uint8_t, ccchMultiCnt, CcchMultiCnt);
/**
* @brief Count of group iterations per RCCH superframe.
*/
__PROPERTY(uint8_t, rcchIterateCnt, RcchIterateCount);
DECLARE_PROPERTY(uint8_t, rcchIterateCnt, RcchIterateCount);
__COPY(MESSAGE_TYPE_SITE_INFO);
DECLARE_COPY(MESSAGE_TYPE_SITE_INFO);
};
} // namespace rcch
} // namespace lc

@ -1,4 +1,4 @@
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Common Library
* MIT Open Source. Use is subject to license terms.
@ -126,16 +126,16 @@ namespace p25
/**
* @brief Traffic Encryption Key Algorithm ID.
*/
__PROPERTY(uint8_t, tekAlgoId, TEKAlgoId);
DECLARE_PROPERTY(uint8_t, tekAlgoId, TEKAlgoId);
/**
* @brief Traffic Encryption Key ID.
*/
__PROPERTY(uint16_t, tekKeyId, TEKKeyId);
DECLARE_PROPERTY(uint16_t, tekKeyId, TEKKeyId);
/**
* @brief Traffic Encryption Key Length.
*/
__READONLY_PROPERTY(uint8_t, tekLength, TEKLength);
DECLARE_RO_PROPERTY(uint8_t, tekLength, TEKLength);
private:
uint8_t* m_keystream;

@ -65,7 +65,7 @@ namespace p25
/**
* @brief Data unit ID.
*/
__READONLY_PROPERTY(defines::DUID::E, duid, DUID);
DECLARE_RO_PROPERTY(defines::DUID::E, duid, DUID);
private:
uint32_t m_nac;

@ -260,55 +260,55 @@ namespace p25
/**
* @brief P25 location resource area.
*/
__READONLY_PROPERTY_PLAIN(uint8_t, lra);
DECLARE_RO_PROPERTY_PLAIN(uint8_t, lra);
/**
* @brief P25 network ID.
*/
__READONLY_PROPERTY_PLAIN(uint32_t, netId);
DECLARE_RO_PROPERTY_PLAIN(uint32_t, netId);
/**
* @brief Gets the P25 system ID.
*/
__READONLY_PROPERTY_PLAIN(uint32_t, sysId);
DECLARE_RO_PROPERTY_PLAIN(uint32_t, sysId);
/**
* @brief P25 RFSS ID.
*/
__READONLY_PROPERTY_PLAIN(uint8_t, rfssId);
DECLARE_RO_PROPERTY_PLAIN(uint8_t, rfssId);
/**
* @brief P25 site ID.
*/
__READONLY_PROPERTY_PLAIN(uint8_t, siteId);
DECLARE_RO_PROPERTY_PLAIN(uint8_t, siteId);
/**
* @brief Channel ID.
*/
__READONLY_PROPERTY_PLAIN(uint8_t, channelId);
DECLARE_RO_PROPERTY_PLAIN(uint8_t, channelId);
/**
* @brief Channel number.
*/
__READONLY_PROPERTY_PLAIN(uint32_t, channelNo);
DECLARE_RO_PROPERTY_PLAIN(uint32_t, channelNo);
/**
* @brief Service class.
*/
__READONLY_PROPERTY_PLAIN(uint8_t, serviceClass);
DECLARE_RO_PROPERTY_PLAIN(uint8_t, serviceClass);
/**
* @brief Flag indicating whether this site data is for an adjacent site.
*/
__READONLY_PROPERTY_PLAIN(bool, isAdjSite);
DECLARE_RO_PROPERTY_PLAIN(bool, isAdjSite);
/**
* @brief Callsign.
*/
__READONLY_PROPERTY_PLAIN(std::string, callsign);
DECLARE_RO_PROPERTY_PLAIN(std::string, callsign);
/**
* @brief Count of available channels.
*/
__READONLY_PROPERTY_PLAIN(uint8_t, chCnt);
DECLARE_RO_PROPERTY_PLAIN(uint8_t, chCnt);
/**
* @brief Flag indicating whether this site is a linked active network member.
*/
__READONLY_PROPERTY_PLAIN(bool, netActive);
DECLARE_RO_PROPERTY_PLAIN(bool, netActive);
/**
* @brief Local Time Offset.
*/
__READONLY_PROPERTY_PLAIN(int8_t, lto);
DECLARE_RO_PROPERTY_PLAIN(int8_t, lto);
/** @} */
};
} // namespace p25

@ -90,12 +90,12 @@ namespace p25
/**
* @brief Sets the data block serial number.
*/
__PROPERTY(uint8_t, serialNo, SerialNo);
DECLARE_PROPERTY(uint8_t, serialNo, SerialNo);
/**
* @brief Flag indicating this is the last block in a sequence of block.
*/
__PROPERTY(bool, lastBlock, LastBlock);
DECLARE_PROPERTY(bool, lastBlock, LastBlock);
private:
edac::Trellis m_trellis;

@ -129,97 +129,97 @@ namespace p25
/**
* @brief Flag indicating if acknowledgement is needed.
*/
__PROPERTY(bool, ackNeeded, AckNeeded);
DECLARE_PROPERTY(bool, ackNeeded, AckNeeded);
/**
* @brief Flag indicating if this is an outbound data packet.
*/
__PROPERTY(bool, outbound, Outbound);
DECLARE_PROPERTY(bool, outbound, Outbound);
/**
* @brief Data packet format.
*/
__PROPERTY(uint8_t, fmt, Format);
DECLARE_PROPERTY(uint8_t, fmt, Format);
/**
* @brief Service access point.
*/
__PROPERTY(uint8_t, sap, SAP);
DECLARE_PROPERTY(uint8_t, sap, SAP);
/**
* @brief Manufacturer ID.
*/
__PROPERTY(uint8_t, mfId, MFId);
DECLARE_PROPERTY(uint8_t, mfId, MFId);
/**
* @brief Logical link ID.
*/
__PROPERTY(uint32_t, llId, LLId);
DECLARE_PROPERTY(uint32_t, llId, LLId);
/**
* @brief Total number of blocks following this header.
*/
__PROPERTY(uint8_t, blocksToFollow, BlocksToFollow);
DECLARE_PROPERTY(uint8_t, blocksToFollow, BlocksToFollow);
/**
* @brief Total number of padding bytes.
*/
__PROPERTY(uint8_t, padLength, PadLength);
DECLARE_PROPERTY(uint8_t, padLength, PadLength);
/**
* @brief Flag indicating whether or not this data packet is a full message.
*/
__PROPERTY(bool, F, FullMessage);
DECLARE_PROPERTY(bool, F, FullMessage);
/**
* @brief Synchronize Flag.
*/
__PROPERTY(bool, S, Synchronize);
DECLARE_PROPERTY(bool, S, Synchronize);
/**
* @brief Fragment Sequence Number.
*/
__PROPERTY(uint8_t, fsn, FSN);
DECLARE_PROPERTY(uint8_t, fsn, FSN);
/**
* @brief Send Sequence Number.
*/
__PROPERTY(uint8_t, Ns, Ns);
DECLARE_PROPERTY(uint8_t, Ns, Ns);
/**
* @brief Flag indicating whether or not this is the last fragment in a message.
*/
__PROPERTY(bool, lastFragment, LastFragment);
DECLARE_PROPERTY(bool, lastFragment, LastFragment);
/**
* @brief Offset of the header.
*/
__PROPERTY(uint8_t, headerOffset, HeaderOffset);
DECLARE_PROPERTY(uint8_t, headerOffset, HeaderOffset);
// Extended Addressing Data
/**
* @brief Service access point.
*/
__PROPERTY(uint8_t, exSap, EXSAP);
DECLARE_PROPERTY(uint8_t, exSap, EXSAP);
/**
* @brief Source Logical link ID.
*/
__PROPERTY(uint32_t, srcLlId, SrcLLId);
DECLARE_PROPERTY(uint32_t, srcLlId, SrcLLId);
// Response Data
/**
* @brief Response class.
*/
__PROPERTY(uint8_t, rspClass, ResponseClass);
DECLARE_PROPERTY(uint8_t, rspClass, ResponseClass);
/**
* @brief Response type.
*/
__PROPERTY(uint8_t, rspType, ResponseType);
DECLARE_PROPERTY(uint8_t, rspType, ResponseType);
/**
* @brief Response status.
*/
__PROPERTY(uint8_t, rspStatus, ResponseStatus);
DECLARE_PROPERTY(uint8_t, rspStatus, ResponseStatus);
// AMBT Data
/**
* @brief Alternate Trunking Block Opcode
*/
__PROPERTY(uint8_t, ambtOpcode, AMBTOpcode);
DECLARE_PROPERTY(uint8_t, ambtOpcode, AMBTOpcode);
/**
* @brief Alternate Trunking Block Field 8
*/
__PROPERTY(uint8_t, ambtField8, AMBTField8);
DECLARE_PROPERTY(uint8_t, ambtField8, AMBTField8);
/**
* @brief Alternate Trunking Block Field 9
*/
__PROPERTY(uint8_t, ambtField9, AMBTField9);
DECLARE_PROPERTY(uint8_t, ambtField9, AMBTField9);
private:
edac::Trellis m_trellis;

@ -11,6 +11,7 @@
#include "Defines.h"
#include "p25/data/LowSpeedData.h"
#include "p25/P25Utils.h"
#include "Utils.h"
using namespace p25;
using namespace p25::data;
@ -105,6 +106,8 @@ void LowSpeedData::process(uint8_t* data)
}
}
// Utils::dump(1U, "P25 Low Speed Data", lsd, 4U);
m_lsd1 = lsd[0U];
m_lsd2 = lsd[2U];

@ -63,11 +63,11 @@ namespace p25
/**
* @brief Low speed data 1 value.
*/
__PROPERTY(uint8_t, lsd1, LSD1);
DECLARE_PROPERTY(uint8_t, lsd1, LSD1);
/**
* @brief Low speed data 2 value.
*/
__PROPERTY(uint8_t, lsd2, LSD2);
DECLARE_PROPERTY(uint8_t, lsd2, LSD2);
private:
/**

@ -326,8 +326,7 @@ void LC::encodeLDU1(uint8_t* data, const uint8_t* imbe)
// encode RS (24,12,13) FEC
m_rs.encode241213(rs);
UInt8Array __dfsiFrame = std::make_unique<uint8_t[]>(frameLength);
uint8_t* dfsiFrame = __dfsiFrame.get();
DECLARE_UINT8_ARRAY(dfsiFrame, frameLength);
dfsiFrame[0U] = m_frameType; // Frame Type
@ -567,8 +566,7 @@ void LC::encodeLDU2(uint8_t* data, const uint8_t* imbe)
// encode RS (24,16,9) FEC
m_rs.encode24169(rs);
UInt8Array __dfsiFrame = std::make_unique<uint8_t[]>(frameLength);
uint8_t* dfsiFrame = __dfsiFrame.get();
DECLARE_UINT8_ARRAY(dfsiFrame, frameLength);
dfsiFrame[0U] = m_frameType; // Frame Type

@ -103,21 +103,21 @@ namespace p25
/**
* @brief Frame Type.
*/
__PROPERTY(defines::DFSIFrameType::E, frameType, FrameType);
DECLARE_PROPERTY(defines::DFSIFrameType::E, frameType, FrameType);
/**
* @brief RSSI.
*/
__PROPERTY(uint8_t, rssi, RSSI);
DECLARE_PROPERTY(uint8_t, rssi, RSSI);
/**
* @brief Link control data.
*/
__READONLY_PROPERTY_PLAIN(p25::lc::LC*, control);
DECLARE_RO_PROPERTY_PLAIN(p25::lc::LC*, control);
/**
* @brief Low speed data.
*/
__READONLY_PROPERTY_PLAIN(p25::data::LowSpeedData*, lsd);
DECLARE_RO_PROPERTY_PLAIN(p25::data::LowSpeedData*, lsd);
private:
edac::RS634717 m_rs;

@ -85,19 +85,19 @@ namespace p25
* @brief Payload type.
* This simple boolean marks this header as either IANA standard, or profile specific.
*/
__PROPERTY(bool, payloadType, PayloadType);
DECLARE_PROPERTY(bool, payloadType, PayloadType);
/**
* @brief Block type.
*/
__PROPERTY(BlockType::E, blockType, BlockType);
DECLARE_PROPERTY(BlockType::E, blockType, BlockType);
/**
* @brief Timestamp Offset.
*/
__PROPERTY(uint16_t, timestampOffset, TimestampOffset);
DECLARE_PROPERTY(uint16_t, timestampOffset, TimestampOffset);
/**
* @brief Block length.
*/
__PROPERTY(uint16_t, blockLength, BlockLength);
DECLARE_PROPERTY(uint16_t, blockLength, BlockLength);
};
} // namespace frames
} // namespace dfsi

@ -72,15 +72,15 @@ namespace p25
/**
* @brief
*/
__PROPERTY(bool, signal, Signal);
DECLARE_PROPERTY(bool, signal, Signal);
/**
* @brief Indicates a compact (1) or verbose (0) block header.
*/
__PROPERTY(bool, compact, Compact);
DECLARE_PROPERTY(bool, compact, Compact);
/**
* @brief Number of block headers following this control octet.
*/
__PROPERTY(uint8_t, blockHeaderCnt, BlockHeaderCnt);
DECLARE_PROPERTY(uint8_t, blockHeaderCnt, BlockHeaderCnt);
};
} // namespace frames
} // namespace dfsi

@ -231,27 +231,27 @@ namespace p25
/**
* @brief Frame Type.
*/
__PROPERTY(defines::DFSIFrameType::E, frameType, FrameType);
DECLARE_PROPERTY(defines::DFSIFrameType::E, frameType, FrameType);
/**
* @brief Total errors detected in the frame.
*/
__PROPERTY(uint8_t, totalErrors, TotalErrors);
DECLARE_PROPERTY(uint8_t, totalErrors, TotalErrors);
/**
* @brief Flag indicating the frame should be muted.
*/
__PROPERTY(bool, muteFrame, MuteFrame);
DECLARE_PROPERTY(bool, muteFrame, MuteFrame);
/**
* @brief Flag indicating the frame was lost.
*/
__PROPERTY(bool, lostFrame, LostFrame);
DECLARE_PROPERTY(bool, lostFrame, LostFrame);
/**
* @brief Superframe Counter.
*/
__PROPERTY(uint8_t, superframeCnt, SuperframeCnt);
DECLARE_PROPERTY(uint8_t, superframeCnt, SuperframeCnt);
/**
* @brief Busy Status.
*/
__PROPERTY(uint8_t, busy, Busy);
DECLARE_PROPERTY(uint8_t, busy, Busy);
private:
/**

@ -97,11 +97,11 @@ namespace p25
/**
* @brief Frame Type.
*/
__PROPERTY(defines::DFSIFrameType::E, frameType, FrameType);
DECLARE_PROPERTY(defines::DFSIFrameType::E, frameType, FrameType);
/**
* @brief V.24 Data Source.
*/
__PROPERTY(SourceFlag::E, source, Source);
DECLARE_PROPERTY(SourceFlag::E, source, Source);
private:
/**

@ -78,19 +78,19 @@ namespace p25
/**
* @brief
*/
__PROPERTY(uint8_t, marker, Marker);
DECLARE_PROPERTY(uint8_t, marker, Marker);
/**
* @brief RT/RT Flag.
*/
__PROPERTY(RTFlag::E, rt, RT);
DECLARE_PROPERTY(RTFlag::E, rt, RT);
/**
* @brief Start/Stop.
*/
__PROPERTY(StartStopFlag::E, startStop, StartStop);
DECLARE_PROPERTY(StartStopFlag::E, startStop, StartStop);
/**
* @brief Stream Type.
*/
__PROPERTY(StreamTypeFlag::E, streamType, StreamType);
DECLARE_PROPERTY(StreamTypeFlag::E, streamType, StreamType);
};
} // namespace frames
} // namespace dfsi

@ -92,23 +92,23 @@ namespace p25
/**
* @brief
*/
__PROPERTY(ICWFlag::E, icw, ICW);
DECLARE_PROPERTY(ICWFlag::E, icw, ICW);
/**
* @brief RSSI Value.
*/
__PROPERTY(uint8_t, rssi, RSSI);
DECLARE_PROPERTY(uint8_t, rssi, RSSI);
/**
* @brief Flag indicating whether or not the RSSI field is valid.
*/
__PROPERTY(RssiValidityFlag::E, rssiValidity, RSSIValidity);
DECLARE_PROPERTY(RssiValidityFlag::E, rssiValidity, RSSIValidity);
/**
* @brief
*/
__PROPERTY(uint8_t, nRssi, NRSSI);
DECLARE_PROPERTY(uint8_t, nRssi, NRSSI);
/**
* @brief
*/
__PROPERTY(uint8_t, adjMM, AdjMM);
DECLARE_PROPERTY(uint8_t, adjMM, AdjMM);
};
} // namespace frames
} // namespace dfsi

@ -96,19 +96,19 @@ namespace p25
/**
* @brief
*/
__PROPERTY(ICWFlag::E, icw, ICW);
DECLARE_PROPERTY(ICWFlag::E, icw, ICW);
/**
* @brief RSSI Value.
*/
__PROPERTY(uint8_t, rssi, RSSI);
DECLARE_PROPERTY(uint8_t, rssi, RSSI);
/**
* @brief Flag indicating whether or not the RSSI field is valid.
*/
__PROPERTY(RssiValidityFlag::E, rssiValidity, RSSIValidity);
DECLARE_PROPERTY(RssiValidityFlag::E, rssiValidity, RSSIValidity);
/**
* @brief
*/
__PROPERTY(uint8_t, nRssi, NRSSI);
DECLARE_PROPERTY(uint8_t, nRssi, NRSSI);
};
} // namespace frames
} // namespace dfsi

@ -91,7 +91,7 @@ namespace p25
/**
* @brief V.24 Data Source.
*/
__PROPERTY(SourceFlag::E, source, Source);
DECLARE_PROPERTY(SourceFlag::E, source, Source);
};
} // namespace frames
} // namespace dfsi

@ -47,7 +47,7 @@ bool StartOfStream::decode(const uint8_t* data)
{
assert(data != nullptr);
m_nid = __GET_UINT16B(data, 0U); // Network Identifier
m_nid = GET_UINT16(data, 0U); // Network Identifier
m_errorCount = (data[2U] & 0x0FU); // Error Count
return true;
@ -59,6 +59,6 @@ void StartOfStream::encode(uint8_t* data)
{
assert(data != nullptr);
__SET_UINT16B(m_nid, data, 0U); // Network Identifier
SET_UINT16(m_nid, data, 0U); // Network Identifier
data[2U] = m_errorCount & 0x0FU; // Error Count
}

@ -72,11 +72,11 @@ namespace p25
/**
* @brief Network Identifier.
*/
__PROPERTY(uint16_t, nid, NID);
DECLARE_PROPERTY(uint16_t, nid, NID);
/**
* @brief Error count.
*/
__PROPERTY(uint8_t, errorCount, ErrorCount);
DECLARE_PROPERTY(uint8_t, errorCount, ErrorCount);
};
} // namespace frames
} // namespace dfsi

@ -65,23 +65,23 @@ namespace p25
/**
* @brief Acknowledged Message ID.
*/
__PROPERTY(FSCMessageType::E, ackMessageId, AckMessageId);
DECLARE_PROPERTY(FSCMessageType::E, ackMessageId, AckMessageId);
/**
* @brief Acknowledged Message Version.
*/
__READONLY_PROPERTY(uint8_t, ackVersion, AckVersion);
DECLARE_RO_PROPERTY(uint8_t, ackVersion, AckVersion);
/**
* @brief
*/
__PROPERTY(uint8_t, ackCorrelationTag, AckCorrelationTag);
DECLARE_PROPERTY(uint8_t, ackCorrelationTag, AckCorrelationTag);
/**
* @brief Response code.
*/
__PROPERTY(FSCAckResponseCode::E, responseCode, ResponseCode);
DECLARE_PROPERTY(FSCAckResponseCode::E, responseCode, ResponseCode);
/**
* @brief Response Data Length.
*/
__PROPERTY(uint8_t, respLength, ResponseLength);
DECLARE_PROPERTY(uint8_t, respLength, ResponseLength);
};
} // namespace fsc
} // namespace frames

@ -41,8 +41,8 @@ bool FSCConnect::decode(const uint8_t* data)
assert(data != nullptr);
FSCMessage::decode(data);
m_vcBasePort = __GET_UINT16B(data, 3U); // Voice Conveyance RTP Port
m_vcSSRC = __GET_UINT32(data, 5U); // Voice Conveyance SSRC
m_vcBasePort = GET_UINT16(data, 3U); // Voice Conveyance RTP Port
m_vcSSRC = GET_UINT32(data, 5U); // Voice Conveyance SSRC
m_fsHeartbeatPeriod = data[9U]; // Fixed Station Heartbeat Period
m_hostHeartbeatPeriod = data[10U]; // Host Heartbeat Period
@ -56,8 +56,8 @@ void FSCConnect::encode(uint8_t* data)
assert(data != nullptr);
FSCMessage::encode(data);
__SET_UINT16B(m_vcBasePort, data, 3U); // Voice Conveyance RTP Port
__SET_UINT32(m_vcSSRC, data, 5U); // Voice Conveyance SSRC
SET_UINT16(m_vcBasePort, data, 3U); // Voice Conveyance RTP Port
SET_UINT32(m_vcSSRC, data, 5U); // Voice Conveyance SSRC
data[9U] = m_fsHeartbeatPeriod; // Fixed Station Heartbeat Period
data[10U] = m_hostHeartbeatPeriod; // Host Heartbeat Period
}

@ -63,19 +63,19 @@ namespace p25
/**
* @brief Voice Conveyance RTP Port.
*/
__PROPERTY(uint16_t, vcBasePort, VCBasePort);
DECLARE_PROPERTY(uint16_t, vcBasePort, VCBasePort);
/**
* @brief SSRC Identifier for all RTP transmissions.
*/
__PROPERTY(uint32_t, vcSSRC, VCSSRC);
DECLARE_PROPERTY(uint32_t, vcSSRC, VCSSRC);
/**
* @brief Fixed Station Heartbeat Period.
*/
__PROPERTY(uint8_t, fsHeartbeatPeriod, FSHeartbeatPeriod);
DECLARE_PROPERTY(uint8_t, fsHeartbeatPeriod, FSHeartbeatPeriod);
/**
* @brief Host Heartbeat Period.
*/
__PROPERTY(uint8_t, hostHeartbeatPeriod, HostHeartbeatPeriod);
DECLARE_PROPERTY(uint8_t, hostHeartbeatPeriod, HostHeartbeatPeriod);
};
} // namespace fsc
} // namespace frames

@ -69,15 +69,15 @@ namespace p25
/**
* @brief Message ID.
*/
__PROTECTED_PROPERTY(FSCMessageType::E, messageId, MessageId);
DECLARE_PROTECTED_PROPERTY(FSCMessageType::E, messageId, MessageId);
/**
* @brief Message Version.
*/
__PROTECTED_READONLY_PROPERTY(uint8_t, version, Version);
DECLARE_PROTECTED_RO_PROPERTY(uint8_t, version, Version);
/**
* @brief
*/
__PROPERTY(uint8_t, correlationTag, CorrelationTag);
DECLARE_PROPERTY(uint8_t, correlationTag, CorrelationTag);
};
} // namespace fsc
} // namespace frames

@ -63,11 +63,11 @@ namespace p25
/**
* @brief Receive Channel Number.
*/
__PROPERTY(uint8_t, rxChan, RxChan);
DECLARE_PROPERTY(uint8_t, rxChan, RxChan);
/**
* @brief Transmit Channel Number.
*/
__PROPERTY(uint8_t, txChan, TxChan);
DECLARE_PROPERTY(uint8_t, txChan, TxChan);
};
} // namespace fsc
} // namespace frames

@ -45,7 +45,7 @@ bool KMMDeregistrationCommand::decode(const uint8_t* data)
KMMFrame::decodeHeader(data);
m_bodyFormat = data[10U]; // Body Format
m_kmfRSI = __GET_UINT16(data, 11U); // KMF RSI
m_kmfRSI = GET_UINT24(data, 11U); // KMF RSI
return true;
}
@ -61,7 +61,7 @@ void KMMDeregistrationCommand::encode(uint8_t* data)
KMMFrame::encodeHeader(data);
data[10U] = m_bodyFormat; // Body Format
__SET_UINT16(m_kmfRSI, data, 11U); // KMF RSI
SET_UINT24(m_kmfRSI, data, 11U); // KMF RSI
}
// ---------------------------------------------------------------------------

@ -71,13 +71,13 @@ namespace p25
/**
* @brief
*/
__PROPERTY(uint8_t, bodyFormat, BodyFormat);
DECLARE_PROPERTY(uint8_t, bodyFormat, BodyFormat);
/**
* @brief
* @brief KMF RSI.
*/
__PROPERTY(uint32_t, kmfRSI, KMFRSI);
DECLARE_PROPERTY(uint32_t, kmfRSI, KMFRSI);
__COPY(KMMDeregistrationCommand);
DECLARE_COPY(KMMDeregistrationCommand);
};
} // namespace kmm
} // namespace p25

@ -69,11 +69,11 @@ namespace p25
public:
/**
* @brief
* @brief Deregistration response status.
*/
__PROPERTY(uint8_t, status, Status);
DECLARE_PROPERTY(uint8_t, status, Status);
__COPY(KMMDeregistrationResponse);
DECLARE_COPY(KMMDeregistrationResponse);
};
} // namespace kmm
} // namespace p25

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save

Powered by TurnKey Linux.