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 10 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) if (COMPILE_WIN32)
set(ARCH amd64) set(ARCH amd64)
set(CMAKE_SYSTEM_PROCESSOR amd64) set(CMAKE_SYSTEM_PROCESSOR amd64)
message(CHECK_START "Detect Host Architecture - ${ARCH}")
# No TUI for this # No TUI for this
set(ENABLE_TUI_SUPPORT OFF) set(ENABLE_TUI_SUPPORT OFF)
@ -49,7 +50,25 @@ if (COMPILE_WIN32)
else() else()
set(CMAKE_C_COMPILER /usr/bin/gcc CACHE STRING "C compiler") set(CMAKE_C_COMPILER /usr/bin/gcc CACHE STRING "C compiler")
set(CMAKE_CXX_COMPILER /usr/bin/g++ 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(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) set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE amd64)
endif (COMPILE_WIN32) endif (COMPILE_WIN32)
@ -60,6 +79,7 @@ if (CROSS_COMPILE_ARM)
set(CMAKE_SYSTEM_PROCESSOR armhf) set(CMAKE_SYSTEM_PROCESSOR armhf)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE armhf) set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE armhf)
set(OPENSSL_ROOT_DIR /usr/lib/arm-linux-gnueabihf) 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}") message(CHECK_START "Cross compiling for 32-bit ARM - ${CMAKE_C_COMPILER}")
endif (CROSS_COMPILE_ARM) endif (CROSS_COMPILE_ARM)
if (CROSS_COMPILE_AARCH64) if (CROSS_COMPILE_AARCH64)
@ -69,6 +89,7 @@ if (CROSS_COMPILE_AARCH64)
set(CMAKE_SYSTEM_PROCESSOR arm64) set(CMAKE_SYSTEM_PROCESSOR arm64)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE arm64) set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE arm64)
set(OPENSSL_ROOT_DIR /usr/lib/aarch64-linux-gnu) 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}") message(CHECK_START "Cross compiling for 64-bit ARM - ${CMAKE_C_COMPILER}")
endif (CROSS_COMPILE_AARCH64) endif (CROSS_COMPILE_AARCH64)
@ -107,6 +128,7 @@ if (CROSS_COMPILE_RPI_ARM)
set(ARCH armhf) set(ARCH armhf)
set(CMAKE_SYSTEM_PROCESSOR armhf) set(CMAKE_SYSTEM_PROCESSOR armhf)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE 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}") message(CHECK_START "Cross compiling for (old RPi) 32-bit ARM - ${CMAKE_C_COMPILER}")
# No TUI for this # No TUI for this

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

@ -38,6 +38,8 @@ master:
# Hostname/IP address to listen on (blank for all). # Hostname/IP address to listen on (blank for all).
address: 0.0.0.0 address: 0.0.0.0
# Port number to listen on. # 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 port: 62031
# FNE access password. # FNE access password.
password: RPT1234 password: RPT1234
@ -211,22 +213,16 @@ system:
# Maximum number of missable pings before a peer is considered disconnected. # Maximum number of missable pings before a peer is considered disconnected.
maxMissedPings: 10 maxMissedPings: 10
# Time in minutes between updates of the talkgroup rules. # Time in minutes between updates of the ACL rules.
tgRuleUpdateTime: 10 aclRuleUpdateTime: 10
# Flag indicating the TGID information for this master will be sent to its peers. # Flag indicating the TGID information for this master will be sent to its peers.
sendTalkgroups: true sendTalkgroups: true
# Flag indicating the FNE should use an alternate port dedicated to diagnostic and activity # Flag indicating when this FNE instance receives peer link configuration updates, it will save those
# log processing. This port number is always: master port + 1 (so for example, a master port # peer link configurations.
# of 62031 will use 62032 for diagnostic and activity messages.) peerLinkSaveACL: false
# 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 whether or not the host diagnostic log will be sent to the network. # Flag indicating whether or not the host diagnostic log will be sent to the network.
allowDiagnosticTransfer: true allowDiagnosticTransfer: true

@ -263,7 +263,7 @@ int main(int argc, char** argv)
#endif #endif
uint32_t hash = ::strtoul(__GIT_VER_HASH__, 0, 16); 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) if (argv[0] != nullptr && *argv[0] != 0)
g_progExe = std::string(argv[0]); g_progExe = std::string(argv[0]);

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

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

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

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

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

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

@ -192,8 +192,7 @@ bool PeerNetwork::writeConfig()
json::value v = json::value(config); json::value v = json::value(config);
std::string json = v.serialize(); std::string json = v.serialize();
CharArray __buffer = std::make_unique<char[]>(json.length() + 9U); DECLARE_CHAR_ARRAY(buffer, json.length() + 9U);
char* buffer = __buffer.get();
::memcpy(buffer + 0U, TAG_REPEATER_CONFIG, 4U); ::memcpy(buffer + 0U, TAG_REPEATER_CONFIG, 4U);
::snprintf(buffer + 8U, json.length() + 1U, "%s", json.c_str()); ::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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX * 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 * @file Defines.h
* @ingroup common * @ingroup common
*/ */
#pragma once
#if !defined(__COMMON_DEFINES_H__) #if !defined(__COMMON_DEFINES_H__)
#define __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)) #define PACK(decl) __pragma(pack(push, 1)) decl __pragma(pack(pop))
#endif #endif
// ---------------------------------------------------------------------------
// Meta-Programming Macro Includes
// ---------------------------------------------------------------------------
#include "common/ClassProperties.h"
#include "common/BitManipulation.h"
#include "common/VariableLengthArray.h"
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Constants // Constants
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -108,7 +117,7 @@ typedef unsigned long long ulong64_t;
#define __EXE_NAME__ "" #define __EXE_NAME__ ""
#define VERSION_MAJOR "04" #define VERSION_MAJOR "04"
#define VERSION_MINOR "30" #define VERSION_MINOR "31"
#define VERSION_REV "H" #define VERSION_REV "H"
#define __NETVER__ "DVM_R" VERSION_MAJOR VERSION_REV VERSION_MINOR #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_COMPRESS = 0x01U;
const uint8_t IP_COMPRESS_RFC1144_UNCOMPRESS = 0x02U; 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__ #endif // __COMMON_DEFINES_H__

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

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

@ -5,11 +5,11 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2009,2014,2015 Jonathan Naylor, G4KLX * 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. * @brief Defines and implements utility routines.
* @ingroup common * @ingroup common
* *
@ -31,17 +31,24 @@
#endif // !defined(WIN32) #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 * @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; 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 // 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX * 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; 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 */ /** @name LC Service Options */
const uint8_t LC_SVC_OPT_EMERGENCY = 0x80U; const uint8_t LC_SVC_OPT_EMERGENCY = 0x80U;
const uint8_t LC_SVC_OPT_PRIVACY = 0x40U; const uint8_t LC_SVC_OPT_PRIVACY = 0x40U;

@ -156,27 +156,27 @@ namespace dmr
/** /**
* @brief DMR site model type. * @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. * @brief DMR site network ID.
*/ */
__READONLY_PROPERTY_PLAIN(uint16_t, netId); DECLARE_RO_PROPERTY_PLAIN(uint16_t, netId);
/** /**
* @brief DMR site ID. * @brief DMR site ID.
*/ */
__READONLY_PROPERTY_PLAIN(uint16_t, siteId); DECLARE_RO_PROPERTY_PLAIN(uint16_t, siteId);
/** /**
* @brief DMR partition ID. * @brief DMR partition ID.
*/ */
__READONLY_PROPERTY_PLAIN(uint8_t, parId); DECLARE_RO_PROPERTY_PLAIN(uint8_t, parId);
/** /**
* @brief DMR require registration. * @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. * @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 } // namespace dmr

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

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

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

@ -56,17 +56,17 @@ namespace dmr
/** /**
* @brief DMR access color code. * @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. * @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. * @brief Link control start/stop.
*/ */
__PROPERTY(uint8_t, LCSS, LCSS); DECLARE_PROPERTY(uint8_t, LCSS, LCSS);
}; };
} // namespace data } // namespace data
} // namespace dmr } // namespace dmr

@ -96,11 +96,11 @@ namespace dmr
/** /**
* @brief Flag indicating whether or not the embedded data is valid. * @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. * @brief Full-link control opcode.
*/ */
__READONLY_PROPERTY(defines::FLCO::E, FLCO, FLCO); DECLARE_RO_PROPERTY(defines::FLCO::E, FLCO, FLCO);
private: private:
LC_STATE m_state; LC_STATE m_state;

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

@ -117,116 +117,116 @@ namespace dmr
/** /**
* @brief DMR access color code. * @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. * @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. * @brief Flag indicating whether the CSBK is a Cdef block.
*/ */
__PROTECTED_PROPERTY(bool, Cdef, Cdef); DECLARE_PROTECTED_PROPERTY(bool, Cdef, Cdef);
/** /**
* @brief CSBK opcode. * @brief CSBK opcode.
*/ */
__PROTECTED_PROPERTY(uint8_t, CSBKO, CSBKO); DECLARE_PROTECTED_PROPERTY(uint8_t, CSBKO, CSBKO);
/** /**
* @brief */ * @brief */
__PROTECTED_PROPERTY(uint8_t, FID, FID); DECLARE_PROTECTED_PROPERTY(uint8_t, FID, FID);
/** /**
* @brief Flag indicating whether the CSBK is group or individual. * @brief Flag indicating whether the CSBK is group or individual.
*/ */
__PROTECTED_PROPERTY(bool, GI, GI); DECLARE_PROTECTED_PROPERTY(bool, GI, GI);
/** /**
* @brief Source ID. * @brief Source ID.
*/ */
__PROTECTED_PROPERTY(uint32_t, srcId, SrcId); DECLARE_PROTECTED_PROPERTY(uint32_t, srcId, SrcId);
/** /**
* @brief Destination ID. * @brief Destination ID.
*/ */
__PROTECTED_PROPERTY(uint32_t, dstId, DstId); DECLARE_PROTECTED_PROPERTY(uint32_t, dstId, DstId);
/** /**
* @brief * @brief
*/ */
__PROTECTED_READONLY_PROPERTY(bool, dataContent, DataContent); DECLARE_PROTECTED_RO_PROPERTY(bool, dataContent, DataContent);
/** /**
* @brief Number of blocks to follow. * @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. * @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 */ /** @name Common Service Options */
/** /**
* @brief Flag indicating the emergency bits are set. * @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. * @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. * @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. * @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. * @brief Flag indicating a broadcast service.
*/ */
__PROTECTED_PROPERTY(bool, broadcast, Broadcast); DECLARE_PROTECTED_PROPERTY(bool, broadcast, Broadcast);
/** /**
* @brief Flag indicating a proxy. * @brief Flag indicating a proxy.
*/ */
__PROTECTED_PROPERTY(bool, proxy, Proxy); DECLARE_PROTECTED_PROPERTY(bool, proxy, Proxy);
/** /**
* @brief Response information. * @brief Response information.
*/ */
__PROTECTED_PROPERTY(uint8_t, response, Response); DECLARE_PROTECTED_PROPERTY(uint8_t, response, Response);
/** /**
* @brief Reason type. * @brief Reason type.
*/ */
__PROTECTED_PROPERTY(uint8_t, reason, Reason); DECLARE_PROTECTED_PROPERTY(uint8_t, reason, Reason);
/** @} */ /** @} */
/** @name Tier 3 */ /** @name Tier 3 */
/** /**
* @brief Site offset timing. * @brief Site offset timing.
*/ */
__PROTECTED_PROPERTY(bool, siteOffsetTiming, SiteOffsetTiming); DECLARE_PROTECTED_PROPERTY(bool, siteOffsetTiming, SiteOffsetTiming);
/** /**
* @brief Broadcast Logical Channel ID 1. * @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. * @brief Broadcast Logical Channel ID 2.
*/ */
__PROTECTED_PROPERTY(uint16_t, logicalCh2, LogicalCh2); DECLARE_PROTECTED_PROPERTY(uint16_t, logicalCh2, LogicalCh2);
/** /**
* @brief Logical Channel Slot Number. * @brief Logical Channel Slot Number.
*/ */
__PROTECTED_PROPERTY(uint8_t, slotNo, SlotNo); DECLARE_PROTECTED_PROPERTY(uint8_t, slotNo, SlotNo);
/** @} */ /** @} */
/** @name Local Site data */ /** @name Local Site data */
/** /**
* @brief Local Site Identity Entry. * @brief Local Site Identity Entry.
*/ */
__PROTECTED_PROPERTY_PLAIN(::lookups::IdenTable, siteIdenEntry); DECLARE_PROTECTED_PROPERTY_PLAIN(::lookups::IdenTable, siteIdenEntry);
/** @} */ /** @} */
protected: protected:
@ -261,7 +261,7 @@ namespace dmr
*/ */
void encode(uint8_t* data, const uint8_t* payload); void encode(uint8_t* data, const uint8_t* payload);
__PROTECTED_COPY(CSBK); DECLARE_PROTECTED_COPY(CSBK);
private: private:
uint8_t* m_raw; uint8_t* m_raw;

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

@ -7,7 +7,7 @@
* @package DVM / Common Library * @package DVM / Common Library
* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0) * @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" #include "Defines.h"
@ -160,3 +160,25 @@ void PrivacyLC::getData(bool* bits) const
Utils::byteToBitsBE(bytes[8U], bits + 64U); Utils::byteToBitsBE(bytes[8U], bits + 64U);
Utils::byteToBitsBE(bytes[9U], bits + 72U); 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 * @package DVM / Common Library
* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0) * @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; 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: public:
/** @name Common Data */ /** @name Common Data */
/** /**
* @brief Feature ID * @brief Feature ID
*/ */
__PROPERTY(uint8_t, FID, FID); DECLARE_PROPERTY(uint8_t, FID, FID);
/** /**
* @brief Destination ID. * @brief Destination ID.
*/ */
__PROPERTY(uint32_t, dstId, DstId); DECLARE_PROPERTY(uint32_t, dstId, DstId);
/** @} */ /** @} */
/** @name Service Options */ /** @name Service Options */
/** /**
* @brief Flag indicating a group/talkgroup operation. * @brief Flag indicating a group/talkgroup operation.
*/ */
__PROPERTY(bool, group, Group); DECLARE_PROPERTY(bool, group, Group);
/** @} */ /** @} */
/** @name Encryption data */ /** @name Encryption data */
/** /**
* @brief Encryption algorithm ID. * @brief Encryption algorithm ID.
*/ */
__PROPERTY(uint8_t, algId, AlgId); DECLARE_PROPERTY(uint8_t, algId, AlgId);
/** /**
* @brief Encryption key ID. * @brief Encryption key ID.
*/ */
__PROPERTY(uint32_t, kId, KId); DECLARE_PROPERTY(uint32_t, kId, KId);
/** @} */ /** @} */
private: private:

@ -61,22 +61,22 @@ namespace dmr
/** /**
* @brief Aloha Site Time Slot Synchronization. * @brief Aloha Site Time Slot Synchronization.
*/ */
__PROPERTY(bool, siteTSSync, SiteTSSync); DECLARE_PROPERTY(bool, siteTSSync, SiteTSSync);
/** /**
* @brief Aloha MS mask. * @brief Aloha MS mask.
*/ */
__PROPERTY(uint8_t, alohaMask, AlohaMask); DECLARE_PROPERTY(uint8_t, alohaMask, AlohaMask);
/** /**
* @brief Backoff Number. * @brief Backoff Number.
*/ */
__PROPERTY(uint8_t, backoffNo, BackoffNo); DECLARE_PROPERTY(uint8_t, backoffNo, BackoffNo);
/** /**
* @brief Random Access Wait Delay. * @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 csbk
} // namespace lc } // namespace lc

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

@ -61,9 +61,9 @@ namespace dmr
/** /**
* @brief Base Station ID. * @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 csbk
} // namespace lc } // namespace lc

@ -61,9 +61,9 @@ namespace dmr
/** /**
* @brief Extended function opcode. * @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 csbk
} // namespace lc } // namespace lc

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

@ -61,9 +61,9 @@ namespace dmr
/** /**
* @brief Service Kind. * @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 csbk
} // namespace lc } // namespace lc

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

@ -61,9 +61,9 @@ namespace dmr
/** /**
* @brief Flag indicating whether the grant is a late entry. * @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 csbk
} // namespace lc } // namespace lc

@ -48,6 +48,8 @@ namespace lookups
VoiceChData() : VoiceChData() :
m_chId(0U), m_chId(0U),
m_chNo(0U), m_chNo(0U),
m_rxChId(0xFFU),
m_rxChNo(0xFFFFU),
m_address(), m_address(),
m_port(), m_port(),
m_password(), 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) : VoiceChData(uint8_t chId, uint32_t chNo, std::string address, uint16_t port, std::string password, bool ssl = false) :
m_chId(chId), m_chId(chId),
m_chNo(chNo), 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_address(address),
m_port(port), m_port(port),
m_password(password), m_password(password),
@ -84,6 +111,8 @@ namespace lookups
if (this != &data) { if (this != &data) {
m_chId = data.m_chId; m_chId = data.m_chId;
m_chNo = data.m_chNo; m_chNo = data.m_chNo;
m_rxChId = data.m_rxChId;
m_rxChNo = data.m_rxChNo;
m_address = data.m_address; m_address = data.m_address;
m_port = data.m_port; m_port = data.m_port;
m_password = data.m_password; m_password = data.m_password;
@ -103,32 +132,56 @@ namespace lookups
* @returns True, if channel is valid, otherwise false. * @returns True, if channel is valid, otherwise false.
*/ */
bool isValidCh() const { return m_chNo != 0U; } 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: public:
/** /**
* @brief Voice Channel Identity. * @brief Voice Channel Identity.
*/ */
__READONLY_PROPERTY_PLAIN(uint8_t, chId); DECLARE_RO_PROPERTY_PLAIN(uint8_t, chId);
/** /**
* @brief Voice Channel Number. * @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. * @brief RPC/REST API Address.
*/ */
__PROPERTY_PLAIN(std::string, address); DECLARE_PROPERTY_PLAIN(std::string, address);
/** /**
* @brief RPC/REST API Port. * @brief RPC/REST API Port.
*/ */
__PROPERTY_PLAIN(uint16_t, port); DECLARE_PROPERTY_PLAIN(uint16_t, port);
/** /**
* @brief RPC/REST API Password. * @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. * @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. * @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. * @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. * @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. * @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. * @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. * @brief Peer ID.
*/ */
__PROPERTY_PLAIN(uint32_t, peerId); DECLARE_PROPERTY_PLAIN(uint32_t, peerId);
/** /**
* @breif Peer Alias * @breif Peer Alias
*/ */
__PROPERTY_PLAIN(std::string, peerAlias); DECLARE_PROPERTY_PLAIN(std::string, peerAlias);
/** /**
* @brief Per Peer Password. * @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. * @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. * @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. * @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. * @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. * @brief Flag indicating if the radio is default.
*/ */
__READONLY_PROPERTY_PLAIN(bool, radioDefault); DECLARE_RO_PROPERTY_PLAIN(bool, radioDefault);
/** /**
* @brief Alias for the radio. * @brief Alias for the radio.
*/ */
__READONLY_PROPERTY_PLAIN(std::string, radioAlias); DECLARE_RO_PROPERTY_PLAIN(std::string, radioAlias);
/** /**
* @brief IP Address for the radio. * @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. * @brief Talkgroup ID.
*/ */
__PROPERTY_PLAIN(uint32_t, tgId); DECLARE_PROPERTY_PLAIN(uint32_t, tgId);
/** /**
* @brief Talkgroup DMR slot. * @brief Talkgroup DMR slot.
*/ */
__PROPERTY_PLAIN(uint8_t, tgSlot); DECLARE_PROPERTY_PLAIN(uint8_t, tgSlot);
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -160,15 +160,15 @@ namespace lookups
/** /**
* @brief Peer ID. * @brief Peer ID.
*/ */
__PROPERTY_PLAIN(uint32_t, peerId); DECLARE_PROPERTY_PLAIN(uint32_t, peerId);
/** /**
* @brief Talkgroup ID. * @brief Talkgroup ID.
*/ */
__PROPERTY_PLAIN(uint32_t, tgId); DECLARE_PROPERTY_PLAIN(uint32_t, tgId);
/** /**
* @brief Talkgroup DMR slot. * @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. * @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. * @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. * @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. * @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. * @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. * @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. * @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. * @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. * @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. * @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. * @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. * @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. * @brief Configuration for the routing rule.
*/ */
__PROPERTY_PLAIN(TalkgroupRuleConfig, config); DECLARE_PROPERTY_PLAIN(TalkgroupRuleConfig, config);
/** /**
* @brief Source talkgroup information for the routing rule. * @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. * @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. * @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. * @brief List of group voice rules.
*/ */
__PROPERTY_PLAIN(std::vector<TalkgroupRuleGroupVoice>, groupVoice); DECLARE_PROPERTY_PLAIN(std::vector<TalkgroupRuleGroupVoice>, groupVoice);
}; };
} // namespace lookups } // namespace lookups

@ -101,8 +101,8 @@ bool BaseNetwork::writeGrantReq(const uint8_t mode, const uint32_t srcId, const
uint8_t buffer[MSG_HDR_SIZE]; uint8_t buffer[MSG_HDR_SIZE];
::memset(buffer, 0x00U, MSG_HDR_SIZE); ::memset(buffer, 0x00U, MSG_HDR_SIZE);
__SET_UINT32(srcId, buffer, 11U); // Source Address SET_UINT32(srcId, buffer, 11U); // Source Address
__SET_UINT32(dstId, buffer, 15U); // Destination Address SET_UINT32(dstId, buffer, 15U); // Destination Address
buffer[19U] = slot; // Slot Number buffer[19U] = slot; // Slot Number
if (unitToUnit) if (unitToUnit)
@ -220,8 +220,8 @@ bool BaseNetwork::announceGroupAffiliation(uint32_t srcId, uint32_t dstId)
uint8_t buffer[DATA_PACKET_LENGTH]; uint8_t buffer[DATA_PACKET_LENGTH];
__SET_UINT16(srcId, buffer, 0U); SET_UINT24(srcId, buffer, 0U);
__SET_UINT16(dstId, buffer, 3U); 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); 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]; 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); 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]; 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); 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]; 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); 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) if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING)
return false; return false;
UInt8Array __buffer = std::make_unique<uint8_t[]>(4U + (affs.size() * 8U)); DECLARE_UINT8_ARRAY(buffer, 4U + (affs.size() * 8U));
uint8_t* buffer = __buffer.get();
::memset(buffer, 0x00U, 4U + (affs.size() * 8U));
__SET_UINT32(affs.size(), buffer, 0U); SET_UINT32(affs.size(), buffer, 0U);
// write talkgroup IDs to active TGID payload // write talkgroup IDs to active TGID payload
uint32_t offs = 4U; uint32_t offs = 4U;
for (auto it : affs) { for (auto it : affs) {
__SET_UINT16(it.first, buffer, offs); SET_UINT24(it.first, buffer, offs);
__SET_UINT16(it.second, buffer, offs + 4U); SET_UINT24(it.second, buffer, offs + 4U);
offs += 8U; 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) if (m_status != NET_STAT_RUNNING && m_status != NET_STAT_MST_RUNNING)
return false; return false;
UInt8Array __buffer = std::make_unique<uint8_t[]>(4U + (peers.size() * 4U)); DECLARE_UINT8_ARRAY(buffer, 4U + (peers.size() * 4U));
uint8_t* buffer = __buffer.get();
::memset(buffer, 0x00U, 4U + (peers.size() * 4U));
__SET_UINT32(peers.size(), buffer, 0U); SET_UINT32(peers.size(), buffer, 0U);
// write peer IDs to active TGID payload // write peer IDs to active TGID payload
uint32_t offs = 4U; uint32_t offs = 4U;
for (auto it : peers) { for (auto it : peers) {
__SET_UINT32(it, buffer, offs); SET_UINT32(it, buffer, offs);
offs += 4U; offs += 4U;
} }
@ -762,10 +758,10 @@ UInt8Array BaseNetwork::createDMR_Message(uint32_t& length, const uint32_t strea
::memcpy(buffer + 0U, TAG_DMR_DATA, 4U); ::memcpy(buffer + 0U, TAG_DMR_DATA, 4U);
uint32_t srcId = data.getSrcId(); // Source Address uint32_t srcId = data.getSrcId(); // Source Address
__SET_UINT16(srcId, buffer, 5U); SET_UINT24(srcId, buffer, 5U);
uint32_t dstId = data.getDstId(); // Target Address uint32_t dstId = data.getDstId(); // Target Address
__SET_UINT16(dstId, buffer, 8U); SET_UINT24(dstId, buffer, 8U);
uint32_t slotNo = data.getSlotNo(); 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 buffer[4U] = control.getLCO(); // LCO
uint32_t srcId = control.getSrcId(); // Source Address uint32_t srcId = control.getSrcId(); // Source Address
__SET_UINT16(srcId, buffer, 5U); SET_UINT24(srcId, buffer, 5U);
uint32_t dstId = control.getDstId(); // Target Address 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 uint16_t sysId = control.getSiteData().sysId(); // System ID
__SET_UINT16B(sysId, buffer, 11U); SET_UINT16(sysId, buffer, 11U);
buffer[14U] = 0U; // Control Bits buffer[14U] = 0U; // Control Bits
buffer[15U] = control.getMFId(); // MFId buffer[15U] = control.getMFId(); // MFId
uint32_t netId = control.getSiteData().netId(); // Network ID 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[20U] = lsd.getLSD1(); // LSD 1
buffer[21U] = lsd.getLSD2(); // LSD 2 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 buffer[181U] = control.getAlgId(); // Algorithm ID
uint32_t kid = control.getKId(); uint32_t kid = control.getKId();
__SET_UINT16B(kid, buffer, 182U); // Key ID SET_UINT16(kid, buffer, 182U); // Key ID
// copy MI data // copy MI data
uint8_t mi[MI_LENGTH_BYTES]; uint8_t mi[MI_LENGTH_BYTES];
@ -1125,7 +1121,7 @@ UInt8Array BaseNetwork::createP25_PDUMessage(uint32_t& length, const p25::data::
buffer[4U] |= 0x80U; buffer[4U] |= 0x80U;
} }
__SET_UINT16(len, buffer, 8U); // PDU Length [bytes] SET_UINT24(len, buffer, 8U); // PDU Length [bytes]
buffer[15U] = header.getMFId(); // MFId 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 buffer[4U] = lc.getMessageType(); // Message Type
uint32_t srcId = lc.getSrcId(); // Source Address uint32_t srcId = lc.getSrcId(); // Source Address
__SET_UINT16(srcId, buffer, 5U); SET_UINT24(srcId, buffer, 5U);
uint32_t dstId = lc.getDstId(); // Target Address uint32_t dstId = lc.getDstId(); // Target Address
__SET_UINT16(dstId, buffer, 8U); SET_UINT24(dstId, buffer, 8U);
buffer[14U] = 0U; // Control Bits buffer[14U] = 0U; // Control Bits

@ -444,34 +444,34 @@ namespace network
/** /**
* @brief Gets the peer ID of the 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. * @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. * @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. * @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. * @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. * @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. * @brief Flag indicating whether network traffic is duplex.
*/ */
__PROTECTED_READONLY_PROPERTY(bool, duplex, Duplex); DECLARE_PROTECTED_RO_PROPERTY(bool, duplex, Duplex);
protected: protected:
bool m_useAlternatePortForDiagnostics; bool m_useAlternatePortForDiagnostics;

@ -32,6 +32,9 @@ using namespace network::frame;
FrameQueue::FrameQueue(udp::Socket* socket, uint32_t peerId, bool debug) : RawFrameQueue(socket, debug), FrameQueue::FrameQueue(udp::Socket* socket, uint32_t peerId, bool debug) : RawFrameQueue(socket, debug),
m_peerId(peerId), m_peerId(peerId),
#if defined(_WIN32)
m_streamTSMtx(),
#endif // defined(_WIN32)
m_streamTimestamps() m_streamTimestamps()
{ {
assert(peerId < 999999999U); assert(peerId < 999999999U);
@ -148,6 +151,12 @@ bool FrameQueue::write(const uint8_t* message, uint32_t length, uint32_t streamI
uint32_t bufferLen = 0U; uint32_t bufferLen = 0U;
uint8_t* buffer = generateMessage(message, length, streamId, peerId, ssrc, opcode, rtpSeq, &bufferLen); 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; bool ret = true;
if (!m_socket->write(buffer, bufferLen, addr, addrLen)) { if (!m_socket->write(buffer, bufferLen, addr, addrLen)) {
// LogError(LOG_NET, "Failed writing data to the network"); // 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; uint32_t bufferLen = 0U;
uint8_t* buffer = generateMessage(message, length, streamId, peerId, ssrc, opcode, rtpSeq, &bufferLen); 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; udp::UDPDatagram *dgram = new udp::UDPDatagram;
dgram->buffer = buffer; dgram->buffer = buffer;
dgram->length = bufferLen; dgram->length = bufferLen;
@ -219,7 +234,11 @@ uint8_t* FrameQueue::generateMessage(const uint8_t* message, uint32_t length, ui
uint32_t timestamp = INVALID_TS; uint32_t timestamp = INVALID_TS;
if (streamId != 0U) { if (streamId != 0U) {
#if defined(_WIN32)
std::lock_guard<std::mutex> lock(m_streamTSMtx);
#else
m_streamTimestamps.lock(false); m_streamTimestamps.lock(false);
#endif // defined(_WIN32)
auto entry = m_streamTimestamps.find(streamId); auto entry = m_streamTimestamps.find(streamId);
if (entry != m_streamTimestamps.end()) { if (entry != m_streamTimestamps.end()) {
timestamp = entry->second; 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); 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; m_streamTimestamps[streamId] = timestamp;
} }
#if !defined(_WIN32)
m_streamTimestamps.unlock(); m_streamTimestamps.unlock();
#endif // defined(_WIN32)
} }
uint32_t bufferLen = RTP_HEADER_LENGTH_BYTES + RTP_EXTENSION_HEADER_LENGTH_BYTES + RTP_FNE_HEADER_LENGTH_BYTES + length; uint32_t bufferLen = RTP_HEADER_LENGTH_BYTES + RTP_EXTENSION_HEADER_LENGTH_BYTES + RTP_FNE_HEADER_LENGTH_BYTES + length;
@ -253,21 +274,34 @@ uint8_t* FrameQueue::generateMessage(const uint8_t* message, uint32_t length, ui
timestamp = (uint32_t)system_clock::ntp::now(); timestamp = (uint32_t)system_clock::ntp::now();
header.setTimestamp(timestamp); 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); m_streamTimestamps.insert(streamId, timestamp);
#endif // defined(_WIN32)
} }
header.encode(buffer); header.encode(buffer);
if (streamId != 0U && rtpSeq == RTP_END_OF_CALL_SEQ) { 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); m_streamTimestamps.lock(false);
#endif // defined(_WIN32)
auto entry = m_streamTimestamps.find(streamId); auto entry = m_streamTimestamps.find(streamId);
if (entry != m_streamTimestamps.end()) { if (entry != m_streamTimestamps.end()) {
if (m_debug) if (m_debug)
LogDebugEx(LOG_NET, "FrameQueue::generateMessage()", "RTP streamId = %u, rtpSeq = %u", streamId, rtpSeq); LogDebugEx(LOG_NET, "FrameQueue::generateMessage()", "RTP streamId = %u, rtpSeq = %u", streamId, rtpSeq);
#if !defined(_WIN32)
m_streamTimestamps.unlock(); m_streamTimestamps.unlock();
#endif // defined(_WIN32)
m_streamTimestamps.erase(streamId); m_streamTimestamps.erase(streamId);
} }
#if !defined(_WIN32)
m_streamTimestamps.unlock(); m_streamTimestamps.unlock();
#endif // defined(_WIN32)
} }
RTPFNEHeader fneHeader = RTPFNEHeader(); RTPFNEHeader fneHeader = RTPFNEHeader();

@ -115,7 +115,12 @@ namespace network
private: private:
uint32_t m_peerId; 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; concurrent::unordered_map<uint32_t, uint32_t> m_streamTimestamps;
#endif // defined(_WIN32)
/** /**
* @brief Generate RTP message for the frame queue. * @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); header.setMessageLength(json.length() + 1U);
// generate message // generate message
CharArray __message = std::make_unique<char[]>(json.length() + 1U); DECLARE_CHAR_ARRAY(message, json.length() + 1U);
char* message = __message.get();
::snprintf(message, json.length() + 1U, "%s", json.c_str()); ::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); header.setCRC(crc);
// generate RPC message // generate RPC message
UInt8Array __buffer = std::make_unique<uint8_t[]>(json.length() + 9U); DECLARE_UINT8_ARRAY(buffer, json.length() + 9U);
uint8_t* buffer = __buffer.get();
header.encode(buffer); header.encode(buffer);
::memcpy(buffer + 8U, message, json.length() + 1U); ::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); header.setMessageLength(json.length() + 1U);
// generate message // generate message
CharArray __message = std::make_unique<char[]>(json.length() + 1U); DECLARE_CHAR_ARRAY(message, json.length() + 1U);
char* message = __message.get();
::snprintf(message, json.length() + 1U, "%s", json.c_str()); ::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); header.setCRC(crc);
// generate RPC message // generate RPC message
UInt8Array __buffer = std::make_unique<uint8_t[]>(json.length() + 9U); DECLARE_UINT8_ARRAY(buffer, json.length() + 9U);
uint8_t* buffer = __buffer.get();
header.encode(buffer); header.encode(buffer);
::memcpy(buffer + 8U, message, json.length() + 1U); ::memcpy(buffer + 8U, message, json.length() + 1U);

@ -444,10 +444,10 @@ void Network::clock(uint32_t ms)
if (m_ridLookup != nullptr) { if (m_ridLookup != nullptr) {
// update RID lists // update RID lists
uint32_t len = __GET_UINT32(buffer, 6U); uint32_t len = GET_UINT32(buffer, 6U);
uint32_t offs = 11U; uint32_t offs = 11U;
for (uint32_t i = 0; i < len; i++) { 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); m_ridLookup->toggleEntry(id, true);
offs += 4U; offs += 4U;
} }
@ -470,10 +470,10 @@ void Network::clock(uint32_t ms)
if (m_ridLookup != nullptr) { if (m_ridLookup != nullptr) {
// update RID lists // update RID lists
uint32_t len = __GET_UINT32(buffer, 6U); uint32_t len = GET_UINT32(buffer, 6U);
uint32_t offs = 11U; uint32_t offs = 11U;
for (uint32_t i = 0; i < len; i++) { 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); m_ridLookup->toggleEntry(id, false);
offs += 4U; offs += 4U;
} }
@ -497,10 +497,10 @@ void Network::clock(uint32_t ms)
if (m_tidLookup != nullptr) { if (m_tidLookup != nullptr) {
// update TGID lists // update TGID lists
uint32_t len = __GET_UINT32(buffer, 6U); uint32_t len = GET_UINT32(buffer, 6U);
uint32_t offs = 11U; uint32_t offs = 11U;
for (uint32_t i = 0; i < len; i++) { 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; uint8_t slot = (buffer[offs + 3U]) & 0x03U;
bool affiliated = (buffer[offs + 3U] & 0x40U) == 0x40U; bool affiliated = (buffer[offs + 3U] & 0x40U) == 0x40U;
bool nonPreferred = (buffer[offs + 3U] & 0x80U) == 0x80U; bool nonPreferred = (buffer[offs + 3U] & 0x80U) == 0x80U;
@ -547,10 +547,10 @@ void Network::clock(uint32_t ms)
if (m_tidLookup != nullptr) { if (m_tidLookup != nullptr) {
// update TGID lists // update TGID lists
uint32_t len = __GET_UINT32(buffer, 6U); uint32_t len = GET_UINT32(buffer, 6U);
uint32_t offs = 11U; uint32_t offs = 11U;
for (uint32_t i = 0; i < len; i++) { 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]); uint8_t slot = (buffer[offs + 3U]);
lookups::TalkgroupRuleGroupVoice tid = m_tidLookup->find(id, slot); lookups::TalkgroupRuleGroupVoice tid = m_tidLookup->find(id, slot);
@ -588,7 +588,7 @@ void Network::clock(uint32_t ms)
{ {
if (m_enabled && m_dmrEnabled) { if (m_enabled && m_dmrEnabled) {
NET_ICC::ENUM command = (NET_ICC::ENUM)buffer[10U]; 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]; uint8_t slot = buffer[14U];
// fire off DMR in-call callback if we have one // 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) { if (m_enabled && m_p25Enabled) {
NET_ICC::ENUM command = (NET_ICC::ENUM)buffer[10U]; 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 // fire off P25 in-call callback if we have one
if (m_p25InCallCallback != nullptr) { if (m_p25InCallCallback != nullptr) {
@ -615,7 +615,7 @@ void Network::clock(uint32_t ms)
{ {
if (m_enabled && m_nxdnEnabled) { if (m_enabled && m_nxdnEnabled) {
NET_ICC::ENUM command = (NET_ICC::ENUM)buffer[10U]; 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 // fire off NXDN in-call callback if we have one
if (m_nxdnInCallCallback != nullptr) { if (m_nxdnInCallCallback != nullptr) {
@ -677,7 +677,7 @@ void Network::clock(uint32_t ms)
// then 10 bytes and process the reason value // then 10 bytes and process the reason value
uint16_t reason = 0U; uint16_t reason = 0U;
if (length > 10) { if (length > 10) {
reason = __GET_UINT16B(buffer, 10U); reason = GET_UINT16(buffer, 10U);
switch (reason) { switch (reason) {
case NET_CONN_NAK_MODE_NOT_ENABLED: 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()); 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; m_useAlternatePortForDiagnostics = (buffer[6U] & 0x80U) == 0x80U;
if (m_useAlternatePortForDiagnostics) { 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()); 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; break;
@ -781,9 +786,9 @@ void Network::clock(uint32_t ms)
} }
} }
break; 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; m_status = NET_STAT_WAITING_CONNECT;
// fire off peer disconnected callback if we have one // fire off peer disconnected callback if we have one
@ -895,7 +900,7 @@ void Network::close()
uint8_t buffer[1U]; uint8_t buffer[1U];
::memset(buffer, 0x00U, 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(); m_socket->close();
@ -934,7 +939,7 @@ bool Network::writeLogin()
uint8_t buffer[8U]; uint8_t buffer[8U];
::memcpy(buffer + 0U, TAG_REPEATER_LOGIN, 4U); ::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) if (m_debug)
Utils::dump(1U, "Network Message, Login", buffer, 8U); Utils::dump(1U, "Network Message, Login", buffer, 8U);
@ -962,7 +967,7 @@ bool Network::writeAuthorisation()
uint8_t out[40U]; uint8_t out[40U];
::memcpy(out + 0U, TAG_REPEATER_AUTH, 4U); ::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; edac::SHA256 sha256;
sha256.buffer(in, (uint32_t)(size + sizeof(uint32_t)), out + 8U); sha256.buffer(in, (uint32_t)(size + sizeof(uint32_t)), out + 8U);
@ -1025,8 +1030,7 @@ bool Network::writeConfig()
json::value v = json::value(config); json::value v = json::value(config);
std::string json = v.serialize(); std::string json = v.serialize();
CharArray __buffer = std::make_unique<char[]>(json.length() + 9U); DECLARE_CHAR_ARRAY(buffer, json.length() + 9U);
char* buffer = __buffer.get();
::memcpy(buffer + 0U, TAG_REPEATER_CONFIG, 4U); ::memcpy(buffer + 0U, TAG_REPEATER_CONFIG, 4U);
::snprintf(buffer + 8U, json.length() + 1U, "%s", json.c_str()); ::snprintf(buffer + 8U, json.length() + 1U, "%s", json.c_str());

@ -222,7 +222,7 @@ namespace network
/** /**
* @brief Last received RTP sequence number. * @brief Last received RTP sequence number.
*/ */
__READONLY_PROPERTY_PLAIN(uint16_t, pktLastSeq); DECLARE_RO_PROPERTY_PLAIN(uint16_t, pktLastSeq);
protected: protected:
std::string m_address; 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); assert(data != nullptr);
m_crc16 = (data[0U] << 8) | (data[1U] << 0); // CRC-16 m_crc16 = (data[0U] << 8) | (data[1U] << 0); // CRC-16
m_func = __GET_UINT16B(data, 2U); // Function m_func = GET_UINT16(data, 2U); // Function
m_messageLength = __GET_UINT32(data, 4U); // Message Length m_messageLength = GET_UINT32(data, 4U); // Message Length
return true; return true;
} }
@ -54,7 +54,7 @@ void RPCHeader::encode(uint8_t* data)
data[0U] = (m_crc16 >> 8) & 0xFFU; // CRC-16 MSB data[0U] = (m_crc16 >> 8) & 0xFFU; // CRC-16 MSB
data[1U] = (m_crc16 >> 0) & 0xFFU; // CRC-16 LSB 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. * @brief Payload packet CRC-16.
*/ */
__PROPERTY(uint16_t, crc16, CRC); DECLARE_PROPERTY(uint16_t, crc16, CRC);
/** /**
* @brief Function. * @brief Function.
*/ */
__PROPERTY(uint16_t, func, Function); DECLARE_PROPERTY(uint16_t, func, Function);
/** /**
* @brief Message Length. * @brief Message Length.
*/ */
__PROPERTY(uint32_t, messageLength, MessageLength); DECLARE_PROPERTY(uint32_t, messageLength, MessageLength);
}; };
} // namespace frame } // namespace frame
} // namespace network } // namespace network

@ -73,11 +73,11 @@ namespace network
/** /**
* @brief Format of the extension header payload contained within the packet. * @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). * @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 frame
} // namespace network } // namespace network

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

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

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

@ -85,39 +85,39 @@ namespace network
/** /**
* @brief RTP Protocol Version. * @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. * @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. * @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. * @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. * @brief Flag indicating application-specific behavior.
*/ */
__PROPERTY(bool, marker, Marker); DECLARE_PROPERTY(bool, marker, Marker);
/** /**
* @brief Format of the payload contained within the packet. * @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. * @brief Sequence number for the RTP packet.
*/ */
__PROPERTY(uint16_t, seq, Sequence); DECLARE_PROPERTY(uint16_t, seq, Sequence);
/** /**
* @brief RTP packet timestamp. * @brief RTP packet timestamp.
*/ */
__PROPERTY(uint32_t, timestamp, Timestamp); DECLARE_PROPERTY(uint32_t, timestamp, Timestamp);
/** /**
* @brief Synchronization Source ID. * @brief Synchronization Source ID.
*/ */
__PROPERTY(uint32_t, ssrc, SSRC); DECLARE_PROPERTY(uint32_t, ssrc, SSRC);
private: private:
static std::chrono::time_point<std::chrono::high_resolution_clock> m_wcStart; static std::chrono::time_point<std::chrono::high_resolution_clock> m_wcStart;

@ -106,6 +106,12 @@ bool RawFrameQueue::write(const uint8_t* message, uint32_t length, sockaddr_stor
if (m_debug) if (m_debug)
Utils::dump(1U, "RawFrameQueue::write() Message", buffer, length); 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; bool ret = true;
if (!m_socket->write(buffer, length, addr, addrLen, lenWritten)) { if (!m_socket->write(buffer, length, addr, addrLen, lenWritten)) {
// LogError(LOG_NET, "Failed writing data to the network"); // 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); 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]; uint8_t* buffer = new uint8_t[length];
::memset(buffer, 0x00U, length); ::memset(buffer, 0x00U, length);
::memcpy(buffer, message, length); ::memcpy(buffer, message, length);

@ -29,6 +29,7 @@ namespace network
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
const uint32_t DATA_PACKET_LENGTH = 8192U; const uint32_t DATA_PACKET_LENGTH = 8192U;
const uint32_t OVERSIZED_PACKET_WARN = 1536U;
const uint8_t MAX_FAILED_READ_CNT_LOGGING = 5U; 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? // 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) { if (magic == AES_WRAPPED_PCKT_MAGIC) {
uint32_t cryptedLen = (len - 2U) * sizeof(uint8_t); uint32_t cryptedLen = (len - 2U) * sizeof(uint8_t);
uint8_t* cryptoBuffer = buffer + 2U; uint8_t* cryptoBuffer = buffer + 2U;
@ -347,7 +347,7 @@ bool Socket::write(const uint8_t* buffer, uint32_t length, const sockaddr_storag
delete[] cryptoBuffer; delete[] cryptoBuffer;
if (crypted != nullptr) { if (crypted != nullptr) {
::memcpy(out.get() + 2U, crypted, cryptedLen); ::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; delete[] crypted;
length = cryptedLen + 2U; length = cryptedLen + 2U;
} else { } else {
@ -494,10 +494,9 @@ bool Socket::write(BufferVector& buffers, ssize_t* lenWritten) noexcept
// Utils::dump(1U, "Socket::write() crypted", crypted, cryptedLen); // Utils::dump(1U, "Socket::write() crypted", crypted, cryptedLen);
// finalize // finalize
UInt8Array __outBuf = std::make_unique<uint8_t[]>(cryptedLen + 2U); DECLARE_UINT8_ARRAY(out, cryptedLen + 2U);
uint8_t* out = __outBuf.get();
::memcpy(out + 2U, crypted, cryptedLen); ::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 // cleanup buffers and replace with new
delete[] crypted; delete[] crypted;

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

@ -173,39 +173,39 @@ namespace nxdn
/** /**
* @brief NXDN location ID. * @brief NXDN location ID.
*/ */
__READONLY_PROPERTY_PLAIN(uint32_t, locId); DECLARE_RO_PROPERTY_PLAIN(uint32_t, locId);
/** /**
* @brief Channel ID. * @brief Channel ID.
*/ */
__READONLY_PROPERTY_PLAIN(uint8_t, channelId); DECLARE_RO_PROPERTY_PLAIN(uint8_t, channelId);
/** /**
* @brief Channel number. * @brief Channel number.
*/ */
__READONLY_PROPERTY_PLAIN(uint32_t, channelNo); DECLARE_RO_PROPERTY_PLAIN(uint32_t, channelNo);
/** /**
* @brief Site Information 1. * @brief Site Information 1.
*/ */
__READONLY_PROPERTY_PLAIN(uint8_t, siteInfo1); DECLARE_RO_PROPERTY_PLAIN(uint8_t, siteInfo1);
/** /**
* @brief Site Information 2. * @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. * @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. * @brief Callsign.
*/ */
__READONLY_PROPERTY_PLAIN(std::string, callsign); DECLARE_RO_PROPERTY_PLAIN(std::string, callsign);
/** /**
* @brief NXDN require registration. * @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. * @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 } // namespace nxdn

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

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

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

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

@ -65,45 +65,45 @@ namespace nxdn
/** /**
* @brief Flag indicating if confirmed delivery is needed. * @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. * @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. * @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. * @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. * @brief Flag indicating the first fragment.
*/ */
__PROPERTY(bool, start, Start); DECLARE_PROPERTY(bool, start, Start);
/** /**
* @brief Flag indicating if the Tx fragment count circulates. * @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. * @brief The number and sequence of fragments.
*/ */
__PROPERTY(uint16_t, fragmentCount, FragmentCount); DECLARE_PROPERTY(uint16_t, fragmentCount, FragmentCount);
// Response Data // Response Data
/** /**
* @brief Response class. * @brief Response class.
*/ */
__PROPERTY(uint8_t, rspClass, ResponseClass); DECLARE_PROPERTY(uint8_t, rspClass, ResponseClass);
/** /**
* @brief Response type. * @brief Response type.
*/ */
__PROPERTY(uint8_t, rspType, ResponseType); DECLARE_PROPERTY(uint8_t, rspType, ResponseType);
/** /**
* @brief Error Block Flag. * @brief Error Block Flag.
*/ */
__PROPERTY(uint16_t, rspErrorBlock, ResponseErrorBlock); DECLARE_PROPERTY(uint16_t, rspErrorBlock, ResponseErrorBlock);
}; };
} // namespace lc } // namespace lc
} // namespace nxdn } // namespace nxdn

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

@ -89,92 +89,92 @@ namespace nxdn
/** /**
* @brief Message Type * @brief Message Type
*/ */
__PROPERTY(uint8_t, messageType, MessageType); DECLARE_PROPERTY(uint8_t, messageType, MessageType);
/** /**
* @brief Call Type * @brief Call Type
*/ */
__PROPERTY(uint8_t, callType, CallType); DECLARE_PROPERTY(uint8_t, callType, CallType);
/** /**
* @brief Source ID. * @brief Source ID.
*/ */
__PROPERTY(uint16_t, srcId, SrcId); DECLARE_PROPERTY(uint16_t, srcId, SrcId);
/** /**
* @brief Destination ID. * @brief Destination ID.
*/ */
__PROPERTY(uint16_t, dstId, DstId); DECLARE_PROPERTY(uint16_t, dstId, DstId);
/** @} */ /** @} */
/** @name Common Call Options */ /** @name Common Call Options */
/** /**
* @brief Flag indicating the emergency bits are set. * @brief Flag indicating the emergency bits are set.
*/ */
__PROPERTY(bool, emergency, Emergency); DECLARE_PROPERTY(bool, emergency, Emergency);
/** /**
* @brief Flag indicating that encryption is enabled. * @brief Flag indicating that encryption is enabled.
*/ */
__PROPERTY(bool, encrypted, Encrypted); DECLARE_PROPERTY(bool, encrypted, Encrypted);
/** /**
* @brief Flag indicating priority paging. * @brief Flag indicating priority paging.
*/ */
__PROPERTY(bool, priority, Priority); DECLARE_PROPERTY(bool, priority, Priority);
/** /**
* @brief Flag indicating a group/talkgroup operation. * @brief Flag indicating a group/talkgroup operation.
*/ */
__PROPERTY(bool, group, Group); DECLARE_PROPERTY(bool, group, Group);
/** /**
* @brief Flag indicating a half/full duplex operation. * @brief Flag indicating a half/full duplex operation.
*/ */
__PROPERTY(bool, duplex, Duplex); DECLARE_PROPERTY(bool, duplex, Duplex);
/** /**
* @brief Transmission mode. * @brief Transmission mode.
*/ */
__PROPERTY(uint8_t, transmissionMode, TransmissionMode); DECLARE_PROPERTY(uint8_t, transmissionMode, TransmissionMode);
/** @} */ /** @} */
/** @name Data Call Data */ /** @name Data Call Data */
/** /**
* @brief Data packet information. * @brief Data packet information.
*/ */
__PROPERTY(PacketInformation, packetInfo, PacketInfo); DECLARE_PROPERTY(PacketInformation, packetInfo, PacketInfo);
/** /**
* @brief Data packet information. * @brief Data packet information.
*/ */
__PROPERTY(PacketInformation, rsp, Response); DECLARE_PROPERTY(PacketInformation, rsp, Response);
/** /**
* @brief Data packet frame number. * @brief Data packet frame number.
*/ */
__PROPERTY(uint8_t, dataFrameNumber, DataFrameNumber); DECLARE_PROPERTY(uint8_t, dataFrameNumber, DataFrameNumber);
/** /**
* @brief Data packet block number. * @brief Data packet block number.
*/ */
__PROPERTY(uint8_t, dataBlockNumber, DataBlockNumber); DECLARE_PROPERTY(uint8_t, dataBlockNumber, DataBlockNumber);
/** @} */ /** @} */
/** @name Header Delay Data */ /** @name Header Delay Data */
/** /**
* @brief Delay count. * @brief Delay count.
*/ */
__PROPERTY(uint16_t, delayCount, DelayCount); DECLARE_PROPERTY(uint16_t, delayCount, DelayCount);
/** @} */ /** @} */
/** @name Encryption data */ /** @name Encryption data */
/** /**
* @brief Encryption algorithm ID. * @brief Encryption algorithm ID.
*/ */
__PROPERTY(uint8_t, algId, AlgId); DECLARE_PROPERTY(uint8_t, algId, AlgId);
/** /**
* @brief Encryption key ID. * @brief Encryption key ID.
*/ */
__PROPERTY(uint8_t, kId, KId); DECLARE_PROPERTY(uint8_t, kId, KId);
/** @} */ /** @} */
/** /**
* @brief Cause Response. * @brief Cause Response.
*/ */
__PROPERTY(uint8_t, causeRsp, CauseResponse); DECLARE_PROPERTY(uint8_t, causeRsp, CauseResponse);
private: private:
static bool m_verbose; 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); ::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
rcch[1U] = (m_regOption << 3) + // Registration Option 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; uint16_t systemCode = (m_siteData.locId() >> 12U) << 7U;
rcch[2U] = (systemCode >> 8U) & 0x03U; // ... rcch[2U] = (systemCode >> 8U) & 0x03U; // ...

@ -66,25 +66,25 @@ namespace nxdn
/** /**
* @brief Count of BCCH frames per RCCH superframe. * @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. * @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. * @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. * @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. * @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 rcch
} // namespace lc } // namespace lc

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

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

@ -260,55 +260,55 @@ namespace p25
/** /**
* @brief P25 location resource area. * @brief P25 location resource area.
*/ */
__READONLY_PROPERTY_PLAIN(uint8_t, lra); DECLARE_RO_PROPERTY_PLAIN(uint8_t, lra);
/** /**
* @brief P25 network ID. * @brief P25 network ID.
*/ */
__READONLY_PROPERTY_PLAIN(uint32_t, netId); DECLARE_RO_PROPERTY_PLAIN(uint32_t, netId);
/** /**
* @brief Gets the P25 system ID. * @brief Gets the P25 system ID.
*/ */
__READONLY_PROPERTY_PLAIN(uint32_t, sysId); DECLARE_RO_PROPERTY_PLAIN(uint32_t, sysId);
/** /**
* @brief P25 RFSS ID. * @brief P25 RFSS ID.
*/ */
__READONLY_PROPERTY_PLAIN(uint8_t, rfssId); DECLARE_RO_PROPERTY_PLAIN(uint8_t, rfssId);
/** /**
* @brief P25 site ID. * @brief P25 site ID.
*/ */
__READONLY_PROPERTY_PLAIN(uint8_t, siteId); DECLARE_RO_PROPERTY_PLAIN(uint8_t, siteId);
/** /**
* @brief Channel ID. * @brief Channel ID.
*/ */
__READONLY_PROPERTY_PLAIN(uint8_t, channelId); DECLARE_RO_PROPERTY_PLAIN(uint8_t, channelId);
/** /**
* @brief Channel number. * @brief Channel number.
*/ */
__READONLY_PROPERTY_PLAIN(uint32_t, channelNo); DECLARE_RO_PROPERTY_PLAIN(uint32_t, channelNo);
/** /**
* @brief Service class. * @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. * @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. * @brief Callsign.
*/ */
__READONLY_PROPERTY_PLAIN(std::string, callsign); DECLARE_RO_PROPERTY_PLAIN(std::string, callsign);
/** /**
* @brief Count of available channels. * @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. * @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. * @brief Local Time Offset.
*/ */
__READONLY_PROPERTY_PLAIN(int8_t, lto); DECLARE_RO_PROPERTY_PLAIN(int8_t, lto);
/** @} */ /** @} */
}; };
} // namespace p25 } // namespace p25

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

@ -129,97 +129,97 @@ namespace p25
/** /**
* @brief Flag indicating if acknowledgement is needed. * @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. * @brief Flag indicating if this is an outbound data packet.
*/ */
__PROPERTY(bool, outbound, Outbound); DECLARE_PROPERTY(bool, outbound, Outbound);
/** /**
* @brief Data packet format. * @brief Data packet format.
*/ */
__PROPERTY(uint8_t, fmt, Format); DECLARE_PROPERTY(uint8_t, fmt, Format);
/** /**
* @brief Service access point. * @brief Service access point.
*/ */
__PROPERTY(uint8_t, sap, SAP); DECLARE_PROPERTY(uint8_t, sap, SAP);
/** /**
* @brief Manufacturer ID. * @brief Manufacturer ID.
*/ */
__PROPERTY(uint8_t, mfId, MFId); DECLARE_PROPERTY(uint8_t, mfId, MFId);
/** /**
* @brief Logical link ID. * @brief Logical link ID.
*/ */
__PROPERTY(uint32_t, llId, LLId); DECLARE_PROPERTY(uint32_t, llId, LLId);
/** /**
* @brief Total number of blocks following this header. * @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. * @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. * @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. * @brief Synchronize Flag.
*/ */
__PROPERTY(bool, S, Synchronize); DECLARE_PROPERTY(bool, S, Synchronize);
/** /**
* @brief Fragment Sequence Number. * @brief Fragment Sequence Number.
*/ */
__PROPERTY(uint8_t, fsn, FSN); DECLARE_PROPERTY(uint8_t, fsn, FSN);
/** /**
* @brief Send Sequence Number. * @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. * @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. * @brief Offset of the header.
*/ */
__PROPERTY(uint8_t, headerOffset, HeaderOffset); DECLARE_PROPERTY(uint8_t, headerOffset, HeaderOffset);
// Extended Addressing Data // Extended Addressing Data
/** /**
* @brief Service access point. * @brief Service access point.
*/ */
__PROPERTY(uint8_t, exSap, EXSAP); DECLARE_PROPERTY(uint8_t, exSap, EXSAP);
/** /**
* @brief Source Logical link ID. * @brief Source Logical link ID.
*/ */
__PROPERTY(uint32_t, srcLlId, SrcLLId); DECLARE_PROPERTY(uint32_t, srcLlId, SrcLLId);
// Response Data // Response Data
/** /**
* @brief Response class. * @brief Response class.
*/ */
__PROPERTY(uint8_t, rspClass, ResponseClass); DECLARE_PROPERTY(uint8_t, rspClass, ResponseClass);
/** /**
* @brief Response type. * @brief Response type.
*/ */
__PROPERTY(uint8_t, rspType, ResponseType); DECLARE_PROPERTY(uint8_t, rspType, ResponseType);
/** /**
* @brief Response status. * @brief Response status.
*/ */
__PROPERTY(uint8_t, rspStatus, ResponseStatus); DECLARE_PROPERTY(uint8_t, rspStatus, ResponseStatus);
// AMBT Data // AMBT Data
/** /**
* @brief Alternate Trunking Block Opcode * @brief Alternate Trunking Block Opcode
*/ */
__PROPERTY(uint8_t, ambtOpcode, AMBTOpcode); DECLARE_PROPERTY(uint8_t, ambtOpcode, AMBTOpcode);
/** /**
* @brief Alternate Trunking Block Field 8 * @brief Alternate Trunking Block Field 8
*/ */
__PROPERTY(uint8_t, ambtField8, AMBTField8); DECLARE_PROPERTY(uint8_t, ambtField8, AMBTField8);
/** /**
* @brief Alternate Trunking Block Field 9 * @brief Alternate Trunking Block Field 9
*/ */
__PROPERTY(uint8_t, ambtField9, AMBTField9); DECLARE_PROPERTY(uint8_t, ambtField9, AMBTField9);
private: private:
edac::Trellis m_trellis; edac::Trellis m_trellis;

@ -11,6 +11,7 @@
#include "Defines.h" #include "Defines.h"
#include "p25/data/LowSpeedData.h" #include "p25/data/LowSpeedData.h"
#include "p25/P25Utils.h" #include "p25/P25Utils.h"
#include "Utils.h"
using namespace p25; using namespace p25;
using namespace p25::data; 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_lsd1 = lsd[0U];
m_lsd2 = lsd[2U]; m_lsd2 = lsd[2U];

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

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

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

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

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

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

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

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

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

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

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

@ -47,7 +47,7 @@ bool StartOfStream::decode(const uint8_t* data)
{ {
assert(data != nullptr); 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 m_errorCount = (data[2U] & 0x0FU); // Error Count
return true; return true;
@ -59,6 +59,6 @@ void StartOfStream::encode(uint8_t* data)
{ {
assert(data != nullptr); 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 data[2U] = m_errorCount & 0x0FU; // Error Count
} }

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

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

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

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

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

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

@ -45,7 +45,7 @@ bool KMMDeregistrationCommand::decode(const uint8_t* data)
KMMFrame::decodeHeader(data); KMMFrame::decodeHeader(data);
m_bodyFormat = data[10U]; // Body Format m_bodyFormat = data[10U]; // Body Format
m_kmfRSI = __GET_UINT16(data, 11U); // KMF RSI m_kmfRSI = GET_UINT24(data, 11U); // KMF RSI
return true; return true;
} }
@ -61,7 +61,7 @@ void KMMDeregistrationCommand::encode(uint8_t* data)
KMMFrame::encodeHeader(data); KMMFrame::encodeHeader(data);
data[10U] = m_bodyFormat; // Body Format 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 * @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 kmm
} // namespace p25 } // namespace p25

@ -69,11 +69,11 @@ namespace p25
public: 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 kmm
} // namespace p25 } // 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.