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;

pull/61/head
Bryan Biedenkapp 2 years ago
parent ba8067c55c
commit f0f1d489d1

@ -60,8 +60,11 @@ dfsi:
remoteRtpPort: 27500
serial:
# Modem port type.
portType: "uart" # Valid values are "null", and "uart"
# Serial configuration for serial DFSI
port: "/dev/ttyACM0"
#
baudrate: 115200
# RT/RT flag enabled (0x02) or disabled (0x04)
rtrt: false

@ -225,49 +225,11 @@ int Dfsi::run()
UInt8Array p25Buffer = m_network->readP25(netReadRet, length);
if (netReadRet) {
uint8_t duid = p25Buffer[22U];
uint8_t MFId = p25Buffer[15U];
uint8_t lco = p25Buffer[4U];
uint32_t srcId = __GET_UINT16(p25Buffer, 5U);
uint32_t dstId = __GET_UINT16(p25Buffer, 8U);
if (!g_hideMessages)
LogMessage(LOG_NET, "P25, duid = $%02X, lco = $%02X, MFId = $%02X, srcId = %u, dstId = %u, len = %u", duid, lco, MFId, srcId, dstId, length);
// Send the data to the serial handler if serial is up
if (m_serial != nullptr)
m_serial->processP25FromNet(std::move(p25Buffer), length);
}
// We keep DMR & NXDN in so nothing breaks, even though DFSI doesn't do DMR or NXDN
UInt8Array dmrBuffer = m_network->readDMR(netReadRet, length);
if (netReadRet) {
uint8_t seqNo = dmrBuffer[4U];
uint32_t srcId = __GET_UINT16(dmrBuffer, 5U);
uint32_t dstId = __GET_UINT16(dmrBuffer, 8U);
uint8_t flco = (dmrBuffer[15U] & 0x40U) == 0x40U ? dmr::FLCO_PRIVATE : dmr::FLCO_GROUP;
uint32_t slotNo = (dmrBuffer[15U] & 0x80U) == 0x80U ? 2U : 1U;
if (!g_hideMessages)
LogMessage(LOG_NET, "DMR, slotNo = %u, seqNo = %u, flco = $%02X, srcId = %u, dstId = %u, len = %u", slotNo, seqNo, flco, srcId, dstId, length);
}
UInt8Array nxdnBuffer = m_network->readNXDN(netReadRet, length);
if (netReadRet) {
uint8_t messageType = nxdnBuffer[4U];
uint32_t srcId = __GET_UINT16(nxdnBuffer, 5U);
uint32_t dstId = __GET_UINT16(nxdnBuffer, 8U);
if (!g_hideMessages)
LogMessage(LOG_NET, "NXDN, messageType = $%02X, srcId = %u, dstId = %u, len = %u", messageType, srcId, dstId, length);
}
// ------------------------------------------------------
// -- Network TX Clocking --
// ------------------------------------------------------
@ -414,11 +376,18 @@ bool Dfsi::createPeerNetwork()
return true;
}
/// <summary>
/// Initializes serial V24 network.
/// </summary>
/// <param name="p25BufferSize"></param>
/// <param name="callTimeout"></param>
/// <returns></returns>
bool Dfsi::createSerialNetwork(uint32_t p25BufferSize, uint16_t callTimeout)
{
// Read serial config
yaml::Node dfsi_conf = m_conf["dfsi"];
yaml::Node serial_conf = dfsi_conf["serial"];
std::string portType = serial_conf["portType"].as<std::string>("null");
std::string port = serial_conf["port"].as<std::string>();
uint32_t baudrate = serial_conf["baudrate"].as<uint32_t>();
bool rtrt = serial_conf["rtrt"].as<bool>();
@ -428,6 +397,7 @@ bool Dfsi::createSerialNetwork(uint32_t p25BufferSize, uint16_t callTimeout)
bool serial_trace = serial_conf["trace"].as<bool>();
LogInfo("Serial Parameters");
LogInfo(" Port Type: %s", portType.c_str());
LogInfo(" Port: %s", port.c_str());
LogInfo(" Baudrate: %u", baudrate);
LogInfo(" RT/RT: %s", rtrt ? "Enabled" : "Disabled");
@ -437,7 +407,7 @@ bool Dfsi::createSerialNetwork(uint32_t p25BufferSize, uint16_t callTimeout)
LogInfo(" Trace: %s", serial_trace ? "Enabled" : "Disabled");
// Create serial service
m_serial = new SerialService(port, baudrate, rtrt, diu, jitter, m_network, p25BufferSize, p25BufferSize, callTimeout, serial_debug, serial_trace);
m_serial = new SerialService(portType, port, baudrate, rtrt, diu, jitter, m_network, p25BufferSize, p25BufferSize, callTimeout, serial_debug, serial_trace);
// Open serial
bool ret = m_serial->open();

@ -152,9 +152,6 @@ int checkArgs(int argc, char* argv[])
else if (IS("--syslog")) {
g_useSyslog = true;
}
else if (IS("-s")) {
g_hideMessages = true;
}
else if (IS("-c")) {
if (argc-- <= 0)
usage("error: %s", "must specify the configuration file to use");

@ -29,7 +29,6 @@ extern std::string g_lockFile;
extern bool g_foreground;
extern bool g_killed;
extern bool g_hideMessages;
extern std::string g_masterAddress;
extern uint16_t g_masterPort;

@ -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__

@ -25,6 +25,21 @@ namespace p25
// Constants
// ---------------------------------------------------------------------------
/// <summary>
/// DFSI Block Types
/// </summary>
enum BlockType {
FULL_RATE_VOICE = 0,
VOICE_HEADER_P1 = 6,
VOICE_HEADER_P2 = 7,
START_OF_STREAM = 9,
END_OF_STREAM = 10,
UNDEFINED = 127
};
/// <summary>
///
/// </summary>

@ -17,8 +17,13 @@
#include "Defines.h"
// TIA
#include "frames/StartOfStream.h"
#include "frames/ControlOctet.h"
#include "frames/BlockHeader.h"
#include "frames/FullRateVoice.h"
// "The" Manufacturer
#include "frames/MotFullRateVoice.h"
#include "frames/MotStartOfStream.h"
#include "frames/MotStartVoiceFrame.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__

@ -179,7 +179,7 @@ void MotFullRateVoice::encode(uint8_t* data, bool shortened)
}
// ---------------------------------------------------------------------------
// Protected Class Members
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>

@ -46,7 +46,6 @@ namespace p25
class HOST_SW_API MotFullRateVoice {
public:
// Frame information
static const uint8_t LENGTH = 17;
static const uint8_t SHORTENED_LENGTH = 13;
static const uint8_t ADDITIONAL_LENGTH = 4;
@ -70,7 +69,7 @@ namespace p25
uint8_t* imbeData; // ?? - this should probably be private with getters/setters
uint8_t* additionalData; // ?? - this should probably be private with getters/setters
/// <summary></summary>
/// <summary>Frame Type.</summary>
__PROPERTY(uint8_t, frameType, FrameType);
/// <summary></summary>
__PROPERTY(uint8_t, source, Source);

@ -44,7 +44,11 @@ MotStartOfStream::MotStartOfStream() :
/// Initializes a instance of the MotStartOfStream class.
/// </summary>
/// <param name="data"></param>
MotStartOfStream::MotStartOfStream(uint8_t* data)
MotStartOfStream::MotStartOfStream(uint8_t* data) :
m_marker(FIXED_MARKER),
m_rt(DISABLED),
m_startStop(START),
m_streamType(VOICE)
{
decode(data);
}

@ -48,12 +48,15 @@ MotStartVoiceFrame::MotStartVoiceFrame() :
/// Initializes a instance of the MotStartVoiceFrame class.
/// </summary>
/// <param name="data"></param>
MotStartVoiceFrame::MotStartVoiceFrame(uint8_t* data)
MotStartVoiceFrame::MotStartVoiceFrame(uint8_t* data) :
startOfStream(nullptr),
fullRateVoice(nullptr),
m_icw(ICW_DIU),
m_rssi(0U),
m_rssiValidity(INVALID),
m_nRssi(0U),
m_adjMM(0U)
{
// set our pointers to null since we don't initialize them anywhere else
startOfStream = nullptr;
fullRateVoice = nullptr;
// decode
decode(data);
}

@ -49,12 +49,14 @@ MotVoiceHeader1::MotVoiceHeader1() :
/// Initializes a instance of the MotVoiceHeader1 class.
/// </summary>
/// <param name="data"></param>
MotVoiceHeader1::MotVoiceHeader1(uint8_t* data)
MotVoiceHeader1::MotVoiceHeader1(uint8_t* data) :
header(nullptr),
startOfStream(nullptr),
m_icw(ICW_DIU),
m_rssi(0U),
m_rssiValidity(INVALID),
m_nRssi(0U)
{
// set our pointers to null since we haven't initialized them yet
startOfStream = nullptr;
header = nullptr;
// decode
decode(data);
}

@ -43,11 +43,10 @@ MotVoiceHeader2::MotVoiceHeader2() :
/// Initializes a instance of the MotVoiceHeader2 class.
/// </summary>
/// <param name="data"></param>
MotVoiceHeader2::MotVoiceHeader2(uint8_t* data)
MotVoiceHeader2::MotVoiceHeader2(uint8_t* data) :
header(nullptr),
m_source(SOURCE_QUANTAR)
{
// set pointer to null since it hasn't been initialized yet
header = nullptr;
// decode
decode(data);
}

@ -57,8 +57,8 @@ bool StartOfStream::decode(const uint8_t* data)
{
assert(data != nullptr);
m_nid = __GET_UINT16(data, 0U); // Network Identifier
m_errorCount = (data[2U] & 0x0FU); // Error Count
m_nid = __GET_UINT16(data, 0U); // Network Identifier
m_errorCount = (data[2U] & 0x0FU); // Error Count
return true;
}
@ -71,6 +71,6 @@ void StartOfStream::encode(uint8_t* data)
{
assert(data != nullptr);
__SET_UINT16(m_nid, data, 0U); // Network Identifier
data[2U] = m_errorCount & 0x0FU; // Error Count
__SET_UINT16(m_nid, data, 0U); // Network Identifier
data[2U] = m_errorCount & 0x0FU; // Error Count
}

@ -27,7 +27,6 @@ namespace p25
// ---------------------------------------------------------------------------
// Class Declaration
// Implements a P25 DFSI start of stream packet.
// </summary>
//
// Byte 0 1 2
// 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
@ -51,9 +50,9 @@ namespace p25
void encode(uint8_t* data);
public:
/// <summary></summary>
/// <summary>Network Identifier.</summary>
__PROPERTY(uint16_t, nid, NID);
/// <summary></summary>
/// <summary>Error count.</summary>
__PROPERTY(uint8_t, errorCount, ErrorCount);
};
} // namespace dfsi

@ -23,7 +23,27 @@ using namespace modem;
using namespace p25;
using namespace dfsi;
SerialService::SerialService(const std::string& portName, uint32_t baudrate, bool rtrt, bool diu, uint16_t jitter, DfsiPeerNetwork* network, uint32_t p25TxQueueSize, uint32_t p25RxQueueSize, uint16_t callTimeout, bool debug, bool trace) :
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the SerialService class.
/// </summary>
/// <param name="portType"></param>
/// <param name="portName"></param>
/// <param name="baudrate"></param>
/// <param name="rtrt"></param>
/// <param name="diu"></param>
/// <param name="jitter"></param>
/// <param name="network"></param>
/// <param name="p25TxQueueSize"></param>
/// <param name="p25RxQueueSize"></param>
/// <param name="callTimeout"></param>
/// <param name="debug"></param>
/// <param name="trace"></param>
SerialService::SerialService(std::string& portType, const std::string& portName, uint32_t baudrate, bool rtrt, bool diu, uint16_t jitter, DfsiPeerNetwork* network,
uint32_t p25TxQueueSize, uint32_t p25RxQueueSize, uint16_t callTimeout, bool debug, bool trace) :
m_portName(portName),
m_baudrate(baudrate),
m_rtrt(rtrt),
@ -62,7 +82,13 @@ SerialService::SerialService(const std::string& portName, uint32_t baudrate, boo
// Setup serial
port::SERIAL_SPEED serialSpeed = port::SERIAL_115200;
m_port = new port::UARTPort(portName, serialSpeed, false);
std::transform(portType.begin(), portType.end(), portType.begin(), ::tolower);
if (portType == NULL_PORT) {
m_port = new port::ModemNullPort();
}
else {
m_port = new port::UARTPort(portName, serialSpeed, false);
}
m_lastIMBE = new uint8_t[11U];
::memcpy(m_lastIMBE, P25_NULL_IMBE, 11U);
@ -70,6 +96,9 @@ SerialService::SerialService(const std::string& portName, uint32_t baudrate, boo
m_msgBuffer = new uint8_t[BUFFER_LENGTH];
}
/// <summary>
/// Finalizes a instance of the SerialService class.
/// </summary>
SerialService::~SerialService()
{
if (m_port != nullptr) {
@ -86,6 +115,10 @@ SerialService::~SerialService()
delete m_rxVoiceCallData;
}
/// <summary>
/// Updates the timer by the passed number of milliseconds.
/// </summary>
/// <param name="ms"></param>
void SerialService::clock(uint32_t ms)
{
// Get now
@ -193,6 +226,10 @@ void SerialService::clock(uint32_t ms)
}
}
/// <summary>
/// Opens connection to the serial interface.
/// </summary>
/// <returns>True, if connection is established, otherwise false.</returns>
bool SerialService::open()
{
LogInfoEx(LOG_SERIAL, "Opening port %s at %u baud", m_portName.c_str(), m_baudrate);
@ -209,6 +246,9 @@ bool SerialService::open()
return true;
}
/// <summary>
/// Closes connection to the serial interface.
/// </summary>
void SerialService::close()
{
LogInfoEx(LOG_SERIAL, "Closing port");
@ -916,6 +956,10 @@ void SerialService::processP25ToNet()
}
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>Read a data message from the serial port</summary>
/// This is borrowed from the Modem::getResponse() function
/// <returns>Response type</returns>

@ -33,6 +33,7 @@
#include "host/modem/Modem.h"
#include "host/modem/port/IModemPort.h"
#include "host/modem/port/UARTPort.h"
#include "host/modem/port/ModemNullPort.h"
// System Includes
#include <string>
@ -48,7 +49,6 @@ using namespace dfsi;
namespace network
{
// DFSI serial tx flags used to determine proper jitter handling of data in ringbuffer
enum SERIAL_TX_TYPE {
NONIMBE,
@ -56,20 +56,24 @@ namespace network
};
// ---------------------------------------------------------------------------
// Class Declaration
// Class Declaration
// Serial V24 service
// ---------------------------------------------------------------------------
class HOST_SW_API SerialService {
public:
SerialService(const std::string& portName, uint32_t baudrate, bool rtrt, bool diu, uint16_t jitter, DfsiPeerNetwork* network, uint32_t p25TxQueueSize, uint32_t p25RxQueueSize, uint16_t callTimeout, bool debug, bool trace);
/// <summary>Initializes an instance of the SerialService class.</summary>
SerialService(std::string& portType, const std::string& portName, uint32_t baudrate, bool rtrt, bool diu, uint16_t jitter, DfsiPeerNetwork* network, uint32_t p25TxQueueSize, uint32_t p25RxQueueSize, uint16_t callTimeout, bool debug, bool trace);
/// <summary>Finalizes an instance of the SerialService class.</summary>
~SerialService();
/// <summary>Updates the serial interface by the passed number of milliseconds.</summary>
void clock(uint32_t ms);
/// <summary>Opens connection to the serial interface.</summary>
bool open();
/// <summary>Closes connection to the serial interface.</summary>
void close();
// Handle P25 data from network to V24
@ -156,10 +160,6 @@ namespace network
void printDebug(const uint8_t* buffer, uint16_t length);
};
// Defines for Mot DFSI
} // namespace network
#endif // __SERIAL_SERVICE_H__
Loading…
Cancel
Save

Powered by TurnKey Linux.