Merge branch 'master' into incall_ctrl

pull/86/head
Bryan Biedenkapp 12 months ago
commit 3177d38897

@ -57,15 +57,15 @@ if (COMPILE_WIN32)
set(ENABLE_TCP_SSL OFF) set(ENABLE_TCP_SSL OFF)
message(CHECK_START "Enable TCP SSL support - no; for simplicity WIN32 does not support TCP SSL.") message(CHECK_START "Enable TCP SSL support - no; for simplicity WIN32 does not support TCP SSL.")
else() else()
set(CMAKE_C_COMPILER /usr/bin/gcc) set(CMAKE_C_COMPILER /usr/bin/gcc CACHE STRING "C compiler")
set(CMAKE_CXX_COMPILER /usr/bin/g++) set(CMAKE_CXX_COMPILER /usr/bin/g++ CACHE STRING "C++ compiler")
set(ARCH amd64) set(ARCH amd64)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE amd64) set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE amd64)
endif (COMPILE_WIN32) endif (COMPILE_WIN32)
if (CROSS_COMPILE_ARM) if (CROSS_COMPILE_ARM)
set(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabihf-gcc) set(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabihf-gcc CACHE STRING "C compiler")
set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabihf-g++) set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabihf-g++ CACHE STRING "C++ compiler")
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)
@ -73,8 +73,8 @@ if (CROSS_COMPILE_ARM)
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)
set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc) set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc CACHE STRING "C compiler")
set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++) set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++ CACHE STRING "C++ compiler")
set(ARCH arm64) set(ARCH arm64)
set(CMAKE_SYSTEM_PROCESSOR arm64) set(CMAKE_SYSTEM_PROCESSOR arm64)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE arm64) set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE arm64)
@ -97,16 +97,16 @@ if (CROSS_COMPILE_RPI_ARM)
GIT_REPOSITORY https://github.com/raspberrypi/tools.git GIT_REPOSITORY https://github.com/raspberrypi/tools.git
) )
FetchContent_MakeAvailable(RPiTools) FetchContent_MakeAvailable(RPiTools)
set(CMAKE_C_COMPILER ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc) set(CMAKE_C_COMPILER ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc CACHE STRING "C compiler" FORCE)
set(CMAKE_CXX_COMPILER ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-g++) set(CMAKE_CXX_COMPILER ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ CACHE STRING "C++ compiler" FORCE)
message(CHECK_START "Apply OpenSSL library binaries for cross compling (old RPi) 32-bit ARM - ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src") message(CHECK_START "Apply OpenSSL library binaries for cross compling (old RPi) 32-bit ARM - ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src")
execute_process(COMMAND tar xzf contrib/openssl_cross_patch.RPI_ARM.tar.gz -C ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}) execute_process(COMMAND tar xzf contrib/openssl_cross_patch.RPI_ARM.tar.gz -C ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
set(OPENSSL_ROOT_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/arm-linux-gnueabihf/sysroot/usr/lib) set(OPENSSL_ROOT_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/rpitools-src/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/arm-linux-gnueabihf/sysroot/usr/lib)
else() else()
set(CMAKE_C_COMPILER ${RPI_ARM_TOOLS}/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc) set(CMAKE_C_COMPILER ${RPI_ARM_TOOLS}/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc CACHE STRING "C compiler" FORCE)
set(CMAKE_CXX_COMPILER ${RPI_ARM_TOOLS}/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-g++) set(CMAKE_CXX_COMPILER ${RPI_ARM_TOOLS}/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ CACHE STRING "C++ compiler" FORCE)
message(CHECK_START "Apply OpenSSL library binaries for cross compling (old RPi) 32-bit ARM - ${RPI_ARM_TOOLS}") message(CHECK_START "Apply OpenSSL library binaries for cross compling (old RPi) 32-bit ARM - ${RPI_ARM_TOOLS}")
execute_process(COMMAND tar xzf contrib/openssl_cross_patch.RPI_ARM.tar.gz -C ${RPI_ARM_TOOLS} WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}) execute_process(COMMAND tar xzf contrib/openssl_cross_patch.RPI_ARM.tar.gz -C ${RPI_ARM_TOOLS} WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
@ -538,7 +538,7 @@ add_custom_target(old_install
COMMAND install -m 644 ../configs/fne-config.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/fne-config.example.yml COMMAND install -m 644 ../configs/fne-config.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/fne-config.example.yml
COMMAND install -m 644 ../configs/fne-sysview.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/fne-sysview.example.yml COMMAND install -m 644 ../configs/fne-sysview.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/fne-sysview.example.yml
COMMAND install -m 644 ../configs/monitor-config.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/monitor-config.example.yml COMMAND install -m 644 ../configs/monitor-config.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/monitor-config.example.yml
COMMAND install -m 644 ../configs/iden_table.dat ${CMAKE_LEGACY_INSTALL_PREFIX}/iden_table.dat COMMAND install -m 644 ../configs/iden_table.example.dat ${CMAKE_LEGACY_INSTALL_PREFIX}/iden_table.example.dat
COMMAND install -m 644 ../configs/RSSI.dat ${CMAKE_LEGACY_INSTALL_PREFIX}/RSSI.dat COMMAND install -m 644 ../configs/RSSI.dat ${CMAKE_LEGACY_INSTALL_PREFIX}/RSSI.dat
COMMAND install -m 644 ../configs/rid_acl.example.dat ${CMAKE_LEGACY_INSTALL_PREFIX}/rid_acl.dat COMMAND install -m 644 ../configs/rid_acl.example.dat ${CMAKE_LEGACY_INSTALL_PREFIX}/rid_acl.dat
COMMAND install -m 644 ../configs/talkgroup_rules.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/talkgroup_rules.example.yml COMMAND install -m 644 ../configs/talkgroup_rules.example.yml ${CMAKE_LEGACY_INSTALL_PREFIX}/talkgroup_rules.example.yml
@ -580,9 +580,9 @@ add_custom_target(old_install-service
COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/fne-config.example.yml COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/fne-config.example.yml
COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/fne-sysview.example.yml COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/fne-sysview.example.yml
COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/monitor-config.example.yml COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/monitor-config.example.yml
COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/iden_table.dat COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/iden_table.example.dat
COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/RSSI.dat COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/RSSI.dat
COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/rid_acl.dat COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/rid_acl.example.dat
COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/talkgroup_rules.example.yml COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/talkgroup_rules.example.yml
COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/bridge-config.example.yml COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/bridge-config.example.yml
COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/log COMMAND chown dvmhost:dvmhost ${CMAKE_LEGACY_INSTALL_PREFIX}/log

@ -73,6 +73,9 @@ network:
# Flag indicating UDP audio should be transmitted without the length leader. # Flag indicating UDP audio should be transmitted without the length leader.
# NOTE: This flag is only applicable when encoding G.711 uLaw. # NOTE: This flag is only applicable when encoding G.711 uLaw.
udpNoIncludeLength: false udpNoIncludeLength: false
# Flag indicating UDP audio should be RTP framed.
# NOTE: This flag is only applicable when encoding G.711 uLaw.
udpRTPFrames: false
# Source "Radio ID" for transmitted audio frames. # Source "Radio ID" for transmitted audio frames.
sourceId: 1234567 sourceId: 1234567
@ -140,3 +143,8 @@ system:
# Enable local audio over speakers. # Enable local audio over speakers.
localAudio: true localAudio: true
# Flag indicating whether or not trace logging is enabled.
trace: false
# Flag indicating whether or not debug logging is enabled.
debug: false

@ -225,6 +225,8 @@ protocols:
legacyGroupReg: false legacyGroupReg: false
# Flag indicating the host should send a network grant demand TDU for conventional traffic. # Flag indicating the host should send a network grant demand TDU for conventional traffic.
convNetGrantDemand: false convNetGrantDemand: false
# Flag indicating the host should demand a full unit registration for a refused affiliation request.
demandUnitRegForRefusedAff: true
# Flag indicating the host should verify group affiliation. # Flag indicating the host should verify group affiliation.
verifyAff: false verifyAff: false
# Flag indicating the host should verify unit registration. # Flag indicating the host should verify unit registration.

@ -4,7 +4,7 @@
* 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) 2024 Bryan Biedenkapp, N2PLL * Copyright (C) 2024-2025 Bryan Biedenkapp, N2PLL
* *
*/ */
#include "Defines.h" #include "Defines.h"
@ -19,6 +19,7 @@
#include "common/p25/dfsi/LC.h" #include "common/p25/dfsi/LC.h"
#include "common/p25/lc/LC.h" #include "common/p25/lc/LC.h"
#include "common/p25/P25Utils.h" #include "common/p25/P25Utils.h"
#include "common/network/RTPHeader.h"
#include "common/network/udp/Socket.h" #include "common/network/udp/Socket.h"
#include "common/Log.h" #include "common/Log.h"
#include "common/StopWatch.h" #include "common/StopWatch.h"
@ -30,6 +31,7 @@
#include "SampleTimeConversion.h" #include "SampleTimeConversion.h"
using namespace network; using namespace network;
using namespace network::frame;
using namespace network::udp; using namespace network::udp;
#include <cstdio> #include <cstdio>
@ -67,6 +69,8 @@ static short seg_uend[8] = { 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FF
#define BIAS (0x84) // bias for linear code #define BIAS (0x84) // bias for linear code
#define CLIP 8159 #define CLIP 8159
const uint8_t RTP_G711_PAYLOAD_TYPE = 0x00U;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Static Class Members // Static Class Members
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -161,17 +165,17 @@ static short search(short val, short* table, short size)
/* Helper to convert PCM into G.711 aLaw. */ /* Helper to convert PCM into G.711 aLaw. */
uint8_t pcmToaLaw(short pcm) uint8_t encodeALaw(short pcm)
{ {
short mask; short mask;
unsigned char aval; uint8_t aval;
pcm = pcm >> 3; pcm = pcm >> 3;
if (pcm >= 0) { if (pcm >= 0) {
mask = 0xD5; // sign (7th) bit = 1 mask = 0xD5U; // sign (7th) bit = 1
} else { } else {
mask = 0x55; // sign bit = 0 mask = 0x55U; // sign bit = 0
pcm = -pcm - 1; pcm = -pcm - 1;
} }
@ -196,9 +200,9 @@ uint8_t pcmToaLaw(short pcm)
/* Helper to convert G.711 aLaw into PCM. */ /* Helper to convert G.711 aLaw into PCM. */
short aLawToPCM(uint8_t alaw) short decodeALaw(uint8_t alaw)
{ {
alaw ^= 0x55; alaw ^= 0x55U;
short t = (alaw & QUANT_MASK) << 4; short t = (alaw & QUANT_MASK) << 4;
short seg = ((unsigned)alaw & SEG_MASK) >> SEG_SHIFT; short seg = ((unsigned)alaw & SEG_MASK) >> SEG_SHIFT;
@ -207,19 +211,19 @@ short aLawToPCM(uint8_t alaw)
t += 8; t += 8;
break; break;
case 1: case 1:
t += 0x108; t += 0x108U;
break; break;
default: default:
t += 0x108; t += 0x108U;
t <<= seg - 1; t <<= seg - 1;
} }
return ((alaw & SIGN_BIT) ? t : -t); return ((alaw & SIGN_BIT) ? t : -t);
} }
/* Helper to convert PCM into G.711 uLaw. */ /* Helper to convert PCM into G.711 MuLaw. */
uint8_t pcmTouLaw(short pcm) uint8_t encodeMuLaw(short pcm)
{ {
short mask; short mask;
@ -252,9 +256,9 @@ uint8_t pcmTouLaw(short pcm)
} }
} }
/* Helper to convert G.711 uLaw into PCM. */ /* Helper to convert G.711 MuLaw into PCM. */
short uLawToPCM(uint8_t ulaw) short decodeMuLaw(uint8_t ulaw)
{ {
// complement to obtain normal u-law value // complement to obtain normal u-law value
ulaw = ~ulaw; ulaw = ~ulaw;
@ -288,6 +292,7 @@ HostBridge::HostBridge(const std::string& confFile) :
m_udpReceiveAddress("127.0.0.1"), m_udpReceiveAddress("127.0.0.1"),
m_udpNoIncludeLength(false), m_udpNoIncludeLength(false),
m_udpUseULaw(false), m_udpUseULaw(false),
m_udpRTPFrames(false),
m_srcId(p25::defines::WUID_FNE), m_srcId(p25::defines::WUID_FNE),
m_srcIdOverride(0U), m_srcIdOverride(0U),
m_overrideSrcIdFromMDC(false), m_overrideSrcIdFromMDC(false),
@ -345,7 +350,10 @@ HostBridge::HostBridge(const std::string& confFile) :
m_detectedSampleCnt(0U), m_detectedSampleCnt(0U),
m_dumpSampleLevel(false), m_dumpSampleLevel(false),
m_running(false), m_running(false),
m_debug(false) m_trace(false),
m_debug(false),
m_rtpSeqNo(0U),
m_rtpTimestamp(INVALID_TS)
#if defined(_WIN32) #if defined(_WIN32)
, ,
m_encoderState(nullptr), m_encoderState(nullptr),
@ -962,6 +970,9 @@ bool HostBridge::readParams()
yaml::Node networkConf = m_conf["network"]; yaml::Node networkConf = m_conf["network"];
m_udpAudio = networkConf["udpAudio"].as<bool>(false); m_udpAudio = networkConf["udpAudio"].as<bool>(false);
m_trace = systemConf["trace"].as<bool>(false);
m_debug = systemConf["debug"].as<bool>(false);
LogInfo("General Parameters"); LogInfo("General Parameters");
LogInfo(" Rx Audio Gain: %.1f", m_rxAudioGain); LogInfo(" Rx Audio Gain: %.1f", m_rxAudioGain);
LogInfo(" Vocoder Decoder Audio Gain: %.1f", m_vocoderDecoderAudioGain); LogInfo(" Vocoder Decoder Audio Gain: %.1f", m_vocoderDecoderAudioGain);
@ -980,6 +991,10 @@ bool HostBridge::readParams()
LogInfo(" Local Audio: %s", m_localAudio ? "yes" : "no"); LogInfo(" Local Audio: %s", m_localAudio ? "yes" : "no");
LogInfo(" UDP Audio: %s", m_udpAudio ? "yes" : "no"); LogInfo(" UDP Audio: %s", m_udpAudio ? "yes" : "no");
if (m_debug) {
LogInfo(" Debug: yes");
}
return true; return true;
} }
@ -1005,8 +1020,12 @@ bool HostBridge::createNetwork()
m_udpReceiveAddress = networkConf["udpReceiveAddress"].as<std::string>(); m_udpReceiveAddress = networkConf["udpReceiveAddress"].as<std::string>();
m_udpUseULaw = networkConf["udpUseULaw"].as<bool>(false); m_udpUseULaw = networkConf["udpUseULaw"].as<bool>(false);
if (m_udpUseULaw) if (m_udpUseULaw) {
m_udpNoIncludeLength = networkConf["udpNoIncludeLength"].as<bool>(false); m_udpNoIncludeLength = networkConf["udpNoIncludeLength"].as<bool>(false);
m_udpRTPFrames = networkConf["udpRTPFrames"].as<bool>(false);
if (m_udpRTPFrames)
m_udpNoIncludeLength = true; // RTP disables the length being included
}
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
@ -1072,9 +1091,10 @@ bool HostBridge::createNetwork()
LogInfo(" UDP Audio Send Port: %u", m_udpSendPort); LogInfo(" UDP Audio Send Port: %u", m_udpSendPort);
LogInfo(" UDP Audio Receive Address: %s", m_udpReceiveAddress.c_str()); LogInfo(" UDP Audio Receive Address: %s", m_udpReceiveAddress.c_str());
LogInfo(" UDP Audio Receive Port: %u", m_udpReceivePort); LogInfo(" UDP Audio Receive Port: %u", m_udpReceivePort);
LogInfo(" UDP Audio Use uLaw Encoding: %u", m_udpUseULaw ? "yes" : "no"); LogInfo(" UDP Audio Use uLaw Encoding: %s", m_udpUseULaw ? "yes" : "no");
if (m_udpUseULaw) { if (m_udpUseULaw) {
LogInfo(" UDP Audio No Length Header: %u", m_udpNoIncludeLength ? "yes" : "no"); LogInfo(" UDP Audio No Length Header: %s", m_udpNoIncludeLength ? "yes" : "no");
LogInfo(" UDP Audio RTP Framed: %s", m_udpRTPFrames ? "yes" : "no");
} }
} }
@ -1148,8 +1168,8 @@ void HostBridge::processUDPAudio()
} }
if (length > 0) { if (length > 0) {
if (m_debug) if (m_trace)
Utils::dump(1U, "UDP Audio Network Packet", buffer, length); Utils::dump(1U, "HostBridge()::processUDPAudio() Audio Network Packet", buffer, length);
uint32_t pcmLength = 0; uint32_t pcmLength = 0;
if (m_udpNoIncludeLength) { if (m_udpNoIncludeLength) {
@ -1158,15 +1178,31 @@ void HostBridge::processUDPAudio()
pcmLength = __GET_UINT32(buffer, 0U); pcmLength = __GET_UINT32(buffer, 0U);
} }
if (m_udpRTPFrames)
pcmLength = MBE_SAMPLES_LENGTH * 2U;
UInt8Array __pcm = std::make_unique<uint8_t[]>(pcmLength); UInt8Array __pcm = std::make_unique<uint8_t[]>(pcmLength);
uint8_t* pcm = __pcm.get(); uint8_t* pcm = __pcm.get();
if (m_udpRTPFrames) {
RTPHeader rtpHeader = RTPHeader();
rtpHeader.decode(buffer);
if (rtpHeader.getPayloadType() != RTP_G711_PAYLOAD_TYPE) {
LogError(LOG_HOST, "Invalid RTP payload type %u", rtpHeader.getPayloadType());
return;
}
::memcpy(pcm, buffer + RTP_HEADER_LENGTH_BYTES, MBE_SAMPLES_LENGTH * 2U);
}
else {
if (m_udpNoIncludeLength) { if (m_udpNoIncludeLength) {
::memcpy(pcm, buffer, pcmLength); ::memcpy(pcm, buffer, pcmLength);
} }
else { else {
::memcpy(pcm, buffer + 4U, pcmLength); ::memcpy(pcm, buffer + 4U, pcmLength);
} }
}
// Utils::dump(1U, "PCM RECV BYTE BUFFER", pcm, pcmLength); // Utils::dump(1U, "PCM RECV BYTE BUFFER", pcm, pcmLength);
@ -1183,10 +1219,20 @@ void HostBridge::processUDPAudio()
int smpIdx = 0; int smpIdx = 0;
short samples[MBE_SAMPLES_LENGTH]; short samples[MBE_SAMPLES_LENGTH];
if (m_udpUseULaw) { if (m_udpUseULaw) {
for (uint32_t pcmIdx = 0; pcmIdx < pcmLength; pcmIdx++) { if (m_trace)
samples[smpIdx] = uLawToPCM(pcm[pcmIdx]); Utils::dump(1U, "HostBridge()::processUDPAudio() uLaw Audio", pcm, MBE_SAMPLES_LENGTH * 2U);
for (uint32_t pcmIdx = 0; pcmIdx < MBE_SAMPLES_LENGTH; pcmIdx++) {
samples[smpIdx] = decodeMuLaw(pcm[pcmIdx]);
smpIdx++; smpIdx++;
} }
int pcmIdx = 0;
for (uint32_t smpIdx = 0; smpIdx < MBE_SAMPLES_LENGTH; smpIdx++) {
pcm[pcmIdx + 0] = (uint8_t)(samples[smpIdx] & 0xFF);
pcm[pcmIdx + 1] = (uint8_t)((samples[smpIdx] >> 8) & 0xFF);
pcmIdx += 2;
}
} }
else { else {
for (uint32_t pcmIdx = 0; pcmIdx < pcmLength; pcmIdx += 2) { for (uint32_t pcmIdx = 0; pcmIdx < pcmLength; pcmIdx += 2) {
@ -1379,6 +1425,9 @@ void HostBridge::processDMRNetwork(uint8_t* buffer, uint32_t length)
m_rxDMRPILC = lc::PrivacyLC(); m_rxDMRPILC = lc::PrivacyLC();
m_rxStartTime = 0U; m_rxStartTime = 0U;
m_rxStreamId = 0U; m_rxStreamId = 0U;
m_rtpSeqNo = 0U;
m_rtpTimestamp = INVALID_TS;
return; return;
} }
@ -1474,8 +1523,11 @@ void HostBridge::decodeDMRAudioFrame(uint8_t* ambe, uint32_t srcId, uint32_t dst
uint8_t pcm[MBE_SAMPLES_LENGTH * 2U]; uint8_t pcm[MBE_SAMPLES_LENGTH * 2U];
if (m_udpUseULaw) { if (m_udpUseULaw) {
for (uint32_t smpIdx = 0; smpIdx < MBE_SAMPLES_LENGTH; smpIdx++) { for (uint32_t smpIdx = 0; smpIdx < MBE_SAMPLES_LENGTH; smpIdx++) {
pcm[smpIdx] = pcmTouLaw(samples[smpIdx]); pcm[smpIdx] = encodeMuLaw(samples[smpIdx]);
} }
if (m_trace)
Utils::dump(1U, "HostBridge()::decodeDMRAudioFrame() Encoded uLaw Audio", pcm, MBE_SAMPLES_LENGTH);
} }
else { else {
for (uint32_t smpIdx = 0; smpIdx < MBE_SAMPLES_LENGTH; smpIdx++) { for (uint32_t smpIdx = 0; smpIdx < MBE_SAMPLES_LENGTH; smpIdx++) {
@ -1498,6 +1550,22 @@ void HostBridge::decodeDMRAudioFrame(uint8_t* ambe, uint32_t srcId, uint32_t dst
__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);
} }
// are we sending RTP audio frames?
if (m_udpRTPFrames) {
uint8_t* rtpFrame = generateRTPHeaders(MBE_SAMPLES_LENGTH, m_rtpSeqNo);
if (rtpFrame != nullptr) {
length += RTP_HEADER_LENGTH_BYTES;
uint8_t* newAudioData = new uint8_t[length];
::memcpy(newAudioData, rtpFrame, RTP_HEADER_LENGTH_BYTES);
::memcpy(newAudioData + RTP_HEADER_LENGTH_BYTES, audioData, MBE_SAMPLES_LENGTH);
delete[] audioData;
audioData = newAudioData;
}
m_rtpSeqNo++;
}
} }
else { else {
__SET_UINT32((MBE_SAMPLES_LENGTH * 2U), audioData, 0U); __SET_UINT32((MBE_SAMPLES_LENGTH * 2U), audioData, 0U);
@ -1583,6 +1651,9 @@ void HostBridge::encodeDMRAudioFrame(uint8_t* pcm, uint32_t forcedSrcId, uint32_
dmrData.setData(data); dmrData.setData(data);
LogMessage(LOG_HOST, DMR_DT_VOICE_LC_HEADER ", slot = %u, srcId = %u, dstId = %u, FLCO = $%02X", m_slot,
dmrLC.getSrcId(), dmrLC.getDstId(), dmrData.getFLCO());
m_network->writeDMR(dmrData, false); m_network->writeDMR(dmrData, false);
m_txStreamId = m_network->getDMRStreamId(m_slot); m_txStreamId = m_network->getDMRStreamId(m_slot);
@ -1798,6 +1869,9 @@ void HostBridge::processP25Network(uint8_t* buffer, uint32_t length)
m_rxP25LC = lc::LC(); m_rxP25LC = lc::LC();
m_rxStartTime = 0U; m_rxStartTime = 0U;
m_rxStreamId = 0U; m_rxStreamId = 0U;
m_rtpSeqNo = 0U;
m_rtpTimestamp = INVALID_TS;
return; return;
} }
@ -2040,8 +2114,11 @@ void HostBridge::decodeP25AudioFrame(uint8_t* ldu, uint32_t srcId, uint32_t dstI
uint8_t pcm[MBE_SAMPLES_LENGTH * 2U]; uint8_t pcm[MBE_SAMPLES_LENGTH * 2U];
if (m_udpUseULaw) { if (m_udpUseULaw) {
for (uint32_t smpIdx = 0; smpIdx < MBE_SAMPLES_LENGTH; smpIdx++) { for (uint32_t smpIdx = 0; smpIdx < MBE_SAMPLES_LENGTH; smpIdx++) {
pcm[smpIdx] = pcmTouLaw(samples[smpIdx]); pcm[smpIdx] = encodeMuLaw(samples[smpIdx]);
} }
if (m_trace)
Utils::dump(1U, "HostBridge()::decodeP25AudioFrame() Encoded uLaw Audio", pcm, MBE_SAMPLES_LENGTH);
} }
else { else {
for (uint32_t smpIdx = 0; smpIdx < MBE_SAMPLES_LENGTH; smpIdx++) { for (uint32_t smpIdx = 0; smpIdx < MBE_SAMPLES_LENGTH; smpIdx++) {
@ -2064,6 +2141,22 @@ void HostBridge::decodeP25AudioFrame(uint8_t* ldu, uint32_t srcId, uint32_t dstI
__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);
} }
// are we sending RTP audio frames?
if (m_udpRTPFrames) {
uint8_t* rtpFrame = generateRTPHeaders(MBE_SAMPLES_LENGTH, m_rtpSeqNo);
if (rtpFrame != nullptr) {
length += RTP_HEADER_LENGTH_BYTES;
uint8_t* newAudioData = new uint8_t[length];
::memcpy(newAudioData, rtpFrame, RTP_HEADER_LENGTH_BYTES);
::memcpy(newAudioData + RTP_HEADER_LENGTH_BYTES, audioData, MBE_SAMPLES_LENGTH);
delete[] audioData;
audioData = newAudioData;
}
m_rtpSeqNo++;
}
} }
else { else {
__SET_UINT32((MBE_SAMPLES_LENGTH * 2U), audioData, 0U); __SET_UINT32((MBE_SAMPLES_LENGTH * 2U), audioData, 0U);
@ -2248,7 +2341,7 @@ void HostBridge::encodeP25AudioFrame(uint8_t* pcm, uint32_t forcedSrcId, uint32_
m_p25N++; m_p25N++;
} }
/* Helper to generate the preamble tone. */ /* Helper to generate the single-tone preamble tone. */
void HostBridge::generatePreambleTone() void HostBridge::generatePreambleTone()
{ {
@ -2260,6 +2353,8 @@ void HostBridge::generatePreambleTone()
return; return;
} }
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); UInt8Array __sine = std::make_unique<uint8_t[]>(pcmBytes);
uint8_t* sine = __sine.get(); uint8_t* sine = __sine.get();
@ -2278,6 +2373,40 @@ void HostBridge::generatePreambleTone()
m_outputAudio.addData(sineSamples, frameCount); m_outputAudio.addData(sineSamples, frameCount);
} }
/* Helper to generate outgoing RTP headers. */
uint8_t* HostBridge::generateRTPHeaders(uint8_t msgLen, uint16_t& rtpSeq)
{
uint32_t timestamp = m_rtpTimestamp;
if (timestamp != INVALID_TS) {
timestamp += (RTP_GENERIC_CLOCK_RATE / 50);
if (m_debug)
LogDebug(LOG_NET, "HostBridge::generateRTPHeaders() RTP, previous TS = %u, TS = %u, rtpSeq = %u", m_rtpTimestamp, timestamp, rtpSeq);
m_rtpTimestamp = timestamp;
}
// generate RTP header
RTPHeader header = RTPHeader();
header.setPayloadType(RTP_G711_PAYLOAD_TYPE);
header.setTimestamp(timestamp);
header.setSequence(rtpSeq);
header.setSSRC(m_network->getPeerId());
uint8_t* buffer = new uint8_t[RTP_HEADER_LENGTH_BYTES + msgLen];
::memset(buffer, 0x00U, RTP_HEADER_LENGTH_BYTES + msgLen);
header.encode(buffer);
if (timestamp == INVALID_TS) {
if (m_debug)
LogDebug(LOG_NET, "HostBridge::generateRTPHeaders() RTP, initial TS = %u, rtpSeq = %u", header.getTimestamp(), rtpSeq);
m_rtpTimestamp = header.getTimestamp();
}
return buffer;
}
/* Helper to end a local or UDP call. */ /* Helper to end a local or UDP call. */
void HostBridge::callEnd(uint32_t srcId, uint32_t dstId) void HostBridge::callEnd(uint32_t srcId, uint32_t dstId)
@ -2297,10 +2426,25 @@ void HostBridge::callEnd(uint32_t srcId, uint32_t dstId)
switch (m_txMode) { switch (m_txMode) {
case TX_MODE_DMR: case TX_MODE_DMR:
{ {
dmr::defines::DataType::E dataType = dmr::defines::DataType::VOICE_SYNC;
if (m_dmrN == 0)
dataType = dmr::defines::DataType::VOICE_SYNC;
else {
dataType = dmr::defines::DataType::VOICE;
}
dmr::data::NetData data = dmr::data::NetData(); dmr::data::NetData data = dmr::data::NetData();
data.setDataType(dmr::defines::DataType::TERMINATOR_WITH_LC); data.setSlotNo(m_slot);
data.setDstId(dstId); data.setDataType(dataType);
data.setSrcId(srcId); data.setSrcId(srcId);
data.setDstId(dstId);
data.setFLCO(dmr::defines::FLCO::GROUP);
data.setN(m_dmrN);
data.setSeqNo(m_dmrSeqNo);
data.setBER(0U);
data.setRSSI(0U);
LogMessage(LOG_HOST, DMR_DT_TERMINATOR_WITH_LC ", slot = %u, dstId = %u", m_slot, dstId);
m_network->writeDMRTerminator(data, &m_dmrSeqNo, &m_dmrN, m_dmrEmbeddedData); m_network->writeDMRTerminator(data, &m_dmrSeqNo, &m_dmrN, m_dmrEmbeddedData);
m_network->resetDMR(data.getSlotNo()); m_network->resetDMR(data.getSlotNo());
@ -2315,6 +2459,8 @@ void HostBridge::callEnd(uint32_t srcId, uint32_t dstId)
p25::data::LowSpeedData lsd = p25::data::LowSpeedData(); p25::data::LowSpeedData lsd = p25::data::LowSpeedData();
LogMessage(LOG_HOST, P25_TDU_STR);
uint8_t controlByte = 0x00U; uint8_t controlByte = 0x00U;
m_network->writeP25TDU(lc, lsd, controlByte); m_network->writeP25TDU(lc, lsd, controlByte);
m_network->resetP25(); m_network->resetP25();
@ -2334,6 +2480,9 @@ void HostBridge::callEnd(uint32_t srcId, uint32_t dstId)
m_dmrN = 0U; m_dmrN = 0U;
m_p25SeqNo = 0U; m_p25SeqNo = 0U;
m_p25N = 0U; m_p25N = 0U;
m_rtpSeqNo = 0U;
m_rtpTimestamp = INVALID_TS;
} }
/* Entry point to audio processing thread. */ /* Entry point to audio processing thread. */

@ -4,7 +4,7 @@
* 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) 2024 Bryan Biedenkapp, N2PLL * Copyright (C) 2024-2025 Bryan Biedenkapp, N2PLL
* *
*/ */
/** /**
@ -96,25 +96,25 @@ void mdcPacketDetected(int frameCount, mdc_u8_t op, mdc_u8_t arg, mdc_u16_t unit
* @param pcm PCM value. * @param pcm PCM value.
* @return uint8_t aLaw value. * @return uint8_t aLaw value.
*/ */
uint8_t pcmToaLaw(short pcm); uint8_t encodeALaw(short pcm);
/** /**
* @brief Helper to convert G.711 aLaw into PCM. * @brief Helper to convert G.711 aLaw into PCM.
* @param alaw aLaw value. * @param alaw aLaw value.
* @return short PCM value. * @return short PCM value.
*/ */
short aLawToPCM(uint8_t alaw); short decodeALaw(uint8_t alaw);
/** /**
* @brief Helper to convert PCM into G.711 uLaw. * @brief Helper to convert PCM into G.711 MuLaw.
* @param pcm PCM value. * @param pcm PCM value.
* @return uint8_t uLaw value. * @return uint8_t MuLaw value.
*/ */
uint8_t pcmTouLaw(short pcm); uint8_t encodeMuLaw(short pcm);
/** /**
* @brief Helper to convert G.711 uLaw into PCM. * @brief Helper to convert G.711 MuLaw into PCM.
* @param ulaw uLaw value. * @param ulaw MuLaw value.
* @return short PCM value. * @return short PCM value.
*/ */
short uLawToPCM(uint8_t ulaw); short decodeMuLaw(uint8_t ulaw);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Class Declaration // Class Declaration
@ -161,6 +161,7 @@ private:
std::string m_udpReceiveAddress; std::string m_udpReceiveAddress;
bool m_udpNoIncludeLength; bool m_udpNoIncludeLength;
bool m_udpUseULaw; bool m_udpUseULaw;
bool m_udpRTPFrames;
uint32_t m_srcId; uint32_t m_srcId;
uint32_t m_srcIdOverride; uint32_t m_srcIdOverride;
@ -238,8 +239,12 @@ private:
bool m_dumpSampleLevel; bool m_dumpSampleLevel;
bool m_running; bool m_running;
bool m_trace;
bool m_debug; bool m_debug;
uint16_t m_rtpSeqNo;
uint32_t m_rtpTimestamp;
static std::mutex m_audioMutex; static std::mutex m_audioMutex;
static std::mutex m_networkMutex; static std::mutex m_networkMutex;
@ -434,7 +439,15 @@ private:
void encodeP25AudioFrame(uint8_t* pcm, uint32_t forcedSrcId = 0U, uint32_t forcedDstId = 0U); void encodeP25AudioFrame(uint8_t* pcm, uint32_t forcedSrcId = 0U, uint32_t forcedDstId = 0U);
/** /**
* @brief Helper to generate the preamble tone. * @brief Helper to generate outgoing RTP headers.
* @param msgLen Message Length.
* @param rtpSeq RTP Sequence.
* @returns uint8_t* Buffer containing the encoded RTP headers.
*/
uint8_t* generateRTPHeaders(uint8_t msgLen, uint16_t& rtpSeq);
/**
* @brief Helper to generate the single-tone preamble tone.
*/ */
void generatePreambleTone(); void generatePreambleTone();

@ -4,7 +4,7 @@
* 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) 2022,204 Bryan Biedenkapp, N2PLL * Copyright (C) 2022,2024 Bryan Biedenkapp, N2PLL
* *
*/ */
#include "nxdn/NXDNDefines.h" #include "nxdn/NXDNDefines.h"

@ -5,6 +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) 2016 Jonathan Naylor, G4KLX * Copyright (C) 2016 Jonathan Naylor, G4KLX
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
* *
*/ */
#include "Defines.h" #include "Defines.h"

@ -136,7 +136,7 @@ bool TagDMRData::processFrame(const uint8_t* data, uint32_t len, uint32_t peerId
// is this the end of the call stream? // is this the end of the call stream?
if (dataSync && (dataType == DataType::TERMINATOR_WITH_LC)) { if (dataSync && (dataType == DataType::TERMINATOR_WITH_LC)) {
if (srcId == 0U && dstId == 0U) { if (srcId == 0U && dstId == 0U) {
LogWarning(LOG_NET, "DMR, invalid TERMINATOR, peer = %u, srcId = %u, dstId = %u, streamId = %u, external = %u", peerId, srcId, dstId, streamId, external); LogWarning(LOG_NET, "DMR, invalid TERMINATOR, peer = %u, srcId = %u, dstId = %u, slot = %u, streamId = %u, external = %u", peerId, srcId, dstId, slotNo, streamId, external);
return false; return false;
} }
@ -149,8 +149,8 @@ bool TagDMRData::processFrame(const uint8_t* data, uint32_t len, uint32_t peerId
return false; return false;
}); });
if (it == m_status.end()) { if (it == m_status.end()) {
LogError(LOG_NET, "DMR, tried to end call for non-existent call in progress?, peer = %u, srcId = %u, dstId = %u, streamId = %u, external = %u", LogError(LOG_NET, "DMR, tried to end call for non-existent call in progress?, peer = %u, srcId = %u, dstId = %u, slot = %u, streamId = %u, external = %u",
peerId, srcId, dstId, streamId, external); peerId, srcId, dstId, slotNo, streamId, external);
} }
else { else {
status = it->second; status = it->second;
@ -179,8 +179,8 @@ bool TagDMRData::processFrame(const uint8_t* data, uint32_t len, uint32_t peerId
} }
} }
LogMessage(LOG_NET, "DMR, Call End, peer = %u, srcId = %u, dstId = %u, duration = %u, streamId = %u, external = %u", LogMessage(LOG_NET, "DMR, Call End, peer = %u, srcId = %u, dstId = %u, slot = %u, duration = %u, streamId = %u, external = %u",
peerId, srcId, dstId, duration / 1000, streamId, external); peerId, srcId, dstId, slotNo, duration / 1000, streamId, external);
// report call event to InfluxDB // report call event to InfluxDB
if (m_network->m_enableInfluxDB) { if (m_network->m_enableInfluxDB) {

@ -494,6 +494,7 @@ bool Host::createModem()
bool disableOFlowReset = modemConf["disableOFlowReset"].as<bool>(false); bool disableOFlowReset = modemConf["disableOFlowReset"].as<bool>(false);
bool ignoreModemConfigArea = modemConf["ignoreModemConfigArea"].as<bool>(false); bool ignoreModemConfigArea = modemConf["ignoreModemConfigArea"].as<bool>(false);
bool dumpModemStatus = modemConf["dumpModemStatus"].as<bool>(false); bool dumpModemStatus = modemConf["dumpModemStatus"].as<bool>(false);
bool respTrace = modemConf["respTrace"].as<bool>(false);
bool trace = modemConf["trace"].as<bool>(false); bool trace = modemConf["trace"].as<bool>(false);
bool debug = modemConf["debug"].as<bool>(false); bool debug = modemConf["debug"].as<bool>(false);
@ -687,6 +688,8 @@ bool Host::createModem()
m_modem->setP25NAC(m_p25NAC); m_modem->setP25NAC(m_p25NAC);
} }
m_modem->setResponseTrace(respTrace);
if (m_modemRemote) { if (m_modemRemote) {
m_modem->setOpenHandler(MODEM_OC_PORT_HANDLER_BIND(Host::rmtPortModemOpen, this)); m_modem->setOpenHandler(MODEM_OC_PORT_HANDLER_BIND(Host::rmtPortModemOpen, this));
m_modem->setCloseHandler(MODEM_OC_PORT_HANDLER_BIND(Host::rmtPortModemClose, this)); m_modem->setCloseHandler(MODEM_OC_PORT_HANDLER_BIND(Host::rmtPortModemClose, this));

@ -4,9 +4,6 @@
* 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.
* *
* @package DVM / Modem Host Software
* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
*
* Copyright (C) 2023-2024 Bryan Biedenkapp, N2PLL * Copyright (C) 2023-2024 Bryan Biedenkapp, N2PLL
* *
*/ */

@ -158,6 +158,7 @@ Modem::Modem(port::IModemPort* port, bool duplex, bool rxInvert, bool txInvert,
m_flashDisabled(false), m_flashDisabled(false),
m_gotModemStatus(false), m_gotModemStatus(false),
m_dumpModemStatus(dumpModemStatus), m_dumpModemStatus(dumpModemStatus),
m_respTrace(false),
m_trace(trace), m_trace(trace),
m_debug(debug) m_debug(debug)
{ {
@ -579,6 +580,8 @@ void Modem::clock(uint32_t ms)
m_rxDMRQueue1.addData(&data, 1U); m_rxDMRQueue1.addData(&data, 1U);
m_rxDMRQueue1.addData(m_buffer + 3U, m_length - 3U); m_rxDMRQueue1.addData(m_buffer + 3U, m_length - 3U);
if (m_trace)
Utils::dump(1U, "Modem::clock() RX DMR Data 1", m_buffer + 3U, m_length - 3U);
} }
} }
break; break;
@ -603,6 +606,8 @@ void Modem::clock(uint32_t ms)
m_rxDMRQueue2.addData(&data, 1U); m_rxDMRQueue2.addData(&data, 1U);
m_rxDMRQueue2.addData(m_buffer + 3U, m_length - 3U); m_rxDMRQueue2.addData(m_buffer + 3U, m_length - 3U);
if (m_trace)
Utils::dump(1U, "Modem::clock() RX DMR Data 2", m_buffer + 3U, m_length - 3U);
} }
} }
break; break;
@ -663,6 +668,8 @@ void Modem::clock(uint32_t ms)
m_rxP25Queue.addData(&data, 1U); m_rxP25Queue.addData(&data, 1U);
m_rxP25Queue.addData(m_buffer + (cmdOffset + 1U), m_length - (cmdOffset + 1U)); m_rxP25Queue.addData(m_buffer + (cmdOffset + 1U), m_length - (cmdOffset + 1U));
if (m_trace)
Utils::dump(1U, "Modem::clock() RX P25 Data", m_buffer + (cmdOffset + 1U), m_length - (cmdOffset + 1U));
} }
} }
break; break;
@ -704,6 +711,8 @@ void Modem::clock(uint32_t ms)
m_rxNXDNQueue.addData(&data, 1U); m_rxNXDNQueue.addData(&data, 1U);
m_rxNXDNQueue.addData(m_buffer + 3U, m_length - 3U); m_rxNXDNQueue.addData(m_buffer + 3U, m_length - 3U);
if (m_trace)
Utils::dump(1U, "Modem::clock() RX NXDN Data", m_buffer + 3U, m_length - 3U);
} }
} }
break; break;
@ -1391,8 +1400,8 @@ bool Modem::writeDMRFrame1(const uint8_t* data, uint32_t length)
if (m_dmrSpace1 >= length) { if (m_dmrSpace1 >= length) {
if (m_debug) if (m_debug)
LogDebug(LOG_MODEM, "Modem::writeDMRData1(); immediate write (len %u)", length); LogDebug(LOG_MODEM, "Modem::writeDMRData1(); immediate write (len %u)", length);
//if (m_trace) if (m_trace)
// Utils::dump(1U, "Immediate TX DMR Data 1", buffer, len); Utils::dump(1U, "Modem::writeDMRData1() Immediate TX DMR Data 1", buffer + 3U, length - 1U);
int ret = write(buffer, len); int ret = write(buffer, len);
if (ret != int(len)) { if (ret != int(len)) {
@ -1445,8 +1454,8 @@ bool Modem::writeDMRFrame2(const uint8_t* data, uint32_t length)
if (m_dmrSpace2 >= length) { if (m_dmrSpace2 >= length) {
if (m_debug) if (m_debug)
LogDebug(LOG_MODEM, "Modem::writeDMRData2(); immediate write (len %u)", length); LogDebug(LOG_MODEM, "Modem::writeDMRData2(); immediate write (len %u)", length);
//if (m_trace) if (m_trace)
// Utils::dump(1U, "Immediate TX DMR Data 2", buffer, len); Utils::dump(1U, "Modem::writeDMRData2() Immediate TX DMR Data 2", buffer + 3U, length - 1U);
int ret = write(buffer, len); int ret = write(buffer, len);
if (ret != int(len)) { if (ret != int(len)) {
@ -1511,8 +1520,8 @@ bool Modem::writeP25Frame(const uint8_t* data, uint32_t length)
if (m_p25Space >= length) { if (m_p25Space >= length) {
if (m_debug) if (m_debug)
LogDebug(LOG_MODEM, "Modem::writeP25Data(); immediate write (len %u)", length); LogDebug(LOG_MODEM, "Modem::writeP25Data(); immediate write (len %u)", length);
//if (m_trace) if (m_trace)
// Utils::dump(1U, "Immediate TX P25 Data", buffer, len); Utils::dump(1U, "Modem::writeP25Data() Immediate TX P25 Data", buffer + 3U, length - 3U);
int ret = write(buffer, len); int ret = write(buffer, len);
if (ret != int(len)) { if (ret != int(len)) {
@ -1565,8 +1574,8 @@ bool Modem::writeNXDNFrame(const uint8_t* data, uint32_t length)
if (m_nxdnSpace >= length) { if (m_nxdnSpace >= length) {
if (m_debug) if (m_debug)
LogDebug(LOG_MODEM, "Modem::writeNXDNData(); immediate write (len %u)", length); LogDebug(LOG_MODEM, "Modem::writeNXDNData(); immediate write (len %u)", length);
//if (m_trace) if (m_trace)
// Utils::dump(1U, "Immediate TX NXDN Data", buffer, len); Utils::dump(1U, "Modem::writeNXDNData() Immediate TX NXDN Data", buffer + 3U, length - 1U);
int ret = write(buffer, len); int ret = write(buffer, len);
if (ret != int(len)) { if (ret != int(len)) {
@ -1749,8 +1758,8 @@ bool Modem::sendCWId(const std::string& callsign)
for (uint32_t i = 0U; i < length; i++) for (uint32_t i = 0U; i < length; i++)
buffer[i + 3U] = callsign.at(i); buffer[i + 3U] = callsign.at(i);
//if (m_trace) if (m_trace)
// Utils::dump(1U, "CW ID Data", buffer, length + 3U); Utils::dump(1U, "CW ID Data", buffer, length + 3U);
return write(buffer, length + 3U) == int(length + 3U); return write(buffer, length + 3U) == int(length + 3U);
} }
@ -2324,36 +2333,36 @@ void Modem::printDebug(const uint8_t* buffer, uint16_t len)
} }
if (buffer[2U] == CMD_DEBUG1) { if (buffer[2U] == CMD_DEBUG1) {
LogDebug(LOG_MODEM, "M: %.*s", len - 3U, buffer + 3U); LogDebug(LOG_MODEM, "DSP_FW_API %.*s", len - 3U, buffer + 3U);
} }
else if (buffer[2U] == CMD_DEBUG2) { else if (buffer[2U] == CMD_DEBUG2) {
short val1 = (buffer[len - 2U] << 8) | buffer[len - 1U]; short val1 = (buffer[len - 2U] << 8) | buffer[len - 1U];
LogDebug(LOG_MODEM, "M: %.*s %X", len - 5U, buffer + 3U, val1); LogDebug(LOG_MODEM, "DSP_FW_API %.*s %X", len - 5U, buffer + 3U, val1);
} }
else if (buffer[2U] == CMD_DEBUG3) { else if (buffer[2U] == CMD_DEBUG3) {
short val1 = (buffer[len - 4U] << 8) | buffer[len - 3U]; short val1 = (buffer[len - 4U] << 8) | buffer[len - 3U];
short val2 = (buffer[len - 2U] << 8) | buffer[len - 1U]; short val2 = (buffer[len - 2U] << 8) | buffer[len - 1U];
LogDebug(LOG_MODEM, "M: %.*s %X %X", len - 7U, buffer + 3U, val1, val2); LogDebug(LOG_MODEM, "DSP_FW_API %.*s %X %X", len - 7U, buffer + 3U, val1, val2);
} }
else if (buffer[2U] == CMD_DEBUG4) { else if (buffer[2U] == CMD_DEBUG4) {
short val1 = (buffer[len - 6U] << 8) | buffer[len - 5U]; short val1 = (buffer[len - 6U] << 8) | buffer[len - 5U];
short val2 = (buffer[len - 4U] << 8) | buffer[len - 3U]; short val2 = (buffer[len - 4U] << 8) | buffer[len - 3U];
short val3 = (buffer[len - 2U] << 8) | buffer[len - 1U]; short val3 = (buffer[len - 2U] << 8) | buffer[len - 1U];
LogDebug(LOG_MODEM, "M: %.*s %X %X %X", len - 9U, buffer + 3U, val1, val2, val3); LogDebug(LOG_MODEM, "DSP_FW_API %.*s %X %X %X", len - 9U, buffer + 3U, val1, val2, val3);
} }
else if (buffer[2U] == CMD_DEBUG5) { else if (buffer[2U] == CMD_DEBUG5) {
short val1 = (buffer[len - 8U] << 8) | buffer[len - 7U]; short val1 = (buffer[len - 8U] << 8) | buffer[len - 7U];
short val2 = (buffer[len - 6U] << 8) | buffer[len - 5U]; short val2 = (buffer[len - 6U] << 8) | buffer[len - 5U];
short val3 = (buffer[len - 4U] << 8) | buffer[len - 3U]; short val3 = (buffer[len - 4U] << 8) | buffer[len - 3U];
short val4 = (buffer[len - 2U] << 8) | buffer[len - 1U]; short val4 = (buffer[len - 2U] << 8) | buffer[len - 1U];
LogDebug(LOG_MODEM, "M: %.*s %X %X %X %X", len - 11U, buffer + 3U, val1, val2, val3, val4); LogDebug(LOG_MODEM, "DSP_FW_API %.*s %X %X %X %X", len - 11U, buffer + 3U, val1, val2, val3, val4);
} }
else if (buffer[2U] == CMD_DEBUG_DUMP) { else if (buffer[2U] == CMD_DEBUG_DUMP) {
uint8_t data[255U]; uint8_t data[255U];
::memset(data, 0x00U, 255U); ::memset(data, 0x00U, 255U);
::memcpy(data, buffer, len); ::memcpy(data, buffer, len);
Utils::dump(1U, "Modem Debug Dump", data, len); Utils::dump(1U, "Modem::printDebug() DSP_FW_API Debug Dump", data, len);
} }
} }
@ -2363,7 +2372,7 @@ RESP_TYPE_DVM Modem::getResponse()
{ {
m_rspDoubleLength = false; m_rspDoubleLength = false;
//LogDebug(LOG_MODEM, "getResponse(), checking if we have data"); //LogDebug(LOG_MODEM, "Modem::getResponse(), checking if we have data");
// get the start of the frame or nothing at all // get the start of the frame or nothing at all
if (m_rspState == RESP_START) { if (m_rspState == RESP_START) {
@ -2375,7 +2384,7 @@ RESP_TYPE_DVM Modem::getResponse()
} }
if (ret == 0) { if (ret == 0) {
//LogDebug(LOG_MODEM, "getResponse(), no data available"); //LogDebug(LOG_MODEM, "Modem::getResponse(), no data available");
return RTM_TIMEOUT; return RTM_TIMEOUT;
} }
@ -2391,12 +2400,12 @@ RESP_TYPE_DVM Modem::getResponse()
m_rspDoubleLength = true; m_rspDoubleLength = true;
} }
//LogDebug(LOG_MODEM, "getResponse(), RESP_START"); //LogDebug(LOG_MODEM, "Modem::getResponse(), RESP_START");
m_rspState = RESP_LENGTH1; m_rspState = RESP_LENGTH1;
} }
//LogDebug(LOG_MODEM, "getResponse(), getting frame length 1/2, rspDoubleLength = %u", m_rspDoubleLength); //LogDebug(LOG_MODEM, "Modem::getResponse(), getting frame length 1/2, rspDoubleLength = %u", m_rspDoubleLength);
// get the length of the frame, 1/2 // get the length of the frame, 1/2
if (m_rspState == RESP_LENGTH1) { if (m_rspState == RESP_LENGTH1) {
int ret = m_port->read(m_buffer + 1U, 1U); int ret = m_port->read(m_buffer + 1U, 1U);
@ -2423,12 +2432,12 @@ RESP_TYPE_DVM Modem::getResponse()
m_length = m_buffer[1U]; m_length = m_buffer[1U];
} }
//LogDebug(LOG_MODEM, "getResponse(), RESP_LENGTH1, len = %u", m_length); //LogDebug(LOG_MODEM, "Modem::getResponse(), RESP_LENGTH1, len = %u", m_length);
m_rspOffset = 2U; m_rspOffset = 2U;
} }
//LogDebug(LOG_MODEM, "getResponse(), getting frame length 2/2"); //LogDebug(LOG_MODEM, "Modem::getResponse(), getting frame length 2/2");
// get the length of the frame, 2/2 // get the length of the frame, 2/2
if (m_rspState == RESP_LENGTH2) { if (m_rspState == RESP_LENGTH2) {
int ret = m_port->read(m_buffer + 2U, 1U); int ret = m_port->read(m_buffer + 2U, 1U);
@ -2444,13 +2453,13 @@ RESP_TYPE_DVM Modem::getResponse()
m_length = (m_length + (m_buffer[2U] & 0xFFU)); m_length = (m_length + (m_buffer[2U] & 0xFFU));
m_rspState = RESP_TYPE; m_rspState = RESP_TYPE;
//LogDebug(LOG_MODEM, "getResponse(), RESP_LENGTH2, len = %u", m_length); //LogDebug(LOG_MODEM, "Modem::getResponse(), RESP_LENGTH2, len = %u", m_length);
m_rspDoubleLength = true; m_rspDoubleLength = true;
m_rspOffset = 3U; m_rspOffset = 3U;
} }
//LogDebug(LOG_MODEM, "getResponse(), getting frame type"); //LogDebug(LOG_MODEM, "Modem::getResponse(), getting frame type");
// get the frame type // get the frame type
if (m_rspState == RESP_TYPE) { if (m_rspState == RESP_TYPE) {
int ret = m_port->read(m_buffer + m_rspOffset, 1U); int ret = m_port->read(m_buffer + m_rspOffset, 1U);
@ -2465,18 +2474,18 @@ RESP_TYPE_DVM Modem::getResponse()
m_rspType = (DVM_COMMANDS)m_buffer[m_rspOffset]; m_rspType = (DVM_COMMANDS)m_buffer[m_rspOffset];
//LogDebug(LOG_MODEM, "getResponse(), RESP_TYPE, len = %u, type = %u", m_length, m_rspType); //LogDebug(LOG_MODEM, "Modem::getResponse(), RESP_TYPE, len = %u, type = %u", m_length, m_rspType);
m_rspState = RESP_DATA; m_rspState = RESP_DATA;
m_rspOffset++; m_rspOffset++;
} }
//LogDebug(LOG_MODEM, "getResponse(), getting frame data"); //LogDebug(LOG_MODEM, "Modem::getResponse(), getting frame data");
// get the frame data // get the frame data
if (m_rspState == RESP_DATA) { if (m_rspState == RESP_DATA) {
if (m_debug && m_trace) if (m_respTrace)
LogDebug(LOG_MODEM, "getResponse(), RESP_DATA, len = %u, offset = %u, type = %02X", m_length, m_rspOffset, m_rspType); LogDebug(LOG_MODEM, "Modem::getResponse(), RESP_DATA, len = %u, offset = %u, type = %02X", m_length, m_rspOffset, m_rspType);
while (m_rspOffset < m_length) { while (m_rspOffset < m_length) {
int ret = m_port->read(m_buffer + m_rspOffset, m_length - m_rspOffset); int ret = m_port->read(m_buffer + m_rspOffset, m_length - m_rspOffset);
@ -2493,8 +2502,8 @@ RESP_TYPE_DVM Modem::getResponse()
m_rspOffset += ret; m_rspOffset += ret;
} }
if (m_debug && m_trace) if (m_respTrace)
Utils::dump(1U, "Modem getResponse()", m_buffer, m_length); Utils::dump(1U, "Modem::getResponse() Buffer", m_buffer, m_length);
} }
m_rspState = RESP_START; m_rspState = RESP_START;

@ -897,6 +897,10 @@ namespace modem
std::string rsnToString(uint8_t reason); std::string rsnToString(uint8_t reason);
public: public:
/**
* @brief Flag indicating if modem response trace is enabled.
*/
__PROTECTED_PROPERTY(bool, respTrace, ResponseTrace);
/** /**
* @brief Flag indicating if modem trace is enabled. * @brief Flag indicating if modem trace is enabled.
*/ */

@ -4,7 +4,7 @@
* 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) 2024-2024 Bryan Biedenkapp, N2PLL * Copyright (C) 2024-2025 Bryan Biedenkapp, N2PLL
* Copyright (C) 2024 Patrick McDonnell, W3AXL * Copyright (C) 2024 Patrick McDonnell, W3AXL
* *
*/ */
@ -198,6 +198,8 @@ void ModemV24::clock(uint32_t ms)
convertToAirTIA(m_buffer + (cmdOffset + 1U), m_length - (cmdOffset + 1U)); convertToAirTIA(m_buffer + (cmdOffset + 1U), m_length - (cmdOffset + 1U));
else else
convertToAir(m_buffer + (cmdOffset + 1U), m_length - (cmdOffset + 1U)); convertToAir(m_buffer + (cmdOffset + 1U), m_length - (cmdOffset + 1U));
if (m_trace)
Utils::dump(1U, "ModemV24::clock() RX P25 Data", m_buffer + (cmdOffset + 1U), m_length - (cmdOffset + 1U));
} }
} }
break; break;

@ -840,6 +840,8 @@ void V24UDPPort::getStatus()
reply[3U] = 0x00U; reply[3U] = 0x00U;
reply[3U] |= 0x08U; // P25 enable flag reply[3U] |= 0x08U; // P25 enable flag
if (m_fscState == CS_CONNECTED)
reply[3U] |= 0x40U; // V.24 connected flag
reply[4U] = uint8_t(m_modemState); reply[4U] = uint8_t(m_modemState);

@ -4,10 +4,6 @@
* 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.
* *
* @package DVM / Modem Host Software
* @derivedfrom MMDVMHost (https://github.com/g4klx/MMDVMHost)
* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
*
* Copyright (C) 2015,2016,2017,2018 Jonathan Naylor, G4KLX * Copyright (C) 2015,2016,2017,2018 Jonathan Naylor, G4KLX
* Copyright (C) 2017-2023 Bryan Biedenkapp, N2PLL * Copyright (C) 2017-2023 Bryan Biedenkapp, N2PLL
* *

@ -4,10 +4,6 @@
* 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.
* *
* @package DVM / Modem Host Software
* @derivedfrom MMDVMHost (https://github.com/g4klx/MMDVMHost)
* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
*
* Copyright (C) 2015-2020 Jonathan Naylor, G4KLX * Copyright (C) 2015-2020 Jonathan Naylor, G4KLX
* Copyright (C) 2022-2024 Bryan Biedenkapp, N2PLL * Copyright (C) 2022-2024 Bryan Biedenkapp, N2PLL
* *

@ -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) 2016,2017,2018 Jonathan Naylor, G4KLX * Copyright (C) 2016,2017,2018 Jonathan Naylor, G4KLX
* Copyright (C) 2017-2024 Bryan Biedenkapp, N2PLL * Copyright (C) 2017-2025 Bryan Biedenkapp, N2PLL
* *
*/ */
#include "Defines.h" #include "Defines.h"
@ -78,6 +78,7 @@ Control::Control(bool authoritative, uint32_t nac, uint32_t callHang, uint32_t q
m_convNetGrantDemand(false), m_convNetGrantDemand(false),
m_sndcpSupport(false), m_sndcpSupport(false),
m_ignoreAffiliationCheck(false), m_ignoreAffiliationCheck(false),
m_demandUnitRegForRefusedAff(true),
m_idenTable(idenTable), m_idenTable(idenTable),
m_ridLookup(ridLookup), m_ridLookup(ridLookup),
m_tidLookup(tidLookup), m_tidLookup(tidLookup),
@ -267,6 +268,7 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw
m_sndcpSupport = p25Protocol["sndcpSupport"].as<bool>(false); m_sndcpSupport = p25Protocol["sndcpSupport"].as<bool>(false);
m_ignoreAffiliationCheck = p25Protocol["ignoreAffiliationCheck"].as<bool>(false); m_ignoreAffiliationCheck = p25Protocol["ignoreAffiliationCheck"].as<bool>(false);
m_demandUnitRegForRefusedAff = p25Protocol["demandUnitRegForRefusedAff"].as<bool>(true);
yaml::Node control = p25Protocol["control"]; yaml::Node control = p25Protocol["control"];
m_enableControl = control["enable"].as<bool>(false); m_enableControl = control["enable"].as<bool>(false);
@ -493,6 +495,7 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw
LogInfo(" Unit-to-Unit Availability Check: %s", m_control->m_unitToUnitAvailCheck ? "yes" : "no"); LogInfo(" Unit-to-Unit Availability Check: %s", m_control->m_unitToUnitAvailCheck ? "yes" : "no");
LogInfo(" Explicit Source ID Support: %s", m_allowExplicitSourceId ? "yes" : "no"); LogInfo(" Explicit Source ID Support: %s", m_allowExplicitSourceId ? "yes" : "no");
LogInfo(" Conventional Network Grant Demand: %s", m_convNetGrantDemand ? "yes" : "no"); LogInfo(" Conventional Network Grant Demand: %s", m_convNetGrantDemand ? "yes" : "no");
LogInfo(" Demand Unit Registration for Refused Affiliation: %s", m_demandUnitRegForRefusedAff ? "yes" : "no");
if (disableUnitRegTimeout) { if (disableUnitRegTimeout) {
LogInfo(" Disable Unit Registration Timeout: yes"); LogInfo(" Disable Unit Registration Timeout: yes");

@ -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) 2016,2017 Jonathan Naylor, G4KLX * Copyright (C) 2016,2017 Jonathan Naylor, G4KLX
* Copyright (C) 2017-2024 Bryan Biedenkapp, N2PLL * Copyright (C) 2017-2025 Bryan Biedenkapp, N2PLL
* *
*/ */
/** /**
@ -319,6 +319,7 @@ namespace p25
bool m_convNetGrantDemand; bool m_convNetGrantDemand;
bool m_sndcpSupport; bool m_sndcpSupport;
bool m_ignoreAffiliationCheck; bool m_ignoreAffiliationCheck;
bool m_demandUnitRegForRefusedAff;
::lookups::IdenTableLookup* m_idenTable; ::lookups::IdenTableLookup* m_idenTable;
::lookups::RadioIdLookup* m_ridLookup; ::lookups::RadioIdLookup* m_ridLookup;

@ -4,7 +4,7 @@
* 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) 2017-2024 Bryan Biedenkapp, N2PLL * Copyright (C) 2017-2025 Bryan Biedenkapp, N2PLL
* Copyright (C) 2022 Jason-UWU * Copyright (C) 2022 Jason-UWU
* *
*/ */
@ -540,7 +540,11 @@ bool ControlSignaling::process(uint8_t* data, uint32_t len, std::unique_ptr<lc::
writeRF_TSDU_ACK_FNE(srcId, TSBKO::IOSP_GRP_AFF, true, true); writeRF_TSDU_ACK_FNE(srcId, TSBKO::IOSP_GRP_AFF, true, true);
} }
writeRF_TSDU_Grp_Aff_Rsp(srcId, dstId); if (writeRF_TSDU_Grp_Aff_Rsp(srcId, dstId) == ResponseCode::REFUSED) {
if (m_p25->m_demandUnitRegForRefusedAff) {
writeRF_TSDU_U_Reg_Cmd(srcId);
}
}
} }
break; break;
case TSBKO::ISP_GRP_AFF_Q_RSP: case TSBKO::ISP_GRP_AFF_Q_RSP:
@ -1153,7 +1157,7 @@ void ControlSignaling::writeRF_TSDU_Ext_Func(uint32_t func, uint32_t arg, uint32
break; break;
} }
writeRF_TSDU_SBF_Imm(iosp.get(), false); writeRF_TSDU_SBF_Imm(iosp.get(), true);
} }
/* Helper to write a group affiliation query packet. */ /* Helper to write a group affiliation query packet. */
@ -2637,10 +2641,8 @@ void ControlSignaling::writeRF_TSDU_Deny(uint32_t srcId, uint32_t dstId, uint8_t
/* Helper to write a group affiliation response packet. */ /* Helper to write a group affiliation response packet. */
bool ControlSignaling::writeRF_TSDU_Grp_Aff_Rsp(uint32_t srcId, uint32_t dstId) uint8_t ControlSignaling::writeRF_TSDU_Grp_Aff_Rsp(uint32_t srcId, uint32_t dstId)
{ {
bool ret = false;
std::unique_ptr<IOSP_GRP_AFF> iosp = std::make_unique<IOSP_GRP_AFF>(); std::unique_ptr<IOSP_GRP_AFF> iosp = std::make_unique<IOSP_GRP_AFF>();
iosp->setMFId(m_lastMFID); iosp->setMFId(m_lastMFID);
iosp->setAnnounceGroup(m_announcementGroup); iosp->setAnnounceGroup(m_announcementGroup);
@ -2714,7 +2716,6 @@ bool ControlSignaling::writeRF_TSDU_Grp_Aff_Rsp(uint32_t srcId, uint32_t dstId)
} }
::ActivityLog("P25", true, "group affiliation request from %u to %s %u", srcId, "TG ", dstId); ::ActivityLog("P25", true, "group affiliation request from %u to %s %u", srcId, "TG ", dstId);
ret = true;
// update dynamic affiliation table // update dynamic affiliation table
m_p25->m_affiliations.groupAff(srcId, dstId); m_p25->m_affiliations.groupAff(srcId, dstId);
@ -2724,7 +2725,7 @@ bool ControlSignaling::writeRF_TSDU_Grp_Aff_Rsp(uint32_t srcId, uint32_t dstId)
} }
writeRF_TSDU_SBF_Imm(iosp.get(), noNet); writeRF_TSDU_SBF_Imm(iosp.get(), noNet);
return ret; return iosp->getResponse();
} }
/* Helper to write a unit registration response packet. */ /* Helper to write a unit registration response packet. */

@ -4,7 +4,7 @@
* 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) 2017-2024 Bryan Biedenkapp, N2PLL * Copyright (C) 2017-2025 Bryan Biedenkapp, N2PLL
* *
*/ */
/** /**
@ -364,8 +364,9 @@ namespace p25
* @brief Helper to write a group affiliation response packet. * @brief Helper to write a group affiliation response packet.
* @param srcId Source Radio ID. * @param srcId Source Radio ID.
* @param dstId Destination ID. * @param dstId Destination ID.
* @returns uint8_t Grant response code.
*/ */
bool writeRF_TSDU_Grp_Aff_Rsp(uint32_t srcId, uint32_t dstId); uint8_t writeRF_TSDU_Grp_Aff_Rsp(uint32_t srcId, uint32_t dstId);
/** /**
* @brief Helper to write a unit registration response packet. * @brief Helper to write a unit registration response packet.
* @param srcId Source Radio ID. * @param srcId Source Radio ID.

@ -409,7 +409,7 @@ bool Voice::process(uint8_t* data, uint32_t len)
// are we auto-registering legacy radios to groups? // are we auto-registering legacy radios to groups?
if (m_p25->m_legacyGroupReg && group) { if (m_p25->m_legacyGroupReg && group) {
if (!m_p25->m_affiliations.isGroupAff(srcId, dstId)) { if (!m_p25->m_affiliations.isGroupAff(srcId, dstId)) {
if (!m_p25->m_control->writeRF_TSDU_Grp_Aff_Rsp(srcId, dstId)) { if (m_p25->m_control->writeRF_TSDU_Grp_Aff_Rsp(srcId, dstId) != ResponseCode::ACCEPT) {
LogWarning(LOG_RF, P25_HDU_STR " denial, conventional affiliation required, not affiliated to TGID, srcId = %u, dstId = %u", srcId, dstId); LogWarning(LOG_RF, P25_HDU_STR " denial, conventional affiliation required, not affiliated to TGID, srcId = %u, dstId = %u", srcId, dstId);
m_p25->m_rfLastDstId = 0U; m_p25->m_rfLastDstId = 0U;
m_p25->m_rfLastSrcId = 0U; m_p25->m_rfLastSrcId = 0U;

@ -4,9 +4,6 @@
* 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.
* *
* @package DVM / Remote Command Client
* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
*
* Copyright (C) 2023,2024 Bryan Biedenkapp, N2PLL * Copyright (C) 2023,2024 Bryan Biedenkapp, N2PLL
* *
*/ */

Loading…
Cancel
Save

Powered by TurnKey Linux.