factoryize NXDN RCCH;

3.0-rcon_maint
Bryan Biedenkapp 3 years ago
parent 6a85108a91
commit fd4920f70c

@ -49,6 +49,8 @@ file(GLOB dvmhost_SRC
"nxdn/channel/*.cpp"
"nxdn/lc/*.h"
"nxdn/lc/*.cpp"
"nxdn/lc/rcch/*.h"
"nxdn/lc/rcch/*.cpp"
"nxdn/packet/*.h"
"nxdn/packet/*.cpp"

@ -69,7 +69,7 @@ namespace dmr
private:
/// <summary></summary>
static std::unique_ptr<CSBK> decode(CSBK* tsbk, const uint8_t* data);
static std::unique_ptr<CSBK> decode(CSBK* csbk, const uint8_t* data);
};
} // namespace csbk
} // namespace lc

@ -34,6 +34,7 @@
#include "nxdn/acl/AccessControl.h"
#include "nxdn/channel/SACCH.h"
#include "nxdn/channel/FACCH1.h"
#include "nxdn/lc/RCCH.h"
#include "nxdn/lc/RTCH.h"
#include "nxdn/Sync.h"
#include "nxdn/NXDNUtils.h"
@ -142,12 +143,12 @@ Control::Control(uint32_t ran, uint32_t callHang, uint32_t queueSize, uint32_t t
acl::AccessControl::init(m_ridLookup, m_tidLookup);
m_voice = new Voice(this, network, dumpRCCHData, debug, verbose);
m_trunk = new Trunk(this, network, dumpRCCHData, debug, verbose);
m_voice = new Voice(this, network, debug, verbose);
m_trunk = new Trunk(this, network, debug, verbose);
m_data = new Data(this, network, debug, verbose);
m_rfLC.setVerbose(m_dumpRCCH);
m_netLC.setVerbose(m_dumpRCCH);
lc::RCCH::setVerbose(dumpRCCHData);
lc::RTCH::setVerbose(dumpRCCHData);
}
/// <summary>
@ -187,13 +188,11 @@ void Control::reset()
m_queue.clear();
m_rfMask = 0x00U;
m_rfLC.setVerbose(m_dumpRCCH);
m_rfLC.reset();
m_netState = RS_NET_IDLE;
m_netMask = 0x00U;
m_netLC.setVerbose(m_dumpRCCH);
m_netLC.reset();
}
@ -248,6 +247,9 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s
m_siteData = SiteData(locId, channelId, channelNo, serviceClass, false);
m_siteData.setCallsign(cwCallsign);
lc::RCCH::setSiteData(m_siteData);
lc::RCCH::setCallsign(cwCallsign);
std::vector<lookups::IdenTable> entries = m_idenTable->list();
for (auto it = entries.begin(); it != entries.end(); ++it) {
lookups::IdenTable entry = *it;
@ -281,11 +283,6 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s
if (m_data != nullptr) {
m_data->resetRF();
}
if (m_trunk != nullptr) {
m_trunk->resetRF();
m_trunk->resetNet();
}
}
/// <summary>
@ -613,6 +610,8 @@ void Control::setDebugVerbose(bool debug, bool verbose)
void Control::setRCCHVerbose(bool verbose)
{
m_dumpRCCH = verbose;
lc::RCCH::setVerbose(verbose);
lc::RTCH::setVerbose(verbose);
}
// ---------------------------------------------------------------------------
@ -731,8 +730,8 @@ bool Control::writeRF_ControlData()
return false;
}
const uint8_t maxSeq = m_trunk->m_rfLC.getBcchCnt() + (m_trunk->m_rfLC.getCcchPagingCnt() + m_trunk->m_rfLC.getCcchMultiCnt()) *
m_trunk->m_rfLC.getRcchGroupingCnt() * m_trunk->m_rfLC.getRcchIterateCount();
const uint8_t maxSeq = m_trunk->m_bcchCnt + (m_trunk->m_ccchPagingCnt + m_trunk->m_ccchMultiCnt) *
m_trunk->m_rcchGroupingCnt * m_trunk->m_rcchIterateCnt;
if (m_ccSeq == maxSeq) {
m_ccSeq = 0U;
}

@ -39,6 +39,15 @@ using namespace nxdn::lc;
#include <cassert>
#include <cstring>
// ---------------------------------------------------------------------------
// Static Class Members
// ---------------------------------------------------------------------------
bool RCCH::m_verbose = false;
uint8_t *RCCH::m_siteCallsign = nullptr;
SiteData RCCH::m_siteData = SiteData();
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
@ -47,7 +56,7 @@ using namespace nxdn::lc;
/// Initializes a copy instance of the RCCH class.
/// </summary>
/// <param name="data"></param>
RCCH::RCCH(const RCCH& data) : RCCH(SiteData())
RCCH::RCCH(const RCCH& data) : RCCH()
{
copy(data);
}
@ -55,23 +64,28 @@ RCCH::RCCH(const RCCH& data) : RCCH(SiteData())
/// <summary>
/// Initializes a new instance of the RCCH class.
/// </summary>
/// <param name="siteData"></param>
/// <param name="entry"></param>
RCCH::RCCH(SiteData siteData, lookups::IdenTable entry) : RCCH(siteData)
{
m_siteIdenEntry = entry;
}
/// <summary>
/// Initializes a new instance of the RCCH class.
/// </summary>
/// <param name="siteData"></param>
/// <param name="entry"></param>
/// <param name="verbose"></param>
RCCH::RCCH(SiteData siteData, lookups::IdenTable entry, bool verbose) : RCCH(siteData)
RCCH::RCCH() :
m_messageType(MESSAGE_TYPE_IDLE),
m_srcId(0U),
m_dstId(0U),
m_locId(0U),
m_regOption(0U),
m_version(0U),
m_causeRsp(NXDN_CAUSE_MM_REG_ACCEPTED),
m_grpVchNo(0U),
m_callType(CALL_TYPE_UNSPECIFIED),
m_emergency(false),
m_encrypted(false),
m_priority(false),
m_group(true),
m_duplex(false),
m_transmissionMode(TRANSMISSION_MODE_4800),
m_siteIdenEntry()
{
m_verbose = verbose;
m_siteIdenEntry = entry;
if (m_siteCallsign == nullptr) {
m_siteCallsign = new uint8_t[NXDN_CALLSIGN_LENGTH_BYTES];
::memset(m_siteCallsign, 0x00U, NXDN_CALLSIGN_LENGTH_BYTES);
}
}
/// <summary>
@ -83,32 +97,43 @@ RCCH::~RCCH()
}
/// <summary>
/// Equals operator.
/// Sets the callsign.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
RCCH& RCCH::operator=(const RCCH& data)
/// <param name="callsign">Callsign.</param>
void RCCH::setCallsign(std::string callsign)
{
if (&data != this) {
copy(data);
if (m_siteCallsign == nullptr) {
m_siteCallsign = new uint8_t[NXDN_CALLSIGN_LENGTH_BYTES];
::memset(m_siteCallsign, 0x00U, NXDN_CALLSIGN_LENGTH_BYTES);
}
return *this;
uint32_t idLength = callsign.length();
if (idLength > 0) {
::memset(m_siteCallsign, 0x20U, NXDN_CALLSIGN_LENGTH_BYTES);
if (idLength > NXDN_CALLSIGN_LENGTH_BYTES)
idLength = NXDN_CALLSIGN_LENGTH_BYTES;
for (uint32_t i = 0; i < idLength; i++)
m_siteCallsign[i] = callsign[i];
}
}
/// ---------------------------------------------------------------------------
// Protected Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Decode call link control data.
/// Internal helper to decode a trunking signalling block.
/// </summary>
/// <param name="data"></param>
/// <param name="rcch"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
/// <returns>True, if RCCH was decoded, otherwise false.</returns>
void RCCH::decode(const uint8_t* data, uint32_t length, uint32_t offset)
void RCCH::decode(const uint8_t* data, uint8_t* rcch, uint32_t length, uint32_t offset)
{
assert(data != nullptr);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
assert(rcch != nullptr);
for (uint32_t i = 0U; i < length; i++, offset++) {
bool b = READ_BIT(data, offset);
@ -119,23 +144,22 @@ void RCCH::decode(const uint8_t* data, uint32_t length, uint32_t offset)
Utils::dump(2U, "Decoded RCCH Data", rcch, NXDN_RCCH_LC_LENGTH_BYTES);
}
decodeLC(rcch);
m_messageType = data[0U] & 0x3FU; // Message Type
}
/// <summary>
/// Encode call link control data.
/// Internal helper to encode a RCCH.
/// </summary>
/// <param name="data"></param>
/// <param name="rcch"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void RCCH::encode(uint8_t* data, uint32_t length, uint32_t offset)
void RCCH::encode(uint8_t* data, const uint8_t* rcch, uint32_t length, uint32_t offset)
{
assert(data != nullptr);
assert(rcch != nullptr);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
encodeLC(rcch);
data[0U] = m_messageType & 0x3FU; // Message Type
for (uint32_t i = 0U; i < length; i++, offset++) {
bool b = READ_BIT(rcch, i);
@ -147,315 +171,13 @@ void RCCH::encode(uint8_t* data, uint32_t length, uint32_t offset)
}
}
/// <summary>
///
/// </summary>
void RCCH::reset()
{
m_messageType = MESSAGE_TYPE_IDLE;
m_srcId = 0U;
m_dstId = 0U;
m_locId = 0U;
m_regOption = 0U;
m_version = 0U;
m_causeRsp = NXDN_CAUSE_MM_REG_ACCEPTED;
m_grpVchNo = 0U;
m_emergency = false;
m_encrypted = false;
m_priority = false;
m_group = true;
m_duplex = false;
m_transmissionMode = TRANSMISSION_MODE_4800;
}
/// <summary>
/// Sets the callsign.
/// </summary>
/// <param name="callsign">Callsign.</param>
void RCCH::setCallsign(std::string callsign)
{
uint32_t idLength = callsign.length();
if (idLength > 0) {
::memset(m_siteCallsign, 0x20U, NXDN_CALLSIGN_LENGTH_BYTES);
if (idLength > NXDN_CALLSIGN_LENGTH_BYTES)
idLength = NXDN_CALLSIGN_LENGTH_BYTES;
for (uint32_t i = 0; i < idLength; i++)
m_siteCallsign[i] = callsign[i];
}
}
/// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the RCCH class.
/// </summary>
RCCH::RCCH() : RCCH(SiteData())
{
/* stub */
}
/// <summary>
/// Initializes a new instance of the RCCH class.
/// </summary>
/// <param name="siteData"></param>
RCCH::RCCH(SiteData siteData) :
m_verbose(false),
m_messageType(MESSAGE_TYPE_IDLE),
m_srcId(0U),
m_dstId(0U),
m_locId(0U),
m_regOption(0U),
m_version(0U),
m_causeRsp(NXDN_CAUSE_MM_REG_ACCEPTED),
m_grpVchNo(0U),
m_callType(CALL_TYPE_UNSPECIFIED),
m_emergency(false),
m_encrypted(false),
m_priority(false),
m_group(true),
m_duplex(false),
m_transmissionMode(TRANSMISSION_MODE_4800),
m_siteData(siteData),
m_siteIdenEntry(),
m_bcchCnt(1U),
m_rcchGroupingCnt(1U),
m_ccchPagingCnt(2U),
m_ccchMultiCnt(2U),
m_rcchIterateCnt(2U)
{
m_siteCallsign = new uint8_t[NXDN_CALLSIGN_LENGTH_BYTES];
::memset(m_siteCallsign, 0x00U, NXDN_CALLSIGN_LENGTH_BYTES);
setCallsign(siteData.callsign());
}
/// <summary>
/// Decode link control.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
bool RCCH::decodeLC(const uint8_t* data)
{
assert(data != nullptr);
m_messageType = data[0U] & 0x3FU; // Message Type
// message type opcodes
switch (m_messageType) {
case RTCH_MESSAGE_TYPE_VCALL:
case RCCH_MESSAGE_TYPE_VCALL_CONN:
m_callType = (data[2U] >> 5) & 0x07U; // Call Type
m_emergency = (data[1U] & 0x80U) == 0x80U; // Emergency Flag
m_priority = (data[1U] & 0x20U) == 0x20U; // Priority Flag
m_duplex = (data[2U] & 0x10U) == 0x10U; // Half/Full Duplex Flag
m_transmissionMode = (data[2U] & 0x07U); // Transmission Mode
m_srcId = (uint16_t)((data[3U] << 8) | data[4U]) & 0xFFFFU; // Source Radio Address
m_dstId = (uint16_t)((data[5U] << 8) | data[6U]) & 0xFFFFU; // Target Radio Address
break;
case RTCH_MESSAGE_TYPE_DCALL_HDR:
m_callType = (data[2U] >> 5) & 0x07U; // Call Type
m_emergency = (data[1U] & 0x80U) == 0x80U; // Emergency Flag
m_priority = (data[1U] & 0x20U) == 0x20U; // Priority Flag
m_duplex = (data[2U] & 0x10U) == 0x10U; // Half/Full Duplex Flag
m_transmissionMode = (data[2U] & 0x07U); // Transmission Mode
m_srcId = (uint16_t)((data[3U] << 8) | data[4U]) & 0xFFFFU; // Source Radio Address
m_dstId = (uint16_t)((data[5U] << 8) | data[6U]) & 0xFFFFU; // Target Radio Address
break;
case MESSAGE_TYPE_IDLE:
break;
case RCCH_MESSAGE_TYPE_REG:
m_regOption = data[1U] >> 3; // Registration Option
m_locId = (uint16_t)((data[2U] << 8) | data[3U]) & 0xFFFFU; // Location ID
m_srcId = (uint16_t)((data[4U] << 8) | data[5U]) & 0xFFFFU; // Source Radio Address
m_dstId = (uint16_t)((data[6U] << 8) | data[7U]) & 0xFFFFU; // Target Radio Address
// bryanb: maybe process subscriber type? (byte 8 and 9)
m_version = data[10U]; // Version
break;
case RCCH_MESSAGE_TYPE_REG_C:
m_regOption = data[1U] >> 3; // Registration Option
m_locId = (uint16_t)((data[2U] << 8) | data[3U]) & 0xFFFFU; // Location ID
m_srcId = (uint16_t)((data[4U] << 8) | data[5U]) & 0xFFFFU; // Source Radio Address
break;
case RCCH_MESSAGE_TYPE_GRP_REG:
m_regOption = data[1U]; // Group Registration Option
m_srcId = (uint16_t)((data[2U] << 8) | data[3U]) & 0xFFFFU; // Source Radio Address
m_dstId = (uint16_t)((data[4U] << 8) | data[5U]) & 0xFFFFU; // Target Radio Address
break;
default:
LogError(LOG_NXDN, "RCCH::decodeRCCH(), unknown RCCH value, messageType = $%02X", m_messageType);
return false;
}
return true;
}
/// <summary>
/// Encode link control.
/// </summary>
/// <param name="rs"></param>
void RCCH::encodeLC(uint8_t* data)
{
assert(data != nullptr);
data[0U] = m_messageType & 0x3FU; // Message Type
// message type opcodes
switch (m_messageType) {
case RTCH_MESSAGE_TYPE_VCALL:
case RCCH_MESSAGE_TYPE_VCALL_CONN:
data[1U] = (m_emergency ? 0x80U : 0x00U) + // Emergency Flag
(m_priority ? 0x20U : 0x00U); // Priority Flag
data[2U] = ((m_callType & 0x07U) << 5) + // Call Type
(m_duplex ? 0x10U : 0x00U) + // Half/Full Duplex Flag
(m_transmissionMode & 0x07U); // Transmission Mode
data[3U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address
data[4U] = (m_srcId >> 0U) & 0xFFU; // ...
data[5U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address
data[6U] = (m_dstId >> 0U) & 0xFFU; // ...
data[7U] = m_causeRsp; // Cause (VD)
data[9U] = (m_siteData.locId() >> 8) & 0xFFU; // Location ID
data[10U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
break;
case RCCH_MESSAGE_TYPE_VCALL_ASSGN:
case RCCH_MESSAGE_TYPE_DCALL_ASSGN:
data[1U] = (m_emergency ? 0x80U : 0x00U) + // Emergency Flag
(m_priority ? 0x20U : 0x00U); // Priority Flag
data[2U] = ((m_callType & 0x07U) << 5) + // Call Type
(m_duplex ? 0x10U : 0x00U) + // Half/Full Duplex Flag
(m_transmissionMode & 0x07U); // Transmission Mode
data[3U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address
data[4U] = (m_srcId >> 0U) & 0xFFU; // ...
data[5U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address
data[6U] = (m_dstId >> 0U) & 0xFFU; // ...
data[7U] = (m_grpVchNo >> 10) & 0x03U; // Channel
data[8U] = (m_grpVchNo & 0xFFU); // ...
data[10U] = (m_siteData.locId() >> 8) & 0xFFU; // Location ID
data[11U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
break;
case RTCH_MESSAGE_TYPE_DCALL_HDR:
data[1U] = (m_emergency ? 0x80U : 0x00U) + // Emergency Flag
(m_priority ? 0x20U : 0x00U); // Priority Flag
data[2U] = ((m_callType & 0x07U) << 5) + // Call Type
(m_duplex ? 0x10U : 0x00U) + // Half/Full Duplex Flag
(m_transmissionMode & 0x07U); // Transmission Mode
data[3U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address
data[4U] = (m_srcId >> 0U) & 0xFFU; // ...
data[5U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address
data[6U] = (m_dstId >> 0U) & 0xFFU; // ...
data[7U] = m_causeRsp; // Cause (VD)
data[9U] = (m_siteData.locId() >> 8) & 0xFFU; // Location ID
data[10U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
break;
case MESSAGE_TYPE_IDLE:
break;
case MESSAGE_TYPE_DST_ID_INFO:
data[1U] = 0xC0U + NXDN_CALLSIGN_LENGTH_BYTES; // Station ID Option - Start / End / Character Count
data[2U] = (m_siteCallsign[0]); // Character 0
for (uint8_t i = 1; i < NXDN_CALLSIGN_LENGTH_BYTES; i++) {
data[i + 2U] = m_siteCallsign[i]; // Character 1 - 7
}
break;
case RCCH_MESSAGE_TYPE_SITE_INFO:
{
data[1U] = (m_siteData.locId() >> 16) & 0xFFU; // Location ID
data[2U] = (m_siteData.locId() >> 8) & 0xFFU; // ...
data[3U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
data[4U] = ((m_bcchCnt & 0x03U) << 6) + // Channel Structure - Number of BCCH
((m_rcchGroupingCnt & 0x07U) << 3) + // ... - Number of Grouping
(((m_ccchPagingCnt >> 1) & 0x07U) << 0); // ... - Number of Paging Frames
data[5U] = ((m_ccchPagingCnt & 0x01U) << 7) + // ... - Number of Paging Frames
((m_ccchMultiCnt & 0x07U) << 4) + // ... - Number of Multipurpose Frames
((m_rcchIterateCnt & 0x0FU) << 0); // ... - Number of Iteration
data[6U] = m_siteData.serviceClass(); // Service Information
data[7U] = (m_siteData.netActive() ? NXDN_SIF2_IP_NETWORK : 0x00U); // ...
// bryanb: this is currently fixed -- maybe dynamic in the future
data[8U] = 0U; // Restriction Information - No access restriction / No cycle restriction
data[9U] = 0x08U; // ... - No group restriction / GMS; Location Registration Restriction
data[10U] = (!m_siteData.netActive() ? 0x01U : 0x00U); // ... - No group ratio restriction / No delay time extension / ISO
// bryanb: this is currently fixed -- maybe dynamic in the future
data[11U] = NXDN_CH_ACCESS_BASE_FREQ_SYS_DEFINED; // Channel Access Information - Channel Version / Sys Defined Step / Sys Defined Base Freq
data[14U] = 1U; // Version
uint16_t channelNo = m_siteData.channelNo() & 0x3FFU;
data[15U] = (channelNo >> 6) & 0x0FU; // 1st Control Channel
data[16U] = (channelNo & 0x3FU) << 2; // ...
}
break;
case MESSAGE_TYPE_SRV_INFO:
data[1U] = (m_siteData.locId() >> 16) & 0xFFU; // Location ID
data[2U] = (m_siteData.locId() >> 8) & 0xFFU; // ...
data[3U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
data[4U] = m_siteData.serviceClass(); // Service Information
data[5U] = (m_siteData.netActive() ? NXDN_SIF2_IP_NETWORK : 0x00U); // ...
// bryanb: this is currently fixed -- maybe dynamic in the future
data[6U] = 0U; // Restriction Information - No access restriction / No cycle restriction
data[7U] = 0x08U; // ... - No group restriction / GMS; Location Registration Restriction
data[8U] = (!m_siteData.netActive() ? 0x01U : 0x00U); // ... - No group ratio restriction / No delay time extension / ISO
break;
case RCCH_MESSAGE_TYPE_REG:
data[2U] = (m_siteData.locId() >> 8) & 0xFFU; // ...
data[3U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
data[4U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address
data[5U] = (m_srcId >> 0U) & 0xFFU; // ...
data[6U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address
data[7U] = (m_dstId >> 0U) & 0xFFU; // ...
data[8U] = m_causeRsp; // Cause (MM)
break;
case RCCH_MESSAGE_TYPE_REG_C:
data[2U] = (m_siteData.locId() >> 8) & 0xFFU; // Location ID
data[3U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
data[4U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address
data[5U] = (m_dstId >> 0U) & 0xFFU; // ...
data[6U] = m_causeRsp; // Cause (MM)
break;
case RCCH_MESSAGE_TYPE_REG_COMM:
data[2U] = (m_siteData.locId() >> 8) & 0xFFU; // Location ID
data[3U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
data[4U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address
data[5U] = (m_dstId >> 0U) & 0xFFU; // ...
break;
case RCCH_MESSAGE_TYPE_GRP_REG:
data[2U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address
data[3U] = (m_srcId >> 0U) & 0xFFU; // ...
data[4U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address
data[5U] = (m_dstId >> 0U) & 0xFFU; // ...
data[6U] = m_causeRsp; // Cause (MM)
data[8U] = (m_siteData.locId() >> 8) & 0xFFU; // Location ID
data[9U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
break;
default:
LogError(LOG_NXDN, "RCCH::encodeRCCH(), unknown RCCH value, messageType = $%02X", m_messageType);
return;
}
}
// <summary>
/// Internal helper to copy the the class.
/// </summary>
/// <param name="data"></param>
void RCCH::copy(const RCCH& data)
{
m_verbose = data.m_verbose;
m_messageType = data.m_messageType;
m_srcId = data.m_srcId;
m_dstId = data.m_dstId;
@ -479,19 +201,5 @@ void RCCH::copy(const RCCH& data)
m_transmissionMode = data.m_transmissionMode;
m_siteData = data.m_siteData;
m_siteIdenEntry = data.m_siteIdenEntry;
delete[] m_siteCallsign;
uint8_t* callsign = new uint8_t[NXDN_CALLSIGN_LENGTH_BYTES];
::memcpy(callsign, data.m_siteCallsign, NXDN_CALLSIGN_LENGTH_BYTES);
m_siteCallsign = callsign;
m_bcchCnt = data.m_bcchCnt;
m_rcchGroupingCnt = data.m_rcchGroupingCnt;
m_ccchPagingCnt = data.m_ccchPagingCnt;
m_ccchMultiCnt = data.m_ccchMultiCnt;
m_rcchIterateCnt = data.m_rcchIterateCnt;
}

@ -48,107 +48,88 @@ namespace nxdn
public:
/// <summary>Initializes a copy instance of the RCCH class.</summary>
RCCH(const RCCH& data);
/// <summary>Initializes a new instance of the TSBK class.</summary>
RCCH(SiteData siteData, lookups::IdenTable entry);
/// <summary>Initializes a new instance of the TSBK class.</summary>
RCCH(SiteData siteData, lookups::IdenTable entry, bool verbose);
/// <summary>Initializes a new instance of the RCCH class.</summary>
RCCH();
/// <summary>Finalizes a instance of the RCCH class.</summary>
~RCCH();
/// <summary>Equals operator.</summary>
RCCH& operator=(const RCCH& data);
virtual ~RCCH();
/// <summary>Decode layer 3 data.</summary>
void decode(const uint8_t* data, uint32_t length, uint32_t offset = 0U);
virtual void decode(const uint8_t* data, uint32_t length, uint32_t offset = 0U) = 0;
/// <summary>Encode layer 3 data.</summary>
void encode(uint8_t* data, uint32_t length, uint32_t offset = 0U);
virtual void encode(uint8_t* data, uint32_t length, uint32_t offset = 0U) = 0;
/// <summary></summary>
void reset();
/// <summary>Sets the flag indicating verbose log output.</summary>
static void setVerbose(bool verbose) { m_verbose = verbose; }
/** Local Site data */
/// <summary>Sets the callsign.</summary>
void setCallsign(std::string callsign);
static void setCallsign(std::string callsign);
public:
/// <summary>Flag indicating verbose log output.</summary>
__PROPERTY(bool, verbose, Verbose);
/// <summary>Gets the local site data.</summary>
static SiteData getSiteData() { return m_siteData; }
/// <summary>Sets the local site data.</summary>
static void setSiteData(SiteData siteData) { m_siteData = siteData; }
public:
/** Common Data */
/// <summary>Message Type</summary>
__PROPERTY(uint8_t, messageType, MessageType);
__PROTECTED_PROPERTY(uint8_t, messageType, MessageType);
/// <summary>Source ID.</summary>
__PROPERTY(uint16_t, srcId, SrcId);
__PROTECTED_PROPERTY(uint16_t, srcId, SrcId);
/// <summary>Destination ID.</summary>
__PROPERTY(uint16_t, dstId, DstId);
__PROTECTED_PROPERTY(uint16_t, dstId, DstId);
/// <summary>Location ID.</summary>
__PROPERTY(uint32_t, locId, LocId);
__PROTECTED_PROPERTY(uint32_t, locId, LocId);
/// <summary>Registration Option.</summary>
__PROPERTY(uint8_t, regOption, RegOption);
__PROTECTED_PROPERTY(uint8_t, regOption, RegOption);
/// <summary>Version Number.</summary>
__PROPERTY(uint8_t, version, Version);
__PROTECTED_PROPERTY(uint8_t, version, Version);
/// <summary>Cause Response.</summary>
__PROPERTY(uint8_t, causeRsp, CauseResponse);
__PROTECTED_PROPERTY(uint8_t, causeRsp, CauseResponse);
/// <summary>Voice channel number.</summary>
__PROPERTY(uint32_t, grpVchNo, GrpVchNo);
__PROTECTED_PROPERTY(uint32_t, grpVchNo, GrpVchNo);
/** Call Data */
/// <summary>Call Type</summary>
__PROPERTY(uint8_t, callType, CallType);
__PROTECTED_PROPERTY(uint8_t, callType, CallType);
/** Common Call Options */
/// <summary>Flag indicating the emergency bits are set.</summary>
__PROPERTY(bool, emergency, Emergency);
__PROTECTED_PROPERTY(bool, emergency, Emergency);
/// <summary>Flag indicating that encryption is enabled.</summary>
__PROPERTY(bool, encrypted, Encrypted);
__PROTECTED_PROPERTY(bool, encrypted, Encrypted);
/// <summary>Flag indicating priority paging.</summary>
__PROPERTY(bool, priority, Priority);
__PROTECTED_PROPERTY(bool, priority, Priority);
/// <summary>Flag indicating a group/talkgroup operation.</summary>
__PROPERTY(bool, group, Group);
__PROTECTED_PROPERTY(bool, group, Group);
/// <summary>Flag indicating a half/full duplex operation.</summary>
__PROPERTY(bool, duplex, Duplex);
__PROTECTED_PROPERTY(bool, duplex, Duplex);
/// <summary>Transmission mode.</summary>
__PROPERTY(uint8_t, transmissionMode, TransmissionMode);
__PROTECTED_PROPERTY(uint8_t, transmissionMode, TransmissionMode);
/** Local Site data */
/// <summary>Local Site Data.</summary>
__PROPERTY_PLAIN(SiteData, siteData, siteData);
/// <summary>Local Site Identity Entry.</summary>
__PROPERTY_PLAIN(lookups::IdenTable, siteIdenEntry, siteIdenEntry);
/** Channel Structure Data */
/// <summary>Count of BCCH frames per RCCH superframe.</summary>
__PROPERTY(uint8_t, bcchCnt, BcchCnt);
/// <summary>Count of RCCH frame groupings per RCCH superframe.</summary>
__PROPERTY(uint8_t, rcchGroupingCnt, RcchGroupingCnt);
/// <summary>Count of CCCH/UPCH paging frames per RCCH superframe.</summary>
__PROPERTY(uint8_t, ccchPagingCnt, CcchPagingCnt);
/// <summary>Count of CCCH/UPCH multi-purpose frames per RCCH superframe.</summary>
__PROPERTY(uint8_t, ccchMultiCnt, CcchMultiCnt);
/// <summary>Count of group iterations per RCCH superframe.</summary>
__PROPERTY(uint8_t, rcchIterateCnt, RcchIterateCount);
private:
/// <summary>Initializes a new instance of the RCCH class.</summary>
RCCH();
/// <summary>Initializes a new instance of the RCCH class.</summary>
RCCH(SiteData siteData);
__PROTECTED_PROPERTY_PLAIN(lookups::IdenTable, siteIdenEntry, siteIdenEntry);
protected:
static bool m_verbose;
/** Local Site data */
uint8_t* m_siteCallsign;
static uint8_t* m_siteCallsign;
static SiteData m_siteData;
/// <summary>Decode link control.</summary>
bool decodeLC(const uint8_t* data);
/// <summary>Encode link control.</summary>
void encodeLC(uint8_t* data);
/// <summary>Internal helper to decode a RCCH.</summary>
void decode(const uint8_t* data, uint8_t* rcch, uint32_t length, uint32_t offset = 0U);
/// <summary>Internal helper to encode a RCCH.</summary>
void encode(uint8_t* data, const uint8_t* rcch, uint32_t length, uint32_t offset = 0U);
/// <summary>Internal helper to copy the class.</summary>
void copy(const RCCH& data);
__PROTECTED_COPY(RCCH);
};
} // namespace lc
} // namespace nxdn

@ -40,6 +40,12 @@ using namespace nxdn::lc;
#include <cassert>
#include <cstring>
// ---------------------------------------------------------------------------
// Static Class Members
// ---------------------------------------------------------------------------
bool RTCH::m_verbose = false;
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
@ -48,7 +54,6 @@ using namespace nxdn::lc;
/// Initializes a new instance of the RTCH class.
/// </summary>
RTCH::RTCH() :
m_verbose(false),
m_messageType(MESSAGE_TYPE_IDLE),
m_callType(CALL_TYPE_UNSPECIFIED),
m_srcId(0U),
@ -77,7 +82,6 @@ RTCH::RTCH() :
/// </summary>
/// <param name="data"></param>
RTCH::RTCH(const RTCH& data) :
m_verbose(false),
m_messageType(MESSAGE_TYPE_IDLE),
m_callType(CALL_TYPE_UNSPECIFIED),
m_srcId(0U),
@ -449,8 +453,6 @@ void RTCH::encodeLC(uint8_t* data)
/// <param name="data"></param>
void RTCH::copy(const RTCH& data)
{
m_verbose = data.m_verbose;
m_messageType = data.m_messageType;
m_callType = data.m_callType;

@ -63,10 +63,10 @@ namespace nxdn
/// <summary></summary>
void reset();
public:
/// <summary>Flag indicating verbose log output.</summary>
__PROPERTY(bool, verbose, Verbose);
/// <summary>Sets the flag indicating verbose log output.</summary>
static void setVerbose(bool verbose) { m_verbose = verbose; }
public:
/** Common Data */
/// <summary>Message Type</summary>
__PROPERTY(uint8_t, messageType, MessageType);
@ -118,6 +118,8 @@ namespace nxdn
__PROPERTY(uint8_t, causeRsp, CauseResponse);
private:
static bool m_verbose;
/** Encryption data */
uint8_t* m_mi;

@ -0,0 +1,103 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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.
*/
#include "Defines.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_DCALL_HDR.h"
#include "Log.h"
#include "Utils.h"
using namespace nxdn::lc::rcch;
using namespace nxdn::lc;
using namespace nxdn;
#include <cassert>
#include <cmath>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the MESSAGE_TYPE_DCALL_HDR class.
/// </summary>
MESSAGE_TYPE_DCALL_HDR::MESSAGE_TYPE_DCALL_HDR() : RCCH()
{
m_messageType = RTCH_MESSAGE_TYPE_DCALL_HDR;
}
/// <summary>
/// Decode layer 3 data.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_DCALL_HDR::decode(const uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
RCCH::decode(data, rcch, length, offset);
m_callType = (rcch[2U] >> 5) & 0x07U; // Call Type
m_emergency = (rcch[1U] & 0x80U) == 0x80U; // Emergency Flag
m_priority = (rcch[1U] & 0x20U) == 0x20U; // Priority Flag
m_duplex = (rcch[2U] & 0x10U) == 0x10U; // Half/Full Duplex Flag
m_transmissionMode = (rcch[2U] & 0x07U); // Transmission Mode
m_srcId = (uint16_t)((rcch[3U] << 8) | rcch[4U]) & 0xFFFFU; // Source Radio Address
m_dstId = (uint16_t)((rcch[5U] << 8) | rcch[6U]) & 0xFFFFU; // Target Radio Address
}
/// <summary>
/// Encode a control signalling block.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_DCALL_HDR::encode(uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
rcch[1U] = (m_emergency ? 0x80U : 0x00U) + // Emergency Flag
(m_priority ? 0x20U : 0x00U); // Priority Flag
rcch[2U] = ((m_callType & 0x07U) << 5) + // Call Type
(m_duplex ? 0x10U : 0x00U) + // Half/Full Duplex Flag
(m_transmissionMode & 0x07U); // Transmission Mode
rcch[3U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address
rcch[4U] = (m_srcId >> 0U) & 0xFFU; // ...
rcch[5U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address
rcch[6U] = (m_dstId >> 0U) & 0xFFU; // ...
rcch[7U] = m_causeRsp; // Cause (VD)
rcch[9U] = (m_siteData.locId() >> 8) & 0xFFU; // Location ID
rcch[10U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
RCCH::encode(data, rcch, length, offset);
}

@ -0,0 +1,58 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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_LC_RCCH__MESSAGE_TYPE_DCALL_HDR_H__)
#define __NXDN_LC_RCCH__MESSAGE_TYPE_DCALL_HDR_H__
#include "Defines.h"
#include "nxdn/lc/RCCH.h"
namespace nxdn
{
namespace lc
{
namespace rcch
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements VCALL_CONN - Voice Call Connection Request (ISP) and
// Voice Call Connection Response (OSP)
// ---------------------------------------------------------------------------
class HOST_SW_API MESSAGE_TYPE_DCALL_HDR : public RCCH {
public:
/// <summary>Initializes a new instance of the MESSAGE_TYPE_DCALL_HDR class.</summary>
MESSAGE_TYPE_DCALL_HDR();
/// <summary>Decode layer 3 data.</summary>
virtual void decode(const uint8_t* data, uint32_t length, uint32_t offset = 0U);
/// <summary>Encode layer 3 data.</summary>
virtual void encode(uint8_t* data, uint32_t length, uint32_t offset = 0U);
};
} // namespace rcch
} // namespace lc
} // namespace nxdn
#endif // __NXDN_LC_RCCH__MESSAGE_TYPE_DCALL_HDR_H__

@ -0,0 +1,86 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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.
*/
#include "Defines.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_DST_ID_INFO.h"
#include "Log.h"
#include "Utils.h"
using namespace nxdn::lc::rcch;
using namespace nxdn::lc;
using namespace nxdn;
#include <cassert>
#include <cmath>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the MESSAGE_TYPE_DST_ID_INFO class.
/// </summary>
MESSAGE_TYPE_DST_ID_INFO::MESSAGE_TYPE_DST_ID_INFO() : RCCH()
{
m_messageType = nxdn::MESSAGE_TYPE_DST_ID_INFO;
}
/// <summary>
/// Decode layer 3 data.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_DST_ID_INFO::decode(const uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
RCCH::decode(data, rcch, length, offset);
}
/// <summary>
/// Encode a control signalling block.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_DST_ID_INFO::encode(uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
rcch[1U] = 0xC0U + NXDN_CALLSIGN_LENGTH_BYTES; // Station ID Option - Start / End / Character Count
rcch[2U] = (m_siteCallsign[0]); // Character 0
for (uint8_t i = 1; i < NXDN_CALLSIGN_LENGTH_BYTES; i++) {
rcch[i + 2U] = m_siteCallsign[i]; // Character 1 - 7
}
RCCH::encode(data, rcch, length, offset);
}

@ -0,0 +1,57 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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_LC_RCCH__MESSAGE_TYPE_DST_ID_INFO_H__)
#define __NXDN_LC_RCCH__MESSAGE_TYPE_DST_ID_INFO_H__
#include "Defines.h"
#include "nxdn/lc/RCCH.h"
namespace nxdn
{
namespace lc
{
namespace rcch
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements DST_ID_INFO - Digital Station ID
// ---------------------------------------------------------------------------
class HOST_SW_API MESSAGE_TYPE_DST_ID_INFO : public RCCH {
public:
/// <summary>Initializes a new instance of the MESSAGE_TYPE_DST_ID_INFO class.</summary>
MESSAGE_TYPE_DST_ID_INFO();
/// <summary>Decode layer 3 data.</summary>
virtual void decode(const uint8_t* data, uint32_t length, uint32_t offset = 0U);
/// <summary>Encode layer 3 data.</summary>
virtual void encode(uint8_t* data, uint32_t length, uint32_t offset = 0U);
};
} // namespace rcch
} // namespace lc
} // namespace nxdn
#endif // __NXDN_LC_RCCH__MESSAGE_TYPE_DST_ID_INFO_H__

@ -0,0 +1,92 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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.
*/
#include "Defines.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_GRP_REG.h"
#include "Log.h"
#include "Utils.h"
using namespace nxdn::lc::rcch;
using namespace nxdn::lc;
using namespace nxdn;
#include <cassert>
#include <cmath>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the MESSAGE_TYPE_GRP_REG class.
/// </summary>
MESSAGE_TYPE_GRP_REG::MESSAGE_TYPE_GRP_REG() : RCCH()
{
m_messageType = RCCH_MESSAGE_TYPE_GRP_REG;
}
/// <summary>
/// Decode layer 3 data.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_GRP_REG::decode(const uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
RCCH::decode(data, rcch, length, offset);
m_regOption = rcch[1U]; // Group Registration Option
m_srcId = (uint16_t)((rcch[2U] << 8) | rcch[3U]) & 0xFFFFU; // Source Radio Address
m_dstId = (uint16_t)((rcch[4U] << 8) | rcch[5U]) & 0xFFFFU; // Target Radio Address
}
/// <summary>
/// Encode a control signalling block.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_GRP_REG::encode(uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
rcch[2U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address
rcch[3U] = (m_srcId >> 0U) & 0xFFU; // ...
rcch[4U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address
rcch[5U] = (m_dstId >> 0U) & 0xFFU; // ...
rcch[6U] = m_causeRsp; // Cause (MM)
rcch[8U] = (m_siteData.locId() >> 8) & 0xFFU; // Location ID
rcch[9U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
RCCH::encode(data, rcch, length, offset);
}

@ -0,0 +1,58 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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_LC_RCCH__MESSAGE_TYPE_GRP_REG_H__)
#define __NXDN_LC_RCCH__MESSAGE_TYPE_GRP_REG_H__
#include "Defines.h"
#include "nxdn/lc/RCCH.h"
namespace nxdn
{
namespace lc
{
namespace rcch
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements GRP_REG - Group Registration Request (ISP) and
// Group Registration Response (OSP)
// ---------------------------------------------------------------------------
class HOST_SW_API MESSAGE_TYPE_GRP_REG : public RCCH {
public:
/// <summary>Initializes a new instance of the MESSAGE_TYPE_GRP_REG class.</summary>
MESSAGE_TYPE_GRP_REG();
/// <summary>Decode layer 3 data.</summary>
virtual void decode(const uint8_t* data, uint32_t length, uint32_t offset = 0U);
/// <summary>Encode layer 3 data.</summary>
virtual void encode(uint8_t* data, uint32_t length, uint32_t offset = 0U);
};
} // namespace rcch
} // namespace lc
} // namespace nxdn
#endif // __NXDN_LC_RCCH__MESSAGE_TYPE_GRP_REG_H__

@ -0,0 +1,80 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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.
*/
#include "Defines.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_IDLE.h"
#include "Log.h"
#include "Utils.h"
using namespace nxdn::lc::rcch;
using namespace nxdn::lc;
using namespace nxdn;
#include <cassert>
#include <cmath>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the MESSAGE_TYPE_IDLE class.
/// </summary>
MESSAGE_TYPE_IDLE::MESSAGE_TYPE_IDLE() : RCCH()
{
m_messageType = nxdn::MESSAGE_TYPE_IDLE;
}
/// <summary>
/// Decode layer 3 data.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_IDLE::decode(const uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
RCCH::decode(data, rcch, length, offset);
}
/// <summary>
/// Encode a control signalling block.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_IDLE::encode(uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
RCCH::encode(data, rcch, length, offset);
}

@ -0,0 +1,57 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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_LC_RCCH__MESSAGE_TYPE_IDLE_H__)
#define __NXDN_LC_RCCH__MESSAGE_TYPE_IDLE_H__
#include "Defines.h"
#include "nxdn/lc/RCCH.h"
namespace nxdn
{
namespace lc
{
namespace rcch
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements IDLE - Idle
// ---------------------------------------------------------------------------
class HOST_SW_API MESSAGE_TYPE_IDLE : public RCCH {
public:
/// <summary>Initializes a new instance of the MESSAGE_TYPE_IDLE class.</summary>
MESSAGE_TYPE_IDLE();
/// <summary>Decode layer 3 data.</summary>
virtual void decode(const uint8_t* data, uint32_t length, uint32_t offset = 0U);
/// <summary>Encode layer 3 data.</summary>
virtual void encode(uint8_t* data, uint32_t length, uint32_t offset = 0U);
};
} // namespace rcch
} // namespace lc
} // namespace nxdn
#endif // __NXDN_LC_RCCH__MESSAGE_TYPE_IDLE_H__

@ -0,0 +1,95 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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.
*/
#include "Defines.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_REG.h"
#include "Log.h"
#include "Utils.h"
using namespace nxdn::lc::rcch;
using namespace nxdn::lc;
using namespace nxdn;
#include <cassert>
#include <cmath>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the MESSAGE_TYPE_REG class.
/// </summary>
MESSAGE_TYPE_REG::MESSAGE_TYPE_REG() : RCCH()
{
m_messageType = RCCH_MESSAGE_TYPE_REG;
}
/// <summary>
/// Decode layer 3 data.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_REG::decode(const uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
RCCH::decode(data, rcch, length, offset);
m_regOption = rcch[1U] >> 3; // Registration Option
m_locId = (uint16_t)((rcch[2U] << 8) | rcch[3U]) & 0xFFFFU; // Location ID
m_srcId = (uint16_t)((rcch[4U] << 8) | rcch[5U]) & 0xFFFFU; // Source Radio Address
m_dstId = (uint16_t)((rcch[6U] << 8) | rcch[7U]) & 0xFFFFU; // Target Radio Address
// bryanb: maybe process subscriber type? (byte 8 and 9)
m_version = rcch[10U]; // Version
}
/// <summary>
/// Encode a control signalling block.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_REG::encode(uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
rcch[2U] = (m_siteData.locId() >> 8) & 0xFFU; // ...
rcch[3U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
rcch[4U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address
rcch[5U] = (m_srcId >> 0U) & 0xFFU; // ...
rcch[6U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address
rcch[7U] = (m_dstId >> 0U) & 0xFFU; // ...
rcch[8U] = m_causeRsp; // Cause (MM)
RCCH::encode(data, rcch, length, offset);
}

@ -0,0 +1,58 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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_LC_RCCH__MESSAGE_TYPE_REG_H__)
#define __NXDN_LC_RCCH__MESSAGE_TYPE_REG_H__
#include "Defines.h"
#include "nxdn/lc/RCCH.h"
namespace nxdn
{
namespace lc
{
namespace rcch
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements REG - Registration Request (ISP) and
// Registration Response (OSP)
// ---------------------------------------------------------------------------
class HOST_SW_API MESSAGE_TYPE_REG : public RCCH {
public:
/// <summary>Initializes a new instance of the MESSAGE_TYPE_REG class.</summary>
MESSAGE_TYPE_REG();
/// <summary>Decode layer 3 data.</summary>
virtual void decode(const uint8_t* data, uint32_t length, uint32_t offset = 0U);
/// <summary>Encode layer 3 data.</summary>
virtual void encode(uint8_t* data, uint32_t length, uint32_t offset = 0U);
};
} // namespace rcch
} // namespace lc
} // namespace nxdn
#endif // __NXDN_LC_RCCH__MESSAGE_TYPE_REG_H__

@ -0,0 +1,90 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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.
*/
#include "Defines.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_REG_C.h"
#include "Log.h"
#include "Utils.h"
using namespace nxdn::lc::rcch;
using namespace nxdn::lc;
using namespace nxdn;
#include <cassert>
#include <cmath>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the MESSAGE_TYPE_REG_C class.
/// </summary>
MESSAGE_TYPE_REG_C::MESSAGE_TYPE_REG_C() : RCCH()
{
m_messageType = RCCH_MESSAGE_TYPE_REG_C;
}
/// <summary>
/// Decode layer 3 data.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_REG_C::decode(const uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
RCCH::decode(data, rcch, length, offset);
m_regOption = rcch[1U] >> 3; // Registration Option
m_locId = (uint16_t)((rcch[2U] << 8) | rcch[3U]) & 0xFFFFU; // Location ID
m_srcId = (uint16_t)((rcch[4U] << 8) | rcch[5U]) & 0xFFFFU; // Source Radio Address
}
/// <summary>
/// Encode a control signalling block.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_REG_C::encode(uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
rcch[2U] = (m_siteData.locId() >> 8) & 0xFFU; // Location ID
rcch[3U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
rcch[4U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address
rcch[5U] = (m_dstId >> 0U) & 0xFFU; // ...
rcch[6U] = m_causeRsp; // Cause (MM)
RCCH::encode(data, rcch, length, offset);
}

@ -0,0 +1,58 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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_LC_RCCH__MESSAGE_TYPE_REG_C_H__)
#define __NXDN_LC_RCCH__MESSAGE_TYPE_REG_C_H__
#include "Defines.h"
#include "nxdn/lc/RCCH.h"
namespace nxdn
{
namespace lc
{
namespace rcch
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements REG_C - Registration Clear Request (ISP) and
// Registration Clear Response (OSP)
// ---------------------------------------------------------------------------
class HOST_SW_API MESSAGE_TYPE_REG_C : public RCCH {
public:
/// <summary>Initializes a new instance of the MESSAGE_TYPE_REG_C class.</summary>
MESSAGE_TYPE_REG_C();
/// <summary>Decode layer 3 data.</summary>
virtual void decode(const uint8_t* data, uint32_t length, uint32_t offset = 0U);
/// <summary>Encode layer 3 data.</summary>
virtual void encode(uint8_t* data, uint32_t length, uint32_t offset = 0U);
};
} // namespace rcch
} // namespace lc
} // namespace nxdn
#endif // __NXDN_LC_RCCH__MESSAGE_TYPE_REG_C_H__

@ -0,0 +1,85 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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.
*/
#include "Defines.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_REG_COMM.h"
#include "Log.h"
#include "Utils.h"
using namespace nxdn::lc::rcch;
using namespace nxdn::lc;
using namespace nxdn;
#include <cassert>
#include <cmath>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the MESSAGE_TYPE_REG_COMM class.
/// </summary>
MESSAGE_TYPE_REG_COMM::MESSAGE_TYPE_REG_COMM() : RCCH()
{
m_messageType = RCCH_MESSAGE_TYPE_REG_COMM;
}
/// <summary>
/// Decode layer 3 data.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_REG_COMM::decode(const uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
RCCH::decode(data, rcch, length, offset);
}
/// <summary>
/// Encode a control signalling block.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_REG_COMM::encode(uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
rcch[2U] = (m_siteData.locId() >> 8) & 0xFFU; // Location ID
rcch[3U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
rcch[4U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address
rcch[5U] = (m_dstId >> 0U) & 0xFFU; // ...
RCCH::encode(data, rcch, length, offset);
}

@ -0,0 +1,57 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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_LC_RCCH__MESSAGE_TYPE_REG_COMM_H__)
#define __NXDN_LC_RCCH__MESSAGE_TYPE_REG_COMM_H__
#include "Defines.h"
#include "nxdn/lc/RCCH.h"
namespace nxdn
{
namespace lc
{
namespace rcch
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements REG_COMM - Registration Command
// ---------------------------------------------------------------------------
class HOST_SW_API MESSAGE_TYPE_REG_COMM : public RCCH {
public:
/// <summary>Initializes a new instance of the MESSAGE_TYPE_REG_COMM class.</summary>
MESSAGE_TYPE_REG_COMM();
/// <summary>Decode layer 3 data.</summary>
virtual void decode(const uint8_t* data, uint32_t length, uint32_t offset = 0U);
/// <summary>Encode layer 3 data.</summary>
virtual void encode(uint8_t* data, uint32_t length, uint32_t offset = 0U);
};
} // namespace rcch
} // namespace lc
} // namespace nxdn
#endif // __NXDN_LC_RCCH__MESSAGE_TYPE_REG_COMM_H__

@ -0,0 +1,131 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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.
*/
#include "Defines.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_SITE_INFO.h"
#include "Log.h"
#include "Utils.h"
using namespace nxdn::lc::rcch;
using namespace nxdn::lc;
using namespace nxdn;
#include <cassert>
#include <cmath>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the MESSAGE_TYPE_SITE_INFO class.
/// </summary>
MESSAGE_TYPE_SITE_INFO::MESSAGE_TYPE_SITE_INFO() : RCCH(),
m_bcchCnt(1U),
m_rcchGroupingCnt(1U),
m_ccchPagingCnt(2U),
m_ccchMultiCnt(2U),
m_rcchIterateCnt(2U)
{
m_messageType = RCCH_MESSAGE_TYPE_SITE_INFO;
}
/// <summary>
/// Decode layer 3 data.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_SITE_INFO::decode(const uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
RCCH::decode(data, rcch, length, offset);
}
/// <summary>
/// Encode a control signalling block.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_SITE_INFO::encode(uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
rcch[1U] = (m_siteData.locId() >> 16) & 0xFFU; // Location ID
rcch[2U] = (m_siteData.locId() >> 8) & 0xFFU; // ...
rcch[3U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
rcch[4U] = ((m_bcchCnt & 0x03U) << 6) + // Channel Structure - Number of BCCH
((m_rcchGroupingCnt & 0x07U) << 3) + // ... - Number of Grouping
(((m_ccchPagingCnt >> 1) & 0x07U) << 0); // ... - Number of Paging Frames
rcch[5U] = ((m_ccchPagingCnt & 0x01U) << 7) + // ... - Number of Paging Frames
((m_ccchMultiCnt & 0x07U) << 4) + // ... - Number of Multipurpose Frames
((m_rcchIterateCnt & 0x0FU) << 0); // ... - Number of Iteration
rcch[6U] = m_siteData.serviceClass(); // Service Information
rcch[7U] = (m_siteData.netActive() ? NXDN_SIF2_IP_NETWORK : 0x00U); // ...
// bryanb: this is currently fixed -- maybe dynamic in the future
rcch[8U] = 0U; // Restriction Information - No access restriction / No cycle restriction
rcch[9U] = 0x08U; // ... - No group restriction / GMS; Location Registration Restriction
rcch[10U] = (!m_siteData.netActive() ? 0x01U : 0x00U); // ... - No group ratio restriction / No delay time extension / ISO
// bryanb: this is currently fixed -- maybe dynamic in the future
rcch[11U] = NXDN_CH_ACCESS_BASE_FREQ_SYS_DEFINED; // Channel Access Information - Channel Version / Sys Defined Step / Sys Defined Base Freq
rcch[14U] = 1U; // Version
uint16_t channelNo = m_siteData.channelNo() & 0x3FFU;
rcch[15U] = (channelNo >> 6) & 0x0FU; // 1st Control Channel
rcch[16U] = (channelNo & 0x3FU) << 2; // ...
RCCH::encode(data, rcch, length, offset);
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Internal helper to copy the the class.
/// </summary>
/// <param name="data"></param>
void MESSAGE_TYPE_SITE_INFO::copy(const MESSAGE_TYPE_SITE_INFO& data)
{
RCCH::copy(data);
m_bcchCnt = data.m_bcchCnt;
m_rcchGroupingCnt = data.m_rcchGroupingCnt;
m_ccchPagingCnt = data.m_ccchPagingCnt;
m_ccchMultiCnt = data.m_ccchMultiCnt;
m_rcchIterateCnt = data.m_rcchIterateCnt;
}

@ -0,0 +1,72 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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_LC_RCCH__MESSAGE_TYPE_SITE_INFO_H__)
#define __NXDN_LC_RCCH__MESSAGE_TYPE_SITE_INFO_H__
#include "Defines.h"
#include "nxdn/lc/RCCH.h"
namespace nxdn
{
namespace lc
{
namespace rcch
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements SITE_INFO - Site Information
// ---------------------------------------------------------------------------
class HOST_SW_API MESSAGE_TYPE_SITE_INFO : public RCCH {
public:
/// <summary>Initializes a new instance of the MESSAGE_TYPE_SITE_INFO class.</summary>
MESSAGE_TYPE_SITE_INFO();
/// <summary>Decode layer 3 data.</summary>
virtual void decode(const uint8_t* data, uint32_t length, uint32_t offset = 0U);
/// <summary>Encode layer 3 data.</summary>
virtual void encode(uint8_t* data, uint32_t length, uint32_t offset = 0U);
public:
/** Channel Structure Data */
/// <summary>Count of BCCH frames per RCCH superframe.</summary>
__PROPERTY(uint8_t, bcchCnt, BcchCnt);
/// <summary>Count of RCCH frame groupings per RCCH superframe.</summary>
__PROPERTY(uint8_t, rcchGroupingCnt, RcchGroupingCnt);
/// <summary>Count of CCCH/UPCH paging frames per RCCH superframe.</summary>
__PROPERTY(uint8_t, ccchPagingCnt, CcchPagingCnt);
/// <summary>Count of CCCH/UPCH multi-purpose frames per RCCH superframe.</summary>
__PROPERTY(uint8_t, ccchMultiCnt, CcchMultiCnt);
/// <summary>Count of group iterations per RCCH superframe.</summary>
__PROPERTY(uint8_t, rcchIterateCnt, RcchIterateCount);
__COPY(MESSAGE_TYPE_SITE_INFO);
};
} // namespace rcch
} // namespace lc
} // namespace nxdn
#endif // __NXDN_LC_RCCH__MESSAGE_TYPE_SITE_INFO_H__

@ -0,0 +1,91 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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.
*/
#include "Defines.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_SRV_INFO.h"
#include "Log.h"
#include "Utils.h"
using namespace nxdn::lc::rcch;
using namespace nxdn::lc;
using namespace nxdn;
#include <cassert>
#include <cmath>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the MESSAGE_TYPE_SRV_INFO class.
/// </summary>
MESSAGE_TYPE_SRV_INFO::MESSAGE_TYPE_SRV_INFO() : RCCH()
{
m_messageType = nxdn::MESSAGE_TYPE_SRV_INFO;
}
/// <summary>
/// Decode layer 3 data.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_SRV_INFO::decode(const uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
RCCH::decode(data, rcch, length, offset);
}
/// <summary>
/// Encode a control signalling block.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_SRV_INFO::encode(uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
rcch[1U] = (m_siteData.locId() >> 16) & 0xFFU; // Location ID
rcch[2U] = (m_siteData.locId() >> 8) & 0xFFU; // ...
rcch[3U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
rcch[4U] = m_siteData.serviceClass(); // Service Information
rcch[5U] = (m_siteData.netActive() ? NXDN_SIF2_IP_NETWORK : 0x00U); // ...
// bryanb: this is currently fixed -- maybe dynamic in the future
rcch[6U] = 0U; // Restriction Information - No access restriction / No cycle restriction
rcch[7U] = 0x08U; // ... - No group restriction / GMS; Location Registration Restriction
rcch[8U] = (!m_siteData.netActive() ? 0x01U : 0x00U); // ... - No group ratio restriction / No delay time extension / ISO
RCCH::encode(data, rcch, length, offset);
}

@ -0,0 +1,57 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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_LC_RCCH__MESSAGE_TYPE_SRV_INFO_H__)
#define __NXDN_LC_RCCH__MESSAGE_TYPE_SRV_INFO_H__
#include "Defines.h"
#include "nxdn/lc/RCCH.h"
namespace nxdn
{
namespace lc
{
namespace rcch
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements SRV_INFO - Service Information
// ---------------------------------------------------------------------------
class HOST_SW_API MESSAGE_TYPE_SRV_INFO : public RCCH {
public:
/// <summary>Initializes a new instance of the MESSAGE_TYPE_SRV_INFO class.</summary>
MESSAGE_TYPE_SRV_INFO();
/// <summary>Decode layer 3 data.</summary>
virtual void decode(const uint8_t* data, uint32_t length, uint32_t offset = 0U);
/// <summary>Encode layer 3 data.</summary>
virtual void encode(uint8_t* data, uint32_t length, uint32_t offset = 0U);
};
} // namespace rcch
} // namespace lc
} // namespace nxdn
#endif // __NXDN_LC_RCCH__MESSAGE_TYPE_SRV_INFO_H__

@ -0,0 +1,97 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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.
*/
#include "Defines.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_VCALL_ASSGN.h"
#include "Log.h"
#include "Utils.h"
using namespace nxdn::lc::rcch;
using namespace nxdn::lc;
using namespace nxdn;
#include <cassert>
#include <cmath>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the MESSAGE_TYPE_VCALL_ASSGN class.
/// </summary>
MESSAGE_TYPE_VCALL_ASSGN::MESSAGE_TYPE_VCALL_ASSGN() : RCCH()
{
m_messageType = RCCH_MESSAGE_TYPE_VCALL_ASSGN;
}
/// <summary>
/// Decode layer 3 data.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_VCALL_ASSGN::decode(const uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
RCCH::decode(data, rcch, length, offset);
}
/// <summary>
/// Encode a control signalling block.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_VCALL_ASSGN::encode(uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
rcch[1U] = (m_emergency ? 0x80U : 0x00U) + // Emergency Flag
(m_priority ? 0x20U : 0x00U); // Priority Flag
rcch[2U] = ((m_callType & 0x07U) << 5) + // Call Type
(m_duplex ? 0x10U : 0x00U) + // Half/Full Duplex Flag
(m_transmissionMode & 0x07U); // Transmission Mode
rcch[3U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address
rcch[4U] = (m_srcId >> 0U) & 0xFFU; // ...
rcch[5U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address
rcch[6U] = (m_dstId >> 0U) & 0xFFU; // ...
rcch[7U] = (m_grpVchNo >> 10) & 0x03U; // Channel
rcch[8U] = (m_grpVchNo & 0xFFU); // ...
rcch[10U] = (m_siteData.locId() >> 8) & 0xFFU; // Location ID
rcch[11U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
RCCH::encode(data, rcch, length, offset);
}

@ -0,0 +1,57 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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_LC_RCCH__MESSAGE_TYPE_VCALL_ASSGN_H__)
#define __NXDN_LC_RCCH__MESSAGE_TYPE_VCALL_ASSGN_H__
#include "Defines.h"
#include "nxdn/lc/RCCH.h"
namespace nxdn
{
namespace lc
{
namespace rcch
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements VCALL_ASSGN - Voice Call Assignment
// ---------------------------------------------------------------------------
class HOST_SW_API MESSAGE_TYPE_VCALL_ASSGN : public RCCH {
public:
/// <summary>Initializes a new instance of the MESSAGE_TYPE_VCALL_ASSGN class.</summary>
MESSAGE_TYPE_VCALL_ASSGN();
/// <summary>Decode layer 3 data.</summary>
virtual void decode(const uint8_t* data, uint32_t length, uint32_t offset = 0U);
/// <summary>Encode layer 3 data.</summary>
virtual void encode(uint8_t* data, uint32_t length, uint32_t offset = 0U);
};
} // namespace rcch
} // namespace lc
} // namespace nxdn
#endif // __NXDN_LC_RCCH__MESSAGE_TYPE_VCALL_ASSGN_H__

@ -0,0 +1,103 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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.
*/
#include "Defines.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_VCALL_CONN.h"
#include "Log.h"
#include "Utils.h"
using namespace nxdn::lc::rcch;
using namespace nxdn::lc;
using namespace nxdn;
#include <cassert>
#include <cmath>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the MESSAGE_TYPE_VCALL_CONN class.
/// </summary>
MESSAGE_TYPE_VCALL_CONN::MESSAGE_TYPE_VCALL_CONN() : RCCH()
{
m_messageType = RCCH_MESSAGE_TYPE_VCALL_CONN;
}
/// <summary>
/// Decode layer 3 data.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_VCALL_CONN::decode(const uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
RCCH::decode(data, rcch, length, offset);
m_callType = (rcch[2U] >> 5) & 0x07U; // Call Type
m_emergency = (rcch[1U] & 0x80U) == 0x80U; // Emergency Flag
m_priority = (rcch[1U] & 0x20U) == 0x20U; // Priority Flag
m_duplex = (rcch[2U] & 0x10U) == 0x10U; // Half/Full Duplex Flag
m_transmissionMode = (rcch[2U] & 0x07U); // Transmission Mode
m_srcId = (uint16_t)((rcch[3U] << 8) | rcch[4U]) & 0xFFFFU; // Source Radio Address
m_dstId = (uint16_t)((rcch[5U] << 8) | rcch[6U]) & 0xFFFFU; // Target Radio Address
}
/// <summary>
/// Encode a control signalling block.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
void MESSAGE_TYPE_VCALL_CONN::encode(uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != NULL);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
rcch[1U] = (m_emergency ? 0x80U : 0x00U) + // Emergency Flag
(m_priority ? 0x20U : 0x00U); // Priority Flag
rcch[2U] = ((m_callType & 0x07U) << 5) + // Call Type
(m_duplex ? 0x10U : 0x00U) + // Half/Full Duplex Flag
(m_transmissionMode & 0x07U); // Transmission Mode
rcch[3U] = (m_srcId >> 8U) & 0xFFU; // Source Radio Address
rcch[4U] = (m_srcId >> 0U) & 0xFFU; // ...
rcch[5U] = (m_dstId >> 8U) & 0xFFU; // Target Radio Address
rcch[6U] = (m_dstId >> 0U) & 0xFFU; // ...
rcch[7U] = m_causeRsp; // Cause (VD)
rcch[9U] = (m_siteData.locId() >> 8) & 0xFFU; // Location ID
rcch[10U] = (m_siteData.locId() >> 0) & 0xFFU; // ...
RCCH::encode(data, rcch, length, offset);
}

@ -0,0 +1,58 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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_LC_RCCH__MESSAGE_TYPE_VCALL_CONN_H__)
#define __NXDN_LC_RCCH__MESSAGE_TYPE_VCALL_CONN_H__
#include "Defines.h"
#include "nxdn/lc/RCCH.h"
namespace nxdn
{
namespace lc
{
namespace rcch
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements VCALL_CONN - Voice Call Connection Request (ISP) and
// Voice Call Connection Response (OSP)
// ---------------------------------------------------------------------------
class HOST_SW_API MESSAGE_TYPE_VCALL_CONN : public RCCH {
public:
/// <summary>Initializes a new instance of the MESSAGE_TYPE_VCALL_CONN class.</summary>
MESSAGE_TYPE_VCALL_CONN();
/// <summary>Decode layer 3 data.</summary>
virtual void decode(const uint8_t* data, uint32_t length, uint32_t offset = 0U);
/// <summary>Encode layer 3 data.</summary>
virtual void encode(uint8_t* data, uint32_t length, uint32_t offset = 0U);
};
} // namespace rcch
} // namespace lc
} // namespace nxdn
#endif // __NXDN_LC_RCCH__MESSAGE_TYPE_VCALL_CONN_H__

@ -0,0 +1,120 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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.
*/
#include "Defines.h"
#include "nxdn/lc/rcch/RCCHFactory.h"
#include "Log.h"
#include "Utils.h"
using namespace nxdn::lc::rcch;
using namespace nxdn::lc;
using namespace nxdn;
#include <cassert>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the RCCHFactory class.
/// </summary>
RCCHFactory::RCCHFactory()
{
/* stub */
}
/// <summary>
/// Finalizes a instance of RCCHFactory class.
/// </summary>
RCCHFactory::~RCCHFactory()
{
/* stub */
}
/// <summary>
/// Create an instance of a RCCH.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
/// <returns>True, if RCCH was decoded, otherwise false.</returns>
std::unique_ptr<RCCH> RCCHFactory::createRCCH(const uint8_t* data, uint32_t length, uint32_t offset)
{
assert(data != nullptr);
uint8_t rcch[22U];
::memset(rcch, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES + 4U);
for (uint32_t i = 0U; i < length; i++, offset++) {
bool b = READ_BIT(data, offset);
WRITE_BIT(rcch, i, b);
}
uint8_t messageType = data[0U] & 0x3FU; // Message Type
// message type opcodes
switch (messageType) {
case RTCH_MESSAGE_TYPE_VCALL:
case RCCH_MESSAGE_TYPE_VCALL_CONN:
return decode(new MESSAGE_TYPE_VCALL_CONN(), data, length, offset);
case RTCH_MESSAGE_TYPE_DCALL_HDR:
return decode(new MESSAGE_TYPE_DCALL_HDR(), data, length, offset);
case nxdn::MESSAGE_TYPE_IDLE:
return decode(new MESSAGE_TYPE_IDLE(), data, length, offset);
case RCCH_MESSAGE_TYPE_REG:
return decode(new MESSAGE_TYPE_REG(), data, length, offset);
case RCCH_MESSAGE_TYPE_REG_C:
return decode(new MESSAGE_TYPE_REG_C(), data, length, offset);
case RCCH_MESSAGE_TYPE_GRP_REG:
return decode(new MESSAGE_TYPE_GRP_REG(), data, length, offset);
default:
LogError(LOG_NXDN, "RCCH::decodeRCCH(), unknown RCCH value, messageType = $%02X", messageType);
return nullptr;
}
return nullptr;
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
///
/// </summary>
/// <param name="rcch"></param>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="offset"></param>
/// <returns></returns>
std::unique_ptr<RCCH> RCCHFactory::decode(RCCH* rcch, const uint8_t* data, uint32_t length, uint32_t offset)
{
assert(rcch != nullptr);
assert(data != nullptr);
rcch->decode(data, length, offset);
return std::unique_ptr<RCCH>(rcch);
}

@ -0,0 +1,73 @@
/**
* 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 Software
*
*/
/*
* Copyright (C) 2022 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_LC__RCCH_FACTORY_H__)
#define __NXDN_LC__RCCH_FACTORY_H__
#include "Defines.h"
#include "nxdn/lc/RCCH.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_DCALL_HDR.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_DST_ID_INFO.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_GRP_REG.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_IDLE.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_REG_C.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_REG_COMM.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_REG.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_SITE_INFO.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_SRV_INFO.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_VCALL_ASSGN.h"
#include "nxdn/lc/rcch/MESSAGE_TYPE_VCALL_CONN.h"
namespace nxdn
{
namespace lc
{
namespace rcch
{
// ---------------------------------------------------------------------------
// Class Declaration
// Helper class to instantiate an instance of a RCCH.
// ---------------------------------------------------------------------------
class HOST_SW_API RCCHFactory {
public:
/// <summary>Initializes a new instance of the RCCHFactory class.</summary>
RCCHFactory();
/// <summary>Finalizes a instance of the RCCHFactory class.</summary>
~RCCHFactory();
/// <summary>Create an instance of a RCCH.</summary>
static std::unique_ptr<RCCH> createRCCH(const uint8_t* data, uint32_t length, uint32_t offset = 0U);
private:
/// <summary></summary>
static std::unique_ptr<RCCH> decode(RCCH* rcch, const uint8_t* data, uint32_t length, uint32_t offset = 0U);
};
} // namespace rcch
} // namespace lc
} // namespace nxdn
#endif // __NXDN_LC__RCCH_FACTORY_H__

@ -32,6 +32,7 @@
#include "nxdn/channel/CAC.h"
#include "nxdn/packet/Trunk.h"
#include "nxdn/acl/AccessControl.h"
#include "nxdn/lc/rcch/RCCHFactory.h"
#include "nxdn/Sync.h"
#include "nxdn/NXDNUtils.h"
#include "edac/CRC.h"
@ -40,6 +41,7 @@
#include "Utils.h"
using namespace nxdn;
using namespace nxdn::lc;
using namespace nxdn::packet;
#include <cassert>
@ -55,7 +57,7 @@ using namespace nxdn::packet;
#define IS_SUPPORT_CONTROL_CHECK(_PCKT_STR, _PCKT, _SRCID) \
if (!m_nxdn->m_control) { \
LogWarning(LOG_RF, "NXDN, " _PCKT_STR " denial, unsupported service, srcId = %u", _SRCID); \
writeRF_Message_Deny(NXDN_CAUSE_SVC_UNAVAILABLE, _PCKT); \
writeRF_Message_Deny(0U, _SRCID, NXDN_CAUSE_SVC_UNAVAILABLE, _PCKT); \
m_nxdn->m_rfState = RS_RF_REJECTED; \
return false; \
}
@ -64,7 +66,7 @@ using namespace nxdn::packet;
#define VALID_SRCID(_PCKT_STR, _PCKT, _SRCID, _RSN) \
if (!acl::AccessControl::validateSrcId(_SRCID)) { \
LogWarning(LOG_RF, "NXDN, " _PCKT_STR " denial, RID rejection, srcId = %u", _SRCID); \
writeRF_Message_Deny(_RSN, _PCKT); \
writeRF_Message_Deny(0U, _SRCID, _RSN, _PCKT); \
m_nxdn->m_rfState = RS_RF_REJECTED; \
return false; \
}
@ -73,16 +75,16 @@ using namespace nxdn::packet;
#define VALID_DSTID(_PCKT_STR, _PCKT, _DSTID, _RSN) \
if (!acl::AccessControl::validateSrcId(_DSTID)) { \
LogWarning(LOG_RF, "NXDN, " _PCKT_STR " denial, RID rejection, dstId = %u", _DSTID); \
writeRF_Message_Deny(_RSN, _PCKT); \
writeRF_Message_Deny(0U, _SRCID, _RSN, _PCKT); \
m_nxdn->m_rfState = RS_RF_REJECTED; \
return false; \
}
// Validate the talkgroup ID.
#define VALID_TGID(_PCKT_STR, _PCKT, _DSTID, _RSN) \
#define VALID_TGID(_PCKT_STR, _PCKT, _DSTID, _SRCID, _RSN) \
if (!acl::AccessControl::validateTGId(_DSTID)) { \
LogWarning(LOG_RF, "NXDN, " _PCKT_STR " denial, TGID rejection, dstId = %u", _DSTID); \
writeRF_Message_Deny(_RSN, _PCKT); \
writeRF_Message_Deny(0U, _SRCID, _RSN, _PCKT); \
m_nxdn->m_rfState = RS_RF_REJECTED; \
return false; \
}
@ -91,7 +93,7 @@ using namespace nxdn::packet;
#define VERIFY_SRCID_REG(_PCKT_STR, _PCKT, _SRCID, _RSN) \
if (!m_nxdn->m_affiliations.isUnitReg(_SRCID) && m_verifyReg) { \
LogWarning(LOG_RF, "NXDN, " _PCKT_STR " denial, RID not registered, srcId = %u", _SRCID); \
writeRF_Message_Deny(_RSN, _PCKT); \
writeRF_Message_Deny(0U, _SRCID, _RSN, _PCKT); \
m_nxdn->m_rfState = RS_RF_REJECTED; \
return false; \
}
@ -100,7 +102,7 @@ using namespace nxdn::packet;
#define VERIFY_SRCID_AFF(_PCKT_STR, _PCKT, _SRCID, _DSTID, _RSN) \
if (!m_nxdn->m_affiliations.isGroupAff(_SRCID, _DSTID) && m_verifyAff) { \
LogWarning(LOG_RF, "NXDN, " _PCKT_STR " denial, RID not affiliated to TGID, srcId = %u, dstId = %u", _SRCID, _DSTID); \
writeRF_Message_Deny(_RSN, _PCKT); \
writeRF_Message_Deny(0U, _SRCID, _RSN, _PCKT); \
m_nxdn->m_rfState = RS_RF_REJECTED; \
return false; \
}
@ -115,24 +117,6 @@ const uint32_t GRANT_TIMER_TIMEOUT = 15U;
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Resets the data states for the RF interface.
/// </summary>
void Trunk::resetRF()
{
lc::RCCH lc = lc::RCCH(m_nxdn->m_siteData, m_nxdn->m_idenEntry, m_dumpRCCH);
m_rfLC = lc;
}
/// <summary>
/// Resets the data states for the network.
/// </summary>
void Trunk::resetNet()
{
lc::RCCH lc = lc::RCCH(m_nxdn->m_siteData, m_nxdn->m_idenEntry, m_dumpRCCH);
m_netLC = lc;
}
/// <summary>
/// Process a data frame from the RF interface.
/// </summary>
@ -167,13 +151,16 @@ bool Trunk::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
uint8_t buffer[NXDN_FRAME_LENGTH_BYTES];
cac.getData(buffer);
m_rfLC.decode(buffer, NXDN_RCCH_CAC_LC_SHORT_LENGTH_BITS);
std::unique_ptr<RCCH> rcch = rcch::RCCHFactory::createRCCH(buffer, NXDN_RCCH_CAC_LC_SHORT_LENGTH_BITS);
if (rcch == nullptr)
return false;
uint16_t srcId = m_rfLC.getSrcId();
uint16_t dstId = m_rfLC.getDstId();
uint16_t srcId = rcch->getSrcId();
uint16_t dstId = rcch->getDstId();
switch (m_rfLC.getMessageType()) {
switch (rcch->getMessageType()) {
case RTCH_MESSAGE_TYPE_VCALL:
{
// make sure control data is supported
IS_SUPPORT_CONTROL_CHECK(NXDN_RTCH_MSG_TYPE_VCALL_REQ, RTCH_MESSAGE_TYPE_VCALL, srcId);
@ -181,7 +168,7 @@ bool Trunk::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
VALID_SRCID(NXDN_RTCH_MSG_TYPE_VCALL_REQ, RTCH_MESSAGE_TYPE_VCALL, srcId, NXDN_CAUSE_VD_REQ_UNIT_NOT_PERM);
// validate the talkgroup ID
VALID_TGID(NXDN_RTCH_MSG_TYPE_VCALL_REQ, RTCH_MESSAGE_TYPE_VCALL, dstId, NXDN_CAUSE_VD_TGT_UNIT_NOT_PERM);
VALID_TGID(NXDN_RTCH_MSG_TYPE_VCALL_REQ, RTCH_MESSAGE_TYPE_VCALL, dstId, srcId, NXDN_CAUSE_VD_TGT_UNIT_NOT_PERM);
// verify the source RID is affiliated
VERIFY_SRCID_AFF(NXDN_RTCH_MSG_TYPE_VCALL_REQ, RTCH_MESSAGE_TYPE_VCALL, srcId, dstId, NXDN_CAUSE_VD_REQ_UNIT_NOT_REG);
@ -190,30 +177,39 @@ bool Trunk::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
LogMessage(LOG_RF, "NXDN, " NXDN_RTCH_MSG_TYPE_VCALL_REQ ", srcId = %u, dstId = %u", srcId, dstId);
}
writeRF_Message_Grant(true);
break;
uint8_t serviceOptions = (rcch->getEmergency() ? 0x80U : 0x00U) + // Emergency Flag
(rcch->getEncrypted() ? 0x40U : 0x00U) + // Encrypted Flag
(rcch->getPriority() & 0x07U); // Priority
writeRF_Message_Grant(srcId, dstId, serviceOptions, true);
}
break;
case RCCH_MESSAGE_TYPE_REG:
{
// make sure control data is supported
IS_SUPPORT_CONTROL_CHECK(NXDN_RCCH_MSG_TYPE_REG_REQ, RCCH_MESSAGE_TYPE_REG, srcId);
if (m_verbose) {
LogMessage(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_REG_REQ ", srcId = %u", srcId);
LogMessage(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_REG_REQ ", srcId = %u, locId = %u", srcId, rcch->getLocId());
}
writeRF_Message_U_Reg_Rsp(srcId);
break;
writeRF_Message_U_Reg_Rsp(srcId, rcch->getLocId());
}
break;
case RCCH_MESSAGE_TYPE_GRP_REG:
{
// make sure control data is supported
IS_SUPPORT_CONTROL_CHECK(NXDN_RCCH_MSG_TYPE_GRP_REG_REQ, RCCH_MESSAGE_TYPE_GRP_REG, srcId);
if (m_verbose) {
LogMessage(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_GRP_REG_REQ ", srcId = %u, dstId = %u", srcId, dstId);
LogMessage(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_GRP_REG_REQ ", srcId = %u, dstId = %u, locId = %u", srcId, dstId, rcch->getLocId());
}
writeRF_Message_Grp_Reg_Rsp(srcId, dstId);
break;
writeRF_Message_Grp_Reg_Rsp(srcId, dstId, rcch->getLocId());
}
break;
default:
LogError(LOG_RF, "NXDN, unhandled message type, messageType = $%02X", m_rfLC.getMessageType());
LogError(LOG_RF, "NXDN, unhandled message type, messageType = $%02X", rcch->getMessageType());
break;
}
@ -236,9 +232,6 @@ bool Trunk::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
if (m_nxdn->m_netState == RS_NET_IDLE) {
m_nxdn->m_queue.clear();
resetRF();
resetNet();
}
return true;
@ -260,11 +253,7 @@ void Trunk::clock(uint32_t ms)
// do we have a grant response?
if (m_nxdn->m_network->readGrantRsp(grp, srcId, dstId, grpVchNo)) {
m_rfLC.setSrcId(srcId);
m_rfLC.setDstId(dstId);
m_rfLC.setGrpVchNo(grpVchNo);
writeRF_Message_Grant(grp, true, true, true);
writeRF_Message_Grant(srcId, dstId, 0U, grp, true, grpVchNo, true, true);
}
}
}
@ -283,18 +272,19 @@ void Trunk::clock(uint32_t ms)
/// </summary>
/// <param name="nxdn">Instance of the Control class.</param>
/// <param name="network">Instance of the BaseNetwork class.</param>
/// <param name="dumpRCCHData">Flag indicating whether RCCH data is dumped to the log.</param>
/// <param name="debug">Flag indicating whether NXDN debug is enabled.</param>
/// <param name="verbose">Flag indicating whether NXDN verbose logging is enabled.</param>
Trunk::Trunk(Control* nxdn, network::BaseNetwork* network, bool dumpRCCHData, bool debug, bool verbose) :
Trunk::Trunk(Control* nxdn, network::BaseNetwork* network, bool debug, bool verbose) :
m_nxdn(nxdn),
m_network(network),
m_bcchCnt(1U),
m_rcchGroupingCnt(1U),
m_ccchPagingCnt(2U),
m_ccchMultiCnt(2U),
m_rcchIterateCnt(2U),
m_verifyAff(false),
m_verifyReg(false),
m_rfLC(SiteData(), lookups::IdenTable()),
m_netLC(SiteData(), lookups::IdenTable()),
m_lastRejectId(0U),
m_dumpRCCH(dumpRCCHData),
m_verbose(verbose),
m_debug(debug)
{
@ -372,9 +362,10 @@ void Trunk::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS)
/// <summary>
/// Helper to write a single-block RCCH packet.
/// </summary>
/// <param name="rcch"></param>
/// <param name="noNetwork"></param>
/// <param name="clearBeforeWrite"></param>
void Trunk::writeRF_Message(bool noNetwork, bool clearBeforeWrite)
void Trunk::writeRF_Message(RCCH* rcch, bool noNetwork, bool clearBeforeWrite)
{
if (!m_nxdn->m_control)
return;
@ -395,8 +386,7 @@ void Trunk::writeRF_Message(bool noNetwork, bool clearBeforeWrite)
uint8_t buffer[NXDN_RCCH_LC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES);
m_rfLC.setVerbose(m_dumpRCCH);
m_rfLC.encode(buffer, NXDN_RCCH_LC_LENGTH_BITS);
rcch->encode(buffer, NXDN_RCCH_LC_LENGTH_BITS);
// generate the CAC
channel::CAC cac;
@ -428,19 +418,25 @@ void Trunk::writeRF_Message(bool noNetwork, bool clearBeforeWrite)
/// <summary>
/// Helper to write a grant packet.
/// </summary>
/// <param name="srcId"></param>
/// <param name="dstId"></param>
/// <param name="serviceOptions"></param>
/// <param name="grp"></param>
/// <param name="skip"></param>
/// <param name="chNo"></param>
/// <param name="net"></param>
/// <param name="skipNetCheck"></param>
/// <returns></returns>
bool Trunk::writeRF_Message_Grant(bool grp, bool skip, bool net, bool skipNetCheck)
bool Trunk::writeRF_Message_Grant(uint32_t srcId, uint32_t dstId, uint8_t serviceOptions, bool grp, bool skip, uint32_t chNo, bool net, bool skipNetCheck)
{
uint8_t messageType = m_rfLC.getMessageType();
bool emergency = ((serviceOptions & 0xFFU) & 0x80U) == 0x80U; // Emergency Flag
bool encryption = ((serviceOptions & 0xFFU) & 0x40U) == 0x40U; // Encryption Flag
uint8_t priority = ((serviceOptions & 0xFFU) & 0x07U); // Priority
// do we have a network connection and are we handling grants at the network?
if (m_nxdn->m_network != nullptr) {
if (m_nxdn->m_network->isHandlingChGrants() && m_nxdn->m_siteData.netActive() && !skipNetCheck) {
return m_nxdn->m_network->writeGrantReq(grp, m_rfLC.getSrcId(), m_rfLC.getDstId());
return m_nxdn->m_network->writeGrantReq(grp, srcId, dstId);
}
}
@ -448,127 +444,137 @@ bool Trunk::writeRF_Message_Grant(bool grp, bool skip, bool net, bool skipNetChe
if (!skip) {
if (m_nxdn->m_rfState != RS_RF_LISTENING && m_nxdn->m_rfState != RS_RF_DATA) {
if (!net) {
LogWarning(LOG_RF, "NXDN, " NXDN_RTCH_MSG_TYPE_VCALL_REQ " denied, traffic in progress, dstId = %u", m_rfLC.getDstId());
writeRF_Message_Deny(NXDN_CAUSE_VD_QUE_GRP_BUSY, RTCH_MESSAGE_TYPE_VCALL);
LogWarning(LOG_RF, "NXDN, " NXDN_RTCH_MSG_TYPE_VCALL_REQ " denied, traffic in progress, dstId = %u", dstId);
writeRF_Message_Deny(0U, srcId, NXDN_CAUSE_VD_QUE_GRP_BUSY, RTCH_MESSAGE_TYPE_VCALL);
::ActivityLog("NXDN", true, "group grant request from %u to TG %u denied", m_rfLC.getSrcId(), m_rfLC.getDstId());
::ActivityLog("NXDN", true, "group grant request from %u to TG %u denied", srcId, dstId);
m_nxdn->m_rfState = RS_RF_REJECTED;
}
m_rfLC.setMessageType(messageType);
return false;
}
if (m_nxdn->m_netState != RS_NET_IDLE && m_rfLC.getDstId() == m_nxdn->m_netLastDstId) {
if (m_nxdn->m_netState != RS_NET_IDLE && dstId == m_nxdn->m_netLastDstId) {
if (!net) {
LogWarning(LOG_RF, "NXDN, " NXDN_RTCH_MSG_TYPE_VCALL_REQ " denied, traffic in progress, dstId = %u", m_rfLC.getDstId());
writeRF_Message_Deny(NXDN_CAUSE_VD_QUE_GRP_BUSY, RTCH_MESSAGE_TYPE_VCALL);
LogWarning(LOG_RF, "NXDN, " NXDN_RTCH_MSG_TYPE_VCALL_REQ " denied, traffic in progress, dstId = %u", dstId);
writeRF_Message_Deny(0U, srcId, NXDN_CAUSE_VD_QUE_GRP_BUSY, RTCH_MESSAGE_TYPE_VCALL);
::ActivityLog("NXDN", true, "group grant request from %u to TG %u denied", m_rfLC.getSrcId(), m_rfLC.getDstId());
::ActivityLog("NXDN", true, "group grant request from %u to TG %u denied", srcId, dstId);
m_nxdn->m_rfState = RS_RF_REJECTED;
}
m_rfLC.setMessageType(messageType);
return false;
}
// don't transmit grants if the destination ID's don't match and the network TG hang timer is running
if (m_nxdn->m_rfLastDstId != 0U) {
if (m_nxdn->m_rfLastDstId != m_rfLC.getDstId() && (m_nxdn->m_rfTGHang.isRunning() && !m_nxdn->m_rfTGHang.hasExpired())) {
if (m_nxdn->m_rfLastDstId != dstId && (m_nxdn->m_rfTGHang.isRunning() && !m_nxdn->m_rfTGHang.hasExpired())) {
if (!net) {
writeRF_Message_Deny(NXDN_CAUSE_VD_QUE_GRP_BUSY, RTCH_MESSAGE_TYPE_VCALL);
writeRF_Message_Deny(0U, srcId, NXDN_CAUSE_VD_QUE_GRP_BUSY, RTCH_MESSAGE_TYPE_VCALL);
m_nxdn->m_rfState = RS_RF_REJECTED;
}
m_rfLC.setMessageType(messageType);
return false;
}
}
if (!m_nxdn->m_affiliations.isGranted(m_rfLC.getDstId())) {
if (!m_nxdn->m_affiliations.isGranted(dstId)) {
if (!m_nxdn->m_affiliations.isRFChAvailable()) {
if (grp) {
if (!net) {
LogWarning(LOG_RF, "NXDN, " NXDN_RTCH_MSG_TYPE_VCALL_REQ " queued, no channels available, dstId = %u", m_rfLC.getDstId());
writeRF_Message_Deny(NXDN_CAUSE_VD_QUE_CHN_RESOURCE_NOT_AVAIL, RTCH_MESSAGE_TYPE_VCALL);
LogWarning(LOG_RF, "NXDN, " NXDN_RTCH_MSG_TYPE_VCALL_REQ " queued, no channels available, dstId = %u", dstId);
writeRF_Message_Deny(0U, srcId, NXDN_CAUSE_VD_QUE_CHN_RESOURCE_NOT_AVAIL, RTCH_MESSAGE_TYPE_VCALL);
::ActivityLog("NXDN", true, "group grant request from %u to TG %u queued", m_rfLC.getSrcId(), m_rfLC.getDstId());
::ActivityLog("NXDN", true, "group grant request from %u to TG %u queued", srcId, dstId);
m_nxdn->m_rfState = RS_RF_REJECTED;
}
m_rfLC.setMessageType(messageType);
return false;
}
else {
if (!net) {
LogWarning(LOG_RF, "NXDN, " NXDN_RTCH_MSG_TYPE_VCALL_REQ " queued, no channels available, dstId = %u", m_rfLC.getDstId());
writeRF_Message_Deny(NXDN_CAUSE_VD_QUE_CHN_RESOURCE_NOT_AVAIL, RTCH_MESSAGE_TYPE_VCALL);
LogWarning(LOG_RF, "NXDN, " NXDN_RTCH_MSG_TYPE_VCALL_REQ " queued, no channels available, dstId = %u", dstId);
writeRF_Message_Deny(0U, srcId, NXDN_CAUSE_VD_QUE_CHN_RESOURCE_NOT_AVAIL, RTCH_MESSAGE_TYPE_VCALL);
::ActivityLog("P25", true, "unit-to-unit grant request from %u to %u queued", m_rfLC.getSrcId(), m_rfLC.getDstId());
::ActivityLog("P25", true, "unit-to-unit grant request from %u to %u queued", srcId, dstId);
m_nxdn->m_rfState = RS_RF_REJECTED;
}
m_rfLC.setMessageType(messageType);
return false;
}
}
else {
if (m_nxdn->m_affiliations.grantCh(m_rfLC.getDstId(), GRANT_TIMER_TIMEOUT)) {
uint32_t chNo = m_nxdn->m_affiliations.getGrantedCh(m_rfLC.getDstId());
m_rfLC.setGrpVchNo(chNo);
if (m_nxdn->m_affiliations.grantCh(dstId, GRANT_TIMER_TIMEOUT)) {
chNo = m_nxdn->m_affiliations.getGrantedCh(dstId);
}
}
}
else {
uint32_t chNo = m_nxdn->m_affiliations.getGrantedCh(m_rfLC.getDstId());
m_rfLC.setGrpVchNo(chNo);
chNo = m_nxdn->m_affiliations.getGrantedCh(dstId);
}
}
if (grp) {
if (!net) {
::ActivityLog("NXDN", true, "group grant request from %u to TG %u", m_rfLC.getSrcId(), m_rfLC.getDstId());
::ActivityLog("NXDN", true, "group grant request from %u to TG %u", srcId, dstId);
}
}
else {
if (!net) {
::ActivityLog("NXDN", true, "unit-to-unit grant request from %u to %u", m_rfLC.getSrcId(), m_rfLC.getDstId());
::ActivityLog("NXDN", true, "unit-to-unit grant request from %u to %u", srcId, dstId);
}
}
std::unique_ptr<rcch::MESSAGE_TYPE_VCALL_CONN> rcch = new_unique(rcch::MESSAGE_TYPE_VCALL_CONN);
rcch->setMessageType(RTCH_MESSAGE_TYPE_VCALL);
rcch->setGrpVchNo(chNo);
rcch->setGroup(grp);
rcch->setSrcId(srcId);
rcch->setDstId(dstId);
rcch->setEmergency(emergency);
rcch->setEncrypted(encryption);
rcch->setPriority(priority);
if (m_verbose) {
LogMessage((net) ? LOG_NET : LOG_RF, "NXDN, " NXDN_RTCH_MSG_TYPE_VCALL_RESP ", emerg = %u, encrypt = %u, prio = %u, chNo = %u, srcId = %u, dstId = %u",
m_rfLC.getEmergency(), m_rfLC.getEncrypted(), m_rfLC.getPriority(), m_rfLC.getGrpVchNo(), m_rfLC.getSrcId(), m_rfLC.getDstId());
rcch->getEmergency(), rcch->getEncrypted(), rcch->getPriority(), rcch->getGrpVchNo(), rcch->getSrcId(), rcch->getDstId());
}
// transmit group grant
m_rfLC.setMessageType(RTCH_MESSAGE_TYPE_VCALL);
writeRF_Message(false, true);
m_rfLC.setMessageType(messageType);
writeRF_Message(rcch.get(), false, true);
return true;
}
/// <summary>
/// Helper to write a deny packet.
/// </summary>
/// <param name="srcId"></param>
/// <param name="dstId"></param>
/// <param name="reason"></param>
/// <param name="service"></param>
void Trunk::writeRF_Message_Deny(uint8_t reason, uint8_t service)
void Trunk::writeRF_Message_Deny(uint32_t srcId, uint32_t dstId, uint8_t reason, uint8_t service)
{
uint8_t messageType = m_rfLC.getMessageType();
std::unique_ptr<RCCH> rcch = nullptr;
switch (service) {
case RTCH_MESSAGE_TYPE_VCALL:
rcch = new_unique(rcch::MESSAGE_TYPE_VCALL_CONN);
rcch->setMessageType(RTCH_MESSAGE_TYPE_VCALL);
default:
return;
}
m_rfLC.setMessageType(service);
m_rfLC.setCauseResponse(reason);
rcch->setCauseResponse(reason);
rcch->setSrcId(srcId);
rcch->setDstId(dstId);
if (m_verbose) {
LogMessage(LOG_RF, "NXDN, MSG_DENIAL (Message Denial), reason = $%02X, service = $%02X, srcId = %u, dstId = %u",
service, m_rfLC.getSrcId(), m_rfLC.getDstId());
service, srcId, dstId);
}
writeRF_Message(false);
m_rfLC.setMessageType(messageType);
writeRF_Message(rcch.get(), false);
}
/// <summary>
@ -576,49 +582,48 @@ void Trunk::writeRF_Message_Deny(uint8_t reason, uint8_t service)
/// </summary>
/// <param name="srcId"></param>
/// <param name="dstId"></param>
bool Trunk::writeRF_Message_Grp_Reg_Rsp(uint32_t srcId, uint32_t dstId)
/// <param name="locId"></param>
bool Trunk::writeRF_Message_Grp_Reg_Rsp(uint32_t srcId, uint32_t dstId, uint32_t locId)
{
bool ret = false;
m_rfLC.setMessageType(RCCH_MESSAGE_TYPE_GRP_REG);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_REG_ACCEPTED);
std::unique_ptr<rcch::MESSAGE_TYPE_GRP_REG> rcch = new_unique(rcch::MESSAGE_TYPE_GRP_REG);
rcch->setCauseResponse(NXDN_CAUSE_MM_REG_ACCEPTED);
// validate the location ID
if (m_rfLC.getLocId() != m_nxdn->m_siteData.locId()) {
LogWarning(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_GRP_REG_REQ " denial, LOCID rejection, locId = $%04X", m_rfLC.getLocId());
if (locId != m_nxdn->m_siteData.locId()) {
LogWarning(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_GRP_REG_REQ " denial, LOCID rejection, locId = $%04X", locId);
::ActivityLog("NXDN", true, "group affiliation request from %u denied", srcId);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_REG_FAILED);
rcch->setCauseResponse(NXDN_CAUSE_MM_REG_FAILED);
}
// validate the source RID
if (!acl::AccessControl::validateSrcId(srcId)) {
LogWarning(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_GRP_REG_REQ " denial, RID rejection, srcId = %u", srcId);
::ActivityLog("NXDN", true, "group affiliation request from %u to %s %u denied", srcId, "TG ", dstId);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_REG_FAILED);
rcch->setCauseResponse(NXDN_CAUSE_MM_REG_FAILED);
}
// validate the source RID is registered
if (!m_nxdn->m_affiliations.isUnitReg(srcId) && m_verifyReg) {
LogWarning(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_GRP_REG_REQ " denial, RID not registered, srcId = %u", srcId);
::ActivityLog("NXDN", true, "group affiliation request from %u to %s %u denied", srcId, "TG ", dstId);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_REG_REFUSED);
rcch->setCauseResponse(NXDN_CAUSE_MM_REG_REFUSED);
}
// validate the talkgroup ID
if (m_rfLC.getGroup()) {
if (dstId == 0U) {
LogWarning(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_GRP_REG_REQ ", TGID 0, dstId = %u", dstId);
}
else {
if (!acl::AccessControl::validateTGId(dstId)) {
LogWarning(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_GRP_REG_REQ " denial, TGID rejection, dstId = %u", dstId);
::ActivityLog("NXDN", true, "group affiliation request from %u to %s %u denied", srcId, "TG ", dstId);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_LOC_ACPT_GRP_REFUSE);
}
if (dstId == 0U) {
LogWarning(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_GRP_REG_REQ ", TGID 0, dstId = %u", dstId);
}
else {
if (!acl::AccessControl::validateTGId(dstId)) {
LogWarning(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_GRP_REG_REQ " denial, TGID rejection, dstId = %u", dstId);
::ActivityLog("NXDN", true, "group affiliation request from %u to %s %u denied", srcId, "TG ", dstId);
rcch->setCauseResponse(NXDN_CAUSE_MM_LOC_ACPT_GRP_REFUSE);
}
}
if (m_rfLC.getCauseResponse() == NXDN_CAUSE_MM_REG_ACCEPTED) {
if (rcch->getCauseResponse() == NXDN_CAUSE_MM_REG_ACCEPTED) {
if (m_verbose) {
LogMessage(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_GRP_REG_REQ ", srcId = %u, dstId = %u", srcId, dstId);
}
@ -630,7 +635,7 @@ bool Trunk::writeRF_Message_Grp_Reg_Rsp(uint32_t srcId, uint32_t dstId)
m_nxdn->m_affiliations.groupAff(srcId, dstId);
}
writeRF_Message(false);
writeRF_Message(rcch.get(), false);
return ret;
}
@ -638,28 +643,28 @@ bool Trunk::writeRF_Message_Grp_Reg_Rsp(uint32_t srcId, uint32_t dstId)
/// Helper to write a unit registration response packet.
/// </summary>
/// <param name="srcId"></param>
void Trunk::writeRF_Message_U_Reg_Rsp(uint32_t srcId)
void Trunk::writeRF_Message_U_Reg_Rsp(uint32_t srcId, uint32_t locId)
{
m_rfLC.setMessageType(RCCH_MESSAGE_TYPE_REG);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_REG_ACCEPTED);
std::unique_ptr<rcch::MESSAGE_TYPE_REG> rcch = new_unique(rcch::MESSAGE_TYPE_REG);
rcch->setCauseResponse(NXDN_CAUSE_MM_REG_ACCEPTED);
// validate the location ID
if (m_rfLC.getLocId() != m_nxdn->m_siteData.locId()) {
LogWarning(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_REG_REQ " denial, LOCID rejection, locId = $%04X", m_rfLC.getLocId());
if (locId != m_nxdn->m_siteData.locId()) {
LogWarning(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_REG_REQ " denial, LOCID rejection, locId = $%04X", locId);
::ActivityLog("NXDN", true, "unit registration request from %u denied", srcId);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_REG_FAILED);
rcch->setCauseResponse(NXDN_CAUSE_MM_REG_FAILED);
}
// validate the source RID
if (!acl::AccessControl::validateSrcId(srcId)) {
LogWarning(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_REG_REQ " denial, RID rejection, srcId = %u", srcId);
::ActivityLog("NXDN", true, "unit registration request from %u denied", srcId);
m_rfLC.setCauseResponse(NXDN_CAUSE_MM_REG_FAILED);
rcch->setCauseResponse(NXDN_CAUSE_MM_REG_FAILED);
}
if (m_rfLC.getCauseResponse() == NXDN_CAUSE_MM_REG_ACCEPTED) {
if (rcch->getCauseResponse() == NXDN_CAUSE_MM_REG_ACCEPTED) {
if (m_verbose) {
LogMessage(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_REG_REQ ", srcId = %u, locId = %u", srcId, m_rfLC.getLocId());
LogMessage(LOG_RF, "NXDN, " NXDN_RCCH_MSG_TYPE_REG_REQ ", srcId = %u, locId = %u", srcId, locId);
}
::ActivityLog("NXDN", true, "unit registration request from %u", srcId);
@ -670,10 +675,10 @@ void Trunk::writeRF_Message_U_Reg_Rsp(uint32_t srcId)
}
}
m_rfLC.setSrcId(srcId);
m_rfLC.setDstId(srcId);
rcch->setSrcId(srcId);
rcch->setDstId(srcId);
writeRF_Message(true);
writeRF_Message(rcch.get(), true);
}
/// <summary>
@ -701,9 +706,14 @@ void Trunk::writeRF_CC_Message_Site_Info()
uint8_t buffer[NXDN_RCCH_LC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES);
m_rfLC.setVerbose(m_dumpRCCH);
m_rfLC.setMessageType(RCCH_MESSAGE_TYPE_SITE_INFO);
m_rfLC.encode(buffer, NXDN_RCCH_LC_LENGTH_BITS);
std::unique_ptr<rcch::MESSAGE_TYPE_SITE_INFO> rcch = new_unique(rcch::MESSAGE_TYPE_SITE_INFO);
rcch->setBcchCnt(m_bcchCnt);
rcch->setRcchGroupingCnt(m_rcchGroupingCnt);
rcch->setCcchPagingCnt(m_ccchPagingCnt);
rcch->setCcchMultiCnt(m_ccchMultiCnt);
rcch->setRcchIterateCount(m_rcchIterateCnt);
rcch->encode(buffer, NXDN_RCCH_LC_LENGTH_BITS);
// generate the CAC
channel::CAC cac;
@ -749,10 +759,9 @@ void Trunk::writeRF_CC_Message_Service_Info()
uint8_t buffer[NXDN_RCCH_LC_LENGTH_BYTES];
::memset(buffer, 0x00U, NXDN_RCCH_LC_LENGTH_BYTES);
m_rfLC.setVerbose(m_dumpRCCH);
m_rfLC.setMessageType(MESSAGE_TYPE_SRV_INFO);
m_rfLC.encode(buffer, NXDN_RCCH_LC_LENGTH_BITS / 2U);
m_rfLC.encode(buffer, NXDN_RCCH_LC_LENGTH_BITS / 2U, NXDN_RCCH_LC_LENGTH_BITS / 2U);
std::unique_ptr<rcch::MESSAGE_TYPE_SRV_INFO> rcch = new_unique(rcch::MESSAGE_TYPE_SRV_INFO);
rcch->encode(buffer, NXDN_RCCH_LC_LENGTH_BITS / 2U);
rcch->encode(buffer, NXDN_RCCH_LC_LENGTH_BITS / 2U, NXDN_RCCH_LC_LENGTH_BITS / 2U);
// generate the CAC
channel::CAC cac;

@ -57,11 +57,6 @@ namespace nxdn
class HOST_SW_API Trunk {
public:
/// <summary>Resets the data states for the RF interface.</summary>
virtual void resetRF();
/// <summary>Resets the data states for the network.</summary>
virtual void resetNet();
/// <summary>Process a data frame from the RF interface.</summary>
virtual bool process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len);
/// <summary>Process a data frame from the network.</summary>
@ -78,21 +73,22 @@ namespace nxdn
network::BaseNetwork* m_network;
uint8_t m_bcchCnt;
uint8_t m_rcchGroupingCnt;
uint8_t m_ccchPagingCnt;
uint8_t m_ccchMultiCnt;
uint8_t m_rcchIterateCnt;
bool m_verifyAff;
bool m_verifyReg;
lc::RCCH m_rfLC;
lc::RCCH m_netLC;
uint16_t m_lastRejectId;
bool m_dumpRCCH;
bool m_verbose;
bool m_debug;
/// <summary>Initializes a new instance of the Trunk class.</summary>
Trunk(Control* nxdn, network::BaseNetwork* network, bool dumpRCCHData, bool debug, bool verbose);
Trunk(Control* nxdn, network::BaseNetwork* network, bool debug, bool verbose);
/// <summary>Finalizes a instance of the Trunk class.</summary>
virtual ~Trunk();
@ -103,16 +99,16 @@ namespace nxdn
void writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS);
/// <summary>Helper to write a single-block RCCH packet.</summary>
void writeRF_Message(bool noNetwork, bool clearBeforeWrite = false);
void writeRF_Message(lc::RCCH* rcch, bool noNetwork, bool clearBeforeWrite = false);
/// <summary>Helper to write a grant packet.</summary>
bool writeRF_Message_Grant(bool grp, bool skip = false, bool net = false, bool skipNetCheck = false);
bool writeRF_Message_Grant(uint32_t srcId, uint32_t dstId, uint8_t serviceOptions, bool grp, bool skip = false, uint32_t chNo = 0U, bool net = false, bool skipNetCheck = false);
/// <summary>Helper to write a deny packet.</summary>
void writeRF_Message_Deny(uint8_t reason, uint8_t service);
void writeRF_Message_Deny(uint32_t srcId, uint32_t dstId, uint8_t reason, uint8_t service);
/// <summary>Helper to write a group registration response packet.</summary>
bool writeRF_Message_Grp_Reg_Rsp(uint32_t srcId, uint32_t dstId);
bool writeRF_Message_Grp_Reg_Rsp(uint32_t srcId, uint32_t dstId, uint32_t locId);
/// <summary>Helper to write a unit registration response packet.</summary>
void writeRF_Message_U_Reg_Rsp(uint32_t srcId);
void writeRF_Message_U_Reg_Rsp(uint32_t srcId, uint32_t locId);
/// <summary>Helper to write a CC SITE_INFO broadcast packet on the RF interface.</summary>
void writeRF_CC_Message_Site_Info();

@ -212,7 +212,6 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
facch.getData(buffer);
lc::RTCH lc;
lc.setVerbose(m_dumpRTCH);
lc.decode(buffer, NXDN_FACCH1_FEC_LENGTH_BITS);
uint16_t dstId = lc.getDstId();
uint16_t srcId = lc.getSrcId();
@ -340,7 +339,6 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
facch.getData(buffer);
lc::RTCH lc;
lc.setVerbose(m_dumpRTCH);
lc.decode(buffer, NXDN_FACCH1_FEC_LENGTH_BITS);
hasInfo = lc.getMessageType() == RTCH_MESSAGE_TYPE_VCALL;
@ -646,7 +644,6 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
facch.getData(buffer);
lc::RTCH lc;
lc.setVerbose(m_dumpRTCH);
lc.decode(buffer, NXDN_FACCH1_FEC_LENGTH_BITS);
uint16_t dstId = lc.getDstId();
uint16_t srcId = lc.getSrcId();
@ -753,7 +750,6 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
facch.getData(buffer);
lc::RTCH lc;
lc.setVerbose(m_dumpRTCH);
lc.decode(buffer, NXDN_FACCH1_FEC_LENGTH_BITS);
hasInfo = lc.getMessageType() == RTCH_MESSAGE_TYPE_VCALL;
@ -980,10 +976,9 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
/// </summary>
/// <param name="nxdn">Instance of the Control class.</param>
/// <param name="network">Instance of the BaseNetwork class.</param>
/// <param name="dumpRTCHData">Flag indicating whether RTCH data is dumped to the log.</param>
/// <param name="debug">Flag indicating whether NXDN debug is enabled.</param>
/// <param name="verbose">Flag indicating whether NXDN verbose logging is enabled.</param>
Voice::Voice(Control* nxdn, network::BaseNetwork* network, bool dumpRTCHData, bool debug, bool verbose) :
Voice::Voice(Control* nxdn, network::BaseNetwork* network, bool debug, bool verbose) :
m_nxdn(nxdn),
m_network(network),
m_rfFrames(0U),
@ -994,7 +989,6 @@ Voice::Voice(Control* nxdn, network::BaseNetwork* network, bool dumpRTCHData, bo
m_netLost(0U),
m_lastRejectId(0U),
m_silenceThreshold(DEFAULT_SILENCE_THRESHOLD),
m_dumpRTCH(dumpRTCHData),
m_verbose(verbose),
m_debug(debug)
{

@ -84,13 +84,11 @@ namespace nxdn
uint32_t m_silenceThreshold;
bool m_dumpRTCH;
bool m_verbose;
bool m_debug;
/// <summary>Initializes a new instance of the Voice class.</summary>
Voice(Control* nxdn, network::BaseNetwork* network, bool dumpRTCHData, bool debug, bool verbose);
Voice(Control* nxdn, network::BaseNetwork* network, bool debug, bool verbose);
/// <summary>Finalizes a instance of the Voice class.</summary>
virtual ~Voice();

Loading…
Cancel
Save

Powered by TurnKey Linux.