add TIA frame types (for future use); remove extraneous handling for DMR and NXDN (these are shut off in the network code, which makes the code in Dfsi pointless to have); remove g_hideMessages and logging from Dfsi class (for P25 this is actually instrumented by the debug flag in the SerialService (and when it exists UDPService) class, no need to duplicate this; add support for "null" modem mode for the SerialService, this allows basic code flow to be tested without any V.24 interface attached to the dvmdfsi instance, a "portType" parameter was added to the configuration file for this, by default it should always be "uart" but for null modem testing it can be set to "null"; add commenting and function definition commenting;
parent
ba8067c55c
commit
f0f1d489d1
@ -0,0 +1,108 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/**
|
||||
* Digital Voice Modem - DFSI Peer Application
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* @package DVM / DFSI Peer Application
|
||||
* @derivedfrom MMDVMHost (https://github.com/g4klx/MMDVMHost)
|
||||
* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||
*
|
||||
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
|
||||
*
|
||||
*/
|
||||
|
||||
#include "frames/BlockHeader.h"
|
||||
#include "common/p25/dfsi/DFSIDefines.h"
|
||||
#include "common/Utils.h"
|
||||
#include "common/Log.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
using namespace p25;
|
||||
using namespace dfsi;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public Class Members
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a instance of the BlockHeader class.
|
||||
/// </summary>
|
||||
BlockHeader::BlockHeader() :
|
||||
m_payloadType(false),
|
||||
m_blockLength(UNDEFINED)
|
||||
{
|
||||
/* stub */
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a instance of the BlockHeader class.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="verbose"></param>
|
||||
BlockHeader::BlockHeader(uint8_t* data, bool verbose) :
|
||||
m_payloadType(false),
|
||||
m_blockLength(UNDEFINED)
|
||||
{
|
||||
decode(data, verbose);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode a block header frame.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="verbose"></param>
|
||||
/// <returns></returns>
|
||||
bool BlockHeader::decode(const uint8_t* data, bool verbose)
|
||||
{
|
||||
assert(data != nullptr);
|
||||
|
||||
uint64_t value = 0U;
|
||||
|
||||
// combine bytes into ulong (8 byte) value
|
||||
value = data[0U];
|
||||
value = (value << 8) + data[1U];
|
||||
value = (value << 8) + data[2U];
|
||||
value = (value << 8) + data[3U];
|
||||
|
||||
m_payloadType = (data[0U] & 0x80U) == 0x80U; // Payload Type
|
||||
m_blockType = (BlockType)(data[0U] & 0x7FU); // Block Type
|
||||
|
||||
if (verbose) {
|
||||
m_timestampOffset = (uint32_t)((value >> 10) & 0x3FFU); // Timestamp Offset
|
||||
m_blockLength = (uint32_t)(value & 0x3FFU); // Block Length
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode a block header frame.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="verbose"></param>
|
||||
void BlockHeader::encode(uint8_t* data, bool verbose)
|
||||
{
|
||||
assert(data != nullptr);
|
||||
|
||||
if (!verbose) {
|
||||
data[0U] = (uint8_t)((m_payloadType ? 0x80U : 0x00U) + // Payload Type
|
||||
((uint8_t)m_blockType & 0x7FU)); // Block Type
|
||||
}
|
||||
else {
|
||||
uint64_t value = 0;
|
||||
|
||||
value = (uint8_t)((m_payloadType ? 0x80U : 0x00U) + // Payload Type
|
||||
((uint8_t)m_blockType & 0x7FU)); // Block Type
|
||||
value = (value << 24) + (m_timestampOffset & 0x3FFU); // Timestamp Offset
|
||||
value = (value << 10) + (m_blockLength & 0x3FFU); // Block Length
|
||||
|
||||
// split ulong (8 byte) value into bytes
|
||||
data[0U] = (uint8_t)((value >> 24) & 0xFFU);
|
||||
data[1U] = (uint8_t)((value >> 16) & 0xFFU);
|
||||
data[2U] = (uint8_t)((value >> 8) & 0xFFU);
|
||||
data[3U] = (uint8_t)((value >> 0) & 0xFFU);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/**
|
||||
* Digital Voice Modem - DFSI Peer Application
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* @package DVM / DFSI Peer Application
|
||||
* @derivedfrom MMDVMHost (https://github.com/g4klx/MMDVMHost)
|
||||
* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||
*
|
||||
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
|
||||
*
|
||||
*/
|
||||
#if !defined(__BLOCK_HEADER_H__)
|
||||
#define __BLOCK_HEADER_H__
|
||||
|
||||
#include "Defines.h"
|
||||
#include "common/Defines.h"
|
||||
#include "common/Log.h"
|
||||
#include "common/Utils.h"
|
||||
#include "frames/FrameDefines.h"
|
||||
|
||||
namespace p25
|
||||
{
|
||||
namespace dfsi
|
||||
{
|
||||
// ---------------------------------------------------------------------------
|
||||
// Class Declaration
|
||||
// Implements a DFSI block header packet.
|
||||
//
|
||||
// Compact Form
|
||||
// Byte 0
|
||||
// Bit 0 1 2 3 4 5 6 7
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
// |E| BT |
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
//
|
||||
// Verbose Form
|
||||
// Byte 0 1 2 3
|
||||
// Bit 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |E| BT | TSO | BL |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class HOST_SW_API BlockHeader {
|
||||
public:
|
||||
static const uint8_t LENGTH = 1;
|
||||
static const uint8_t VERBOSE_LENGTH = 4;
|
||||
|
||||
/// <summary>Initializes a copy instance of the BlockHeader class.</summary>
|
||||
BlockHeader();
|
||||
/// <summary>Initializes a copy instance of the BlockHeader class.</summary>
|
||||
BlockHeader(uint8_t* data, bool verbose = false);
|
||||
|
||||
/// <summary>Decode a block header frame.</summary>
|
||||
bool decode(const uint8_t* data, bool verbose = false);
|
||||
/// <summary>Encode a block header frame.</summary>
|
||||
void encode(uint8_t *data, bool verbose = false);
|
||||
|
||||
public:
|
||||
/// <summary>Payload type.</summary>
|
||||
/// <remarks>This simple boolean marks this header as either IANA standard, or profile specific.</remarks>
|
||||
__PROPERTY(bool, payloadType, PayloadType);
|
||||
/// <summary>Block type.</summary>
|
||||
__PROPERTY(BlockType, blockType, BlockType);
|
||||
/// <summary>Timestamp Offset.</summary>
|
||||
__PROPERTY(uint16_t, timestampOffset, TimestampOffset);
|
||||
/// <summary>Block length.</summary>
|
||||
__PROPERTY(uint16_t, blockLength, BlockLength);
|
||||
};
|
||||
} // namespace dfsi
|
||||
} // namespace p25
|
||||
|
||||
#endif // __BLOCK_HEADER_H__
|
||||
@ -0,0 +1,80 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/**
|
||||
* Digital Voice Modem - DFSI Peer Application
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* @package DVM / DFSI Peer Application
|
||||
* @derivedfrom MMDVMHost (https://github.com/g4klx/MMDVMHost)
|
||||
* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||
*
|
||||
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
|
||||
*
|
||||
*/
|
||||
|
||||
#include "frames/ControlOctet.h"
|
||||
#include "common/p25/dfsi/DFSIDefines.h"
|
||||
#include "common/Utils.h"
|
||||
#include "common/Log.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
using namespace p25;
|
||||
using namespace dfsi;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public Class Members
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a instance of the ControlOctet class.
|
||||
/// </summary>
|
||||
ControlOctet::ControlOctet() :
|
||||
m_signal(false),
|
||||
m_compact(true),
|
||||
m_blockHeaderCnt(0U)
|
||||
{
|
||||
/* stub */
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a instance of the ControlOctet class.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
ControlOctet::ControlOctet(uint8_t* data) :
|
||||
m_signal(false),
|
||||
m_compact(true),
|
||||
m_blockHeaderCnt(0U)
|
||||
{
|
||||
decode(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode a control octet frame.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
bool ControlOctet::decode(const uint8_t* data)
|
||||
{
|
||||
assert(data != nullptr);
|
||||
|
||||
m_signal = (data[0U] & 0x07U) == 0x07U; // Signal Flag
|
||||
m_compact = (data[0U] & 0x06U) == 0x06U; // Compact Flag
|
||||
m_blockHeaderCnt = (uint8_t)(data[0U] & 0x3FU); // Block Header Count
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode a control octet frame.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
void ControlOctet::encode(uint8_t* data)
|
||||
{
|
||||
assert(data != nullptr);
|
||||
|
||||
data[0U] = (uint8_t)((m_signal ? 0x07U : 0x00U) + // Signal Flag
|
||||
(m_compact ? 0x06U : 0x00U) + // Control Flag
|
||||
(m_blockHeaderCnt & 0x3F));
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/**
|
||||
* Digital Voice Modem - DFSI Peer Application
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* @package DVM / DFSI Peer Application
|
||||
* @derivedfrom MMDVMHost (https://github.com/g4klx/MMDVMHost)
|
||||
* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||
*
|
||||
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
|
||||
*
|
||||
*/
|
||||
#if !defined(__CONTROL_OCTET_H__)
|
||||
#define __CONTROL_OCTET_H__
|
||||
|
||||
#include "Defines.h"
|
||||
#include "common/Defines.h"
|
||||
#include "common/Log.h"
|
||||
#include "common/Utils.h"
|
||||
#include "frames/FrameDefines.h"
|
||||
|
||||
namespace p25
|
||||
{
|
||||
namespace dfsi
|
||||
{
|
||||
// ---------------------------------------------------------------------------
|
||||
// Class Declaration
|
||||
// Implements a DFSI control octet packet.
|
||||
//
|
||||
// Byte 0
|
||||
// Bit 0 1 2 3 4 5 6 7
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
// |S|C| BHC |
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class HOST_SW_API ControlOctet {
|
||||
public:
|
||||
static const uint8_t LENGTH = 1;
|
||||
|
||||
/// <summary>Initializes a copy instance of the ControlOctet class.</summary>
|
||||
ControlOctet();
|
||||
/// <summary>Initializes a copy instance of the ControlOctet class.</summary>
|
||||
ControlOctet(uint8_t* data);
|
||||
|
||||
/// <summary>Decode a control octet frame.</summary>
|
||||
bool decode(const uint8_t* data);
|
||||
/// <summary>Encode a control octet frame.</summary>
|
||||
void encode(uint8_t* data);
|
||||
|
||||
public:
|
||||
/// <summary></summary>
|
||||
__PROPERTY(bool, signal, Signal);
|
||||
/// <summary>Indicates a compact (1) or verbose (0) block header.</summary>
|
||||
__PROPERTY(bool, compact, Compact);
|
||||
/// <summary>Number of block headers following this control octet.</summary>
|
||||
__PROPERTY(uint8_t, blockHeaderCnt, BlockHeaderCnt);
|
||||
};
|
||||
} // namespace dfsi
|
||||
} // namespace p25
|
||||
|
||||
#endif // __CONTROL_OCTET_H__
|
||||
@ -0,0 +1,191 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/**
|
||||
* Digital Voice Modem - DFSI Peer Application
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* @package DVM / DFSI Peer Application
|
||||
* @derivedfrom MMDVMHost (https://github.com/g4klx/MMDVMHost)
|
||||
* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||
*
|
||||
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
|
||||
*
|
||||
*/
|
||||
|
||||
#include "frames/FullRateVoice.h"
|
||||
#include "common/p25/dfsi/DFSIDefines.h"
|
||||
#include "common/Utils.h"
|
||||
#include "common/Log.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
using namespace p25;
|
||||
using namespace dfsi;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public Class Members
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a instance of the FullRateVoice class.
|
||||
/// </summary>
|
||||
FullRateVoice::FullRateVoice() :
|
||||
imbeData(nullptr),
|
||||
additionalData(nullptr),
|
||||
m_frameType(P25_DFSI_LDU1_VOICE1),
|
||||
m_totalErrors(0U),
|
||||
m_muteFrame(false),
|
||||
m_lostFrame(false),
|
||||
m_superframeCnt(0U),
|
||||
m_busy(0U)
|
||||
{
|
||||
imbeData = new uint8_t[IMBE_BUF_LEN];
|
||||
::memset(imbeData, 0x00U, IMBE_BUF_LEN);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a instance of the FullRateVoice class.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
FullRateVoice::FullRateVoice(uint8_t* data) :
|
||||
imbeData(nullptr),
|
||||
additionalData(nullptr),
|
||||
m_frameType(P25_DFSI_LDU1_VOICE1),
|
||||
m_totalErrors(0U),
|
||||
m_muteFrame(false),
|
||||
m_lostFrame(false),
|
||||
m_superframeCnt(0U),
|
||||
m_busy(0U)
|
||||
{
|
||||
decode(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes a instance of the FullRateVoice class.
|
||||
/// </summary>
|
||||
FullRateVoice::~FullRateVoice()
|
||||
{
|
||||
if (imbeData != nullptr)
|
||||
delete[] imbeData;
|
||||
if (additionalData != nullptr)
|
||||
delete[] additionalData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode a full rate voice frame.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
bool FullRateVoice::decode(const uint8_t* data)
|
||||
{
|
||||
assert(data != nullptr);
|
||||
|
||||
if (imbeData != nullptr)
|
||||
delete imbeData;
|
||||
imbeData = new uint8_t[IMBE_BUF_LEN];
|
||||
::memset(imbeData, 0x00U, IMBE_BUF_LEN);
|
||||
|
||||
m_frameType = data[0U]; // Frame Type
|
||||
::memcpy(imbeData, data + 1U, IMBE_BUF_LEN); // IMBE
|
||||
|
||||
m_totalErrors = (uint8_t)((data[12U] >> 5) & 0x07U); // Total Errors
|
||||
m_muteFrame = (data[12U] & 0x02U) == 0x02U; // Mute Frame Flag
|
||||
m_lostFrame = (data[12U] & 0x01U) == 0x01U; // Lost Frame Flag
|
||||
m_superframeCnt = (uint8_t)((data[13U] >> 2) & 0x03U); // Superframe Counter
|
||||
m_busy = (uint8_t)(data[13U] & 0x03U);
|
||||
|
||||
if (isVoice3thru8() || isVoice12thru17() || isVoice9or10()) {
|
||||
if (additionalData != nullptr)
|
||||
delete additionalData;
|
||||
additionalData = new uint8_t[ADDITIONAL_LENGTH];
|
||||
::memset(additionalData, 0x00U, ADDITIONAL_LENGTH);
|
||||
|
||||
if (isVoice9or10()) {
|
||||
// CAI 9 and 10 are 3 bytes of additional data not 4
|
||||
::memcpy(additionalData, data + 14U, ADDITIONAL_LENGTH - 1U);
|
||||
} else {
|
||||
::memcpy(additionalData, data + 14U, ADDITIONAL_LENGTH);
|
||||
}
|
||||
} else {
|
||||
if (additionalData != nullptr)
|
||||
delete additionalData;
|
||||
additionalData = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode a full rate voice frame.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
void FullRateVoice::encode(uint8_t* data)
|
||||
{
|
||||
assert(data != nullptr);
|
||||
assert(imbeData != nullptr);
|
||||
|
||||
data[0U] = m_frameType; // Frame Type
|
||||
::memcpy(data + 1U, imbeData, IMBE_BUF_LEN); // IMBE
|
||||
|
||||
data[12U] = (uint8_t)(((m_totalErrors & 0x07U) << 5) + // Total Errors
|
||||
(m_muteFrame ? 0x02U : 0x00U) + // Mute Frame Flag
|
||||
(m_lostFrame ? 0x01U : 0x00U)); // Lost Frame Flag
|
||||
data[13U] = (uint8_t)(((m_superframeCnt & 0x03U) << 2) + // Superframe Count
|
||||
(m_busy & 0x03U)); // Busy Status
|
||||
|
||||
if ((isVoice3thru8() || isVoice12thru17() || isVoice9or10()) &&
|
||||
additionalData != nullptr) {
|
||||
if (isVoice9or10()) {
|
||||
// CAI 9 and 10 are 3 bytes of additional data not 4
|
||||
::memcpy(data + 14U, additionalData, ADDITIONAL_LENGTH - 1U);
|
||||
} else {
|
||||
::memcpy(data + 14U, additionalData, ADDITIONAL_LENGTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Private Class Members
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool FullRateVoice::isVoice3thru8()
|
||||
{
|
||||
if ( (m_frameType == P25_DFSI_LDU1_VOICE3) || (m_frameType == P25_DFSI_LDU1_VOICE4) || (m_frameType == P25_DFSI_LDU1_VOICE5) ||
|
||||
(m_frameType == P25_DFSI_LDU1_VOICE6) || (m_frameType == P25_DFSI_LDU1_VOICE7) || (m_frameType == P25_DFSI_LDU1_VOICE8) ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool FullRateVoice::isVoice12thru17()
|
||||
{
|
||||
if ( (m_frameType == P25_DFSI_LDU2_VOICE12) || (m_frameType == P25_DFSI_LDU2_VOICE13) || (m_frameType == P25_DFSI_LDU2_VOICE14) ||
|
||||
(m_frameType == P25_DFSI_LDU2_VOICE15) || (m_frameType == P25_DFSI_LDU2_VOICE16) || (m_frameType == P25_DFSI_LDU2_VOICE17) ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool FullRateVoice::isVoice9or10()
|
||||
{
|
||||
if ( (m_frameType == P25_DFSI_LDU1_VOICE9) || (m_frameType == P25_DFSI_LDU2_VOICE10) ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,215 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/**
|
||||
* Digital Voice Modem - DFSI Peer Application
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* @package DVM / DFSI Peer Application
|
||||
* @derivedfrom MMDVMHost (https://github.com/g4klx/MMDVMHost)
|
||||
* @license GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||
*
|
||||
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
|
||||
*
|
||||
*/
|
||||
#if !defined(__FULL_RATE_VOICE_H__)
|
||||
#define __FULL_RATE_VOICE_H__
|
||||
|
||||
#include "Defines.h"
|
||||
#include "common/Defines.h"
|
||||
#include "common/Log.h"
|
||||
#include "common/Utils.h"
|
||||
#include "frames/FrameDefines.h"
|
||||
|
||||
namespace p25
|
||||
{
|
||||
namespace dfsi
|
||||
{
|
||||
// ---------------------------------------------------------------------------
|
||||
// Class Declaration
|
||||
// Implements a P25 full rate voice packet.
|
||||
//
|
||||
// CAI Frames 1, 2, 10 and 11.
|
||||
//
|
||||
// Byte 0 1 2 3
|
||||
// Bit 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | FT | U0(b11-0) | U1(b11-0) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | U2(b10-0) | U3(b11-0) | U4(b10-3) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | U4 | U5(b10-0) | U6(b10-0) | U7(b6-0) |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | Et | Er |M|L|E| E1 |SF | B |
|
||||
// | | | | |4| | | |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
//
|
||||
// CAI Frames 3 - 8.
|
||||
//
|
||||
// Byte 0 1 2 3
|
||||
// Bit 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | FT | U0(b11-0) | U1(b11-0) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | U2(b10-0) | U3(b11-0) | U4(b10-3) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | U4 | U5(b10-0) | U6(b10-0) | U7(b6-0) |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | Et | Er |M|L|E| E1 |SF | B | LC0,4,8 | LC1,5,9 | LC2, |
|
||||
// | | | | |4| | | | | | 6,10 |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | | LC3,7,11 |R| Status |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
//
|
||||
// CAI Frames 12 - 17.
|
||||
//
|
||||
// Byte 0 1 2 3
|
||||
// Bit 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | FT | U0(b11-0) | U1(b11-0) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | U2(b10-0) | U3(b11-0) | U4(b10-3) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | U4 | U5(b10-0) | U6(b10-0) | U7(b6-0) |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | Et | Er |M|L|E| E1 |SF | B | ES0,4,8 | ES1,5,9 | ES2, |
|
||||
// | | | | |4| | | | | | 6,10 |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | | ES3,7,11 |R| Status |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
//
|
||||
// CAI Frames 9 and 10.
|
||||
//
|
||||
// Byte 0 1 2 3
|
||||
// Bit 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | FT | U0(b11-0) | U1(b11-0) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | U2(b10-0) | U3(b11-0) | U4(b10-3) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | U4 | U5(b10-0) | U6(b10-0) | U7(b6-0) |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | Et | Er |M|L|E| E1 |SF | B | LSD0,2 | LSD1,3 |
|
||||
// | | | | |4| | | | | |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | Rsvd |Si |Sj |
|
||||
// +=+=+=+=+=+=+=+=+
|
||||
//
|
||||
// Because the TIA.102-BAHA spec represents the "message vectors" as
|
||||
// 16-bit units (U0 - U7) this makes understanding the layout of the
|
||||
// buffer ... difficult for the 8-bit aligned minded. The following is
|
||||
// the layout with 8-bit aligned IMBE blocks instead of message vectors:
|
||||
//
|
||||
// CAI Frames 1, 2, 10 and 11.
|
||||
//
|
||||
// Byte 0 1 2 3
|
||||
// Bit 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | FT | IMBE 1 | IMBE 2 | IMBE 3 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | IMBE 4 | IMBE 5 | IMBE 6 | IMBE 7 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | IMBE 8 | IMBE 9 | IMBE 10 | IMBE 11 |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | Et | Er |M|L|E| E1 |SF | B |
|
||||
// | | | | |4| | | |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
//
|
||||
// CAI Frames 3 - 8.
|
||||
//
|
||||
// Byte 0 1 2 3
|
||||
// Bit 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | FT | IMBE 1 | IMBE 2 | IMBE 3 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | IMBE 4 | IMBE 5 | IMBE 6 | IMBE 7 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | IMBE 8 | IMBE 9 | IMBE 10 | IMBE 11 |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | Et | Er |M|L|E| E1 |SF | B | Link Ctrl | Link Ctrl |
|
||||
// | | | | |4| | | | | |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | Link Ctrl |R| Status |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
//
|
||||
// CAI Frames 12 - 17.
|
||||
//
|
||||
// Byte 0 1 2 3
|
||||
// Bit 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | FT | IMBE 1 | IMBE 2 | IMBE 3 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | IMBE 4 | IMBE 5 | IMBE 6 | IMBE 7 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | IMBE 8 | IMBE 9 | IMBE 10 | IMBE 11 |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | Et | Er |M|L|E| E1 |SF | B | Enc Sync | Enc Sync |
|
||||
// | | | | |4| | | | | |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | Enc Sync |R| Status |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
//
|
||||
// CAI Frames 9 and 10.
|
||||
//
|
||||
// Byte 0 1 2 3
|
||||
// Bit 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | FT | IMBE 1 | IMBE 2 | IMBE 3 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | IMBE 4 | IMBE 5 | IMBE 6 | IMBE 7 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | IMBE 8 | IMBE 9 | IMBE 10 | IMBE 11 |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | Et | Er |M|L|E| E1 |SF | B | LSD0,2 | LSD1,3 |
|
||||
// | | | | |4| | | | | |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | Rsvd |Si |Sj |
|
||||
// +=+=+=+=+=+=+=+=+
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class HOST_SW_API FullRateVoice {
|
||||
public:
|
||||
static const uint8_t LENGTH = 18;
|
||||
static const uint8_t ADDITIONAL_LENGTH = 4;
|
||||
static const uint8_t IMBE_BUF_LEN = 11;
|
||||
|
||||
/// <summary>Initializes a copy instance of the FullRateVoice class.</summary>
|
||||
FullRateVoice();
|
||||
/// <summary>Initializes a copy instance of the FullRateVoice class.</summary>
|
||||
FullRateVoice(uint8_t* data);
|
||||
/// <summary>Finalizes a instance of the FullRateVoice class.</summary>
|
||||
~FullRateVoice();
|
||||
|
||||
/// <summary>Decode a full rate voice frame.</summary>
|
||||
bool decode(const uint8_t* data);
|
||||
/// <summary>Encode a full rate voice frame.</summary>
|
||||
void encode(uint8_t* data);
|
||||
|
||||
public:
|
||||
uint8_t* imbeData; // ?? - this should probably be private with getters/setters
|
||||
uint8_t* additionalData; // ?? - this should probably be private with getters/setters
|
||||
|
||||
/// <summary>Frame Type.</summary>
|
||||
__PROPERTY(uint8_t, frameType, FrameType);
|
||||
/// <summary>Total errors detected in the frame.</summary>
|
||||
__PROPERTY(uint8_t, totalErrors, TotalErrors);
|
||||
/// <summary>Flag indicating the frame should be muted.</summary>
|
||||
__PROPERTY(bool, muteFrame, MuteFrame);
|
||||
/// <summary>Flag indicating the frame was lost.</summary>
|
||||
__PROPERTY(bool, lostFrame, LostFrame);
|
||||
/// <summary>Superframe Counter.</summary>
|
||||
__PROPERTY(uint8_t, superframeCnt, SuperframeCnt);
|
||||
/// <summary>Busy Status.</summary>
|
||||
__PROPERTY(uint8_t, busy, Busy);
|
||||
|
||||
private:
|
||||
/// <summary></summary>
|
||||
bool isVoice3thru8();
|
||||
/// <summary></summary>
|
||||
bool isVoice12thru17();
|
||||
/// <summary></summary>
|
||||
bool isVoice9or10();
|
||||
};
|
||||
} // namespace dfsi
|
||||
} // namespace p25
|
||||
|
||||
#endif // __FULL_RATE_VOICE_H__
|
||||
Loading…
Reference in new issue