initial experimental support for DFSI communication via DVM modem serial interface (DFSI support is disabled from compilation entirely by default, the -DENABLE_DFSI_SUPPORT compiler directive is required to enable it);

pull/12/head
Bryan Biedenkapp 4 years ago
parent 1caca50636
commit 4239d21a2b

@ -213,7 +213,9 @@
<ClInclude Include="p25\data\DataHeader.h" />
<ClInclude Include="p25\data\LowSpeedData.h" />
<ClInclude Include="p25\dfsi\DFSIDefines.h" />
<ClInclude Include="p25\dfsi\DFSIVoicePacket.h" />
<ClInclude Include="p25\dfsi\LC.h" />
<ClInclude Include="p25\dfsi\DFSITrunkPacket.h" />
<ClInclude Include="p25\edac\Trellis.h" />
<ClInclude Include="p25\lc\LC.h" />
<ClInclude Include="p25\lc\TDULC.h" />
@ -291,7 +293,9 @@
<ClCompile Include="p25\data\DataBlock.cpp" />
<ClCompile Include="p25\data\DataHeader.cpp" />
<ClCompile Include="p25\data\LowSpeedData.cpp" />
<ClCompile Include="p25\dfsi\DFSIVoicePacket.cpp" />
<ClCompile Include="p25\dfsi\LC.cpp" />
<ClCompile Include="p25\dfsi\DFSITrunkPacket.cpp" />
<ClCompile Include="p25\edac\Trellis.cpp" />
<ClCompile Include="p25\lc\LC.cpp" />
<ClCompile Include="p25\lc\TDULC.cpp" />
@ -320,7 +324,7 @@
</CopyFileToFolders>
<None Include="cpp.hint" />
<None Include="iden_channel_calc.py" />
<CopyFileToFolders Include="iden_table.example.dat">
<CopyFileToFolders Include="iden_table.dat">
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</DeploymentContent>
<FileType>Document</FileType>
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</DeploymentContent>

@ -377,6 +377,12 @@
<ClInclude Include="p25\dfsi\LC.h">
<Filter>Header Files\p25\dfsi</Filter>
</ClInclude>
<ClInclude Include="p25\dfsi\DFSITrunkPacket.h">
<Filter>Header Files\p25\dfsi</Filter>
</ClInclude>
<ClInclude Include="p25\dfsi\DFSIVoicePacket.h">
<Filter>Header Files\p25\dfsi</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Log.cpp">
@ -598,6 +604,12 @@
<ClCompile Include="p25\dfsi\LC.cpp">
<Filter>Source Files\p25\dfsi</Filter>
</ClCompile>
<ClCompile Include="p25\dfsi\DFSITrunkPacket.cpp">
<Filter>Source Files\p25\dfsi</Filter>
</ClCompile>
<ClCompile Include="p25\dfsi\DFSIVoicePacket.cpp">
<Filter>Source Files\p25\dfsi</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="Makefile" />
@ -606,9 +618,9 @@
</ItemGroup>
<ItemGroup>
<CopyFileToFolders Include="RSSI.dat" />
<CopyFileToFolders Include="iden_table.example.dat" />
<CopyFileToFolders Include="config.example.yml" />
<CopyFileToFolders Include="rid_acl.example.dat" />
<CopyFileToFolders Include="tg_acl.example.dat" />
<CopyFileToFolders Include="iden_table.dat" />
</ItemGroup>
</Project>

@ -54,6 +54,8 @@ HOST_OBJECTS = \
p25/data/DataHeader.o \
p25/data/LowSpeedData.o \
p25/dfsi/LC.o \
p25/dfsi/DFSITrunkPacket.o \
p25/dfsi/DFSIVoicePacket.o \
p25/edac/Trellis.o \
p25/lc/LC.o \
p25/lc/TDULC.o \

@ -504,6 +504,14 @@ int Host::run()
g_killed = true;
}
#if ENABLE_DFSI_SUPPORT
// DFSI checks
if (m_useDFSI && m_dmrEnabled) {
::LogError(LOG_HOST, "Cannot have DMR enabled when using DFSI!");
g_killed = true;
}
#endif
// P25 control channel checks
if (m_dmrEnabled && m_p25CtrlChannel) {
::LogError(LOG_HOST, "Cannot have DMR enabled when using dedicated P25 control!");
@ -1497,6 +1505,11 @@ bool Host::createModem()
yaml::Node modemProtocol = modemConf["protocol"];
std::string portType = modemProtocol["type"].as<std::string>("null");
#if NO_NO_FEATURE
m_useDFSI = modemProtocol["dfsi"].as<bool>(false);
#else
m_useDFSI = false;
#endif
yaml::Node uartProtocol = modemProtocol["uart"];
std::string uartPort = uartProtocol["port"].as<std::string>();
@ -1662,6 +1675,10 @@ bool Host::createModem()
LogInfo(" Packet Playout Time: %u ms", packetPlayoutTime);
LogInfo(" Disable Overflow Reset: %s", disableOFlowReset ? "yes" : "no");
if (m_useDFSI) {
LogInfo(" Digital Fixed Station Interface: yes");
}
if (ignoreModemConfigArea) {
LogInfo(" Ignore Modem Configuration Area: yes");
}
@ -1679,6 +1696,9 @@ bool Host::createModem()
m_modem->setRFParams(m_rxFrequency, m_txFrequency, rxTuning, txTuning, rfPower, dmrDiscBWAdj, p25DiscBWAdj, dmrPostBWAdj, p25PostBWAdj, adfGainMode);
m_modem->setDMRColorCode(m_dmrColorCode);
m_modem->setP25NAC(m_p25NAC);
#ifdef ENABLE_DFSI_SUPPORT
m_modem->setP25DFSI(m_useDFSI);
#endif
if (m_modemRemote) {
m_modem->setOpenHandler(MODEM_OC_PORT_HANDLER_BIND(Host::rmtPortModemOpen, this));

@ -88,6 +88,7 @@ private:
bool m_duplex;
bool m_fixedMode;
bool m_useDFSI;
uint32_t m_timeout;
uint32_t m_rfModeHang;

@ -76,7 +76,7 @@ using namespace modem;
}
// Check flash configuration value against class value.
#define FLASH_VALUE_CHECK_FLOAT(_CLASS_VAL, _FLASH_VAL, _DEFAULT, _STR) \
#define FLASH_VALUE_CHECK_FLOAT(_CLASS_VAL, _FLASH_VAL, _DEFAULT, _STR) \
if (_CLASS_VAL == _DEFAULT && _CLASS_VAL != _FLASH_VAL) { \
LogWarning(LOG_MODEM, CONFIG_OPT_MISMATCH_STR MODEM_CONFIG_AREA_DISAGREE_STR _STR " = %f, " _STR " (flash) = %f", _CLASS_VAL, _FLASH_VAL); \
_CLASS_VAL = _FLASH_VAL; \

@ -32,6 +32,8 @@
#include "p25/P25Defines.h"
#include "p25/Control.h"
#include "p25/acl/AccessControl.h"
#include "p25/dfsi/DFSITrunkPacket.h"
#include "p25/dfsi/DFSIVoicePacket.h"
#include "p25/P25Utils.h"
#include "p25/Sync.h"
#include "edac/CRC.h"
@ -140,9 +142,22 @@ Control::Control(uint32_t nac, uint32_t callHang, uint32_t queueSize, modem::Mod
m_hangCount = callHang * 4U;
#if ENABLE_DFSI_SUPPORT
if (m_modem->isP25DFSI()) {
LogMessage(LOG_P25, "DFSI protocol mode is enabled.");
m_voice = new dfsi::DFSIVoicePacket(this, network, debug, verbose);
m_trunk = new dfsi::DFSITrunkPacket(this, network, dumpTSBKData, debug, verbose);
}
else {
m_voice = new VoicePacket(this, network, debug, verbose);
m_trunk = new TrunkPacket(this, network, dumpTSBKData, debug, verbose);
m_data = new DataPacket(this, network, dumpPDUData, repeatPDU, debug, verbose);
}
#else
m_voice = new VoicePacket(this, network, debug, verbose);
m_data = new DataPacket(this, network, dumpPDUData, repeatPDU, debug, verbose);
m_trunk = new TrunkPacket(this, network, dumpTSBKData, debug, verbose);
m_data = new DataPacket(this, network, dumpPDUData, repeatPDU, debug, verbose);
#endif
}
/// <summary>
@ -150,9 +165,17 @@ Control::Control(uint32_t nac, uint32_t callHang, uint32_t queueSize, modem::Mod
/// </summary>
Control::~Control()
{
delete m_voice;
delete m_data;
delete m_trunk;
if (m_voice != NULL) {
delete m_voice;
}
if (m_trunk != NULL) {
delete m_trunk;
}
if (m_data != NULL) {
delete m_data;
}
}
/// <summary>
@ -162,8 +185,14 @@ void Control::reset()
{
m_rfState = RS_RF_LISTENING;
m_voice->resetRF();
m_data->resetRF();
if (m_voice != NULL) {
m_voice->resetRF();
}
if (m_data != NULL) {
m_data->resetRF();
}
m_queue.clear();
}
@ -216,6 +245,12 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s
m_ackTSBKRequests = control["ackRequests"].as<bool>(true);
m_trunk->m_ctrlTSDUMBF = !control["disableTSDUMBF"].as<bool>(false);
#if ENABLE_DFSI_SUPPORT
if (m_modem->isP25DFSI()) {
m_trunk->m_ctrlTSDUMBF = true; // force SBF for TSDUs when using DFSI
}
#endif
m_voice->m_silenceThreshold = p25Protocol["silenceThreshold"].as<uint32_t>(p25::DEFAULT_SILENCE_THRESHOLD);
if (m_voice->m_silenceThreshold > MAX_P25_VOICE_ERRORS) {
LogWarning(LOG_P25, "Silence threshold > %u, defaulting to %u", p25::MAX_P25_VOICE_ERRORS, p25::DEFAULT_SILENCE_THRESHOLD);
@ -314,6 +349,12 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
{
assert(data != NULL);
#if ENABLE_DFSI_SUPPORT
if (m_modem->isP25DFSI()) {
return processDFSI(data, len);
}
#endif
bool sync = data[1U] == 0x01U;
if (data[0U] == modem::TAG_LOST && m_rfState == RS_RF_AUDIO) {
@ -758,6 +799,160 @@ void Control::writeQueueNet(const uint8_t* data, uint32_t length)
m_queue.addData(data, len);
}
#if ENABLE_DFSI_SUPPORT
/// <summary>
/// Process a DFSI data frame from the RF interface.
/// </summary>
/// <param name="data">Buffer containing data frame.</param>
/// <param name="len">Length of data frame.</param>
/// <returns></returns>
bool Control::processDFSI(uint8_t* data, uint32_t len)
{
assert(data != NULL);
dfsi::LC dfsiLC = dfsi::LC();
if (data[0U] == modem::TAG_LOST && m_rfState == RS_RF_AUDIO) {
if (m_rssi != 0U) {
::ActivityLog("P25", true, "transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm",
float(m_voice->m_rfFrames) / 5.56F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
}
else {
::ActivityLog("P25", true, "transmission lost, %.1f seconds, BER: %.1f%%",
float(m_voice->m_rfFrames) / 5.56F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits));
}
LogMessage(LOG_RF, P25_TDU_STR ", total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%",
m_voice->m_rfFrames, m_voice->m_rfBits, m_voice->m_rfUndecodableLC, m_voice->m_rfErrs, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits));
if (m_control) {
m_trunk->releaseDstIdGrant(m_voice->m_rfLC.getDstId(), false);
}
writeRF_TDU(false);
m_voice->m_lastDUID = P25_DUID_TDU;
m_voice->writeNetworkRF(data + 2U, P25_DUID_TDU);
m_rfState = RS_RF_LISTENING;
m_rfLastDstId = 0U;
m_rfTGHang.stop();
m_tailOnIdle = true;
m_rfTimeout.stop();
m_queue.clear();
if (m_network != NULL)
m_network->resetP25();
return false;
}
if (data[0U] == modem::TAG_LOST && m_rfState == RS_RF_DATA) {
m_rfState = RS_RF_LISTENING;
m_rfLastDstId = 0U;
m_rfTGHang.stop();
m_tailOnIdle = true;
m_data->resetRF();
m_rfTimeout.stop();
m_queue.clear();
return false;
}
if (data[0U] == modem::TAG_LOST) {
m_rfState = RS_RF_LISTENING;
m_voice->resetRF();
m_data->resetRF();
m_trunk->m_rfTSBK = lc::TSBK(m_siteData, m_idenEntry);
return false;
}
// Decode the NID
bool valid = dfsiLC.decodeNID(data + 2U);
if (!valid && m_rfState == RS_RF_LISTENING)
return false;
uint8_t duid = 0xFFU; // a very invalid DUID
uint8_t frameType = dfsiLC.getFrameType();
if (m_debug) {
LogDebug(LOG_RF, "P25 DFSI, rfState = %u, netState = %u, frameType = %u", m_rfState, m_netState, dfsiLC.getFrameType());
}
// are we interrupting a running CC?
if (m_ccRunning) {
if (duid != P25_DUID_TSDU) {
g_interruptP25Control = true;
}
}
// convert DFSI frame-types to DUIDs (this doesn't 100% line up)
if (frameType == dfsi::P25_DFSI_START_STOP || frameType == dfsi::P25_DFSI_VHDR1 ||
frameType == dfsi::P25_DFSI_VHDR2) {
duid = P25_DUID_HDU;
}
else if (frameType >= dfsi::P25_DFSI_LDU1_VOICE1 && frameType <= dfsi::P25_DFSI_LDU1_VOICE9) {
duid = P25_DUID_LDU1;
}
else if (frameType >= dfsi::P25_DFSI_LDU2_VOICE10 && frameType <= dfsi::P25_DFSI_LDU2_VOICE18) {
duid = P25_DUID_LDU2;
}
else if (frameType == dfsi::P25_DFSI_TSBK) {
duid = P25_DUID_TSDU;
}
bool ret = false;
// handle individual DUIDs
switch (duid) {
case P25_DUID_HDU:
case P25_DUID_LDU1:
case P25_DUID_LDU2:
if (!m_dedicatedControl)
ret = m_voice->process(data, len);
else {
if (m_voiceOnControl && m_trunk->isChBusy(m_siteData.channelNo())) {
ret = m_voice->process(data, len);
}
}
break;
case P25_DUID_TDU:
case P25_DUID_TDULC:
ret = m_voice->process(data, len);
break;
case P25_DUID_PDU:
if (!m_dedicatedControl)
ret = m_data->process(data, len);
else {
if (m_voiceOnControl && m_trunk->isChBusy(m_siteData.channelNo())) {
ret = m_data->process(data, len);
}
}
break;
case P25_DUID_TSDU:
ret = m_trunk->process(data, len);
break;
default:
LogError(LOG_RF, "P25 unhandled DUID, duid = $%02X", duid);
return false;
}
return ret;
}
#endif
/// <summary>
/// Process a data frames from the network.
/// </summary>
@ -883,6 +1078,13 @@ void Control::writeRF_Preamble(uint32_t preambleCount, bool force)
/// <param name="noNetwork"></param>
void Control::writeRF_TDU(bool noNetwork)
{
#ifdef ENABLE_DFSI_SUPPORT
// for now abort out of this...
if (m_modem->isP25DFSI()) {
return;
}
#endif
uint8_t data[P25_TDU_FRAME_LENGTH_BYTES + 2U];
::memset(data + 2U, 0x00U, P25_TDU_FRAME_LENGTH_BYTES);

@ -56,8 +56,10 @@ namespace p25
// Class Prototypes
// ---------------------------------------------------------------------------
class HOST_SW_API VoicePacket;
namespace dfsi { class HOST_SW_API DFSIVoicePacket; }
class HOST_SW_API DataPacket;
class HOST_SW_API TrunkPacket;
namespace dfsi { class HOST_SW_API DFSITrunkPacket; }
// ---------------------------------------------------------------------------
// Class Declaration
@ -112,10 +114,12 @@ namespace p25
private:
friend class VoicePacket;
friend class dfsi::DFSIVoicePacket;
VoicePacket* m_voice;
friend class DataPacket;
DataPacket* m_data;
friend class TrunkPacket;
friend class dfsi::DFSITrunkPacket;
TrunkPacket* m_trunk;
uint32_t m_nac;
@ -184,6 +188,11 @@ namespace p25
/// <summary>Write data processed from the network to the data ring buffer.</summary>
void writeQueueNet(const uint8_t* data, uint32_t length);
#if ENABLE_DFSI_SUPPORT
/// <summary>Process a DFSI data frame from the RF interface.</summary>
bool processDFSI(uint8_t* data, uint32_t len);
#endif
/// <summary>Process a data frames from the network.</summary>
void processNetwork();

@ -158,9 +158,9 @@ void TrunkPacket::resetNet()
/// </summary>
/// <param name="data">Buffer containing data frame.</param>
/// <param name="len">Length of data frame.</param>
/// <param name="mbtDecoded">Flag indicating the TSBK data is pre-decoded TSBK data.</param>
/// <param name="preDecoded">Flag indicating the TSBK data is pre-decoded TSBK data.</param>
/// <returns></returns>
bool TrunkPacket::process(uint8_t* data, uint32_t len, bool mbtDecoded)
bool TrunkPacket::process(uint8_t* data, uint32_t len, bool preDecoded)
{
assert(data != NULL);
@ -168,7 +168,7 @@ bool TrunkPacket::process(uint8_t* data, uint32_t len, bool mbtDecoded)
return false;
uint8_t duid = 0U;
if (!mbtDecoded) {
if (!preDecoded) {
// Decode the NID
bool valid = m_p25->m_nid.decode(data + 2U);
@ -190,7 +190,7 @@ bool TrunkPacket::process(uint8_t* data, uint32_t len, bool mbtDecoded)
m_p25->m_queue.clear();
if (!mbtDecoded) {
if (!preDecoded) {
resetRF();
resetNet();
@ -1243,7 +1243,7 @@ void TrunkPacket::setTSBKVerbose(bool verbose)
}
// ---------------------------------------------------------------------------
// Private Class Members
// Protected Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the TrunkPacket class.

@ -47,6 +47,7 @@ namespace p25
// Class Prototypes
// ---------------------------------------------------------------------------
class HOST_SW_API VoicePacket;
namespace dfsi { class HOST_SW_API DFSIVoicePacket; }
class HOST_SW_API DataPacket;
class HOST_SW_API Control;
@ -58,14 +59,14 @@ namespace p25
class HOST_SW_API TrunkPacket {
public:
/// <summary>Resets the data states for the RF interface.</summary>
void resetRF();
virtual void resetRF();
/// <summary>Resets the data states for the network.</summary>
void resetNet();
virtual void resetNet();
/// <summary>Process a data frame from the RF interface.</summary>
bool process(uint8_t* data, uint32_t len, bool mbtDecoded = false);
virtual bool process(uint8_t* data, uint32_t len, bool preDecoded = false);
/// <summary>Process a data frame from the network.</summary>
bool processNetwork(uint8_t* data, uint32_t len, lc::LC& control, data::LowSpeedData& lsd, uint8_t& duid);
virtual bool processNetwork(uint8_t* data, uint32_t len, lc::LC& control, data::LowSpeedData& lsd, uint8_t& duid);
/// <summary>Helper used to process AMBTs from PDU data.</summary>
bool processMBT(data::DataHeader dataHeader, data::DataBlock* blocks);
@ -109,8 +110,9 @@ namespace p25
/// <summary>Helper to change the TSBK verbose state.</summary>
void setTSBKVerbose(bool verbose);
private:
protected:
friend class VoicePacket;
friend class dfsi::DFSIVoicePacket;
friend class DataPacket;
friend class Control;
Control* m_p25;
@ -166,7 +168,7 @@ namespace p25
/// <summary>Initializes a new instance of the TrunkPacket class.</summary>
TrunkPacket(Control* p25, network::BaseNetwork* network, bool dumpTSBKData, bool debug, bool verbose);
/// <summary>Finalizes a instance of the TrunkPacket class.</summary>
~TrunkPacket();
virtual ~TrunkPacket();
/// <summary>Write data processed from RF to the network.</summary>
void writeNetworkRF(const uint8_t* data, bool autoReset);
@ -180,7 +182,7 @@ namespace p25
void writeRF_TDULC_ChanRelease(bool grp, uint32_t srcId, uint32_t dstId);
/// <summary>Helper to write a single-block P25 TSDU packet.</summary>
void writeRF_TSDU_SBF(bool noNetwork, bool clearBeforeWrite = false, bool force = false);
virtual void writeRF_TSDU_SBF(bool noNetwork, bool clearBeforeWrite = false, bool force = false);
/// <summary>Helper to write a multi-block (3-block) P25 TSDU packet.</summary>
void writeRF_TSDU_MBF(bool clearBeforeWrite = false);
@ -213,9 +215,9 @@ namespace p25
void writeNet_TSDU_From_RF(uint8_t* data);
/// <summary>Helper to write a network P25 TDU w/ link control packet.</summary>
void writeNet_TDULC(lc::TDULC lc);
virtual void writeNet_TDULC(lc::TDULC lc);
/// <summary>Helper to write a network single-block P25 TSDU packet.</summary>
void writeNet_TSDU();
virtual void writeNet_TSDU();
/// <summary>Helper to automatically inhibit a source ID on a denial.</summary>
void denialInhibit(uint32_t srcId);

@ -871,7 +871,7 @@ bool VoicePacket::writeEndRF()
}
// ---------------------------------------------------------------------------
// Private Class Members
// Protected Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the VoicePacket class.

@ -58,19 +58,19 @@ namespace p25
class HOST_SW_API VoicePacket {
public:
/// <summary>Resets the data states for the RF interface.</summary>
void resetRF();
virtual void resetRF();
/// <summary>Resets the data states for the network.</summary>
void resetNet();
virtual void resetNet();
/// <summary>Process a data frame from the RF interface.</summary>
bool process(uint8_t* data, uint32_t len);
virtual bool process(uint8_t* data, uint32_t len);
/// <summary>Process a data frame from the network.</summary>
bool processNetwork(uint8_t* data, uint32_t len, lc::LC& control, data::LowSpeedData& lsd, uint8_t& duid);
virtual bool processNetwork(uint8_t* data, uint32_t len, lc::LC& control, data::LowSpeedData& lsd, uint8_t& duid);
/// <summary>Helper to write end of frame data.</summary>
bool writeEndRF();
private:
protected:
friend class TrunkPacket;
friend class Control;
Control* m_p25;
@ -119,7 +119,7 @@ namespace p25
/// <summary>Initializes a new instance of the VoicePacket class.</summary>
VoicePacket(Control* p25, network::BaseNetwork* network, bool debug, bool verbose);
/// <summary>Finalizes a instance of the VoicePacket class.</summary>
~VoicePacket();
virtual ~VoicePacket();
/// <summary>Write data processed from RF to the network.</summary>
void writeNetworkRF(const uint8_t* data, uint8_t duid);
@ -128,15 +128,15 @@ namespace p25
void writeRF_EndOfVoice();
/// <summary>Helper to write a network P25 TDU packet.</summary>
void writeNet_TDU();
virtual void writeNet_TDU();
/// <summary>Helper to check for an unflushed LDU1 packet.</summary>
void checkNet_LDU1();
/// <summary>Helper to write a network P25 LDU1 packet.</summary>
void writeNet_LDU1();
virtual void writeNet_LDU1();
/// <summary>Helper to check for an unflushed LDU2 packet.</summary>
void checkNet_LDU2();
/// <summary>Helper to write a network P25 LDU1 packet.</summary>
void writeNet_LDU2();
virtual void writeNet_LDU2();
/// <summary>Helper to insert IMBE silence frames for missing audio.</summary>
void insertMissingAudio(uint8_t* data);

@ -0,0 +1,211 @@
/**
* 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 "p25/P25Defines.h"
#include "p25/dfsi/DFSIDefines.h"
#include "p25/dfsi/DFSITrunkPacket.h"
#include "p25/P25Utils.h"
#include "p25/Sync.h"
#include "Log.h"
#include "Utils.h"
using namespace p25;
using namespace p25::dfsi;
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Resets the data states for the RF interface.
/// </summary>
void DFSITrunkPacket::resetRF()
{
TrunkPacket::resetRF();
LC lc = LC();
m_rfDFSILC = lc;
}
/// <summary>
/// Resets the data states for the network.
/// </summary>
void DFSITrunkPacket::resetNet()
{
TrunkPacket::resetNet();
LC lc = LC();
m_netDFSILC = lc;
}
/// <summary>
/// Process a data frame from the RF interface.
/// </summary>
/// <param name="data">Buffer containing data frame.</param>
/// <param name="len">Length of data frame.</param>
/// <param name="preDecoded">Flag indicating the TSBK data is pre-decoded TSBK data.</param>
/// <returns></returns>
bool DFSITrunkPacket::process(uint8_t* data, uint32_t len, bool preDecoded)
{
assert(data != NULL);
uint8_t tsbk[P25_TSBK_LENGTH_BYTES];
::memset(tsbk, 0x00U, P25_TSBK_LENGTH_BYTES);
if (!m_p25->m_control)
return false;
if (preDecoded) {
return TrunkPacket::process(data + 2U, len, preDecoded);
}
else {
resetRF();
resetNet();
if (m_rfDFSILC.decodeTSBK(data + 2U)) {
m_rfTSBK = m_rfDFSILC.tsbk();
return TrunkPacket::process(tsbk, P25_TSBK_LENGTH_BYTES, true);
}
}
return false;
}
// ---------------------------------------------------------------------------
// Protected Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the DFSITrunkPacket class.
/// </summary>
/// <param name="p25">Instance of the Control class.</param>
/// <param name="network">Instance of the BaseNetwork class.</param>
/// <param name="dumpTSBKData">Flag indicating whether TSBK data is dumped to the log.</param>
/// <param name="debug">Flag indicating whether P25 debug is enabled.</param>
/// <param name="verbose">Flag indicating whether P25 verbose logging is enabled.</param>
DFSITrunkPacket::DFSITrunkPacket(Control* p25, network::BaseNetwork* network, bool dumpTSBKData, bool debug, bool verbose) :
TrunkPacket(p25, network, dumpTSBKData, debug, verbose)
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the DFSITrunkPacket class.
/// </summary>
DFSITrunkPacket::~DFSITrunkPacket()
{
/* stub */
}
/// <summary>
/// Helper to write a P25 TDU w/ link control packet.
/// </summary>
/// <param name="lc"></param>
/// <param name="noNetwork"></param>
void DFSITrunkPacket::writeRF_TDULC(lc::TDULC lc, bool noNetwork)
{
// for now this is ignored...
}
/// <summary>
/// Helper to write a single-block P25 TSDU packet.
/// </summary>
/// <param name="noNetwork"></param>
/// <param name="clearBeforeWrite"></param>
/// <param name="force"></param>
void DFSITrunkPacket::writeRF_TSDU_SBF(bool noNetwork, bool clearBeforeWrite, bool force)
{
if (!m_p25->m_control)
return;
uint8_t data[P25_TSDU_FRAME_LENGTH_BYTES + 2U];
::memset(data + 2U, 0x00U, P25_TSDU_FRAME_LENGTH_BYTES);
m_rfDFSILC.tsbk(m_rfTSBK);
// Generate Sync
Sync::addP25Sync(data + 2U);
// Generate NID
m_p25->m_nid.encode(data + 2U, P25_DUID_TSDU);
// Generate TSBK block
m_rfTSBK.setLastBlock(true); // always set last block -- this a Single Block TSDU
m_rfTSBK.encode(data + 2U);
if (m_debug) {
LogDebug(LOG_RF, P25_TSDU_STR " DFSI, lco = $%02X, mfId = $%02X, lastBlock = %u, AIV = %u, EX = %u, srcId = %u, dstId = %u, sysId = $%03X, netId = $%05X",
m_rfTSBK.getLCO(), m_rfTSBK.getMFId(), m_rfTSBK.getLastBlock(), m_rfTSBK.getAIV(), m_rfTSBK.getEX(), m_rfTSBK.getSrcId(), m_rfTSBK.getDstId(),
m_rfTSBK.getSysId(), m_rfTSBK.getNetId());
Utils::dump(1U, "!!! *TSDU (SBF) TSBK Block Data", data + P25_PREAMBLE_LENGTH_BYTES + 2U, P25_TSBK_FEC_LENGTH_BYTES);
}
// Add busy bits
m_p25->addBusyBits(data + 2U, P25_TSDU_FRAME_LENGTH_BITS, true, false);
// Set first busy bits to 1,1
m_p25->setBusyBits(data + 2U, P25_SS0_START, true, true);
if (!noNetwork)
writeNetworkRF(data + 2U, true);
if (!force) {
if (clearBeforeWrite) {
m_p25->m_modem->clearP25Data();
m_p25->m_queue.clear();
}
}
::memset(data + 2U, 0x00U, P25_TSDU_FRAME_LENGTH_BYTES);
// Generate DFSI TSBK block
m_rfDFSILC.encodeTSBK(data + 2U);
if (m_p25->m_duplex) {
data[0U] = modem::TAG_DATA;
data[1U] = 0x00U;
m_p25->writeQueueRF(data, P25_DFSI_TSBK_FRAME_LENGTH_BYTES + 2U);
}
}
/// <summary>
/// Helper to write a network single-block P25 TSDU packet.
/// </summary>
void DFSITrunkPacket::writeNet_TSDU()
{
uint8_t buffer[P25_DFSI_TSBK_FRAME_LENGTH_BYTES + 2U];
::memset(buffer, 0x00U, P25_DFSI_TSBK_FRAME_LENGTH_BYTES + 2U);
buffer[0U] = modem::TAG_DATA;
buffer[1U] = 0x00U;
// Regenerate TSDU Data
m_netDFSILC.tsbk(m_netTSBK);
m_netDFSILC.encodeTSBK(buffer + 2U);
m_p25->writeQueueNet(buffer, P25_DFSI_TSBK_FRAME_LENGTH_BYTES + 2U);
if (m_network != NULL)
m_network->resetP25();
}

@ -0,0 +1,87 @@
/**
* 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(__P25_DFSI_TRUNK_PACKET_H__)
#define __P25_DFSI_TRUNK_PACKET_H__
#include "Defines.h"
#include "p25/dfsi/LC.h"
#include "p25/TrunkPacket.h"
#include "p25/Control.h"
#include "network/BaseNetwork.h"
namespace p25
{
// ---------------------------------------------------------------------------
// Class Prototypes
// ---------------------------------------------------------------------------
class HOST_SW_API TrunkPacket;
class HOST_SW_API Control;
namespace dfsi
{
// ---------------------------------------------------------------------------
// Class Declaration
// This class implements handling logic for P25 trunking packets using
// the DFSI protocol instead of the P25 OTA protocol.
// ---------------------------------------------------------------------------
class HOST_SW_API DFSITrunkPacket : public TrunkPacket {
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* data, uint32_t len, bool preDecoded = false);
protected:
friend class DFSIVoicePacket;
friend class Control;
LC m_rfDFSILC;
LC m_netDFSILC;
/// <summary>Initializes a new instance of the DFSITrunkPacket class.</summary>
DFSITrunkPacket(Control* p25, network::BaseNetwork* network, bool dumpTSBKData, bool debug, bool verbose);
/// <summary>Finalizes a instance of the DFSITrunkPacket class.</summary>
virtual ~DFSITrunkPacket();
/// <summary>Helper to write a P25 TDU w/ link control packet.</summary>
virtual void writeRF_TDULC(lc::TDULC lc, bool noNetwork);
/// <summary>Helper to write a single-block P25 TSDU packet.</summary>
virtual void writeRF_TSDU_SBF(bool noNetwork, bool clearBeforeWrite = false, bool force = false);
/// <summary>Helper to write a network P25 TDU w/ link control packet.</summary>
//virtual void writeNet_TDULC(lc::TDULC lc);
/// <summary>Helper to write a network single-block P25 TSDU packet.</summary>
virtual void writeNet_TSDU();
};
} // namespace dfsi
} // namespace p25
#endif // __P25_DFSI_TRUNK_PACKET_H__

File diff suppressed because it is too large Load Diff

@ -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
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 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(__P25_DFSI_VOICE_PACKET_H__)
#define __P25_DFSI_VOICE_PACKET_H__
#include "Defines.h"
#include "p25/dfsi/LC.h"
#include "p25/TrunkPacket.h"
#include "p25/Control.h"
#include "network/BaseNetwork.h"
namespace p25
{
// ---------------------------------------------------------------------------
// Class Prototypes
// ---------------------------------------------------------------------------
class HOST_SW_API VoicePacket;
class HOST_SW_API Control;
namespace dfsi
{
// ---------------------------------------------------------------------------
// Class Declaration
// This class implements handling logic for P25 voice packets using
// the DFSI protocol instead of the P25 OTA protocol.
// ---------------------------------------------------------------------------
class HOST_SW_API DFSIVoicePacket : public VoicePacket {
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* data, uint32_t len);
/// <summary>Process a data frame from the network.</summary>
virtual bool processNetwork(uint8_t* data, uint32_t len, lc::LC& control, data::LowSpeedData& lsd, uint8_t& duid);
protected:
friend class DFSITrunkPacket;
friend class Control;
LC m_rfDFSILC;
LC m_netDFSILC;
uint8_t* m_dfsiLDU1;
uint8_t* m_dfsiLDU2;
/// <summary>Initializes a new instance of the VoicePacket class.</summary>
DFSIVoicePacket(Control* p25, network::BaseNetwork* network, bool debug, bool verbose);
/// <summary>Finalizes a instance of the VoicePacket class.</summary>
virtual ~DFSIVoicePacket();
/// <summary>Helper to write a network P25 TDU packet.</summary>
virtual void writeNet_TDU();
/// <summary>Helper to write a network P25 LDU1 packet.</summary>
virtual void writeNet_LDU1();
/// <summary>Helper to write a network P25 LDU1 packet.</summary>
virtual void writeNet_LDU2();
};
} // namespace dfsi
} // namespace p25
#endif // __P25_DFSI_VOICE_PACKET_H__
Loading…
Cancel
Save

Powered by TurnKey Linux.