You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dvmhost/src/common/p25/dfsi/frames/MotFullRateVoice.cpp

222 lines
6.2 KiB

// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Common Library
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2024 Patrick McDonnell, W3AXL
* Copyright (C) 2024-2025 Bryan Biedenkapp, N2PLL
*
*/
#include "common/p25/dfsi/frames/MotFullRateVoice.h"
#include "common/p25/P25Defines.h"
#include "common/p25/dfsi/DFSIDefines.h"
#include "common/Utils.h"
#include "common/Log.h"
#include <cassert>
#include <cstring>
using namespace p25;
using namespace p25::defines;
using namespace p25::dfsi;
using namespace p25::dfsi::defines;
using namespace p25::dfsi::frames;
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a instance of the MotFullRateVoice class. */
MotFullRateVoice::MotFullRateVoice() :
imbeData(nullptr),
additionalData(nullptr),
m_frameType(DFSIFrameType::LDU1_VOICE1),
m_totalErrors(0U),
m_busy(DFSI_BUSY_BITS_TALKAROUND)
{
imbeData = new uint8_t[RAW_IMBE_LENGTH_BYTES];
::memset(imbeData, 0x00U, RAW_IMBE_LENGTH_BYTES);
}
/* Initializes a instance of the MotFullRateVoice class. */
MotFullRateVoice::MotFullRateVoice(uint8_t* data) :
imbeData(nullptr),
additionalData(nullptr),
m_frameType(DFSIFrameType::LDU1_VOICE1),
m_totalErrors(0U),
m_busy(DFSI_BUSY_BITS_TALKAROUND)
{
// set our pointers to null since it doesn't get initialized otherwise
imbeData = nullptr;
additionalData = nullptr;
// decode
decode(data);
}
/* Finalizes a instance of the MotFullRateVoice class. */
MotFullRateVoice::~MotFullRateVoice()
{
if (imbeData != nullptr)
delete[] imbeData;
if (additionalData != nullptr)
delete[] additionalData;
}
/* */
uint32_t MotFullRateVoice::size()
{
uint32_t length = 0;
// set length appropriately based on frame type
if (isVoice1or2or10or11()) {
length += SHORTENED_LENGTH;
} else {
length += LENGTH;
}
// these are weird
if (isVoice9or18()) {
length -= 1;
}
return length;
}
/* Decode a full rate voice frame. */
bool MotFullRateVoice::decode(const uint8_t* data, bool shortened)
{
assert(data != nullptr);
if (imbeData != nullptr)
delete imbeData;
imbeData = new uint8_t[RAW_IMBE_LENGTH_BYTES];
::memset(imbeData, 0x00U, RAW_IMBE_LENGTH_BYTES);
m_frameType = (DFSIFrameType::E)data[0U];
if (isVoice2or11()) {
shortened = true;
}
if (shortened) {
::memcpy(imbeData, data + 1U, RAW_IMBE_LENGTH_BYTES);
m_totalErrors = (uint8_t)((data[12U] >> 3) & 0x0FU); // Total Errors
m_busy = (uint8_t)(data[13U] & 0x03U); // Busy Status
// forgot to set this originally and left additionalData uninitialized, whoops!
additionalData = nullptr;
} else {
// frames $6A and $73 are missing the 0x00 padding byte, so we start IMBE data 1 byte earlier
uint8_t imbeStart = 5U;
if (isVoice9or18()) {
imbeStart = 4U;
}
if (additionalData != nullptr)
delete[] additionalData;
additionalData = new uint8_t[ADDITIONAL_LENGTH];
::memset(additionalData, 0x00U, ADDITIONAL_LENGTH);
::memcpy(additionalData, data + 1U, ADDITIONAL_LENGTH);
// copy IMBE data based on our imbe start position
::memcpy(imbeData, data + imbeStart, RAW_IMBE_LENGTH_BYTES);
if (isVoice9or18()) {
m_totalErrors = 0U; // these frames don't have total errors
m_busy = (uint8_t)(data[3U] & 0x03U); // Busy Status
} else {
m_totalErrors = (uint8_t)((data[imbeStart + RAW_IMBE_LENGTH_BYTES] >> 2) & 0x0FU); // Total Errors
m_busy = (uint8_t)(data[imbeStart + RAW_IMBE_LENGTH_BYTES] & 0x03U); // Busy Status
}
}
return true;
}
/* Encode a full rate voice frame. */
void MotFullRateVoice::encode(uint8_t* data, bool shortened)
{
assert(data != nullptr);
assert(imbeData != nullptr);
// check if we're a shortened frame
data[0U] = m_frameType;
if (isVoice2or11()) {
shortened = true;
}
// copy based on shortened frame or not
if (shortened) {
::memcpy(data + 1U, imbeData, RAW_IMBE_LENGTH_BYTES);
data[13U] = (uint8_t)(m_busy & 0x03U); // Busy Status
}
// if not shortened, our IMBE data start position depends on frame type
else {
// starting index for the IMBE data
uint8_t imbeStart = 5U;
if (isVoice9or18()) {
imbeStart = 4U;
}
// check if we have additional data
if (additionalData != nullptr) {
::memcpy(data + 1U, additionalData, ADDITIONAL_LENGTH);
}
::memcpy(data + imbeStart, imbeData, RAW_IMBE_LENGTH_BYTES);
if (isVoice9or18()) {
data[3U] = (uint8_t)(m_busy & 0x03U); // Busy Status
} else {
data[imbeStart + RAW_IMBE_LENGTH_BYTES] = (uint8_t)(m_busy & 0x03U); // Busy Status
}
}
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/* Helper indicating if the frame is voice 1, 2, 10 or 11. */
bool MotFullRateVoice::isVoice1or2or10or11()
{
if ( (m_frameType == DFSIFrameType::LDU1_VOICE1) || (m_frameType == DFSIFrameType::LDU1_VOICE2) ||
(m_frameType == DFSIFrameType::LDU2_VOICE10) || (m_frameType == DFSIFrameType::LDU2_VOICE11) ) {
return true;
} else {
return false;
}
}
/* Helper indicating if the frame is voice 2 or 11. */
bool MotFullRateVoice::isVoice2or11()
{
if ( (m_frameType == DFSIFrameType::LDU1_VOICE2) || (m_frameType == DFSIFrameType::LDU2_VOICE11) ) {
return true;
} else {
return false;
}
}
/* Helper indicating if the frame is voice 9 or 18. */
bool MotFullRateVoice::isVoice9or18()
{
if ( (m_frameType == DFSIFrameType::LDU1_VOICE9) || (m_frameType == DFSIFrameType::LDU2_VOICE18) ) {
return true;
} else {
return false;
}
}

Powered by TurnKey Linux.