diff --git a/DVMHost.vcxproj b/DVMHost.vcxproj
index 2f218a70..24635be7 100644
--- a/DVMHost.vcxproj
+++ b/DVMHost.vcxproj
@@ -212,6 +212,8 @@
+
+
@@ -242,6 +244,7 @@
+
diff --git a/DVMHost.vcxproj.filters b/DVMHost.vcxproj.filters
index b5ff3973..8feda304 100644
--- a/DVMHost.vcxproj.filters
+++ b/DVMHost.vcxproj.filters
@@ -72,6 +72,9 @@
{ac8d97b8-a9bd-48e3-9fb9-08e997d055d4}
+
+ {c53673fd-d7d5-49f2-a8e4-5a92e379f436}
+
{94f78cbc-78b5-454e-972d-89ff595eca17}
@@ -84,6 +87,9 @@
{d742b2cf-71b2-45a1-afbd-753128c38f66}
+
+ {7c4122c6-5105-4c86-ac60-3a9873921535}
+
{07a6e6a8-699e-41a9-9e0f-0a8a064b2331}
@@ -365,6 +371,12 @@
Header Files\dmr
+
+ Header Files\p25\dfsi
+
+
+ Header Files\p25\dfsi
+
@@ -583,6 +595,9 @@
Source Files\host\setup
+
+ Source Files\p25\dfsi
+
diff --git a/Makefile b/Makefile
index 887aeefc..06fe2697 100644
--- a/Makefile
+++ b/Makefile
@@ -43,6 +43,7 @@ OBJECTS = \
p25/data/DataHeader.o \
p25/data/DataRspHeader.o \
p25/data/LowSpeedData.o \
+ p25/dfsi/LC.o \
p25/edac/Trellis.o \
p25/lc/LC.o \
p25/lc/TDULC.o \
diff --git a/Makefile.arm b/Makefile.arm
index effff533..81c93670 100644
--- a/Makefile.arm
+++ b/Makefile.arm
@@ -43,6 +43,7 @@ OBJECTS = \
p25/data/DataHeader.o \
p25/data/DataRspHeader.o \
p25/data/LowSpeedData.o \
+ p25/dfsi/LC.o \
p25/edac/Trellis.o \
p25/lc/LC.o \
p25/lc/TDULC.o \
diff --git a/Makefile.rpi-arm b/Makefile.rpi-arm
index 09dd4dde..8df53560 100644
--- a/Makefile.rpi-arm
+++ b/Makefile.rpi-arm
@@ -43,6 +43,7 @@ OBJECTS = \
p25/data/DataHeader.o \
p25/data/DataRspHeader.o \
p25/data/LowSpeedData.o \
+ p25/dfsi/LC.o \
p25/edac/Trellis.o \
p25/lc/LC.o \
p25/lc/TDULC.o \
diff --git a/p25/dfsi/DFSIDefines.h b/p25/dfsi/DFSIDefines.h
new file mode 100644
index 00000000..77210b9e
--- /dev/null
+++ b/p25/dfsi/DFSIDefines.h
@@ -0,0 +1,117 @@
+/**
+* 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_DEFINES_H__)
+#define __P25_DFSI_DEFINES_H__
+
+#include "Defines.h"
+
+// Frame Type String(s)
+#define P25_DFSI_VHDR1_STR "P25_DFSI_START_STOP (Start/Stop)"
+#define P25_DFSI_VHDR1_STR "P25_DFSI_VHDR1 (Voice Header 1)"
+#define P25_DFSI_VHDR2_STR "P25_DFSI_VHDR2 (Voice Header 2)"
+#define P25_DFSI_LDU1_STR "P25_DFSI_LDU1 (Logical Link Data Unit 1)"
+#define P25_DFSI_LDU2_STR "P25_DFSI_LDU2 (Logical Link Data Unit 2)"
+#define P25_DFSI_LDU2_STR "P25_DFSI_TSBK (Trunking System Block)"
+
+namespace p25
+{
+ namespace dfsi
+ {
+ // ---------------------------------------------------------------------------
+ // Constants
+ // ---------------------------------------------------------------------------
+
+ const uint32_t P25_DFSI_START_LENGTH_BYTES = 4U;
+
+ const uint32_t P25_DFSI_SS_FRAME_LENGTH_BYTES = 10U;
+
+ const uint32_t P25_DFSI_VHDR1_FRAME_LENGTH_BYTES = 30U;
+ const uint32_t P25_DFSI_VHDR2_FRAME_LENGTH_BYTES = 22U;
+
+ const uint32_t P25_DFSI_LDU1_VOICE1_FRAME_LENGTH_BYTES = 22U;
+ const uint32_t P25_DFSI_LDU1_VOICE2_FRAME_LENGTH_BYTES = 14U;
+ const uint32_t P25_DFSI_LDU1_VOICE3_FRAME_LENGTH_BYTES = 17U;
+ const uint32_t P25_DFSI_LDU1_VOICE4_FRAME_LENGTH_BYTES = 17U;
+ const uint32_t P25_DFSI_LDU1_VOICE5_FRAME_LENGTH_BYTES = 17U;
+ const uint32_t P25_DFSI_LDU1_VOICE6_FRAME_LENGTH_BYTES = 17U;
+ const uint32_t P25_DFSI_LDU1_VOICE7_FRAME_LENGTH_BYTES = 17U;
+ const uint32_t P25_DFSI_LDU1_VOICE8_FRAME_LENGTH_BYTES = 17U;
+ const uint32_t P25_DFSI_LDU1_VOICE9_FRAME_LENGTH_BYTES = 16U;
+
+ const uint32_t P25_DFSI_LDU2_VOICE10_FRAME_LENGTH_BYTES = 22U;
+ const uint32_t P25_DFSI_LDU2_VOICE11_FRAME_LENGTH_BYTES = 14U;
+ const uint32_t P25_DFSI_LDU2_VOICE12_FRAME_LENGTH_BYTES = 17U;
+ const uint32_t P25_DFSI_LDU2_VOICE13_FRAME_LENGTH_BYTES = 17U;
+ const uint32_t P25_DFSI_LDU2_VOICE14_FRAME_LENGTH_BYTES = 17U;
+ const uint32_t P25_DFSI_LDU2_VOICE15_FRAME_LENGTH_BYTES = 17U;
+ const uint32_t P25_DFSI_LDU2_VOICE16_FRAME_LENGTH_BYTES = 17U;
+ const uint32_t P25_DFSI_LDU2_VOICE17_FRAME_LENGTH_BYTES = 17U;
+ const uint32_t P25_DFSI_LDU2_VOICE18_FRAME_LENGTH_BYTES = 16U;
+
+ const uint32_t P25_DFSI_TSBK_FRAME_LENGTH_BYTES = 25U;
+
+ const uint8_t P25_DFSI_RT_ENABLED = 0x02U; //
+ const uint8_t P25_DFSI_RT_DISABLED = 0x04U; //
+
+ const uint8_t P25_DFSI_START_FLAG = 0x0CU; //
+ const uint8_t P25_DFSI_STOP_FLAG = 0x00U; //
+
+ const uint8_t P25_DFSI_TYPE_VOICE = 0x0BU; //
+ const uint8_t P25_DFSI_TYPE_TSBK = 0x0FU; //
+
+ const uint8_t P25_DFSI_ICW_SOURCE = 0x00U; // Infrastructure Source - Default Source
+
+ // Frame Type(s)
+ const uint8_t P25_DFSI_START_STOP = 0x00U; // Start/Stop
+
+ const uint8_t P25_DFSI_VHDR1 = 0x60U; // Voice Header 1
+ const uint8_t P25_DFSI_VHDR2 = 0x61U; // Voice Header 2
+
+ const uint8_t P25_DFSI_LDU1_VOICE1 = 0x62U; // IMBE LDU1 - Voice 1
+ const uint8_t P25_DFSI_LDU1_VOICE2 = 0x63U; // IMBE LDU1 - Voice 2
+ const uint8_t P25_DFSI_LDU1_VOICE3 = 0x64U; // IMBE LDU1 - Voice 3 + Link Control
+ const uint8_t P25_DFSI_LDU1_VOICE4 = 0x65U; // IMBE LDU1 - Voice 4 + Link Control
+ const uint8_t P25_DFSI_LDU1_VOICE5 = 0x66U; // IMBE LDU1 - Voice 5 + Link Control
+ const uint8_t P25_DFSI_LDU1_VOICE6 = 0x67U; // IMBE LDU1 - Voice 6 + Link Control
+ const uint8_t P25_DFSI_LDU1_VOICE7 = 0x68U; // IMBE LDU1 - Voice 7 + Link Control
+ const uint8_t P25_DFSI_LDU1_VOICE8 = 0x69U; // IMBE LDU1 - Voice 8 + Link Control
+ const uint8_t P25_DFSI_LDU1_VOICE9 = 0x6AU; // IMBE LDU1 - Voice 9 + Low Speed Data
+
+ const uint8_t P25_DFSI_LDU2_VOICE10 = 0x6BU; // IMBE LDU2 - Voice 10
+ const uint8_t P25_DFSI_LDU2_VOICE11 = 0x6CU; // IMBE LDU2 - Voice 11
+ const uint8_t P25_DFSI_LDU2_VOICE12 = 0x6DU; // IMBE LDU2 - Voice 12 + Encryption Sync
+ const uint8_t P25_DFSI_LDU2_VOICE13 = 0x6EU; // IMBE LDU2 - Voice 13 + Encryption Sync
+ const uint8_t P25_DFSI_LDU2_VOICE14 = 0x6FU; // IMBE LDU2 - Voice 14 + Encryption Sync
+ const uint8_t P25_DFSI_LDU2_VOICE15 = 0x70U; // IMBE LDU2 - Voice 15 + Encryption Sync
+ const uint8_t P25_DFSI_LDU2_VOICE16 = 0x71U; // IMBE LDU2 - Voice 16 + Encryption Sync
+ const uint8_t P25_DFSI_LDU2_VOICE17 = 0x72U; // IMBE LDU2 - Voice 17 + Encryption Sync
+ const uint8_t P25_DFSI_LDU2_VOICE18 = 0x73U; // IMBE LDU2 - Voice 18 + Low Speed Data
+
+ const uint8_t P25_DFSI_TSBK = 0xA1U; // TSBK
+ } // namespace dfsi
+} // namespace p25
+
+#endif // __P25_DFSI_DEFINES_H__
diff --git a/p25/dfsi/LC.cpp b/p25/dfsi/LC.cpp
new file mode 100644
index 00000000..da3bbdec
--- /dev/null
+++ b/p25/dfsi/LC.cpp
@@ -0,0 +1,156 @@
+/**
+* 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) 2016,2017 by Jonathan Naylor G4KLX
+* Copyright (C) 2017-2019 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/LC.h"
+#include "p25/P25Utils.h"
+#include "Log.h"
+#include "Utils.h"
+
+using namespace p25::dfsi;
+using namespace p25;
+
+#include
+#include
+#include
+
+// ---------------------------------------------------------------------------
+// Public Class Members
+// ---------------------------------------------------------------------------
+///
+/// Initializes a new instance of the LC class.
+///
+///
+LC::LC() :
+ m_rtModeFlag(P25_DFSI_RT_ENABLED),
+ m_startStopFlag(P25_DFSI_START_FLAG),
+ m_typeFlag(P25_DFSI_TYPE_VOICE),
+ m_control(),
+ m_lsd()
+{
+ /* stub */
+}
+
+///
+/// Finalizes a instance of LC class.
+///
+LC::~LC()
+{
+ /* stub */
+}
+
+///
+/// Equals operator.
+///
+///
+///
+LC& LC::operator=(const LC& data)
+{
+ if (this != &data) {
+ m_frameType = data.m_frameType;
+ m_rtModeFlag = data.m_rtModeFlag;
+ m_startStopFlag = data.m_startStopFlag;
+ m_typeFlag = data.m_typeFlag;
+
+ m_control = data.m_control;
+ m_lsd = data.m_lsd;
+ }
+
+ return *this;
+}
+
+///
+/// Decode a NID start/stop.
+///
+///
+/// True, if decoded, otherwise false.
+bool LC::decodeNID(const uint8_t* data)
+{
+ assert(data != NULL);
+
+ m_frameType = data[0U]; // Frame Type
+
+ return decodeStart(data);
+}
+
+///
+/// Encode a NID start/stop.
+///
+///
+void LC::encodeNID(uint8_t* data)
+{
+ assert(data != NULL);
+
+ uint8_t raw[P25_DFSI_SS_FRAME_LENGTH_BYTES];
+ ::memset(raw, 0x00U, P25_DFSI_SS_FRAME_LENGTH_BYTES);
+
+ raw[0U] = m_frameType; // Frame Type
+ encodeStart(raw + 1U);
+}
+
+// ---------------------------------------------------------------------------
+// Private Class Members
+// ---------------------------------------------------------------------------
+///
+/// Decode start data.
+///
+///
+/// True, if decoded, otherwise false.
+bool LC::decodeStart(const uint8_t* data)
+{
+ assert(data != NULL);
+
+ m_rtModeFlag = data[1U]; // RT Mode Flag
+ m_startStopFlag = data[2U]; // Start/Stop Flag
+ m_typeFlag = data[3U]; // Type Flag
+
+ return true;
+}
+
+///
+/// Encode start data.
+///
+///
+void LC::encodeStart(uint8_t* data)
+{
+ assert(data != NULL);
+
+ uint8_t raw[P25_DFSI_START_LENGTH_BYTES];
+ ::memset(raw, 0x00U, P25_DFSI_START_LENGTH_BYTES);
+
+ raw[0U] = 0x02U;
+ raw[1U] = m_rtModeFlag; // RT Mode Flag
+ raw[2U] = m_startStopFlag; // Start/Stop Flag
+ raw[3U] = m_typeFlag; // Type flag
+
+ ::memcpy(data, raw, P25_DFSI_START_LENGTH_BYTES);
+}
diff --git a/p25/dfsi/LC.h b/p25/dfsi/LC.h
new file mode 100644
index 00000000..9b0d8488
--- /dev/null
+++ b/p25/dfsi/LC.h
@@ -0,0 +1,104 @@
+/**
+* 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__LC_H__)
+#define __P25_DFSI__LC_H__
+
+#include "Defines.h"
+#include "p25/data/LowSpeedData.h"
+#include "p25/lc/LC.h"
+
+#include
+
+namespace p25
+{
+ namespace dfsi
+ {
+ // ---------------------------------------------------------------------------
+ // Class Declaration
+ // Represents link control data for DFSI VHDR, LDU1 and 2 packets.
+ // ---------------------------------------------------------------------------
+
+ class HOST_SW_API LC {
+ public:
+ /// Initializes a new instance of the LC class.
+ LC();
+ /// Finalizes a instance of the LC class.
+ ~LC();
+
+ /// Equals operator.
+ LC& operator=(const LC& data);
+
+ /// Decode a NID start/stop.
+ bool decodeNID(const uint8_t* data);
+ /// Encode a NID start/stop.
+ void encodeNID(uint8_t* data);
+
+ /// Decode a voice header 1.
+ bool decodeVHDR1(const uint8_t* data);
+ /// Encode a voice header 1.
+ void encodeVHDR1(uint8_t* data);
+
+ /// Decode a voice header 2.
+ bool decodeVHDR2(const uint8_t* data);
+ /// Encode a voice header 2.
+ void encodeVHDR2(uint8_t* data);
+
+ /// Decode a logical link data unit 1.
+ bool decodeLDU1(const uint8_t* data);
+ /// Encode a logical link data unit 1.
+ void encodeLDU1(uint8_t* data);
+
+ /// Decode a logical link data unit 2.
+ bool decodeLDU2(const uint8_t* data);
+ /// Encode a logical link data unit 2.
+ void encodeLDU2(uint8_t* data);
+
+ public:
+ /** Common Data */
+ /// Frame Type.
+ __PROPERTY(uint8_t, frameType, FrameType);
+ /// RT Mode Flag.
+ __PROPERTY(uint8_t, rtModeFlag, RTMode);
+ /// Start/Stop Flag.
+ __PROPERTY(uint8_t, startStopFlag, StartStop);
+ /// Type Flag.
+ __PROPERTY(uint8_t, typeFlag, Type);
+
+ /// Link control data.
+ __PROPERTY(p25::lc::LC, control, Control);
+ /// Low speed data.
+ __PROPERTY(p25::data::LowSpeedData, lsd, LSD);
+
+ private:
+ /// Decode start data.
+ bool decodeStart(const uint8_t* data);
+ /// Encode start data.
+ void encodeStart(uint8_t* data);
+ };
+ } // namespace dfsi
+} // namespace p25
+
+#endif // __P25_DFSI__LC_H__