diff --git a/CMakeLists.txt b/CMakeLists.txt
index 42d0a7f..1e36638 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,16 +14,18 @@ find_package(RTLSDR)
#more messing around
#find_package(Curses)
find_package(Curses REQUIRED) #making this required until I can fix all instances of it being called to ifdef lines
-find_package(PULSEAUDIO)
+find_package(PulseAudio)
#include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ${CURSES_INCLUDE_DIR})
#set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${CURSES_LIBRARY})
#remove CURSES from 'required' set up top AFTER switching all commands to ifdef in dsd_main, dsd_framesync, and dsd_ncurses.c
-#also, figure out how to make it build for wide character support in Linux Mint etc, like this -- $(ncursesw5-config --cflags --libs)
+#also, figure out how to make it build for wide character support in Linux Mint etc, like this -- $(ncursesw5-config --cflags --libs)
include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ${CURSES_INCLUDE_DIR})
set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${CURSES_LIBRARY})
+
if(Curses_FOUND)
+ set(CURSES_NEED_WIDE TRUE)
include_directories(SYSTEM ${CURSES_INCLUDE_PATH})
list(APPEND LIBS ${CURSES_LIBRARY})
add_definitions(-DUSE_CURSES)
diff --git a/cmake/FindCURSES.cmake b/cmake/FindCURSES.cmake
index 29818ba..bfa1d6f 100644
--- a/cmake/FindCURSES.cmake
+++ b/cmake/FindCURSES.cmake
@@ -1,16 +1,276 @@
-# - Try to find NCURSES
-# Once done this will define
-#
-# ITPP_FOUND - System has ITPP
-# ITPP_INCLUDE_DIR - The ITPP include directory
-# ITPP_LIBRARY - The library needed to use ITPP
-#
-set(CURSES_LIBRARY "/opt/lib/libncurses.so")
-set(CURSES_INCLUDE_PATH "/opt/include")
-find_path(CURSES_INCLUDE_DIR /usr/ncurses.h)
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
-set(CURSES_NAMES ${CURSES_NAMES} curses.h curses curses5w curses6w curses6 curses5 libncursesw)
-FIND_LIBRARY(CURSES_LIBRARY NAMES ${CURSES_NAMES})
+#[=======================================================================[.rst:
+FindCurses
+----------
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(CURSES DEFAULT_MSG NCURSES_LIBRARY CURSES_INCLUDE_DIR)
+Find the curses or ncurses include file and library.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``CURSES_FOUND``
+ True if Curses is found.
+``CURSES_INCLUDE_DIRS``
+ The include directories needed to use Curses.
+``CURSES_LIBRARIES``
+ The libraries needed to use Curses.
+``CURSES_CFLAGS``
+ .. versionadded:: 3.16
+
+ Parameters which ought be given to C/C++ compilers when using Curses.
+``CURSES_HAVE_CURSES_H``
+ True if curses.h is available.
+``CURSES_HAVE_NCURSES_H``
+ True if ncurses.h is available.
+``CURSES_HAVE_NCURSES_NCURSES_H``
+ True if ``ncurses/ncurses.h`` is available.
+``CURSES_HAVE_NCURSES_CURSES_H``
+ True if ``ncurses/curses.h`` is available.
+
+Set ``CURSES_NEED_NCURSES`` to ``TRUE`` before the
+``find_package(Curses)`` call if NCurses functionality is required.
+
+.. versionadded:: 3.10
+ Set ``CURSES_NEED_WIDE`` to ``TRUE`` before the
+ ``find_package(Curses)`` call if unicode functionality is required.
+
+Backward Compatibility
+^^^^^^^^^^^^^^^^^^^^^^
+
+The following variable are provided for backward compatibility:
+
+``CURSES_INCLUDE_DIR``
+ Path to Curses include. Use ``CURSES_INCLUDE_DIRS`` instead.
+``CURSES_LIBRARY``
+ Path to Curses library. Use ``CURSES_LIBRARIES`` instead.
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/CheckLibraryExists.cmake)
+
+# we don't know anything about cursesw, so only ncurses
+# may be ncursesw
+if(NOT CURSES_NEED_WIDE)
+ set(NCURSES_LIBRARY_NAME "ncurses")
+ set(CURSES_FORM_LIBRARY_NAME "form")
+else()
+ set(NCURSES_LIBRARY_NAME "ncursesw")
+ set(CURSES_FORM_LIBRARY_NAME "formw")
+ # Also, if we are searching for wide curses - we are actually searching
+ # for ncurses, we don't know about any other unicode version.
+ set(CURSES_NEED_NCURSES TRUE)
+endif()
+
+find_library(CURSES_CURSES_LIBRARY NAMES curses)
+
+find_library(CURSES_NCURSES_LIBRARY NAMES "${NCURSES_LIBRARY_NAME}" )
+set(CURSES_USE_NCURSES FALSE)
+
+if(CURSES_NCURSES_LIBRARY AND ((NOT CURSES_CURSES_LIBRARY) OR CURSES_NEED_NCURSES))
+ set(CURSES_USE_NCURSES TRUE)
+endif()
+# http://cygwin.com/ml/cygwin-announce/2010-01/msg00002.html
+# cygwin ncurses stopped providing curses.h symlinks see above
+# message. Cygwin is an ncurses package, so force ncurses on
+# cygwin if the curses.h is missing
+if(CURSES_NCURSES_LIBRARY AND CYGWIN)
+ if (CURSES_NEED_WIDE)
+ if(NOT EXISTS /usr/include/ncursesw/curses.h)
+ set(CURSES_USE_NCURSES TRUE)
+ endif()
+ else()
+ if(NOT EXISTS /usr/include/curses.h)
+ set(CURSES_USE_NCURSES TRUE)
+ endif()
+ endif()
+endif()
+
+
+# Not sure the logic is correct here.
+# If NCurses is required, use the function wsyncup() to check if the library
+# has NCurses functionality (at least this is where it breaks on NetBSD).
+# If wsyncup is in curses, use this one.
+# If not, try to find ncurses and check if this has the symbol.
+# Once the ncurses library is found, search the ncurses.h header first, but
+# some web pages also say that even with ncurses there is not always a ncurses.h:
+# http://osdir.com/ml/gnome.apps.mc.devel/2002-06/msg00029.html
+# So at first try ncurses.h, if not found, try to find curses.h under the same
+# prefix as the library was found, if still not found, try curses.h with the
+# default search paths.
+if(CURSES_CURSES_LIBRARY AND CURSES_NEED_NCURSES)
+ include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_QUIET ${Curses_FIND_QUIETLY})
+ CHECK_LIBRARY_EXISTS("${CURSES_CURSES_LIBRARY}"
+ wsyncup "" CURSES_CURSES_HAS_WSYNCUP)
+
+ if(CURSES_NCURSES_LIBRARY AND NOT CURSES_CURSES_HAS_WSYNCUP)
+ CHECK_LIBRARY_EXISTS("${CURSES_NCURSES_LIBRARY}"
+ wsyncup "" CURSES_NCURSES_HAS_WSYNCUP)
+ if( CURSES_NCURSES_HAS_WSYNCUP)
+ set(CURSES_USE_NCURSES TRUE)
+ endif()
+ endif()
+ cmake_pop_check_state()
+
+endif()
+
+if(CURSES_USE_NCURSES)
+ get_filename_component(_cursesLibDir "${CURSES_NCURSES_LIBRARY}" PATH)
+ get_filename_component(_cursesParentDir "${_cursesLibDir}" PATH)
+
+ # Use CURSES_NCURSES_INCLUDE_PATH if set, for compatibility.
+ if(CURSES_NCURSES_INCLUDE_PATH)
+ if (CURSES_NEED_WIDE)
+ find_path(CURSES_INCLUDE_PATH
+ NAMES ncursesw/ncurses.h ncursesw/curses.h ncursesw.h cursesw.h
+ PATHS ${CURSES_NCURSES_INCLUDE_PATH}
+ NO_DEFAULT_PATH
+ )
+ else()
+ find_path(CURSES_INCLUDE_PATH
+ NAMES ncurses/ncurses.h ncurses/curses.h ncurses.h curses.h
+ PATHS ${CURSES_NCURSES_INCLUDE_PATH}
+ NO_DEFAULT_PATH
+ )
+ endif()
+ endif()
+
+ if (CURSES_NEED_WIDE)
+ set(CURSES_TINFO_LIBRARY_NAME tinfow)
+ find_path(CURSES_INCLUDE_PATH
+ NAMES ncursesw/ncurses.h ncursesw/curses.h ncursesw.h cursesw.h
+ HINTS "${_cursesParentDir}/include"
+ )
+ else()
+ set(CURSES_TINFO_LIBRARY_NAME tinfo)
+ find_path(CURSES_INCLUDE_PATH
+ NAMES ncurses/ncurses.h ncurses/curses.h ncurses.h curses.h
+ HINTS "${_cursesParentDir}/include"
+ )
+ endif()
+
+ # Previous versions of FindCurses provided these values.
+ if(NOT DEFINED CURSES_LIBRARY)
+ set(CURSES_LIBRARY "${CURSES_NCURSES_LIBRARY}")
+ endif()
+
+ CHECK_LIBRARY_EXISTS("${CURSES_NCURSES_LIBRARY}"
+ cbreak "" CURSES_NCURSES_HAS_CBREAK)
+ CHECK_LIBRARY_EXISTS("${CURSES_NCURSES_LIBRARY}"
+ nodelay "" CURSES_NCURSES_HAS_NODELAY)
+ if(NOT CURSES_NCURSES_HAS_CBREAK OR NOT CURSES_NCURSES_HAS_NODELAY)
+ find_library(CURSES_EXTRA_LIBRARY "${CURSES_TINFO_LIBRARY_NAME}" HINTS "${_cursesLibDir}")
+ find_library(CURSES_EXTRA_LIBRARY "${CURSES_TINFO_LIBRARY_NAME}" )
+
+ mark_as_advanced(
+ CURSES_EXTRA_LIBRARY
+ )
+ endif()
+else()
+ get_filename_component(_cursesLibDir "${CURSES_CURSES_LIBRARY}" PATH)
+ get_filename_component(_cursesParentDir "${_cursesLibDir}" PATH)
+
+ #We can't find anything with CURSES_NEED_WIDE because we know
+ #only about ncursesw unicode curses version
+ if(NOT CURSES_NEED_WIDE)
+ find_path(CURSES_INCLUDE_PATH
+ NAMES curses.h
+ HINTS "${_cursesParentDir}/include"
+ )
+ endif()
+
+ # Previous versions of FindCurses provided these values.
+ if(NOT DEFINED CURSES_CURSES_H_PATH)
+ set(CURSES_CURSES_H_PATH "${CURSES_INCLUDE_PATH}")
+ endif()
+ if(NOT DEFINED CURSES_LIBRARY)
+ set(CURSES_LIBRARY "${CURSES_CURSES_LIBRARY}")
+ endif()
+endif()
+
+# Report whether each possible header name exists in the include directory.
+if(NOT DEFINED CURSES_HAVE_NCURSES_NCURSES_H)
+ if(CURSES_NEED_WIDE)
+ if(EXISTS "${CURSES_INCLUDE_PATH}/ncursesw/ncurses.h")
+ set(CURSES_HAVE_NCURSES_NCURSES_H "${CURSES_INCLUDE_PATH}/ncursesw/ncurses.h")
+ endif()
+ elseif(EXISTS "${CURSES_INCLUDE_PATH}/ncurses/ncurses.h")
+ set(CURSES_HAVE_NCURSES_NCURSES_H "${CURSES_INCLUDE_PATH}/ncurses/ncurses.h")
+ endif()
+ if(NOT DEFINED CURSES_HAVE_NCURSES_NCURSES_H)
+ set(CURSES_HAVE_NCURSES_NCURSES_H "CURSES_HAVE_NCURSES_NCURSES_H-NOTFOUND")
+ endif()
+endif()
+if(NOT DEFINED CURSES_HAVE_NCURSES_CURSES_H)
+ if(CURSES_NEED_WIDE)
+ if(EXISTS "${CURSES_INCLUDE_PATH}/ncursesw/curses.h")
+ set(CURSES_HAVE_NCURSES_CURSES_H "${CURSES_INCLUDE_PATH}/ncursesw/curses.h")
+ endif()
+ elseif(EXISTS "${CURSES_INCLUDE_PATH}/ncurses/curses.h")
+ set(CURSES_HAVE_NCURSES_CURSES_H "${CURSES_INCLUDE_PATH}/ncurses/curses.h")
+ endif()
+ if(NOT DEFINED CURSES_HAVE_NCURSES_CURSES_H)
+ set(CURSES_HAVE_NCURSES_CURSES_H "CURSES_HAVE_NCURSES_CURSES_H-NOTFOUND")
+ endif()
+endif()
+if(NOT CURSES_NEED_WIDE)
+ #ncursesw can't be found for this paths
+ if(NOT DEFINED CURSES_HAVE_NCURSES_H)
+ if(EXISTS "${CURSES_INCLUDE_PATH}/ncurses.h")
+ set(CURSES_HAVE_NCURSES_H "${CURSES_INCLUDE_PATH}/ncurses.h")
+ else()
+ set(CURSES_HAVE_NCURSES_H "CURSES_HAVE_NCURSES_H-NOTFOUND")
+ endif()
+ endif()
+ if(NOT DEFINED CURSES_HAVE_CURSES_H)
+ if(EXISTS "${CURSES_INCLUDE_PATH}/curses.h")
+ set(CURSES_HAVE_CURSES_H "${CURSES_INCLUDE_PATH}/curses.h")
+ else()
+ set(CURSES_HAVE_CURSES_H "CURSES_HAVE_CURSES_H-NOTFOUND")
+ endif()
+ endif()
+endif()
+
+find_library(CURSES_FORM_LIBRARY "${CURSES_FORM_LIBRARY_NAME}" HINTS "${_cursesLibDir}")
+find_library(CURSES_FORM_LIBRARY "${CURSES_FORM_LIBRARY_NAME}" )
+
+# Previous versions of FindCurses provided these values.
+if(NOT DEFINED FORM_LIBRARY)
+ set(FORM_LIBRARY "${CURSES_FORM_LIBRARY}")
+endif()
+
+# Need to provide the *_LIBRARIES
+set(CURSES_LIBRARIES ${CURSES_LIBRARY})
+
+if(CURSES_EXTRA_LIBRARY)
+ set(CURSES_LIBRARIES ${CURSES_LIBRARIES} ${CURSES_EXTRA_LIBRARY})
+endif()
+
+if(CURSES_FORM_LIBRARY)
+ set(CURSES_LIBRARIES ${CURSES_LIBRARIES} ${CURSES_FORM_LIBRARY})
+endif()
+
+# Provide the *_INCLUDE_DIRS and *_CFLAGS results.
+set(CURSES_INCLUDE_DIRS ${CURSES_INCLUDE_PATH})
+set(CURSES_INCLUDE_DIR ${CURSES_INCLUDE_PATH}) # compatibility
+
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(NCURSES QUIET ${NCURSES_LIBRARY_NAME})
+ set(CURSES_CFLAGS ${NCURSES_CFLAGS_OTHER})
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Curses DEFAULT_MSG
+ CURSES_LIBRARY CURSES_INCLUDE_PATH)
+
+mark_as_advanced(
+ CURSES_INCLUDE_PATH
+ CURSES_CURSES_LIBRARY
+ CURSES_NCURSES_LIBRARY
+ CURSES_FORM_LIBRARY
+ )
diff --git a/cmake/FindCURSES.cmake.bkp b/cmake/FindCURSES.cmake.bkp
new file mode 100644
index 0000000..29818ba
--- /dev/null
+++ b/cmake/FindCURSES.cmake.bkp
@@ -0,0 +1,16 @@
+# - Try to find NCURSES
+# Once done this will define
+#
+# ITPP_FOUND - System has ITPP
+# ITPP_INCLUDE_DIR - The ITPP include directory
+# ITPP_LIBRARY - The library needed to use ITPP
+#
+set(CURSES_LIBRARY "/opt/lib/libncurses.so")
+set(CURSES_INCLUDE_PATH "/opt/include")
+find_path(CURSES_INCLUDE_DIR /usr/ncurses.h)
+
+set(CURSES_NAMES ${CURSES_NAMES} curses.h curses curses5w curses6w curses6 curses5 libncursesw)
+FIND_LIBRARY(CURSES_LIBRARY NAMES ${CURSES_NAMES})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(CURSES DEFAULT_MSG NCURSES_LIBRARY CURSES_INCLUDE_DIR)
diff --git a/include/dsd.h b/include/dsd.h
index 7a19cc5..a24cfd0 100644
--- a/include/dsd.h
+++ b/include/dsd.h
@@ -71,8 +71,84 @@
*/
static volatile int exitflag;
-//volatile int exitflag; //didn't work, couldn't build, multiple definitions of exitflag
+//borrow from LEH
+typedef struct
+{
+ uint8_t RFChannelType;
+ uint8_t FunctionnalChannelType;
+ uint8_t Option;
+ uint8_t Direction;
+ uint8_t CompleteLich; /* 7 bits of LICH without parity */
+ uint8_t PreviousCompleteLich; /* 7 bits of previous LICH without parity */
+} NxdnLich_t;
+
+
+typedef struct
+{
+ uint8_t StructureField;
+ uint8_t RAN;
+ uint8_t Data[18];
+ uint8_t CrcIsGood;
+} NxdnSacchRawPart_t;
+
+
+typedef struct
+{
+ uint8_t Data[80];
+ uint8_t CrcIsGood;
+} NxdnFacch1RawPart_t;
+
+
+typedef struct
+{
+ uint8_t Data[184];
+ uint8_t CrcIsGood;
+} NxdnFacch2RawPart_t;
+
+
+typedef struct
+{
+ uint8_t F1;
+ uint8_t F2;
+ uint8_t MessageType;
+
+ /****************************/
+ /***** VCALL parameters *****/
+ /****************************/
+ uint8_t CCOption;
+ uint8_t CallType;
+ uint8_t VoiceCallOption;
+ uint16_t SourceUnitID;
+ uint16_t DestinationID; /* May be a Group ID or a Unit ID */
+ uint8_t CipherType;
+ uint8_t KeyID;
+ uint8_t VCallCrcIsGood;
+
+ /*******************************/
+ /***** VCALL_IV parameters *****/
+ /*******************************/
+ uint8_t IV[8];
+ uint8_t VCallIvCrcIsGood;
+
+ /*****************************/
+ /***** Custom parameters *****/
+ /*****************************/
+
+ /* Specifies if the "CipherType" and the "KeyID" parameter are valid
+ * 1 = Valid ; 0 = CRC error */
+ uint8_t CipherParameterValidity;
+
+ /* Used on DES and AES encrypted frames */
+ uint8_t PartOfCurrentEncryptedFrame; /* Could be 1 or 2 */
+ uint8_t PartOfNextEncryptedFrame; /* Could be 1 or 2 */
+ uint8_t CurrentIVComputed[8];
+ uint8_t NextIVComputed[8];
+} NxdnElementsContent_t;
+
+
+
+//end borrow from LEH
typedef struct
{
@@ -162,6 +238,7 @@ typedef struct
pa_simple *pulse_digi_dev_in;
pa_simple *pulse_digi_dev_out;
int use_ncurses_terminal;
+ int reset_state;
} dsd_opts;
@@ -194,7 +271,8 @@ typedef struct
int maxbuf[1024];
int minbuf[1024];
int midx;
- char err_str[64];
+ char err_str[64]; //actual error errorbars
+ char err_buf[64]; //make copy of err_str for comparison, only have string print when strcmp is different??
char fsubtype[16];
char ftype[16];
int symbolcnt;
@@ -248,6 +326,35 @@ typedef struct
short input_sample_buffer; //HERE HERE
short pulse_raw_out_buffer; //HERE HERE
//float *input_sample_buffer; //HERE HERE
+ short dibit_to_hex_buf;
+ // state->sr_0 shift registers
+ short hexbuf;
+ unsigned long long sr_0; //64-bit shift registers for pushing decoded binary or dibit data
+ unsigned long long sr_1; //384
+ unsigned long long sr_2; //
+ unsigned long long sr_3; //
+ unsigned long long sr_4; //
+ unsigned long long sr_5; //
+ unsigned long long sr_6; //
+
+ unsigned int dmr_color_code;
+ unsigned int nxdn_last_ran;
+ unsigned int nxdn_last_rid;
+ //borrow from LEH
+ NxdnSacchRawPart_t NxdnSacchRawPart[4];
+ NxdnFacch1RawPart_t NxdnFacch1RawPart[2];
+ NxdnFacch2RawPart_t NxdnFacch2RawPart;
+ NxdnElementsContent_t NxdnElementsContent;
+ NxdnLich_t NxdnLich;
+
+ int printNXDNAmbeVoiceSampleHex;
+
+ char ambe_ciphered[49];
+ char ambe_deciphered[49];
+ //end borrow
+
+
+
#ifdef TRACE_DSD
char debug_prefix;
@@ -277,34 +384,34 @@ typedef struct
#define INV_DSTAR_HD "313131313111311331313333"
#define DSTAR_SYNC "313131313133131113313111"
#define INV_DSTAR_SYNC "131313131311313331131333"
-// original sync numbers which is FSW plus LICH
+
+//bogus nxdnn data syncs to troubleshoot
+/*
+#define NXDN_MS_DATA_SYNC "33333313133113131111333333333111"
+#define INV_NXDN_MS_DATA_SYNC "11133331313113313133331113333331"
+#define INV_NXDN_BS_DATA_SYNC "33331111313113313133331313333333"
+#define NXDN_BS_DATA_SYNC "11113333131331131311113133333333"
+//end bogus nxdn data syncs
+*/
#define NXDN_MS_DATA_SYNC "313133113131111333"
#define INV_NXDN_MS_DATA_SYNC "131311331313333111"
-#define NXDN_MS_VOICE_SYNC "313133113131113133"
-#define INV_NXDN_MS_VOICE_SYNC "131311331313331311"
#define INV_NXDN_BS_DATA_SYNC "131311331313333131"
#define NXDN_BS_DATA_SYNC "313133113131111313"
-#define INV_NXDN_BS_VOICE_SYNC "131311331313331331"
-#define NXDN_BS_VOICE_SYNC "313133113131113113"
-
-//Try using only FSW and no LICH
-/*
-#define NXDN_MS_DATA_SYNC "3131331131"
-#define INV_NXDN_MS_DATA_SYNC "1313113313"
#define NXDN_MS_VOICE_SYNC "313133113131113133"
#define INV_NXDN_MS_VOICE_SYNC "131311331313331311"
-#define INV_NXDN_BS_DATA_SYNC "1313113313"
-#define NXDN_BS_DATA_SYNC "3131331131"
#define INV_NXDN_BS_VOICE_SYNC "131311331313331331"
#define NXDN_BS_VOICE_SYNC "313133113131113113"
-//how do two values equate to 4 symbol types? shouldn't it be -3, -1, 1, 3?
-*/
#define DMR_BS_DATA_SYNC "313333111331131131331131"
#define DMR_BS_VOICE_SYNC "131111333113313313113313"
#define DMR_MS_DATA_SYNC "311131133313133331131113"
#define DMR_MS_VOICE_SYNC "133313311131311113313331"
-
+//borrow extra syncs from LEH
+#define DMR_DIRECT_MODE_TS1_DATA_SYNC "331333313111313133311111"
+#define DMR_DIRECT_MODE_TS1_VOICE_SYNC "113111131333131311133333"
+#define DMR_DIRECT_MODE_TS2_DATA_SYNC "311311111333113333133311"
+#define DMR_DIRECT_MODE_TS2_VOICE_SYNC "133133333111331111311133"
+//end LEH
#define INV_PROVOICE_SYNC "31313111333133133311331133113311"
#define PROVOICE_SYNC "13131333111311311133113311331133"
#define INV_PROVOICE_EA_SYNC "13313133113113333311313133133311"
@@ -374,14 +481,62 @@ short nxdn_filter(short sample);
//borrow from LEH for testing 'improved NXDN detection'
int strncmperr(const char *s1, const char *s2, size_t size, int MaxErr);
+/* Global functions */ //also borrowed
+uint32_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength);
+uint32_t ConvertAsciiToByte(uint8_t AsciiMsbByte, uint8_t AsciiLsbByte, uint8_t * OutputByte);
+void Convert49BitSampleInto7Bytes(char * InputBit, char * OutputByte);
+void Convert7BytesInto49BitSample(char * InputByte, char * OutputBit);
//
//ifdef ncurses
void ncursesOpen ();
void ncursesPrinter (dsd_opts * opts, dsd_state * state);
void ncursesClose ();
//endif ncurses
+//borrow from LEH
+/* NXDN frame decoding functions */
+void ProcessNXDNFrame(dsd_opts * opts, dsd_state * state, uint8_t Inverted);
+void ProcessNxdnRCCHFrame(dsd_opts * opts, dsd_state * state, uint8_t Inverted);
+void ProcessNxdnRTCHFrame(dsd_opts * opts, dsd_state * state, uint8_t Inverted);
+void ProcessNxdnRDCHFrame(dsd_opts * opts, dsd_state * state, uint8_t Inverted);
+void ProcessNxdnRTCH_C_Frame(dsd_opts * opts, dsd_state * state, uint8_t Inverted);
+void ProcessNXDNIdleData (dsd_opts * opts, dsd_state * state, uint8_t Inverted);
+void ProcessNXDNFacch1Data (dsd_opts * opts, dsd_state * state, uint8_t Inverted);
+void ProcessNXDNUdchData (dsd_opts * opts, dsd_state * state, uint8_t Inverted);
+//end borrow
+//borrow from LEH
+/* NXDN functions */
+void CNXDNConvolution_start(void);
+void CNXDNConvolution_decode(uint8_t s0, uint8_t s1);
+void CNXDNConvolution_chainback(unsigned char* out, unsigned int nBits);
+void CNXDNConvolution_encode(const unsigned char* in, unsigned char* out, unsigned int nBits);
+uint8_t NXDN_decode_LICH(uint8_t InputLich[8],
+ uint8_t * RFChannelType,
+ uint8_t * FunctionnalChannelType,
+ uint8_t * Option,
+ uint8_t * Direction,
+ uint8_t * CompleteLichBinaryFormat,
+ uint8_t Inverted);
+uint8_t NXDN_SACCH_raw_part_decode(uint8_t * Input, uint8_t * Output);
+void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state);
+uint8_t NXDN_FACCH1_decode(uint8_t * Input, uint8_t * Output);
+uint8_t NXDN_UDCH_decode(uint8_t * Input, uint8_t * Output);
+void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
+ uint8_t CrcCorrect, uint8_t * ElementsContent);
+void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message);
+void NXDN_decode_VCALL_IV(dsd_opts * opts, dsd_state * state, uint8_t * Message);
+char * NXDN_Call_Type_To_Str(uint8_t CallType);
+void NXDN_Voice_Call_Option_To_Str(uint8_t VoiceCallOption, uint8_t * Duplex, uint8_t * TransmissionMode);
+char * NXDN_Cipher_Type_To_Str(uint8_t CipherType);
+uint16_t CRC15BitNXDN(uint8_t * BufferIn, uint32_t BitLength);
+uint16_t CRC12BitNXDN(uint8_t * BufferIn, uint32_t BitLength);
+uint8_t CRC6BitNXDN(uint8_t * BufferIn, uint32_t BitLength);
+void ScrambledNXDNVoiceBit(int * LfsrValue, char * BufferIn, char * BufferOut, int NbOfBitToScramble);
+void NxdnEncryptionStreamGeneration (dsd_opts* opts, dsd_state* state, uint8_t KeyStream[1664]);
+void processMbeFrameEncrypted (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24], char ambe_keystream[49], char imbe_keystream[88]);
+//end borrow from LEH
+void resetState (dsd_state * state);
#ifdef __cplusplus
extern "C" {
diff --git a/include/nxdn_const.h b/include/nxdn_const.h
index a447faa..9bfa907 100644
--- a/include/nxdn_const.h
+++ b/include/nxdn_const.h
@@ -21,13 +21,88 @@ extern const int nX[36];
extern const int nY[36];
extern const int nZ[36];
extern const char nxdnpr[145];
+extern const char nxdnpr2[145]; //why is this 145 but referenced later as 182 or 384
+//borrow from LEH
+extern const unsigned char nsW[72];
+extern const int DSDNXDN_SACCH_m_Interleave[60];
+extern const int DSDNXDN_SACCH_m_PunctureList[12];
+extern const int DSDNXDN_FACCH1_m_Interleave[144];
+extern const int DSDNXDN_FACCH1_m_PunctureList[48];
+extern const int DSDNXDN_UDCH_m_Interleave[348];
+extern const int DSDNXDN_UDCH_m_PunctureList[58];
+//
+//enum
+//{
+#define NXDN_VCALL 0b000001 /* VCALL = VCALL_REQ = VCALL_RESP */
+#define NXDN_VCALL_IV 0b000011
+#define NXDN_DCALL_HDR 0b001001 /* Header Format - NXDN_DCALL_HDR = NXDN_DCALL_REQ = NXDN_DCALL_RESP */
+#define NXDN_DCALL_USR 0b001011 /* User Data Format */
+#define NXDN_DCALL_ACK 0b001100
+#define NXDN_REL_EX 0b000111
+#define NXDN_HEAD_DLY 0b001111
+#define NXDN_SDCALL_REQ_HDR 0b111000 /* Header Format */
+#define NXDN_SDCALL_REQ_USR 0b111001 /* User Data Format */
+#define NXDN_SDCALL_RESP 0b111011
+#define NXDN_SDCALL_IV 0b111010
+#define NXDN_STAT_INQ_REQ 0b110000
+#define NXDN_STAT_INQ_RESP 0b110001
+#define NXDN_STAT_REQ 0b110010
+#define NXDN_STAT_RESP 0b110011
+#define NXDN_REM_CON_REQ 0b110100
+#define NXDN_REM_CON_RESP 0b110101
+#define NXDN_REM_CON_E_REQ 0b110110
+#define NXDN_REM_CON_E_RESP 0b110111
+//NXDN_VCALL_REQ = 0b000001, /* VCALL = VCALL_REQ = VCALL_RESP */
+//NXDN_VCALL_RESP = 0b000001, /* VCALL = VCALL_REQ = VCALL_RESP */
+#define NXDN_VCALL_REC_REQ = 0b000010 /* NXDN_VCALL_REC_REQ = NXDN_VCALL_REC_RESP */
+//NXDN_VCALL_REC_RESP = 0b000010,
+#define NXDN_VCALL_CONN_REQ = 0b000011 /* NXDN_VCALL_CONN_REQ = NXDN_VCALL_CONN_RESP */
+//NXDN_VCALL_CONN_RESP = 0b000011, /* NXDN_VCALL_CONN_REQ = NXDN_VCALL_CONN_RESP */
+#define NXDN_VCALL_ASSGN_DUP = 0b000101
+//NXDN_DCALL_REQ = 0b001001, /* NXDN_DCALL_HDR = NXDN_DCALL_REQ = NXDN_DCALL_RESP */
+//NXDN_DCALL_RESP = 0b001001, /* NXDN_DCALL_HDR = NXDN_DCALL_REQ = NXDN_DCALL_RESP */
+#define NXDN_DCALL_REC_REQ = 0b001010 /* NXDN_DCALL_REC_REQ = NXDN_DCALL_REC_RESP */
+//NXDN_DCALL_REC_RESP = 0b001010, /* NXDN_DCALL_REC_REQ = NXDN_DCALL_REC_RESP */
+#define NXDN_DCALL_ASSGN = 0b001110
+#define NXDN_DCALL_ASSGN_DUP = 0b001101
+#define NXDN_IDLE = 0b010000
+#define NXDN_DISC_REQ = 0b010001 /* NXDN_DISC_REQ = NXDN_DISC */
+#define NXDN_DISC = 0b010001 /* NXDN_DISC_REQ = NXDN_DISC */
+
#else
/*
* pseudorandom bit sequence
*/
const char nxdnpr[145] = { 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1 };
-
+//const unsigned char nxdnpr2[384] =
+const unsigned char nxdnpr2[182] = //is this a problem, should it be 384/2 for dibits?
+{
+ 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0,
+ 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0,
+ 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1,
+ 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1,
+ 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1,
+ 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1,
+ 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1,
+ 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1,
+ 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1,
+ 1, 1, 0, 0, 0, 1//, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
+// 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0,
+// 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,
+// 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+// 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1,
+// 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0,
+// 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1,
+// 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1,
+// 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1,
+// 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0,
+// 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0,
+// 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1
+};
/*
* NXDN AMBE interleave schedule
*/
@@ -63,4 +138,120 @@ const int nZ[36] = { 5, 3, 4, 2, 3, 1,
13, 2, 12, 1, 11, 0
};
+/*
+ * NXDN SACCH interleave
+ */
+const unsigned char nsW[72] = {
+ 0, 12, 24, 36, 48, 60,
+ 1, 13, 25, 37, 49, 61,
+ 2, 14, 26, 38, 50, 62,
+ 3, 15, 27, 39, 51, 63,
+ 4, 16, 28, 40, 52, 64,
+ 5, 17, 29, 41, 53, 65,
+ 6, 18, 30, 42, 54, 66,
+ 7, 19, 31, 43, 55, 67,
+ 8, 20, 32, 44, 56, 68,
+ 9, 21, 33, 45, 57, 69,
+ 10,22, 34, 46, 58, 70,
+ 11,23, 35, 47, 59, 71
+};
+
+const int DSDNXDN_SACCH_m_Interleave[60] =
+{
+ 0, 12, 24, 36, 48,
+ 1, 13, 25, 37, 49,
+ 2, 14, 26, 38, 50,
+ 3, 15, 27, 39, 51,
+ 4, 16, 28, 40, 52,
+ 5, 17, 29, 41, 53,
+ 6, 18, 30, 42, 54,
+ 7, 19, 31, 43, 55,
+ 8, 20, 32, 44, 56,
+ 9, 21, 33, 45, 57,
+ 10, 22, 34, 46, 58,
+ 11, 23, 35, 47, 59,
+};
+
+const int DSDNXDN_SACCH_m_PunctureList[12] = { 5, 11, 17, 23, 29, 35, 41, 47, 53, 59, 65, 71 };
+
+const unsigned int DSDNXDN_FACCH1_m_Interleave[144] =
+{
+ 0, 16, 32, 48, 64, 80, 96, 112, 128,
+ 1, 17, 33, 49, 65, 81, 97, 113, 129,
+ 2, 18, 34, 50, 66, 82, 98, 114, 130,
+ 3, 19, 35, 51, 67, 83, 99, 115, 131,
+ 4, 20, 36, 52, 68, 84, 100, 116, 132,
+ 5, 21, 37, 53, 69, 85, 101, 117, 133,
+ 6, 22, 38, 54, 70, 86, 102, 118, 134,
+ 7, 23, 39, 55, 71, 87, 103, 119, 135,
+ 8, 24, 40, 56, 72, 88, 104, 120, 136,
+ 9, 25, 41, 57, 73, 89, 105, 121, 137,
+ 10, 26, 42, 58, 74, 90, 106, 122, 138,
+ 11, 27, 43, 59, 75, 91, 107, 123, 139,
+ 12, 28, 44, 60, 76, 92, 108, 124, 140,
+ 13, 29, 45, 61, 77, 93, 109, 125, 141,
+ 14, 30, 46, 62, 78, 94, 110, 126, 142,
+ 15, 31, 47, 63, 79, 95, 111, 127, 143,
+};
+
+const unsigned int DSDNXDN_FACCH1_m_PunctureList[48] =
+{
+ 1U, 5U, 9U, 13U, 17U, 21U, 25U, 29U, 33U, 37U,
+ 41U, 45U, 49U, 53U, 57U, 61U, 65U, 69U, 73U, 77U,
+ 81U, 85U, 89U, 93U, 97U, 101U, 105U, 109U, 113U, 117U,
+ 121U, 125U, 129U, 133U, 137U, 141U, 145U, 149U, 153U, 157U,
+ 161U, 165U, 169U, 173U, 177U, 181U, 185U, 189U
+};
+
+const int DSDNXDN_UDCH_m_Interleave[348] = {
+ 0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120, 132, 144, 156, 168, 180, 192, 204, 216, 228, 240, 252, 264, 276, 288, 300, 312, 324, 336,
+ 1, 13, 25, 37, 49, 61, 73, 85, 97, 109, 121, 133, 145, 157, 169, 181, 193, 205, 217, 229, 241, 253, 265, 277, 289, 301, 313, 325, 337,
+ 2, 14, 26, 38, 50, 62, 74, 86, 98, 110, 122, 134, 146, 158, 170, 182, 194, 206, 218, 230, 242, 254, 266, 278, 290, 302, 314, 326, 338,
+ 3, 15, 27, 39, 51, 63, 75, 87, 99, 111, 123, 135, 147, 159, 171, 183, 195, 207, 219, 231, 243, 255, 267, 279, 291, 303, 315, 327, 339,
+ 4, 16, 28, 40, 52, 64, 76, 88, 100, 112, 124, 136, 148, 160, 172, 184, 196, 208, 220, 232, 244, 256, 268, 280, 292, 304, 316, 328, 340,
+ 5, 17, 29, 41, 53, 65, 77, 89, 101, 113, 125, 137, 149, 161, 173, 185, 197, 209, 221, 233, 245, 257, 269, 281, 293, 305, 317, 329, 341,
+ 6, 18, 30, 42, 54, 66, 78, 90, 102, 114, 126, 138, 150, 162, 174, 186, 198, 210, 222, 234, 246, 258, 270, 282, 294, 306, 318, 330, 342,
+ 7, 19, 31, 43, 55, 67, 79, 91, 103, 115, 127, 139, 151, 163, 175, 187, 199, 211, 223, 235, 247, 259, 271, 283, 295, 307, 319, 331, 343,
+ 8, 20, 32, 44, 56, 68, 80, 92, 104, 116, 128, 140, 152, 164, 176, 188, 200, 212, 224, 236, 248, 260, 272, 284, 296, 308, 320, 332, 344,
+ 9, 21, 33, 45, 57, 69, 81, 93, 105, 117, 129, 141, 153, 165, 177, 189, 201, 213, 225, 237, 249, 261, 273, 285, 297, 309, 321, 333, 345,
+ 10, 22, 34, 46, 58, 70, 82, 94, 106, 118, 130, 142, 154, 166, 178, 190, 202, 214, 226, 238, 250, 262, 274, 286, 298, 310, 322, 334, 346,
+ 11, 23, 35, 47, 59, 71, 83, 95, 107, 119, 131, 143, 155, 167, 179, 191, 203, 215, 227, 239, 251, 263, 275, 287, 299, 311, 323, 335, 347,
+};
+
+const int DSDNXDN_UDCH_m_PunctureList[58] = {
+ 3, 11,
+ 17, 25,
+ 31, 39,
+ 45, 53,
+ 59, 67,
+ 73, 81,
+ 87, 95,
+ 101, 109,
+ 115, 123,
+ 129, 137,
+ 143, 151,
+ 157, 165,
+ 171, 179,
+ 185, 193,
+ 199, 207,
+ 213, 221,
+ 227, 235,
+ 241, 249,
+ 255, 263,
+ 269, 277,
+ 283, 291,
+ 297, 305,
+ 311, 319,
+ 325, 333,
+ 339, 347,
+ 353, 361,
+ 367, 375,
+ 381, 389,
+ 395, 403,
+};
+
+//#endif /* _MAIN */
+
+
+
#endif
diff --git a/src/dmr_data.c b/src/dmr_data.c
index b1d870e..8d61c0f 100644
--- a/src/dmr_data.c
+++ b/src/dmr_data.c
@@ -28,13 +28,18 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
char cachdata[13];
char cc[5];
char bursttype[5];
+ int dcc_buf;
#ifdef DMR_DUMP
int k;
char syncbits[49];
char cachbits[25];
#endif
-
+ cc[0]=0;
+ cc[1]=0;
+ cc[2]=0;
+ cc[3]=0; //initialize with zeroes to prevent segfault down below
+ state->dmr_color_code = 0; //reset
cc[4] = 0;
bursttype[4] = 0;
@@ -95,8 +100,14 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
{
dibit = (dibit ^ 2);
}
- cc[0] = (1 & (dibit >> 1)) + 48; // bit 1
- cc[1] = (1 & dibit) + 48; // bit 0
+ //c[0] = (1 & (dibit >> 1)) + 48; // bit 1
+ //cc[1] = (1 & dibit) + 48; // bit 0
+ cc[0] = (1 & (dibit >> 1)); // bit 1
+ cc[1] = (1 & dibit); // bit 0
+ dcc_buf = 0;
+ //dcc_buf = (1 & (dibit >> 1)) | (1 & dibit);
+ dcc_buf = ((1 & (dibit >> 1)) + 48) | ((1 & dibit) + 48);
+
dibit = *dibit_p;
dibit_p++;
@@ -104,8 +115,20 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
{
dibit = (dibit ^ 2);
}
- cc[2] = (1 & (dibit >> 1)) + 48; // bit 1
- cc[3] = (1 & dibit) + 48; // bit 0
+ //cc[2] = (1 & (dibit >> 1)) + 48; // bit 1
+ //cc[3] = (1 & dibit) + 48; // bit 0
+ cc[2] = (1 & (dibit >> 1)); // bit 1
+ cc[3] = (1 & dibit); // bit 0
+
+ dcc_buf = dcc_buf << 2;
+ //dcc_buf = (1 & (dibit >> 1)) | (1 & dibit);
+ dcc_buf = ((1 & (dibit >> 1)) + 48) | ((1 & dibit) + 48);
+
+ //state->dmr_color_code = dcc_buf;
+ state->dmr_color_code = (unsigned int)((cc[0] << 3) + (cc[1] << 2) + (cc[2] << 1) + cc[3]);
+ //cc[2] = (1 & (dibit >> 1)); // bit 1
+ //cc[3] = (1 & dibit); // bit 0
+
dibit = *dibit_p;
dibit_p++;
diff --git a/src/dsd_dibit.c b/src/dsd_dibit.c
index 325d443..7502861 100644
--- a/src/dsd_dibit.c
+++ b/src/dsd_dibit.c
@@ -358,6 +358,61 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol)
}
state->last_dibit = dibit;
+ //test loading up a shift register and printing it to stderr
+ //di-bit shift register for hex values
+ //check for which dibit is equal to which half-nibble
+ if (dibit == 0){state->hexbuf = 0x0;} //+1
+ if (dibit == 1){state->hexbuf = 0x1;} //+3
+ if (dibit == 2){state->hexbuf = 0x2;} //-1
+ if (dibit == 3){state->hexbuf = 0x3;} //-3
+ state->sr_0 = (state->sr_0 << 2) | (state->sr_1 >> 62);
+ state->sr_1 = (state->sr_1 << 2) | (state->sr_2 >> 62);
+ state->sr_2 = (state->sr_2 << 2) | (state->sr_3 >> 62);
+ state->sr_3 = (state->sr_3 << 2) | (state->sr_4 >> 62);
+ state->sr_4 = (state->sr_4 << 2) | (state->sr_5 >> 62);
+ state->sr_5 = (state->sr_5 << 2) | (state->sr_6 >> 62);
+ state->sr_6 = state->sr_6 << 2;
+ state->sr_6 |= state->hexbuf;
+ if (1 == 2) //disable this later on
+ {
+ fprintf (stderr, "\nsr_0 = %16llX \n", state->sr_0);
+ fprintf (stderr, "sr_1 = %16llX \n", state->sr_1);
+ fprintf (stderr, "sr_2 = %16llX \n", state->sr_2);
+ fprintf (stderr, "sr_3 = %16llX \n", state->sr_3);
+ fprintf (stderr, "sr_4 = %16llX \n", state->sr_4);
+ fprintf (stderr, "sr_5 = %16llX \n", state->sr_5);
+ fprintf (stderr, "sr_6 = %16llX \n", state->sr_6);
+ /*
+ printw ("sr_0 = %16llX \n", sr_0);
+ printw ("sr_1 = %16llX \n", sr_1);
+ printw ("sr_2 = %16llX \n", sr_2);
+ printw ("sr_3 = %16llX \n", sr_3);
+ printw ("sr_4 = %16llX \n", sr_4);
+ printw ("sr_5 = %16llX \n", sr_5);
+ printw ("sr_6 = %16llX \n", sr_6);
+ */
+ }
+
+ if ( state->sr_5 & 0xFFFFF == 0xDDF5D) //disable this later on
+ {
+ fprintf (stderr, "\nsr_0 = %16llX \n", state->sr_0);
+ fprintf (stderr, "sr_1 = %16llX \n", state->sr_1);
+ fprintf (stderr, "sr_2 = %16llX \n", state->sr_2);
+ fprintf (stderr, "sr_3 = %16llX \n", state->sr_3);
+ fprintf (stderr, "sr_4 = %16llX \n", state->sr_4);
+ fprintf (stderr, "sr_5 = %16llX \n", state->sr_5);
+ fprintf (stderr, "sr_6 = %16llX \n", state->sr_6);
+ /*
+ printw ("sr_0 = %16llX \n", sr_0);
+ printw ("sr_1 = %16llX \n", sr_1);
+ printw ("sr_2 = %16llX \n", sr_2);
+ printw ("sr_3 = %16llX \n", sr_3);
+ printw ("sr_4 = %16llX \n", sr_4);
+ printw ("sr_5 = %16llX \n", sr_5);
+ printw ("sr_6 = %16llX \n", sr_6);
+ */
+ }
+
*state->dibit_buf_p = dibit;
state->dibit_buf_p++;
diff --git a/src/dsd_file.c b/src/dsd_file.c
index b27b67a..9a0dc32 100644
--- a/src/dsd_file.c
+++ b/src/dsd_file.c
@@ -16,7 +16,7 @@
*/
#include "dsd.h"
-
+int payload = 0;
void
saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
{
@@ -28,17 +28,28 @@ saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
fputc (err, opts->mbe_out_f);
k = 0;
+ if (payload == 1) //make opt variable later on to toggle this
+ {
+ fprintf(stderr, "\n");
+ }
+
for (i = 0; i < 11; i++)
{
b = 0;
+
for (j = 0; j < 8; j++)
{
b = b << 1;
b = b + imbe_d[k];
k++;
}
+ if (payload == 1) //make opt variable later on to toggle this
+ {
+ fprintf (stderr, "[%2X] ", b);
+ }
fputc (b, opts->mbe_out_f);
}
+ //fprintf(stderr, "\n");
fflush (opts->mbe_out_f);
}
@@ -53,17 +64,28 @@ saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
fputc (err, opts->mbe_out_f);
k = 0;
+ if (payload == 1) //make opt variable later on to toggle this
+ {
+ fprintf(stderr, "\n");
+ }
for (i = 0; i < 6; i++)
{
b = 0;
+
for (j = 0; j < 8; j++)
{
b = b << 1;
b = b + ambe_d[k];
k++;
}
+ if (payload == 1) //make opt variable later on to toggle this
+ {
+ fprintf (stderr, "[%2X] ", b);
+ }
+
fputc (b, opts->mbe_out_f);
}
+ //fprintf(stderr, "\n");
b = ambe_d[48];
fputc (b, opts->mbe_out_f);
fflush (opts->mbe_out_f);
diff --git a/src/dsd_frame.c b/src/dsd_frame.c
index 2390994..6044f5b 100644
--- a/src/dsd_frame.c
+++ b/src/dsd_frame.c
@@ -78,10 +78,10 @@ processFrame (dsd_opts * opts, dsd_state * state)
state->minref = state->min;
}
- if ((state->synctype == 8) || (state->synctype == 9)) //lets make this NOT do this...maybe...
+ if ((state->synctype == 8) || (state->synctype == 9)) //NXDN Voice
{
//state->rf_mod = 2; //wrong type of modulation HERE HERE
- //state->nac = 0;
+ state->nac = 0;
state->lastsrc = 0;
state->lasttg = 0;
if (opts->errorbars == 1)
@@ -89,7 +89,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
if (opts->verbose > 0)
{
level = (int) state->max / 164;
- fprintf (stderr,"inlvl: %2i%% ", level);
+ fprintf (stderr, "inlvl: %2i%% ", level);
}
}
state->nac = 0;
@@ -101,10 +101,10 @@ processFrame (dsd_opts * opts, dsd_state * state)
processNXDNVoice (opts, state);
return;
}
- else if ((state->synctype == 16) || (state->synctype == 17))
+ else if ((state->synctype == 16) || (state->synctype == 17)) //NXDN Data
{
//state->rf_mod = 2;
- //state->nac = 0;
+ state->nac = 0;
state->lastsrc = 0;
state->lasttg = 0;
if (opts->errorbars == 1)
diff --git a/src/dsd_frame_sync.c b/src/dsd_frame_sync.c
index f9a7f38..3b37932 100644
--- a/src/dsd_frame_sync.c
+++ b/src/dsd_frame_sync.c
@@ -185,12 +185,20 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
while (sync == 0)
{
//fprintf (stderr,"now=%d\n", now); //okay, so this is incrementing as expected
+ if (opts->use_ncurses_terminal == 1)
+ {
+ ncursesPrinter(opts, state);
+ }
if ( opts->monitor_input_audio == 1 && (time(NULL) - now) > 1 ) //okay, still something going on, still doing the read part for some reason
{
playRawAudio(opts, state); //this is on line 21 in dsd_audio.c
- //fprintf( stderr, "Farts");
}
-
+ /*
+ if (opts->reset_state == 1 && state->carrier == 0)
+ {
+ resetState (state);
+ }
+ */
t++;
symbol = getSymbol (opts, state, 0);
@@ -406,7 +414,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
- sprintf (state->ftype, " P25 Phase 1 ");
+ sprintf (state->ftype, "P25 Phase 1");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +P25p1 ", synctest_pos + 1, modulation);
@@ -421,7 +429,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
- sprintf (state->ftype, " P25 Phase 1 ");
+ sprintf (state->ftype, "P25 Phase 1");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -P25p1 ", synctest_pos + 1, modulation);
@@ -442,7 +450,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
if (opts->inverted_x2tdma == 0)
{
// data frame
- sprintf (state->ftype, " X2-TDMA ");
+ sprintf (state->ftype, "X2-TDMA");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +X2-TDMA ", synctest_pos + 1, modulation);
@@ -453,7 +461,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
else
{
// inverted voice frame
- sprintf (state->ftype, " X2-TDMA ");
+ sprintf (state->ftype, "X2-TDMA");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -X2-TDMA ", synctest_pos + 1, modulation);
@@ -476,7 +484,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
if (opts->inverted_x2tdma == 0)
{
// voice frame
- sprintf (state->ftype, " X2-TDMA ");
+ sprintf (state->ftype, "X2-TDMA");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +X2-TDMA ", synctest_pos + 1, modulation);
@@ -491,7 +499,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
else
{
// inverted data frame
- sprintf (state->ftype, " X2-TDMA ");
+ sprintf (state->ftype, "X2-TDMA");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -X2-TDMA ", synctest_pos + 1, modulation);
@@ -503,7 +511,8 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
}
if (opts->frame_dmr == 1)
{
- if ((strcmp (synctest, DMR_MS_DATA_SYNC) == 0) || (strcmp (synctest, DMR_BS_DATA_SYNC) == 0))
+ if ((strcmp (synctest, DMR_MS_DATA_SYNC) == 0) || (strcmp (synctest, DMR_BS_DATA_SYNC) == 0) )//try this
+ //if ((strncmperr (synctest, DMR_MS_DATA_SYNC, 24, 1) == 0) || (strncmperr (synctest, DMR_MS_DATA_SYNC, 24, 1) == 0))
{
now = time(NULL);
state->carrier = 1;
@@ -513,7 +522,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
if (opts->inverted_dmr == 0)
{
// data frame
- sprintf (state->ftype, " DMR ");
+ sprintf (state->ftype, "DMR");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +DMR ", synctest_pos + 1, modulation);
@@ -524,7 +533,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
else
{
// inverted voice frame
- sprintf (state->ftype, " DMR ");
+ sprintf (state->ftype, "DMR");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -DMR ", synctest_pos + 1, modulation);
@@ -538,6 +547,8 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
}
}
if ((strcmp (synctest, DMR_MS_VOICE_SYNC) == 0) || (strcmp (synctest, DMR_BS_VOICE_SYNC) == 0))
+ //if ( strcmp (synctest, DMR_MS_VOICE_SYNC) == 0 || strcmp (synctest, DMR_BS_VOICE_SYNC) == 0 || strcmp (synctest, DMR_DIRECT_MODE_TS1_VOICE_SYNC) == 0 || strcmp (synctest, DMR_DIRECT_MODE_TS2_VOICE_SYNC) == 0 )
+ //if ((strncmperr (synctest, DMR_MS_VOICE_SYNC, 24, 1) == 0) || (strncmperr (synctest, DMR_BS_VOICE_SYNC, 24, 1) == 0))
{
now = time(NULL);
state->carrier = 1;
@@ -547,7 +558,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
if (opts->inverted_dmr == 0)
{
// voice frame
- sprintf (state->ftype, " DMR ");
+ sprintf (state->ftype, "DMR");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +DMR ", synctest_pos + 1, modulation);
@@ -562,7 +573,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
else
{
// inverted data frame
- sprintf (state->ftype, " DMR ");
+ sprintf (state->ftype, "DMR");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -DMR ", synctest_pos + 1, modulation);
@@ -582,7 +593,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
- sprintf (state->ftype, " ProVoice ");
+ sprintf (state->ftype, "ProVoice");
if (opts->errorbars == 1)
//if (opts->errorbars == 1 && (time(NULL) - now) > 2 )
{
@@ -602,7 +613,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
- sprintf (state->ftype, " ProVoice ");
+ sprintf (state->ftype, "ProVoice");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -ProVoice ", synctest_pos + 1, modulation);
@@ -634,15 +645,17 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
if (state->samplesPerSymbol == 20)
{
- sprintf (state->ftype, " NXDN48 ");
+ //sprintf (state->ftype, " NXDN48 ");
+ sprintf (state->ftype, "NXDN48"); //get rid of spaces
if (opts->errorbars == 1)
{
- printFrameSync (opts, state, " +NXDN48 ", synctest_pos + 1, modulation);
+ //printFrameSync (opts, state, " +NXDN48 ", synctest_pos + 1, modulation);
+ printFrameSync (opts, state, " +NXDN48", synctest_pos + 1, modulation);
}
}
else
{
- sprintf (state->ftype, " NXDN96 ");
+ sprintf (state->ftype, "NXDN96");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +NXDN96 ", synctest_pos + 1, modulation);
@@ -675,15 +688,17 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->min = ((state->min) + lmin) / 2;
if (state->samplesPerSymbol == 20)
{
- sprintf (state->ftype, " NXDN48 ");
+ //sprintf (state->ftype, " NXDN48 ");
+ sprintf (state->ftype, "NXDN48");
if (opts->errorbars == 1)
{
- printFrameSync (opts, state, " -NXDN48 ", synctest_pos + 1, modulation);
+ //printFrameSync (opts, state, " -NXDN48 ", synctest_pos + 1, modulation);
+ printFrameSync (opts, state, " -NXDN48", synctest_pos + 1, modulation);
}
}
else
{
- sprintf (state->ftype, " NXDN96 ");
+ sprintf (state->ftype, "NXDN96");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -NXDN96 ", synctest_pos + 1, modulation);
@@ -714,15 +729,17 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->min = ((state->min) + lmin) / 2;
if (state->samplesPerSymbol == 20)
{
- sprintf (state->ftype, " NXDN48 ");
+ //sprintf (state->ftype, " NXDN48 ");
+ sprintf (state->ftype, "NXDN48");
if (opts->errorbars == 1)
{
- printFrameSync (opts, state, " +NXDN48 ", synctest_pos + 1, modulation);
+ //printFrameSync (opts, state, " +NXDN48 ", synctest_pos + 1, modulation);
+ printFrameSync (opts, state, " +NXDN48", synctest_pos + 1, modulation);
}
}
else
{
- sprintf (state->ftype, " NXDN96 ");
+ sprintf (state->ftype, "NXDN96");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +NXDN96 ", synctest_pos + 1, modulation);
@@ -751,10 +768,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
- sprintf (state->ftype, " NXDN ");
+ //sprintf (state->ftype, " NXDN ");
+ sprintf (state->ftype, "NXDN");
if (state->samplesPerSymbol == 20)
{
- sprintf (state->ftype, " NXDN48 ");
+ sprintf (state->ftype, "NXDN48");
+ //sprintf (state->ftype, "NXDN48");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -NXDN48 ", synctest_pos + 1, modulation);
@@ -762,7 +781,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
}
else
{
- sprintf (state->ftype, " NXDN96 ");
+ sprintf (state->ftype, "NXDN96");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -NXDN96 ", synctest_pos + 1, modulation);
@@ -792,7 +811,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
- sprintf (state->ftype, " D-STAR ");
+ sprintf (state->ftype, "D-STAR");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +D-STAR ", synctest_pos + 1, modulation);
@@ -811,7 +830,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
- sprintf (state->ftype, " D-STAR ");
+ sprintf (state->ftype, "D-STAR");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -D-STAR ", synctest_pos + 1, modulation);
@@ -830,7 +849,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
- sprintf (state->ftype, " D-STAR_HD ");
+ sprintf (state->ftype, "D-STAR_HD");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +D-STAR_HD ", synctest_pos + 1, modulation);
@@ -849,7 +868,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
- sprintf (state->ftype, " D-STAR_HD ");
+ sprintf (state->ftype, "D-STAR_HD");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -D-STAR_HD ", synctest_pos + 1, modulation);
@@ -927,7 +946,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
- sprintf (state->ftype, "(X2-TDMA) ");
+ sprintf (state->ftype, "(X2-TDMA)");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, "(+X2-TDMA) ", synctest_pos + 1, modulation);
@@ -945,7 +964,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
- sprintf (state->ftype, "(DMR) ");
+ sprintf (state->ftype, "(DMR)");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, "(-DMR) ", synctest_pos + 1, modulation);
@@ -1006,6 +1025,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
fprintf (stderr,"Press CTRL + C to close.\n"); //Kindly remind user to double tap CTRL + C
}
noCarrier (opts, state);
+ /*
+ if (opts->reset_state == 1)
+ {
+ resetState (state);
+ }
+ */
return (-1);
}
}
diff --git a/src/dsd_main.c b/src/dsd_main.c
index cfd5941..8f74c25 100644
--- a/src/dsd_main.c
+++ b/src/dsd_main.c
@@ -293,6 +293,8 @@ initState (dsd_state * state)
state->debug_header_errors = 0;
state->debug_header_critical_errors = 0;
+ state->nxdn_last_ran = 0;
+
#ifdef TRACE_DSD
state->debug_sample_index = 0;
state->debug_label_file = NULL;
@@ -332,7 +334,7 @@ usage ()
fprintf (stderr," -d
Create mbe data files, use this directory\n");
fprintf (stderr," -r Read/Play saved mbe data from file(s)\n");
fprintf (stderr," -g Audio output gain (default = 0 = auto, disable = -1)\n");
- fprintf (stderr," -n Do not send synthesized speech to audio output device\n");
+ //fprintf (stderr," -n Do not send synthesized speech to audio output device\n");
fprintf (stderr," -w Output synthesized speech to a .wav file\n");
fprintf (stderr," -a Display port audio devices\n");
fprintf (stderr," -W Monitor Source Audio When No Sync Detected (WIP!)\n");
@@ -379,6 +381,9 @@ usage ()
fprintf (stderr," (default=36)\n");
fprintf (stderr," -M Min/Max buffer size for QPSK decision point tracking\n");
fprintf (stderr," (default=15)\n");
+ fprintf (stderr," -n Reset P25 Heuristics and initState variables on mixed decoding signal\n");
+ fprintf (stderr," Helps when decoding multiple signal types at same time\n");
+ fprintf (stderr," (WiP! May Cause Slow Memory Leak - Experimental)\n");
fprintf (stderr,"\n");
fprintf (stderr,"Report bugs to: https://github.com/lwvmobile/dsd-fme/issues \n");
exit (0);
@@ -555,6 +560,8 @@ sigfun (int sig)
{
exitflag = 1;
signal (SIGINT, SIG_DFL);
+ ncursesClose ();
+
#ifdef USE_RTLSDR
rtlsdr_sighandler();
#endif
@@ -711,6 +718,7 @@ main (int argc, char **argv)
case 'N':
opts.use_ncurses_terminal = 1;
fprintf (stderr,"Enabling NCurses Terminal.\n");
+ fprintf (stderr," - may need to issue 'reset' command in terminal after use\n");
break;
case 'z':
@@ -760,8 +768,12 @@ main (int argc, char **argv)
}
break;
case 'n':
- opts.audio_out = 0;
- fprintf (stderr,"Disabling audio output to soundcard.\n");
+ //opts.audio_out = 0;
+ //fprintf (stderr,"Disabling audio output to soundcard.\n");
+ opts.reset_state = 1;
+ fprintf (stderr,"Enabling Automatic Reset of P25 states\n");
+ fprintf (stderr," -Helps with multiple signal type decoding\n");
+ fprintf (stderr," -(WiP! May cause slow memory leak)\n");
break;
case 'w':
strncpy(opts.wav_out_file, optarg, 1023);
@@ -787,7 +799,7 @@ main (int argc, char **argv)
opts.frame_x2tdma = 1;
opts.frame_p25p1 = 1;
opts.frame_nxdn48 = 0; //turn it on, doesn't work due to symbol rate difference
- opts.frame_nxdn96 = 0; //causes false positives, leave on 0
+ opts.frame_nxdn96 = 0; //causes false positives, leave on 0
opts.frame_dmr = 1;
opts.frame_provoice = 0; //turn it on, doesn't work due to symbol rate difference
}
@@ -877,7 +889,6 @@ main (int argc, char **argv)
opts.mod_qpsk = 0;
opts.mod_gfsk = 0; //was 1
state.rf_mod = 0; //was 2
- //fprintf (stderr,"Enabling only GFSK modulation optimizations.\n");
fprintf (stderr,"Enabling only C4FM modulation optimizations.\n");
fprintf (stderr,"Decoding only NXDN 9600 baud frames.\n");
}
@@ -890,6 +901,9 @@ main (int argc, char **argv)
opts.frame_nxdn96 = 0;
opts.frame_dmr = 1;
opts.frame_provoice = 0;
+ opts.mod_c4fm = 1; //just a test
+ opts.mod_qpsk = 0;
+ opts.mod_gfsk = 0; //was 1
fprintf (stderr,"Decoding only DMR/MOTOTRBO frames.\n");
}
break;
@@ -1083,6 +1097,7 @@ main (int argc, char **argv)
else
{
liveScanner (&opts, &state);
+
}
if (opts.use_ncurses_terminal == 1){
ncursesClose ();
diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c
index 7fbd669..01f2d96 100644
--- a/src/dsd_mbe.c
+++ b/src/dsd_mbe.c
@@ -17,6 +17,8 @@
#include "dsd.h"
+static void DecipherData(char * Input, char * KeyStream, char * Output, int NbData);
+
void
playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
{
@@ -73,12 +75,14 @@ playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
void
processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24])
{
-
+ //comment out line below should return print back to normal
+ //strncpy (state->err_buf, state->err_str, sizeof(state->err_str)); //right at the very top before err_str gets returned?
int i;
char imbe_d[88];
char ambe_d[49];
-#ifdef AMBE_PACKET_OUT
char ambe_d_str[50];
+#ifdef AMBE_PACKET_OUT
+
#endif
for (i = 0; i < 88; i++)
@@ -117,6 +121,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
{
mbe_processAmbe3600x2450Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
#ifdef AMBE_PACKET_OUT
+
for(i=0; i<49; i++) {
ambe_d_str[i] = ambe_d[i] + '0';
}
@@ -124,7 +129,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
// print binary string
fprintf (stderr, "\n?\t?\t%s\t", ambe_d_str);
// print error data
- fprintf (stderr, "E1: %d; E2: %d; S: %s", state->errs, state->errs2, state->err_str);
+ fprintf (stderr, "E1: %d; E2: %d; S: %s", state->errs, state->errs2, state->err_str);}
#endif
if (opts->mbe_out_f != NULL)
{
@@ -134,8 +139,10 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
if (opts->errorbars == 1)
{
- fprintf (stderr, "%s", state->err_str);
- //printw("%s", state->err_str);
+ //state->err_buf = state->err_str; //make comy to compare, and only print when comparison differs?? THIS HERE HERE
+ //strncpy (state->err_buf, state->err_str, sizeof(state->err_str)); //is this the correct placement for this? want it just before err_str is set?
+ fprintf (stderr, "%s", state->err_str); //this the actual error 'bar' ==== printer, find way to keep this entire string from printing constantly unless err_str changes
+ //fprintf (stderr, "%s", state->err_buf);
}
state->debug_audio_errors += state->errs2;
@@ -151,3 +158,128 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
playSynthesizedVoice (opts, state);
}
}
+
+void processMbeFrameEncrypted (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24], char ambe_keystream[49], char imbe_keystream[88])
+{
+
+ int i;
+ char imbe_d[88];
+ char ambe_d[49];
+#ifdef AMBE_PACKET_OUT
+ char ambe_d_str[50];
+#endif
+
+ for (i = 0; i < 88; i++)
+ {
+ imbe_d[i] = 0;
+ }
+
+ if ((state->synctype == 0) || (state->synctype == 1))
+ {
+ // 0 +P25p1
+ // 1 -P25p1
+
+ mbe_processImbe7200x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
+
+ DecipherData(imbe_d, imbe_keystream, imbe_d, 88);
+
+ if (opts->mbe_out_f != NULL)
+ {
+ saveImbe4400Data (opts, state, imbe_d);
+ }
+ }
+ else if ((state->synctype == 14) || (state->synctype == 15))
+ {
+ mbe_processImbe7100x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe7100_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
+
+ DecipherData(imbe_d, imbe_keystream, imbe_d, 88);
+
+ if (opts->mbe_out_f != NULL)
+ {
+ saveImbe4400Data (opts, state, imbe_d);
+ }
+ }
+ else if ((state->synctype == 6) || (state->synctype == 7))
+ {
+ //mbe_processAmbe3600x2400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
+
+ state->errs = 0;
+ state->errs2 = 0;
+ state->errs = mbe_eccAmbe3600x2400C0 (ambe_fr);
+ mbe_demodulateAmbe3600x2400Data (ambe_fr);
+ state->errs2 = state->errs;
+ state->errs2 += mbe_eccAmbe3600x2400Data (ambe_fr, ambe_d);
+
+ memcpy(state->ambe_ciphered, ambe_d, sizeof(state->ambe_ciphered));
+ DecipherData(ambe_d, ambe_keystream, ambe_d, 49);
+ memcpy(state->ambe_deciphered, ambe_d, sizeof(state->ambe_deciphered));
+
+ mbe_processAmbe2400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
+
+ if (opts->mbe_out_f != NULL)
+ {
+ saveAmbe2450Data (opts, state, ambe_d);
+ }
+ }
+ else
+ {
+ //mbe_processAmbe3600x2450Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
+
+ state->errs = 0;
+ state->errs2 = 0;
+ state->errs = mbe_eccAmbe3600x2450C0 (ambe_fr);
+ mbe_demodulateAmbe3600x2450Data (ambe_fr);
+ state->errs2 = state->errs;
+ state->errs2 += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d);
+
+ memcpy(state->ambe_ciphered, ambe_d, sizeof(state->ambe_ciphered));
+ DecipherData(ambe_d, ambe_keystream, ambe_d, 49);
+ memcpy(state->ambe_deciphered, ambe_d, sizeof(state->ambe_deciphered));
+
+ mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
+
+#ifdef AMBE_PACKET_OUT
+ for(i=0; i<49; i++) {
+ ambe_d_str[i] = ambe_d[i] + '0';
+ }
+ ambe_d_str[49] = '\0';
+ // print binary string
+ fprintf(stderr, "\n?\t?\t%s\t", ambe_d_str);
+ // print error data
+ fprintf(stderr, "E1: %d; E2: %d; S: %s", state->errs, state->errs2, state->err_str);
+#endif
+ if (opts->mbe_out_f != NULL)
+ {
+ saveAmbe2450Data (opts, state, ambe_d);
+ }
+ }
+
+ if (opts->errorbars == 1)
+ {
+ fprintf(stderr, "%s", state->err_str);
+ }
+
+ state->debug_audio_errors += state->errs2;
+
+ processAudio (opts, state);
+ if (opts->wav_out_f != NULL)
+ {
+ writeSynthesizedVoice (opts, state);
+ }
+
+ if (opts->audio_out == 1)
+ {
+ playSynthesizedVoice (opts, state);
+ }
+}
+
+/* This function decipher/decrypt data */
+static void DecipherData(char * Input, char * KeyStream, char * Output, int NbData)
+{
+ int i;
+
+ for(i = 0; i < NbData; i++)
+ {
+ Output[i] = Input[i] ^ KeyStream[i];
+ }
+}
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
index deb3e66..037e9dc 100644
--- a/src/dsd_ncurses.c
+++ b/src/dsd_ncurses.c
@@ -27,7 +27,21 @@
#include "dsd.h"
#include "git_ver.h"
+
+int reset = 0;
+char c; //getch key
+int tg; //last tg
+int rd; //last rid
+int rn; //last ran
+int nc; //nac
+int src; //last rid? double?
+int lls = -1; //last last sync type
+int dcc = 0; //initialize with 0 to prevent core dump
+int i = 0;
+char * s0last = " ";
+char * s1last = " ";
char versionstr[25];
+unsigned long long int call_matrix[33][6]; //0 - sync type; 1 - tg/ran; 2 - rid; 3 - slot; 4 - cc; 5 - time(NULL) ;
char * FM_bannerN[9] = {
" CTRL + C twice to exit",
" ██████╗ ██████╗██████╗ ███████╗███╗ ███╗███████╗",
@@ -39,6 +53,7 @@ char * FM_bannerN[9] = {
"https://github.com/lwvmobile/dsd-fme/tree/pulseaudio "
};
+/*
char * SyncTypes[20] = {
"P25P1_SYNC",
"INV_P25P1_SYNC",
@@ -48,19 +63,43 @@ char * SyncTypes[20] = {
"INV_X2TDMA_BS/MS_VOICE_SYNC",
"DSTAR_SYNC",
"INV_DSTAR_SYNC",
- "NXDN_BS_VOICE_SYNC", //8
- "INV_NXDN_BS_VOICE_SYNC", //9
- "DMR_BS/MS_DATA_SYNC",
- "INV_DMR_BS/MS_DATA_SYNC",
- "DMR_BS/MS_VOICE_SYNC",
- "INV_DMR_BS/MS_VOICE_SYNC",
- "PROVOICE_SYNC", //14
- "INV_PROVOICE_SYNC", //15
- "NXDN_BS_DATA_SYNC", //16
- "INV_NXDN_BS_DATA_SYNC", //17
+ "NXDN_BS_VOICE_SYNC", //8
+ "INV_NXDN_BS_VOICE_SYNC", //9
+ "DMR_BS/MS_DATA_SYNC", //10
+ "DMR_MS/BS_VOICE_SYNC", //11
+ "DMR_MS/BS_DATA_SYNC", //12
+ "INV_DMR_BS/MS_VOICE_SYNC", //13
+ "PROVOICE_SYNC", //14
+ "INV_PROVOICE_SYNC", //15
+ "NXDN_BS_DATA_SYNC", //16
+ "INV_NXDN_BS_DATA_SYNC", //17
"DSTAR_HD",
"INV_DSTAR_HD"
+};
+*/
+char * SyncTypes[20] = {
+ "+P25P1",
+ "-P25P1",
+ "+X2TDMA DATA",
+ "-X2TDMA DATA",
+ "+X2TDMA VOICE",
+ "-X2TDMA VOICE",
+ "+DSTARC",
+ "-DSTAR",
+ "+NXDN VOICE", //8
+ "-NXDN VOICE", //9
+ "+DMR DATA", //10
+ "-DMR VOICE", //11
+ "+DMR DATA", //12
+ "-DMR VOICE", //13
+ "+PROVOICE", //14
+ "-PROVOICE", //15
+ "+NXDN DATA", //16
+ "-NXDN DATA", //17
+ "+DSTAR HD",
+ "-DSTAR HD"
+
};
time_t nowN;
@@ -82,7 +121,7 @@ char * getTimeN(void) //get pretty hh:mm:ss timestamp
void ncursesOpen ()
{
mbe_printVersion (versionstr);
- setlocale(LC_ALL, "");
+ //setlocale(LC_ALL, "");
initscr(); //Initialize NCURSES screen window
start_color();
init_pair(1, COLOR_YELLOW, COLOR_BLACK); //Yellow/Amber for frame sync/control channel, NV style
@@ -92,98 +131,354 @@ void ncursesOpen ()
init_pair(5, COLOR_MAGENTA, COLOR_BLACK); //Magenta for no frame sync/signal
noecho();
cbreak();
+ //fprintf (stderr, "Opening NCurses Terminal. \n");
+
}
void
ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
int level;
- level = (int) state->max / 164;
+
+ //level = (int) state->max / 164;
+ level = 0; //start each cycle with 0
erase();
//disabling until wide support can be built for LM, etc. $(ncursesw5-config --cflags --libs)
//printw ("%s \n", FM_bannerN[0]); //top line in white
- //attron(COLOR_PAIR(4));
- //for (short int i = 1; i < 7; i++) { //following lines in cyan
- //printw("%s \n", FM_bannerN[i]); }
- //attroff(COLOR_PAIR(4));
- printw ("%s \n", FM_bannerN[7]); //http link
- printw ("Digital Speech Decoder: Florida Man Edition\n");
- printw ("Github Build Version: %s \n", GIT_TAG);
- printw ("mbelib version %s\n", versionstr);
- printw ("Time: ");
- printw ("%s ", getTimeN());
- if (SyncTypes[state->lastsynctype] != NULL)
+ attron(COLOR_PAIR(4));
+ //for (short int i = 1; i < 7; i++) //following lines in cyan
+ //{
+ //printw("%s \n", FM_bannerN[i]);
+ //}
+ attroff(COLOR_PAIR(4));
+ printw ("--Build Info------------------------------------------------------------------\n");
+ //printw ("| %s \n", FM_bannerN[7]); //http link
+ printw ("| Digital Speech Decoder: Florida Man Edition\n");
+ printw ("| Github Build Version: %s \n", GIT_TAG);
+ printw ("| mbelib version %s\n", versionstr);
+ printw ("------------------------------------------------------------------------------\n");
+
+
+ if ( (lls == 14 || lls == 15) && (time(NULL) - call_matrix[9][5] > 5) ) //honestly have no idea how to do this for pV, just going time based?
{
- printw ("%s \n", SyncTypes[state->lastsynctype]);
- //printw("%s ", state->ftype); //moved to front, some ftype strings have spaces in front of them, and others dont
- /* Not sure if I'm going to use the error bars yet
- if (opts->errorbars == 1)
+ for (short int k = 0; k < 9; k++)
{
- printw("-"); //AFAIK, errorbars==1 is the internal value for if a system has inverted signal types, not at all misleading
- }
- else
- {
- printw("+");
- }
- */
- if (1 == 1){ //figure out method that will tell me when is active and when not active, maybe carrier but this doesn't print anyways unless activity
- attron(COLOR_PAIR(3));
- }
- printw ("%s %s\n", state->ftype, state->fsubtype); //some ftype strings have extra spaces in them
- if (state->lasttg < 0) //triggers compiler warning: comparison between pointer and integer
- {
- //sprintf(state->ftype, )
- //state->lasttg = state->ftype; //warning: assignment to ‘int’ from ‘char *
- state->lasttg = 0;
- }
- printw ("TG [%7i] RID [%12i] \n", state->lasttg, state->lastsrc); //variables to fill with info from other system types too
- //printw ("TG [%s] \n", state->lasttg);
- //printw ("TDMA activity: %s %s \n", state->slot0light, state->slot1light);
- printw("In Level: [%2i%%] ", level);
- printw ("Voice Error [%s] \n", state->err_str); //no idea if this shows anything outside of TDMA or P1 or what
- if (1 == 1){ //same as above
- attroff(COLOR_PAIR(3));
+ call_matrix[k][0] = call_matrix[k+1][0];
+ call_matrix[k][1] = call_matrix[k+1][1];
+ call_matrix[k][2] = call_matrix[k+1][2];
+ call_matrix[k][3] = call_matrix[k+1][3];
+ call_matrix[k][4] = call_matrix[k+1][4];
+ call_matrix[k][5] = call_matrix[k+1][5];
}
+
+ call_matrix[9][0] = lls;
+ call_matrix[9][1] = 1;
+ call_matrix[9][2] = 1;
+ call_matrix[9][3] = 1;
+ call_matrix[9][4] = 1;
+ call_matrix[9][5] = time(NULL);
+ //nowN = time(NULL);
}
- /*
- if (state->lastsynctype == 8 ||state->lastsynctype == 9 ||state->lastsynctype == 16 ||state->lastsynctype == 17)
+ //if ( (state->nxdn_last_rid != src && src > 0) || (state->nxdn_last_ran != rn && rn > 0) ) //find condition to make this work well, probably if last != local last variables
+ //if ( (call_matrix[9][2] != src && src > 0) || (call_matrix[9][1] != rn && rn > 0) ) //NXDN working well now with this, updates immediately and only once
+ if ( call_matrix[9][2] != src && src > 0 && rn > 0 ) //NXDN working well now with this, updates immediately and only once
{
- if (state->samplesPerSymbol == 20)
+ for (short int k = 0; k < 9; k++)
+ {
+ call_matrix[k][0] = call_matrix[k+1][0];
+ call_matrix[k][1] = call_matrix[k+1][1];
+ call_matrix[k][2] = call_matrix[k+1][2];
+ call_matrix[k][3] = call_matrix[k+1][3];
+ call_matrix[k][4] = call_matrix[k+1][4];
+ call_matrix[k][5] = call_matrix[k+1][5];
+ }
+ call_matrix[9][0] = lls;
+ call_matrix[9][1] = rn;
+ call_matrix[9][2] = src;
+ call_matrix[9][3] = 0;
+ call_matrix[9][4] = 0;
+ call_matrix[9][5] = time(NULL);
+
+ }
+
+ //if (state->dmr_color_code != dcc && (lls == 11 || lls == 13 || lls == 10 || lls == 12) ) //DMR Voice + last two is data
+ if ( (call_matrix[9][4] != dcc || call_matrix[9][2] != rd) && (lls == 11 || lls == 13 || lls == 10 || lls == 12) ) //DMR Voice + last two is data
+ {
+ //dcc = state->dmr_color_code;
+ for (short int k = 0; k < 9; k++)
+ {
+ call_matrix[k][0] = call_matrix[k+1][0];
+ call_matrix[k][1] = call_matrix[k+1][1];
+ call_matrix[k][2] = call_matrix[k+1][2];
+ call_matrix[k][3] = call_matrix[k+1][3];
+ call_matrix[k][4] = call_matrix[k+1][4];
+ call_matrix[k][5] = call_matrix[k+1][5];
+ }
+
+ call_matrix[9][0] = lls;
+ call_matrix[9][1] = tg;
+ call_matrix[9][2] = rd;
+ call_matrix[9][3] = 0;
+ call_matrix[9][4] = dcc;
+ call_matrix[9][5] = time(NULL);
+ //i++;
+ }
+
+ //if ( (lls == 0 || lls == 1) && state->lastsrc != rd && state->lastsrc > 0) //find condition to make this work well, probably if last != local last variables
+ if ( (lls == 0 || lls == 1) && call_matrix[9][2] != rd && nc > 0 && tg > 0) //P25
+ {
+ for (short int k = 0; k < 9; k++)
+ {
+ call_matrix[k][0] = call_matrix[k+1][0];
+ call_matrix[k][1] = call_matrix[k+1][1];
+ call_matrix[k][2] = call_matrix[k+1][2];
+ call_matrix[k][3] = call_matrix[k+1][3];
+ call_matrix[k][4] = call_matrix[k+1][4];
+ call_matrix[k][5] = call_matrix[k+1][5];
+ }
+
+ call_matrix[9][0] = lls;
+ call_matrix[9][1] = tg;
+ call_matrix[9][2] = rd;
+ call_matrix[9][3] = 0;
+ call_matrix[9][4] = nc;
+ call_matrix[9][5] = time(NULL);
+ //i++;
+ }
+ //printw ("Time: ");
+ //printw ("%s \n", getTimeN());
+ attron(COLOR_PAIR(4));
+ printw ("--Input Output----------------------------------------------------------------\n");
+ if (opts->audio_in_type == 0)
+ {
+ printw ("| Pulse Audio Input [%i] kHz [%i] Channel\n", opts->pulse_digi_rate_in/1000, opts->pulse_digi_in_channels);
+ }
+ if (opts->audio_in_type == 1)
+ {
+ printw ("| STDIN - Input\n");
+ }
+ if (opts->audio_in_type == 3)
+ {
+ printw ("| RTL2838 Device #[%d]", opts->rtl_dev_index);
+ printw (" Gain [%i] dB -", opts->rtl_gain_value);
+ printw (" Squelch [%i]", opts->rtl_squelch_level);
+ printw (" VFO [%i] kHz\n", opts->rtl_bandwidth);
+ printw ("| Freq: [%lld] Hz", opts->rtlsdr_center_freq);
+ printw (" - Tuning available on UDP Port [%i]\n", opts->rtl_udp_port);
+ }
+ if (opts->audio_out_type == 0)
+ {
+ printw ("| Pulse Audio Output [%i] kHz [%i] Channel\n", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels);
+ }
+ if (opts->mbe_out_dir[0] != 0)
+ {
+ printw ("| Writing MBE data files to directory %s\n", opts->mbe_out_dir);
+ }
+ if (opts->wav_out_file[0] != 0)
+ {
+ printw ("| Writing Audio WAV to file %s\n", opts->wav_out_file);
+ }
+
+ printw ("------------------------------------------------------------------------------\n");
+ attroff(COLOR_PAIR(4));
+
+ if (state->carrier == 1){ //figure out method that will tell me when is active and when not active, maybe carrier but this doesn't print anyways unless activity
+ attron(COLOR_PAIR(3));
+ level = (int) state->max / 164; //only update on carrier present
+ reset = 1;
+ }
+ if (state->carrier == 0 && opts->reset_state == 1 && reset == 1)
+ {
+ resetState (state);
+ reset = 0;
+ }
+
+
+ printw ("--Audio Decode----------------------------------------------------------------\n");
+ printw ("| In Level: [%3i%%] \n", level);
+ printw ("| Voice Error: [%i][%i] \n| Error Bars: [%s] \n", state->errs, state->errs2, state->err_str); //
+ //printw ("| Carrier = %i\n", state->carrier);
+ printw ("------------------------------------------------------------------------------\n");
+
+
+ printw ("--Call Info-------------------------------------------------------------------\n");
+ if (state->lastsynctype != -1) //not sure if this will be okay
+ {
+ lls = state->lastsynctype;
+ }
+ if (state->nxdn_last_rid > 0 && state->nxdn_last_rid != src);
+ {
+ src = state->nxdn_last_rid;
+ //rn = state->nxdn_last_ran;
+ }
+ if (state->nxdn_last_ran > 0 && state->nxdn_last_rid != rn);
+ {
+ //src = state->nxdn_last_rid;
+ rn = state->nxdn_last_ran;
+ }
+ //if (state->lastsynctype == 8 || state->lastsynctype == 9 || state->lastsynctype == 16 || state->lastsynctype == 17) //change this to NXDN syncs later on
+ if (lls == 8 || lls == 9 || lls == 16 || lls == 17)
+ {
+ //printw ("| RAN: [%02d] \n", state->nxdn_last_ran);
+ printw ("| RAN: [%02d] \n", rn);
+ printw ("| RID: [%d] \n", src); //maybe change to nxdn_last_rid
+ }
+
+ //printw ("Error?: [%i] [%i] \n", state->errs, state->errs2); //what are these?
+
+ if (state->lasttg > 0 && state->lastsrc > 0)
+ {
+ tg = state->lasttg;
+ rd = state->lastsrc;
+ }
+ if (state->nac > 0)
+ {
+ nc = state->nac;
+ }
+ if ((lls == 0 || lls == 1)) //1 for P25 P1 Audio
+ {
+ printw("| TID:[%i] \n| RID:[%i] \n", tg, rd);
+ printw("| NAC: [0x%X] \n", nc);
+ }
+ //if (state->lastsynctype == 12 || state->lastsynctype == 13) //DMR Voice Types
+ if (lls == 11 || lls == 13) //DMR Voice Types
+ {
+ printw ("| DCC: [%i]\n", state->dmr_color_code);
+ //printw ("%s ", state->slot0light);
+ printw ("| SLOT 0 ");
+ if (state->currentslot == 0) //find out how to tell when slot0 has voice
+ {
+ s0last = "Voice";
+ //printw("Voice");
+ }
+ printw ("%s ", s0last);
+
+ //printw ("%s ", state->slot1light);
+ printw ("SLOT 1 ");
+ if (state->currentslot == 1) //find out how to tell when slot1 has voice
+ {
+ s1last = "Voice";
+ //printw("Voice");
+ }
+ printw ("%s \n", s1last);
+ }
+
+ if (state->dmr_color_code > 0 && (lls == 11 || lls == 13 || lls == 10 || lls == 12) ) //DMR Voice + last two is data
+ {
+ dcc = state->dmr_color_code;
+ }
+ //if (state->lastsynctype == 10 || state->lastsynctype == 11) //DMR Data Types
+ if (lls == 10 || lls == 11) //DMR Data Types
+ {
+ printw ("| DCC: [%i]\n", dcc);
+ //printw ("%s ", state->slot0light);
+ printw ("| SLOT 0 ");
+ if (state->currentslot == 0) //find out how to tell when slot0 has voice
+ {
+ s0last = "Data ";
+ if (strcmp (state->fsubtype, " Slot idle ") == 0)
{
- //sprintf (state->ftype, " NXDN48 ");
- if (opts->errorbars == 1)
- {
- //printFrameSync (opts, state, " -NXDN48 ", synctest_pos + 1, modulation);
- printw("NXDN48 ");
- printw("%s \n", SyncTypes[state->lastsynctype]);
- printw("%s ", state->ftype);
- }
+ s0last = "Idle ";
}
- else
+ }
+ printw ("%s ", s0last);
+ //printw ("%s ", state->slot1light);
+ printw ("SLOT 1 ");
+ if (state->currentslot == 1) //find out how to tell when slot1 has voice
+ {
+ s1last = "Data ";
+ if (strcmp (state->fsubtype, " Slot idle ") == 0)
{
- //sprintf (state->ftype, " NXDN96 ");
- if (opts->errorbars == 1)
- {
- //printFrameSync (opts, state, " -NXDN96 ", synctest_pos + 1, modulation);
- printw("NXDN96 ");
- printw("%s ", SyncTypes[state->lastsynctype]);
- printw("%s ", state->ftype);
- }
+ s1last = "Idle ";
}
+ }
+ printw ("%s \n", s1last);
+ }
+ if (lls != -1) //is there a synctype 0?
+ {
+ printw ("| %s \n", SyncTypes[lls]);
+ }
+ printw ("------------------------------------------------------------------------------\n");
+ //colors off
+ if (state->carrier == 1){ //same as above
+ attroff(COLOR_PAIR(3));
+ }
+ //if (state->carrier == 0){ //same as above
+ //attroff(COLOR_PAIR(1));
+ //}
+
+ attron(COLOR_PAIR(4)); //cyan for history
+ //add other interesting info to put here
+ //make Call_Matrix
+ //0 - sync type; 1 - tg/ran; 2 - rid; 3 - slot; 4 - cc; 5 - time(NULL) ;
+
+ printw ("--Call History----------------------------------------------------------------\n");
+ for (short int j = 0; j < 10; j++)
+ {
+ if ( ((time(NULL) - call_matrix[9-j][5]) < 9999) )
+ //if (1 == 1)
+ {
+ printw ("| #%d %s ", j, SyncTypes[call_matrix[9-j][0]]);
+ if (lls == 8 || lls == 9 || lls == 16 || lls == 17)
+ {
+ printw ("RAN [%2d] ", call_matrix[9-j][1]);
+ }
+ if (lls == 0 || lls == 1 || lls == 11 || lls == 13) //P25 P1 and DMR Voice
+ {
+ printw ("TID [%2d] ", call_matrix[9-j][1]);
+ }
+
+ printw ("RID [%4d] ", call_matrix[9-j][2]);
+ //printw ("S %d - ", call_matrix[j][3]);
+ if (call_matrix[9-j][0] == 0 || call_matrix[9-j][0] == 1) //P25P1 Voice
+ {
+ printw ("NAC [0x%X] ", call_matrix[9-j][4]);
+ }
+ if (call_matrix[9-j][0] == 12 || call_matrix[9-j][0] == 13 || call_matrix[9-j][0] == 10 || call_matrix[9-j][0] == 11 ) //DMR Voice Types
+ {
+ printw ("DCC [%d] ", call_matrix[9-j][4]);
+ }
+ printw ("%d secs ago\n", time(NULL) - call_matrix[9-j][5]);
+ }
+ //printw("\n");
+ }
+ printw ("------------------------------------------------------------------------------\n");
+ attroff(COLOR_PAIR(4)); //cyan for history
+ //put sync type at very bottom
+ //printw ("%s %s\n", state->ftype, state->fsubtype); //some ftype strings have extra spaces in them
+ //if (state->lastsynctype != -1) //is there a synctype 0?
+
+ //while((c = getch()) != '~') {
+ // printw ("%c\n",c);}
+ //c = getch();
+ /*
+ if (c = getch() != '~')
+ {
+ printf ("%c\n",c);
+ printf ("closing NCurses");
+ ncursesClose();
}
*/
+ //debug sr printw
+ if (1==2) //disable this later on
+ {
- printw("\n"); //line return
- //add other interesting info to put here
+ printw ("sr_0 = %16llX \n", state->sr_0);
+ printw ("sr_1 = %16llX \n", state->sr_1);
+ printw ("sr_2 = %16llX \n", state->sr_2);
+ printw ("sr_3 = %16llX \n", state->sr_3);
+ printw ("sr_4 = %16llX \n", state->sr_4);
+ printw ("sr_5 = %16llX \n", state->sr_5);
+ printw ("sr_6 = %16llX \n", state->sr_6);
+ }
refresh();
-
}
void ncursesClose ()
{
- erase();
- refresh();
+ //erase();
+ //refresh();
endwin();
}
diff --git a/src/dsd_reset.c b/src/dsd_reset.c
new file mode 100644
index 0000000..e8aa893
--- /dev/null
+++ b/src/dsd_reset.c
@@ -0,0 +1,107 @@
+
+#include "dsd.h"
+#include "p25p1_heuristics.h"
+
+void
+resetState (dsd_state * state)
+{
+
+ int i, j;
+
+ state->dibit_buf = malloc (sizeof (int) * 1000000);
+ state->dibit_buf_p = state->dibit_buf + 200;
+ memset (state->dibit_buf, 0, sizeof (int) * 200);
+ state->repeat = 0; //not sure yet
+ //state->audio_out_buf = malloc (sizeof (short) * 1000000);
+ //memset (state->audio_out_buf, 0, 100 * sizeof (short));
+ //state->audio_out_buf_p = state->audio_out_buf + 100;
+ //state->audio_out_float_buf = malloc (sizeof (float) * 1000000);
+ //memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
+ //state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
+ //state->audio_out_idx = 0;
+ //state->audio_out_idx2 = 0;
+ //state->audio_out_temp_buf_p = state->audio_out_temp_buf;
+ //state->wav_out_bytes = 0;
+ state->center = 0;
+ state->jitter = -1;
+ state->synctype = -1;
+ state->min = -15000;
+ state->max = 15000;
+ state->lmid = 0;
+ state->umid = 0;
+ state->minref = -12000;
+ state->maxref = 12000;
+ state->lastsample = 0;
+ for (i = 0; i < 128; i++)
+ {
+ state->sbuf[i] = 0;
+ }
+ state->sidx = 0;
+ for (i = 0; i < 1024; i++)
+ {
+ state->maxbuf[i] = 15000;
+ }
+ for (i = 0; i < 1024; i++)
+ {
+ state->minbuf[i] = -15000;
+ }
+ state->midx = 0;
+ state->err_str[0] = 0;
+ sprintf (state->fsubtype, " ");
+ sprintf (state->ftype, " ");
+ state->symbolcnt = 0;
+ state->rf_mod = 0;
+ state->numflips = 0;
+ state->lastsynctype = -1;
+ state->lastp25type = 0;
+ state->offset = 0;
+ state->carrier = 0;
+ for (i = 0; i < 25; i++)
+ {
+ for (j = 0; j < 16; j++)
+ {
+ state->tg[i][j] = 48;
+ }
+ }
+ state->tgcount = 0;
+ state->lasttg = 0;
+ state->lastsrc = 0;
+ state->nac = 0;
+ state->errs = 0;
+ state->errs2 = 0;
+ state->mbe_file_type = -1;
+ state->optind = 0;
+ state->numtdulc = 0;
+ state->firstframe = 0;
+ sprintf (state->slot0light, " slot0 ");
+ sprintf (state->slot1light, " slot1 ");
+ state->aout_gain = 25;
+ memset (state->aout_max_buf, 0, sizeof (float) * 200);
+ state->aout_max_buf_p = state->aout_max_buf;
+ state->aout_max_buf_idx = 0;
+ state->samplesPerSymbol = 10;
+ state->symbolCenter = 4;
+ sprintf (state->algid, "________");
+ sprintf (state->keyid, "________________");
+ state->currentslot = 0;
+ state->cur_mp = malloc (sizeof (mbe_parms));
+ state->prev_mp = malloc (sizeof (mbe_parms));
+ state->prev_mp_enhanced = malloc (sizeof (mbe_parms));
+ mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
+ state->p25kid = 0;
+
+ state->debug_audio_errors = 0;
+ state->debug_header_errors = 0;
+ state->debug_header_critical_errors = 0;
+
+ state->nxdn_last_ran = 0;
+
+//#ifdef TRACE_DSD
+// state->debug_sample_index = 0;
+// state->debug_label_file = NULL;
+// state->debug_label_dibit_file = NULL;
+// state->debug_label_imbe_file = NULL;
+//#endif
+
+ initialize_p25_heuristics(&state->p25_heuristics); //see if we want to re-init this or not, currently seems to cause memory leak when running over and over, mitigated with a reset flag
+}
diff --git a/src/dsd_symbol.c b/src/dsd_symbol.c
index a9a474e..131cf2f 100644
--- a/src/dsd_symbol.c
+++ b/src/dsd_symbol.c
@@ -27,7 +27,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
sum = 0;
count = 0;
- for (i = 0; i < state->samplesPerSymbol; i++) //right HERE, this is how many samples it will grab, depending on samplesPerSymbol and also rf_mod messing with it too
+ for (i = 0; i < state->samplesPerSymbol; i++) //right HERE
{
// timing control
diff --git a/src/nxdn_data.c b/src/nxdn_data.c
index 7eb3cbe..ad535f7 100644
--- a/src/nxdn_data.c
+++ b/src/nxdn_data.c
@@ -1,36 +1,105 @@
#include "dsd.h"
+#include "nxdn_const.h"
-void
-processNXDNData (dsd_opts * opts, dsd_state * state)
+//don't know why this doesn't work right in LEH, need to figure that out for him
+//works just fien when ripped from his and into mine
+//must be some random thing, I'll look at his when I have a chance
+void processNXDNData (dsd_opts * opts, dsd_state * state)
{
- int i, dibit;
+ int i, dibit = 0;
+ unsigned char sacch_raw[72] = {0};
+ unsigned char sacch_decoded[32] = {0}; /* 26 bit + 6 bit CRC */
+ unsigned char *pr;
+ uint8_t CrcIsGood = 0;
+ uint8_t StructureField = 0;
+ uint8_t RAN = 0;
+ uint8_t PartOfFrame = 0;
+
+ /* Remove compiler warning */
+ //UNUSED_VARIABLE(dibit);
if (opts->errorbars == 1)
- {
- fprintf (stderr, "DATA ");
- }
+ {
+ fprintf(stderr, "DATA - ");
+ }
+ /* Start pseudo-random NXDN sequence after
+ * LITCH = 16 bit = 8 dibit
+ * ==> Index 8 */
+ pr = (unsigned char *)(&nxdnpr2[8]);
for (i = 0; i < 30; i++)
- {
- dibit = getDibit (opts, state);
+ {
+ dibit = getDibit (opts, state);
+
+ /* Store and de-interleave directly SACCH bits */
+ sacch_raw[(2*i)] = ((*pr) & 1) ^ (1 & (dibit >> 1)); // bit 1
+ sacch_raw[(2*i)+1] = (1 & dibit); // bit 0
+ pr++;
#ifdef NXDN_DUMP
- fprintf (stderr, "%c", dibit + 48);
+ fprintf(stderr, "%c", dibit + 48);
#endif
- }
+ }
#ifdef NXDN_DUMP
- fprintf (stderr, " ");
+ fprintf(stderr, " ");
#endif
+
+ /* Decode the SACCH fields */
+ CrcIsGood = NXDN_SACCH_raw_part_decode(sacch_raw, sacch_decoded);
+ StructureField = (sacch_decoded[0]<<1 | sacch_decoded[1]<<0) & 0x03; /* Compute the Structure Field (remove 2 first bits of the SR Information in the SACCH) */
+ RAN = (sacch_decoded[2]<<5 | sacch_decoded[3]<<4 | sacch_decoded[4]<<3 | sacch_decoded[5]<<2 | sacch_decoded[6]<<1 | sacch_decoded[7]<<0) & 0x3F; /* Compute the RAN (6 last bits of the SR Information in the SACCH) */
+
+ /* Compute the Part of Frame according to the structure field */
+ if (StructureField == 3) PartOfFrame = 0;
+ else if(StructureField == 2) PartOfFrame = 1;
+ else if(StructureField == 1) PartOfFrame = 2;
+ else if(StructureField == 0) PartOfFrame = 3;
+ else PartOfFrame = 0; /* Normally we should never go here */
+
+ /* Fill the SACCH structure */
+ state->NxdnSacchRawPart[PartOfFrame].CrcIsGood = CrcIsGood;
+ state->NxdnSacchRawPart[PartOfFrame].StructureField = StructureField;
+ state->NxdnSacchRawPart[PartOfFrame].RAN = RAN;
+
+ memcpy(state->NxdnSacchRawPart[PartOfFrame].Data, &sacch_decoded[8], 18); /* Copy the 18 bits of SACCH content */
+
+ //fprintf(stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1);
+ if(CrcIsGood)
+ {
+ fprintf (stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1);
+ fprintf (stderr, " (OK) - ");
+ state->nxdn_last_ran = RAN; //disable, try to grab this in voice instead
+ }
+
+ else fprintf (stderr, "(CRC ERR) - ");
+
+
+ /* Decode the SACCH only when all 4 voice frame
+ * SACCH spare parts have been received */
+ if(PartOfFrame == 3)
+ {
+ /* Decode the entire SACCH content */
+ NXDN_SACCH_Full_decode(opts, state);
+ }
+
for (i = 0; i < 144; i++)
- {
- dibit = getDibit (opts, state);
+ {
+ dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
- fprintf (stderr, "%c", dibit + 48);
+ fprintf(stderr, "%c", dibit + 48);
#endif
- }
+ }
if (opts->errorbars == 1)
- {
- fprintf (stderr, "\n");
- }
-}
+ {
+ fprintf(stderr, "\n");
+ }
+
+ /* Reset the SACCH CRCs when all 4 voice frame
+ * SACCH spare parts have been received */
+ if(PartOfFrame == 3)
+ {
+ /* Reset all CRCs of the SACCH */
+ for(i = 0; i < 4; i++) state->NxdnSacchRawPart[i].CrcIsGood = 0;
+ }
+} /* End processNXDNData() */
diff --git a/src/nxdn_lib.c b/src/nxdn_lib.c
new file mode 100644
index 0000000..d96e1fd
--- /dev/null
+++ b/src/nxdn_lib.c
@@ -0,0 +1,1084 @@
+/*
+ ============================================================================
+ Name : nxdn_lib
+ Author :
+ Version : 1.0
+ Date : 2018 December 26
+ Copyright : No copyright
+ Description : NXDN decoding source lib
+ ============================================================================
+ */
+
+
+/* Include ------------------------------------------------------------------*/
+#include "dsd.h"
+#include "nxdn_const.h"
+
+
+/* Global variables ---------------------------------------------------------*/
+
+
+/* Functions ----------------------------------------------------------------*/
+
+
+/*
+ * @brief : This function decodes the LICH
+ *
+ * @param InputLich : A 8 ASCII bytes buffer
+ *
+ * @param RFChannelType : Output of RF Channel Type
+ * parameter
+ *
+ * @param FunctionnalChannelType : Output of Functional
+ * Channel Type parameter
+ *
+ * @param Option : Output of Option parameter
+ *
+ * @param : CompleteLichBinaryFormat : The constitued LICH (7 bits)
+ *
+ * @param Direction : Output of Direction parameter
+ *
+ * @param Inverted : 1 = Inverted frame ; 0 = Normal frame
+ *
+ * @return 1 when LICH parity is good
+ * 0 when LICH parity is bad
+ *
+ */
+ //borrowed from LEH my_lib.c file
+ uint32_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength)
+ {
+ uint32_t Output = 0;
+ uint32_t i;
+
+ for(i = 0; i < BitLength; i++)
+ {
+ Output <<= 1;
+ Output |= (uint32_t)(BufferIn[i] & 1);
+ }
+
+ return Output;
+ } /* End ConvertBitIntoBytes() */
+
+
+uint8_t NXDN_decode_LICH(uint8_t InputLich[8],
+ uint8_t * RFChannelType,
+ uint8_t * FunctionnalChannelType,
+ uint8_t * Option,
+ uint8_t * Direction,
+ uint8_t * CompleteLichBinaryFormat,
+ uint8_t Inverted)
+{
+ uint8_t GoodParity = 0;
+ uint32_t i;
+ uint8_t LichDibits[8] = {0};
+ uint8_t LichBits[8] = {0};
+ uint8_t EvenParityComputed = 0;
+ uint8_t *pr;
+ uint8_t dibit;
+ uint8_t InvertionDibitValue;
+ uint8_t CompleteLich = 0;
+
+ if(Inverted) InvertionDibitValue = 0x02;
+ else InvertionDibitValue = 0x00;
+
+ pr = (uint8_t *)(&nxdnpr[0]);
+
+ /* Recreate a 8 bits field
+ * 7 bits of LICH + 1 parity bit */
+ for(i = 0; i < 8; i++)
+ {
+ /* Get the dibit value (convert ASCII to bin value) */
+ dibit = ((InputLich[i] - '0') & 0x03) ^ InvertionDibitValue;
+
+ /* Descramble the dibit */
+ LichDibits[i] = dibit ^ ((*pr & 0x01) << 1);
+
+ /* Increment pseudo-random pointer */
+ pr++;
+
+ /* Decode LICH dibit */
+ switch(LichDibits[i])
+ {
+ case 0:
+ {
+ LichBits[i] = 0;
+ break;
+ }
+ case 1:
+ {
+ LichBits[i] = 0;
+ break;
+ }
+ case 2:
+ {
+ LichBits[i] = 1;
+ break;
+ }
+ default:
+ {
+ LichBits[i] = 1;
+ break;
+ }
+ } /* End switch(LichDibits[i]) */
+
+ /* Parity should be even */
+ EvenParityComputed += LichBits[i];
+
+ } /* End for(i = 0; i < 8; i++) */
+
+ /* Even parity = Good */
+ if((EvenParityComputed % 2) == 0)
+ {
+ GoodParity = 1;
+ }
+ else
+ {
+ /* Odd parity = Wrong */
+ }
+
+ *RFChannelType = ((LichBits[0] & 0x01) << 1) | (LichBits[1] & 0x01);
+ *FunctionnalChannelType = ((LichBits[2] & 0x01) << 1) | (LichBits[3] & 0x01);
+ *Option = ((LichBits[4] & 0x01) << 1) | (LichBits[5] & 0x01);
+ *Direction = LichBits[6] & 0x01;
+
+ CompleteLich = 0;
+ for(i = 0; i < 7; i++)
+ {
+ CompleteLich = ((CompleteLich << 1) | LichBits[i]) & 0x7F;
+ }
+ *CompleteLichBinaryFormat = CompleteLich;
+
+ return GoodParity;
+} /* End NXDN_decode_LICH() */
+
+
+/*
+ * @brief : This function decodes the RAW part of SACCH received when
+ * each voice frame starts.
+ * This is NOT the full SACCH but only 18 bits on 72.
+ *
+ * @param Input : A 60 bit (60 bytes) buffer pointer of input data
+ *
+ * @param Output : A 32 bit (26 bytes data + 6 bytes CRC) buffer where write output data
+ *
+ * @return 1 when CRC is good
+ * 0 when CRC is bad
+ *
+ */
+uint8_t NXDN_SACCH_raw_part_decode(uint8_t * Input, uint8_t * Output)
+{
+ uint32_t i;
+ uint8_t sacchRaw[60]; /* SACCH bits retrieved from RF channel */
+ uint8_t sacch[72] = {0};
+ uint8_t s0;
+ uint8_t s1;
+ uint8_t m_data[5] = {0}; /* SACCH bytes after de-convolution (36 bits) */
+ uint8_t CRCComputed = 0;
+ uint8_t CRCExtracted = 0;
+ uint32_t index = 0;
+ uint32_t punctureIndex = 0;
+ uint8_t temp[90] = {0}; /* SACCH working area */
+ //uint8_t RAN = 0;
+ //uint8_t StructureField = 0;
+ uint8_t GoodCrc = 0;
+
+ //UNUSED_VARIABLE(sacch[0]);
+
+ /* De-interleave */
+ for(i = 0; i < 60; i++)
+ {
+ sacchRaw[DSDNXDN_SACCH_m_Interleave[i]] = Input[i];
+ }
+
+ /* Un-Punture */
+ for (index = 0, punctureIndex = 0, i = 0; i < 60; i++)
+ {
+ if (index == (uint32_t)DSDNXDN_SACCH_m_PunctureList[punctureIndex])
+ {
+ temp[index++] = 1;
+ punctureIndex++;
+ }
+
+ temp[index++] = sacchRaw[i]<<1; // 0->0, 1->2
+ }
+
+ for (i = 0; i < 8; i++)
+ {
+ temp[index++] = 0;
+ }
+
+ /* Convolutional decoding */
+ CNXDNConvolution_start();
+ for (i = 0U; i < 40U; i++)
+ {
+ s0 = temp[(2*i)];
+ s1 = temp[(2*i)+1];
+
+ CNXDNConvolution_decode(s0, s1);
+ }
+
+ CNXDNConvolution_chainback(m_data, 36U);
+
+
+ for(i = 0; i < 4; i++)
+ {
+ Output[(i*8)+0] = (m_data[i] >> 7) & 1;
+ Output[(i*8)+1] = (m_data[i] >> 6) & 1;
+ Output[(i*8)+2] = (m_data[i] >> 5) & 1;
+ Output[(i*8)+3] = (m_data[i] >> 4) & 1;
+ Output[(i*8)+4] = (m_data[i] >> 3) & 1;
+ Output[(i*8)+5] = (m_data[i] >> 2) & 1;
+ Output[(i*8)+6] = (m_data[i] >> 1) & 1;
+ Output[(i*8)+7] = (m_data[i] >> 0) & 1;
+ }
+
+ /* Extract the 6 bit CRC */
+ CRCExtracted = m_data[3] & 0x3F;
+
+ /* Compute the 6 bit CRC */
+ CRCComputed = CRC6BitNXDN(Output, 26);
+
+ /* Compute the RAN (6 last bits of the SR Information in the SACCH) */
+ //RAN = m_data[0] & 0x3F;
+
+ /* Compute the Structure Field (remove 2 first bits of the SR Information in the SACCH) */
+ //StructureField = (m_data[0] >> 6) & 0x03;
+
+ //fprintf(stderr, "RAN=%u ; StructureField=%u ; ", RAN, StructureField);
+
+ //fprintf(stderr, "SACCH=0x%02X-0x%02X-0x%02X-0x%02X-0x%02X ; ",
+ // m_data[0], m_data[1], m_data[2], m_data[3], m_data[4]);
+
+ //fprintf(stderr, "CRC Extracted=0x%02X ; CRC computed=0x%02X ; ", CRCExtracted, CRCComputed);
+
+ /* Check CRCs */
+ if(CRCExtracted == CRCComputed)
+ {
+ //fprintf(stderr, "OK !\n");
+ GoodCrc = 1;
+ }
+ else
+ {
+ //fprintf(stderr, "ERROR !\n");
+ GoodCrc = 0;
+ }
+
+ return GoodCrc;
+} /* NXDN_SACCH_raw_part_decode() */
+
+
+/*
+ * @brief : This function decodes the full SACCH (when 4 voice frame parts
+ * have been successfully received)
+ *
+ * @param opts : Option structure parameters pointer
+ *
+ * @param state : State structure parameters pointer
+ *
+ * @return None
+ *
+ */
+void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state)
+{
+ uint8_t SACCH[72];
+ uint32_t i;
+ uint8_t CrcCorrect = 1;
+
+ /* Consider all SACCH CRC parts as corrects */
+ CrcCorrect = 1;
+
+ /* Reconstitute the full 72 bits SACCH */
+ for(i = 0; i < 4; i++)
+ {
+ memcpy(&SACCH[i * 18], state->NxdnSacchRawPart[i].Data, 18);
+
+ /* Check CRC */
+ if(state->NxdnSacchRawPart[i].CrcIsGood == 0) CrcCorrect = 0;
+ }
+
+ /* Decodes the element content */
+ NXDN_Elements_Content_decode(opts, state, CrcCorrect, SACCH);
+
+} /* End NXDN_SACCH_Full_decode() */
+
+
+/*
+ * @brief : This function decodes the RAW part of FACCH1 received when
+ * each voice frame starts.
+ *
+ * @param Input : A 144 bits (144 bytes) buffer pointer of input data
+ *
+ * @param Output : A 96 bits (80 bytes data + 12 bytes CRC + 4 bytes "Tail" all "0") buffer where write output data
+ *
+ * @return 1 when CRC is good
+ * 0 when CRC is bad
+ *
+ */
+uint8_t NXDN_FACCH1_decode(uint8_t * Input, uint8_t * Output)
+{
+ uint32_t i;
+ uint8_t GoodCrc = 0;
+ uint16_t CRCComputed = 0;
+ uint16_t CRCExtracted = 0;
+ uint8_t facch1Raw[144]; /* FACCH1 bits retrieved from RF channel */
+ uint8_t s0;
+ uint8_t s1;
+ uint8_t m_data[12] = {0}; /* FACCH1 bytes after de-convolution (96 bits) */
+ uint32_t index = 0;
+ uint32_t punctureIndex = 0;
+ uint8_t temp[210] = {0}; /* FACCH1 working area */
+
+ /* De-interleave */
+ for(i = 0; i < 144; i++)
+ {
+ facch1Raw[DSDNXDN_FACCH1_m_Interleave[i]] = Input[i];
+ }
+
+ /* Un-Punture */
+ for (index = 0, punctureIndex = 0, i = 0; i < 144; i++)
+ {
+ if (index == (uint32_t)DSDNXDN_FACCH1_m_PunctureList[punctureIndex])
+ {
+ temp[index++] = 1;
+ punctureIndex++;
+ }
+
+ temp[index++] = facch1Raw[i]<<1; // 0->0, 1->2
+ }
+
+ for (i = 0; i < 8; i++)
+ {
+ temp[index++] = 0;
+ }
+
+ /* Convolutional decoding */
+ CNXDNConvolution_start();
+ for (i = 0U; i < 100U; i++)
+ {
+ s0 = temp[(2*i)];
+ s1 = temp[(2*i)+1];
+
+ CNXDNConvolution_decode(s0, s1);
+ }
+ /*
+ fprintf (stderr, "\n");
+ for (i = 0U; i < 100U; i++)
+ {
+ fprintf (stderr, "temp=%X", temp[i]);
+ }
+ fprintf (stderr, "\n");
+ */
+ CNXDNConvolution_chainback(m_data, 96U);
+
+ /* Reconstitute L3 Data (Data 80 bits + CRC 12 bits + 4 tail bits = Total 96 bits = 12 bytes) */
+ for(i = 0; i < 12; i++)
+ {
+ Output[(i*8)+0] = (m_data[i] >> 7) & 1;
+ Output[(i*8)+1] = (m_data[i] >> 6) & 1;
+ Output[(i*8)+2] = (m_data[i] >> 5) & 1;
+ Output[(i*8)+3] = (m_data[i] >> 4) & 1;
+ Output[(i*8)+4] = (m_data[i] >> 3) & 1;
+ Output[(i*8)+5] = (m_data[i] >> 2) & 1;
+ Output[(i*8)+6] = (m_data[i] >> 1) & 1;
+ Output[(i*8)+7] = (m_data[i] >> 0) & 1;
+ }
+
+ /* Extract the 12 bits CRC */
+ CRCExtracted = ((uint16_t)(m_data[10] << 4) | (uint16_t)(m_data[11] >> 4)) & 0x0FFF;
+
+ /* Compute the 12 bits CRC */
+ CRCComputed = CRC12BitNXDN(Output, 80);
+
+ //fprintf(stderr, "\n");
+
+ //fprintf(stderr, "SACCH1 Data = ");
+ //for(i = 0; i < 12; i++)
+ //{
+ // fprintf(stderr, "0x%02X - ", m_data[i]);
+ //}
+ //fprintf(stderr, "\n");
+
+ //fprintf(stderr, "CRC computed = 0x%03X - CRC extracted = 0x%03X\n", CRCComputed, CRCExtracted);
+
+ /* Check CRCs */
+ if(CRCExtracted == CRCComputed)
+ {
+ //fprintf(stderr, "OK !\n");
+ GoodCrc = 1;
+ }
+ else
+ {
+ //fprintf(stderr, "ERROR !\n");
+ GoodCrc = 0;
+ }
+
+ return GoodCrc;
+} /* End NXDN_FACCH1_decode() */
+
+
+
+/*
+ * @brief : This function decodes the UDCH/FACCH2 received.
+ *
+ * @param Input : A 348 bits (348 bytes) buffer pointer of input data
+ *
+ * @param Output : A 203 bits (184 bytes data + 15 bytes CRC + 4 bytes "Tail" all "0") buffer where write output data
+ *
+ * @return 1 when CRC is good
+ * 0 when CRC is bad
+ *
+ */
+uint8_t NXDN_UDCH_decode(uint8_t * Input, uint8_t * Output)
+{
+ uint32_t i;
+ uint8_t GoodCrc = 0;
+ uint16_t CRCComputed = 0;
+ uint16_t CRCExtracted = 0;
+ uint8_t UdchRaw[348]; /* UDCH bits retrieved from RF channel */
+ uint8_t s0;
+ uint8_t s1;
+ uint8_t m_data[26] = {0}; /* UDCH bytes after de-convolution (203 bits) */
+ uint32_t index = 0;
+ uint32_t punctureIndex = 0;
+ uint8_t temp[420] = {0}; /* UDCH working area */
+
+ /* De-interleave */
+ for(i = 0; i < 348; i++)
+ {
+ UdchRaw[DSDNXDN_UDCH_m_Interleave[i]] = Input[i];
+ }
+
+ /* Un-Punture */
+ for (index = 0, punctureIndex = 0, i = 0; i < 348; i++)
+ {
+ if (index == (uint32_t)DSDNXDN_UDCH_m_PunctureList[punctureIndex])
+ {
+ temp[index++] = 1;
+ punctureIndex++;
+ }
+
+ temp[index++] = UdchRaw[i]<<1; // 0->0, 1->2
+ }
+
+ for (i = 0; i < 8; i++)
+ {
+ temp[index++] = 0;
+ }
+
+ /* Convolutional decoding */
+ CNXDNConvolution_start();
+ for (i = 0U; i < 207U; i++)
+ {
+ s0 = temp[(2*i)];
+ s1 = temp[(2*i)+1];
+
+ CNXDNConvolution_decode(s0, s1);
+ }
+
+ CNXDNConvolution_chainback(m_data, 203U);
+
+ /* Reconstitute L3 Data (Data 184 bits + CRC 15 bits + 4 tail bits = Total 203 bits = 26 bytes) */
+ for(i = 0; i < 25; i++)
+ {
+ Output[(i*8)+0] = (m_data[i] >> 7) & 1;
+ Output[(i*8)+1] = (m_data[i] >> 6) & 1;
+ Output[(i*8)+2] = (m_data[i] >> 5) & 1;
+ Output[(i*8)+3] = (m_data[i] >> 4) & 1;
+ Output[(i*8)+4] = (m_data[i] >> 3) & 1;
+ Output[(i*8)+5] = (m_data[i] >> 2) & 1;
+ Output[(i*8)+6] = (m_data[i] >> 1) & 1;
+ Output[(i*8)+7] = (m_data[i] >> 0) & 1;
+ }
+ /* Get the 3 last bits */
+ Output[200] = (m_data[25] >> 7) & 1;
+ Output[201] = (m_data[25] >> 6) & 1;
+ Output[202] = (m_data[25] >> 5) & 1;
+
+ /* Extract the 15 bits CRC */
+ CRCExtracted = ((uint16_t)(m_data[23] << 7) | (uint16_t)(m_data[24] >> 1)) & 0x7FFF;
+
+ /* Compute the 15 bits CRC */
+ CRCComputed = CRC15BitNXDN(Output, 184);
+
+ //fprintf(stderr, "\n");
+
+ //fprintf(stderr, "FACCH2 Data = ");
+ //for(i = 0; i < 26; i++)
+ //{
+ // fprintf(stderr, "0x%02X - ", m_data[i]);
+ //}
+ //fprintf(stderr, "\n");
+
+ //fprintf(stderr, "CRC computed = 0x%04X - CRC extracted = 0x%04X\n", CRCComputed, CRCExtracted);
+
+ /* Check CRCs */
+ if(CRCExtracted == CRCComputed)
+ {
+ //fprintf(stderr, "OK !\n");
+ GoodCrc = 1;
+ }
+ else
+ {
+ //fprintf(stderr, "ERROR !\n");
+ GoodCrc = 0;
+ }
+
+ return GoodCrc;
+} /* End NXDN_UDCH_decode() */
+
+
+
+/*
+ * @brief : This function decodes the content of elements in :
+ * - Full SACCH (when 4 voice frame parts have been
+ * successfully received)
+ *
+ * @param opts : Option structure parameters pointer
+ *
+ * @param state : State structure parameters pointer
+ *
+ * @param CrcCorrect : The CRC status of the last element received
+ * 0 = CRC incorrect
+ * Oher = CRC correct
+ *
+ * @param ElementsContent : A 64 to 144 bits buffer containing the
+ * element content
+ *
+ * @return None
+ *
+ */
+void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
+ uint8_t CrcCorrect, uint8_t * ElementsContent)
+{
+ uint32_t i;
+ uint8_t MessageType;
+ uint64_t CurrentIV = 0;
+
+ /* Get the "Message Type" field */
+ MessageType = (ElementsContent[2] & 1) << 5;
+ MessageType |= (ElementsContent[3] & 1) << 4;
+ MessageType |= (ElementsContent[4] & 1) << 3;
+ MessageType |= (ElementsContent[5] & 1) << 2;
+ MessageType |= (ElementsContent[6] & 1) << 1;
+ MessageType |= (ElementsContent[7] & 1) << 0;
+
+ /* Save the "F1" and "F2" flags */
+ state->NxdnElementsContent.F1 = ElementsContent[0];
+ state->NxdnElementsContent.F2 = ElementsContent[1];
+
+ /* Save the "Message Type" field */
+ state->NxdnElementsContent.MessageType = MessageType;
+
+ //fprintf(stderr, "Message Type = 0x%02X ", MessageType & 0xFF);
+
+ /* Decode the right "Message Type" */
+ switch(MessageType)
+ {
+ /* VCALL */
+ case NXDN_VCALL:
+ {
+ /* Set the CRC state */
+ state->NxdnElementsContent.VCallCrcIsGood = CrcCorrect;
+
+ /* Decode the "VCALL" message */
+ NXDN_decode_VCALL(opts, state, ElementsContent);
+
+ /* Check the "Cipher Type" and the "Key ID" validity */
+ if(CrcCorrect)
+ {
+ state->NxdnElementsContent.CipherParameterValidity = 1;
+ }
+ else state->NxdnElementsContent.CipherParameterValidity = 0;
+ break;
+ } /* End case NXDN_VCALL: */
+
+ /* VCALL_IV */
+ case NXDN_VCALL_IV:
+ {
+ /* Set the CRC state */
+ state->NxdnElementsContent.VCallIvCrcIsGood = CrcCorrect;
+
+ /* Decode the "VCALL_IV" message */
+ NXDN_decode_VCALL_IV(opts, state, ElementsContent);
+
+ if(CrcCorrect)
+ {
+ /* CRC is correct, copy the next theorical IV to use directly from the
+ * received VCALL_IV */
+ memcpy(state->NxdnElementsContent.NextIVComputed, state->NxdnElementsContent.IV, 8);
+ }
+ else
+ {
+ /* CRC is incorrect, compute the next IV to use */
+ CurrentIV = 0;
+
+ /* Convert the 8 bytes buffer into a 64 bits integer */
+ for(i = 0; i < 8; i++)
+ {
+ CurrentIV |= state->NxdnElementsContent.NextIVComputed[i];
+ CurrentIV = CurrentIV << 8;
+ }
+
+ /* Encryption is not supported in the public version,
+ * so do not compute the next IV */
+ }
+ break;
+ } /* End case NXDN_VCALL_IV: */
+
+ /* Unknown Message Type */
+ default:
+ {
+ fprintf(stderr, "Unknown Message type ");
+ break;
+ }
+ } /* End switch(MessageType) */
+
+} /* End NXDN_Elements_Content_decode() */
+
+
+/*
+ * @brief : This function decodes the VCALL message
+ *
+ * @param opts : Option structure parameters pointer
+ *
+ * @param state : State structure parameters pointer
+ *
+ * @param Message : A 64 bit buffer containing the VCALL message to decode
+ *
+ * @return None
+ *
+ */
+void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message)
+{
+ //uint32_t i;
+ uint8_t CCOption = 0;
+ uint8_t CallType = 0;
+ uint8_t VoiceCallOption = 0;
+ uint16_t SourceUnitID = 0;
+ uint16_t DestinationID = 0;
+ uint8_t CipherType = 0;
+ uint8_t KeyID = 0;
+ uint8_t DuplexMode[32] = {0};
+ uint8_t TransmissionMode[32] = {0};
+
+ //UNUSED_VARIABLE(opts);
+ //UNUSED_VARIABLE(state);
+ //UNUSED_VARIABLE(DuplexMode[0]);
+ //UNUSED_VARIABLE(TransmissionMode[0]);
+
+ /* Message[0..7] contains :
+ * - The "F1" and "F2" flags
+ * - The "Message Type" (already decoded before calling this function)
+ *
+ * So no need to decode it a second time
+ */
+
+ /* Decode "CC Option" */
+ CCOption = (uint8_t)ConvertBitIntoBytes(&Message[8], 8);
+ state->NxdnElementsContent.CCOption = CCOption;
+
+ /* Decode "Call Type" */
+ CallType = (uint8_t)ConvertBitIntoBytes(&Message[16], 3);
+ state->NxdnElementsContent.CallType = CallType;
+
+ /* Decode "Voice Call Option" */
+ VoiceCallOption = (uint8_t)ConvertBitIntoBytes(&Message[19], 5);
+ state->NxdnElementsContent.VoiceCallOption = VoiceCallOption;
+
+ /* Decode "Source Unit ID" */
+ SourceUnitID = (uint16_t)ConvertBitIntoBytes(&Message[24], 16);
+ state->NxdnElementsContent.SourceUnitID = SourceUnitID;
+
+ /* Decode "Destination ID" */
+ DestinationID = (uint16_t)ConvertBitIntoBytes(&Message[40], 16);
+ state->NxdnElementsContent.DestinationID = DestinationID;
+
+ /* Decode the "Cipher Type" */
+ CipherType = (uint8_t)ConvertBitIntoBytes(&Message[56], 2);
+ state->NxdnElementsContent.CipherType = CipherType;
+
+ /* Decode the "Key ID" */
+ KeyID = (uint8_t)ConvertBitIntoBytes(&Message[58], 6);
+ state->NxdnElementsContent.KeyID = KeyID;
+
+ /* Print the "CC Option" */
+ if(CCOption & 0x80) fprintf(stderr, "Emergency ");
+ if(CCOption & 0x40) fprintf(stderr, "Visitor ");
+ if(CCOption & 0x20) fprintf(stderr, "Priority Paging ");
+
+ /* On an AES or DES encrypted frame one IV is used on two
+ * superframe.
+ * The first superframe contains a VCALL message inside
+ * the SACCH and the second superframe contains the next IV
+ * to use.
+ *
+ * Set the correct part of encrypted frame flag.
+ */
+ if((CipherType == 2) || (CipherType == 3))
+ {
+ state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 1;
+ state->NxdnElementsContent.PartOfNextEncryptedFrame = 2;
+ }
+ else
+ {
+ state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 1;
+ state->NxdnElementsContent.PartOfNextEncryptedFrame = 1;
+ }
+
+ /* Print the "Call Type" */
+ fprintf(stderr, "%s - ", NXDN_Call_Type_To_Str(CallType));
+
+ /* Print the "Voice Call Option" */
+ NXDN_Voice_Call_Option_To_Str(VoiceCallOption, DuplexMode, TransmissionMode);
+ fprintf(stderr, "%s %s - ", DuplexMode, TransmissionMode);
+
+ /* Print the "Cipher Type" */
+ if(CipherType != 0) fprintf(stderr, "%s - ", NXDN_Cipher_Type_To_Str(CipherType));
+
+ /* Print the Key ID */
+ if(CipherType != 0) fprintf(stderr, "Key ID %u - ", KeyID & 0xFF);
+
+ /* Print Source ID and Destination ID (Talk Group or Unit ID) */
+ fprintf(stderr, "Src=%u - Dst/TG=%u ", SourceUnitID & 0xFFFF, DestinationID & 0xFFFF);
+
+ if(state->NxdnElementsContent.VCallCrcIsGood)
+ {
+ if ( (SourceUnitID & 0xFFFF) > 0 )
+ {
+ state->nxdn_last_rid = SourceUnitID & 0xFFFF; //only grab if CRC is okay
+ }
+ fprintf(stderr, " (OK) - ");
+ }
+ //fprintf(stderr, " (OK) - ");
+ else fprintf(stderr, "(CRC ERR) - ");
+
+ //fprintf(stderr, "\nVCALL = ");
+
+ //for(i = 0; i < 8; i++)
+ //{
+ // fprintf(stderr, "0x%02X, ", ConvertBitIntoBytes(&Message[i * 8], 8) & 0xFF);
+ //}
+ //fprintf(stderr, "\n");
+
+} /* End NXDN_decode_VCALL() */
+
+
+/*
+ * @brief : This function decodes the VCALL_IV message
+ *
+ * @param opts : Option structure parameters pointer
+ *
+ * @param state : State structure parameters pointer
+ *
+ * @param Message : A 72 bit buffer containing the VCALL_IV message to decode
+ *
+ * @return None
+ *
+ */
+void NXDN_decode_VCALL_IV(dsd_opts * opts, dsd_state * state, uint8_t * Message)
+{
+ uint32_t i;
+
+ //UNUSED_VARIABLE(opts);
+ //UNUSED_VARIABLE(state);
+
+ /* Message[0..7] contains :
+ * - The "F1" and "F2" flags
+ * - The "Message Type" (already decoded before calling this function)
+ *
+ * So no need to decode it a second time
+ *
+ * Message[8..71] contains : The 64 bits IV
+ */
+
+ /* Extract the IV from the VCALL_IV message */
+ for(i = 0; i < 8; i++)
+ {
+ state->NxdnElementsContent.IV[i] = (uint8_t)ConvertBitIntoBytes(&Message[(i + 1) * 8], 8);
+ }
+
+ /* On an AES or DES encrypted frame one IV is used on two
+ * superframe.
+ * The first superframe contains a VCALL message inside
+ * the SACCH and the second superframe contains the next IV
+ * to use.
+ *
+ * Set the correct part of encrypted frame flag.
+ */
+ state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 2;
+ state->NxdnElementsContent.PartOfNextEncryptedFrame = 1;
+
+} /* End NXDN_decode_VCALL_IV() */
+
+
+/*
+ * @brief : This function decodes the "Call Type" and return the
+ * ASCII string corresponding to it.
+ *
+ * @param CallType : The call type parameter to decode
+ *
+ * @return An ASCII string of the "Call Type"
+ *
+ */
+char * NXDN_Call_Type_To_Str(uint8_t CallType)
+{
+ char * Ptr = NULL;
+
+ switch(CallType)
+ {
+ case 0: Ptr = "Broadcast Call"; break;
+ case 1: Ptr = "Group Call"; break;
+ case 2: Ptr = "Unspecified Call"; break;
+ case 3: Ptr = "Reserved"; break;
+ case 4: Ptr = "Individual Call"; break;
+ case 5: Ptr = "Reserved"; break;
+ case 6: Ptr = "Interconnect Call"; break;
+ case 7: Ptr = "Speed Dial Call"; break;
+ default: Ptr = "Unknown Call Type"; break;
+ }
+
+ return Ptr;
+} /* End NXDN_Call_Type_To_Str() */
+
+
+/*
+ * @brief : This function decodes the "Voice Call Option" and return the
+ * ASCII string corresponding to it.
+ *
+ * @param VoiceCallOption : The call type parameter to decode
+ *
+ * @param Duplex : A 32 bytes ASCII buffer pointer where store
+ * the Duplex/Half duplex mode
+ *
+ * @param TransmissionMode : A 32 bytes ASCII buffer pointer where store
+ * the transmission mode (bit rate)
+ *
+ * @return An ASCII string of the "Voice Call Option"
+ *
+ */
+void NXDN_Voice_Call_Option_To_Str(uint8_t VoiceCallOption, uint8_t * Duplex, uint8_t * TransmissionMode)
+{
+ char * Ptr = NULL;
+
+ Duplex[0] = 0;
+ TransmissionMode[0] = 0;
+
+ if(VoiceCallOption & 0x10) strcpy((char *)Duplex, "Duplex");
+ else strcpy((char *)Duplex, "Half Duplex");
+
+ switch(VoiceCallOption & 0x17)
+ {
+ case 0: Ptr = "4800bps/EHR"; break;
+ case 2: Ptr = "9600bps/EHR"; break;
+ case 3: Ptr = "9600bps/EFR"; break;
+ default: Ptr = "Reserved Voice Call Option"; break;
+ }
+
+ strcpy((char *)TransmissionMode, Ptr);
+} /* End NXDN_Voice_Call_Option_To_Str() */
+
+
+/*
+ * @brief : This function decodes the "Cipher Type" and return the
+ * ASCII string corresponding to it.
+ *
+ * @param CipherType : The cipher type parameter to decode
+ *
+ * @return An ASCII string of the "Cipher Type"
+ *
+ */
+char * NXDN_Cipher_Type_To_Str(uint8_t CipherType)
+{
+ char * Ptr = NULL;
+
+ switch(CipherType)
+ {
+ case 0: Ptr = ""; break; /* Non-ciphered mode / clear call */
+ case 1: Ptr = "Scrambler"; break;
+ case 2: Ptr = "DES"; break;
+ case 3: Ptr = "AES"; break;
+ default: Ptr = "Unknown Cipher Type"; break;
+ }
+
+ return Ptr;
+} /* End NXDN_Cipher_Type_To_Str() */
+
+
+/* CRC 15 bits computation with the following polynomial :
+ * X^15 + X^14 + X^11 + X^10 + X^7 + X^6 + X^2 + 1
+ *
+ * X^15 + (1X^14 + 0X^13 + 0X^12 + 1X^11 + 1X^10 + 0X^9 + 0X^8 + 1X^7 + 1X^6 + 0X^5 + 0X^4 + 0X^3 + 1X^2 + 0X^1 + 1X^0)
+ * => Polynomial = 0b100110011000101 = 0x4CC5
+ */
+uint16_t CRC15BitNXDN(uint8_t * BufferIn, uint32_t BitLength)
+{
+ uint16_t CRC = 0x7FFF; /* Initial value = All bit to '1' (only 15 LSBit are used) */
+ uint16_t Polynome = 0x4CC5; /* X^15 + X^14 + X^11 + X^10 + X^7 + X^6 + X^2 + 1 */
+ uint32_t i;
+
+ for(i = 0; i < BitLength; i++)
+ {
+ if(((CRC >> 14) & 1) ^ (BufferIn[i] & 1))
+ {
+ CRC = ((CRC << 1) ^ Polynome) & 0x7FFF;
+ }
+ else
+ {
+ CRC = (CRC << 1) & 0x7FFF;
+ }
+ }
+
+ return CRC;
+} /* End CRC15BitNXDN() */
+
+
+/* CRC 12 bits computation with the following polynomial :
+ * X^12 + X^11 + X^3 + X^2 + X + 1
+ *
+ * X^12 + (1X^11 + 0X^10 + 0X^9 + 0X^8 + 0X^7 + 0X^6 + 0X^5 + 0X^4 + 1X^3 + 1X^2 + 1X^1 + 1X^0)
+ * => Polynomial = 0b100000001111 = 0x80F
+ */
+uint16_t CRC12BitNXDN(uint8_t * BufferIn, uint32_t BitLength)
+{
+ uint16_t CRC = 0x0FFF; /* Initial value = All bit to '1' (only 12 LSBit are used) */
+ uint16_t Polynome = 0x80F; /* X^12 + X^11 + X^3 + X^2 + X + 1 */
+ uint32_t i;
+
+ for(i = 0; i < BitLength; i++)
+ {
+ if(((CRC >> 11) & 1) ^ (BufferIn[i] & 1))
+ {
+ CRC = ((CRC << 1) ^ Polynome) & 0x0FFF;
+ }
+ else
+ {
+ CRC = (CRC << 1) & 0x0FFF;
+ }
+ }
+
+ return CRC;
+} /* End CRC12BitNXDN() */
+
+
+/* CRC 6 bit computation with the following
+ * polynomial : X^6 + X^5 + X^2 + X + 1
+ *
+ * X^6 + (1X^5 + 0X^4 + 0X^3 + 1X^2 + 1X^1 + 1X^0)
+ * => Polynomial = 0b100111 = 0x27
+ */
+uint8_t CRC6BitNXDN(uint8_t * BufferIn, uint32_t BitLength)
+{
+ uint8_t CRC = 0x3F; /* Initial value = All bit to '1' (only 6 LSBit are used) */
+ uint8_t Polynome = 0x27; /* X^6 + X^5 + X^2 + X + 1 */
+ uint32_t i;
+
+ for(i = 0; i < BitLength; i++)
+ {
+ if(((CRC >> 5) & 1) ^ (BufferIn[i] & 1))
+ {
+ CRC = ((CRC << 1) ^ Polynome) & 0x3F;
+ }
+ else
+ {
+ CRC = (CRC << 1) & 0x3F;
+ }
+ }
+
+ return CRC;
+} /* End CRC6BitNXDN() */
+
+
+/* Scrambler used for NXDN transmission (different of the
+ * voice encryption scrambler), see NXDN Part1-A Common Air Interface chapter
+ * 4.6 for the polynomial description.
+ * It is a X^9 + X^4 + 1 polynomial used as pseudo-random generator */
+void ScrambledNXDNVoiceBit(int * LfsrValue, char * BufferIn, char * BufferOut, int NbOfBitToScramble)
+{
+ uint32_t i;
+ uint32_t LFSR;
+ uint8_t bit;
+
+ /* Load the initial LFSR value
+ * LFSR = 0x0E4 at starting value */
+ LFSR = (uint32_t)*LfsrValue;
+
+ for(i = 0; i < (uint32_t)NbOfBitToScramble; i++)
+ {
+ /* Bit 0 of LFSR is used to scramble data */
+ BufferOut[i] = (BufferIn[i] ^ (LFSR & 1)) & 1;
+
+ /* Compute bit = X^0 + X^4 */
+ bit = ((LFSR & 1) ^ ((LFSR >> 4) & 1)) & 1;
+
+ /* Insert bit on the 9th bit (X^9) */
+ LFSR = ((LFSR >> 1) & 0xFF) | ((bit << 8) & 0x100);
+ }
+
+ *LfsrValue = (int)LFSR;
+} /* End ScrambledNXDNVoiceBit() */
+
+
+void NxdnEncryptionStreamGeneration (dsd_opts* opts, dsd_state* state, uint8_t KeyStream[1664])
+{
+ uint32_t i = 0, j = 0, k = 0;
+ uint32_t LFSR = 0;
+ uint64_t CurrentIV = 0;
+ uint64_t NextIV = 0;
+ uint64_t TempIV = 0;
+ uint8_t Temp = 0;
+
+ /* Remove compiler warning */
+ /*
+ UNUSED_VARIABLE(opts);
+ UNUSED_VARIABLE(state);
+ UNUSED_VARIABLE(i);
+ UNUSED_VARIABLE(j);
+ UNUSED_VARIABLE(k);
+ UNUSED_VARIABLE(LFSR);
+ UNUSED_VARIABLE(CurrentIV);
+ UNUSED_VARIABLE(NextIV);
+ UNUSED_VARIABLE(TempIV);
+ UNUSED_VARIABLE(Temp);
+ */
+ if((state->NxdnElementsContent.CipherParameterValidity))
+ {
+ //fprintf(stderr, "Scrambler Encryption ");
+
+ /* Scrambler encryption mode */
+ if(state->NxdnElementsContent.CipherType == 0x01)
+ {
+ /* Encryption not supported in the public version
+ * Set the keystream to 0 */
+ memset(KeyStream, 0, sizeof(uint8_t) * 1664);
+
+ } /* End if(state->NxdnElementsContent.CipherType == 0x01) - Scrambler */
+ /* DES Mode */
+ else if(state->NxdnElementsContent.CipherType == 0x02)
+ {
+ /* Encryption not supported in the public version
+ * Set the keystream to 0 */
+ memset(KeyStream, 0, sizeof(uint8_t) * 1664);
+ } /* End else if(state->NxdnElementsContent.CipherType == 0x02) - DES mode */
+ /* AES Mode */
+ else if(state->NxdnElementsContent.CipherType == 0x03)
+ {
+ /* Encryption not supported in the public version
+ * Set the keystream to 0 */
+ memset(KeyStream, 0, sizeof(uint8_t) * 1664);
+ } /* End else if(state->NxdnElementsContent.CipherType == 0x03) - AES mode */
+ else
+ {
+ /* No encryption required, simply set the keystream to "0" */
+ memset(KeyStream, 0, sizeof(uint8_t) * 1664);
+ }
+ }
+ else
+ {
+ /* No encryption required or error, simply set the keystream to "0" */
+ memset(KeyStream, 0, sizeof(uint8_t) * 1664);
+ }
+
+} /* End NxdnEncryptionStreamGeneration() */
+
+
+/* End of file */
diff --git a/src/nxdn_voice.c b/src/nxdn_voice.c
index 7ef59d2..8f7486d 100644
--- a/src/nxdn_voice.c
+++ b/src/nxdn_voice.c
@@ -1,59 +1,181 @@
#include "dsd.h"
#include "nxdn_const.h"
-void
-processNXDNVoice (dsd_opts * opts, dsd_state * state)
+//don't know why this doesn't work right in LEH, need to figure that out for him
+//works just fien when ripped from his and into mine
+//must be some random thing, I'll look at his when I have a chance
+void processNXDNVoice (dsd_opts * opts, dsd_state * state)
{
int i, j, dibit;
char ambe_fr[4][24];
+ unsigned char sacch_raw[72] = {0};
+ unsigned char sacch_decoded[32] = {0}; /* 26 bit + 6 bit CRC */
const int *w, *x, *y, *z;
- const char *pr;
+ unsigned char *pr;
+ uint8_t CrcIsGood = 0;
+ uint8_t StructureField = 0;
+ uint8_t RAN = 0;
+ uint8_t PartOfFrame = 0;
+ uint8_t KeyStream[1664] = {0};
+ char ambe7bytesArray[7] = {0};
+ int PartOfEncryptedSuperFrame = 0;
if (opts->errorbars == 1)
- {
- fprintf (stderr,"VOICE e:");
- }
+ {
+ fprintf(stderr, "VOICE - ");
+ }
+ /* Start pseudo-random NXDN sequence after
+ * LITCH = 16 bit = 8 dibit
+ * ==> Index 8 */
+ pr = (unsigned char *)(&nxdnpr2[8]);
for (i = 0; i < 30; i++)
+ {
+ dibit = getDibit (opts, state);
+
+ /* Store and de-interleave directly SACCH bits */
+ sacch_raw[(2*i)] = ((*pr) & 1) ^ (1 & (dibit >> 1)); // bit 1
+ sacch_raw[(2*i)+1] = (1 & dibit); // bit 0
+
+// TODO : Deinterleave is done in the "NXDN_SACCH_decode" function
+// /* Store and de-interleave directly SACCH bits */
+// sacch_raw[nsW[2*i]] = *pr ^ (1 & (dibit >> 1)); // bit 1
+// sacch_raw[nsW[2*i+1]] = (1 & dibit); // bit 0
+ pr++;
+#ifdef NXDN_DUMP
+ fprintf(stderr, "%c", dibit + 48);
+#endif
+ }
+#ifdef NXDN_DUMP
+ fprintf(stderr, " ");
+#endif
+
+// TODO : Unpuncture is done in the "NXDN_SACCH_decode" function
+// /* For the sake of simplicity, handle the re-insertion of punctured bits here.
+// * This makes the actual Viterbi decoder code a LOT simpler. */
+// for (i = 30; i < 36; i++)
+// {
+// sacch_raw[nsW[2*i]] = 0;
+// sacch_raw[nsW[2*i+1]] = 0;
+// }
+
+ /* Decode the SACCH fields */
+ CrcIsGood = NXDN_SACCH_raw_part_decode(sacch_raw, sacch_decoded);
+ StructureField = (sacch_decoded[0]<<1 | sacch_decoded[1]<<0) & 0x03; /* Compute the Structure Field (remove 2 first bits of the SR Information in the SACCH) */
+ RAN = (sacch_decoded[2]<<5 | sacch_decoded[3]<<4 | sacch_decoded[4]<<3 | sacch_decoded[5]<<2 | sacch_decoded[6]<<1 | sacch_decoded[7]<<0) & 0x3F; /* Compute the RAN (6 last bits of the SR Information in the SACCH) */
+
+ /* Compute the Part of Frame according to the structure field */
+ if (StructureField == 3) PartOfFrame = 0;
+ else if(StructureField == 2) PartOfFrame = 1;
+ else if(StructureField == 1) PartOfFrame = 2;
+ else if(StructureField == 0) PartOfFrame = 3;
+ else PartOfFrame = 0; /* Normally we should never go here */
+
+ /* Fill the SACCH structure */
+ state->NxdnSacchRawPart[PartOfFrame].CrcIsGood = CrcIsGood;
+ state->NxdnSacchRawPart[PartOfFrame].StructureField = StructureField;
+ state->NxdnSacchRawPart[PartOfFrame].RAN = RAN;
+ memcpy(state->NxdnSacchRawPart[PartOfFrame].Data, &sacch_decoded[8], 18); /* Copy the 18 bits of SACCH content */
+
+ //fprintf(stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1);
+ //if(CrcIsGood) fprintf(stderr, " (OK) - ");
+ if(CrcIsGood)
+ {
+ fprintf (stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1);
+ fprintf (stderr, " (OK) - ");
+ state->nxdn_last_ran = RAN; //disable, try to grab this in voice instead
+ }
+ else fprintf(stderr, "(CRC ERR) - ");
+
+ /* Generate the key stream */
+ NxdnEncryptionStreamGeneration(opts, state, KeyStream);
+
+ //fprintf(stderr, "\nKeyStream = ");
+ //for(i = 0; i < 49; i++) fprintf(stderr, "%d", KeyStream[i]);
+ //fprintf(stderr, "\n");
+
+
+ /* Determine the current part of superframe
+ * (in an AES or DES encrypted frame, two superframes
+ * are used with the same IV, so to decipher the sound
+ * correctly we must know the current superframe part) */
+ if(state->NxdnElementsContent.PartOfNextEncryptedFrame == 1) PartOfEncryptedSuperFrame = 0;
+ else if(state->NxdnElementsContent.PartOfNextEncryptedFrame == 2) PartOfEncryptedSuperFrame = 1;
+ else PartOfEncryptedSuperFrame = 0;
+
+ /* Decode the SACCH only when all 4 voice frame
+ * SACCH spare parts have been received */
+ if(PartOfFrame == 3)
+ {
+ /* Decode the entire SACCH content */
+ NXDN_SACCH_Full_decode(opts, state);
+ }
+
+
+ if (opts->errorbars == 1)
+ {
+ fprintf(stderr, "e:");
+ }
+
+ /* Start pseudo-random NXDN sequence after
+ * LITCH = 16 bit = 8 dibit +
+ * SACCH = 60 bit = 30 dibit
+ * = 76 bit = 38 dibit
+ * ==> Index 38 */
+ pr = (unsigned char *)(&nxdnpr2[38]);
+ for (j = 0; j < 4; j++)
+ {
+ w = nW;
+ x = nX;
+ y = nY;
+ z = nZ;
+ for (i = 0; i < 36; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
- fprintf (stderr,"%c", dibit + 48);
-#endif
- }
-#ifdef NXDN_DUMP
- fprintf (stderr," ");
+ fprintf(stderr, "%c", dibit + 48);
#endif
+ ambe_fr[*w][*x] = *pr ^ (1 & (dibit >> 1)); // bit 1
+ pr++;
+ ambe_fr[*y][*z] = (1 & dibit); // bit 0
- pr = nxdnpr;
- for (j = 0; j < 4; j++)
- {
- w = nW;
- x = nX;
- y = nY;
- z = nZ;
- for (i = 0; i < 36; i++)
- {
- dibit = getDibit (opts, state);
-#ifdef NXDN_DUMP
- fprintf (stderr,"%c", dibit + 48);
-#endif
- ambe_fr[*w][*x] = *pr ^ (1 & (dibit >> 1)); // bit 1
- pr++;
- ambe_fr[*y][*z] = (1 & dibit); // bit 0
- w++;
- x++;
- y++;
- z++;
- }
- processMbeFrame (opts, state, NULL, ambe_fr, NULL);
-#ifdef NXDN_DUMP
- fprintf (stderr," ");
-#endif
+ w++;
+ x++;
+ y++;
+ z++;
}
+ //processMbeFrame (opts, state, NULL, ambe_fr, NULL);
+ processMbeFrameEncrypted(opts, state, NULL, ambe_fr, NULL, (char *)&KeyStream[(PartOfEncryptedSuperFrame * 4 * 4 * 49) + (PartOfFrame * 4 * 49) + (j * 49)], NULL);
+
+
+#ifdef BUILD_DSD_WITH_FRAME_CONTENT_DISPLAY
+ if(state->printNXDNAmbeVoiceSampleHex)
+ {
+ /* Display AMBE frame content */
+ /* Convert the 49 bit AMBE frame into 7 bytes */
+ Convert49BitSampleInto7Bytes(state->ambe_deciphered, ambe7bytesArray);
+ fprintf(stderr, "\nVoice Frame %d/4 : ", j + 1);
+ fprintf(stderr, "E1 = %d ; E2 = %d ; Content = ", state->errs, state->errs2);
+ for(i = 0; i < 7; i++) fprintf(stderr, "0x%02X, ", ambe7bytesArray[i] & 0xFF);
+ //fprintf(stderr, "\n");
+ }
+#endif /* BUILD_DSD_WITH_FRAME_CONTENT_DISPLAY */
+
+#ifdef NXDN_DUMP
+ fprintf(stderr, " ");
+#endif
+ } /* End for (j = 0; j < 4; j++) */
if (opts->errorbars == 1)
- {
- fprintf (stderr,"\n");
- }
-}
+ {
+ fprintf(stderr, "\n");
+ }
+
+ /* Reset the SACCH CRCs when all 4 voice frame
+ * SACCH spare parts have been received */
+ if(PartOfFrame == 3)
+ {
+ /* Reset all CRCs of the SACCH */
+ for(i = 0; i < 4; i++) state->NxdnSacchRawPart[i].CrcIsGood = 0;
+ }
+} /* End processNXDNVoice() */
diff --git a/src/nxdnconvolution.c b/src/nxdnconvolution.c
new file mode 100644
index 0000000..082103b
--- /dev/null
+++ b/src/nxdnconvolution.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2009-2016,2018 by Jonathan Naylor G4KLX
+ *
+ * Copyright (C) 2018 by Edouard Griffiths F4EXB:
+ * - Cosmetic changes to integrate with DSDcc
+ *
+ * Copyright (C) 2018 by Louis HERVE F4HUZ:
+ * - Transform C++ lib into C lib to integrate with DSD
+ *
+ * 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 ------------------------------------------------------------------*/
+//#include "nxdnconvolution.h"
+
+#include
+//#include
+#include
+#include
+#include
+#include
+
+
+/* Define -------------------------------------------------------------------*/
+
+
+/* Global variables ---------------------------------------------------------*/
+static const uint8_t CNXDNConvolution_BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
+
+#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | CNXDNConvolution_BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~CNXDNConvolution_BIT_MASK_TABLE[(i)&7])
+#define READ_BIT1(p,i) (p[(i)>>3] & CNXDNConvolution_BIT_MASK_TABLE[(i)&7])
+
+static const uint8_t CNXDNConvolution_BRANCH_TABLE1[] = {0U, 0U, 0U, 0U, 2U, 2U, 2U, 2U};
+static const uint8_t CNXDNConvolution_BRANCH_TABLE2[] = {0U, 2U, 2U, 0U, 0U, 2U, 2U, 0U};
+
+static const unsigned int CNXDNConvolution_NUM_OF_STATES_D2 = 8U;
+static const unsigned int CNXDNConvolution_NUM_OF_STATES = 16U;
+static const uint32_t CNXDNConvolution_M = 4U;
+static const unsigned int CNXDNConvolution_K = 5U;
+
+static uint16_t m_metrics1[16U] = {0};
+static uint16_t m_metrics2[16U] = {0};
+static uint64_t m_decisions[300U] = {0};
+static uint16_t * m_oldMetrics = NULL;
+static uint16_t * m_newMetrics = NULL;
+static uint64_t * m_dp = NULL;
+
+
+/* Functions ----------------------------------------------------------------*/
+
+void CNXDNConvolution_start(void)
+{
+ memset(m_metrics1, 0x00U, CNXDNConvolution_NUM_OF_STATES * sizeof(uint16_t));
+ memset(m_metrics2, 0x00U, CNXDNConvolution_NUM_OF_STATES * sizeof(uint16_t));
+
+ m_oldMetrics = m_metrics1;
+ m_newMetrics = m_metrics2;
+ m_dp = m_decisions;
+}
+
+
+void CNXDNConvolution_decode(uint8_t s0, uint8_t s1)
+{
+ uint8_t i = 0;
+ uint8_t j = 0;
+ uint8_t decision0 = 0;
+ uint8_t decision1 = 0;
+ uint16_t metric = 0;
+ uint16_t m0 = 0;
+ uint16_t m1 = 0;
+ uint16_t * tmp = NULL;
+
+ *m_dp = 0U;
+
+ for (i = 0U; i < CNXDNConvolution_NUM_OF_STATES_D2; i++)
+ {
+ j = i * 2U;
+
+ metric = abs(CNXDNConvolution_BRANCH_TABLE1[i] - s0) + abs(CNXDNConvolution_BRANCH_TABLE2[i] - s1);
+
+ m0 = m_oldMetrics[i] + metric;
+ m1 = m_oldMetrics[i + CNXDNConvolution_NUM_OF_STATES_D2] + (CNXDNConvolution_M - metric);
+ decision0 = (m0 >= m1) ? 1U : 0U;
+ m_newMetrics[j + 0U] = decision0 != 0U ? m1 : m0;
+
+ m0 = m_oldMetrics[i] + (CNXDNConvolution_M - metric);
+ m1 = m_oldMetrics[i + CNXDNConvolution_NUM_OF_STATES_D2] + metric;
+ decision1 = (m0 >= m1) ? 1U : 0U;
+ m_newMetrics[j + 1U] = decision1 != 0U ? m1 : m0;
+
+ *m_dp |= ((uint64_t)(decision1) << (j + 1U)) | ((uint64_t)(decision0) << (j + 0U));
+ }
+
+ ++m_dp;
+
+ //assert((m_dp - m_decisions) <= 300);
+
+ tmp = m_oldMetrics;
+ m_oldMetrics = m_newMetrics;
+ m_newMetrics = tmp;
+}
+
+void CNXDNConvolution_chainback(unsigned char* out, unsigned int nBits)
+{
+ //assert(out != 0);
+
+ uint32_t state = 0U;
+ uint32_t i = 0;
+ uint8_t bit = 0;
+
+ while (nBits-- > 0)
+ {
+ --m_dp;
+
+ i = state >> (9 - CNXDNConvolution_K);
+ bit = (uint8_t)(*m_dp >> i) & 1;
+ state = (bit << 7) | (state >> 1);
+
+ WRITE_BIT1(out, nBits, bit != 0U);
+ }
+}
+
+void CNXDNConvolution_encode(const unsigned char* in, unsigned char* out, unsigned int nBits)
+{
+ //assert(in != 0);
+ //assert(out != 0);
+ //assert(nBits > 0U);
+
+ uint8_t g1 = 0U;
+ uint8_t g2 = 0U;
+ uint8_t d = 0U;
+ uint8_t d1 = 0U;
+ uint8_t d2 = 0U;
+ uint8_t d3 = 0U;
+ uint8_t d4 = 0U;
+ uint32_t k = 0U;
+ unsigned int i = 0U;
+
+ for (i = 0U; i < nBits; i++)
+ {
+ d = READ_BIT1(in, i) ? 1U : 0U;
+
+ g1 = (d + d3 + d4) & 1;
+ g2 = (d + d1 + d2 + d4) & 1;
+
+ d4 = d3;
+ d3 = d2;
+ d2 = d1;
+ d1 = d;
+
+ WRITE_BIT1(out, k, g1 != 0U);
+ k++;
+
+ WRITE_BIT1(out, k, g2 != 0U);
+ k++;
+ }
+}
+
diff --git a/src/rtl_sdr_fm.cpp b/src/rtl_sdr_fm.cpp
index a5989f4..75fb919 100644
--- a/src/rtl_sdr_fm.cpp
+++ b/src/rtl_sdr_fm.cpp
@@ -953,6 +953,7 @@ static void *socket_thread_fn(void *arg) {
if(buffer[0] == 0) {
new_freq = chars_to_int(buffer);
dongle.freq = new_freq; //
+ //opts->rtlsdr_center_freq = new_freq; //or dongle.freq, this should update the freq displayed in ncurses terminal hopefully and not do anything naughty
optimal_settings(new_freq, demod.rate_in);
rtlsdr_set_center_freq(dongle.dev, dongle.freq);
//fprintf (stderr, "Tuning to: %d [Hz] (central freq: %d [Hz])\n", new_freq, new_freq + freq_offset);
@@ -1043,6 +1044,7 @@ void rtlsdr_sighandler()
{
fprintf (stderr, "Signal caught, exiting!\n");
fprintf (stderr, "Press CTRL + C again to close. Thanks. \n"); //Kindly remind user to double tap CTRL + C
+
rtlsdr_cancel_async(dongle.dev);
//cleanup_rtlsdr_stream(); //thank the wraith for this one...if it works...didn't work
//_Exit(1);