implement (probably wrong) silence threshold handling for NXDN voice; implement site data for NXDN;

pull/12/head
Bryan Biedenkapp 4 years ago
parent f47728760a
commit 99d1de340e

@ -122,6 +122,15 @@ Host::Host(const std::string& confFile) :
m_p25CCData(false),
m_p25CtrlChannel(false),
m_p25CtrlBroadcast(false),
m_siteId(1U),
m_dmrNetId(1U),
m_dmrColorCode(1U),
m_p25NAC(0x293U),
m_p25PatchSuperGroup(0xFFFFU),
m_p25NetId(0xBB800U),
m_p25SysId(1U),
m_p25RfssId(1U),
m_nxdnRAN(1U),
m_activeTickDelay(5U),
m_idleTickDelay(5U),
m_remoteControl(NULL)
@ -568,7 +577,7 @@ int Host::run()
nxdn = new nxdn::Control(m_nxdnRAN, callHang, queueSizeBytes, m_timeout, m_rfTalkgroupHang,
m_modem, m_network, m_duplex, m_ridLookup, m_tidLookup, m_idenTable, rssi,
nxdnDebug, nxdnVerbose);
nxdn->setOptions(m_conf, m_cwCallsign, m_voiceChNo, m_channelId, m_channelNo, true);
nxdn->setOptions(m_conf, m_cwCallsign, m_voiceChNo, m_siteId, m_channelId, m_channelNo, true);
if (nxdnVerbose) {
LogInfo(" Verbose: yes");

@ -92,6 +92,9 @@ Control::Control(uint32_t ran, uint32_t callHang, uint32_t queueSize, uint32_t t
m_modem(modem),
m_network(network),
m_duplex(duplex),
m_control(false),
m_dedicatedControl(false),
m_voiceOnControl(false),
m_rfLastLICH(),
m_rfLC(),
m_netLC(),
@ -106,10 +109,14 @@ Control::Control(uint32_t ran, uint32_t callHang, uint32_t queueSize, uint32_t t
m_rfLastDstId(0U),
m_netState(RS_NET_IDLE),
m_netLastDstId(0U),
m_ccRunning(false),
m_ccPrevRunning(false),
m_ccHalted(false),
m_rfTimeout(1000U, timeout),
m_rfTGHang(1000U, tgHang),
m_netTimeout(1000U, timeout),
m_networkWatchdog(1000U, 0U, 1500U),
m_siteData(),
m_rssiMapper(rssiMapper),
m_rssi(0U),
m_maxRSSI(0U),
@ -176,21 +183,48 @@ void Control::reset()
/// <param name="conf">Instance of the yaml::Node class.</param>
/// <param name="cwCallsign"></param>
/// <param name="voiceChNo"></param>
/// <param name="locId"></param>
/// <param name="channelId"></param>
/// <param name="channelNo"></param>
/// <param name="printOptions"></param>
void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const std::vector<uint32_t> voiceChNo,
uint8_t channelId, uint32_t channelNo, bool printOptions)
uint16_t locId, uint8_t channelId, uint32_t channelNo, bool printOptions)
{
yaml::Node systemConf = conf["system"];
yaml::Node nxdnProtocol = conf["protocols"]["nxdn"];
yaml::Node control = nxdnProtocol["control"];
m_control = control["enable"].as<bool>(false);
if (m_control) {
m_dedicatedControl = control["dedicated"].as<bool>(false);
}
else {
m_dedicatedControl = false;
}
m_voiceOnControl = nxdnProtocol["voiceOnControl"].as<bool>(false);
m_voice->m_silenceThreshold = nxdnProtocol["silenceThreshold"].as<uint32_t>(nxdn::DEFAULT_SILENCE_THRESHOLD);
if (m_voice->m_silenceThreshold > MAX_NXDN_VOICE_ERRORS) {
LogWarning(LOG_NXDN, "Silence threshold > %u, defaulting to %u", nxdn::MAX_NXDN_VOICE_ERRORS, nxdn::DEFAULT_SILENCE_THRESHOLD);
m_voice->m_silenceThreshold = nxdn::DEFAULT_SILENCE_THRESHOLD;
}
bool disableCompositeFlag = nxdnProtocol["disableCompositeFlag"].as<bool>(false);
uint8_t serviceClass = NXDN_SIF1_VOICE_CALL_SVC | NXDN_SIF1_DATA_CALL_SVC;
if (m_control) {
serviceClass |= NXDN_SIF1_GRP_REG_SVC;
}
if (m_voiceOnControl) {
if (!disableCompositeFlag) {
serviceClass |= NXDN_SIF1_COMPOSITE_CONTROL;
}
}
m_siteData = SiteData(locId, channelId, channelNo, serviceClass, false);
m_siteData.setCallsign(cwCallsign);
std::vector<lookups::IdenTable> entries = m_idenTable->list();
for (auto it = entries.begin(); it != entries.end(); ++it) {
lookups::IdenTable entry = *it;
@ -202,6 +236,10 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s
if (printOptions) {
LogInfo(" Silence Threshold: %u (%.1f%%)", m_voice->m_silenceThreshold, float(m_voice->m_silenceThreshold) / 12.33F);
if (m_control) {
LogInfo(" Voice on Control: %s", m_voiceOnControl ? "yes" : "no");
}
}
if (m_voice != NULL) {

@ -37,6 +37,7 @@
#include "nxdn/lc/LC.h"
#include "nxdn/packet/Voice.h"
#include "nxdn/packet/Data.h"
#include "nxdn/SiteData.h"
#include "network/BaseNetwork.h"
#include "network/RemoteControl.h"
#include "lookups/RSSIInterpolator.h"
@ -80,7 +81,7 @@ namespace nxdn
/// <summary>Helper to set NXDN configuration options.</summary>
void setOptions(yaml::Node& conf, const std::string cwCallsign, const std::vector<uint32_t> voiceChNo,
uint8_t channelId, uint32_t channelNo, bool printOptions);
uint16_t locId, uint8_t channelId, uint32_t channelNo, bool printOptions);
/// <summary>Process a data frame from the RF interface.</summary>
bool processFrame(uint8_t* data, uint32_t len);
@ -109,6 +110,9 @@ namespace nxdn
network::BaseNetwork* m_network;
bool m_duplex;
bool m_control;
bool m_dedicatedControl;
bool m_voiceOnControl;
channel::LICH m_rfLastLICH;
lc::LC m_rfLC;
@ -130,11 +134,17 @@ namespace nxdn
RPT_NET_STATE m_netState;
uint32_t m_netLastDstId;
bool m_ccRunning;
bool m_ccPrevRunning;
bool m_ccHalted;
Timer m_rfTimeout;
Timer m_rfTGHang;
Timer m_netTimeout;
Timer m_networkWatchdog;
SiteData m_siteData;
lookups::RSSIInterpolator* m_rssiMapper;
uint8_t m_rssi;
uint8_t m_maxRSSI;

@ -152,6 +152,8 @@ namespace nxdn
const uint32_t MAX_NXDN_VOICE_ERRORS = 144U;
const uint32_t MAX_NXDN_VOICE_ERRORS_STEAL = 94U;
const uint8_t NXDN_NULL_AMBE[] = { 0xB1U, 0xA8U, 0x22U, 0x25U, 0x6BU, 0xD1U, 0x6CU, 0xCFU, 0x67U };
const uint32_t NXDN_MI_LENGTH_BYTES = 8U;
const uint32_t NXDN_PCKT_INFO_LENGTH_BYTES = 3U;
@ -181,8 +183,27 @@ namespace nxdn
const uint8_t NXDN_CAUSE_DISC_NORMAL = 0x01U;
const uint8_t NXDN_CAUSE_DISC_NORMAL_TC = 0x02U;
const uint8_t NXDN_SIF1_DATA_CALL_SVC = 0x01U;
const uint8_t NXDN_SIF1_VOICE_CALL_SVC = 0x02U;
const uint8_t NXDN_SIF1_COMPOSITE_CONTROL = 0x04U;
const uint8_t NXDN_SIF1_AUTH_SVC = 0x08U;
const uint8_t NXDN_SIF1_GRP_REG_SVC = 0x10U;
const uint8_t NXDN_SIF1_LOC_REG_SVC = 0x20U;
const uint8_t NXDN_SIF1_MULTI_SYSTEM_SVC = 0x40U;
const uint8_t NXDN_SIF1_MULTI_SITE_SVC = 0x80U;
const uint8_t NXDN_SIF2_IP_NETWORK = 0x10U;
const uint8_t NXDN_SIF2_PSTN_NETWORK = 0x20U;
const uint8_t NXDN_SIF2_STATUS_CALL_REM_CTRL = 0x40U;
const uint8_t NXDN_SIF2_SHORT_DATA_CALL_SVC = 0x80U;
// Common Message Types
const uint8_t MESSAGE_TYPE_IDLE = 0x10U; // IDLE - Idle
const uint8_t MESSAGE_TYPE_DISC = 0x11U; // DISC - Disconnect
const uint8_t MESSAGE_TYPE_DST_ID_INFO = 0x17U; // DST_ID_INFO - Digital Station ID
const uint8_t MESSAGE_TYPE_SRV_INFO = 0x19U; // SRV_INFO - Service Information
const uint8_t MESSAGE_TYPE_CCH_INFO = 0x1AU; // CCH_INFO - Control Channel Information
const uint8_t MESSAGE_TYPE_ADJ_SITE_INFO = 0x1BU; // ADJ_SITE_INFO - Adjacent Site Information
// Traffic Channel Message Types
const uint8_t RTCH_MESSAGE_TYPE_VCALL = 0x01U; // VCALL - Voice Call
@ -199,6 +220,11 @@ namespace nxdn
const uint8_t RTCH_MESSAGE_TYPE_SDCALL_RESP = 0x3BU; // SDCALL_RESP - Short Data Call Response
// Control Channel Message Types
const uint8_t RCCH_MESSAGE_TYPE_SITE_INFO = 0x18U; // SITE_INFO - Site Information
const uint8_t RCCH_MESSAGE_TYPE_REG = 0x20U; // REG - Registration Request (ISP) / Registration Response (OSP)
const uint8_t RCCH_MESSAGE_TYPE_REG_C = 0x22U; // REG_C - Registration Clear Request (ISP) / Registration Clear Response (OSP)
const uint8_t RCCH_MESSAGE_TYPE_REG_COMM = 0x23U; // REG_COMM - Registration Command
const uint8_t RCCH_MESSAGE_TYPE_GRP_REG = 0x24U; // GRP_REG - Group Registration Request (ISP) / Group Registration Response (OSP)
const uint8_t RCCH_MESSAGE_TYPE_PROP_FORM = 0x3FU; // PROP_FORM - Proprietary Form
// Call Types

@ -0,0 +1,186 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Server
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2021 by Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__NXDN_SITE_DATA_H__)
#define __NXDN_SITE_DATA_H__
#include "Defines.h"
#include "nxdn/NXDNDefines.h"
namespace nxdn
{
// ---------------------------------------------------------------------------
// Class Declaration
// Represents site data for NXDN.
// ---------------------------------------------------------------------------
class HOST_SW_API SiteData {
public:
/// <summary>Initializes a new instance of the SiteData class.</summary>
SiteData() :
m_locId(1U),
m_channelId(1U),
m_channelNo(1U),
m_serviceClass(NXDN_SIF1_VOICE_CALL_SVC | NXDN_SIF1_DATA_CALL_SVC),
m_isAdjSite(false),
m_callsign("CHANGEME"),
m_requireReg(false),
m_netActive(false)
{
/* stub */
}
/// <summary>Initializes a new instance of the SiteData class.</summary>
/// <param name="locId">NXDN Location ID.</param>
/// <param name="channelId">Channel ID.</param>
/// <param name="channelNo">Channel Number.</param>
/// <param name="serviceClass">Service class.</param>
/// <param name="requireReg"></param>
SiteData(uint16_t locId, uint8_t channelId, uint32_t channelNo, uint8_t serviceClass, bool requireReq) :
m_locId(locId),
m_channelId(1U),
m_channelNo(1U),
m_serviceClass(NXDN_SIF1_VOICE_CALL_SVC | NXDN_SIF1_DATA_CALL_SVC),
m_isAdjSite(false),
m_callsign("CHANGEME"),
m_requireReg(requireReq),
m_netActive(false)
{
if (m_locId > 0xFFFU)
m_locId = 0xFFFU;
// channel id clamping
if (channelId > 15U)
channelId = 15U;
// channel number clamping
if (m_channelNo == 0U) { // clamp to 1
m_channelNo = 1U;
}
if (m_channelNo > 4095U) { // clamp to 4095
m_channelNo = 4095U;
}
m_serviceClass = serviceClass;
}
/// <summary>Helper to set the site callsign.</summary>
/// <param name="callsign">Callsign.</param>
void setCallsign(std::string callsign)
{
m_callsign = callsign;
}
/// <summary>Helper to set the site network active flag.</summary>
/// <param name="netActive">Network active.</param>
void setNetActive(bool netActive)
{
m_netActive = netActive;
}
/// <summary>Helper to set adjacent site data.</summary>
/// <param name="locId">NXDN Location ID.</param>
/// <param name="channelId">Channel ID.</param>
/// <param name="channelNo">Channel Number.</param>
/// <param name="serviceClass">Service class.</param>
void setAdjSite(uint32_t locId, uint8_t rfssId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, uint8_t serviceClass)
{
if (locId > 0xFFFU)
locId = 0xFFFU;
// channel id clamping
if (channelId > 15U)
channelId = 15U;
// channel number clamping
if (channelNo == 0U) { // clamp to 1
channelNo = 1U;
}
if (channelNo > 4095U) { // clamp to 4095
channelNo = 4095U;
}
m_locId = locId;
m_channelId = channelId;
m_channelNo = channelNo;
m_serviceClass = serviceClass;
m_isAdjSite = true;
m_callsign = "ADJSITE ";
m_netActive = true; // adjacent sites are explicitly network active
}
/// <summary>Equals operator.</summary>
/// <param name="data"></param>
/// <returns></returns>
SiteData & operator=(const SiteData & data)
{
if (this != &data) {
m_locId = data.m_locId;
m_channelId = data.m_channelId;
m_channelNo = data.m_channelNo;
m_serviceClass = data.m_serviceClass;
m_isAdjSite = data.m_isAdjSite;
m_callsign = data.m_callsign;
m_requireReg = data.m_requireReg;
m_netActive = data.m_netActive;
}
return *this;
}
public:
/// <summary>NXDN location ID.</summary>
__READONLY_PROPERTY_PLAIN(uint16_t, locId, locId);
/// <summary>Channel ID.</summary>
__READONLY_PROPERTY_PLAIN(uint8_t, channelId, channelId);
/// <summary>Channel number.</summary>
__READONLY_PROPERTY_PLAIN(uint32_t, channelNo, channelNo);
/// <summary>Service class.</summary>
__READONLY_PROPERTY_PLAIN(uint8_t, serviceClass, serviceClass);
/// <summary>Flag indicating whether this site data is for an adjacent site.</summary>
__READONLY_PROPERTY_PLAIN(bool, isAdjSite, isAdjSite);
/// <summary>Callsign.</summary>
__READONLY_PROPERTY_PLAIN(std::string, callsign, callsign);
/// <summary>NXDN require registration.</summary>
__READONLY_PROPERTY_PLAIN(bool, requireReg, requireReg);
/// <summary>Flag indicating whether this site is a linked active network member.</summary>
__READONLY_PROPERTY_PLAIN(bool, netActive, netActive);
};
} // namespace nxdn
#endif // __NXDN_SITE_DATA_H__

@ -157,7 +157,7 @@ CAC& CAC::operator=(const CAC& data)
}
/// <summary>
/// Decode a slow associated control channel.
/// Decode a common access channel.
/// </summary>
/// <param name="data"></param>
/// <returns>True, if CAC was decoded, otherwise false.</returns>
@ -223,7 +223,7 @@ bool CAC::decode(const uint8_t* data)
}
/// <summary>
/// Encode a slow associated control channel.
/// Encode a common access channel.
/// </summary>
/// <param name="data"></param>
void CAC::encode(uint8_t* data) const

@ -487,6 +487,19 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len)
errors += ambe.regenerateNXDN(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U);
errors += ambe.regenerateNXDN(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U);
// replace audio with silence in cases where the error rate
// has exceeded the configured threshold
if (errors > m_silenceThreshold) {
// bryanb: this is probably the wrong way to go about this...
// generate null audio
::memcpy(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 0U, NXDN_NULL_AMBE, 9U);
::memcpy(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 9U, NXDN_NULL_AMBE, 9U);
::memcpy(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U, NXDN_NULL_AMBE, 9U);
::memcpy(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U, NXDN_NULL_AMBE, 9U);
LogWarning(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", exceeded lost audio threshold, filling in");
}
m_rfErrs += errors;
m_rfBits += 188U;
@ -506,6 +519,17 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len)
errors += ambe.regenerateNXDN(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U);
errors += ambe.regenerateNXDN(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U);
// replace audio with silence in cases where the error rate
// has exceeded the configured threshold
if (errors > (m_silenceThreshold / 2U)) {
// bryanb: this is probably the wrong way to go about this...
// generate null audio
::memcpy(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U, NXDN_NULL_AMBE, 9U);
::memcpy(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U, NXDN_NULL_AMBE, 9U);
LogWarning(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", exceeded lost audio threshold, filling in");
}
m_rfErrs += errors;
m_rfBits += 94U;
@ -519,8 +543,19 @@ bool Voice::process(uint8_t usc, uint8_t option, uint8_t* data, uint32_t len)
uint32_t errors = 0U;
errors += ambe.regenerateNXDN(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES);
errors += ambe.regenerateNXDN(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 0U);
errors += ambe.regenerateNXDN(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 9U);
// replace audio with silence in cases where the error rate
// has exceeded the configured threshold
if (errors > (m_silenceThreshold / 2U)) {
// bryanb: this is probably the wrong way to go about this...
// generate null audio
::memcpy(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 0U, NXDN_NULL_AMBE, 9U);
::memcpy(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 9U, NXDN_NULL_AMBE, 9U);
LogWarning(LOG_RF, NXDN_MESSAGE_TYPE_VCALL ", exceeded lost audio threshold, filling in");
}
m_rfErrs += errors;
m_rfBits += 94U;

@ -165,11 +165,11 @@ namespace p25
channelId = 15U;
// channel number clamping
if (m_channelNo == 0U) { // clamp to 1
m_channelNo = 1U;
if (channelNo == 0U) { // clamp to 1
channelNo = 1U;
}
if (m_channelNo > 4095U) { // clamp to 4095
m_channelNo = 4095U;
if (channelNo > 4095U) { // clamp to 4095
channelNo = 4095U;
}
m_lra = 0U;
@ -237,7 +237,7 @@ namespace p25
__READONLY_PROPERTY_PLAIN(uint8_t, channelId, channelId);
/// <summary>Channel number.</summary>
__READONLY_PROPERTY_PLAIN(uint32_t, channelNo, channelNo);
/// <summary>Channel number.</summary>
/// <summary>Service class.</summary>
__READONLY_PROPERTY_PLAIN(uint8_t, serviceClass, serviceClass);
/// <summary>Flag indicating whether this site data is for an adjacent site.</summary>
__READONLY_PROPERTY_PLAIN(bool, isAdjSite, isAdjSite);

Loading…
Cancel
Save

Powered by TurnKey Linux.